From 4899a6d306d644fd880d3a062b5fd720c8eaefe3 Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sun, 19 Dec 2010 22:14:02 +0000
Subject: [PATCH] Refactor fields to private and replace with getters, and lots
 of prep for lack of metainfo and storage.

---
 .../src/org/klomp/snark/PeerAcceptor.java     |   2 +-
 .../src/org/klomp/snark/PeerCheckerTask.java  |   3 -
 .../src/org/klomp/snark/PeerCoordinator.java  |  58 +++-
 .../java/src/org/klomp/snark/Snark.java       | 263 ++++++++++++++++--
 .../src/org/klomp/snark/SnarkManager.java     |  73 +++--
 .../java/src/org/klomp/snark/StaticSnark.java |   3 +-
 .../src/org/klomp/snark/TrackerClient.java    |  30 +-
 .../org/klomp/snark/web/I2PSnarkServlet.java  | 140 +++++-----
 8 files changed, 409 insertions(+), 163 deletions(-)

diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java b/apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java
index 58ef3ae2db..050884e5c0 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerAcceptor.java
@@ -120,7 +120,7 @@ public class PeerAcceptor
                 else 
                   {
                     if (_log.shouldLog(Log.DEBUG))
-                      _log.debug("Rejecting new peer for " + cur.snark.torrent);
+                      _log.debug("Rejecting new peer for " + cur.getName());
                     socket.close();
                     return;
                   }
diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java
index aa9cf2187d..d6e2c60895 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCheckerTask.java
@@ -51,10 +51,7 @@ class PeerCheckerTask extends TimerTask
   {
         List<Peer> peerList = coordinator.peerList();
         if (peerList.isEmpty() || coordinator.halted()) {
-          coordinator.peerCount = 0;
-          coordinator.interestedAndChoking = 0;
           coordinator.setRateHistory(0, 0);
-          coordinator.uploaders = 0;
           if (coordinator.halted())
             cancel();
           return;
diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
index c9cdf61419..ba9727d8a6 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java
@@ -42,18 +42,33 @@ import net.i2p.util.SimpleTimer2;
 public class PeerCoordinator implements PeerListener
 {
   private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(PeerCoordinator.class);
+
+  /**
+   * External use by PeerMonitorTask only.
+   */
   final MetaInfo metainfo;
+
+  /**
+   * External use by PeerMonitorTask only.
+   */
   final Storage storage;
-  final Snark snark;
+  private final Snark snark;
 
   // package local for access by CheckDownLoadersTask
   final static long CHECK_PERIOD = 40*1000; // 40 seconds
   final static int MAX_UPLOADERS = 6;
 
-  // Approximation of the number of current uploaders.
-  // Resynced by PeerChecker once in a while.
-  int uploaders = 0;
-  int interestedAndChoking = 0;
+  /**
+   * Approximation of the number of current uploaders.
+   * Resynced by PeerChecker once in a while.
+   * External use by PeerCheckerTask only.
+   */
+  int uploaders;
+
+  /**
+   * External use by PeerCheckerTask only.
+   */
+  int interestedAndChoking;
 
   // final static int MAX_DOWNLOADERS = MAX_CONNECTIONS;
   // int downloaders = 0;
@@ -61,14 +76,18 @@ public class PeerCoordinator implements PeerListener
   private long uploaded;
   private long downloaded;
   final static int RATE_DEPTH = 3; // make following arrays RATE_DEPTH long
-  private long uploaded_old[] = {-1,-1,-1};
-  private long downloaded_old[] = {-1,-1,-1};
+  private final long uploaded_old[] = {-1,-1,-1};
+  private final long downloaded_old[] = {-1,-1,-1};
 
-  // synchronize on this when changing peers or downloaders
-  // This is a Queue, not a Set, because PeerCheckerTask keeps things in order for choking/unchoking
+  /**
+   * synchronize on this when changing peers or downloaders.
+   * This is a Queue, not a Set, because PeerCheckerTask keeps things in order for choking/unchoking.
+   * External use by PeerMonitorTask only.
+   */
   final Queue<Peer> peers;
+
   /** estimate of the peers, without requiring any synchronization */
-  volatile int peerCount;
+  private volatile int peerCount;
 
   /** Timer to handle all periodical tasks. */
   private final CheckEvent timer;
@@ -86,12 +105,9 @@ public class PeerCoordinator implements PeerListener
   private boolean halted = false;
 
   private final CoordinatorListener listener;
-  public I2PSnarkUtil _util;
+  private final I2PSnarkUtil _util;
   private static final Random _random = I2PAppContext.getGlobalContext().random();
   
-  public String trackerProblems = null;
-  public int trackerSeenPeers = 0;
-
   public PeerCoordinator(I2PSnarkUtil util, byte[] id, MetaInfo metainfo, Storage storage,
                          CoordinatorListener listener, Snark torrent)
   {
@@ -153,7 +169,6 @@ public class PeerCoordinator implements PeerListener
   }
 
   public Storage getStorage() { return storage; }
-  public CoordinatorListener getListener() { return listener; }
 
   // for web page detailed stats
   public List<Peer> peerList()
@@ -166,6 +181,11 @@ public class PeerCoordinator implements PeerListener
     return id;
   }
 
+  public String getName()
+  {
+    return snark.getName();
+  }
+
   public boolean completed()
   {
     return storage.complete();
@@ -1107,6 +1127,14 @@ public class PeerCoordinator implements PeerListener
         return MAX_UPLOADERS;
   }
 
+  /**
+   *  @return current
+   *  @since 0.8.4
+   */
+  public int getUploaders() {
+      return uploaders;
+  }
+
   public boolean overUpBWLimit()
   {
     if (listener != null)
diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
index 31105a2693..79807d68f2 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java
@@ -26,6 +26,7 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Properties;
@@ -112,6 +113,8 @@ public class Snark
       
   }
   
+/******** No, not maintaining a command-line client
+
   public static void main(String[] args)
   {
     System.out.println(copyright);
@@ -235,19 +238,27 @@ public class Snark
       }
   }
 
+***********/
+
   public static final String PROP_MAX_CONNECTIONS = "i2psnark.maxConnections";
-  public String torrent;
-  public MetaInfo meta;
-  public Storage storage;
-  public PeerCoordinator coordinator;
-  public ConnectionAcceptor acceptor;
-  public TrackerClient trackerclient;
-  public String rootDataDir = ".";
-  public CompleteListener completeListener;
-  public boolean stopped;
-  byte[] id;
-  public I2PSnarkUtil _util;
-  private PeerCoordinatorSet _peerCoordinatorSet;
+
+  /** most of these used to be public, use accessors below instead */
+  private final String torrent;
+  private MetaInfo meta;
+  private Storage storage;
+  private PeerCoordinator coordinator;
+  private ConnectionAcceptor acceptor;
+  private TrackerClient trackerclient;
+  private String rootDataDir = ".";
+  private final CompleteListener completeListener;
+  private boolean stopped;
+  private byte[] id;
+  private byte[] infoHash;
+  private final I2PSnarkUtil _util;
+  private final PeerCoordinatorSet _peerCoordinatorSet;
+  private String trackerProblems;
+  private int trackerSeenPeers;
+
 
   /** from main() via parseArguments() single torrent */
   Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
@@ -486,7 +497,7 @@ public class Snark
             // single torrent
             acceptor = new ConnectionAcceptor(_util, serversocket, new PeerAcceptor(coordinator));
         }
-        trackerclient = new TrackerClient(_util, meta, coordinator);
+        trackerclient = new TrackerClient(_util, meta, coordinator, this);
     }
 
     stopped = false;
