From ebe7f3b127f81049c7e71351d06fdc770c91e8e6 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Mon, 20 Dec 2010 18:55:10 +0000
Subject: [PATCH] UI adjustments when no metainfo yet

---
 .../java/src/org/klomp/snark/Snark.java       |   8 +-
 .../src/org/klomp/snark/SnarkManager.java     |  66 ++++++---
 .../src/org/klomp/snark/TrackerClient.java    |  17 ++-
 .../org/klomp/snark/web/I2PSnarkServlet.java  | 126 ++++++++++--------
 4 files changed, 140 insertions(+), 77 deletions(-)

diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
index 2460e9f530..27e38b5ca0 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
@@ -531,6 +531,7 @@ public class Snark
             // single torrent
             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);
     }
 
@@ -781,8 +782,11 @@ public class Snark
     public long getNeeded() {
         if (storage != null)
             return storage.needed();
-        // FIXME else return metainfo length if available
-        return -1;
+        if (meta != null)
+            // FIXME subtract chunks we have
+            return meta.getTotalLength();
+        // FIXME fake
+        return 16 * 16 * 1024;
     }
 
     /**
diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index 270937688e..24e8ebc7f6 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -20,6 +20,7 @@ import java.util.Collection;
 import net.i2p.I2PAppContext;
 import net.i2p.data.Base64;
 import net.i2p.data.DataHelper;
+import net.i2p.util.ConcurrentHashSet;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
 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) */
     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 /* FIXME final FIXME */ File _configFile;
     private Properties _config;
