UI adjustments when no metainfo yet

This commit is contained in:
zzz
2010-12-20 18:55:10 +00:00
parent 7602999274
commit ebe7f3b127
4 changed files with 140 additions and 77 deletions

View File

@ -531,6 +531,7 @@ public class Snark
// single torrent // single torrent
acceptor = new ConnectionAcceptor(_util, serversocket, new PeerAcceptor(coordinator)); acceptor = new ConnectionAcceptor(_util, serversocket, new PeerAcceptor(coordinator));
} }
// TODO pass saved closest DHT nodes to the tracker? or direct to the coordinator?
trackerclient = new TrackerClient(_util, meta, coordinator, this); trackerclient = new TrackerClient(_util, meta, coordinator, this);
} }
@ -781,8 +782,11 @@ public class Snark
public long getNeeded() { public long getNeeded() {
if (storage != null) if (storage != null)
return storage.needed(); return storage.needed();
// FIXME else return metainfo length if available if (meta != null)
return -1; // FIXME subtract chunks we have
return meta.getTotalLength();
// FIXME fake
return 16 * 16 * 1024;
} }
/** /**

View File

@ -20,6 +20,7 @@ import java.util.Collection;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
import net.i2p.data.Base64; import net.i2p.data.Base64;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.I2PAppThread; import net.i2p.util.I2PAppThread;
import net.i2p.util.Log; import net.i2p.util.Log;
import net.i2p.util.OrderedProperties; import net.i2p.util.OrderedProperties;
@ -34,6 +35,8 @@ public class SnarkManager implements Snark.CompleteListener {
/** map of (canonical) filename of the .torrent file to Snark instance (unsynchronized) */ /** map of (canonical) filename of the .torrent file to Snark instance (unsynchronized) */
private final Map<String, Snark> _snarks; private final Map<String, Snark> _snarks;
/** used to prevent DirMonitor from deleting torrents that don't have a torrent file yet */
private final Set<String> _magnets;
private final Object _addSnarkLock; private final Object _addSnarkLock;
private /* FIXME final FIXME */ File _configFile; private /* FIXME final FIXME */ File _configFile;
private Properties _config; private Properties _config;
@ -72,6 +75,7 @@ public class SnarkManager implements Snark.CompleteListener {
public static final int DEFAULT_STARTUP_DELAY = 3; public static final int DEFAULT_STARTUP_DELAY = 3;
private SnarkManager() { private SnarkManager() {
_snarks = new HashMap(); _snarks = new HashMap();
_magnets = new ConcurrentHashSet();
_addSnarkLock = new Object(); _addSnarkLock = new Object();
_context = I2PAppContext.getGlobalContext(); _context = I2PAppContext.getGlobalContext();
_log = _context.logManager().getLog(SnarkManager.class); _log = _context.logManager().getLog(SnarkManager.class);
@ -90,8 +94,6 @@ public class SnarkManager implements Snark.CompleteListener {
_running = true; _running = true;
_peerCoordinatorSet = new PeerCoordinatorSet(); _peerCoordinatorSet = new PeerCoordinatorSet();
_connectionAcceptor = new ConnectionAcceptor(_util); _connectionAcceptor = new ConnectionAcceptor(_util);
int minutes = getStartupDelayMinutes();
_messages.add(_("Adding torrents in {0} minutes", minutes));
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true); _monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
_monitor.start(); _monitor.start();
_context.addShutdownTask(new SnarkManagerShutdown()); _context.addShutdownTask(new SnarkManagerShutdown());
@ -321,7 +323,7 @@ public class SnarkManager implements Snark.CompleteListener {
_util.setStartupDelay(minutes); _util.setStartupDelay(minutes);
changed = true; changed = true;
_config.setProperty(PROP_STARTUP_DELAY, "" + minutes); _config.setProperty(PROP_STARTUP_DELAY, "" + minutes);
addMessage(_("Startup delay limit changed to {0} minutes", minutes)); addMessage(_("Startup delay changed to {0}", DataHelper.formatDuration2(minutes * 60 * 1000)));
} }
} }
@ -549,6 +551,7 @@ public class SnarkManager implements Snark.CompleteListener {
addMessage(rejectMessage); addMessage(rejectMessage);
return; return;
} else { } else {
// TODO load saved closest DHT nodes and pass to the Snark ?
torrent = new Snark(_util, filename, null, -1, null, null, this, torrent = new Snark(_util, filename, null, -1, null, null, this,
_peerCoordinatorSet, _connectionAcceptor, _peerCoordinatorSet, _connectionAcceptor,
false, dataDir.getPath()); false, dataDir.getPath());
@ -583,6 +586,7 @@ public class SnarkManager implements Snark.CompleteListener {
* *
* @param name hex or b32 name from the magnet link * @param name hex or b32 name from the magnet link
* @param ih 20 byte info hash * @param ih 20 byte info hash
* @throws RuntimeException via Snark.fatal()
* @since 0.8.4 * @since 0.8.4
*/ */
public void addMagnet(String name, byte[] ih) { public void addMagnet(String name, byte[] ih) {
@ -590,7 +594,8 @@ public class SnarkManager implements Snark.CompleteListener {
_peerCoordinatorSet, _connectionAcceptor, _peerCoordinatorSet, _connectionAcceptor,
false, getDataDir().getPath()); false, getDataDir().getPath());
// TODO tell the dir monitor not to delete us // Tell the dir monitor not to delete us
_magnets.add(name);
synchronized (_snarks) { synchronized (_snarks) {
_snarks.put(name, torrent); _snarks.put(name, torrent);
} }
@ -608,12 +613,17 @@ public class SnarkManager implements Snark.CompleteListener {
} }
/** /**
* Delete a torrent with the info hash alone (magnet / maggot) * Stop and delete a torrent running in magnet mode
* *
* @param ih 20 byte info hash * @param snark a torrent with a fake file name ("Magnet xxxx")
* @since 0.8.4 * @since 0.8.4
*/ */
public void deleteMagnet(byte[] ih) { public void deleteMagnet(Snark snark) {
synchronized (_snarks) {
_snarks.remove(snark.getName());
}
snark.stopTorrent();
_magnets.remove(snark.getName());
} }
/** /**
@ -748,6 +758,8 @@ public class SnarkManager implements Snark.CompleteListener {
_config.remove(prop); _config.remove(prop);
} }
// TODO save closest DHT nodes too
saveConfig(); saveConfig();
} }
@ -828,6 +840,23 @@ public class SnarkManager implements Snark.CompleteListener {
} }
return torrent; return torrent;
} }
/**
* Stop the torrent, leaving it on the list of torrents unless told to remove it
* @since 0.8.4
*/
public void stopTorrent(Snark torrent, boolean shouldRemove) {
if (shouldRemove) {
synchronized (_snarks) {
_snarks.remove(torrent.getName());
}
}
boolean wasStopped = torrent.isStopped();
torrent.stopTorrent();
if (!wasStopped)
addMessage(_("Torrent stopped: \"{0}\"", torrent.getBaseName()));
}
/** /**
* Stop the torrent and delete the torrent file itself, but leaving the data * Stop the torrent and delete the torrent file itself, but leaving the data
* behind. * behind.
@ -846,11 +875,16 @@ public class SnarkManager implements Snark.CompleteListener {
private class DirMonitor implements Runnable { private class DirMonitor implements Runnable {
public void run() { public void run() {
try { Thread.sleep(60*1000*getStartupDelayMinutes()); } catch (InterruptedException ie) {} // don't bother delaying if auto start is false
// the first message was a "We are starting up in 1m" long delay = 60 * 1000 * getStartupDelayMinutes();
synchronized (_messages) { if (delay > 0 && shouldAutoStart()) {
if (_messages.size() == 1) _messages.add(_("Adding torrents in {0}", DataHelper.formatDuration2(delay)));
_messages.remove(0); try { Thread.sleep(delay); } catch (InterruptedException ie) {}
// the first message was a "We are starting up in 1m"
synchronized (_messages) {
if (_messages.size() == 1)
_messages.remove(0);
}
} }
// here because we need to delay until I2CP is up // here because we need to delay until I2CP is up
@ -922,6 +956,8 @@ public class SnarkManager implements Snark.CompleteListener {
} }
} }
} }
// Don't remove magnet torrents that don't have a torrent file yet
existingNames.removeAll(_magnets);
// now lets see which ones have been removed... // now lets see which ones have been removed...
for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) { for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) {
String name = (String)iter.next(); String name = (String)iter.next();
@ -975,12 +1011,12 @@ public class SnarkManager implements Snark.CompleteListener {
/** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */ /** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */
public static final String PROP_TRACKERS = "i2psnark.trackers"; public static final String PROP_TRACKERS = "i2psnark.trackers";
private static Map trackerMap = null; private static Map<String, String> trackerMap = null;
/** sorted map of name to announceURL=baseURL */ /** sorted map of name to announceURL=baseURL */
public Map getTrackers() { public Map<String, String> getTrackers() {
if (trackerMap != null) // only do this once, can't be updated while running if (trackerMap != null) // only do this once, can't be updated while running
return trackerMap; return trackerMap;
Map rv = new TreeMap(); Map<String, String> rv = new TreeMap();
String trackers = _config.getProperty(PROP_TRACKERS); String trackers = _config.getProperty(PROP_TRACKERS);
if ( (trackers == null) || (trackers.trim().length() <= 0) ) if ( (trackers == null) || (trackers.trim().length() <= 0) )
trackers = _context.getProperty(PROP_TRACKERS); trackers = _context.getProperty(PROP_TRACKERS);

View File

@ -126,10 +126,9 @@ public class TrackerClient extends I2PAppThread
@Override @Override
public void run() public void run()
{ {
String infoHash = urlencode(meta.getInfoHash()); String infoHash = urlencode(snark.getInfoHash());
String peerID = urlencode(snark.getID()); String peerID = urlencode(snark.getID());
_log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash);
// Construct the list of trackers for this torrent, // Construct the list of trackers for this torrent,
// starting with the primary one listed in the metainfo, // starting with the primary one listed in the metainfo,
@ -138,12 +137,18 @@ public class TrackerClient extends I2PAppThread
// the primary tracker, that we don't add it twice. // the primary tracker, that we don't add it twice.
// todo: check for b32 matches as well // todo: check for b32 matches as well
trackers = new ArrayList(2); trackers = new ArrayList(2);
String primary = meta.getAnnounce(); String primary;
if (isValidAnnounce(primary)) { if (meta != null) {
trackers.add(new Tracker(meta.getAnnounce(), true)); primary = meta.getAnnounce();
if (isValidAnnounce(primary)) {
trackers.add(new Tracker(meta.getAnnounce(), true));
} else {
_log.warn("Skipping invalid or non-i2p announce: " + primary);
}
} else { } else {
_log.warn("Skipping invalid or non-i2p announce: " + primary); primary = "";
} }
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
List tlist = _util.getOpenTrackers(); List tlist = _util.getOpenTrackers();
if (tlist != null) { if (tlist != null) {
for (int i = 0; i < tlist.size(); i++) { for (int i = 0; i < tlist.size(); i++) {

View File

@ -462,7 +462,7 @@ public class I2PSnarkServlet extends Default {
} else if (newURL.startsWith(MAGNET) || newURL.startsWith(MAGGOT)) { } else if (newURL.startsWith(MAGNET) || newURL.startsWith(MAGGOT)) {
addMagnet(newURL); addMagnet(newURL);
} else { } else {
_manager.addMessage(_("Invalid URL - must start with http://, {0} or {1}", MAGNET, MAGGOT)); _manager.addMessage(_("Invalid URL: Must start with \"http://\", \"{0}\", or \"{1}\"", MAGNET, MAGGOT));
} }
} else { } else {
// no file or URL specified // no file or URL specified
@ -476,7 +476,7 @@ public class I2PSnarkServlet extends Default {
String name = (String)iter.next(); String name = (String)iter.next();
Snark snark = _manager.getTorrent(name); Snark snark = _manager.getTorrent(name);
if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) { if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
_manager.stopTorrent(name, false); _manager.stopTorrent(snark, false);
break; break;
} }
} }
@ -506,13 +506,14 @@ public class I2PSnarkServlet extends Default {
String name = (String)iter.next(); String name = (String)iter.next();
Snark snark = _manager.getTorrent(name); Snark snark = _manager.getTorrent(name);
if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) { if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
_manager.stopTorrent(name, true);
MetaInfo meta = snark.getMetaInfo(); MetaInfo meta = snark.getMetaInfo();
if (meta == null) { if (meta == null) {
// magnet // magnet - remove and delete are the same thing
_manager.deleteMagnet(snark.getInfoHash()); _manager.deleteMagnet(snark);
_manager.addMessage(_("Magnet deleted: {0}", name));
return; return;
} }
_manager.stopTorrent(snark, true);
// should we delete the torrent file? // should we delete the torrent file?
// yeah, need to, otherwise it'll get autoadded again (at the moment // yeah, need to, otherwise it'll get autoadded again (at the moment
File f = new File(name); File f = new File(name);
@ -532,13 +533,14 @@ public class I2PSnarkServlet extends Default {
String name = (String)iter.next(); String name = (String)iter.next();
Snark snark = _manager.getTorrent(name); Snark snark = _manager.getTorrent(name);
if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) { if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
_manager.stopTorrent(name, true);
MetaInfo meta = snark.getMetaInfo(); MetaInfo meta = snark.getMetaInfo();
if (meta == null) { if (meta == null) {
// magnet // magnet - remove and delete are the same thing
_manager.deleteMagnet(snark.getInfoHash()); _manager.deleteMagnet(snark);
_manager.addMessage(_("Magnet deleted: {0}", name));
return; return;
} }
_manager.stopTorrent(snark, true);
File f = new File(name); File f = new File(name);
f.delete(); f.delete();
_manager.addMessage(_("Torrent file deleted: {0}", f.getAbsolutePath())); _manager.addMessage(_("Torrent file deleted: {0}", f.getAbsolutePath()));
@ -635,7 +637,7 @@ public class I2PSnarkServlet extends Default {
for (int i = 0; i < snarks.size(); i++) { for (int i = 0; i < snarks.size(); i++) {
Snark snark = (Snark)snarks.get(i); Snark snark = (Snark)snarks.get(i);
if (!snark.isStopped()) if (!snark.isStopped())
_manager.stopTorrent(snark.getName(), false); _manager.stopTorrent(snark, false);
} }
if (_manager.util().connected()) { if (_manager.util().connected()) {
// Give the stopped announces time to get out // Give the stopped announces time to get out
@ -750,8 +752,9 @@ public class I2PSnarkServlet extends Default {
stats[5] += total; stats[5] += total;
MetaInfo meta = snark.getMetaInfo(); MetaInfo meta = snark.getMetaInfo();
// isValid means isNotMagnet
boolean isValid = meta != null; boolean isValid = meta != null;
boolean singleFile = (!isValid) || meta.getFiles() == null; boolean isMultiFile = isValid && meta.getFiles() != null;
String err = snark.getTrackerProblems(); String err = snark.getTrackerProblems();
int curPeers = snark.getPeerCount(); int curPeers = snark.getPeerCount();
@ -776,7 +779,7 @@ public class I2PSnarkServlet extends Default {
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
"<br>" + err; "<br>" + err;
} }
} else if (remaining <= 0) { } else if (remaining == 0) { // < 0 means no meta size yet
if (isRunning && curPeers > 0 && !showPeers) if (isRunning && curPeers > 0 && !showPeers)
statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
@ -822,9 +825,12 @@ public class I2PSnarkServlet extends Default {
out.write("<td class=\"" + rowClass + "\">"); out.write("<td class=\"" + rowClass + "\">");
// temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash // temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash
String announce = meta.getAnnounce(); String announce = null;
if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") || if (isValid)
announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") || announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/")) { announce = meta.getAnnounce();
if (announce != null && (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") ||
announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") ||
announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/"))) {
Map trackers = _manager.getTrackers(); Map trackers = _manager.getTrackers();
for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) { for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) {
Map.Entry entry = (Map.Entry)iter.next(); Map.Entry entry = (Map.Entry)iter.next();
@ -849,13 +855,13 @@ public class I2PSnarkServlet extends Default {
out.write("</td>\n<td class=\"" + rowClass + "\">"); out.write("</td>\n<td class=\"" + rowClass + "\">");
StringBuilder buf = null; StringBuilder buf = null;
if (remaining == 0 || meta.getFiles() != null) { if (remaining == 0 || isMultiFile) {
buf = new StringBuilder(128); buf = new StringBuilder(128);
buf.append("<a href=\"").append(snark.getBaseName()); buf.append("<a href=\"").append(snark.getBaseName());
if (meta.getFiles() != null) if (isMultiFile)
buf.append('/'); buf.append('/');
buf.append("\" title=\""); buf.append("\" title=\"");
if (meta.getFiles() != null) if (isMultiFile)
buf.append(_("View files")); buf.append(_("View files"));
else else
buf.append(_("Open file")); buf.append(_("Open file"));
@ -863,21 +869,24 @@ public class I2PSnarkServlet extends Default {
out.write(buf.toString()); out.write(buf.toString());
} }
String icon; String icon;
if (meta.getFiles() != null) if (isMultiFile)
icon = "folder"; icon = "folder";
else else if (isValid)
icon = toIcon(meta.getName()); icon = toIcon(meta.getName());
if (remaining == 0 || meta.getFiles() != null) { else
// todo get a nice magnet icon?
icon = "page_white";
if (remaining == 0 || isMultiFile) {
out.write(toImg(icon, _("Open"))); out.write(toImg(icon, _("Open")));
out.write("</a>"); out.write("</a>");
} else { } else {
out.write(toImg(icon)); out.write(toImg(icon));
} }
out.write("</td><td class=\"snarkTorrentName " + rowClass + "\">"); out.write("</td><td class=\"snarkTorrentName " + rowClass + "\">");
if (remaining == 0 || meta.getFiles() != null) if (remaining == 0 || isMultiFile)
out.write(buf.toString()); out.write(buf.toString());
out.write(filename); out.write(filename);
if (remaining == 0 || meta.getFiles() != null) if (remaining == 0 || isMultiFile)
out.write("</a>"); out.write("</a>");
out.write("<td align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">"); out.write("<td align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">");
@ -887,19 +896,21 @@ public class I2PSnarkServlet extends Default {
out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">"); out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">");
if (remaining > 0) if (remaining > 0)
out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total)); out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total));
else else if (remaining == 0)
out.write(formatSize(total)); // 3GB out.write(formatSize(total)); // 3GB
else
out.write("??"); // no meta size yet
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentUploaded " + rowClass + "\">"); out.write("<td align=\"right\" class=\"snarkTorrentUploaded " + rowClass + "\">");
if(isRunning) if(isRunning && isValid)
out.write(formatSize(uploaded)); out.write(formatSize(uploaded));
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">"); out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
if(isRunning && remaining > 0) if(isRunning && remaining != 0)
out.write(formatSize(downBps) + "ps"); out.write(formatSize(downBps) + "ps");
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">"); out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">");
if(isRunning) if(isRunning && isValid)
out.write(formatSize(upBps) + "ps"); out.write(formatSize(upBps) + "ps");
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td align=\"center\" class=\"snarkTorrentAction " + rowClass + "\">"); out.write("<td align=\"center\" class=\"snarkTorrentAction " + rowClass + "\">");
@ -919,7 +930,6 @@ public class I2PSnarkServlet extends Default {
if (isDegraded) if (isDegraded)
out.write("</a>"); out.write("</a>");
} else { } else {
if (isValid) {
if (isDegraded) if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\""); out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
else else
@ -930,24 +940,25 @@ public class I2PSnarkServlet extends Default {
out.write("\">"); out.write("\">");
if (isDegraded) if (isDegraded)
out.write("</a>"); out.write("</a>");
}
if (isDegraded) if (isValid) {
out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\""); if (isDegraded)
else out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\""); else
out.write(_("Remove the torrent from the active list, deleting the .torrent file")); out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\"");
out.write("\" onclick=\"if (!confirm('"); out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
// Can't figure out how to escape double quotes inside the onclick string. out.write("\" onclick=\"if (!confirm('");
// Single quotes in translate strings with parameters must be doubled. // Can't figure out how to escape double quotes inside the onclick string.
// Then the remaining single quite must be escaped // Single quotes in translate strings with parameters must be doubled.
out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename)); // Then the remaining single quite must be escaped
out.write("')) { return false; }\""); out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename));
out.write(" src=\"" + _imgPath + "remove.png\" alt=\""); out.write("')) { return false; }\"");
out.write(_("Remove")); out.write(" src=\"" + _imgPath + "remove.png\" alt=\"");
out.write("\">"); out.write(_("Remove"));
if (isDegraded) out.write("\">");
out.write("</a>"); if (isDegraded)
out.write("</a>");
}
if (isDegraded) if (isDegraded)
out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\""); out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
@ -1002,14 +1013,21 @@ public class I2PSnarkServlet extends Default {
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">"); out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">"); out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
float pct = (float) (100.0 * (float) peer.completed() / meta.getPieces()); float pct;
if (pct == 100.0) if (isValid) {
out.write(_("Seed")); pct = (float) (100.0 * (float) peer.completed() / meta.getPieces());
else { if (pct == 100.0)
String ps = String.valueOf(pct); out.write(_("Seed"));
if (ps.length() > 5) else {
ps = ps.substring(0, 5); String ps = String.valueOf(pct);
out.write(ps + "%"); if (ps.length() > 5)
ps = ps.substring(0, 5);
out.write(ps + "%");
}
} else {
pct = (float) 101.0;
// until we get the metainfo we don't know how many pieces there are
out.write("??");
} }
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">"); out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">");
@ -1031,7 +1049,7 @@ public class I2PSnarkServlet extends Default {
} }
out.write("</td>\n\t"); out.write("</td>\n\t");
out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">"); out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
if (pct != 100.0) { if (isValid && pct < 100.0) {
if (peer.isInterested() && !peer.isChoking()) { if (peer.isInterested() && !peer.isChoking()) {
out.write("<span class=\"unchoked\">"); out.write("<span class=\"unchoked\">");
out.write(formatSize(peer.getUploadRate()) + "ps</span>"); out.write(formatSize(peer.getUploadRate()) + "ps</span>");
@ -1363,7 +1381,7 @@ public class I2PSnarkServlet extends Default {
_manager.addMessage(_("Invalid info hash in magnet URL {0}", url)); _manager.addMessage(_("Invalid info hash in magnet URL {0}", url));
return; return;
} }
_manager.addMagnet(ihash, ih); _manager.addMagnet(name, ih);
} }
/** copied from ConfigTunnelsHelper */ /** copied from ConfigTunnelsHelper */