@@ -496,8 +507,7 @@ public class Snark
         // restart safely, so lets build a new one to replace the old
         if (_peerCoordinatorSet != null)
             _peerCoordinatorSet.remove(coordinator);
-        PeerCoordinator newCoord = new PeerCoordinator(_util, coordinator.getID(), coordinator.getMetaInfo(), 
-                                                       coordinator.getStorage(), coordinator.getListener(), this);
+        PeerCoordinator newCoord = new PeerCoordinator(_util, id, meta, storage, this, this);
         if (_peerCoordinatorSet != null)
             _peerCoordinatorSet.add(newCoord);
         coordinator = newCoord;
@@ -517,7 +527,7 @@ public class Snark
             }
             fatal("Could not reopen storage", ioe);
           }
-        TrackerClient newClient = new TrackerClient(_util, coordinator.getMetaInfo(), coordinator);
+        TrackerClient newClient = new TrackerClient(_util, coordinator.getMetaInfo(), coordinator, this);
         if (!trackerclient.halted())
             trackerclient.halt();
         trackerclient = newClient;
@@ -553,18 +563,223 @@ public class Snark
         _util.disconnect();
   }
 
-  static Snark parseArguments(String[] args)
+  private static Snark parseArguments(String[] args)
   {
     return parseArguments(args, null, null);
   }
 
