diff --git a/apps/i2psnark/java/src/org/klomp/snark/CoordinatorListener.java b/apps/i2psnark/java/src/org/klomp/snark/CoordinatorListener.java
index a86afa781b6c32d7cd64bbd4d1d6920153c8aaa0..478c17bb507832aa2bdcd12a799513e870714380 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/CoordinatorListener.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/CoordinatorListener.java
@@ -31,6 +31,12 @@ public interface CoordinatorListener
    */
   void peerChange(PeerCoordinator coordinator, Peer peer);
 
+  /**
+   * Called when the PeerCoordinator got the MetaInfo via magnet.
+   * @since 0.8.4
+   */
+  void gotMetaInfo(PeerCoordinator coordinator, MetaInfo metainfo);
+
   public boolean overUploadLimit(int uploaders);
   public boolean overUpBWLimit();
   public boolean overUpBWLimit(long total);
diff --git a/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java b/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java
index 41cfcdf8d275c0a653dd4b3c4865ab605809dbbc..e212f6f6139b2c42019cf7db0dc841faf4eb28c4 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/ExtensionHandler.java
@@ -26,7 +26,8 @@ abstract class ExtensionHandler {
 
     public static final int ID_METADATA = 3;
     private static final String TYPE_METADATA = "ut_metadata";
-    private static final int MAX_METADATA_SIZE = Storage.MAX_PIECES * 32 * 5 / 4;
+    /** Pieces * SHA1 Hash length, + 25% extra for file names, benconding overhead, etc */
+    private static final int MAX_METADATA_SIZE = Storage.MAX_PIECES * 20 * 5 / 4;
     private static final int PARALLEL_REQUESTS = 3;
 
 
@@ -49,16 +50,16 @@ abstract class ExtensionHandler {
         return BEncoder.bencode(handshake);
     }
 
-    public static void handleMessage(Peer peer, int id, byte[] bs) {
+    public static void handleMessage(Peer peer, PeerListener listener, int id, byte[] bs) {
         if (id == 0)
-            handleHandshake(peer, bs);
+            handleHandshake(peer, listener, bs);
         else if (id == ID_METADATA)
-            handleMetadata(peer, bs);
+            handleMetadata(peer, listener, bs);
         else if (_log.shouldLog(Log.INFO))
             _log.info("Unknown extension msg " + id + " from " + peer);
     }
 
-    private static void handleHandshake(Peer peer, byte[] bs) {
+    private static void handleHandshake(Peer peer, PeerListener listener, byte[] bs) {
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Got handshake msg from " + peer);
         try {
@@ -67,11 +68,11 @@ abstract class ExtensionHandler {
             BDecoder dec = new BDecoder(is);
             BEValue bev = dec.bdecodeMap();
             Map<String, BEValue> map = bev.getMap();
-            Map<String, BEValue> msgmap = map.get("m").getMap();
             peer.setHandshakeMap(map);
+            Map<String, BEValue> msgmap = map.get("m").getMap();
 
-            // not used, just to throw out of here
-            int hisMsgCode = peer.getHandshakeMap().get("m").getMap().get(TYPE_METADATA).getInt();
+            // rv not used, just to throw an NPE to get out of here
+            msgmap.get(TYPE_METADATA).getInt();
 
             int metaSize = map.get("metadata_size").getInt();
             MagnetState state = peer.getMagnetState();
@@ -121,13 +122,12 @@ abstract class ExtensionHandler {
     private static final int TYPE_REJECT = 2;
 
     private static final int CHUNK_SIZE = 16*1024;
-    /** 25% extra for file names, benconding overhead, etc */
 
     /**
      * REF: BEP 9
      * @since 0.8.4
      */
-    private static void handleMetadata(Peer peer, byte[] bs) {
+    private static void handleMetadata(Peer peer, PeerListener listener, byte[] bs) {
         if (_log.shouldLog(Log.DEBUG))
             _log.debug("Got metadata msg from " + peer);
         try {
@@ -145,6 +145,9 @@ abstract class ExtensionHandler {
                     pc = state.getChunk(piece);
                 }
                 sendPiece(peer, piece, pc);
+                // Do this here because PeerConnectionOut only reports for PIECE messages
+                peer.uploaded(pc.length);
+                listener.uploaded(peer, pc.length);
             } else if (type == TYPE_DATA) {
                 int size = map.get("total_size").getInt();
                 boolean done;
@@ -153,6 +156,8 @@ abstract class ExtensionHandler {
                     if (state.isComplete())
                         return;
                     int len = is.available();
+                    peer.downloaded(len);
+                    listener.downloaded(peer, len);
                     done = state.saveChunk(piece, bs, bs.length - len, len);
                     if (_log.shouldLog(Log.INFO))
                         _log.info("Got chunk " + piece + " from " + peer);
@@ -189,8 +194,17 @@ abstract class ExtensionHandler {
     }
 
     private static void sendRequest(Peer peer, int piece) {
+        sendMessage(peer, TYPE_REQUEST, piece);
+    }
+
+    private static void sendReject(Peer peer, int piece) {
+        sendMessage(peer, TYPE_REJECT, piece);
+    }
+
+    /** REQUEST and REJECT are the same except for message type */
+    private static void sendMessage(Peer peer, int type, int piece) {
         Map<String, Object> map = new HashMap();
-        map.put("msg_type", TYPE_REQUEST);
+        map.put("msg_type", Integer.valueOf(type));
         map.put("piece", Integer.valueOf(piece));
         byte[] payload = BEncoder.bencode(map);
         try {
@@ -205,7 +219,7 @@ abstract class ExtensionHandler {
 
     private static void sendPiece(Peer peer, int piece, byte[] data) {
         Map<String, Object> map = new HashMap();
-        map.put("msg_type", TYPE_REQUEST);
+        map.put("msg_type", Integer.valueOf(TYPE_REQUEST));
         map.put("piece", Integer.valueOf(piece));
         map.put("total_size", Integer.valueOf(data.length));
         byte[] dict = BEncoder.bencode(map);
diff --git a/apps/i2psnark/java/src/org/klomp/snark/Peer.java b/apps/i2psnark/java/src/org/klomp/snark/Peer.java
index 681a1a5806546ded305f9a0ab61f2fe64db73a72..0f13d1470d49787b9d1fcf6950d8027dd5516c07 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/Peer.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/Peer.java
@@ -53,6 +53,10 @@ public class Peer implements Comparable
   private DataInputStream din;
   private DataOutputStream dout;
 
+  /** running counters */
+  private long downloaded;
+  private long uploaded;
+
   // Keeps state for in/out connections.  Non-null when the handshake
   // was successful, the connection setup and runs
   PeerState state;
@@ -410,10 +414,10 @@ public class Peer implements Comparable
    *  Switch from magnet mode to normal mode
    *  @since 0.8.4
    */
-  public void gotMetaInfo(MetaInfo meta) {
+  public void setMetaInfo(MetaInfo meta) {
     PeerState s = state;
     if (s != null)
-        s.gotMetaInfo(meta);
+        s.setMetaInfo(meta);
   }
 
   public boolean isConnected()
@@ -577,14 +581,29 @@ public class Peer implements Comparable
     return (s == null) || s.choked;
   }
 
+  /**
+   * Increment the counter.
+   * @since 0.8.4
+   */
+  public void downloaded(int size) {
+      downloaded += size;
+  }
+
+  /**
+   * Increment the counter.
+   * @since 0.8.4
+   */
+  public void uploaded(int size) {
+      uploaded += size;
+  }
+
   /**
    * Returns the number of bytes that have been downloaded.
    * Can be reset to zero with <code>resetCounters()</code>/
    */
   public long getDownloaded()
   {
-    PeerState s = state;
-    return (s != null) ? s.downloaded : 0;
+      return downloaded;
   }
 
   /**
@@ -593,8 +612,7 @@ public class Peer implements Comparable
    */
   public long getUploaded()
   {
-    PeerState s = state;
-    return (s != null) ? s.uploaded : 0;
+      return uploaded;
   }
 
   /**
@@ -602,12 +620,8 @@ public class Peer implements Comparable
    */
   public void resetCounters()
   {
-    PeerState s = state;
-    if (s != null)
-      {
-        s.downloaded = 0;
-        s.uploaded = 0;
-      }
+      downloaded = 0;
+      uploaded = 0;
   }
   
   public long getInactiveTime() {
diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
index 6eb730fc9dd2b4fcbb6360661aafb5d3b4a98549..0ad2c1e37261745101f07a8e7bca5677fb824308 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
@@ -45,13 +45,15 @@ public class PeerCoordinator implements PeerListener
 
   /**
    * External use by PeerMonitorTask only.
+   * Will be null when in magnet mode.
    */
-  final MetaInfo metainfo;
+  MetaInfo metainfo;
 
   /**
    * External use by PeerMonitorTask only.
+   * Will be null when in magnet mode.
    */
-  final Storage storage;
+  Storage storage;
   private final Snark snark;
 
   // package local for access by CheckDownLoadersTask
@@ -1150,7 +1152,10 @@ public class PeerCoordinator implements PeerListener
       }
   }
 
-  /** @since 0.8.4 */
+  /**
+   *  PeerListener callback
+   *  @since 0.8.4
+   */
   public void gotExtension(Peer peer, int id, byte[] bs) {
       if (_log.shouldLog(Log.DEBUG))
           _log.debug("Got extension message " + id + " from " + peer);
@@ -1160,18 +1165,29 @@ public class PeerCoordinator implements PeerListener
               if (magnetState.isComplete()) {
                   if (_log.shouldLog(Log.WARN))
                       _log.warn("Got completed metainfo via extension");
-                  MetaInfo newinfo = magnetState.getMetaInfo();
-                  // more validation
-                  // set global
-                  // instantiate storage
-                  // tell Snark listener
-                  // tell all peers
+                  metainfo = magnetState.getMetaInfo();
+                  listener.gotMetaInfo(this, metainfo);
+                  for (Peer p : peers) {
+                      p.setMetaInfo(metainfo);
+                  }
               }
           }
       }
   }
 
-  /** @since 0.8.4 */
+  /**
+   *  Sets the storage after transition out of magnet mode
+   *  Snark calls this after we call gotMetaInfo()
+   *  @since 0.8.4
+   */
+  public void setStorage(Storage stg) {
+      storage = stg;
+  }
+
+  /**
+   *  PeerListener callback
+   *  @since 0.8.4
+   */
   public void gotPort(Peer peer, int port) {
       // send to DHT
   }
diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java
index a85207476b9a58def420f982de2cf693d9337dca..4164e310a21936c38792407a8636e0f2c4fc4af3 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java
@@ -36,8 +36,9 @@ class PeerState implements DataLoader
 {
   private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerState.class);
   private final Peer peer;
+  /** Fixme, used by Peer.disconnect() to get to the coordinator */
   final PeerListener listener;
-  private final MetaInfo metainfo;
+  private MetaInfo metainfo;
 
   // Interesting and choking describes whether we are interested in or
   // are choking the other side.
@@ -49,10 +50,6 @@ class PeerState implements DataLoader
   boolean interested = false;
   boolean choked = true;
 
-  // Package local for use by Peer.
-  long downloaded;
-  long uploaded;
-
   /** the pieces the peer has */
   BitField bitfield;
 
@@ -285,7 +282,7 @@ class PeerState implements DataLoader
    */
   void uploaded(int size)
   {
-    uploaded += size;
+    peer.uploaded(size);
     listener.uploaded(peer, size);
   }
 
@@ -305,7 +302,7 @@ class PeerState implements DataLoader
   void pieceMessage(Request req)
   {
     int size = req.len;
-    downloaded += size;
+    peer.downloaded(size);
     listener.downloaded(peer, size);
 
     if (_log.shouldLog(Log.DEBUG))
@@ -326,9 +323,6 @@ class PeerState implements DataLoader
           {
             if (_log.shouldLog(Log.WARN))
               _log.warn("Got BAD " + req.piece + " from " + peer);
-            // XXX ARGH What now !?!
-            // FIXME Why would we set downloaded to 0?
-            downloaded = 0;
           }
       }
 
@@ -372,7 +366,6 @@ class PeerState implements DataLoader
           _log.info("Unrequested 'piece: " + piece + ", "
                       + begin + ", " + length + "' received from "
                       + peer);
-        downloaded = 0; // XXX - punishment?
         return null;
       }
 
@@ -397,7 +390,6 @@ class PeerState implements DataLoader
                           + begin + ", "
                           + length + "' received from "
                           + peer);
-            downloaded = 0; // XXX - punishment?
             return null;
           }
 
@@ -497,7 +489,7 @@ class PeerState implements DataLoader
   /** @since 0.8.2 */
   void extensionMessage(int id, byte[] bs)
   {
-      ExtensionHandler.handleMessage(peer, id, bs);
+      ExtensionHandler.handleMessage(peer, listener, id, bs);
       // Peer coord will get metadata from MagnetState,
       // verify, and then call gotMetaInfo()
       listener.gotExtension(peer, id, bs);
@@ -507,9 +499,18 @@ class PeerState implements DataLoader
    *  Switch from magnet mode to normal mode
    *  @since 0.8.4
    */
-  public void gotMetaInfo(MetaInfo meta) {
-      // set metainfo
-      // fix bitfield
+  public void setMetaInfo(MetaInfo meta) {
+      BitField oldBF = bitfield;
+      if (oldBF != null) {
+          if (oldBF.size() != meta.getPieces())
+              // fix bitfield, it was too big by 1-7 bits
+              bitfield = new BitField(oldBF.getFieldBytes(), meta.getPieces());
+          // else no extra
+      } else {
+          // it will be initialized later
+          //bitfield = new BitField(meta.getPieces());
+      }
+      metainfo = meta;
   }
 
   /** @since 0.8.4 */
diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
index fd7a88b57a43532ed2168997f2b9b1ca311987c4..bd3d0d20dd29238da2afc621d75c0b425ddca592 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
@@ -1004,6 +1004,30 @@ public class Snark
     // System.out.println(peer.toString());
   }
   
+  /**
+   * Called when the PeerCoordinator got the MetaInfo via magnet.
+   * CoordinatorListener.
+   * Create the storage, tell SnarkManager, and give the storage
+   * back to the coordinator.
+   *
+   * @throws RuntimeException via fatal()
+   * @since 0.8.4
+   */
+  public void gotMetaInfo(PeerCoordinator coordinator, MetaInfo metainfo) {
+      meta = metainfo;
+      try {
+          storage = new Storage(_util, meta, this);
+          if (completeListener != null)
+              completeListener.gotMetaInfo(this);
+          coordinator.setStorage(storage);
+      } catch (IOException ioe) {
+          if (storage != null) {
+              try { storage.close(); } catch (IOException ioee) {}
+          }
+          fatal("Could not check or create storage", ioe);
+      }
+  }
+
   private boolean allocating = false;
   public void storageCreateFile(Storage storage, String name, long length)
   {
diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index d5a51c584c7449b1ef1e10e8dc9e70d188121bbf..c1410e7fa47fc76a876888ec05cab46e4741e368 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -573,9 +573,11 @@ public class SnarkManager implements Snark.CompleteListener {
                     
                     if (!TrackerClient.isValidAnnounce(info.getAnnounce())) {
                         if (_util.shouldUseOpenTrackers() && _util.getOpenTrackers() != null) {
-                            addMessage(_("Warning - Ignoring non-i2p tracker in \"{0}\", will announce to i2p open trackers only", info.getName()));
+                            addMessage(_("Warning - No I2P trackers in \"{0}\", will announce to I2P open trackers and DHT only.", info.getName()));
+                        } else if (_util.getDHT() != null) {
+                            addMessage(_("Warning - No I2P trackers in \"{0}\", and open trackers are disabled, will announce to DHT only.", info.getName()));
                         } else {
-                            addMessage(_("Warning - Ignoring non-i2p tracker in \"{0}\", and open trackers are disabled, you must enable open trackers before starting the torrent!", info.getName()));
+                            addMessage(_("Warning - No I2P trackers in \"{0}\", and DHT and open trackers are disabled, you should enable open trackers or DHT before starting the torrent.", info.getName()));
                             dontAutoStart = true;
                         }
                     }