@@ -72,6 +75,7 @@ public class SnarkManager implements Snark.CompleteListener {
     public static final int DEFAULT_STARTUP_DELAY = 3; 
     private SnarkManager() {
         _snarks = new HashMap();
+        _magnets = new ConcurrentHashSet();
         _addSnarkLock = new Object();
         _context = I2PAppContext.getGlobalContext();
         _log = _context.logManager().getLog(SnarkManager.class);
@@ -90,8 +94,6 @@ public class SnarkManager implements Snark.CompleteListener {
         _running = true;
         _peerCoordinatorSet = new PeerCoordinatorSet();
         _connectionAcceptor = new ConnectionAcceptor(_util);
-        int minutes = getStartupDelayMinutes();
-        _messages.add(_("Adding torrents in {0} minutes", minutes));
         _monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
         _monitor.start();
         _context.addShutdownTask(new SnarkManagerShutdown());
@@ -321,7 +323,7 @@ public class SnarkManager implements Snark.CompleteListener {
                 	    _util.setStartupDelay(minutes);
 	                    changed = true;
         	            _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);
                         return;
                     } else {
+                        // TODO load saved closest DHT nodes and pass to the Snark ?
                         torrent = new Snark(_util, filename, null, -1, null, null, this,
                                             _peerCoordinatorSet, _connectionAcceptor,
                                             false, dataDir.getPath());
@@ -583,6 +586,7 @@ public class SnarkManager implements Snark.CompleteListener {
      *
      * @param name hex or b32 name from the magnet link
      * @param ih 20 byte info hash
+     * @throws RuntimeException via Snark.fatal()
      * @since 0.8.4
      */
     public void addMagnet(String name, byte[] ih) {
@@ -590,7 +594,8 @@ public class SnarkManager implements Snark.CompleteListener {
                                   _peerCoordinatorSet, _connectionAcceptor,
                                   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) {
             _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
      */
-    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);
         }
 
+        // TODO save closest DHT nodes too
+
         saveConfig();
     }
     
@@ -828,6 +840,23 @@ public class SnarkManager implements Snark.CompleteListener {
         }
         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
      * behind.
@@ -846,11 +875,16 @@ public class SnarkManager implements Snark.CompleteListener {
     
     private class DirMonitor implements Runnable {
         public void run() {
-            try { Thread.sleep(60*1000*getStartupDelayMinutes()); } catch (InterruptedException ie) {}
-            // the first message was a "We are starting up in 1m" 
-            synchronized (_messages) { 
-                if (_messages.size() == 1)
-                    _messages.remove(0);
+            // don't bother delaying if auto start is false
+            long delay = 60 * 1000 * getStartupDelayMinutes();
+            if (delay > 0 && shouldAutoStart()) {
+                _messages.add(_("Adding torrents in {0}", DataHelper.formatDuration2(delay)));
+                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
@@ -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...
         for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) {
             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 */
     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 */
-    public Map getTrackers() { 
+    public Map<String, String> getTrackers() { 
         if (trackerMap != null) // only do this once, can't be updated while running
             return trackerMap;
-        Map rv = new TreeMap();
+        Map<String, String> rv = new TreeMap();
         String trackers = _config.getProperty(PROP_TRACKERS);
         if ( (trackers == null) || (trackers.trim().length() <= 0) )
             trackers = _context.getProperty(PROP_TRACKERS);
diff --git a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
index d14abaa0c9..f437beeeb6 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
@@ -126,10 +126,9 @@ public class TrackerClient extends I2PAppThread
     @Override
   public void run()
   {
-    String infoHash = urlencode(meta.getInfoHash());
+    String infoHash = urlencode(snark.getInfoHash());
     String peerID = urlencode(snark.getID());
 
-    _log.debug("Announce: [" + meta.getAnnounce() + "] infoHash: " + infoHash);
 
     // Construct the list of trackers for this torrent,
     // 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.
     // todo: check for b32 matches as well
     trackers = new ArrayList(2);
-    String primary = meta.getAnnounce();
-    if (isValidAnnounce(primary)) {
-        trackers.add(new Tracker(meta.getAnnounce(), true));
+    String primary;
+    if (meta != null) {
+        primary = meta.getAnnounce();
+        if (isValidAnnounce(primary)) {
+            trackers.add(new Tracker(meta.getAnnounce(), true));
+        } else {
+            _log.warn("Skipping invalid or non-i2p announce: " + primary);
+        }
     } else {
-        _log.warn("Skipping invalid or non-i2p announce: " + primary);
+        primary = "";
     }
+    _log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
     List tlist = _util.getOpenTrackers();
     if (tlist != null) {
         for (int i = 0; i < tlist.size(); i++) {
diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
index 917652bc04..c6ba8b9fd8 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -462,7 +462,7 @@ public class I2PSnarkServlet extends Default {
                 } else if (newURL.startsWith(MAGNET) || newURL.startsWith(MAGGOT)) {
                     addMagnet(newURL);
                 } 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 {
                 // no file or URL specified
@@ -476,7 +476,7 @@ public class I2PSnarkServlet extends Default {
                         String name = (String)iter.next();
                         Snark snark = _manager.getTorrent(name);
                         if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
-                            _manager.stopTorrent(name, false);
+                            _manager.stopTorrent(snark, false);
                             break;
                         }
                     }
@@ -506,13 +506,14 @@ public class I2PSnarkServlet extends Default {
                         String name = (String)iter.next();
                         Snark snark = _manager.getTorrent(name);
                         if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
-                            _manager.stopTorrent(name, true);
                             MetaInfo meta = snark.getMetaInfo();
                             if (meta == null) {
-                                // magnet
-                                _manager.deleteMagnet(snark.getInfoHash());
+                                // magnet - remove and delete are the same thing
+                                _manager.deleteMagnet(snark);
+                                _manager.addMessage(_("Magnet deleted: {0}", name));
                                 return;
                             }
+                            _manager.stopTorrent(snark, true);
                             // should we delete the torrent file?
                             // yeah, need to, otherwise it'll get autoadded again (at the moment
                             File f = new File(name);
@@ -532,13 +533,14 @@ public class I2PSnarkServlet extends Default {
                         String name = (String)iter.next();
                         Snark snark = _manager.getTorrent(name);
                         if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
-                            _manager.stopTorrent(name, true);
                             MetaInfo meta = snark.getMetaInfo();
                             if (meta == null) {
-                                // magnet
-                                _manager.deleteMagnet(snark.getInfoHash());
+                                // magnet - remove and delete are the same thing
+                                _manager.deleteMagnet(snark);
+                                _manager.addMessage(_("Magnet deleted: {0}", name));
                                 return;
                             }
+                            _manager.stopTorrent(snark, true);
                             File f = new File(name);
                             f.delete();
                             _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++) {
                 Snark snark = (Snark)snarks.get(i);
                 if (!snark.isStopped())
-                    _manager.stopTorrent(snark.getName(), false);
+                    _manager.stopTorrent(snark, false);
             }
             if (_manager.util().connected()) {
                 // Give the stopped announces time to get out
@@ -750,8 +752,9 @@ public class I2PSnarkServlet extends Default {
         stats[5] += total;
         
         MetaInfo meta = snark.getMetaInfo();
+        // isValid means isNotMagnet
         boolean isValid = meta != null;
-        boolean singleFile = (!isValid) || meta.getFiles() == null;
+        boolean isMultiFile = isValid && meta.getFiles() != null;
         
         String err = snark.getTrackerProblems();
         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") +
                 "<br>" + err;
             }
-        } else if (remaining <= 0) {
+        } else if (remaining == 0) {  // < 0 means no meta size yet
             if (isRunning && curPeers > 0 && !showPeers)
                 statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") +
                                ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
@@ -822,9 +825,12 @@ public class I2PSnarkServlet extends Default {
 
         out.write("<td class=\"" + rowClass + "\">");
         // temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash
-        String announce = meta.getAnnounce();
-        if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") ||
-            announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/") || announce.startsWith("http://ahsplxkbhemefwvvml7qovzl5a2b5xo5i7lyai7ntdunvcyfdtna.b32.i2p/")) {
+        String announce = null;
+        if (isValid)
+            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();
             for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) {
                 Map.Entry entry = (Map.Entry)iter.next();
@@ -849,13 +855,13 @@ public class I2PSnarkServlet extends Default {
 
         out.write("</td>\n<td class=\"" + rowClass + "\">");
         StringBuilder buf = null;
-        if (remaining == 0 || meta.getFiles() != null) {
+        if (remaining == 0 || isMultiFile) {
             buf = new StringBuilder(128);
             buf.append("<a href=\"").append(snark.getBaseName());
-            if (meta.getFiles() != null)
+            if (isMultiFile)
                 buf.append('/');
             buf.append("\" title=\"");
-            if (meta.getFiles() != null)
+            if (isMultiFile)
                 buf.append(_("View files"));
             else
                 buf.append(_("Open file"));
@@ -863,21 +869,24 @@ public class I2PSnarkServlet extends Default {
             out.write(buf.toString());
         }
         String icon;
-        if (meta.getFiles() != null)
+        if (isMultiFile)
             icon = "folder";
-        else
+        else if (isValid)
             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("</a>");
         } else {
             out.write(toImg(icon));
         }
         out.write("</td><td class=\"snarkTorrentName " + rowClass + "\">");
-        if (remaining == 0 || meta.getFiles() != null)
+        if (remaining == 0 || isMultiFile)
             out.write(buf.toString());
         out.write(filename);
-        if (remaining == 0 || meta.getFiles() != null)
+        if (remaining == 0 || isMultiFile)
             out.write("</a>");
 
         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 + "\">");
         if (remaining > 0)
             out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total));
-        else
+        else if (remaining == 0)
             out.write(formatSize(total)); // 3GB
+        else
+            out.write("??");  // no meta size yet
         out.write("</td>\n\t");
         out.write("<td align=\"right\" class=\"snarkTorrentUploaded " + rowClass + "\">");
-        if(isRunning)
+        if(isRunning && isValid)
            out.write(formatSize(uploaded));
         out.write("</td>\n\t");
         out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">");
-        if(isRunning && remaining > 0)
+        if(isRunning && remaining != 0)
             out.write(formatSize(downBps) + "ps");
         out.write("</td>\n\t");
         out.write("<td align=\"right\" class=\"snarkTorrentRateUp\">");
-        if(isRunning)
+        if(isRunning && isValid)
             out.write(formatSize(upBps) + "ps");
         out.write("</td>\n\t");
         out.write("<td align=\"center\" class=\"snarkTorrentAction " + rowClass + "\">");
@@ -919,7 +930,6 @@ public class I2PSnarkServlet extends Default {
             if (isDegraded)
                 out.write("</a>");
         } else {
-            if (isValid) {
                 if (isDegraded)
                     out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
                 else
@@ -930,24 +940,25 @@ public class I2PSnarkServlet extends Default {
                 out.write("\">");
                 if (isDegraded)
                     out.write("</a>");
-            }
 
-            if (isDegraded)
-                out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
-            else
-                out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\"");
-            out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
-            out.write("\" onclick=\"if (!confirm('");
-            // Can't figure out how to escape double quotes inside the onclick string.
-            // Single quotes in translate strings with parameters must be doubled.
-            // Then the remaining single quite must be escaped
-            out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename));
-            out.write("')) { return false; }\"");
-            out.write(" src=\"" + _imgPath + "remove.png\" alt=\"");
-            out.write(_("Remove"));
-            out.write("\">");
-            if (isDegraded)
-                out.write("</a>");
+            if (isValid) {
+                if (isDegraded)
+                    out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&amp;nonce=" + _nonce + "\"><img title=\"");
+                else
+                    out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\"");
+                out.write(_("Remove the torrent from the active list, deleting the .torrent file"));
+                out.write("\" onclick=\"if (!confirm('");
+                // Can't figure out how to escape double quotes inside the onclick string.
+                // Single quotes in translate strings with parameters must be doubled.
+                // Then the remaining single quite must be escaped
+                out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename));
+                out.write("')) { return false; }\"");
+                out.write(" src=\"" + _imgPath + "remove.png\" alt=\"");
+                out.write(_("Remove"));
+                out.write("\">");
+                if (isDegraded)
+                    out.write("</a>");
+            }
 
             if (isDegraded)
                 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>\n\t");
                 out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
-                float pct = (float) (100.0 * (float) peer.completed() / meta.getPieces());
-                if (pct == 100.0)
-                    out.write(_("Seed"));
-                else {
-                    String ps = String.valueOf(pct);
-                    if (ps.length() > 5)
-                        ps = ps.substring(0, 5);
-                    out.write(ps + "%");
+                float pct;
+                if (isValid) {
+                    pct = (float) (100.0 * (float) peer.completed() / meta.getPieces());
+                    if (pct == 100.0)
+                        out.write(_("Seed"));
+                    else {
+                        String ps = String.valueOf(pct);
+                        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 class=\"snarkTorrentStatus " + rowClass + "\">");
@@ -1031,7 +1049,7 @@ public class I2PSnarkServlet extends Default {
                 }
                 out.write("</td>\n\t");
                 out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">");
-                if (pct != 100.0) {
+                if (isValid && pct < 100.0) {
                     if (peer.isInterested() && !peer.isChoking()) {
                         out.write("<span class=\"unchoked\">");
                         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));
             return;
         }
-        _manager.addMagnet(ihash, ih);
+        _manager.addMagnet(name, ih);
     }
 
     /** copied from ConfigTunnelsHelper */
-- 
GitLab