+    // Accessors
+
+    /**
+     *  @return file name of .torrent file (should be full absolute path), or a fake name if in magnet mode.
+     *  @since 0.8.4
+     */
+    public String getName() {
+        return torrent;
+    }
+
+    /**
+     *  @return base name of torrent [filtered version of getMetaInfo.getName()], or a fake name if in magnet mode
+     *  @since 0.8.4
+     */
+    public String getBaseName() {
+        if (storage != null)
+            return storage.getBaseName();
+        return torrent;
+    }
+
+    /**
+     *  @return always will be valid even in magnet mode
+     *  @since 0.8.4
+     */
+    public byte[] getID() {
+        return id;
+    }
+
+    /**
+     *  @return always will be valid even in magnet mode
+     *  @since 0.8.4
+     */
+    public byte[] getInfoHash() {
+        if (meta != null)
+            return meta.getInfoHash();
+        return infoHash;
+    }
+
+    /**
+     *  @return may be null if in magnet mode
+     *  @since 0.8.4
+     */
+    public MetaInfo getMetaInfo() {
+        return meta;
+    }
+
+    /**
+     *  @return may be null if in magnet mode
+     *  @since 0.8.4
+     */
+    public Storage getStorage() {
+        return storage;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public boolean isStopped() {
+        return stopped;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public long getDownloadRate() {
+        PeerCoordinator coord = coordinator;
+        if (coord != null)
+            return coord.getDownloadRate();
+        return 0;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public long getUploadRate() {
+        PeerCoordinator coord = coordinator;
+        if (coord != null)
+            return coord.getUploadRate();
+        return 0;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public long getDownloaded() {
+        PeerCoordinator coord = coordinator;
+        if (coord != null)
+            return coord.getDownloaded();
+        return 0;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public long getUploaded() {
+        PeerCoordinator coord = coordinator;
+        if (coord != null)
+            return coord.getUploaded();
+        return 0;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public int getPeerCount() {
+        PeerCoordinator coord = coordinator;
+        if (coord != null)
+            return coord.getPeerCount();
+        return 0;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public List<Peer> getPeerList() {
+        PeerCoordinator coord = coordinator;
+        if (coord != null)
+            return coord.peerList();
+        return Collections.EMPTY_LIST;
+    }
+
+    /**
+     *  @return String returned from tracker, or null if no error
+     *  @since 0.8.4
+     */
+    public String getTrackerProblems() {
+        return trackerProblems;
+    }
+
+    /**
+     *  @param p tracker error string or null
+     *  @since 0.8.4
+     */
+    public void setTrackerProblems(String p) {
+        trackerProblems = p;
+    }
+
+    /**
+     *  @return count returned from tracker
+     *  @since 0.8.4
+     */
+    public int getTrackerSeenPeers() {
+        return trackerSeenPeers;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public void setTrackerSeenPeers(int p) {
+        trackerSeenPeers = p;
+    }
+
+    /**
+     *  @since 0.8.4
+     */
+    public void updatePiecePriorities() {
+        PeerCoordinator coord = coordinator;
+        if (coord != null)
+            coord.updatePiecePriorities();
+    }
+
+    /**
+     *  @return total of all torrent files, or total of metainfo file if fetching magnet, or -1
+     *  @since 0.8.4
+     */
+    public long getTotalLength() {
+        if (meta != null)
+            return meta.getTotalLength();
+        // FIXME else return metainfo length if available
+        return -1;
+    }
+
+    /**
+     *  @return needed of all torrent files, or total of metainfo file if fetching magnet, or -1
+     *  @since 0.8.4
+     */
+    public long getNeeded() {
+        if (storage != null)
+            return storage.needed();
+        // FIXME else return metainfo length if available
+        return -1;
+    }
+
+    /**
+     *  @param p the piece number
+     *  @return metainfo piece length or 16K if fetching magnet
+     *  @since 0.8.4
+     */
+    public int getPieceLength(int p) {
+        if (meta != null)
+            return meta.getPieceLength(p);
+        return 16*1024;
+    }
+
+    /**
+     *  @return true if restarted
+     *  @since 0.8.4
+     */
+    public boolean restartAcceptor() {
+        if (acceptor == null)
+            return false;
+        acceptor.restart();
+        return true;
+    }
+
   /**
    * Sets debug, ip and torrent variables then creates a Snark
    * instance.  Calls usage(), which terminates the program, if
    * non-valid argument list.  The given listeners will be
    * passed to all components that take one.
    */
-  static Snark parseArguments(String[] args,
+  private static Snark parseArguments(String[] args,
                               StorageListener slistener,
                               CoordinatorListener clistener)
   {
@@ -719,7 +934,7 @@ public class Snark
   /**
    * Aborts program abnormally.
    */
-  public void fatal(String s)
+  private void fatal(String s)
   {
     fatal(s, null);
   }
@@ -727,7 +942,7 @@ public class Snark
   /**
    * Aborts program abnormally.
    */
-  public void fatal(String s, Throwable t)
+  private void fatal(String s, Throwable t)
   {
     _util.debug(s, ERROR, t);
     //System.err.println("snark: " + s + ((t == null) ? "" : (": " + t)));
@@ -751,7 +966,7 @@ public class Snark
     // System.out.println(peer.toString());
   }
   
-  boolean allocating = false;
+  private boolean allocating = false;
   public void storageCreateFile(Storage storage, String name, long length)
   {
     //if (allocating)
@@ -774,9 +989,9 @@ public class Snark
     //  System.out.println(); // We have all the disk space we need.
   }
 
-  boolean allChecked = false;
-  boolean checking = false;
-  boolean prechecking = true;
+  private boolean allChecked = false;
+  private boolean checking = false;
+  private boolean prechecking = true;
   public void storageChecked(Storage storage, int num, boolean checked)
   {
     allocating = false;
diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
index 82d1d80f4f..6a4eb4c7c5 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java
@@ -359,7 +359,7 @@ public class SnarkManager implements Snark.CompleteListener {
                 Set names = listTorrentFiles();
                 for (Iterator iter = names.iterator(); iter.hasNext(); ) {
                     Snark snark = getTorrent((String)iter.next());
-                    if ( (snark != null) && (!snark.stopped) ) {
+                    if ( (snark != null) && (!snark.isStopped()) ) {
                         snarksActive = true;
                         break;
                     }
@@ -398,9 +398,8 @@ public class SnarkManager implements Snark.CompleteListener {
                         for (Iterator iter = names.iterator(); iter.hasNext(); ) {
                             String name = (String)iter.next();
                             Snark snark = getTorrent(name);
-                            if ( (snark != null) && (snark.acceptor != null) ) {
-                                snark.acceptor.restart();
-                                addMessage(_("I2CP listener restarted for \"{0}\"", snark.meta.getName()));
+                            if (snark != null && snark.restartAcceptor()) {
+                                addMessage(_("I2CP listener restarted for \"{0}\"", snark.getBaseName()));
                             }
                         }
                     }
@@ -478,7 +477,7 @@ public class SnarkManager implements Snark.CompleteListener {
     public Snark getTorrentByBaseName(String filename) {
         synchronized (_snarks) {
             for (Snark s : _snarks.values()) {
-                if (s.storage.getBaseName().equals(filename))
+                if (s.getBaseName().equals(filename))
                     return s;
             }
         }
@@ -554,7 +553,6 @@ public class SnarkManager implements Snark.CompleteListener {
                                             _peerCoordinatorSet, _connectionAcceptor,
                                             false, dataDir.getPath());
                         loadSavedFilePriorities(torrent);
-                        torrent.completeListener = this;
                         synchronized (_snarks) {
                             _snarks.put(filename, torrent);
                         }
@@ -572,12 +570,11 @@ public class SnarkManager implements Snark.CompleteListener {
             return;
         }
         // ok, snark created, now lets start it up or configure it further
-        File f = new File(filename);
         if (!dontAutoStart && shouldAutoStart()) {
             torrent.startTorrent();
-            addMessage(_("Torrent added and started: \"{0}\"", torrent.storage.getBaseName()));
+            addMessage(_("Torrent added and started: \"{0}\"", torrent.getBaseName()));
         } else {
-            addMessage(_("Torrent added: \"{0}\"", torrent.storage.getBaseName()));
+            addMessage(_("Torrent added: \"{0}\"", torrent.getBaseName()));
         }
     }
     
@@ -585,8 +582,7 @@ public class SnarkManager implements Snark.CompleteListener {
      * Get the timestamp for a torrent from the config file
      */
     public long getSavedTorrentTime(Snark snark) {
-        MetaInfo metainfo = snark.meta;
-        byte[] ih = metainfo.getInfoHash();
+        byte[] ih = snark.getInfoHash();
         String infohash = Base64.encode(ih);
         infohash = infohash.replace('=', '$');
         String time = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
@@ -605,8 +601,10 @@ public class SnarkManager implements Snark.CompleteListener {
      * Convert "." to a full bitfield.
      */
     public BitField getSavedTorrentBitField(Snark snark) {
-        MetaInfo metainfo = snark.meta;
-        byte[] ih = metainfo.getInfoHash();
+        MetaInfo metainfo = snark.getMetaInfo();
+        if (metainfo == null)
+            return null;
+        byte[] ih = snark.getInfoHash();
         String infohash = Base64.encode(ih);
         infohash = infohash.replace('=', '$');
         String bf = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX);
@@ -636,10 +634,13 @@ public class SnarkManager implements Snark.CompleteListener {
      * @since 0.8.1
      */
     public void loadSavedFilePriorities(Snark snark) {
-        MetaInfo metainfo = snark.meta;
+        MetaInfo metainfo = snark.getMetaInfo();
+        Storage storage = snark.getStorage();
+        if (metainfo == null || storage == null)
+            return;
         if (metainfo.getFiles() == null)
             return;
-        byte[] ih = metainfo.getInfoHash();
+        byte[] ih = snark.getInfoHash();
         String infohash = Base64.encode(ih);
         infohash = infohash.replace('=', '$');
         String pri = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_PRIORITY_SUFFIX);
@@ -655,7 +656,7 @@ public class SnarkManager implements Snark.CompleteListener {
                 } catch (Throwable t) {}
             }
         }
-        snark.storage.setFilePriorities(rv);
+        storage.setFilePriorities(rv);
     }
     
     /**
@@ -777,21 +778,15 @@ public class SnarkManager implements Snark.CompleteListener {
             remaining = _snarks.size();
         }
         if (torrent != null) {
-            boolean wasStopped = torrent.stopped;
+            boolean wasStopped = torrent.isStopped();
             torrent.stopTorrent();
             if (remaining == 0) {
                 // should we disconnect/reconnect here (taking care to deal with the other thread's
                 // I2PServerSocket.accept() call properly?)
                 ////_util.
             }
-            String name;
-            if (torrent.storage != null) {
-                name = torrent.storage.getBaseName();
-            } else {
-                name = sfile.getName();
-            }
             if (!wasStopped)
-                addMessage(_("Torrent stopped: \"{0}\"", name));
+                addMessage(_("Torrent stopped: \"{0}\"", torrent.getBaseName()));
         }
         return torrent;
     }
@@ -804,14 +799,10 @@ public class SnarkManager implements Snark.CompleteListener {
         if (torrent != null) {
             File torrentFile = new File(filename);
             torrentFile.delete();
-            String name;
-            if (torrent.storage != null) {
-                removeTorrentStatus(torrent.storage.getMetaInfo());
-                name = torrent.storage.getBaseName();
-            } else {
-                name = torrentFile.getName();
-            }
-            addMessage(_("Torrent removed: \"{0}\"", name));
+            Storage storage = torrent.getStorage();
+            if (storage != null)
+                removeTorrentStatus(storage.getMetaInfo());
+            addMessage(_("Torrent removed: \"{0}\"", torrent.getBaseName()));
         }
     }
     
@@ -843,18 +834,24 @@ public class SnarkManager implements Snark.CompleteListener {
     
     /** two listeners */
     public void torrentComplete(Snark snark) {
+        MetaInfo meta = snark.getMetaInfo();
+        Storage storage = snark.getStorage();
+        if (meta == null || storage == null)
+            return;
         StringBuilder buf = new StringBuilder(256);
-        buf.append("<a href=\"/i2psnark/").append(snark.storage.getBaseName());
-        if (snark.meta.getFiles() != null)
+        buf.append("<a href=\"/i2psnark/").append(storage.getBaseName());
+        if (meta.getFiles() != null)
             buf.append('/');
-        buf.append("\">").append(snark.storage.getBaseName()).append("</a>");
-        long len = snark.meta.getTotalLength();
+        buf.append("\">").append(storage.getBaseName()).append("</a>");
         addMessage(_("Download finished: {0}", buf.toString())); //  + " (" + _("size: {0}B", DataHelper.formatSize2(len)) + ')');
         updateStatus(snark);
     }
     
     public void updateStatus(Snark snark) {
-        saveTorrentStatus(snark.meta, snark.storage.getBitField(), snark.storage.getFilePriorities());
+        MetaInfo meta = snark.getMetaInfo();
+        Storage storage = snark.getStorage();
+        if (meta != null && storage != null)
+            saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities());
     }
     
     private void monitorTorrents(File dir) {
@@ -984,7 +981,7 @@ public class SnarkManager implements Snark.CompleteListener {
             Set names = listTorrentFiles();
             for (Iterator iter = names.iterator(); iter.hasNext(); ) {
                 Snark snark = getTorrent((String)iter.next());
-                if ( (snark != null) && (!snark.stopped) )
+                if ( (snark != null) && (!snark.isStopped()) )
                     snark.stopTorrent();
             }
         }
diff --git a/apps/i2psnark/java/src/org/klomp/snark/StaticSnark.java b/apps/i2psnark/java/src/org/klomp/snark/StaticSnark.java
index 38b470a7c9..52bef12b47 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/StaticSnark.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/StaticSnark.java
@@ -38,6 +38,7 @@ public class StaticSnark
     //Security.addProvider(gnu);
 
     // And finally call the normal starting point.
-    Snark.main(args);
+    //Snark.main(args);
+    System.err.println("unsupported");
   }
 }
diff --git a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
index a1a3f4cc21..6bded21008 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/TrackerClient.java
@@ -34,9 +34,11 @@ import java.util.Random;
 import java.util.Set;
 
 import net.i2p.I2PAppContext;
+import net.i2p.data.Hash;
 import net.i2p.util.I2PAppThread;
 import net.i2p.util.Log;
 
+
 /**
  * Informs metainfo tracker of events and gets new peers for peer
  * coordinator.
@@ -63,6 +65,7 @@ public class TrackerClient extends I2PAppThread
   private I2PSnarkUtil _util;
   private final MetaInfo meta;
   private final PeerCoordinator coordinator;
+  private final Snark snark;
   private final int port;
 
   private boolean stop;
@@ -70,15 +73,16 @@ public class TrackerClient extends I2PAppThread
 
   private List trackers;
 
-  public TrackerClient(I2PSnarkUtil util, MetaInfo meta, PeerCoordinator coordinator)
+  public TrackerClient(I2PSnarkUtil util, MetaInfo meta, PeerCoordinator coordinator, Snark snark)
   {
     super();
     // Set unique name.
-    String id = urlencode(coordinator.getID());
+    String id = urlencode(snark.getID());
     setName("TrackerClient " + id.substring(id.length() - 12));
     _util = util;
     this.meta = meta;
     this.coordinator = coordinator;
+    this.snark = snark;
 
     this.port = 6881; //(port == -1) ? 9 : port;
 
@@ -119,10 +123,10 @@ public class TrackerClient extends I2PAppThread
   public void run()
   {
     String infoHash = urlencode(meta.getInfoHash());
-    String peerID = urlencode(coordinator.getID());
+    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,
     // followed by the secondary open trackers
@@ -200,7 +204,7 @@ public class TrackerClient extends I2PAppThread
                   firstTime = false;
                 } else if (completed && runStarted)
                   delay = 3*SLEEP*60*1000 + random;
-                else if (coordinator.trackerProblems != null && ++consecutiveFails < MAX_CONSEC_FAILS)
+                else if (snark.getTrackerProblems() != null && ++consecutiveFails < MAX_CONSEC_FAILS)
                   delay = INITIAL_SLEEP;
                 else
                   // sleep a while, when we wake up we will contact only the trackers whose intervals have passed
@@ -251,7 +255,7 @@ public class TrackerClient extends I2PAppThread
                                                  uploaded, downloaded, left,
                                                  event);
 
-                    coordinator.trackerProblems = null;
+                    snark.setTrackerProblems(null);
                     tr.trackerProblems = null;
                     tr.registerFails = 0;
                     tr.consecutiveFails = 0;
@@ -262,8 +266,8 @@ public class TrackerClient extends I2PAppThread
 
                     Set peers = info.getPeers();
                     tr.seenPeers = info.getPeerCount();
-                    if (coordinator.trackerSeenPeers < tr.seenPeers) // update rising number quickly
-                        coordinator.trackerSeenPeers = tr.seenPeers;
+                    if (snark.getTrackerSeenPeers() < tr.seenPeers) // update rising number quickly
+                        snark.setTrackerSeenPeers(tr.seenPeers);
                     if ( (left > 0) && (!completed) ) {
                         // we only want to talk to new people if we need things
                         // from them (duh)
@@ -293,12 +297,12 @@ public class TrackerClient extends I2PAppThread
                     tr.trackerProblems = ioe.getMessage();
                     // don't show secondary tracker problems to the user
                     if (tr.isPrimary)
-                      coordinator.trackerProblems = tr.trackerProblems;
+                      snark.setTrackerProblems(tr.trackerProblems);
                     if (tr.trackerProblems.toLowerCase().startsWith(NOT_REGISTERED)) {
                       // Give a guy some time to register it if using opentrackers too
                       if (trackers.size() == 1) {
                         stop = true;
-                        coordinator.snark.stopTorrent();
+                        snark.stopTorrent();
                       } else { // hopefully each on the opentrackers list is really open
                         if (tr.registerFails++ > MAX_REGISTER_FAILS)
                           tr.stop = true;
@@ -316,7 +320,7 @@ public class TrackerClient extends I2PAppThread
             }  // *** end of trackers loop here
 
             // we could try and total the unique peers but that's too hard for now
-            coordinator.trackerSeenPeers = maxSeenPeers;
+            snark.setTrackerSeenPeers(maxSeenPeers);
             if (!runStarted)
                 _util.debug("         Retrying in one minute...", Snark.DEBUG);
           } // *** end of while loop
@@ -377,8 +381,8 @@ public class TrackerClient extends I2PAppThread
     try {
         in = new FileInputStream(fetched);
 
-        TrackerInfo info = new TrackerInfo(in, coordinator.getID(),
-                                           coordinator.getMetaInfo());
+        TrackerInfo info = new TrackerInfo(in, snark.getID(),
+                                           snark.getMetaInfo());
         _util.debug("TrackerClient response: " + info, Snark.INFO);
 
         String failure = info.getFailureReason();
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 d74426ee12..57e8bd4461 100644
--- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
+++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java
@@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import net.i2p.I2PAppContext;
+import net.i2p.data.Base32;
 import net.i2p.data.Base64;
 import net.i2p.data.DataHelper;
 import net.i2p.util.FileUtil;
@@ -361,7 +362,7 @@ public class I2PSnarkServlet extends Default {
         for (int i = 0; i < snarks.size(); i++) {
             Snark snark = (Snark)snarks.get(i);
             boolean showDebug = "2".equals(peerParam);
-            boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam);
+            boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.getInfoHash()).equals(peerParam);
             displaySnark(out, snark, uri, i, stats, showPeers, isDegraded, showDebug);
         }
 
@@ -452,7 +453,7 @@ public class I2PSnarkServlet extends Default {
             if (newURL != null) {
                 if (newURL.startsWith("http://")) {
                     _manager.addMessage(_("Fetching {0}", urlify(newURL)));
-                    I2PAppThread fetch = new I2PAppThread(new FetchAndAdd(_manager, newURL), "Fetch and add");
+                    I2PAppThread fetch = new I2PAppThread(new FetchAndAdd(_manager, newURL), "Fetch and add", true);
                     fetch.start();
                 } else {
                     _manager.addMessage(_("Invalid URL - must start with http://"));
@@ -468,7 +469,7 @@ public class I2PSnarkServlet extends Default {
                     for (Iterator iter = _manager.listTorrentFiles().iterator(); iter.hasNext(); ) {
                         String name = (String)iter.next();
                         Snark snark = _manager.getTorrent(name);
-                        if ( (snark != null) && (DataHelper.eq(infoHash, snark.meta.getInfoHash())) ) {
+                        if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
                             _manager.stopTorrent(name, false);
                             break;
                         }
@@ -482,11 +483,9 @@ public class I2PSnarkServlet extends Default {
                 if ( (infoHash != null) && (infoHash.length == 20) ) { // valid sha1
                     for (String name : _manager.listTorrentFiles()) {
                         Snark snark = _manager.getTorrent(name);
-                        if ( (snark != null) && (DataHelper.eq(infoHash, snark.meta.getInfoHash())) ) {
+                        if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
                             snark.startTorrent();
-                            if (snark.storage != null)
-                                name = snark.storage.getBaseName();
-                            _manager.addMessage(_("Starting up torrent {0}", name));
+                            _manager.addMessage(_("Starting up torrent {0}", snark.getBaseName()));
                             break;
                         }
                     }
@@ -500,8 +499,12 @@ public class I2PSnarkServlet extends Default {
                     for (Iterator iter = _manager.listTorrentFiles().iterator(); iter.hasNext(); ) {
                         String name = (String)iter.next();
                         Snark snark = _manager.getTorrent(name);
-                        if ( (snark != null) && (DataHelper.eq(infoHash, snark.meta.getInfoHash())) ) {
+                        if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
                             _manager.stopTorrent(name, true);
+                            MetaInfo meta = snark.getMetaInfo();
+                            if (meta == null) {
+                                return;
+                            }
                             // should we delete the torrent file?
                             // yeah, need to, otherwise it'll get autoadded again (at the moment
                             File f = new File(name);
@@ -520,13 +523,17 @@ public class I2PSnarkServlet extends Default {
                     for (Iterator iter = _manager.listTorrentFiles().iterator(); iter.hasNext(); ) {
                         String name = (String)iter.next();
                         Snark snark = _manager.getTorrent(name);
-                        if ( (snark != null) && (DataHelper.eq(infoHash, snark.meta.getInfoHash())) ) {
+                        if ( (snark != null) && (DataHelper.eq(infoHash, snark.getInfoHash())) ) {
                             _manager.stopTorrent(name, true);
+                            MetaInfo meta = snark.getMetaInfo();
+                            if (meta == null) {
+                                return;
+                            }
                             File f = new File(name);
                             f.delete();
                             _manager.addMessage(_("Torrent file deleted: {0}", f.getAbsolutePath()));
-                            List files = snark.meta.getFiles();
-                            String dataFile = snark.meta.getName();
+                            List files = meta.getFiles();
+                            String dataFile = snark.getBaseName();
                             f = new File(_manager.getDataDir(), dataFile);
                             if (files == null) { // single file torrent
                                 if (f.delete())
@@ -617,8 +624,8 @@ public class I2PSnarkServlet extends Default {
             List snarks = getSortedSnarks(req);
             for (int i = 0; i < snarks.size(); i++) {
                 Snark snark = (Snark)snarks.get(i);
-                if (!snark.stopped)
-                    _manager.stopTorrent(snark.torrent, false);
+                if (!snark.isStopped())
+                    _manager.stopTorrent(snark.getName(), false);
             }
             if (_manager.util().connected()) {
                 // Give the stopped announces time to get out
@@ -631,7 +638,7 @@ public class I2PSnarkServlet extends Default {
             List snarks = getSortedSnarks(req);
             for (int i = 0; i < snarks.size(); i++) {
                 Snark snark = (Snark)snarks.get(i);
-                if (snark.stopped)
+                if (snark.isStopped())
                     snark.startTorrent();
             }
         } else {
@@ -699,7 +706,7 @@ public class I2PSnarkServlet extends Default {
     private static final int MAX_DISPLAYED_ERROR_LENGTH = 43;
     private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers,
                               boolean isDegraded, boolean showDebug) throws IOException {
-        String filename = snark.torrent;
+        String filename = snark.getName();
         File f = new File(filename);
         filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name
         int i = filename.lastIndexOf(".torrent");
@@ -710,28 +717,21 @@ public class I2PSnarkServlet extends Default {
             fullFilename = new String(filename);
             filename = filename.substring(0, MAX_DISPLAYED_FILENAME_LENGTH) + "&hellip;";
         }
-        long total = snark.meta.getTotalLength();
+        long total = snark.getTotalLength();
         // Early typecast, avoid possibly overflowing a temp integer
-        long remaining = (long) snark.storage.needed() * (long) snark.meta.getPieceLength(0); 
+        long remaining = (long) snark.getNeeded() * (long) snark.getPieceLength(0); 
         if (remaining > total)
             remaining = total;
-        long downBps = 0;
-        long upBps = 0;
-        if (snark.coordinator != null) {
-            downBps = snark.coordinator.getDownloadRate();
-            upBps = snark.coordinator.getUploadRate();
-        }
+        long downBps = snark.getDownloadRate();
+        long upBps = snark.getUploadRate();
         long remainingSeconds;
         if (downBps > 0)
             remainingSeconds = remaining / downBps;
         else
             remainingSeconds = -1;
-        boolean isRunning = !snark.stopped;
-        long uploaded = 0;
-        if (snark.coordinator != null) {
-            uploaded = snark.coordinator.getUploaded();
-            stats[0] += snark.coordinator.getDownloaded();
-        }
+        boolean isRunning = !snark.isStopped();
+        long uploaded = snark.getUploaded();
+        stats[0] += snark.getDownloaded();
         stats[1] += uploaded;
         if (isRunning) {
             stats[2] += downBps;
@@ -739,25 +739,21 @@ public class I2PSnarkServlet extends Default {
         }
         stats[5] += total;
         
-        boolean isValid = snark.meta != null;
-        boolean singleFile = snark.meta.getFiles() == null;
+        MetaInfo meta = snark.getMetaInfo();
+        boolean isValid = meta != null;
+        boolean singleFile = (!isValid) || meta.getFiles() == null;
         
-        String err = null;
-        int curPeers = 0;
-        int knownPeers = 0;
-        if (snark.coordinator != null) {
-            err = snark.coordinator.trackerProblems;
-            curPeers = snark.coordinator.getPeerCount();
-            stats[4] += curPeers;
-            knownPeers = Math.max(curPeers, snark.coordinator.trackerSeenPeers);
-        }
+        String err = snark.getTrackerProblems();
+        int curPeers = snark.getPeerCount();
+        stats[4] += curPeers;
+        int knownPeers = Math.max(curPeers, snark.getTrackerSeenPeers());
         
         String rowClass = (row % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd");
         String statusString;
         if (err != null) {
             if (isRunning && curPeers > 0 && !showPeers)
                 statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") +
-                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
+                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
                                curPeers + thinsp(isDegraded) +
                                ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
             else if (isRunning)
@@ -773,7 +769,7 @@ public class I2PSnarkServlet extends Default {
         } else if (remaining <= 0) {
             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.meta.getInfoHash()) + "\">" +
+                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
                                curPeers + thinsp(isDegraded) +
                                ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
             else if (isRunning)
@@ -785,7 +781,7 @@ public class I2PSnarkServlet extends Default {
         } else {
             if (isRunning && curPeers > 0 && downBps > 0 && !showPeers)
                 statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") +
-                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
+                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
                                curPeers + thinsp(isDegraded) +
                                ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
             else if (isRunning && curPeers > 0 && downBps > 0)
@@ -794,7 +790,7 @@ public class I2PSnarkServlet extends Default {
                                ngettext("1 peer", "{0} peers", knownPeers);
             else if (isRunning && curPeers > 0 && !showPeers)
                 statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") +
-                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" +
+                               ": <a href=\"" + uri + "?p=" + Base64.encode(snark.getInfoHash()) + "\">" +
                                curPeers + thinsp(isDegraded) +
                                ngettext("1 peer", "{0} peers", knownPeers) + "</a>";
             else if (isRunning && curPeers > 0)
@@ -816,7 +812,7 @@ 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 = snark.meta.getAnnounce();
+        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/")) {
             Map trackers = _manager.getTrackers();
@@ -833,7 +829,7 @@ public class I2PSnarkServlet extends Default {
                     continue;
                 baseURL = baseURL.substring(e + 1);
                 out.write("<a href=\"" + baseURL + "details.php?dllist=1&amp;filelist=1&amp;info_hash=");
-                out.write(TrackerClient.urlencode(snark.meta.getInfoHash()));
+                out.write(TrackerClient.urlencode(snark.getInfoHash()));
                 out.write("\" title=\"" + _("Details at {0} tracker", name) + "\" target=\"_blank\">");
                 out.write("<img alt=\"" + _("Info") + "\" border=\"0\" src=\"" + _imgPath + "details.png\">");
                 out.write("</a>");
@@ -843,13 +839,13 @@ public class I2PSnarkServlet extends Default {
 
         out.write("</td>\n<td class=\"" + rowClass + "\">");
         StringBuilder buf = null;
-        if (remaining == 0 || snark.meta.getFiles() != null) {
+        if (remaining == 0 || meta.getFiles() != null) {
             buf = new StringBuilder(128);
-            buf.append("<a href=\"").append(snark.storage.getBaseName());
-            if (snark.meta.getFiles() != null)
+            buf.append("<a href=\"").append(snark.getBaseName());
+            if (meta.getFiles() != null)
                 buf.append('/');
             buf.append("\" title=\"");
-            if (snark.meta.getFiles() != null)
+            if (meta.getFiles() != null)
                 buf.append(_("View files"));
             else
                 buf.append(_("Open file"));
@@ -857,21 +853,21 @@ public class I2PSnarkServlet extends Default {
             out.write(buf.toString());
         }
         String icon;
-        if (snark.meta.getFiles() != null)
+        if (meta.getFiles() != null)
             icon = "folder";
         else
-            icon = toIcon(snark.meta.getName());
-        if (remaining == 0 || snark.meta.getFiles() != null) {
+            icon = toIcon(meta.getName());
+        if (remaining == 0 || meta.getFiles() != null) {
             out.write(toImg(icon, _("Open")));
             out.write("</a>");
         } else {
             out.write(toImg(icon));
         }
         out.write("</td><td class=\"snarkTorrentName " + rowClass + "\">");
-        if (remaining == 0 || snark.meta.getFiles() != null)
+        if (remaining == 0 || meta.getFiles() != null)
             out.write(buf.toString());
         out.write(filename);
-        if (remaining == 0 || snark.meta.getFiles() != null)
+        if (remaining == 0 || meta.getFiles() != null)
             out.write("</a>");
 
         out.write("<td align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">");
@@ -897,8 +893,8 @@ public class I2PSnarkServlet extends Default {
             out.write(formatSize(upBps) + "ps");
         out.write("</td>\n\t");
         out.write("<td align=\"center\" class=\"snarkTorrentAction " + rowClass + "\">");
-        String parameters = "&nonce=" + _nonce + "&torrent=" + Base64.encode(snark.meta.getInfoHash());
-        String b64 = Base64.encode(snark.meta.getInfoHash());
+        String parameters = "&nonce=" + _nonce + "&torrent=" + Base64.encode(snark.getInfoHash());
+        String b64 = Base64.encode(snark.getInfoHash());
         if (showPeers)
             parameters = parameters + "&p=1";
         if (isRunning) {
@@ -963,7 +959,7 @@ public class I2PSnarkServlet extends Default {
         out.write("</td>\n</tr>\n");
 
         if(showPeers && isRunning && curPeers > 0) {
-            List<Peer> peers = snark.coordinator.peerList();
+            List<Peer> peers = snark.getPeerList();
             if (!showDebug)
                 Collections.sort(peers, new PeerComparator());
             for (Peer peer : peers) {
@@ -996,7 +992,7 @@ 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() / snark.meta.getPieces());
+                float pct = (float) (100.0 * (float) peer.completed() / meta.getPieces());
                 if (pct == 100.0)
                     out.write(_("Seed"));
                 else {
@@ -1358,6 +1354,11 @@ public class I2PSnarkServlet extends Default {
         return _manager.util().getString(s, o);
     }
 
+    /** translate */
+    private String _(String s, Object o, Object o2) {
+        return _manager.util().getString(s, o, o2);
+    }
+
     /** translate (ngettext) @since 0.7.14 */
     private String ngettext(String s, String p, int n) {
         return _manager.util().getString(n, s, p);
@@ -1469,7 +1470,7 @@ public class I2PSnarkServlet extends Default {
         
         if (parent)  // always true
             buf.append("<div class=\"page\"><div class=\"mainsection\">");
-        boolean showPriority = snark != null && !snark.storage.complete();
+        boolean showPriority = snark != null && snark.getStorage() != null && !snark.getStorage().complete();
         if (showPriority)
             buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n");
         buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" >" +
@@ -1516,15 +1517,16 @@ public class I2PSnarkServlet extends Default {
                 complete = true;
                 status = toImg("tick") + ' ' + _("Directory");
             } else {
-                if (snark == null) {
+                if (snark == null || snark.getStorage() == null) {
                     // Assume complete, perhaps he removed a completed torrent but kept a bookmark
                     complete = true;
                     status = toImg("cancel") + ' ' + _("Torrent not found?");
                 } else {
+                    Storage storage = snark.getStorage();
                     try {
                         File f = item.getFile();
                         if (f != null) {
-                            long remaining = snark.storage.remaining(f.getCanonicalPath());
+                            long remaining = storage.remaining(f.getCanonicalPath());
                             if (remaining < 0) {
                                 complete = true;
                                 status = toImg("cancel") + ' ' + _("File not found in torrent?");
@@ -1532,7 +1534,7 @@ public class I2PSnarkServlet extends Default {
                                 complete = true;
                                 status = toImg("tick") + ' ' + _("Complete");
                             } else {
-                                int priority = snark.storage.getPriority(f.getCanonicalPath());
+                                int priority = storage.getPriority(f.getCanonicalPath());
                                 if (priority < 0)
                                     status = toImg("cancel");
                                 else if (priority == 0)
@@ -1588,7 +1590,7 @@ public class I2PSnarkServlet extends Default {
                 buf.append("<td class=\"priority\">");
                 File f = item.getFile();
                 if ((!complete) && (!item.isDirectory()) && f != null) {
-                    int pri = snark.storage.getPriority(f.getCanonicalPath());
+                    int pri = snark.getStorage().getPriority(f.getCanonicalPath());
                     buf.append("<input type=\"radio\" value=\"5\" name=\"pri.").append(f.getCanonicalPath()).append("\" ");
                     if (pri > 0)
                         buf.append("checked=\"true\"");
@@ -1690,6 +1692,9 @@ public class I2PSnarkServlet extends Default {
 
     /** @since 0.8.1 */
     private void savePriorities(Snark snark, Map postParams) {
+        Storage storage = snark.getStorage();
+        if (storage == null)
+            return;
         Set<Map.Entry> entries = postParams.entrySet();
         for (Map.Entry entry : entries) {
             String key = (String)entry.getKey();
@@ -1698,14 +1703,13 @@ public class I2PSnarkServlet extends Default {
                     String file = key.substring(4);
                     String val = ((String[])entry.getValue())[0];   // jetty arrays
                     int pri = Integer.parseInt(val);
-                    snark.storage.setPriority(file, pri);
+                    storage.setPriority(file, pri);
                     //System.err.println("Priority now " + pri + " for " + file);
                 } catch (Throwable t) { t.printStackTrace(); }
             }
         }
-        if (snark.coordinator != null)
-            snark.coordinator.updatePiecePriorities();
-        _manager.saveTorrentStatus(snark.storage.getMetaInfo(), snark.storage.getBitField(), snark.storage.getFilePriorities());
+         snark.updatePiecePriorities();
+        _manager.saveTorrentStatus(snark.getMetaInfo(), storage.getBitField(), storage.getFilePriorities());
     }
 
 
-- 
GitLab