diff --git a/apps/i2psnark/_icons/bug.png b/apps/i2psnark/_icons/bug.png deleted file mode 100644 index 2d5fb90ec..000000000 Binary files a/apps/i2psnark/_icons/bug.png and /dev/null differ diff --git a/apps/i2psnark/java/build.xml b/apps/i2psnark/java/build.xml index d3b653d59..4d7fbbe94 100644 --- a/apps/i2psnark/java/build.xml +++ b/apps/i2psnark/java/build.xml @@ -73,7 +73,7 @@ - + diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java index 5e40f662e..8f24c864a 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerCoordinator.java @@ -62,7 +62,7 @@ public class PeerCoordinator implements PeerListener private long downloaded_old[] = {-1,-1,-1,-1,-1,-1}; // synchronize on this when changing peers or downloaders - final List peers = new ArrayList(); + final List peers = new ArrayList(); /** estimate of the peers, without requiring any synchronization */ volatile int peerCount; @@ -72,7 +72,7 @@ public class PeerCoordinator implements PeerListener private final byte[] id; // Some random wanted pieces - private List wantedPieces; + private List wantedPieces; private boolean halted = false; @@ -117,7 +117,7 @@ public class PeerCoordinator implements PeerListener public CoordinatorListener getListener() { return listener; } // for web page detailed stats - public List peerList() + public List peerList() { synchronized(peers) { @@ -135,8 +135,10 @@ public class PeerCoordinator implements PeerListener return storage.complete(); } + /** might be wrong */ public int getPeerCount() { return peerCount; } + /** should be right */ public int getPeers() { synchronized(peers) @@ -260,7 +262,7 @@ public class PeerCoordinator implements PeerListener public void halt() { halted = true; - List removed = new ArrayList(); + List removed = new ArrayList(); synchronized(peers) { // Stop peer checker task. @@ -273,7 +275,7 @@ public class PeerCoordinator implements PeerListener } while (!removed.isEmpty()) { - Peer peer = (Peer)removed.remove(0); + Peer peer = removed.remove(0); peer.disconnect(); removePeerFromPieces(peer); } @@ -340,9 +342,9 @@ public class PeerCoordinator implements PeerListener // caller must synchronize on peers private static Peer peerIDInList(PeerID pid, List peers) { - Iterator it = peers.iterator(); + Iterator it = peers.iterator(); while (it.hasNext()) { - Peer cur = (Peer)it.next(); + Peer cur = it.next(); if (pid.sameID(cur.getPeerID())) return cur; } @@ -407,15 +409,15 @@ public class PeerCoordinator implements PeerListener // linked list will contain all interested peers that we choke. // At the start are the peers that have us unchoked at the end the // other peer that are interested, but are choking us. - List interested = new LinkedList(); + List interested = new LinkedList(); synchronized (peers) { int count = 0; int unchokedCount = 0; int maxUploaders = allowedUploaders(); - Iterator it = peers.iterator(); + Iterator it = peers.iterator(); while (it.hasNext()) { - Peer peer = (Peer)it.next(); + Peer peer = it.next(); if (peer.isChoking() && peer.isInterested()) { count++; @@ -431,7 +433,7 @@ public class PeerCoordinator implements PeerListener while (uploaders < maxUploaders && !interested.isEmpty()) { - Peer peer = (Peer)interested.remove(0); + Peer peer = interested.remove(0); if (_log.shouldLog(Log.DEBUG)) _log.debug("Unchoke: " + peer); peer.setChoking(false); @@ -476,10 +478,10 @@ public class PeerCoordinator implements PeerListener synchronized(wantedPieces) { - Iterator it = wantedPieces.iterator(); + Iterator it = wantedPieces.iterator(); while (it.hasNext()) { - Piece p = (Piece)it.next(); + Piece p = it.next(); int i = p.getId(); if (bitfield.get(i)) { p.addPeer(peer); @@ -513,11 +515,11 @@ public class PeerCoordinator implements PeerListener { Piece piece = null; Collections.sort(wantedPieces); // Sort in order of rarest first. - List requested = new ArrayList(); - Iterator it = wantedPieces.iterator(); + List requested = new ArrayList(); + Iterator it = wantedPieces.iterator(); while (piece == null && it.hasNext()) { - Piece p = (Piece)it.next(); + Piece p = it.next(); if (havePieces.get(p.getId()) && !p.isRequested()) { piece = p; @@ -537,10 +539,10 @@ public class PeerCoordinator implements PeerListener return -1; // nothing to request and not in end game // let's not all get on the same piece Collections.shuffle(requested); - Iterator it2 = requested.iterator(); + Iterator it2 = requested.iterator(); while (piece == null && it2.hasNext()) { - Piece p = (Piece)it2.next(); + Piece p = it2.next(); if (havePieces.get(p.getId())) { piece = p; @@ -660,11 +662,11 @@ public class PeerCoordinator implements PeerListener // Disconnect from other seeders when we get the last piece synchronized(peers) { - List toDisconnect = new ArrayList(); - Iterator it = peers.iterator(); + List toDisconnect = new ArrayList(); + Iterator it = peers.iterator(); while (it.hasNext()) { - Peer p = (Peer)it.next(); + Peer p = it.next(); if (p.isConnected()) { if (completed() && p.isCompleted()) @@ -676,7 +678,7 @@ public class PeerCoordinator implements PeerListener it = toDisconnect.iterator(); while (it.hasNext()) { - Peer p = (Peer)it.next(); + Peer p = it.next(); p.disconnect(true); } } @@ -742,8 +744,8 @@ public class PeerCoordinator implements PeerListener */ public void removePeerFromPieces(Peer peer) { synchronized(wantedPieces) { - for(Iterator iter = wantedPieces.iterator(); iter.hasNext(); ) { - Piece piece = (Piece)iter.next(); + for(Iterator iter = wantedPieces.iterator(); iter.hasNext(); ) { + Piece piece = iter.next(); piece.removePeer(peer); } } @@ -797,8 +799,8 @@ public class PeerCoordinator implements PeerListener } synchronized(wantedPieces) { - for(Iterator iter = wantedPieces.iterator(); iter.hasNext(); ) { - Piece piece = (Piece)iter.next(); + for(Iterator iter = wantedPieces.iterator(); iter.hasNext(); ) { + Piece piece = iter.next(); if (piece.getId() == savedRequest.piece) { Request req = savedRequest; piece.setRequested(true); @@ -823,9 +825,9 @@ public class PeerCoordinator implements PeerListener // see if anybody else is requesting synchronized (peers) { - Iterator it = peers.iterator(); + Iterator it = peers.iterator(); while (it.hasNext()) { - Peer p = (Peer)it.next(); + Peer p = it.next(); if (p.equals(peer)) continue; if (p.state == null) @@ -843,9 +845,9 @@ public class PeerCoordinator implements PeerListener // nobody is, so mark unrequested synchronized(wantedPieces) { - Iterator it = wantedPieces.iterator(); + Iterator it = wantedPieces.iterator(); while (it.hasNext()) { - Piece p = (Piece)it.next(); + Piece p = it.next(); if (p.getId() == piece) { p.setRequested(false); if (_log.shouldLog(Log.DEBUG)) diff --git a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java index d1865a2b9..5e9250e22 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/PeerState.java +++ b/apps/i2psnark/java/src/org/klomp/snark/PeerState.java @@ -523,8 +523,10 @@ class PeerState _log.debug(peer + " requests " + outstandingRequests); } - // Starts requesting first chunk of next piece. Returns true if - // something has been added to the requests, false otherwise. + /** + * Starts requesting first chunk of next piece. Returns true if + * something has been added to the requests, false otherwise. + */ private boolean requestNextPiece() { // Check that we already know what the other side has. @@ -556,6 +558,15 @@ class PeerState if (nextPiece != -1 && (lastRequest == null || lastRequest.piece != nextPiece)) { + // Fail safe to make sure we are interested + // When we transition into the end game we may not be interested... + if (!interesting) { + if (_log.shouldLog(Log.DEBUG)) + _log.debug(peer + " transition to end game, setting interesting"); + interesting = true; + out.sendInterest(true); + } + int piece_length = metainfo.getPieceLength(nextPiece); //Catch a common place for OOMs esp. on 1MB pieces byte[] bs; diff --git a/apps/i2psnark/java/src/org/klomp/snark/Snark.java b/apps/i2psnark/java/src/org/klomp/snark/Snark.java index c2afec346..9d6cd9460 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/Snark.java +++ b/apps/i2psnark/java/src/org/klomp/snark/Snark.java @@ -437,7 +437,7 @@ public class Snark try { storage.close(); } catch (IOException ioee) { ioee.printStackTrace(); } - fatal("Could not create storage", ioe); + fatal("Could not check or create storage", ioe); } } diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index c1ce6164d..b0fe6d1ba 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -1,861 +1,880 @@ -package org.klomp.snark; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.TreeMap; - -import net.i2p.I2PAppContext; -import net.i2p.data.Base64; -import net.i2p.data.DataHelper; -import net.i2p.util.I2PAppThread; -import net.i2p.util.Log; -import net.i2p.util.OrderedProperties; -import net.i2p.util.SecureDirectory; - -/** - * Manage multiple snarks - */ -public class SnarkManager implements Snark.CompleteListener { - private static SnarkManager _instance = new SnarkManager(); - public static SnarkManager instance() { return _instance; } - - /** map of (canonical) filename of the .torrent file to Snark instance (unsynchronized) */ - private final Map _snarks; - private final Object _addSnarkLock; - private /* FIXME final FIXME */ File _configFile; - private Properties _config; - private I2PAppContext _context; - private Log _log; - private final List _messages; - private I2PSnarkUtil _util; - private PeerCoordinatorSet _peerCoordinatorSet; - private ConnectionAcceptor _connectionAcceptor; - private Thread _monitor; - private boolean _running; - - public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost"; - public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort"; - public static final String PROP_I2CP_OPTS = "i2psnark.i2cpOptions"; - //public static final String PROP_EEP_HOST = "i2psnark.eepHost"; - //public static final String PROP_EEP_PORT = "i2psnark.eepPort"; - public static final String PROP_UPLOADERS_TOTAL = "i2psnark.uploaders.total"; - public static final String PROP_UPBW_MAX = "i2psnark.upbw.max"; - public static final String PROP_DIR = "i2psnark.dir"; - public static final String PROP_META_PREFIX = "i2psnark.zmeta."; - public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield"; - - private static final String CONFIG_FILE = "i2psnark.config"; - public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops - public static final String DEFAULT_AUTO_START = "false"; - public static final String PROP_LINK_PREFIX = "i2psnark.linkPrefix"; - public static final String DEFAULT_LINK_PREFIX = "file:///"; - public static final String PROP_STARTUP_DELAY = "i2psnark.startupDelay"; - - public static final int MIN_UP_BW = 2; - public static final int DEFAULT_MAX_UP_BW = 10; - public static final int DEFAULT_STARTUP_DELAY = 3; - private SnarkManager() { - _snarks = new HashMap(); - _addSnarkLock = new Object(); - _context = I2PAppContext.getGlobalContext(); - _log = _context.logManager().getLog(SnarkManager.class); - _messages = new ArrayList(16); - _util = new I2PSnarkUtil(_context); - _configFile = new File(CONFIG_FILE); - if (!_configFile.isAbsolute()) - _configFile = new File(_context.getConfigDir(), CONFIG_FILE); - loadConfig(null); - } - - /** Caller _must_ call loadConfig(file) before this if setting new values - * for i2cp host/port or i2psnark.dir - */ - public void start() { - _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()); - } - - public void stop() { - _running = false; - _monitor.interrupt(); - _connectionAcceptor.halt(); - (new SnarkManagerShutdown()).run(); - } - - /** hook to I2PSnarkUtil for the servlet */ - public I2PSnarkUtil util() { return _util; } - - private static final int MAX_MESSAGES = 5; - public void addMessage(String message) { - synchronized (_messages) { - _messages.add(message); - while (_messages.size() > MAX_MESSAGES) - _messages.remove(0); - } - if (_log.shouldLog(Log.INFO)) - _log.info("MSG: " + message); - } - - /** newest last */ - public List getMessages() { - synchronized (_messages) { - return new ArrayList(_messages); - } - } - - public boolean shouldAutoStart() { - return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue(); - } - public String linkPrefix() { - return _config.getProperty(PROP_LINK_PREFIX, DEFAULT_LINK_PREFIX + getDataDir().getAbsolutePath() + File.separatorChar); - } - private int getStartupDelayMinutes() { - return Integer.valueOf(_config.getProperty(PROP_STARTUP_DELAY)).intValue(); - } - public File getDataDir() { - String dir = _config.getProperty(PROP_DIR, "i2psnark"); - File f = new SecureDirectory(dir); - if (!f.isAbsolute()) - f = new SecureDirectory(_context.getAppDir(), dir); - return f; - } - - /** null to set initial defaults */ - public void loadConfig(String filename) { - if (_config == null) - _config = new OrderedProperties(); - if (filename != null) { - File cfg = new File(filename); - if (!cfg.isAbsolute()) - cfg = new File(_context.getConfigDir(), filename); - _configFile = cfg; - if (cfg.exists()) { - try { - DataHelper.loadProps(_config, cfg); - } catch (IOException ioe) { - _log.error("Error loading I2PSnark config '" + filename + "'", ioe); - } - } - } - // now add sane defaults - if (!_config.containsKey(PROP_I2CP_HOST)) - _config.setProperty(PROP_I2CP_HOST, "127.0.0.1"); - if (!_config.containsKey(PROP_I2CP_PORT)) - _config.setProperty(PROP_I2CP_PORT, "7654"); - if (!_config.containsKey(PROP_I2CP_OPTS)) - _config.setProperty(PROP_I2CP_OPTS, "inbound.length=2 inbound.lengthVariance=0 outbound.length=2 outbound.lengthVariance=0 inbound.quantity=3 outbound.quantity=3"); - //if (!_config.containsKey(PROP_EEP_HOST)) - // _config.setProperty(PROP_EEP_HOST, "127.0.0.1"); - //if (!_config.containsKey(PROP_EEP_PORT)) - // _config.setProperty(PROP_EEP_PORT, "4444"); - if (!_config.containsKey(PROP_UPLOADERS_TOTAL)) - _config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS); - if (!_config.containsKey(PROP_DIR)) - _config.setProperty(PROP_DIR, "i2psnark"); - if (!_config.containsKey(PROP_AUTO_START)) - _config.setProperty(PROP_AUTO_START, DEFAULT_AUTO_START); - if (!_config.containsKey(PROP_STARTUP_DELAY)) - _config.setProperty(PROP_STARTUP_DELAY, "" + DEFAULT_STARTUP_DELAY); - - updateConfig(); - } - - /** call from DirMonitor since loadConfig() is called before router I2CP is up */ - private void getBWLimit() { - if (!_config.containsKey(PROP_UPBW_MAX)) { - int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort()); - if (limits != null && limits[1] > 0) - _util.setMaxUpBW(limits[1]); - } - } - - private void updateConfig() { - String i2cpHost = _config.getProperty(PROP_I2CP_HOST); - int i2cpPort = getInt(PROP_I2CP_PORT, 7654); - String opts = _config.getProperty(PROP_I2CP_OPTS); - Map i2cpOpts = new HashMap(); - if (opts != null) { - StringTokenizer tok = new StringTokenizer(opts, " "); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split > 0) - i2cpOpts.put(pair.substring(0, split), pair.substring(split+1)); - } - } - if (i2cpHost != null) { - _util.setI2CPConfig(i2cpHost, i2cpPort, i2cpOpts); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Configuring with I2CP options " + i2cpOpts); - } - //I2PSnarkUtil.instance().setI2CPConfig("66.111.51.110", 7654, new Properties()); - //String eepHost = _config.getProperty(PROP_EEP_HOST); - //int eepPort = getInt(PROP_EEP_PORT, 4444); - //if (eepHost != null) - // _util.setProxy(eepHost, eepPort); - _util.setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS)); - _util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW)); - _util.setStartupDelay(getInt(PROP_STARTUP_DELAY, DEFAULT_STARTUP_DELAY)); - String ot = _config.getProperty(I2PSnarkUtil.PROP_OPENTRACKERS); - if (ot != null) - _util.setOpenTrackerString(ot); - // FIXME set util use open trackers property somehow - getDataDir().mkdirs(); - } - - private int getInt(String prop, int defaultVal) { - String p = _config.getProperty(prop); - try { - if ( (p != null) && (p.trim().length() > 0) ) - return Integer.parseInt(p.trim()); - } catch (NumberFormatException nfe) { - // ignore - } - return defaultVal; - } - - public void updateConfig(String dataDir, boolean autoStart, String startDelay, String seedPct, String eepHost, - String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts, - String upLimit, String upBW, boolean useOpenTrackers, String openTrackers) { - boolean changed = false; - //if (eepHost != null) { - // // unused, we use socket eepget - // int port = _util.getEepProxyPort(); - // try { port = Integer.parseInt(eepPort); } catch (NumberFormatException nfe) {} - // String host = _util.getEepProxyHost(); - // if ( (eepHost.trim().length() > 0) && (port > 0) && - // ((!host.equals(eepHost) || (port != _util.getEepProxyPort()) )) ) { - // _util.setProxy(eepHost, port); - // changed = true; - // _config.setProperty(PROP_EEP_HOST, eepHost); - // _config.setProperty(PROP_EEP_PORT, eepPort+""); - // addMessage("EepProxy location changed to " + eepHost + ":" + port); - // } - //} - if (upLimit != null) { - int limit = _util.getMaxUploaders(); - try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {} - if ( limit != _util.getMaxUploaders()) { - if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) { - _util.setMaxUploaders(limit); - changed = true; - _config.setProperty(PROP_UPLOADERS_TOTAL, "" + limit); - addMessage(_("Total uploaders limit changed to {0}", limit)); - } else { - addMessage(_("Minimum total uploaders limit is {0}", Snark.MIN_TOTAL_UPLOADERS)); - } - } - } - if (upBW != null) { - int limit = _util.getMaxUpBW(); - try { limit = Integer.parseInt(upBW); } catch (NumberFormatException nfe) {} - if ( limit != _util.getMaxUpBW()) { - if ( limit >= MIN_UP_BW ) { - _util.setMaxUpBW(limit); - changed = true; - _config.setProperty(PROP_UPBW_MAX, "" + limit); - addMessage(_("Up BW limit changed to {0}KBps", limit)); - } else { - addMessage(_("Minimum up bandwidth limit is {0}KBps", MIN_UP_BW)); - } - } - } - - if (startDelay != null){ - int minutes = _util.getStartupDelay(); - try { minutes = Integer.parseInt(startDelay); } catch (NumberFormatException nfe) {} - if ( minutes != _util.getStartupDelay()) { - _util.setStartupDelay(minutes); - changed = true; - _config.setProperty(PROP_STARTUP_DELAY, "" + minutes); - addMessage(_("Startup delay limit changed to {0} minutes", minutes)); - } - - } - if (i2cpHost != null) { - int oldI2CPPort = _util.getI2CPPort(); - String oldI2CPHost = _util.getI2CPHost(); - int port = oldI2CPPort; - try { port = Integer.parseInt(i2cpPort); } catch (NumberFormatException nfe) {} - String host = oldI2CPHost; - Map opts = new HashMap(); - if (i2cpOpts == null) i2cpOpts = ""; - StringTokenizer tok = new StringTokenizer(i2cpOpts, " \t\n"); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split > 0) - opts.put(pair.substring(0, split), pair.substring(split+1)); - } - Map oldOpts = new HashMap(); - String oldI2CPOpts = _config.getProperty(PROP_I2CP_OPTS); - if (oldI2CPOpts == null) oldI2CPOpts = ""; - tok = new StringTokenizer(oldI2CPOpts, " \t\n"); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split > 0) - oldOpts.put(pair.substring(0, split), pair.substring(split+1)); - } - - if ( (i2cpHost.trim().length() > 0) && (port > 0) && - ((!host.equals(i2cpHost) || - (port != _util.getI2CPPort()) || - (!oldOpts.equals(opts)))) ) { - boolean snarksActive = false; - Set names = listTorrentFiles(); - for (Iterator iter = names.iterator(); iter.hasNext(); ) { - Snark snark = getTorrent((String)iter.next()); - if ( (snark != null) && (!snark.stopped) ) { - snarksActive = true; - break; - } - } - if (snarksActive) { - Properties p = new Properties(); - p.putAll(opts); - _util.setI2CPConfig(i2cpHost, port, p); - addMessage(_("I2CP and tunnel changes will take effect after stopping all torrents")); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("i2cp host [" + i2cpHost + "] i2cp port " + port + " opts [" + opts - + "] oldOpts [" + oldOpts + "]"); - } else { - if (_util.connected()) { - _util.disconnect(); - addMessage(_("Disconnecting old I2CP destination")); - } - Properties p = new Properties(); - p.putAll(opts); - addMessage(_("I2CP settings changed to {0}", i2cpHost + ":" + port + " (" + i2cpOpts.trim() + ")")); - _util.setI2CPConfig(i2cpHost, port, p); - boolean ok = _util.connect(); - if (!ok) { - addMessage(_("Unable to connect with the new settings, reverting to the old I2CP settings")); - _util.setI2CPConfig(oldI2CPHost, oldI2CPPort, oldOpts); - ok = _util.connect(); - if (!ok) - addMessage(_("Unable to reconnect with the old settings!")); - } else { - addMessage(_("Reconnected on the new I2CP destination")); - _config.setProperty(PROP_I2CP_HOST, i2cpHost.trim()); - _config.setProperty(PROP_I2CP_PORT, "" + port); - _config.setProperty(PROP_I2CP_OPTS, i2cpOpts.trim()); - changed = true; - // no PeerAcceptors/I2PServerSockets to deal with, since all snarks are inactive - 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())); - } - } - } - } - changed = true; - } - } - if (shouldAutoStart() != autoStart) { - _config.setProperty(PROP_AUTO_START, autoStart + ""); - if (autoStart) - addMessage(_("Enabled autostart")); - else - addMessage(_("Disabled autostart")); - changed = true; - } - if (_util.shouldUseOpenTrackers() != useOpenTrackers) { - _config.setProperty(I2PSnarkUtil.PROP_USE_OPENTRACKERS, useOpenTrackers + ""); - if (useOpenTrackers) - addMessage(_("Enabled open trackers - torrent restart required to take effect.")); - else - addMessage(_("Disabled open trackers - torrent restart required to take effect.")); - changed = true; - } - if (openTrackers != null) { - if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(_util.getOpenTrackerString())) { - _config.setProperty(I2PSnarkUtil.PROP_OPENTRACKERS, openTrackers.trim()); - _util.setOpenTrackerString(openTrackers); - addMessage(_("Open Tracker list changed - torrent restart required to take effect.")); - changed = true; - } - } - if (changed) { - saveConfig(); - } else { - addMessage(_("Configuration unchanged.")); - } - } - - public void saveConfig() { - try { - synchronized (_configFile) { - DataHelper.storeProps(_config, _configFile); - } - } catch (IOException ioe) { - addMessage(_("Unable to save the config to {0}", _configFile.getAbsolutePath())); - } - } - - public Properties getConfig() { return _config; } - - /** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */ - private static final int MAX_FILES_PER_TORRENT = 512; - - /** set of canonical .torrent filenames that we are dealing with */ - public Set listTorrentFiles() { synchronized (_snarks) { return new HashSet(_snarks.keySet()); } } - - /** - * Grab the torrent given the (canonical) filename of the .torrent file - * @return Snark or null - */ - public Snark getTorrent(String filename) { synchronized (_snarks) { return (Snark)_snarks.get(filename); } } - - /** - * Grab the torrent given the base name of the storage - * @return Snark or null - * @since 0.7.14 - */ - public Snark getTorrentByBaseName(String filename) { - synchronized (_snarks) { - for (Snark s : _snarks.values()) { - if (s.storage.getBaseName().equals(filename)) - return s; - } - } - return null; - } - - public void addTorrent(String filename) { addTorrent(filename, false); } - public void addTorrent(String filename, boolean dontAutoStart) { - if ((!dontAutoStart) && !_util.connected()) { - addMessage(_("Connecting to I2P")); - boolean ok = _util.connect(); - if (!ok) { - addMessage(_("Error connecting to I2P - check your I2CP settings!")); - return; - } - } - File sfile = new File(filename); - try { - filename = sfile.getCanonicalPath(); - } catch (IOException ioe) { - _log.error("Unable to add the torrent " + filename, ioe); - addMessage(_("Error: Could not add the torrent {0}", filename) + ": " + ioe.getMessage()); - return; - } - File dataDir = getDataDir(); - Snark torrent = null; - synchronized (_snarks) { - torrent = (Snark)_snarks.get(filename); - } - // don't hold the _snarks lock while verifying the torrent - if (torrent == null) { - synchronized (_addSnarkLock) { - // double-check - synchronized (_snarks) { - if(_snarks.get(filename) != null) - return; - } - - FileInputStream fis = null; - try { - fis = new FileInputStream(sfile); - } catch (IOException ioe) { - // catch this here so we don't try do delete it below - addMessage(_("Cannot open \"{0}\"", sfile.getName()) + ": " + ioe.getMessage()); - return; - } - - try { - MetaInfo info = new MetaInfo(fis); - try { - fis.close(); - fis = null; - } catch (IOException e) {} - - 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())); - } 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())); - dontAutoStart = true; - } - } - String rejectMessage = locked_validateTorrent(info); - if (rejectMessage != null) { - sfile.delete(); - addMessage(rejectMessage); - return; - } else { - torrent = new Snark(_util, filename, null, -1, null, null, this, - _peerCoordinatorSet, _connectionAcceptor, - false, dataDir.getPath()); - torrent.completeListener = this; - synchronized (_snarks) { - _snarks.put(filename, torrent); - } - } - } catch (IOException ioe) { - addMessage(_("Torrent in \"{0}\" is invalid", sfile.getName()) + ": " + ioe.getMessage()); - if (sfile.exists()) - sfile.delete(); - return; - } finally { - if (fis != null) try { fis.close(); } catch (IOException ioe) {} - } - } - } else { - 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}\"", f.getName())); - } else { - addMessage(_("Torrent added: \"{0}\"", f.getName())); - } - } - - /** - * Get the timestamp for a torrent from the config file - */ - public long getSavedTorrentTime(Snark snark) { - MetaInfo metainfo = snark.meta; - byte[] ih = metainfo.getInfoHash(); - String infohash = Base64.encode(ih); - infohash = infohash.replace('=', '$'); - String time = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); - if (time == null) - return 0; - int comma = time.indexOf(','); - if (comma <= 0) - return 0; - time = time.substring(0, comma); - try { return Long.parseLong(time); } catch (NumberFormatException nfe) {} - return 0; - } - - /** - * Get the saved bitfield for a torrent from the config file. - * Convert "." to a full bitfield. - */ - public BitField getSavedTorrentBitField(Snark snark) { - MetaInfo metainfo = snark.meta; - byte[] ih = metainfo.getInfoHash(); - String infohash = Base64.encode(ih); - infohash = infohash.replace('=', '$'); - String bf = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); - if (bf == null) - return null; - int comma = bf.indexOf(','); - if (comma <= 0) - return null; - bf = bf.substring(comma + 1).trim(); - int len = metainfo.getPieces(); - if (bf.equals(".")) { - BitField bitfield = new BitField(len); - for (int i = 0; i < len; i++) - bitfield.set(i); - return bitfield; - } - byte[] bitfield = Base64.decode(bf); - if (bitfield == null) - return null; - if (bitfield.length * 8 < len) - return null; - return new BitField(bitfield, len); - } - - /** - * Save the completion status of a torrent and the current time in the config file - * in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield". - * The config file property key is appended with the Base64 of the infohash, - * with the '=' changed to '$' since a key can't contain '='. - * The time is a standard long converted to string. - * The status is either a bitfield converted to Base64 or "." for a completed - * torrent to save space in the config file and in memory. - */ - public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield) { - byte[] ih = metainfo.getInfoHash(); - String infohash = Base64.encode(ih); - infohash = infohash.replace('=', '$'); - String now = "" + System.currentTimeMillis(); - String bfs; - if (bitfield.complete()) { - bfs = "."; - } else { - byte[] bf = bitfield.getFieldBytes(); - bfs = Base64.encode(bf); - } - _config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs); - saveConfig(); - } - - /** - * Remove the status of a torrent from the config file. - * This may help the config file from growing too big. - */ - public void removeTorrentStatus(MetaInfo metainfo) { - byte[] ih = metainfo.getInfoHash(); - String infohash = Base64.encode(ih); - infohash = infohash.replace('=', '$'); - _config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); - saveConfig(); - } - - /** - * Warning - does not validate announce URL - use TrackerClient.isValidAnnounce() - */ - private String locked_validateTorrent(MetaInfo info) throws IOException { - List files = info.getFiles(); - if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) { - return _("Too many files in \"{0}\" ({1}), deleting it!", info.getName(), files.size()); - } else if ( (files == null) && (info.getName().endsWith(".torrent")) ) { - return _("Torrent file \"{0}\" cannot end in \".torrent\", deleting it!", info.getName()); - } else if (info.getPieces() <= 0) { - return _("No pieces in \"{0}\", deleting it!", info.getName()); - } else if (info.getPieces() > Storage.MAX_PIECES) { - return _("Too many pieces in \"{0}\", limit is {1}, deleting it!", info.getName(), Storage.MAX_PIECES); - } else if (info.getPieceLength(0) > Storage.MAX_PIECE_SIZE) { - return _("Pieces are too large in \"{0}\" ({1}B), deleting it.", info.getName(), DataHelper.formatSize2(info.getPieceLength(0))) + ' ' + - _("Limit is {0}B", DataHelper.formatSize2(Storage.MAX_PIECE_SIZE)); - } else if (info.getTotalLength() > Storage.MAX_TOTAL_SIZE) { - System.out.println("torrent info: " + info.toString()); - List lengths = info.getLengths(); - if (lengths != null) - for (int i = 0; i < lengths.size(); i++) - System.out.println("File " + i + " is " + lengths.get(i) + " long."); - - return _("Torrents larger than {0}B are not supported yet, deleting \"{1}\"", Storage.MAX_TOTAL_SIZE, info.getName()); - } else { - // ok - return null; - } - } - - /** - * Stop the torrent, leaving it on the list of torrents unless told to remove it - */ - public Snark stopTorrent(String filename, boolean shouldRemove) { - File sfile = new File(filename); - try { - filename = sfile.getCanonicalPath(); - } catch (IOException ioe) { - _log.error("Unable to remove the torrent " + filename, ioe); - addMessage(_("Error: Could not remove the torrent {0}", filename) + ": " + ioe.getMessage()); - return null; - } - int remaining = 0; - Snark torrent = null; - synchronized (_snarks) { - if (shouldRemove) - torrent = (Snark)_snarks.remove(filename); - else - torrent = (Snark)_snarks.get(filename); - remaining = _snarks.size(); - } - if (torrent != null) { - boolean wasStopped = torrent.stopped; - torrent.stopTorrent(); - if (remaining == 0) { - // should we disconnect/reconnect here (taking care to deal with the other thread's - // I2PServerSocket.accept() call properly?) - ////_util. - } - if (!wasStopped) - addMessage(_("Torrent stopped: \"{0}\"", sfile.getName())); - } - return torrent; - } - /** - * Stop the torrent and delete the torrent file itself, but leaving the data - * behind. - */ - public void removeTorrent(String filename) { - Snark torrent = stopTorrent(filename, true); - if (torrent != null) { - File torrentFile = new File(filename); - torrentFile.delete(); - if (torrent.storage != null) - removeTorrentStatus(torrent.storage.getMetaInfo()); - addMessage(_("Torrent removed: \"{0}\"", torrentFile.getName())); - } - } - - 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); - } - - // here because we need to delay until I2CP is up - // although the user will see the default until then - getBWLimit(); - while (true) { - File dir = getDataDir(); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Directory Monitor loop over " + dir.getAbsolutePath()); - try { - monitorTorrents(dir); - } catch (Exception e) { - _log.error("Error in the DirectoryMonitor", e); - } - try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} - } - } - } - - /** two listeners */ - public void torrentComplete(Snark snark) { - File f = new File(snark.torrent); - long len = snark.meta.getTotalLength(); - addMessage(_("Download finished: \"{0}\"", f.getName()) + " (" + _("size: {0}B", DataHelper.formatSize2(len)) + ')'); - updateStatus(snark); - } - - public void updateStatus(Snark snark) { - saveTorrentStatus(snark.meta, snark.storage.getBitField()); - } - - private void monitorTorrents(File dir) { - String fileNames[] = dir.list(TorrentFilenameFilter.instance()); - List foundNames = new ArrayList(0); - if (fileNames != null) { - for (int i = 0; i < fileNames.length; i++) { - try { - foundNames.add(new File(dir, fileNames[i]).getCanonicalPath()); - } catch (IOException ioe) { - _log.error("Error resolving '" + fileNames[i] + "' in '" + dir, ioe); - } - } - } - - Set existingNames = listTorrentFiles(); - // lets find new ones first... - for (int i = 0; i < foundNames.size(); i++) { - if (existingNames.contains(foundNames.get(i))) { - // already known. noop - } else { - if (shouldAutoStart() && !_util.connect()) - addMessage(_("Unable to connect to I2P!")); - addTorrent((String)foundNames.get(i), !shouldAutoStart()); - } - } - // now lets see which ones have been removed... - for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) { - String name = (String)iter.next(); - if (foundNames.contains(name)) { - // known and still there. noop - } else { - // known, but removed. drop it - stopTorrent(name, true); - } - } - } - - /** translate */ - private String _(String s) { - return _util.getString(s); - } - - /** translate */ - private String _(String s, Object o) { - return _util.getString(s, o); - } - - /** translate */ - private String _(String s, Object o, Object o2) { - return _util.getString(s, o, o2); - } - - /** - * "name", "announceURL=websiteURL" pairs - */ - private static final String DEFAULT_TRACKERS[] = { -// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/" -// , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/" -// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/" -// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/" -// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/" -// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/" -// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php" -// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/" -// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/" - "POSTMAN", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/" - ,"WELTERDE", "http://tracker.welterde.i2p/a=http://tracker.welterde.i2p/stats?mode=top5" - , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/" - }; - - /** 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; - /** sorted map of name to announceURL=baseURL */ - public Map getTrackers() { - if (trackerMap != null) // only do this once, can't be updated while running - return trackerMap; - Map rv = new TreeMap(); - String trackers = _config.getProperty(PROP_TRACKERS); - if ( (trackers == null) || (trackers.trim().length() <= 0) ) - trackers = _context.getProperty(PROP_TRACKERS); - if ( (trackers == null) || (trackers.trim().length() <= 0) ) { - for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) - rv.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]); - } else { - StringTokenizer tok = new StringTokenizer(trackers, ","); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split <= 0) - continue; - String name = pair.substring(0, split).trim(); - String url = pair.substring(split+1).trim(); - if ( (name.length() > 0) && (url.length() > 0) ) - rv.put(name, url); - } - } - - trackerMap = rv; - return trackerMap; - } - - private static class TorrentFilenameFilter implements FilenameFilter { - private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter(); - public static TorrentFilenameFilter instance() { return _filter; } - public boolean accept(File dir, String name) { - return (name != null) && (name.endsWith(".torrent")); - } - } - - public class SnarkManagerShutdown extends I2PAppThread { - @Override - public void run() { - Set names = listTorrentFiles(); - for (Iterator iter = names.iterator(); iter.hasNext(); ) { - Snark snark = getTorrent((String)iter.next()); - if ( (snark != null) && (!snark.stopped) ) - snark.stopTorrent(); - } - } - } -} +package org.klomp.snark; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeMap; + +import net.i2p.I2PAppContext; +import net.i2p.data.Base64; +import net.i2p.data.DataHelper; +import net.i2p.util.I2PAppThread; +import net.i2p.util.Log; +import net.i2p.util.OrderedProperties; +import net.i2p.util.SecureDirectory; + +/** + * Manage multiple snarks + */ +public class SnarkManager implements Snark.CompleteListener { + private static SnarkManager _instance = new SnarkManager(); + public static SnarkManager instance() { return _instance; } + + /** map of (canonical) filename of the .torrent file to Snark instance (unsynchronized) */ + private final Map _snarks; + private final Object _addSnarkLock; + private /* FIXME final FIXME */ File _configFile; + private Properties _config; + private I2PAppContext _context; + private Log _log; + private final List _messages; + private I2PSnarkUtil _util; + private PeerCoordinatorSet _peerCoordinatorSet; + private ConnectionAcceptor _connectionAcceptor; + private Thread _monitor; + private boolean _running; + + public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost"; + public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort"; + public static final String PROP_I2CP_OPTS = "i2psnark.i2cpOptions"; + //public static final String PROP_EEP_HOST = "i2psnark.eepHost"; + //public static final String PROP_EEP_PORT = "i2psnark.eepPort"; + public static final String PROP_UPLOADERS_TOTAL = "i2psnark.uploaders.total"; + public static final String PROP_UPBW_MAX = "i2psnark.upbw.max"; + public static final String PROP_DIR = "i2psnark.dir"; + public static final String PROP_META_PREFIX = "i2psnark.zmeta."; + public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield"; + + private static final String CONFIG_FILE = "i2psnark.config"; + public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops + public static final String DEFAULT_AUTO_START = "false"; + public static final String PROP_LINK_PREFIX = "i2psnark.linkPrefix"; + public static final String DEFAULT_LINK_PREFIX = "file:///"; + public static final String PROP_STARTUP_DELAY = "i2psnark.startupDelay"; + + public static final int MIN_UP_BW = 2; + public static final int DEFAULT_MAX_UP_BW = 10; + public static final int DEFAULT_STARTUP_DELAY = 3; + private SnarkManager() { + _snarks = new HashMap(); + _addSnarkLock = new Object(); + _context = I2PAppContext.getGlobalContext(); + _log = _context.logManager().getLog(SnarkManager.class); + _messages = new ArrayList(16); + _util = new I2PSnarkUtil(_context); + _configFile = new File(CONFIG_FILE); + if (!_configFile.isAbsolute()) + _configFile = new File(_context.getConfigDir(), CONFIG_FILE); + loadConfig(null); + } + + /** Caller _must_ call loadConfig(file) before this if setting new values + * for i2cp host/port or i2psnark.dir + */ + public void start() { + _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()); + } + + public void stop() { + _running = false; + _monitor.interrupt(); + _connectionAcceptor.halt(); + (new SnarkManagerShutdown()).run(); + } + + /** hook to I2PSnarkUtil for the servlet */ + public I2PSnarkUtil util() { return _util; } + + private static final int MAX_MESSAGES = 5; + public void addMessage(String message) { + synchronized (_messages) { + _messages.add(message); + while (_messages.size() > MAX_MESSAGES) + _messages.remove(0); + } + if (_log.shouldLog(Log.INFO)) + _log.info("MSG: " + message); + } + + /** newest last */ + public List getMessages() { + synchronized (_messages) { + return new ArrayList(_messages); + } + } + + public boolean shouldAutoStart() { + return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue(); + } + public String linkPrefix() { + return _config.getProperty(PROP_LINK_PREFIX, DEFAULT_LINK_PREFIX + getDataDir().getAbsolutePath() + File.separatorChar); + } + private int getStartupDelayMinutes() { + return Integer.valueOf(_config.getProperty(PROP_STARTUP_DELAY)).intValue(); + } + public File getDataDir() { + String dir = _config.getProperty(PROP_DIR, "i2psnark"); + File f = new SecureDirectory(dir); + if (!f.isAbsolute()) + f = new SecureDirectory(_context.getAppDir(), dir); + return f; + } + + /** null to set initial defaults */ + public void loadConfig(String filename) { + if (_config == null) + _config = new OrderedProperties(); + if (filename != null) { + File cfg = new File(filename); + if (!cfg.isAbsolute()) + cfg = new File(_context.getConfigDir(), filename); + _configFile = cfg; + if (cfg.exists()) { + try { + DataHelper.loadProps(_config, cfg); + } catch (IOException ioe) { + _log.error("Error loading I2PSnark config '" + filename + "'", ioe); + } + } + } + // now add sane defaults + if (!_config.containsKey(PROP_I2CP_HOST)) + _config.setProperty(PROP_I2CP_HOST, "127.0.0.1"); + if (!_config.containsKey(PROP_I2CP_PORT)) + _config.setProperty(PROP_I2CP_PORT, "7654"); + if (!_config.containsKey(PROP_I2CP_OPTS)) + _config.setProperty(PROP_I2CP_OPTS, "inbound.length=2 inbound.lengthVariance=0 outbound.length=2 outbound.lengthVariance=0 inbound.quantity=3 outbound.quantity=3"); + //if (!_config.containsKey(PROP_EEP_HOST)) + // _config.setProperty(PROP_EEP_HOST, "127.0.0.1"); + //if (!_config.containsKey(PROP_EEP_PORT)) + // _config.setProperty(PROP_EEP_PORT, "4444"); + if (!_config.containsKey(PROP_UPLOADERS_TOTAL)) + _config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS); + if (!_config.containsKey(PROP_DIR)) + _config.setProperty(PROP_DIR, "i2psnark"); + if (!_config.containsKey(PROP_AUTO_START)) + _config.setProperty(PROP_AUTO_START, DEFAULT_AUTO_START); + if (!_config.containsKey(PROP_STARTUP_DELAY)) + _config.setProperty(PROP_STARTUP_DELAY, "" + DEFAULT_STARTUP_DELAY); + + updateConfig(); + } + + /** call from DirMonitor since loadConfig() is called before router I2CP is up */ + private void getBWLimit() { + if (!_config.containsKey(PROP_UPBW_MAX)) { + int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort()); + if (limits != null && limits[1] > 0) + _util.setMaxUpBW(limits[1]); + } + } + + private void updateConfig() { + String i2cpHost = _config.getProperty(PROP_I2CP_HOST); + int i2cpPort = getInt(PROP_I2CP_PORT, 7654); + String opts = _config.getProperty(PROP_I2CP_OPTS); + Map i2cpOpts = new HashMap(); + if (opts != null) { + StringTokenizer tok = new StringTokenizer(opts, " "); + while (tok.hasMoreTokens()) { + String pair = tok.nextToken(); + int split = pair.indexOf('='); + if (split > 0) + i2cpOpts.put(pair.substring(0, split), pair.substring(split+1)); + } + } + if (i2cpHost != null) { + _util.setI2CPConfig(i2cpHost, i2cpPort, i2cpOpts); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Configuring with I2CP options " + i2cpOpts); + } + //I2PSnarkUtil.instance().setI2CPConfig("66.111.51.110", 7654, new Properties()); + //String eepHost = _config.getProperty(PROP_EEP_HOST); + //int eepPort = getInt(PROP_EEP_PORT, 4444); + //if (eepHost != null) + // _util.setProxy(eepHost, eepPort); + _util.setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS)); + _util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW)); + _util.setStartupDelay(getInt(PROP_STARTUP_DELAY, DEFAULT_STARTUP_DELAY)); + String ot = _config.getProperty(I2PSnarkUtil.PROP_OPENTRACKERS); + if (ot != null) + _util.setOpenTrackerString(ot); + // FIXME set util use open trackers property somehow + getDataDir().mkdirs(); + } + + private int getInt(String prop, int defaultVal) { + String p = _config.getProperty(prop); + try { + if ( (p != null) && (p.trim().length() > 0) ) + return Integer.parseInt(p.trim()); + } catch (NumberFormatException nfe) { + // ignore + } + return defaultVal; + } + + public void updateConfig(String dataDir, boolean autoStart, String startDelay, String seedPct, String eepHost, + String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts, + String upLimit, String upBW, boolean useOpenTrackers, String openTrackers) { + boolean changed = false; + //if (eepHost != null) { + // // unused, we use socket eepget + // int port = _util.getEepProxyPort(); + // try { port = Integer.parseInt(eepPort); } catch (NumberFormatException nfe) {} + // String host = _util.getEepProxyHost(); + // if ( (eepHost.trim().length() > 0) && (port > 0) && + // ((!host.equals(eepHost) || (port != _util.getEepProxyPort()) )) ) { + // _util.setProxy(eepHost, port); + // changed = true; + // _config.setProperty(PROP_EEP_HOST, eepHost); + // _config.setProperty(PROP_EEP_PORT, eepPort+""); + // addMessage("EepProxy location changed to " + eepHost + ":" + port); + // } + //} + if (upLimit != null) { + int limit = _util.getMaxUploaders(); + try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {} + if ( limit != _util.getMaxUploaders()) { + if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) { + _util.setMaxUploaders(limit); + changed = true; + _config.setProperty(PROP_UPLOADERS_TOTAL, "" + limit); + addMessage(_("Total uploaders limit changed to {0}", limit)); + } else { + addMessage(_("Minimum total uploaders limit is {0}", Snark.MIN_TOTAL_UPLOADERS)); + } + } + } + if (upBW != null) { + int limit = _util.getMaxUpBW(); + try { limit = Integer.parseInt(upBW); } catch (NumberFormatException nfe) {} + if ( limit != _util.getMaxUpBW()) { + if ( limit >= MIN_UP_BW ) { + _util.setMaxUpBW(limit); + changed = true; + _config.setProperty(PROP_UPBW_MAX, "" + limit); + addMessage(_("Up BW limit changed to {0}KBps", limit)); + } else { + addMessage(_("Minimum up bandwidth limit is {0}KBps", MIN_UP_BW)); + } + } + } + + if (startDelay != null){ + int minutes = _util.getStartupDelay(); + try { minutes = Integer.parseInt(startDelay); } catch (NumberFormatException nfe) {} + if ( minutes != _util.getStartupDelay()) { + _util.setStartupDelay(minutes); + changed = true; + _config.setProperty(PROP_STARTUP_DELAY, "" + minutes); + addMessage(_("Startup delay limit changed to {0} minutes", minutes)); + } + + } + if (i2cpHost != null) { + int oldI2CPPort = _util.getI2CPPort(); + String oldI2CPHost = _util.getI2CPHost(); + int port = oldI2CPPort; + try { port = Integer.parseInt(i2cpPort); } catch (NumberFormatException nfe) {} + String host = oldI2CPHost; + Map opts = new HashMap(); + if (i2cpOpts == null) i2cpOpts = ""; + StringTokenizer tok = new StringTokenizer(i2cpOpts, " \t\n"); + while (tok.hasMoreTokens()) { + String pair = tok.nextToken(); + int split = pair.indexOf('='); + if (split > 0) + opts.put(pair.substring(0, split), pair.substring(split+1)); + } + Map oldOpts = new HashMap(); + String oldI2CPOpts = _config.getProperty(PROP_I2CP_OPTS); + if (oldI2CPOpts == null) oldI2CPOpts = ""; + tok = new StringTokenizer(oldI2CPOpts, " \t\n"); + while (tok.hasMoreTokens()) { + String pair = tok.nextToken(); + int split = pair.indexOf('='); + if (split > 0) + oldOpts.put(pair.substring(0, split), pair.substring(split+1)); + } + + if ( (i2cpHost.trim().length() > 0) && (port > 0) && + ((!host.equals(i2cpHost) || + (port != _util.getI2CPPort()) || + (!oldOpts.equals(opts)))) ) { + boolean snarksActive = false; + Set names = listTorrentFiles(); + for (Iterator iter = names.iterator(); iter.hasNext(); ) { + Snark snark = getTorrent((String)iter.next()); + if ( (snark != null) && (!snark.stopped) ) { + snarksActive = true; + break; + } + } + if (snarksActive) { + Properties p = new Properties(); + p.putAll(opts); + _util.setI2CPConfig(i2cpHost, port, p); + addMessage(_("I2CP and tunnel changes will take effect after stopping all torrents")); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("i2cp host [" + i2cpHost + "] i2cp port " + port + " opts [" + opts + + "] oldOpts [" + oldOpts + "]"); + } else { + if (_util.connected()) { + _util.disconnect(); + addMessage(_("Disconnecting old I2CP destination")); + } + Properties p = new Properties(); + p.putAll(opts); + addMessage(_("I2CP settings changed to {0}", i2cpHost + ":" + port + " (" + i2cpOpts.trim() + ")")); + _util.setI2CPConfig(i2cpHost, port, p); + boolean ok = _util.connect(); + if (!ok) { + addMessage(_("Unable to connect with the new settings, reverting to the old I2CP settings")); + _util.setI2CPConfig(oldI2CPHost, oldI2CPPort, oldOpts); + ok = _util.connect(); + if (!ok) + addMessage(_("Unable to reconnect with the old settings!")); + } else { + addMessage(_("Reconnected on the new I2CP destination")); + _config.setProperty(PROP_I2CP_HOST, i2cpHost.trim()); + _config.setProperty(PROP_I2CP_PORT, "" + port); + _config.setProperty(PROP_I2CP_OPTS, i2cpOpts.trim()); + changed = true; + // no PeerAcceptors/I2PServerSockets to deal with, since all snarks are inactive + 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())); + } + } + } + } + changed = true; + } + } + if (shouldAutoStart() != autoStart) { + _config.setProperty(PROP_AUTO_START, autoStart + ""); + if (autoStart) + addMessage(_("Enabled autostart")); + else + addMessage(_("Disabled autostart")); + changed = true; + } + if (_util.shouldUseOpenTrackers() != useOpenTrackers) { + _config.setProperty(I2PSnarkUtil.PROP_USE_OPENTRACKERS, useOpenTrackers + ""); + if (useOpenTrackers) + addMessage(_("Enabled open trackers - torrent restart required to take effect.")); + else + addMessage(_("Disabled open trackers - torrent restart required to take effect.")); + changed = true; + } + if (openTrackers != null) { + if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(_util.getOpenTrackerString())) { + _config.setProperty(I2PSnarkUtil.PROP_OPENTRACKERS, openTrackers.trim()); + _util.setOpenTrackerString(openTrackers); + addMessage(_("Open Tracker list changed - torrent restart required to take effect.")); + changed = true; + } + } + if (changed) { + saveConfig(); + } else { + addMessage(_("Configuration unchanged.")); + } + } + + public void saveConfig() { + try { + synchronized (_configFile) { + DataHelper.storeProps(_config, _configFile); + } + } catch (IOException ioe) { + addMessage(_("Unable to save the config to {0}", _configFile.getAbsolutePath())); + } + } + + public Properties getConfig() { return _config; } + + /** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */ + private static final int MAX_FILES_PER_TORRENT = 512; + + /** set of canonical .torrent filenames that we are dealing with */ + public Set listTorrentFiles() { synchronized (_snarks) { return new HashSet(_snarks.keySet()); } } + + /** + * Grab the torrent given the (canonical) filename of the .torrent file + * @return Snark or null + */ + public Snark getTorrent(String filename) { synchronized (_snarks) { return (Snark)_snarks.get(filename); } } + + /** + * Grab the torrent given the base name of the storage + * @return Snark or null + * @since 0.7.14 + */ + public Snark getTorrentByBaseName(String filename) { + synchronized (_snarks) { + for (Snark s : _snarks.values()) { + if (s.storage.getBaseName().equals(filename)) + return s; + } + } + return null; + } + + /** @throws RuntimeException via Snark.fatal() */ + public void addTorrent(String filename) { addTorrent(filename, false); } + + /** @throws RuntimeException via Snark.fatal() */ + public void addTorrent(String filename, boolean dontAutoStart) { + if ((!dontAutoStart) && !_util.connected()) { + addMessage(_("Connecting to I2P")); + boolean ok = _util.connect(); + if (!ok) { + addMessage(_("Error connecting to I2P - check your I2CP settings!")); + return; + } + } + File sfile = new File(filename); + try { + filename = sfile.getCanonicalPath(); + } catch (IOException ioe) { + _log.error("Unable to add the torrent " + filename, ioe); + addMessage(_("Error: Could not add the torrent {0}", filename) + ": " + ioe.getMessage()); + return; + } + File dataDir = getDataDir(); + Snark torrent = null; + synchronized (_snarks) { + torrent = (Snark)_snarks.get(filename); + } + // don't hold the _snarks lock while verifying the torrent + if (torrent == null) { + synchronized (_addSnarkLock) { + // double-check + synchronized (_snarks) { + if(_snarks.get(filename) != null) + return; + } + + FileInputStream fis = null; + try { + fis = new FileInputStream(sfile); + } catch (IOException ioe) { + // catch this here so we don't try do delete it below + addMessage(_("Cannot open \"{0}\"", sfile.getName()) + ": " + ioe.getMessage()); + return; + } + + try { + MetaInfo info = new MetaInfo(fis); + try { + fis.close(); + fis = null; + } catch (IOException e) {} + + 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())); + } 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())); + dontAutoStart = true; + } + } + String rejectMessage = locked_validateTorrent(info); + if (rejectMessage != null) { + sfile.delete(); + addMessage(rejectMessage); + return; + } else { + torrent = new Snark(_util, filename, null, -1, null, null, this, + _peerCoordinatorSet, _connectionAcceptor, + false, dataDir.getPath()); + torrent.completeListener = this; + synchronized (_snarks) { + _snarks.put(filename, torrent); + } + } + } catch (IOException ioe) { + addMessage(_("Torrent in \"{0}\" is invalid", sfile.getName()) + ": " + ioe.getMessage()); + if (sfile.exists()) + sfile.delete(); + return; + } finally { + if (fis != null) try { fis.close(); } catch (IOException ioe) {} + } + } + } else { + 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}\"", f.getName())); + } else { + addMessage(_("Torrent added: \"{0}\"", f.getName())); + } + } + + /** + * Get the timestamp for a torrent from the config file + */ + public long getSavedTorrentTime(Snark snark) { + MetaInfo metainfo = snark.meta; + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + String time = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); + if (time == null) + return 0; + int comma = time.indexOf(','); + if (comma <= 0) + return 0; + time = time.substring(0, comma); + try { return Long.parseLong(time); } catch (NumberFormatException nfe) {} + return 0; + } + + /** + * Get the saved bitfield for a torrent from the config file. + * Convert "." to a full bitfield. + */ + public BitField getSavedTorrentBitField(Snark snark) { + MetaInfo metainfo = snark.meta; + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + String bf = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); + if (bf == null) + return null; + int comma = bf.indexOf(','); + if (comma <= 0) + return null; + bf = bf.substring(comma + 1).trim(); + int len = metainfo.getPieces(); + if (bf.equals(".")) { + BitField bitfield = new BitField(len); + for (int i = 0; i < len; i++) + bitfield.set(i); + return bitfield; + } + byte[] bitfield = Base64.decode(bf); + if (bitfield == null) + return null; + if (bitfield.length * 8 < len) + return null; + return new BitField(bitfield, len); + } + + /** + * Save the completion status of a torrent and the current time in the config file + * in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield". + * The config file property key is appended with the Base64 of the infohash, + * with the '=' changed to '$' since a key can't contain '='. + * The time is a standard long converted to string. + * The status is either a bitfield converted to Base64 or "." for a completed + * torrent to save space in the config file and in memory. + */ + public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield) { + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + String now = "" + System.currentTimeMillis(); + String bfs; + if (bitfield.complete()) { + bfs = "."; + } else { + byte[] bf = bitfield.getFieldBytes(); + bfs = Base64.encode(bf); + } + _config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs); + saveConfig(); + } + + /** + * Remove the status of a torrent from the config file. + * This may help the config file from growing too big. + */ + public void removeTorrentStatus(MetaInfo metainfo) { + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + _config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); + saveConfig(); + } + + /** + * Warning - does not validate announce URL - use TrackerClient.isValidAnnounce() + */ + private String locked_validateTorrent(MetaInfo info) throws IOException { + List files = info.getFiles(); + if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) { + return _("Too many files in \"{0}\" ({1}), deleting it!", info.getName(), files.size()); + } else if ( (files == null) && (info.getName().endsWith(".torrent")) ) { + return _("Torrent file \"{0}\" cannot end in \".torrent\", deleting it!", info.getName()); + } else if (info.getPieces() <= 0) { + return _("No pieces in \"{0}\", deleting it!", info.getName()); + } else if (info.getPieces() > Storage.MAX_PIECES) { + return _("Too many pieces in \"{0}\", limit is {1}, deleting it!", info.getName(), Storage.MAX_PIECES); + } else if (info.getPieceLength(0) > Storage.MAX_PIECE_SIZE) { + return _("Pieces are too large in \"{0}\" ({1}B), deleting it.", info.getName(), DataHelper.formatSize2(info.getPieceLength(0))) + ' ' + + _("Limit is {0}B", DataHelper.formatSize2(Storage.MAX_PIECE_SIZE)); + } else if (info.getTotalLength() > Storage.MAX_TOTAL_SIZE) { + System.out.println("torrent info: " + info.toString()); + List lengths = info.getLengths(); + if (lengths != null) + for (int i = 0; i < lengths.size(); i++) + System.out.println("File " + i + " is " + lengths.get(i) + " long."); + + return _("Torrents larger than {0}B are not supported yet, deleting \"{1}\"", Storage.MAX_TOTAL_SIZE, info.getName()); + } else { + // ok + return null; + } + } + + /** + * Stop the torrent, leaving it on the list of torrents unless told to remove it + */ + public Snark stopTorrent(String filename, boolean shouldRemove) { + File sfile = new File(filename); + try { + filename = sfile.getCanonicalPath(); + } catch (IOException ioe) { + _log.error("Unable to remove the torrent " + filename, ioe); + addMessage(_("Error: Could not remove the torrent {0}", filename) + ": " + ioe.getMessage()); + return null; + } + int remaining = 0; + Snark torrent = null; + synchronized (_snarks) { + if (shouldRemove) + torrent = (Snark)_snarks.remove(filename); + else + torrent = (Snark)_snarks.get(filename); + remaining = _snarks.size(); + } + if (torrent != null) { + boolean wasStopped = torrent.stopped; + torrent.stopTorrent(); + if (remaining == 0) { + // should we disconnect/reconnect here (taking care to deal with the other thread's + // I2PServerSocket.accept() call properly?) + ////_util. + } + if (!wasStopped) + addMessage(_("Torrent stopped: \"{0}\"", sfile.getName())); + } + return torrent; + } + /** + * Stop the torrent and delete the torrent file itself, but leaving the data + * behind. + */ + public void removeTorrent(String filename) { + Snark torrent = stopTorrent(filename, true); + if (torrent != null) { + File torrentFile = new File(filename); + torrentFile.delete(); + if (torrent.storage != null) + removeTorrentStatus(torrent.storage.getMetaInfo()); + addMessage(_("Torrent removed: \"{0}\"", torrentFile.getName())); + } + } + + 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); + } + + // here because we need to delay until I2CP is up + // although the user will see the default until then + getBWLimit(); + while (true) { + File dir = getDataDir(); + if (_log.shouldLog(Log.DEBUG)) + _log.debug("Directory Monitor loop over " + dir.getAbsolutePath()); + try { + monitorTorrents(dir); + } catch (Exception e) { + _log.error("Error in the DirectoryMonitor", e); + } + try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} + } + } + } + + /** two listeners */ + public void torrentComplete(Snark snark) { + StringBuilder buf = new StringBuilder(256); + buf.append("").append(snark.storage.getBaseName()).append(""); + long len = snark.meta.getTotalLength(); + 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()); + } + + private void monitorTorrents(File dir) { + String fileNames[] = dir.list(TorrentFilenameFilter.instance()); + List foundNames = new ArrayList(0); + if (fileNames != null) { + for (int i = 0; i < fileNames.length; i++) { + try { + foundNames.add(new File(dir, fileNames[i]).getCanonicalPath()); + } catch (IOException ioe) { + _log.error("Error resolving '" + fileNames[i] + "' in '" + dir, ioe); + } + } + } + + Set existingNames = listTorrentFiles(); + // lets find new ones first... + for (int i = 0; i < foundNames.size(); i++) { + if (existingNames.contains(foundNames.get(i))) { + // already known. noop + } else { + if (shouldAutoStart() && !_util.connect()) + addMessage(_("Unable to connect to I2P!")); + try { + // Snark.fatal() throws a RuntimeException + // don't let one bad torrent kill the whole loop + addTorrent(foundNames.get(i), !shouldAutoStart()); + } catch (Exception e) { + addMessage(_("Unable to add {0}", foundNames.get(i)) + ": " + e); + } + } + } + // now lets see which ones have been removed... + for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) { + String name = (String)iter.next(); + if (foundNames.contains(name)) { + // known and still there. noop + } else { + // known, but removed. drop it + try { + // Snark.fatal() throws a RuntimeException + // don't let one bad torrent kill the whole loop + stopTorrent(name, true); + } catch (Exception e) { + // don't bother with message + } + } + } + } + + /** translate */ + private String _(String s) { + return _util.getString(s); + } + + /** translate */ + private String _(String s, Object o) { + return _util.getString(s, o); + } + + /** translate */ + private String _(String s, Object o, Object o2) { + return _util.getString(s, o, o2); + } + + /** + * "name", "announceURL=websiteURL" pairs + */ + private static final String DEFAULT_TRACKERS[] = { +// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/" +// , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/" +// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/" +// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/" +// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/" +// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/" +// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php" +// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/" +// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/" + "POSTMAN", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/" + ,"WELTERDE", "http://tracker.welterde.i2p/a=http://tracker.welterde.i2p/stats?mode=top5" + , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/" + }; + + /** 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; + /** sorted map of name to announceURL=baseURL */ + public Map getTrackers() { + if (trackerMap != null) // only do this once, can't be updated while running + return trackerMap; + Map rv = new TreeMap(); + String trackers = _config.getProperty(PROP_TRACKERS); + if ( (trackers == null) || (trackers.trim().length() <= 0) ) + trackers = _context.getProperty(PROP_TRACKERS); + if ( (trackers == null) || (trackers.trim().length() <= 0) ) { + for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) + rv.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]); + } else { + StringTokenizer tok = new StringTokenizer(trackers, ","); + while (tok.hasMoreTokens()) { + String pair = tok.nextToken(); + int split = pair.indexOf('='); + if (split <= 0) + continue; + String name = pair.substring(0, split).trim(); + String url = pair.substring(split+1).trim(); + if ( (name.length() > 0) && (url.length() > 0) ) + rv.put(name, url); + } + } + + trackerMap = rv; + return trackerMap; + } + + private static class TorrentFilenameFilter implements FilenameFilter { + private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter(); + public static TorrentFilenameFilter instance() { return _filter; } + public boolean accept(File dir, String name) { + return (name != null) && (name.endsWith(".torrent")); + } + } + + public class SnarkManagerShutdown extends I2PAppThread { + @Override + public void run() { + Set names = listTorrentFiles(); + for (Iterator iter = names.iterator(); iter.hasNext(); ) { + Snark snark = getTorrent((String)iter.next()); + if ( (snark != null) && (!snark.stopped) ) + snark.stopTorrent(); + } + } + } +} diff --git a/apps/i2psnark/locale/messages_de.po b/apps/i2psnark/locale/messages_de.po index 0c437790e..cdb9c9337 100644 --- a/apps/i2psnark/locale/messages_de.po +++ b/apps/i2psnark/locale/messages_de.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: I2P i2psnark\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-06-13 19:23+0000\n" -"PO-Revision-Date: 2010-06-15 09:07+0100\n" +"POT-Creation-Date: 2010-07-08 08:03+0000\n" +"PO-Revision-Date: 2010-07-08 10:15+0100\n" "Last-Translator: echelon \n" "Language-Team: foo \n" "MIME-Version: 1.0\n" @@ -208,554 +208,554 @@ msgstr "Download beendet:\"{0}\"" #: ../java/src/org/klomp/snark/SnarkManager.java:729 #, java-format msgid "size: {0}B" -msgstr "Größe: \"{0}\"Byte" +msgstr "Größe: {0}Byte" #: ../java/src/org/klomp/snark/SnarkManager.java:757 msgid "Unable to connect to I2P!" msgstr "Konnte nicht mit I2P verbinden!" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:168 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:174 msgid "I2PSnark - Anonymous BitTorrent Client" msgstr "I2PSnark - Anonymer BitTorrent Klient" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:179 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:185 msgid "Torrents" msgstr "Torrents" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:181 #: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:187 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:831 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:193 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:837 msgid "I2PSnark" msgstr "I2PSnark" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:185 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:191 msgid "Refresh page" msgstr "Aktualisiere Seite" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:189 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:195 msgid "Forum" msgstr "Forum" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:234 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1278 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:240 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1289 msgid "Status" msgstr "Status" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:240 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246 msgid "Hide Peers" msgstr "Verstecke Teilnehmer" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:243 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:249 msgid "Show Peers" msgstr "Zeige Teilnehmer" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:248 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1260 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:254 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1271 msgid "Torrent" msgstr "Torrent" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:250 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:256 msgid "ETA" msgstr "ETA" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:252 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:258 msgid "Downloaded" msgstr "Heruntergeladen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:254 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:260 msgid "Uploaded" msgstr "Hochgeladen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:256 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:262 msgid "Down Rate" msgstr "Down Rate" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:258 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:264 msgid "Up Rate" msgstr "Up Rate" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:265 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:271 msgid "Stop all torrents and the I2P tunnel" msgstr "Stoppe alle Torrents und den I2P Tunnel" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:267 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:273 msgid "Stop All" msgstr "Stoppe alle" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:272 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:278 msgid "Start all torrents and the I2P tunnel" msgstr "Starte alle Torrents und den I2P Tunnel" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:274 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:280 msgid "Start All" msgstr "Starte alle" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:291 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:297 msgid "No torrents loaded." msgstr "Keine Torrents geladen." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:296 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:302 msgid "Totals" msgstr "Total" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:298 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:304 #, java-format msgid "1 torrent" msgid_plural "{0} torrents" msgstr[0] "1 Torrent" msgstr[1] "{0} Torrents" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:301 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:307 #, java-format msgid "1 connected peer" msgid_plural "{0} connected peers" msgstr[0] "1 verbundener Teilnehmer" msgstr[1] "{0} verbundene Teilnehmer" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:330 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:336 #, java-format msgid "Torrent file {0} does not exist" msgstr "Torrent Datei {0} existiert nicht" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:340 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1465 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:346 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1476 #, java-format msgid "Torrent already running: {0}" msgstr "Torrent rennt schon: {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:342 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1467 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:348 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1478 #, java-format msgid "Torrent already in the queue: {0}" msgstr "Torrent ist schon in der Queue: {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:346 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:352 #, java-format msgid "Copying torrent to {0}" msgstr "Kopiere Torrent nach {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:349 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:355 #, java-format msgid "Unable to copy the torrent to {0}" msgstr "Konnte den Torrent nicht nach {0} kopieren" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:349 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:355 #, java-format msgid "from {0}" msgstr "von {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:357 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:363 #, java-format msgid "Fetching {0}" msgstr "Hole {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:361 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:367 msgid "Invalid URL - must start with http://" msgstr "Ungültige URL - muß mit http:// anfangen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:391 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:397 #, java-format msgid "Starting up torrent {0}" msgstr "Starte Torrent {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:411 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:429 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:417 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:435 #, java-format msgid "Torrent file deleted: {0}" msgstr "Torrent Datei gelöscht: {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:435 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:445 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:441 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:451 #, java-format msgid "Data file deleted: {0}" msgstr "Daten Datei gelöscht: {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:437 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:447 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:443 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:453 #, java-format msgid "Data file could not be deleted: {0}" msgstr "Datendatei konnte nicht gelöscht werden: {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:456 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:462 #, java-format msgid "Data dir deleted: {0}" msgstr "Datenverzeichnis wurde gelöscht: {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:488 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:494 msgid "Error creating torrent - you must select a tracker" msgstr "Fehler beim Erstellen des Torrent - Sie müssen einen Tracker auswählen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:503 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:509 #, java-format msgid "Torrent created for \"{0}\"" msgstr "Torrent erstellt für \"{0}\"" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:506 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512 #, java-format msgid "Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\"" msgstr "Viele I2P Tracker erfordern eine Registrierung bevor der Torrent verteilt wird - bitte machen Sie dieses vor dem Start von \"{0}\"" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:508 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:514 #, java-format msgid "Error creating a torrent for \"{0}\"" msgstr "Fehler beim Erstellen eines Torrent für \"{0}\"" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:511 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:517 #, java-format msgid "Cannot create a torrent for the nonexistent data: {0}" msgstr "Kann keinen Torrent für nicht existierende Daten erstellen: {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:514 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:520 msgid "Error creating torrent - you must enter a file or directory" msgstr "Fehler beim Erstellen des Torrent - Sie müssen eine Datei oder Verzeichnis angeben." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:517 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:523 msgid "Stopping all torrents and closing the I2P tunnel." msgstr "Stoppt alle Torrents und beendet den I2P Tunnel." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:526 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:532 msgid "I2P tunnel closed." msgstr "I2P Tunnel geschlossen." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:529 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535 msgid "Opening the I2P tunnel and starting all torrents." msgstr "Öffnet den I2P Tunnel und startet alle Torrents." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:651 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:845 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:657 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:851 msgid "Unknown" msgstr "Unbekannt" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:654 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:659 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:664 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:660 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:665 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:670 msgid "TrackerErr" msgstr "TrackerFehler" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:657 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:660 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:671 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:674 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:682 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:685 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:690 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:693 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:663 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:666 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:677 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:680 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:688 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:691 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:696 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:699 #, java-format msgid "1 peer" msgid_plural "{0} peers" msgstr[0] "1 Teilnehmer" msgstr[1] "{0} Teilnehmer" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:668 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:673 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:674 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:679 msgid "Seeding" msgstr "Verteile" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:676 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1316 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:682 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1327 msgid "Complete" msgstr "Komplett" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:679 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:684 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:685 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:690 msgid "OK" msgstr "OK" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:687 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:692 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:693 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:698 msgid "Stalled" msgstr "Gedrosselt" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:695 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:701 msgid "No Peers" msgstr "Keine Teilnehmer" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:697 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:703 msgid "Stopped" msgstr "Gestoppt" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:712 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:718 msgid "View files" msgstr "Betrachte Dateien" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:714 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:720 msgid "Open file" msgstr "Öffne Datei" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:744 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:956 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:750 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:967 msgid "Tracker" msgstr "Tracker" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:745 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:751 msgid "Details" msgstr "Details" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:779 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:785 msgid "Stop the torrent" msgstr "Stoppe den Torrent" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:781 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:787 msgid "Stop" msgstr "Stop" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:787 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:793 msgid "Start the torrent" msgstr "Starte den Torrent" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:789 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:795 msgid "Start" msgstr "Start" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:794 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:800 msgid "Remove the torrent from the active list, deleting the .torrent file" msgstr "Entfernt den Torrent von der aktiven Liste und löscht die .torrent Datei" #. 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 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:799 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:805 #, java-format msgid "Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?" msgstr "Sind Sie sicher, das Sie die Datei \\''{0}.torrent\\'' löschen wollen (heruntergeladene Daten werden nicht gelöscht)?" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:801 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:807 msgid "Remove" msgstr "Entfernen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:805 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:811 msgid "Delete the .torrent file and the associated data file(s)" msgstr "Löscht die .torrent Datei und dazugehörigen Daten Datei(en)" #. 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 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:810 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:816 #, java-format msgid "Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?" msgstr "Sind Sie sicher, das die die Torrentdatei \\''{0}\\'' und alle heruntergeladene Daten löschen wollen?" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:812 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:818 msgid "Delete" msgstr "Löschen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:855 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:861 msgid "Seed" msgstr "Quelle" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:873 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879 msgid "Uninteresting (The peer has no pieces we need)" msgstr "Uninteressiert (Der Teilnehmer hat keine Teile die wir benötigen)" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:875 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:881 msgid "Choked (The peer is not allowing us to request pieces)" msgstr "Gedrosselt (der Teilnehmer hat uns nicht erlaubt Teile anzufordern)" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:889 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:895 msgid "Uninterested (We have no pieces the peer needs)" msgstr "Uninteressiert (Wir haben keine Teile die der Teilnehmer benötigt)" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:891 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:897 msgid "Choking (We are not allowing the peer to request pieces)" msgstr "Gedrosselt (Wir erlauben dem Teilnehmer nicht Teile anzufordern)" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:918 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:927 msgid "Add Torrent" msgstr "Füge Torrent hinzu" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:920 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:929 msgid "From URL" msgstr "Quell URL" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:925 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:934 msgid "Add torrent" msgstr "Füge Torrent hinzu" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:928 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:937 #, java-format msgid "Alternately, you can copy .torrent files to the directory {0}." msgstr "Alternativ können Sie die .torrent Dateien auch nach {0} kopieren." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:930 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:939 msgid "Removing a .torrent file will cause the torrent to stop." msgstr "Entfernen der .torrent Datei stoppt einen Torrent." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:947 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:958 msgid "Create Torrent" msgstr "Erstelle einen Torrent" #. out.write("From file:
\n"); -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:950 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:961 msgid "Data to seed" msgstr "Daten zum Verteilen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:954 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:965 msgid "File or directory to seed (must be within the specified path)" msgstr "Datei oder Verzeichnis zum Verteilen (muß im angegebenen Pfad sein)" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:958 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:969 msgid "Select a tracker" msgstr "Wähle einen Tracker" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:971 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:982 msgid "or" msgstr "oder" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:974 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:985 msgid "Specify custom tracker announce URL" msgstr "Geben Sie eine Tracker Announce URL an" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:977 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:988 msgid "Create torrent" msgstr "Erstelle Torrent" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:995 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1122 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1006 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1133 msgid "Configuration" msgstr "Einstellungen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:998 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1009 msgid "Data directory" msgstr "Daten Verzeichnis" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1001 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1012 msgid "Directory to store torrents and data" msgstr "Verzeichnis zum speichern von Torrent Dateien und Daten" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1003 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1014 msgid "Edit i2psnark.config and restart to change" msgstr "Editiere i2psnark.config zum ändern und starte neu." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1007 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1018 msgid "Auto start" msgstr "Auto Start" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1011 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1022 msgid "If checked, automatically start torrents that are added" msgstr "Wenn markiert werden hinzugefügte Torrents automatisch gestartet." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1015 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1026 msgid "Startup delay" msgstr "Startverzögerung" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1017 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1028 msgid "minutes" msgstr "Minuten" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1041 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1052 msgid "Total uploader limit" msgstr "Totales Uploader Limit." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1044 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1055 msgid "peers" msgstr "Teilnehmer" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1048 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1059 msgid "Up bandwidth limit" msgstr "Upload Bandbreiten Limit." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1051 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1062 msgid "Half available bandwidth recommended." msgstr "Halbe verfügbare Bandbreite ist empfohlen." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1053 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1064 msgid "View or change router bandwidth" msgstr "Router Bandbreite ansehen oder ändern" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1057 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1068 msgid "Use open trackers also" msgstr "Benutze auch Open Tracker" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1061 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1072 msgid "If checked, announce torrents to open trackers as well as the tracker listed in the torrent file" msgstr "Wenn markiert wird der Torrent neben dem angegebenen Tracker auch bei den Open Trackers bekannt gegeben." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1065 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1076 msgid "Open tracker announce URLs" msgstr "Open Tracker Announce URL" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1077 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1088 msgid "Inbound Settings" msgstr "Eingangseinstellungen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1083 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1094 msgid "Outbound Settings" msgstr "Ausgangseinstellungen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1090 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1101 msgid "I2CP host" msgstr "I2CP Host" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1095 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1106 msgid "I2CP port" msgstr "I2CP Port" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1107 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1118 msgid "I2CP options" msgstr "I2CP Optionen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1113 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1124 msgid "Save configuration" msgstr "Speichere Einstellungen" #. * dummies for translation -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1130 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1141 #, java-format msgid "1 hop" msgid_plural "{0} hops" msgstr[0] "1 Zwischenstation" msgstr[1] "{0} Zwischenstationen" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1131 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1142 #, java-format msgid "1 tunnel" msgid_plural "{0} tunnels" msgstr[0] "1 Tunnel" msgstr[1] "{0} Tunnel" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1272 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1283 msgid "Up to higher level directory" msgstr "Eine Hierachie nach oben" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1277 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1288 msgid "File" msgstr "Datei" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1277 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1288 msgid "Size" msgstr "Größe" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1300 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1311 msgid "Directory" msgstr "Daten Verzeichnis" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1305 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1316 msgid "Torrent not found?" msgstr "Torrentdatei nicht gefunden?" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1313 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1324 msgid "File not found in torrent?" msgstr "Datei nicht gefunden im Torrent?" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1319 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1330 msgid "complete" msgstr "Komplett" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1320 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1331 msgid "bytes remaining" msgstr "Bytes noch übrig" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1445 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1456 #, java-format msgid "Torrent fetched from {0}" msgstr "Torrent geholt von {0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1473 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1484 #, java-format msgid "Torrent at {0} was not valid" msgstr "Torrent bei {0} war nicht gültig" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1478 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1489 #, java-format msgid "Torrent was not retrieved from {0}" msgstr "Torrent wurde nicht geladen von {0}" diff --git a/apps/i2psnark/locale/messages_nl.po b/apps/i2psnark/locale/messages_nl.po new file mode 100644 index 000000000..5de0d01fc --- /dev/null +++ b/apps/i2psnark/locale/messages_nl.po @@ -0,0 +1,775 @@ +# I2P +# Copyright (C) 2009 The I2P Project +# This file is distributed under the same license as the i2psnark package. +# To contribute translations, see http://www.i2p2.de/newdevelopers +# foo , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: I2P i2psnark\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-07-05 11:48+0000\n" +"PO-Revision-Date: 2010-06-15 09:07+0100\n" +"Last-Translator: duck \n" +"Language-Team: duck , monkeybrains \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Dutch\n" + +#: ../java/src/org/klomp/snark/SnarkManager.java:88 +#, java-format +msgid "Adding torrents in {0} minutes" +msgstr "Torrents toevoegen in {0} minuten" + +#: ../java/src/org/klomp/snark/SnarkManager.java:258 +#, java-format +msgid "Total uploaders limit changed to {0}" +msgstr "Totale uploaders limiet gewijzigd in {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:260 +#, java-format +msgid "Minimum total uploaders limit is {0}" +msgstr "Minimum totale uploaders limiet is {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:272 +#, java-format +msgid "Up BW limit changed to {0}KBps" +msgstr "Up bandbreedte limiet gewijzigd in {0}KBps" + +#: ../java/src/org/klomp/snark/SnarkManager.java:274 +#, java-format +msgid "Minimum up bandwidth limit is {0}KBps" +msgstr "Minimum up bandbreedte limiet is {0}KBps" + +#: ../java/src/org/klomp/snark/SnarkManager.java:286 +#, java-format +msgid "Startup delay limit changed to {0} minutes" +msgstr "Startup vertragings limiet gewijzigd in {0} minuten" + +#: ../java/src/org/klomp/snark/SnarkManager.java:333 +msgid "I2CP and tunnel changes will take effect after stopping all torrents" +msgstr "I2CP en tunnel wijzigingen hebben pas effect na het stoppen van alle torrents" + +#: ../java/src/org/klomp/snark/SnarkManager.java:339 +msgid "Disconnecting old I2CP destination" +msgstr "Oude I2CP destination wordt afgesloten" + +#: ../java/src/org/klomp/snark/SnarkManager.java:343 +#, java-format +msgid "I2CP settings changed to {0}" +msgstr "I2CP instellingen gewijzigd in {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:347 +msgid "" +"Unable to connect with the new settings, reverting to the old I2CP settings" +msgstr "Kan geen connectie maken met de nieuwe instellingen, we keren terug naar oude I2CP instellingen" + +#: ../java/src/org/klomp/snark/SnarkManager.java:351 +msgid "Unable to reconnect with the old settings!" +msgstr "Kan niet opnieuw verbinden met de oude instellingen!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:353 +msgid "Reconnected on the new I2CP destination" +msgstr "Opnieuw verbonden met de nieuwe I2CP destination" + +#: ../java/src/org/klomp/snark/SnarkManager.java:364 +#, java-format +msgid "I2CP listener restarted for \"{0}\"" +msgstr "I2CP listener herstart voor \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:375 +msgid "Enabled autostart" +msgstr "Autostart ingeschakeld" + +#: ../java/src/org/klomp/snark/SnarkManager.java:377 +msgid "Disabled autostart" +msgstr "Autostart uitgeschakeld" + +#: ../java/src/org/klomp/snark/SnarkManager.java:383 +msgid "Enabled open trackers - torrent restart required to take effect." +msgstr "Open Trackers ingeschakeld - torrent herstart nodig." + +#: ../java/src/org/klomp/snark/SnarkManager.java:385 +msgid "Disabled open trackers - torrent restart required to take effect." +msgstr "Open Trackers uitgeschakeld - torrent herstart nodig." + +#: ../java/src/org/klomp/snark/SnarkManager.java:392 +msgid "Open Tracker list changed - torrent restart required to take effect." +msgstr "Open Tracker lijst gewijzigd - torrent herstart nodig." + +#: ../java/src/org/klomp/snark/SnarkManager.java:399 +msgid "Configuration unchanged." +msgstr "Configuratie ongewijzigd." + +#: ../java/src/org/klomp/snark/SnarkManager.java:409 +#, java-format +msgid "Unable to save the config to {0}" +msgstr "Kan de configuratie niet opslaan in {0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:445 +msgid "Connecting to I2P" +msgstr "Verbinden met I2P" + +#: ../java/src/org/klomp/snark/SnarkManager.java:448 +msgid "Error connecting to I2P - check your I2CP settings!" +msgstr "Fout bij verbinden met I2P - controlleer je I2CP instellingen!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:457 +#, java-format +msgid "Error: Could not add the torrent {0}" +msgstr "Fout: Kan de torrent {0} niet toevoegen" + +#. catch this here so we don't try do delete it below +#: ../java/src/org/klomp/snark/SnarkManager.java:479 +#, java-format +msgid "Cannot open \"{0}\"" +msgstr "Kan \"{0}\" niet openen" + +#: ../java/src/org/klomp/snark/SnarkManager.java:492 +#, java-format +msgid "" +"Warning - Ignoring non-i2p tracker in \"{0}\", will announce to i2p open " +"trackers only" +msgstr "Waarschuwing - Niet-I2P tracker in \"{0}\" wordt genegeerd, zal alleen aankondigen naar i2p open trackers" + +#: ../java/src/org/klomp/snark/SnarkManager.java:494 +#, java-format +msgid "" +"Warning - Ignoring non-i2p tracker in \"{0}\", and open trackers are " +"disabled, you must enable open trackers before starting the torrent!" +msgstr "Waarschuwing - Niet-I2P tracker in \"{0}\" wordt genegeerd, en open trackers zijn uitgeschakeld, je moet open trackers inschakelen voor het starten van de torrent!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:513 +#, java-format +msgid "Torrent in \"{0}\" is invalid" +msgstr "Torrent in \"{0}\" is ongeldig" + +#: ../java/src/org/klomp/snark/SnarkManager.java:528 +#, java-format +msgid "Torrent added and started: \"{0}\"" +msgstr "Torrent toegevoegd en gestart: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:530 +#, java-format +msgid "Torrent added: \"{0}\"" +msgstr "Torrent toegevoegd: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:627 +#, java-format +msgid "Too many files in \"{0}\" ({1}), deleting it!" +msgstr "Te veel bestanden in \"{0}\" ({1}), wordt verwijderd!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:629 +#, java-format +msgid "Torrent file \"{0}\" cannot end in \".torrent\", deleting it!" +msgstr "Torrent bestand \"{0}\" kan niet eindigen in \".torrent\", wordt verwijderd!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:631 +#, java-format +msgid "No pieces in \"{0}\", deleting it!" +msgstr "Geen stukken in \"{0}\", wordt verwijderd!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:633 +#, java-format +msgid "Too many pieces in \"{0}\", limit is {1}, deleting it!" +msgstr "Te veel stukken in \"{0}\", limiet is {1}, wordt verwijderd!" + +#: ../java/src/org/klomp/snark/SnarkManager.java:635 +#, java-format +msgid "Pieces are too large in \"{0}\" ({1}B), deleting it." +msgstr "Stukken zijn te groot in \"{0}\" ({1}B), wordt verwijderd." + +#: ../java/src/org/klomp/snark/SnarkManager.java:636 +#, java-format +msgid "Limit is {0}B" +msgstr "Limiet is {0}B" + +#: ../java/src/org/klomp/snark/SnarkManager.java:644 +#, java-format +msgid "Torrents larger than {0}B are not supported yet, deleting \"{1}\"" +msgstr "Torrents groter dan {0}B worden nog niet ondersteund, verwijder \"{1}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:660 +#, java-format +msgid "Error: Could not remove the torrent {0}" +msgstr "Fout: Kan de torrent {0} niet verwijderen" + +#: ../java/src/org/klomp/snark/SnarkManager.java:681 +#, java-format +msgid "Torrent stopped: \"{0}\"" +msgstr "Torrent gestopt: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:696 +#, java-format +msgid "Torrent removed: \"{0}\"" +msgstr "Torrent verwijderd: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:729 +#, java-format +msgid "Download finished: \"{0}\"" +msgstr "Download gereed: \"{0}\"" + +#: ../java/src/org/klomp/snark/SnarkManager.java:729 +#, java-format +msgid "size: {0}B" +msgstr "grootte: {0}B" + +#: ../java/src/org/klomp/snark/SnarkManager.java:757 +msgid "Unable to connect to I2P!" +msgstr "Kan niet verbinden met I2P!" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:174 +msgid "I2PSnark - Anonymous BitTorrent Client" +msgstr "I2PSnark - Anonieme BitTorrent Client" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:185 +msgid "Torrents" +msgstr "Torrents" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:187 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:193 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:837 +msgid "I2PSnark" +msgstr "I2PSnark" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:191 +msgid "Refresh page" +msgstr "Ververs pagina" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:195 +msgid "Forum" +msgstr "Forum" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:240 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1289 +msgid "Status" +msgstr "Status" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246 +msgid "Hide Peers" +msgstr "Verberg Peers" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:249 +msgid "Show Peers" +msgstr "Toon Peers" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:254 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1271 +msgid "Torrent" +msgstr "Torrent" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:256 +msgid "ETA" +msgstr "ETA" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:258 +msgid "Downloaded" +msgstr "Gedownload" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:260 +msgid "Uploaded" +msgstr "Geupload" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:262 +msgid "Down Rate" +msgstr "Down Snelheid" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:264 +msgid "Up Rate" +msgstr "Up Snelheid" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:271 +msgid "Stop all torrents and the I2P tunnel" +msgstr "Stop alle torrents en de I2P tunnel" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:273 +msgid "Stop All" +msgstr "Stop Alle" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:278 +msgid "Start all torrents and the I2P tunnel" +msgstr "Start alle torrents en de I2P tunnel" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:280 +msgid "Start All" +msgstr "Start Alle" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:297 +msgid "No torrents loaded." +msgstr "Geen torrents geladen." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:302 +msgid "Totals" +msgstr "Totalen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:304 +#, java-format +msgid "1 torrent" +msgid_plural "{0} torrents" +msgstr[0] "1 torrent" +msgstr[1] "{0} torrents" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:307 +#, java-format +msgid "1 connected peer" +msgid_plural "{0} connected peers" +msgstr[0] "1 verbonden peer" +msgstr[1] "{0} verbonden peers" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:336 +#, java-format +msgid "Torrent file {0} does not exist" +msgstr "Torrent bestand {0} bestaat niet" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:346 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1476 +#, java-format +msgid "Torrent already running: {0}" +msgstr "Torrent draait al: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:348 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1478 +#, java-format +msgid "Torrent already in the queue: {0}" +msgstr "Torrent zit al in de wachtrij: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:352 +#, java-format +msgid "Copying torrent to {0}" +msgstr "Kopieer torrent naar {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:355 +#, java-format +msgid "Unable to copy the torrent to {0}" +msgstr "Kan de de torrent niet kopieren naar {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:355 +#, java-format +msgid "from {0}" +msgstr "van {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:363 +#, java-format +msgid "Fetching {0}" +msgstr "Downloaden {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:367 +msgid "Invalid URL - must start with http://" +msgstr "Ongeldige URL - moet beginnen met http://" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:397 +#, java-format +msgid "Starting up torrent {0}" +msgstr "Starten met torrent {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:417 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:435 +#, java-format +msgid "Torrent file deleted: {0}" +msgstr "Torrent bestand verwijderd: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:441 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:451 +#, java-format +msgid "Data file deleted: {0}" +msgstr "Data bestand verwijderd: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:443 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:453 +#, java-format +msgid "Data file could not be deleted: {0}" +msgstr "Kan data bestand niet verwijderen: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:462 +#, java-format +msgid "Data dir deleted: {0}" +msgstr "Data directory verwijderd: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:494 +msgid "Error creating torrent - you must select a tracker" +msgstr "Fout bij maken van torrent - je moet een tracker selecteren" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:509 +#, java-format +msgid "Torrent created for \"{0}\"" +msgstr "Torrent gemaakt voor \"{0}\"" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512 +#, java-format +msgid "" +"Many I2P trackers require you to register new torrents before seeding - " +"please do so before starting \"{0}\"" +msgstr "Veel I2P trackers vereisen dat je de nieuwe torrent registreert voor het seeden - " +"doe dit voordat je \"{0}\" start" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:514 +#, java-format +msgid "Error creating a torrent for \"{0}\"" +msgstr "Fout bij het maken van een torrent voor \"{0}\"" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:517 +#, java-format +msgid "Cannot create a torrent for the nonexistent data: {0}" +msgstr "Kan geen torrent maken voor niet-bestaande data: {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:520 +msgid "Error creating torrent - you must enter a file or directory" +msgstr "Fout bij het maken van de torrent - je moet een bestand of directory invullen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:523 +msgid "Stopping all torrents and closing the I2P tunnel." +msgstr "Stoppen van alle torrents en sluiten van I2P tunnel." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:532 +msgid "I2P tunnel closed." +msgstr "I2P tunnel gesloten." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535 +msgid "Opening the I2P tunnel and starting all torrents." +msgstr "Openen van de I2P tunnel en starten van alle torrents." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:657 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:851 +msgid "Unknown" +msgstr "Onbekend" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:660 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:665 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:670 +msgid "TrackerErr" +msgstr "TrackerErr" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:663 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:666 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:677 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:680 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:688 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:691 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:696 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:699 +#, java-format +msgid "1 peer" +msgid_plural "{0} peers" +msgstr[0] "1 peer" +msgstr[1] "{0} peers" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:674 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:679 +msgid "Seeding" +msgstr "Seeding" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:682 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1327 +msgid "Complete" +msgstr "Voltooid" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:685 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:690 +msgid "OK" +msgstr "OK" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:693 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:698 +msgid "Stalled" +msgstr "Vastgelopen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:701 +msgid "No Peers" +msgstr "Geen Peers" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:703 +msgid "Stopped" +msgstr "Gestopt" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:718 +msgid "View files" +msgstr "Bekijk bestanden" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:720 +msgid "Open file" +msgstr "Open bestand" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:750 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:967 +msgid "Tracker" +msgstr "Tracker" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:751 +msgid "Details" +msgstr "Details" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:785 +msgid "Stop the torrent" +msgstr "Stop de torrent" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:787 +msgid "Stop" +msgstr "Stop" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:793 +msgid "Start the torrent" +msgstr "Start de torrent" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:795 +msgid "Start" +msgstr "Start" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:800 +msgid "Remove the torrent from the active list, deleting the .torrent file" +msgstr "Verwijder de torrent van de actieve lijst, het .torrent bestand wordt verwijderd" + +#. 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 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:805 +#, java-format +msgid "" +"Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded " +"data will not be deleted) ?" +msgstr "Weet je zeker dat je het bestand \\''{0}.torrent\\'' wilt verwijderen (gedownloade data zal niet worden verwijderd) ?" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:807 +msgid "Remove" +msgstr "Weghalen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:811 +msgid "Delete the .torrent file and the associated data file(s)" +msgstr "Verwijder het .torrent bestand en de gerelateerde data bestand(en)" + +#. 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 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:816 +#, java-format +msgid "" +"Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded " +"data?" +msgstr "Weet je zeker dat je de torrent \\''{0}\\'' en alle gedownloade data wilt verwijderen?" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:818 +msgid "Delete" +msgstr "Verwijderen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:861 +msgid "Seed" +msgstr "Seed" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879 +msgid "Uninteresting (The peer has no pieces we need)" +msgstr "Niet interessant (De peer heeft geen stukken die we nodig hebben)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:881 +msgid "Choked (The peer is not allowing us to request pieces)" +msgstr "Verstikt (De peer laat ons niet toe om stukken op te vragen)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:895 +msgid "Uninterested (We have no pieces the peer needs)" +msgstr "Niet geïnteresseerd (We heben geen stukken die de peer nodig heeft)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:897 +msgid "Choking (We are not allowing the peer to request pieces)" +msgstr "Verstikt (We laten de peer niet toe om stukken op te vragen)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:927 +msgid "Add Torrent" +msgstr "Torrent Toevoegen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:929 +msgid "From URL" +msgstr "Van URL" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:934 +msgid "Add torrent" +msgstr "Torrent toevoegen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:937 +#, java-format +msgid "Alternately, you can copy .torrent files to the directory {0}." +msgstr "Als alternatief kan je het .torrent bestand kopieren naar de directory {0}." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:939 +msgid "Removing a .torrent file will cause the torrent to stop." +msgstr "Verwijderen van een .torrent bestand zorgt dat de torrent stopt." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:958 +msgid "Create Torrent" +msgstr "Creëer Torrent" + +#. out.write("From file:
\n"); +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:961 +msgid "Data to seed" +msgstr "Data om te seeden" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:965 +msgid "File or directory to seed (must be within the specified path)" +msgstr "Bestand of directory om te seeden (moet binnen het gespecificeerde pad zijn)" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:969 +msgid "Select a tracker" +msgstr "Selecteer een tracker" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:982 +msgid "or" +msgstr "of" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:985 +msgid "Specify custom tracker announce URL" +msgstr "Specificeer aangepaste tracker aankondigings URL" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:988 +msgid "Create torrent" +msgstr "Creëer torrent" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1006 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1133 +msgid "Configuration" +msgstr "Configuratie" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1009 +msgid "Data directory" +msgstr "Data directory" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1012 +msgid "Directory to store torrents and data" +msgstr "Directory om torrents en data op te slaan" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1014 +msgid "Edit i2psnark.config and restart to change" +msgstr "Bewerk i2psnark.config en herstart de wijziging" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1018 +msgid "Auto start" +msgstr "Auto start" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1022 +msgid "If checked, automatically start torrents that are added" +msgstr "Indien aangevinkt, start toegevoegde torrents automatisch" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1026 +msgid "Startup delay" +msgstr "Startup vertraging" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1028 +msgid "minutes" +msgstr "minuten" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1052 +msgid "Total uploader limit" +msgstr "Totale uploader limiet" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1055 +msgid "peers" +msgstr "peers" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1059 +msgid "Up bandwidth limit" +msgstr "Up bandbreedte limiet" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1062 +msgid "Half available bandwidth recommended." +msgstr "Helft van beschikbare bandbreedte aanbevolen." + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1064 +msgid "View or change router bandwidth" +msgstr "Bekijk of wijzig router bandbreedte" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1068 +msgid "Use open trackers also" +msgstr "Gebruik ook open trackers" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1072 +msgid "" +"If checked, announce torrents to open trackers as well as the tracker listed " +"in the torrent file" +msgstr "Indien aangevinkt, kondig torrents ook aan bij de tracker uit het torrent bestand" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1076 +msgid "Open tracker announce URLs" +msgstr "Open tracker aankondigings URLs" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1088 +msgid "Inbound Settings" +msgstr "Inkomende Instellingen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1094 +msgid "Outbound Settings" +msgstr "Uitgaande Instellingen" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1101 +msgid "I2CP host" +msgstr "I2CP host" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1106 +msgid "I2CP port" +msgstr "I2CP poort" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1118 +msgid "I2CP options" +msgstr "I2CP opties" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1124 +msgid "Save configuration" +msgstr "Configuratie opslaan" + +#. * dummies for translation +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1141 +#, java-format +msgid "1 hop" +msgid_plural "{0} hops" +msgstr[0] "1 hop" +msgstr[1] "{0} hops" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1142 +#, java-format +msgid "1 tunnel" +msgid_plural "{0} tunnels" +msgstr[0] "1 tunnel" +msgstr[1] "{0} tunnels" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1283 +msgid "Up to higher level directory" +msgstr "Naar bovenliggende directory" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1288 +msgid "File" +msgstr "Bestand" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1288 +msgid "Size" +msgstr "Grootte" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1311 +msgid "Directory" +msgstr "Directory" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1316 +msgid "Torrent not found?" +msgstr "Torrent niet gevonden?" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1324 +msgid "File not found in torrent?" +msgstr "Bestand niet gevonden in torrent?" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1330 +msgid "complete" +msgstr "voltooid" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1331 +msgid "bytes remaining" +msgstr "bytes resterend" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1456 +#, java-format +msgid "Torrent fetched from {0}" +msgstr "Torrent gedownload van {0}" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1484 +#, java-format +msgid "Torrent at {0} was not valid" +msgstr "Torrent op {0} was niet geldig" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1489 +#, java-format +msgid "Torrent was not retrieved from {0}" +msgstr "Torrent was niet ontvangen van {0}" diff --git a/apps/i2psnark/locale/messages_zh.po b/apps/i2psnark/locale/messages_zh.po index e5538dd48..e39ae0970 100644 --- a/apps/i2psnark/locale/messages_zh.po +++ b/apps/i2psnark/locale/messages_zh.po @@ -8,8 +8,8 @@ msgid "" msgstr "" "Project-Id-Version: I2P i2psnark\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-05-29 02:34+0000\n" -"PO-Revision-Date: 2010-05-29 10:55+0800\n" +"POT-Creation-Date: 2010-07-01 04:52+0000\n" +"PO-Revision-Date: 2010-07-01 12:53+0800\n" "Last-Translator: walking \n" "Language-Team: foo \n" "MIME-Version: 1.0\n" @@ -18,718 +18,740 @@ msgstr "" "X-Poedit-Language: Chinese\n" "Plural-Forms: nplurals=1; plural=0\n" -#: ../java/src/org/klomp/snark/SnarkManager.java:87 +#: ../java/src/org/klomp/snark/SnarkManager.java:88 #, java-format msgid "Adding torrents in {0} minutes" msgstr "{0}分钟内完成添加" -#: ../java/src/org/klomp/snark/SnarkManager.java:251 +#: ../java/src/org/klomp/snark/SnarkManager.java:258 #, java-format msgid "Total uploaders limit changed to {0}" msgstr "总上传种子数限制已更新为{0}" -#: ../java/src/org/klomp/snark/SnarkManager.java:253 +#: ../java/src/org/klomp/snark/SnarkManager.java:260 #, java-format msgid "Minimum total uploaders limit is {0}" msgstr "最低上传种子数限制为{0}" -#: ../java/src/org/klomp/snark/SnarkManager.java:265 +#: ../java/src/org/klomp/snark/SnarkManager.java:272 #, java-format msgid "Up BW limit changed to {0}KBps" msgstr "上传带宽限制改为 {0} KBps" -#: ../java/src/org/klomp/snark/SnarkManager.java:267 +#: ../java/src/org/klomp/snark/SnarkManager.java:274 #, java-format msgid "Minimum up bandwidth limit is {0}KBps" msgstr "最小上传带宽限制为 {0} KBps" -#: ../java/src/org/klomp/snark/SnarkManager.java:314 +#: ../java/src/org/klomp/snark/SnarkManager.java:286 +#, java-format +msgid "Startup delay limit changed to {0} minutes" +msgstr "启动延迟已更新为{0}" + +#: ../java/src/org/klomp/snark/SnarkManager.java:333 msgid "I2CP and tunnel changes will take effect after stopping all torrents" msgstr "I2CP与隧道设置的变化在所有种子停止后才能生效" -#: ../java/src/org/klomp/snark/SnarkManager.java:320 +#: ../java/src/org/klomp/snark/SnarkManager.java:339 msgid "Disconnecting old I2CP destination" msgstr "正在断开旧的I2CP目标" -#: ../java/src/org/klomp/snark/SnarkManager.java:324 +#: ../java/src/org/klomp/snark/SnarkManager.java:343 #, java-format msgid "I2CP settings changed to {0}" msgstr "I2CP设置改为{0}" -#: ../java/src/org/klomp/snark/SnarkManager.java:328 +#: ../java/src/org/klomp/snark/SnarkManager.java:347 msgid "Unable to connect with the new settings, reverting to the old I2CP settings" msgstr "无法通过新设置连接,恢复I2CP的旧设置" -#: ../java/src/org/klomp/snark/SnarkManager.java:332 +#: ../java/src/org/klomp/snark/SnarkManager.java:351 msgid "Unable to reconnect with the old settings!" msgstr "旧设置也无法连接!" -#: ../java/src/org/klomp/snark/SnarkManager.java:334 +#: ../java/src/org/klomp/snark/SnarkManager.java:353 msgid "Reconnected on the new I2CP destination" msgstr "重新连接新I2CP目标" -#: ../java/src/org/klomp/snark/SnarkManager.java:345 +#: ../java/src/org/klomp/snark/SnarkManager.java:364 #, java-format msgid "I2CP listener restarted for \"{0}\"" msgstr "\"{0}\"的I2CP监听端口已启动" -#: ../java/src/org/klomp/snark/SnarkManager.java:356 +#: ../java/src/org/klomp/snark/SnarkManager.java:375 msgid "Enabled autostart" msgstr "启用自动启动" -#: ../java/src/org/klomp/snark/SnarkManager.java:358 +#: ../java/src/org/klomp/snark/SnarkManager.java:377 msgid "Disabled autostart" msgstr "禁用自动启动" -#: ../java/src/org/klomp/snark/SnarkManager.java:364 +#: ../java/src/org/klomp/snark/SnarkManager.java:383 msgid "Enabled open trackers - torrent restart required to take effect." msgstr "启用OpenTracker-重新启动种子后生效" -#: ../java/src/org/klomp/snark/SnarkManager.java:366 +#: ../java/src/org/klomp/snark/SnarkManager.java:385 msgid "Disabled open trackers - torrent restart required to take effect." msgstr "禁用OpenTracker - 重新启动种子后生效" -#: ../java/src/org/klomp/snark/SnarkManager.java:373 +#: ../java/src/org/klomp/snark/SnarkManager.java:392 msgid "Open Tracker list changed - torrent restart required to take effect." msgstr "OpenTracker列表已改变 - 重新启动种子后生效" -#: ../java/src/org/klomp/snark/SnarkManager.java:380 +#: ../java/src/org/klomp/snark/SnarkManager.java:399 msgid "Configuration unchanged." msgstr "设置未改变" -#: ../java/src/org/klomp/snark/SnarkManager.java:390 +#: ../java/src/org/klomp/snark/SnarkManager.java:409 #, java-format msgid "Unable to save the config to {0}" msgstr "无法保存设置到{0}" -#: ../java/src/org/klomp/snark/SnarkManager.java:408 +#: ../java/src/org/klomp/snark/SnarkManager.java:445 msgid "Connecting to I2P" msgstr "正在连接到I2P" -#: ../java/src/org/klomp/snark/SnarkManager.java:411 +#: ../java/src/org/klomp/snark/SnarkManager.java:448 msgid "Error connecting to I2P - check your I2CP settings!" msgstr "连接I2P时发生错误 - 请检查I2CP设置!" -#: ../java/src/org/klomp/snark/SnarkManager.java:420 +#: ../java/src/org/klomp/snark/SnarkManager.java:457 #, java-format msgid "Error: Could not add the torrent {0}" msgstr "错误:无法添加种子{0}" -#: ../java/src/org/klomp/snark/SnarkManager.java:442 +#. catch this here so we don't try do delete it below +#: ../java/src/org/klomp/snark/SnarkManager.java:479 #, java-format msgid "Cannot open \"{0}\"" msgstr "无法打开 \"{0}\"" -#: ../java/src/org/klomp/snark/SnarkManager.java:455 +#: ../java/src/org/klomp/snark/SnarkManager.java:492 #, java-format msgid "Warning - Ignoring non-i2p tracker in \"{0}\", will announce to i2p open trackers only" msgstr "警告 - 忽略\"{0}\"文件中I2P网络外的Tracker服务器,文件将仅发布至 I2P 内的 Open Tracker 服务器。" -#: ../java/src/org/klomp/snark/SnarkManager.java:457 +#: ../java/src/org/klomp/snark/SnarkManager.java:494 #, java-format msgid "Warning - Ignoring non-i2p tracker in \"{0}\", and open trackers are disabled, you must enable open trackers before starting the torrent!" msgstr "警告 - 忽略\"{0}\"文件中I2P网络外的Tracker服务器,OpenTracker已禁用,启动此种子前您必须启用OpenTracker。" -#: ../java/src/org/klomp/snark/SnarkManager.java:476 +#: ../java/src/org/klomp/snark/SnarkManager.java:513 #, java-format msgid "Torrent in \"{0}\" is invalid" msgstr "无效种子 \"{0}\" " -#: ../java/src/org/klomp/snark/SnarkManager.java:491 +#: ../java/src/org/klomp/snark/SnarkManager.java:528 #, java-format msgid "Torrent added and started: \"{0}\"" msgstr "已添加并启动种子:\"{0}\"" -#: ../java/src/org/klomp/snark/SnarkManager.java:493 +#: ../java/src/org/klomp/snark/SnarkManager.java:530 #, java-format msgid "Torrent added: \"{0}\"" msgstr "已添加种子:\"{0}\"" -#: ../java/src/org/klomp/snark/SnarkManager.java:590 +#: ../java/src/org/klomp/snark/SnarkManager.java:627 #, java-format msgid "Too many files in \"{0}\" ({1}), deleting it!" msgstr "\"{0}\" ({1}) 含有太多文件,删除之!" -#: ../java/src/org/klomp/snark/SnarkManager.java:592 +#: ../java/src/org/klomp/snark/SnarkManager.java:629 #, java-format msgid "Torrent file \"{0}\" cannot end in \".torrent\", deleting it!" msgstr "种子文件 \"{0}\" 不以 \".torrent\"结尾,正在删除!" -#: ../java/src/org/klomp/snark/SnarkManager.java:594 +#: ../java/src/org/klomp/snark/SnarkManager.java:631 #, java-format msgid "No pieces in \"{0}\", deleting it!" msgstr "\"{0}\" 中没有数据片,删除之!" -#: ../java/src/org/klomp/snark/SnarkManager.java:596 +#: ../java/src/org/klomp/snark/SnarkManager.java:633 #, java-format msgid "Too many pieces in \"{0}\", limit is {1}, deleting it!" msgstr "\"{0}\" 中文件分片太多,限额为{1},删除之!" -#: ../java/src/org/klomp/snark/SnarkManager.java:598 +#: ../java/src/org/klomp/snark/SnarkManager.java:635 #, java-format msgid "Pieces are too large in \"{0}\" ({1}B), deleting it." msgstr "\"{0}\" ({1}B) 中文件分片过大,删除之。" -#: ../java/src/org/klomp/snark/SnarkManager.java:599 +#: ../java/src/org/klomp/snark/SnarkManager.java:636 #, java-format msgid "Limit is {0}B" msgstr "限额为 {0}B" -#: ../java/src/org/klomp/snark/SnarkManager.java:607 +#: ../java/src/org/klomp/snark/SnarkManager.java:644 #, java-format msgid "Torrents larger than {0}B are not supported yet, deleting \"{1}\"" msgstr "目前不支持大于{0}B 的种子,正在删除\"{1}\"" -#: ../java/src/org/klomp/snark/SnarkManager.java:623 +#: ../java/src/org/klomp/snark/SnarkManager.java:660 #, java-format msgid "Error: Could not remove the torrent {0}" msgstr "错误:无法删除种子{0}" -#: ../java/src/org/klomp/snark/SnarkManager.java:644 +#: ../java/src/org/klomp/snark/SnarkManager.java:681 #, java-format msgid "Torrent stopped: \"{0}\"" msgstr "种子已停止:\"{0}\"" -#: ../java/src/org/klomp/snark/SnarkManager.java:659 +#: ../java/src/org/klomp/snark/SnarkManager.java:696 #, java-format msgid "Torrent removed: \"{0}\"" msgstr "种子已删除:\"{0}\"" -#: ../java/src/org/klomp/snark/SnarkManager.java:692 +#: ../java/src/org/klomp/snark/SnarkManager.java:729 #, java-format msgid "Download finished: \"{0}\"" msgstr "下载已完成:\"{0}\"" -#: ../java/src/org/klomp/snark/SnarkManager.java:692 +#: ../java/src/org/klomp/snark/SnarkManager.java:729 #, java-format msgid "size: {0}B" msgstr "大小:{0}B" -#: ../java/src/org/klomp/snark/SnarkManager.java:720 +#: ../java/src/org/klomp/snark/SnarkManager.java:757 msgid "Unable to connect to I2P!" msgstr "无法连接至I2P!" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:169 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:174 msgid "I2PSnark - Anonymous BitTorrent Client" msgstr "I2PSnark - 匿名BitTorrent客户端" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:178 -msgid "Refresh page" -msgstr "刷新页面" +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:185 +msgid "Torrents" +msgstr "种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:180 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:808 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:187 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:193 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:837 msgid "I2PSnark" msgstr "" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:182 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:191 +msgid "Refresh page" +msgstr "刷新页面" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:195 msgid "Forum" msgstr "论坛" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:208 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1243 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:240 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1289 msgid "Status" msgstr "状态" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:214 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246 msgid "Hide Peers" msgstr "隐藏用户" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:217 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:249 msgid "Show Peers" msgstr "显示用户" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:222 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1225 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:254 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1271 msgid "Torrent" msgstr "种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:224 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:256 msgid "ETA" msgstr "预计剩余时间" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:226 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:258 msgid "Downloaded" msgstr "已下载" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:228 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:260 msgid "Uploaded" msgstr "已上传" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:230 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:262 msgid "Down Rate" msgstr "下载速度" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:232 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:264 msgid "Up Rate" msgstr "上传速度" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:239 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:271 msgid "Stop all torrents and the I2P tunnel" msgstr "停止全部种子及I2P隧道" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:241 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:273 msgid "Stop All" msgstr "停止全部" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:278 msgid "Start all torrents and the I2P tunnel" msgstr "启动全部种子及I2P隧道" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:248 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:280 msgid "Start All" msgstr "启动全部" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:265 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:297 msgid "No torrents loaded." msgstr "未载入任何种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:270 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:302 msgid "Totals" msgstr "总计" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:272 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:304 #, java-format msgid "1 torrent" msgid_plural "{0} torrents" msgstr[0] "{0}个种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:275 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:307 #, java-format msgid "1 connected peer" msgid_plural "{0} connected peers" msgstr[0] "{0}个已连接用户" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:310 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:336 #, java-format msgid "Torrent file {0} does not exist" msgstr "种子文件{0}不存在" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:320 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1428 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:346 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1476 #, java-format msgid "Torrent already running: {0}" msgstr "种子已启动:{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:322 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1430 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:348 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1478 #, java-format msgid "Torrent already in the queue: {0}" msgstr "种子排队中:{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:326 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:352 #, java-format msgid "Copying torrent to {0}" msgstr "正在复制种子到{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:329 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:355 #, java-format msgid "Unable to copy the torrent to {0}" msgstr "无法复制种子文件到{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:329 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:355 #, java-format msgid "from {0}" msgstr "来源{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:337 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:363 #, java-format msgid "Fetching {0}" msgstr "正在获取{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:341 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:367 msgid "Invalid URL - must start with http://" msgstr "无效链接 - 必须以http:// 开头" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:371 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:397 #, java-format msgid "Starting up torrent {0}" msgstr "正在启动种子{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:391 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:409 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:417 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:435 #, java-format msgid "Torrent file deleted: {0}" msgstr "种子文件已删除:{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:415 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:425 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:441 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:451 #, java-format msgid "Data file deleted: {0}" msgstr "数据文件已删除:{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:417 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:427 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:443 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:453 #, java-format msgid "Data file could not be deleted: {0}" msgstr "无法删除数据文件:{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:436 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:462 #, java-format msgid "Data dir deleted: {0}" msgstr "数据文件夹已删除:{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:467 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:494 msgid "Error creating torrent - you must select a tracker" msgstr "创建种子时发生错误 - 您必须选择一个Tracker" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:482 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:509 #, java-format msgid "Torrent created for \"{0}\"" msgstr "种子创建成功\"{0}\"" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:485 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512 #, java-format msgid "Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\"" msgstr "多数I2PTracker需要用户在做种前注册新种子 - 请在启动 \"{0}\"前到所使用的Tracker进行注册。" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:487 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:514 #, java-format msgid "Error creating a torrent for \"{0}\"" msgstr "创建种子时发生错误 \"{0}\"" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:490 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:517 #, java-format msgid "Cannot create a torrent for the nonexistent data: {0}" msgstr "无法为不存在的数据文件创建种子:{0}" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:493 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:520 msgid "Error creating torrent - you must enter a file or directory" msgstr "创建种子时发生错误 - 必须指定文件或文件夹" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:496 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:523 msgid "Stopping all torrents and closing the I2P tunnel." msgstr "正在停用所有种子并关闭I2P隧道。" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:505 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:532 msgid "I2P tunnel closed." msgstr "I2P隧道已关闭" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:508 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535 msgid "Opening the I2P tunnel and starting all torrents." msgstr "正在打开I2P隧道并启动所有种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:628 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:822 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:657 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:851 msgid "Unknown" msgstr "未知" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:631 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:636 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:641 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:660 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:665 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:670 msgid "TrackerErr" msgstr "Tracker错误" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:634 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:637 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:648 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:651 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:659 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:662 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:667 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:670 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:663 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:666 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:677 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:680 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:688 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:691 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:696 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:699 #, java-format msgid "1 peer" msgid_plural "{0} peers" msgstr[0] "{0}个用户" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:645 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:650 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:674 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:679 msgid "Seeding" msgstr "正做种" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:653 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1281 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:682 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1327 msgid "Complete" msgstr "完成" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:656 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:661 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:685 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:690 msgid "OK" msgstr "确定" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:664 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:669 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:693 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:698 msgid "Stalled" msgstr "等待" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:672 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:701 msgid "No Peers" msgstr "没有用户" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:674 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:703 msgid "Stopped" msgstr "已停用" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:689 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:718 msgid "View files" msgstr "浏览文件" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:691 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:720 msgid "Open file" msgstr "打开文件" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:721 -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:933 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:750 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:967 msgid "Tracker" msgstr "Tracker服务器" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:722 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:751 msgid "Details" msgstr "详情" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:756 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:785 msgid "Stop the torrent" msgstr "停止种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:758 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:787 msgid "Stop" msgstr "停止" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:764 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:793 msgid "Start the torrent" msgstr "启动种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:766 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:795 msgid "Start" msgstr "启动" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:771 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:800 msgid "Remove the torrent from the active list, deleting the .torrent file" msgstr "取消下载任务并删除对应种子文件。" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:776 +#. 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 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:805 #, java-format msgid "Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?" msgstr "您确定要删除文件“{0}.torrent”(下载的数据文件不会被删除)?" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:778 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:807 msgid "Remove" msgstr "移除" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:782 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:811 msgid "Delete the .torrent file and the associated data file(s)" msgstr "删除种子及所下载的文件" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:787 +#. 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 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:816 #, java-format msgid "Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?" msgstr "您确定要删除种子“{0}”(下载的数据文件会一并被删除)?" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:789 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:818 msgid "Delete" msgstr "删除" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:832 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:861 msgid "Seed" msgstr "种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:850 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879 msgid "Uninteresting (The peer has no pieces we need)" msgstr "无需要部分" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:852 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:881 msgid "Choked (The peer is not allowing us to request pieces)" msgstr "拒绝请求" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:866 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:895 msgid "Uninterested (We have no pieces the peer needs)" msgstr "无需要部分" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:868 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:897 msgid "Choking (We are not allowing the peer to request pieces)" msgstr "拒绝请求" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:895 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:927 msgid "Add Torrent" msgstr "添加种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:897 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:929 msgid "From URL" msgstr "从URL" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:902 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:934 msgid "Add torrent" msgstr "添加种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:905 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:937 #, java-format msgid "Alternately, you can copy .torrent files to the directory {0}." msgstr "或者您可以将.torrent文件复制到以下目录{0}." -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:907 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:939 msgid "Removing a .torrent file will cause the torrent to stop." msgstr "删除种子文件将导致中止该下载任务。" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:924 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:958 msgid "Create Torrent" msgstr "创建种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:927 +#. out.write("From file:
\n"); +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:961 msgid "Data to seed" msgstr "做种数据" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:931 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:965 msgid "File or directory to seed (must be within the specified path)" msgstr "做种文件或文件夹(必须下面为Snark指定的文件夹中)" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:935 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:969 msgid "Select a tracker" msgstr "选择一个Tracker" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:948 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:982 msgid "or" msgstr "或" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:951 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:985 msgid "Specify custom tracker announce URL" msgstr "指定Open Tracker发布链接" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:954 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:988 msgid "Create torrent" msgstr "创建种子" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:972 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1006 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1133 msgid "Configuration" msgstr "设置" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:975 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1009 msgid "Data directory" msgstr "数据文件夹" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:978 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1012 msgid "Directory to store torrents and data" msgstr "种子及被做种文件的保存位置。" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:980 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1014 msgid "Edit i2psnark.config and restart to change" msgstr "编辑 i2psnark.config 并重启Snark后生效" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:984 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1018 msgid "Auto start" msgstr "自动启动" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:988 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1022 msgid "If checked, automatically start torrents that are added" msgstr "选中后Snark将自动启动已添加的所有种子。" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1011 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1026 +msgid "Startup delay" +msgstr "启动延迟" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1028 +msgid "minutes" +msgstr "分" + +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1052 msgid "Total uploader limit" msgstr "限制总上传种子数为" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1014 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1055 msgid "peers" msgstr "用户" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1018 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1059 msgid "Up bandwidth limit" msgstr "上传带宽限制" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1021 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1062 msgid "Half available bandwidth recommended." msgstr "推荐设置为可用带宽的一半。" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1023 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1064 msgid "View or change router bandwidth" msgstr "浏览或修改路由器带宽" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1027 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1068 msgid "Use open trackers also" msgstr "同时使用OpenTracker" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1031 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1072 msgid "If checked, announce torrents to open trackers as well as the tracker listed in the torrent file" msgstr "选择后在OpenTracker及种子文件中的Tracker上同时发布。" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1035 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1076 msgid "Open tracker announce URLs" msgstr "Open Tracker发布链接" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1047 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1088 msgid "Inbound Settings" msgstr "入站设置" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1053 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1094 msgid "Outbound Settings" msgstr "出站设置" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1060 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1101 msgid "I2CP host" msgstr "I2CP主机" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1065 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1106 msgid "I2CP port" msgstr "I2CP端口" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1077 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1118 msgid "I2CP options" msgstr "I2CP选项" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1082 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1124 msgid "Save configuration" msgstr "保存设置" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1092 +#. * dummies for translation +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1141 #, java-format msgid "1 hop" msgid_plural "{0} hops" msgstr[0] "{0}跳" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1093 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1142 #, java-format msgid "1 tunnel" msgid_plural "{0} tunnels" msgstr[0] "{0}隧道" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1107 -#, java-format -msgid "1 " -msgid_plural "{0} " -msgstr[0] "" - -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1237 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1283 msgid "Up to higher level directory" msgstr "上一层文件夹" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1242 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1288 msgid "File" msgstr "文件" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1242 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1288 msgid "Size" msgstr "大小" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1265 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1311 msgid "Directory" msgstr "文件夹" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1270 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1316 msgid "Torrent not found?" msgstr "种子未找到" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1278 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1324 msgid "File not found in torrent?" msgstr "种子中没有发现文件?" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1284 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1330 msgid "complete" msgstr "完成" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1285 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1331 msgid "bytes remaining" msgstr "剩余字节数" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1408 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1456 #, java-format msgid "Torrent fetched from {0}" msgstr "从{0}获取种子成功" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1436 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1484 #, java-format msgid "Torrent at {0} was not valid" msgstr "{0}的种子中有错误" -#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1441 +#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1489 #, java-format msgid "Torrent was not retrieved from {0}" msgstr "从{0}获得种子失败" diff --git a/apps/i2ptunnel/java/build.xml b/apps/i2ptunnel/java/build.xml index 9647fa8d1..7b66b6882 100644 --- a/apps/i2ptunnel/java/build.xml +++ b/apps/i2ptunnel/java/build.xml @@ -1,7 +1,7 @@ - + @@ -34,6 +34,10 @@ + + @@ -41,8 +45,6 @@ - - @@ -77,13 +79,13 @@
- + - + diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java index af4049a21..326ebb644 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/HTTPResponseOutputStream.java @@ -24,6 +24,9 @@ import net.i2p.util.I2PAppThread; import net.i2p.util.Log; /** + * This does the transparent gzip decompression on the client side. + * Extended in I2PTunnelHTTPServer to do the compression on the server side. + * * Simple stream for delivering an HTTP response to * the client, trivially filtered to make sure "Connection: close" * is always in the response. Perhaps add transparent handling of the @@ -33,29 +36,27 @@ import net.i2p.util.Log; * */ class HTTPResponseOutputStream extends FilterOutputStream { - private I2PAppContext _context; - private Log _log; - private ByteCache _cache; + private final I2PAppContext _context; + private final Log _log; protected ByteArray _headerBuffer; private boolean _headerWritten; - private byte _buf1[]; + private final byte _buf1[]; protected boolean _gzip; private long _dataWritten; private InternalGZIPInputStream _in; private static final int CACHE_SIZE = 8*1024; + private static final ByteCache _cache = ByteCache.getInstance(8, CACHE_SIZE); + // OOM DOS prevention + private static final int MAX_HEADER_SIZE = 64*1024; public HTTPResponseOutputStream(OutputStream raw) { super(raw); _context = I2PAppContext.getGlobalContext(); - _context.statManager().createRateStat("i2ptunnel.httpCompressionRatio", "ratio of compressed size to decompressed size after transfer", "I2PTunnel", new long[] { 60*1000, 30*60*1000 }); - _context.statManager().createRateStat("i2ptunnel.httpCompressed", "compressed size transferred", "I2PTunnel", new long[] { 60*1000, 30*60*1000 }); - _context.statManager().createRateStat("i2ptunnel.httpExpanded", "size transferred after expansion", "I2PTunnel", new long[] { 60*1000, 30*60*1000 }); + _context.statManager().createRateStat("i2ptunnel.httpCompressionRatio", "ratio of compressed size to decompressed size after transfer", "I2PTunnel", new long[] { 60*60*1000 }); + _context.statManager().createRateStat("i2ptunnel.httpCompressed", "compressed size transferred", "I2PTunnel", new long[] { 60*60*1000 }); + _context.statManager().createRateStat("i2ptunnel.httpExpanded", "size transferred after expansion", "I2PTunnel", new long[] { 60*60*1000 }); _log = _context.logManager().getLog(getClass()); - _cache = ByteCache.getInstance(8, CACHE_SIZE); _headerBuffer = _cache.acquire(); - _headerWritten = false; - _gzip = false; - _dataWritten = 0; _buf1 = new byte[1]; } @@ -96,14 +97,20 @@ class HTTPResponseOutputStream extends FilterOutputStream { } } - /** grow (and free) the buffer as necessary */ - private void ensureCapacity() { + /** + * grow (and free) the buffer as necessary + * @throws IOException if the headers are too big + */ + private void ensureCapacity() throws IOException { + if (_headerBuffer.getValid() >= MAX_HEADER_SIZE) + throw new IOException("Max header size exceeded: " + MAX_HEADER_SIZE); if (_headerBuffer.getValid() + 1 >= _headerBuffer.getData().length) { int newSize = (int)(_headerBuffer.getData().length * 1.5); ByteArray newBuf = new ByteArray(new byte[newSize]); System.arraycopy(_headerBuffer.getData(), 0, newBuf.getData(), 0, _headerBuffer.getValid()); newBuf.setValid(_headerBuffer.getValid()); newBuf.setOffset(0); + // if we changed the ByteArray size, don't put it back in the cache if (_headerBuffer.getData().length == CACHE_SIZE) _cache.release(_headerBuffer); _headerBuffer = newBuf; @@ -219,7 +226,7 @@ class HTTPResponseOutputStream extends FilterOutputStream { //out.flush(); PipedInputStream pi = new PipedInputStream(); PipedOutputStream po = new PipedOutputStream(pi); - new I2PAppThread(new Pusher(pi, out), "HTTP decompresser").start(); + new I2PAppThread(new Pusher(pi, out), "HTTP decompressor").start(); out = po; } @@ -231,13 +238,13 @@ class HTTPResponseOutputStream extends FilterOutputStream { _out = out; } public void run() { - OutputStream to = null; _in = null; - long start = System.currentTimeMillis(); long written = 0; + ByteArray ba = null; try { _in = new InternalGZIPInputStream(_inRaw); - byte buf[] = new byte[8192]; + ba = _cache.acquire(); + byte buf[] = ba.getData(); int read = -1; while ( (read = _in.read(buf)) != -1) { if (_log.shouldLog(Log.DEBUG)) @@ -251,6 +258,8 @@ class HTTPResponseOutputStream extends FilterOutputStream { } catch (IOException ioe) { if (_log.shouldLog(Log.WARN)) _log.warn("Error decompressing: " + written + ", " + (_in != null ? _in.getTotalRead() + "/" + _in.getTotalExpanded() : ""), ioe); + } catch (OutOfMemoryError oom) { + _log.error("OOM in HTTP Decompressor", oom); } finally { if (_log.shouldLog(Log.WARN) && (_in != null)) _log.warn("After decompression, written=" + written + @@ -259,23 +268,26 @@ class HTTPResponseOutputStream extends FilterOutputStream { + ", expanded=" + _in.getTotalExpanded() + ", remaining=" + _in.getRemaining() + ", finished=" + _in.getFinished() : "")); + if (ba != null) + _cache.release(ba); if (_out != null) try { _out.close(); } catch (IOException ioe) {} } - long end = System.currentTimeMillis(); + double compressed = (_in != null ? _in.getTotalRead() : 0); double expanded = (_in != null ? _in.getTotalExpanded() : 0); - double ratio = 0; - if (expanded > 0) - ratio = compressed/expanded; - - _context.statManager().addRateData("i2ptunnel.httpCompressionRatio", (int)(100d*ratio), end-start); - _context.statManager().addRateData("i2ptunnel.httpCompressed", (long)compressed, end-start); - _context.statManager().addRateData("i2ptunnel.httpExpanded", (long)expanded, end-start); + if (compressed > 0 && expanded > 0) { + // only update the stats if we did something + double ratio = compressed/expanded; + _context.statManager().addRateData("i2ptunnel.httpCompressionRatio", (int)(100d*ratio), 0); + _context.statManager().addRateData("i2ptunnel.httpCompressed", (long)compressed, 0); + _context.statManager().addRateData("i2ptunnel.httpExpanded", (long)expanded, 0); + } } } + /** just a wrapper to provide stats for debugging */ private static class InternalGZIPInputStream extends GZIPInputStream { public InternalGZIPInputStream(InputStream in) throws IOException { super(in); @@ -294,6 +306,12 @@ class HTTPResponseOutputStream extends FilterOutputStream { return 0; } } + + /** + * From Inflater javadoc: + * Returns the total number of bytes remaining in the input buffer. This can be used to find out + * what bytes still remain in the input buffer after decompression has finished. + */ public long getRemaining() { try { return super.inf.getRemaining(); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java index 363cd0679..17049626c 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnel.java @@ -69,6 +69,9 @@ import net.i2p.util.EventDispatcher; import net.i2p.util.EventDispatcherImpl; import net.i2p.util.Log; +/** + * Todo: Most events are not listened to elsewhere, so error propagation is poor + */ public class I2PTunnel implements Logging, EventDispatcher { private Log _log; private EventDispatcherImpl _event; @@ -163,7 +166,12 @@ public class I2PTunnel implements Logging, EventDispatcher { System.out.print("I2PTunnel>"); String cmd = r.readLine(); if (cmd == null) break; - runCommand(cmd, this); + if (cmd.length() <= 0) continue; + try { + runCommand(cmd, this); + } catch (Throwable t) { + t.printStackTrace(); + } } } catch (IOException ex) { ex.printStackTrace(); @@ -180,6 +188,7 @@ public class I2PTunnel implements Logging, EventDispatcher { } } + /** @return non-null */ List getSessions() { synchronized (_sessions) { return new ArrayList(_sessions); @@ -351,6 +360,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {hostname, portNumber, privKeyFilename} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runServer(String args[], Logging l) { if (args.length == 3) { @@ -363,7 +373,7 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("unknown host"); _log.error(getPrefix() + "Error resolving " + args[0], uhe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Error resolving " + args[0] + uhe.getMessage()); } try { @@ -372,17 +382,18 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; } + if (portNum <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[1]); privKeyFile = new File(args[2]); if (!privKeyFile.isAbsolute()) privKeyFile = new File(_context.getConfigDir(), args[2]); if (!privKeyFile.canRead()) { - l.log("private key file does not exist"); + l.log(getPrefix() + "Private key file does not exist or is not readable: " + args[2]); _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[2]); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Cannot open private key file " + args[2]); } I2PTunnelServer serv = new I2PTunnelServer(serverHost, portNum, privKeyFile, args[2], l, (EventDispatcher) this, this); serv.setReadTimeout(readTimeout); @@ -400,6 +411,7 @@ public class I2PTunnel implements Logging, EventDispatcher { /** * Same args as runServer * (we should stop duplicating all this code...) + * @throws IllegalArgumentException on config problem */ public void runIrcServer(String args[], Logging l) { if (args.length == 3) { @@ -412,7 +424,7 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("unknown host"); _log.error(getPrefix() + "Error resolving " + args[0], uhe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Error resolving " + args[0] + uhe.getMessage()); } try { @@ -421,17 +433,18 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; } + if (portNum <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[1]); privKeyFile = new File(args[2]); if (!privKeyFile.isAbsolute()) privKeyFile = new File(_context.getConfigDir(), args[2]); if (!privKeyFile.canRead()) { - l.log("private key file does not exist"); + l.log(getPrefix() + "Private key file does not exist or is not readable: " + args[2]); _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[2]); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Cannot open private key file " + args[2]); } I2PTunnelServer serv = new I2PTunnelIRCServer(serverHost, portNum, privKeyFile, args[2], l, (EventDispatcher) this, this); serv.setReadTimeout(readTimeout); @@ -457,6 +470,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {hostname, portNumber, spoofedHost, privKeyFilename} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runHttpServer(String args[], Logging l) { if (args.length == 4) { @@ -469,7 +483,7 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("unknown host"); _log.error(getPrefix() + "Error resolving " + args[0], uhe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Error resolving " + args[0] + uhe.getMessage()); } try { @@ -478,8 +492,9 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; } + if (portNum <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[1]); String spoofedHost = args[2]; @@ -487,10 +502,10 @@ public class I2PTunnel implements Logging, EventDispatcher { if (!privKeyFile.isAbsolute()) privKeyFile = new File(_context.getConfigDir(), args[3]); if (!privKeyFile.canRead()) { - l.log("private key file does not exist"); + l.log(getPrefix() + "Private key file does not exist or is not readable: " + args[3]); _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[3]); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Cannot open private key file " + args[3]); } I2PTunnelHTTPServer serv = new I2PTunnelHTTPServer(serverHost, portNum, privKeyFile, args[3], spoofedHost, l, (EventDispatcher) this, this); serv.setReadTimeout(readTimeout); @@ -519,6 +534,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {hostname, portNumber, proxyPortNumber, spoofedHost, privKeyFilename} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runHttpBidirServer(String args[], Logging l) { if (args.length == 5) { @@ -532,7 +548,7 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("unknown host"); _log.error(getPrefix() + "Error resolving " + args[0], uhe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Error resolving " + args[0] + uhe.getMessage()); } try { @@ -541,7 +557,6 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; } try { @@ -550,8 +565,11 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[2], nfe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; } + if (portNum <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[1]); + if (port2Num <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[2]); String spoofedHost = args[3]; @@ -559,10 +577,10 @@ public class I2PTunnel implements Logging, EventDispatcher { if (!privKeyFile.isAbsolute()) privKeyFile = new File(_context.getConfigDir(), args[4]); if (!privKeyFile.canRead()) { - l.log("private key file does not exist"); + l.log(getPrefix() + "Private key file does not exist or is not readable: " + args[4]); _log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[4]); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Cannot open private key file " + args[4]); } I2PTunnelHTTPBidirServer serv = new I2PTunnelHTTPBidirServer(serverHost, portNum, port2Num, privKeyFile, args[3], spoofedHost, l, (EventDispatcher) this, this); @@ -585,12 +603,16 @@ public class I2PTunnel implements Logging, EventDispatcher { * Run the server pointing at the host and port specified using the private i2p * destination loaded from the given base64 stream.

* + * Deprecated? Why run a server with a private destination? + * Not available from the war GUI + * * Sets the event "serverTaskId" = Integer(taskId) after the tunnel has been started (or -1 on error) * Also sets the event "openServerResult" = "ok" or "error" (displaying "Ready!" on the logger after * 'ok'). So, success = serverTaskId != -1 and openServerResult = ok. * * @param args {hostname, portNumber, privKeyBase64} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runTextServer(String args[], Logging l) { if (args.length == 3) { @@ -602,7 +624,7 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("unknown host"); _log.error(getPrefix() + "Error resolving " + args[0], uhe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; + throw new IllegalArgumentException(getPrefix() + "Error resolving " + args[0] + uhe.getMessage()); } try { @@ -611,8 +633,9 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe); notifyEvent("serverTaskId", Integer.valueOf(-1)); - return; } + if (portNum <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[1]); I2PTunnelServer serv = new I2PTunnelServer(serverHost, portNum, args[2], l, (EventDispatcher) this, this); serv.setReadTimeout(readTimeout); @@ -638,6 +661,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {portNumber, destinationBase64 or "file:filename"[, sharedClient [, privKeyFile]]} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runClient(String args[], Logging l) { boolean isShared = true; @@ -651,8 +675,10 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); notifyEvent("clientTaskId", Integer.valueOf(-1)); - return; } + if (portNum <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); + I2PTunnelTask task; ownDest = !isShared; try { @@ -666,6 +692,11 @@ public class I2PTunnel implements Logging, EventDispatcher { _log.error(getPrefix() + "Invalid I2PTunnel config to create a client [" + host + ":"+ port + "]", iae); l.log("Invalid I2PTunnel configuration [" + host + ":" + port + "]"); notifyEvent("clientTaskId", Integer.valueOf(-1)); + // Since nothing listens to TaskID events, use this to propagate the error to TunnelController + // Otherwise, the tunnel stays up even though the port is down + // This doesn't work for CLI though... and the tunnel doesn't close itself after error, + // so this probably leaves the tunnel open if called from the CLI + throw iae; } } else { l.log("client [,]|file:[ ] []"); @@ -687,6 +718,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {portNumber[, sharedClient][, proxy to be used for the WWW]} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runHttpClient(String args[], Logging l) { if (args.length >= 1 && args.length <= 3) { @@ -697,8 +729,9 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); notifyEvent("httpclientTaskId", Integer.valueOf(-1)); - return; } + if (clientPort <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); String proxy = ""; boolean isShared = true; @@ -733,6 +766,11 @@ public class I2PTunnel implements Logging, EventDispatcher { _log.error(getPrefix() + "Invalid I2PTunnel config to create an httpclient [" + host + ":"+ clientPort + "]", iae); l.log("Invalid I2PTunnel configuration [" + host + ":" + clientPort + "]"); notifyEvent("httpclientTaskId", Integer.valueOf(-1)); + // Since nothing listens to TaskID events, use this to propagate the error to TunnelController + // Otherwise, the tunnel stays up even though the port is down + // This doesn't work for CLI though... and the tunnel doesn't close itself after error, + // so this probably leaves the tunnel open if called from the CLI + throw iae; } } else { l.log("httpclient [] []"); @@ -749,6 +787,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {portNumber[, sharedClient][, proxy to be used for the WWW]} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runConnectClient(String args[], Logging l) { if (args.length >= 1 && args.length <= 3) { @@ -757,8 +796,9 @@ public class I2PTunnel implements Logging, EventDispatcher { _port = Integer.parseInt(args[0]); } catch (NumberFormatException nfe) { _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); - return; } + if (_port <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); String proxy = ""; boolean isShared = true; @@ -789,7 +829,12 @@ public class I2PTunnel implements Logging, EventDispatcher { task = new I2PTunnelConnectClient(_port, l, ownDest, proxy, (EventDispatcher) this, this); addtask(task); } catch (IllegalArgumentException iae) { - _log.error(getPrefix() + "Invalid I2PTunnel config to create an httpclient [" + host + ":"+ _port + "]", iae); + _log.error(getPrefix() + "Invalid I2PTunnel config to create a connect client [" + host + ":"+ _port + "]", iae); + // Since nothing listens to TaskID events, use this to propagate the error to TunnelController + // Otherwise, the tunnel stays up even though the port is down + // This doesn't work for CLI though... and the tunnel doesn't close itself after error, + // so this probably leaves the tunnel open if called from the CLI + throw iae; } } else { l.log("connectclient [] []"); @@ -809,6 +854,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {portNumber,destinationBase64 or "file:filename" [, sharedClient [, privKeyFile]]} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runIrcClient(String args[], Logging l) { if (args.length >= 2) { @@ -819,8 +865,9 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); notifyEvent("ircclientTaskId", Integer.valueOf(-1)); - return; } + if (_port <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); boolean isShared = true; if (args.length > 2) { @@ -848,6 +895,11 @@ public class I2PTunnel implements Logging, EventDispatcher { _log.error(getPrefix() + "Invalid I2PTunnel config to create an ircclient [" + host + ":"+ _port + "]", iae); l.log("Invalid I2PTunnel configuration [" + host + ":" + _port + "]"); notifyEvent("ircclientTaskId", Integer.valueOf(-1)); + // Since nothing listens to TaskID events, use this to propagate the error to TunnelController + // Otherwise, the tunnel stays up even though the port is down + // This doesn't work for CLI though... and the tunnel doesn't close itself after error, + // so this probably leaves the tunnel open if called from the CLI + throw iae; } } else { l.log("ircclient [ []]"); @@ -867,6 +919,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {portNumber [, sharedClient]} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runSOCKSTunnel(String args[], Logging l) { if (args.length >= 1 && args.length <= 2) { @@ -877,8 +930,9 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); notifyEvent("sockstunnelTaskId", Integer.valueOf(-1)); - return; } + if (_port <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); boolean isShared = false; if (args.length > 1) @@ -900,6 +954,7 @@ public class I2PTunnel implements Logging, EventDispatcher { /** * Run an SOCKS IRC tunnel on the given port number * @param args {portNumber [, sharedClient]} or (portNumber, ignored (false), privKeyFile) + * @throws IllegalArgumentException on config problem * @since 0.7.12 */ public void runSOCKSIRCTunnel(String args[], Logging l) { @@ -911,8 +966,9 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); notifyEvent("sockstunnelTaskId", Integer.valueOf(-1)); - return; } + if (_port <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); boolean isShared = false; if (args.length == 2) @@ -938,6 +994,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {targethost, targetport, destinationString} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runStreamrClient(String args[], Logging l) { if (args.length == 3) { @@ -958,8 +1015,9 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); notifyEvent("streamrtunnelTaskId", Integer.valueOf(-1)); - return; } + if (_port <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); StreamrConsumer task = new StreamrConsumer(_host, _port, args[2], l, (EventDispatcher) this, this); task.startRunning(); @@ -977,6 +1035,7 @@ public class I2PTunnel implements Logging, EventDispatcher { * * @param args {port, privkeyfile} * @param l logger to receive events and output + * @throws IllegalArgumentException on config problem */ public void runStreamrServer(String args[], Logging l) { if (args.length == 2) { @@ -987,8 +1046,9 @@ public class I2PTunnel implements Logging, EventDispatcher { l.log("invalid port"); _log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe); notifyEvent("streamrtunnelTaskId", Integer.valueOf(-1)); - return; } + if (_port <= 0) + throw new IllegalArgumentException(getPrefix() + "Bad port " + args[0]); File privKeyFile = new File(args[1]); if (!privKeyFile.isAbsolute()) @@ -1403,6 +1463,7 @@ public class I2PTunnel implements Logging, EventDispatcher { /** * Create a new destination, storing the destination and its private keys where * instructed + * Deprecated - only used by CLI * * @param writeTo location to store the private keys * @param pubDest location to store the destination @@ -1427,6 +1488,7 @@ public class I2PTunnel implements Logging, EventDispatcher { /** * Read in the given destination, display it, and write it to the given location + * Deprecated - only used by CLI * * @param readFrom stream to read the destination from * @param pubDest stream to write the destination to @@ -1448,6 +1510,7 @@ public class I2PTunnel implements Logging, EventDispatcher { /** * Write out the destination to the stream + * Deprecated - only used by CLI * * @param d Destination to write * @param o stream to write the destination to @@ -1465,6 +1528,9 @@ public class I2PTunnel implements Logging, EventDispatcher { * also supported, where filename is a file that either contains a * binary Destination structure or the Base64 encoding of that * structure. + * + * Since file: isn't really used, this method is deprecated, + * just call context.namingService.lookup() directly. */ public static Destination destFromName(String name) throws DataFormatException { @@ -1529,7 +1595,7 @@ public class I2PTunnel implements Logging, EventDispatcher { } } - private String getPrefix() { return '[' + _tunnelId + "]: "; } + private String getPrefix() { return "[" + _tunnelId + "]: "; } public I2PAppContext getContext() { return _context; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java index 89339bf04..d5b88d4d3 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClient.java @@ -20,7 +20,7 @@ public class I2PTunnelClient extends I2PTunnelClientBase { private static final Log _log = new Log(I2PTunnelClient.class); /** list of Destination objects that we point at */ - protected List dests; + protected List dests; private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1 protected long readTimeout = DEFAULT_READ_TIMEOUT; @@ -55,9 +55,20 @@ public class I2PTunnelClient extends I2PTunnelClientBase { } if (dests.isEmpty()) { - l.log("No target destinations found"); + l.log("No valid target destinations found"); notifyEvent("openClientResult", "error"); - return; + // Nothing is listening for the above event, so it's useless + // Maybe figure out where to put a waitEventValue("openClientResult") ?? + // In the meantime, let's do this the easy way + // Note that b32 dests will often not be resolvable at instantiation time; + // a delayed resolution system would be even better. + + // Don't close() here, because it does a removeSession() and then + // TunnelController can't acquire() it to release() it. + //close(true); + // Unfortunately, super() built the whole tunnel before we get here. + throw new IllegalArgumentException("No valid target destinations found"); + //return; } setName(getLocalPort() + " -> " + destinations); @@ -98,8 +109,8 @@ public class I2PTunnelClient extends I2PTunnelClientBase { return null; } if (size == 1) // skip the rand in the most common case - return (Destination)dests.get(0); + return dests.get(0); int index = I2PAppContext.getGlobalContext().random().nextInt(size); - return (Destination)dests.get(index); + return dests.get(index); } } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java index 398fd7349..71a1561ea 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelClientBase.java @@ -583,6 +583,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna } public boolean close(boolean forced) { + if (_log.shouldLog(Log.INFO)) + _log.info("close() called: forced = " + forced + " open = " + open + " sockMgr = " + sockMgr); if (!open) return true; // FIXME: here we might have to wait quite a long time if // there is a connection attempt atm. But without waiting we diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java index 7a80c181f..fe92e94b6 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelConnectClient.java @@ -26,6 +26,7 @@ import net.i2p.util.Log; /** * Supports the following: + *

  *   (where protocol is generally HTTP/1.1 but is ignored)
  *   (where host is one of:
  *      example.i2p
@@ -39,16 +40,19 @@ import net.i2p.util.Log;
  *   CONNECT host protocol
  *   CONNECT host:port
  *   CONNECT host:port protocol (this is the standard)
+ *
* * Additional lines after the CONNECT line but before the blank line are ignored and stripped. * The CONNECT line is removed for .i2p accesses * but passed along for outproxy accesses. * * Ref: + *
  *  INTERNET-DRAFT                                              Ari Luotonen
  *  Expires: September 26, 1997          Netscape Communications Corporation
  *                       March 26, 1997
  *                     Tunneling SSL Through a WWW Proxy
+ *
* * @author zzz a stripped-down I2PTunnelHTTPClient */ diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 62450a755..b6c72821e 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -33,7 +33,6 @@ import net.i2p.data.Destination; import net.i2p.util.EventDispatcher; import net.i2p.util.FileUtil; import net.i2p.util.Log; - import net.i2p.util.Translate; /** @@ -646,11 +645,11 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable if (!Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT)).booleanValue()) { // let's not advertise to external sites that we are from I2P if (usingWWWProxy) - newRequest.append("User-Agent: Wget/1.11.4\r\n"); + newRequest.append("User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.6) Gecko/20100625 Firefox/3.6.6\r\n"); else newRequest.append("User-Agent: MYOB/6.66 (AN/ON)\r\n"); } - newRequest.append("Connection: close\r\n\r\n"); + newRequest.append("Connection: close\r\n\r\n"); break; } else { newRequest.append(line).append("\r\n"); // HTTP spec @@ -772,11 +771,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable _s = s; } String readLine(String method) throws IOException { - if (method == null || "POST".equals(method)) + // Use unbuffered until we can find a BufferedReader that limits line length + //if (method == null || "POST".equals(method)) return DataHelper.readLine(_s); - if (_br == null) - _br = new BufferedReader(new InputStreamReader(_s, "ISO-8859-1")); - return _br.readLine(); + //if (_br == null) + // _br = new BufferedReader(new InputStreamReader(_s, "ISO-8859-1")); + //return _br.readLine(); } } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java index 418dd1de9..ca568ab92 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java @@ -151,7 +151,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { _log.warn("Took a while to handle the request [" + timeToHandle + ", socket create: " + (afterSocket-afterAccept) + "]"); } - private class CompressedRequestor implements Runnable { + private static class CompressedRequestor implements Runnable { private Socket _webserver; private I2PSocket _browser; private String _headers; @@ -214,7 +214,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { } } } - private class Sender implements Runnable { + + private static class Sender implements Runnable { private OutputStream _out; private InputStream _in; private String _name; @@ -248,7 +249,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { } } } - private class CompressedResponseOutputStream extends HTTPResponseOutputStream { + + private static class CompressedResponseOutputStream extends HTTPResponseOutputStream { private InternalGZIPOutputStream _gzipOut; public CompressedResponseOutputStream(OutputStream o) { super(o); @@ -287,7 +289,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { return 0; } } - private class InternalGZIPOutputStream extends GZIPOutputStream { + + /** just a wrapper to provide stats for debugging */ + private static class InternalGZIPOutputStream extends GZIPOutputStream { public InternalGZIPOutputStream(OutputStream target) throws IOException { super(target); } @@ -309,7 +313,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { } } - private String formatHeaders(Properties headers, StringBuilder command) { + private static String formatHeaders(Properties headers, StringBuilder command) { StringBuilder buf = new StringBuilder(command.length() + headers.size() * 64); buf.append(command.toString().trim()).append("\r\n"); for (Iterator iter = headers.keySet().iterator(); iter.hasNext(); ) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java index a7fbcf37b..4d8b85a81 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCClient.java @@ -17,6 +17,9 @@ import net.i2p.util.EventDispatcher; import net.i2p.util.I2PAppThread; import net.i2p.util.Log; +/** + * Todo: Can we extend I2PTunnelClient instead and remove some duplicated code? + */ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable { private static final Log _log = new Log(I2PTunnelIRCClient.class); @@ -25,7 +28,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable private static volatile long __clientId = 0; /** list of Destination objects that we point at */ - protected List dests; + protected List dests; private static final long DEFAULT_READ_TIMEOUT = 5*60*1000; // -1 protected long readTimeout = DEFAULT_READ_TIMEOUT; @@ -47,7 +50,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable "IRCHandler " + (++__clientId), tunnel, pkf); StringTokenizer tok = new StringTokenizer(destinations, ", "); - dests = new ArrayList(1); + dests = new ArrayList(2); while (tok.hasMoreTokens()) { String destination = tok.nextToken(); try { @@ -64,7 +67,18 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable if (dests.isEmpty()) { l.log("No target destinations found"); notifyEvent("openClientResult", "error"); - return; + // Nothing is listening for the above event, so it's useless + // Maybe figure out where to put a waitEventValue("openClientResult") ?? + // In the meantime, let's do this the easy way + // Note that b32 dests will often not be resolvable at instantiation time; + // a delayed resolution system would be even better. + + // Don't close() here, because it does a removeSession() and then + // TunnelController can't acquire() it to release() it. + //close(true); + // Unfortunately, super() built the whole tunnel before we get here. + throw new IllegalArgumentException("No valid target destinations found"); + //return; } setName(getLocalPort() + " -> IRCClient"); @@ -109,9 +123,9 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable return null; } if (size == 1) // skip the rand in the most common case - return (Destination)dests.get(0); + return dests.get(0); int index = I2PAppContext.getGlobalContext().random().nextInt(size); - return (Destination)dests.get(index); + return dests.get(index); } /************************************************************************* @@ -130,6 +144,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable } public void run() { + // Todo: Don't use BufferedReader - IRC spec limits line length to 512 but... BufferedReader in; OutputStream output; try { @@ -204,6 +219,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable } public void run() { + // Todo: Don't use BufferedReader - IRC spec limits line length to 512 but... BufferedReader in; OutputStream output; try { @@ -371,7 +387,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable // "QUIT", // replace with a filtered QUIT to hide client quit messages "SILENCE", "MAP", // seems safe enough, the ircd should protect themselves though - "PART", + // "PART", // replace with filtered PART to hide client part messages "OPER", // "PONG", // replaced with a filtered PING/PONG since some clients send the server IP (thanks aardvax!) // "PING", @@ -475,6 +491,11 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable return ret; } + if ("PART".equals(command)) { + // hide client message + return "PART " + field[1] + " :leaving"; + } + if ("QUIT".equals(command)) { return "QUIT :leaving"; } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java index 3e8d927f2..1d05103e7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelIRCServer.java @@ -170,7 +170,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable { } /** keep reading until we see USER or SERVER */ - private String filterRegistration(InputStream in, String newHostname) throws IOException { + private static String filterRegistration(InputStream in, String newHostname) throws IOException { StringBuilder buf = new StringBuilder(128); int lineCount = 0; diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java index 6be20ba8b..c2a014020 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelRunner.java @@ -127,6 +127,8 @@ public class I2PTunnelRunner extends I2PAppThread implements I2PSocket.SocketErr // this does not increment totalSent i2pout.write(initialI2PData); // do NOT flush here, it will block and then onTimeout.run() won't happen on fail. + // But if we don't flush, then we have to wait for the connectDelay timer to fire + // in i2p socket? To be researched and/or fixed. //i2pout.flush(); } } diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java index 5b7fd3529..02777dafb 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelController.java @@ -30,8 +30,8 @@ public class TunnelController implements Logging { private Log _log; private Properties _config; private I2PTunnel _tunnel; - private List _messages; - private List _sessions; + private List _messages; + private List _sessions; private boolean _running; private boolean _starting; @@ -47,6 +47,7 @@ public class TunnelController implements Logging { public TunnelController(Properties config, String prefix) { this(config, prefix, true); } + /** * * @param createKey for servers, whether we want to create a brand new destination @@ -59,17 +60,21 @@ public class TunnelController implements Logging { setConfig(config, prefix); _messages = new ArrayList(4); _running = false; + boolean keyOK = true; if (createKey && (getType().endsWith("server") || getPersistentClientKey())) - createPrivateKey(); - _starting = getStartOnLoad(); + keyOK = createPrivateKey(); + _starting = keyOK && getStartOnLoad(); } - private void createPrivateKey() { + /** + * @return success + */ + private boolean createPrivateKey() { I2PClient client = I2PClientFactory.createClient(); String filename = getPrivKeyFile(); if ( (filename == null) || (filename.trim().length() <= 0) ) { log("No filename specified for the private key"); - return; + return false; } File keyFile = new File(getPrivKeyFile()); @@ -77,7 +82,7 @@ public class TunnelController implements Logging { keyFile = new File(I2PAppContext.getGlobalContext().getConfigDir(), getPrivKeyFile()); if (keyFile.exists()) { //log("Not overwriting existing private keys in " + keyFile.getAbsolutePath()); - return; + return true; } else { File parent = keyFile.getParentFile(); if ( (parent != null) && (!parent.exists()) ) @@ -95,13 +100,16 @@ public class TunnelController implements Logging { if (_log.shouldLog(Log.ERROR)) _log.error("Error creating new destination", ie); log("Error creating new destination: " + ie.getMessage()); + return false; } catch (IOException ioe) { if (_log.shouldLog(Log.ERROR)) _log.error("Error creating writing the destination to " + keyFile.getAbsolutePath(), ioe); log("Error writing the keys to " + keyFile.getAbsolutePath()); + return false; } finally { if (fos != null) try { fos.close(); } catch (IOException ioe) {} } + return true; } public void startTunnelBackground() { @@ -121,9 +129,16 @@ public class TunnelController implements Logging { } catch (Exception e) { _log.error("Error starting up the tunnel", e); log("Error starting up the tunnel - " + e.getMessage()); + // if we don't acquire() then the release() in stopTunnel() won't work + acquire(); + stopTunnel(); } _starting = false; } + + /** + * @throws IllegalArgumentException via methods in I2PTunnel + */ private void doStartTunnel() { if (_running) { if (_log.shouldLog(Log.INFO)) @@ -257,15 +272,18 @@ public class TunnelController implements Logging { * closed by some other tunnels */ private void acquire() { - List sessions = _tunnel.getSessions(); - if (sessions != null) { + List sessions = _tunnel.getSessions(); + if (!sessions.isEmpty()) { for (int i = 0; i < sessions.size(); i++) { - I2PSession session = (I2PSession)sessions.get(i); + I2PSession session = sessions.get(i); + if (_log.shouldLog(Log.INFO)) + _log.info("Acquiring session " + session); TunnelControllerGroup.getInstance().acquire(this, session); } _sessions = sessions; } else { - _log.error("No sessions to acquire?"); + if (_log.shouldLog(Log.WARN)) + _log.warn("No sessions to acquire? for " + getName()); } } @@ -274,13 +292,16 @@ public class TunnelController implements Logging { * no other tunnels are using them, close them. */ private void release() { - if (_sessions != null) { + if (_sessions != null && !_sessions.isEmpty()) { for (int i = 0; i < _sessions.size(); i++) { - I2PSession s = (I2PSession)_sessions.get(i); + I2PSession s = _sessions.get(i); + if (_log.shouldLog(Log.INFO)) + _log.info("Releasing session " + s); TunnelControllerGroup.getInstance().release(this, s); } } else { - _log.error("No sessions to release?"); + if (_log.shouldLog(Log.WARN)) + _log.warn("No sessions to release? for " + getName()); } } @@ -371,7 +392,7 @@ public class TunnelController implements Logging { _tunnel.port = "7654"; } } - + public void stopTunnel() { _tunnel.runClose(new String[] { "forced", "all" }, this); release(); @@ -440,9 +461,9 @@ public class TunnelController implements Logging { public boolean getPersistentClientKey() { return Boolean.valueOf(_config.getProperty("option.persistentClientKey")).booleanValue(); } public String getMyDestination() { if (_tunnel != null) { - List sessions = _tunnel.getSessions(); + List sessions = _tunnel.getSessions(); for (int i = 0; i < sessions.size(); i++) { - I2PSession session = (I2PSession)sessions.get(i); + I2PSession session = sessions.get(i); Destination dest = session.getMyDestination(); if (dest != null) return dest.toBase64(); @@ -453,9 +474,9 @@ public class TunnelController implements Logging { public String getMyDestHashBase32() { if (_tunnel != null) { - List sessions = _tunnel.getSessions(); + List sessions = _tunnel.getSessions(); for (int i = 0; i < sessions.size(); i++) { - I2PSession session = (I2PSession)sessions.get(i); + I2PSession session = sessions.get(i); Destination dest = session.getMyDestination(); if (dest != null) return Base32.encode(dest.calculateHash().getData()); @@ -557,9 +578,9 @@ public class TunnelController implements Logging { if ( (opts != null) && (opts.length() > 0) ) buf.append("Network options: ").append(opts).append("
\n"); if (_running) { - List sessions = _tunnel.getSessions(); + List sessions = _tunnel.getSessions(); for (int i = 0; i < sessions.size(); i++) { - I2PSession session = (I2PSession)sessions.get(i); + I2PSession session = sessions.get(i); Destination dest = session.getMyDestination(); if (dest != null) { buf.append("Destination hash: ").append(dest.calculateHash().toBase64()).append("
\n"); @@ -598,7 +619,7 @@ public class TunnelController implements Logging { * * @return list of messages pulled off (each is a String, earliest first) */ - public List clearMessages() { + public List clearMessages() { List rv = null; synchronized (this) { rv = new ArrayList(_messages); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java index 7b0c67f70..618b035f7 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/TunnelControllerGroup.java @@ -26,13 +26,14 @@ import net.i2p.util.SecureFileOutputStream; * Coordinate a set of tunnels within the JVM, loading and storing their config * to disk, and building new ones as requested. * + * Warning - this is a singleton. Todo: fix */ public class TunnelControllerGroup { - private Log _log; + private final Log _log; private static TunnelControllerGroup _instance; static final String DEFAULT_CONFIG_FILE = "i2ptunnel.config"; - private List _controllers; + private final List _controllers; private String _configFile = DEFAULT_CONFIG_FILE; /** @@ -41,7 +42,7 @@ public class TunnelControllerGroup { * no more tunnels are using it) * */ - private final Map _sessions; + private final Map> _sessions; public static TunnelControllerGroup getInstance() { synchronized (TunnelControllerGroup.class) { @@ -105,7 +106,7 @@ public class TunnelControllerGroup { private class StartControllers implements Runnable { public void run() { for (int i = 0; i < _controllers.size(); i++) { - TunnelController controller = (TunnelController)_controllers.get(i); + TunnelController controller = _controllers.get(i); if (controller.getStartOnLoad()) controller.startTunnel(); } @@ -142,10 +143,10 @@ public class TunnelControllerGroup { * * @return list of messages from the controller as it is stopped */ - public List removeController(TunnelController controller) { + public List removeController(TunnelController controller) { if (controller == null) return new ArrayList(); controller.stopTunnel(); - List msgs = controller.clearMessages(); + List msgs = controller.clearMessages(); _controllers.remove(controller); msgs.add("Tunnel " + controller.getName() + " removed"); return msgs; @@ -156,10 +157,10 @@ public class TunnelControllerGroup { * * @return list of messages the tunnels generate when stopped */ - public List stopAllControllers() { - List msgs = new ArrayList(); + public List stopAllControllers() { + List msgs = new ArrayList(); for (int i = 0; i < _controllers.size(); i++) { - TunnelController controller = (TunnelController)_controllers.get(i); + TunnelController controller = _controllers.get(i); controller.stopTunnel(); msgs.addAll(controller.clearMessages()); } @@ -173,10 +174,10 @@ public class TunnelControllerGroup { * * @return list of messages the tunnels generate when started */ - public List startAllControllers() { - List msgs = new ArrayList(); + public List startAllControllers() { + List msgs = new ArrayList(); for (int i = 0; i < _controllers.size(); i++) { - TunnelController controller = (TunnelController)_controllers.get(i); + TunnelController controller = _controllers.get(i); controller.startTunnelBackground(); msgs.addAll(controller.clearMessages()); } @@ -191,10 +192,10 @@ public class TunnelControllerGroup { * * @return list of messages the tunnels generate when restarted */ - public List restartAllControllers() { - List msgs = new ArrayList(); + public List restartAllControllers() { + List msgs = new ArrayList(); for (int i = 0; i < _controllers.size(); i++) { - TunnelController controller = (TunnelController)_controllers.get(i); + TunnelController controller = _controllers.get(i); controller.restartTunnel(); msgs.addAll(controller.clearMessages()); } @@ -208,10 +209,10 @@ public class TunnelControllerGroup { * * @return list of messages the tunnels have generated */ - public List clearAllMessages() { - List msgs = new ArrayList(); + public List clearAllMessages() { + List msgs = new ArrayList(); for (int i = 0; i < _controllers.size(); i++) { - TunnelController controller = (TunnelController)_controllers.get(i); + TunnelController controller = _controllers.get(i); msgs.addAll(controller.clearMessages()); } return msgs; @@ -241,7 +242,7 @@ public class TunnelControllerGroup { TreeMap map = new TreeMap(); for (int i = 0; i < _controllers.size(); i++) { - TunnelController controller = (TunnelController)_controllers.get(i); + TunnelController controller = _controllers.get(i); Properties cur = controller.getConfig("tunnel." + i + "."); map.putAll(cur); } @@ -297,7 +298,7 @@ public class TunnelControllerGroup { * * @return list of TunnelController objects */ - public List getControllers() { return _controllers; } + public List getControllers() { return _controllers; } /** @@ -307,7 +308,7 @@ public class TunnelControllerGroup { */ void acquire(TunnelController controller, I2PSession session) { synchronized (_sessions) { - Set owners = (Set)_sessions.get(session); + Set owners = _sessions.get(session); if (owners == null) { owners = new HashSet(1); _sessions.put(session, owners); @@ -327,7 +328,7 @@ public class TunnelControllerGroup { void release(TunnelController controller, I2PSession session) { boolean shouldClose = false; synchronized (_sessions) { - Set owners = (Set)_sessions.get(session); + Set owners = _sessions.get(session); if (owners != null) { owners.remove(controller); if (owners.isEmpty()) { diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java index e6db8ae3d..f6c76d7f6 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/EditBean.java @@ -13,11 +13,20 @@ import java.util.List; import java.util.Properties; import java.util.StringTokenizer; +import net.i2p.data.Base64; +import net.i2p.data.Destination; +import net.i2p.data.PrivateKeyFile; +import net.i2p.data.Signature; +import net.i2p.data.SigningPrivateKey; import net.i2p.i2ptunnel.TunnelController; import net.i2p.i2ptunnel.TunnelControllerGroup; /** * Ugly little accessor for the edit page + * + * Warning - This class is not part of the i2ptunnel API, and at some point + * it will be moved from the jar to the war. + * Usage by classes outside of i2ptunnel.war is deprecated. */ public class EditBean extends IndexBean { public EditBean() { super(); } @@ -64,6 +73,31 @@ public class EditBean extends IndexBean { return "i2ptunnel" + tunnel + "-privKeys.dat"; } + public String getNameSignature(int tunnel) { + String spoof = getSpoofedHost(tunnel); + if (spoof.length() <= 0) + return ""; + TunnelController tun = getController(tunnel); + if (tun == null) + return ""; + String keyFile = tun.getPrivKeyFile(); + if (keyFile != null && keyFile.trim().length() > 0) { + PrivateKeyFile pkf = new PrivateKeyFile(keyFile); + try { + Destination d = pkf.getDestination(); + if (d == null) + return ""; + SigningPrivateKey privKey = pkf.getSigningPrivKey(); + if (privKey == null) + return ""; + //System.err.println("Signing " + spoof + " with " + Base64.encode(privKey.getData())); + Signature sig = _context.dsa().sign(spoof.getBytes("UTF-8"), privKey); + return Base64.encode(sig.getData()); + } catch (Exception e) {} + } + return ""; + } + public boolean startAutomatically(int tunnel) { TunnelController tun = getController(tunnel); if (tun != null) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java index b09452734..d91a7900d 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/web/IndexBean.java @@ -9,6 +9,7 @@ package net.i2p.i2ptunnel.web; */ import java.util.concurrent.ConcurrentHashMap; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -31,6 +32,9 @@ import net.i2p.util.Log; /** * Simple accessor for exposing tunnel info, but also an ugly form handler * + * Warning - This class is not part of the i2ptunnel API, and at some point + * it will be moved from the jar to the war. + * Usage by classes outside of i2ptunnel.war is deprecated. */ public class IndexBean { protected I2PAppContext _context; @@ -38,10 +42,10 @@ public class IndexBean { protected TunnelControllerGroup _group; private String _action; private int _tunnel; - private long _prevNonce; - private long _prevNonce2; - private long _curNonce; - private long _nextNonce; + //private long _prevNonce; + //private long _prevNonce2; + private String _curNonce; + //private long _nextNonce; private String _type; private String _name; @@ -82,10 +86,14 @@ public class IndexBean { /** deprecated unimplemented, now using routerconsole realm */ //public static final String PROP_TUNNEL_PASSPHRASE = "i2ptunnel.passphrase"; public static final String PROP_TUNNEL_PASSPHRASE = "consolePassword"; - static final String PROP_NONCE = IndexBean.class.getName() + ".nonce"; - static final String PROP_NONCE_OLD = PROP_NONCE + '2'; + //static final String PROP_NONCE = IndexBean.class.getName() + ".nonce"; + //static final String PROP_NONCE_OLD = PROP_NONCE + '2'; + /** 3 wasn't enough for some browsers. They are reloading the page for some reason - maybe HEAD? @since 0.8.1 */ + private static final int MAX_NONCES = 5; + /** store nonces in a static FIFO instead of in System Properties @since 0.8.1 */ + private static final List _nonces = new ArrayList(MAX_NONCES + 1); + static final String CLIENT_NICKNAME = "shared clients"; - public static final String PROP_THEME_NAME = "routerconsole.theme"; public static final String DEFAULT_THEME = "light"; public static final String PROP_CSS_DISABLED = "routerconsole.css.disabled"; @@ -95,34 +103,39 @@ public class IndexBean { _context = I2PAppContext.getGlobalContext(); _log = _context.logManager().getLog(IndexBean.class); _group = TunnelControllerGroup.getInstance(); - _action = null; _tunnel = -1; - _curNonce = -1; - _prevNonce = -1; - _prevNonce2 = -1; - try { - String nonce2 = System.getProperty(PROP_NONCE_OLD); - if (nonce2 != null) - _prevNonce2 = Long.parseLong(nonce2); - String nonce = System.getProperty(PROP_NONCE); - if (nonce != null) { - _prevNonce = Long.parseLong(nonce); - System.setProperty(PROP_NONCE_OLD, nonce); - } - } catch (NumberFormatException nfe) {} - _nextNonce = _context.random().nextLong(); - System.setProperty(PROP_NONCE, Long.toString(_nextNonce)); + _curNonce = "-1"; + addNonce(); _booleanOptions = new ConcurrentHashSet(4); _otherOptions = new ConcurrentHashMap(4); } - public long getNextNonce() { return _nextNonce; } + public static String getNextNonce() { + synchronized (_nonces) { + return _nonces.get(0); + } + } + public void setNonce(String nonce) { if ( (nonce == null) || (nonce.trim().length() <= 0) ) return; - try { - _curNonce = Long.parseLong(nonce); - } catch (NumberFormatException nfe) { - _curNonce = -1; + _curNonce = nonce; + } + + /** add a random nonce to the head of the queue @since 0.8.1 */ + private void addNonce() { + String nextNonce = Long.toString(_context.random().nextLong()); + synchronized (_nonces) { + _nonces.add(0, nextNonce); + int sz = _nonces.size(); + if (sz > MAX_NONCES) + _nonces.remove(sz - 1); + } + } + + /** do we know this nonce? @since 0.8.1 */ + private static boolean haveNonce(String nonce) { + synchronized (_nonces) { + return _nonces.contains(nonce); } } @@ -152,7 +165,7 @@ public class IndexBean { private String processAction() { if ( (_action == null) || (_action.trim().length() <= 0) || ("Cancel".equals(_action))) return ""; - if ( (_prevNonce != _curNonce) && (_prevNonce2 != _curNonce) && (!validPassphrase()) ) + if ( (!haveNonce(_curNonce)) && (!validPassphrase()) ) return "Invalid form submission, probably because you used the 'back' or 'reload' button on your browser. Please resubmit."; if ("Stop all".equals(_action)) return stopAll(); diff --git a/apps/i2ptunnel/jsp/editServer.jsp b/apps/i2ptunnel/jsp/editServer.jsp index 939ccf520..97a0a93c9 100644 --- a/apps/i2ptunnel/jsp/editServer.jsp +++ b/apps/i2ptunnel/jsp/editServer.jsp @@ -196,7 +196,16 @@ <%=intl._("Add to local addressbook")%> <% } %> - + + <% if (("httpserver".equals(tunnelType)) || ("httpbidirserver".equals(tunnelType))) { + %>
+ + +
+ <% } %> + diff --git a/apps/i2ptunnel/locale/messages_nl.po b/apps/i2ptunnel/locale/messages_nl.po new file mode 100644 index 000000000..39c31def2 --- /dev/null +++ b/apps/i2ptunnel/locale/messages_nl.po @@ -0,0 +1,689 @@ +# I2P +# Copyright (C) 2009 The I2P Project +# This file is distributed under the same license as the i2ptunnel package. +# To contribute translations, see http://www.i2p2.de/newdevelopers +# foo , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: I2P i2ptunnel\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-07-04 16:39+0000\n" +"PO-Revision-Date: 2010-06-15 14:09+0100\n" +"Last-Translator: duck \n" +"Language-Team: duck , monkeybrains \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Dutch\n" + +#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:492 +#, java-format +msgid "" +"To visit the destination in your host database, click here. To visit the conflicting addresshelper destination, click here." +msgstr "Om de destination in je host database te bezoeken, klik here. Om de conflicterende adreshelper destination te bezoeken, klik here." + +#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:909 +msgid "" +"Click a link below to look for an address helper by using a \"jump\" service:" +msgstr "Klik op een onderstaande link om te zoeken naar een adreshelper via een \"jump\" service:" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:372 +msgid "New Tunnel" +msgstr "Nieuwe Tunnel" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:392 +msgid "Standard client" +msgstr "Standaard client" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:393 +msgid "HTTP client" +msgstr "HTTP client" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:394 +msgid "IRC client" +msgstr "IRC client" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:395 +msgid "Standard server" +msgstr "Standaard server" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:396 +msgid "HTTP server" +msgstr "HTTP server" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:397 +msgid "SOCKS 4/4a/5 proxy" +msgstr "SOCKS 4/4a/5 proxy" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:398 +msgid "SOCKS IRC proxy" +msgstr "SOCKS IRC proxy" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:399 +msgid "CONNECT/SSL/HTTPS proxy" +msgstr "CONNECT/SSL/HTTPS proxy" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:400 +msgid "IRC server" +msgstr "IRC server" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:401 +msgid "Streamr client" +msgstr "Streamr client" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:402 +msgid "Streamr server" +msgstr "Streamr server" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:403 +msgid "HTTP bidir" +msgstr "HTTP bidir" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:73 +msgid "I2P Tunnel Manager - Edit Client Tunnel" +msgstr "I2P Tunnel Manager - Bewerk Client Tunnel" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:93 +msgid "Edit proxy settings" +msgstr "Bewerk proxy instellingen" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:101 +msgid "New proxy settings" +msgstr "Nieuwe proxy instellingen" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:112 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:112 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:107 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:121 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:242 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:257 +msgid "Name" +msgstr "Naam" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:116 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:116 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:246 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:270 +msgid "Type" +msgstr "Type" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:120 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:120 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:226 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:358 +msgid "Description" +msgstr "Omschrijving" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:126 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:136 +msgid "Target" +msgstr "Doel" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:130 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:132 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:167 +msgid "Access Point" +msgstr "Toegangspunt" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:137 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:179 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:207 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:157 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:172 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:228 +msgid "required" +msgstr "vereist" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:150 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:142 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:183 +msgid "Reachable by" +msgstr "Bereikbaar voor" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:162 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:195 +msgid "Locally (127.0.0.1)" +msgstr "Lokaal (127.0.0.1)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:166 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:199 +msgid "Everyone (0.0.0.0)" +msgstr "Iedereen (0.0.0.0)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:170 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:203 +msgid "LAN Hosts (Please specify your LAN address)" +msgstr "LAN Hosts (Specificeer je LAN adres)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:186 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:205 +msgid "Other" +msgstr "Anders" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:195 +msgid "Outproxies" +msgstr "Uitgaande proxies" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:202 +msgid "Tunnel Destination" +msgstr "Tunnel Destinations" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:214 +msgid "name or destination" +msgstr "naam of destination" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:220 +msgid "Shared Client" +msgstr "Gedeelde Client" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:224 +msgid "" +"(Share tunnels with other clients and irc/httpclients? Change requires " +"restart of client proxy)" +msgstr "(Deel tunnels met andere clients en irc/httpclients? Wijziging vereist herstart van de client proxy)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:228 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:124 +msgid "Auto Start" +msgstr "Auto Start" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:232 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:128 +msgid "(Check the Box for 'YES')" +msgstr "(Markeer de Box voor 'JA')" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:234 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:249 +msgid "Advanced networking options" +msgstr "Geavanceerde netwerk opties" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:236 +msgid "" +"(NOTE: when this client proxy is configured to share tunnels, then these " +"options are for all the shared proxy clients!)" +msgstr "(OPMERKING: wanneer deze client proxy is geconfigureerd om tunnels te delen, dan zijn deze opties van toepassing voor alle gedeelde proxy clients!)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:238 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:251 +msgid "Tunnel Options" +msgstr "Tunnel Opties" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:240 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:253 +msgid "Length" +msgstr "Lengte" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:247 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:260 +msgid "0 hop tunnel (low anonymity, low latency)" +msgstr "0 hop tunnel (lage anonimiteit, weinig vertraging)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:251 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:264 +msgid "1 hop tunnel (medium anonymity, medium latency)" +msgstr "1 hop tunnel (gemiddelde anonimiteit, gemiddelde vertraging)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:255 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:268 +msgid "2 hop tunnel (high anonymity, high latency)" +msgstr "2 hop tunnel (hoge anonimiteit, hoge vertraging)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:259 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:272 +msgid "3 hop tunnel (very high anonymity, poor performance)" +msgstr "3 hop tunnel (zeer hoge anonimiteit, slechte prestatie)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:268 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:281 +msgid "hop tunnel (very poor performance)" +msgstr "hop tunnel (zeer slechte prestatie)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:273 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:286 +msgid "Variance" +msgstr "Variantie" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:280 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:293 +msgid "0 hop variance (no randomisation, consistant performance)" +msgstr "0 hop variantie (geen randomisatie, consistente prestatie)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:284 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:297 +msgid "" +"+ 0-1 hop variance (medium additive randomisation, subtractive performance)" +msgstr "+ 0-1 hop variantie (gemiddeld toegevoegde randomisatie, minder prestatie)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:288 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:301 +msgid "" +"+ 0-2 hop variance (high additive randomisation, subtractive performance)" +msgstr "+ 0-2 hop variantie (hoge toegevoegde randomisatie, minder prestatie)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:292 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:305 +msgid "+/- 0-1 hop variance (standard randomisation, standard performance)" +msgstr "+/- 0-1 hop variantie (standaard randomisatie, standaard prestatie)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:296 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:309 +msgid "+/- 0-2 hop variance (not recommended)" +msgstr "+/- 0-2 hop variantie (niet aanbevolen)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:308 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:321 +msgid "hop variance" +msgstr "hop variantie" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:313 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:326 +msgid "Count" +msgstr "Aantal" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:320 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:333 +msgid "1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)" +msgstr "1 inkomende, 1 uitgaande tunnel (laag bandbreedte gebruik, minder betrouwbaar)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:324 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:337 +msgid "" +"2 inbound, 2 outbound tunnels (standard bandwidth usage, standard " +"reliability)" +msgstr "2 inkomende, 2 uitgaande tunnels (standaard bandbreedte gebruik, standaard betrouwbaarheid)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:328 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:341 +msgid "" +"3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)" +msgstr "3 inkomende, 3 uitgaande tunnels (hoge bandbreedte gebruik, hogere betrouwbaarheid)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:337 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:350 +msgid "tunnels" +msgstr "tunnels" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:342 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:355 +msgid "Backup Count" +msgstr "Backup Aantal" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:349 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:362 +msgid "0 backup tunnels (0 redundancy, no added resource usage)" +msgstr "0 backup tunnels (0 redundantie, geen additionele bronnen gebruikt)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:353 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:366 +msgid "1 backup tunnel each direction (low redundancy, low resource usage)" +msgstr "1 backup tunnel in beide richting (lage redundantie, lage aantal bronnen gebruikt)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:357 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:370 +msgid "" +"2 backup tunnels each direction (medium redundancy, medium resource usage)" +msgstr "2 backup tunnels in beide richting (gemiddelde redundantie, gemiddeld aantal bronnen gebruikt)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:361 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:374 +msgid "3 backup tunnels each direction (high redundancy, high resource usage)" +msgstr "3 backup tunnels in beide richting (hoge redundantie, hoog aantal bronnen gebruikt)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:370 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:383 +msgid "backup tunnels" +msgstr "backup tunnels" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:377 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:390 +msgid "Profile" +msgstr "Profiel" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:384 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:397 +msgid "interactive connection" +msgstr "interactieve connectie" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:388 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:401 +msgid "bulk connection (downloads/websites/BT)" +msgstr "bulk connection (downloads/websites/BT)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:390 +msgid "Delay Connect" +msgstr "Vertraagde Connectie" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:394 +msgid "for request/response connections" +msgstr "voor request/response connecties" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:398 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:405 +msgid "I2CP Options" +msgstr "I2CP Opties" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:400 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:146 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:407 +msgid "Host" +msgstr "Host" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:404 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:152 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:411 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:244 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:266 +msgid "Port" +msgstr "Poort" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:410 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:443 +msgid "Reduce tunnel quantity when idle" +msgstr "Verminder tunnel aantal wanneer in rust" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:412 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:426 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:434 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:446 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:456 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:417 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:433 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:445 +msgid "Enable" +msgstr "Ingeschakeld" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:416 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:449 +msgid "Reduced tunnel count" +msgstr "Verminder tunnel aantal" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:420 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:440 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:453 +msgid "Idle minutes" +msgstr "Rust minuten" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:424 +msgid "Close tunnels when idle" +msgstr "Sluit tunnels wanneer in rust" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:430 +msgid "New Keys on Reopen" +msgstr "Nieuwe Sleutels bij Heropenen" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:438 +msgid "Disable" +msgstr "Uitgeschakeld" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:444 +msgid "Delay tunnel open until required" +msgstr "Vertraag tunnel opening totdat het nodig is" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:454 +msgid "Persistent private key" +msgstr "Persistente private sleutel" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:460 +msgid "File" +msgstr "Bestand" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:464 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:235 +msgid "Local destination" +msgstr "Lokale destination" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:468 +msgid "(if known)" +msgstr "(indien bekend)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:472 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:489 +msgid "Custom options" +msgstr "Aangepaste opties" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:476 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:493 +msgid "" +"NOTE: If tunnel is currently running, most changes will not take effect " +"until tunnel is stopped and restarted." +msgstr "OPMERKING: Indien de tunnel op dit moment draait, zullen de meeste wijzigingen pas effect hebben na het stoppen en herstarten van de tunnel." + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:478 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:495 +msgid "Cancel" +msgstr "Annuleer" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:482 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:499 +msgid "Delete" +msgstr "Verwijder" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:484 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:501 +msgid "Save" +msgstr "Opslaan" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:73 +msgid "I2P Tunnel Manager - Edit Server Tunnel" +msgstr "I2P Tunnel Manager - Bewerk Server Tunnel" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:93 +msgid "Edit server settings" +msgstr "Bewerk server instellingen" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:101 +msgid "New server settings" +msgstr "Nieuwe server instellingen" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:214 +msgid "Website name" +msgstr "Website naam" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:218 +msgid "(leave blank for outproxies)" +msgstr "(leeg laten voor uitgaande proxies)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:223 +msgid "Private key file" +msgstr "Private sleutel bestand" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:245 +msgid "Add to local addressbook" +msgstr "Toevoegen aan lokaal adresboek" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:415 +msgid "Encrypt Leaseset" +msgstr "Versleutel Leaseset" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:421 +msgid "Encryption Key" +msgstr "Encryptie Sleutel" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:425 +msgid "Generate New Key" +msgstr "Genereer Nieuwe Sleutel" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:427 +msgid "Generate" +msgstr "Genereer" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:429 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:487 +msgid "(Tunnel must be stopped first)" +msgstr "(Tunnel moet eerst gestopt worden)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:431 +msgid "Restricted Access List" +msgstr "Beperkte Toegangs Lijst" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:437 +msgid "Access List" +msgstr "Toegangs Lijst" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:441 +msgid "(Restrict to these clients only)" +msgstr "(Beperkt tot slechts deze clients)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:457 +msgid "New Certificate type" +msgstr "Nieuw Certificaat type" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:459 +msgid "None" +msgstr "Geen" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:463 +msgid "Hashcash (effort)" +msgstr "Hashcash (effort)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:469 +msgid "Hashcash Calc Time" +msgstr "Hashcash Reken Tijd" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:471 +msgid "Estimate" +msgstr "Inschatten" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:473 +msgid "Hidden" +msgstr "Verborgen" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:477 +msgid "Signed (signed by)" +msgstr "Ondertekend (ondertekend door)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:483 +msgid "Modify Certificate" +msgstr "Wijzig Certificaat" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:485 +msgid "Modify" +msgstr "Wijzig" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:71 +msgid "I2P Tunnel Manager - List" +msgstr "I2P Tunnel Manager - Lijst" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:83 +msgid "Status Messages" +msgstr "Status Berichten" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:87 +msgid "Refresh" +msgstr "Ververs" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:91 +msgid "Stop All" +msgstr "Stop Alles" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:95 +msgid "Start All" +msgstr "Start Alles" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:99 +msgid "Restart All" +msgstr "Herstart Alles" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:103 +msgid "Reload Config" +msgstr "Herlaad Configuratie" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:105 +msgid "I2P Server Tunnels" +msgstr "I2P Server Tunnels" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:109 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:130 +msgid "Points at" +msgstr "Verwijst naar" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:111 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:153 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:157 +msgid "Preview" +msgstr "Preview" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:113 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:177 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:250 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:278 +msgid "Status" +msgstr "Status" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:163 +msgid "Base32 Address" +msgstr "Base32 Adres" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:171 +msgid "No Preview" +msgstr "Geen Preview" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:184 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:285 +msgid "Starting..." +msgstr "Starten..." + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:191 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:205 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:292 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:306 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:320 +msgid "Stop" +msgstr "Stop" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:198 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:313 +msgid "Running" +msgstr "Draait" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:212 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:327 +msgid "Stopped" +msgstr "Gestopt" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:219 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:334 +msgid "Start" +msgstr "Start" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:234 +msgid "New server tunnel" +msgstr "Nieuwe server tunnel" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:236 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:368 +msgid "Standard" +msgstr "Standaard" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:238 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:370 +msgid "Create" +msgstr "Creëer" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:240 +msgid "I2P Client Tunnels" +msgstr "I2P Client Tunnels" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:248 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:274 +msgid "Interface" +msgstr "Interface" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:299 +msgid "Standby" +msgstr "Stand-by" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:346 +msgid "Outproxy" +msgstr "Uitgaande proxy" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:350 +msgid "Destination" +msgstr "Destination" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:366 +msgid "New client tunnel" +msgstr "Nieuwe client tunnel" diff --git a/apps/i2ptunnel/locale/messages_zh.po b/apps/i2ptunnel/locale/messages_zh.po index 833b62fe9..0955d4e0c 100644 --- a/apps/i2ptunnel/locale/messages_zh.po +++ b/apps/i2ptunnel/locale/messages_zh.po @@ -1,677 +1,701 @@ -# I2P -# Copyright (C) 2009 The I2P Project -# This file is distributed under the same license as the i2ptunnel package. -# To contribute translations, see http://www.i2p2.de/newdevelopers -# foo , 2009. -# -msgid "" -msgstr "" -"Project-Id-Version: I2P i2ptunnel\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2010-05-29 02:35+0000\n" -"PO-Revision-Date: 2010-05-29 10:57+0800\n" -"Last-Translator: walking \n" -"Language-Team: foo \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Poedit-Language: Chinese\n" - -#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:493 -#, java-format -msgid "To visit the destination in your host database, click here. To visit the conflicting addresshelper destination, click here." -msgstr "域名冲突:要访问您本地【地址簿】中设置的目标主机(相当与IP),请点击这里。要访问【地址助手】返回的目标主机请点这里。" - -#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:904 -msgid "Click a link below to look for an address helper by using a \"jump\" service:" -msgstr "请点击下面的链接通过【跳转(Jump)】服务提供的【地址助手】链接跳转至域名对应的主机:" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:369 -msgid "New Tunnel" -msgstr "新建隧道" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:389 -msgid "Standard client" -msgstr "标准客户端" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:390 -msgid "HTTP client" -msgstr "HTTP 客户端" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:391 -msgid "IRC client" -msgstr "IRC 客户端" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:392 -msgid "Standard server" -msgstr "标准服务器" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:393 -msgid "HTTP server" -msgstr "HTTP 服务器" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:394 -msgid "SOCKS 4/4a/5 proxy" -msgstr "SOCKS4/4A/5 代理" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:395 -msgid "SOCKS IRC proxy" -msgstr "SOCKS IRC 代理" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:396 -msgid "CONNECT/SSL/HTTPS proxy" -msgstr "CONNECT/SSL/HTTPS 代理" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:397 -msgid "IRC server" -msgstr "IRC 服务器" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:398 -msgid "Streamr client" -msgstr "Streamr 客户端" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:399 -msgid "Streamr server" -msgstr "Streamr 服务器" - -#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:400 -msgid "HTTP bidir" -msgstr "双向http" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:73 -msgid "I2P Tunnel Manager - Edit Client Tunnel" -msgstr "I2P 隧道管理器 - 编辑客户端隧道" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:93 -msgid "Edit proxy settings" -msgstr "编辑代理设置" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:101 -msgid "New proxy settings" -msgstr "新建代理设置" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:112 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:112 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:107 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:121 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:242 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:257 -msgid "Name" -msgstr "名称" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:116 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:116 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:246 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:270 -msgid "Type" -msgstr "类型" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:120 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:120 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:226 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:358 -msgid "Description" -msgstr "描述" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:126 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:136 -msgid "Target" -msgstr "目标" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:130 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:132 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:167 -msgid "Access Point" -msgstr "接入点" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:137 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:179 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:207 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:157 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:172 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:228 -msgid "required" -msgstr "必要" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:150 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:142 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:183 -msgid "Reachable by" -msgstr "访问地址" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:162 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:195 -msgid "Locally (127.0.0.1)" -msgstr "本地(127.0.0.1)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:166 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:199 -msgid "Everyone (0.0.0.0)" -msgstr "任何人(0.0.0.0)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:170 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:203 -msgid "LAN Hosts (Please specify your LAN address)" -msgstr "局域网(请指定LAN地址)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:186 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:205 -msgid "Other" -msgstr "其他" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:195 -msgid "Outproxies" -msgstr "出口代理" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:202 -msgid "Tunnel Destination" -msgstr "隧道目标" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:214 -msgid "name or destination" -msgstr "名称或描述" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:220 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:237 -msgid "Profile" -msgstr "连接类型" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:227 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:244 -msgid "interactive connection" -msgstr "速度连接" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:231 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:248 -msgid "bulk connection (downloads/websites/BT)" -msgstr "效率连接(下载/WEB/BT)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:233 -msgid "Delay Connect" -msgstr "连接延迟断开" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:237 -msgid "for request/response connections" -msgstr "单请求/响应连接" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:239 -msgid "Shared Client" -msgstr "共享客户端" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:243 -msgid "(Share tunnels with other clients and irc/httpclients? Change requires restart of client proxy)" -msgstr "(与其他客户端例如IRC/HTTP共享隧道?修改需要重新启动)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:247 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:124 -msgid "Auto Start" -msgstr "自动启动" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:251 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:128 -msgid "(Check the Box for 'YES')" -msgstr "(选中表示\"是\")" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:253 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:266 -msgid "Advanced networking options" -msgstr "高级网络设置" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:255 -msgid "(NOTE: when this client proxy is configured to share tunnels, then these options are for all the shared proxy clients!)" -msgstr "(注意:此客户代理被设置使用共享隧道时,这些设置将影响所有使用共享隧道的客户端!)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:257 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:268 -msgid "Tunnel Options" -msgstr "隧道选项" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:259 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:270 -msgid "Length" -msgstr "长度" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:266 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:277 -msgid "0 hop tunnel (low anonymity, low latency)" -msgstr "直连(匿名性无,延迟低)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:270 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:281 -msgid "1 hop tunnel (medium anonymity, medium latency)" -msgstr "隧道跳点x1(匿名性中,延迟中)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:274 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:285 -msgid "2 hop tunnel (high anonymity, high latency)" -msgstr "隧道跳点x2(匿名性高,延迟高)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:278 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:289 -msgid "3 hop tunnel (very high anonymity, poor performance)" -msgstr "隧道跳点x3(匿名性优,影响性能)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:287 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:298 -msgid "hop tunnel (very poor performance)" -msgstr "跳点隧道(严重影响性能)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:292 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:303 -msgid "Variance" -msgstr "随机变化" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:299 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:310 -msgid "0 hop variance (no randomisation, consistant performance)" -msgstr "隧道长度恒定(随机性无,性能稳定)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:303 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:314 -msgid "+ 0-1 hop variance (medium additive randomisation, subtractive performance)" -msgstr "隧道长度+ 0-1(随机性中,影响性能)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:307 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:318 -msgid "+ 0-2 hop variance (high additive randomisation, subtractive performance)" -msgstr "隧道长度+ 0-2(随机性高,影响性能)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:311 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:322 -msgid "+/- 0-1 hop variance (standard randomisation, standard performance)" -msgstr "隧道长度+/- 0-1(随机性标准,正常性能)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:315 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:326 -msgid "+/- 0-2 hop variance (not recommended)" -msgstr "隧道程度+/- 0-2(不推荐)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:327 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:338 -msgid "hop variance" -msgstr "节点数量" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:332 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:343 -msgid "Count" -msgstr "计数" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:339 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:350 -msgid "1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)" -msgstr "出/入站隧道x1(带宽低,低可靠性)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:343 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:354 -msgid "2 inbound, 2 outbound tunnels (standard bandwidth usage, standard reliability)" -msgstr "出/入站隧道x2(带宽标准,标准稳定性)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:347 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:358 -msgid "3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)" -msgstr "出/入站隧道x3(带宽高,高稳定性)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:356 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:367 -msgid "tunnels" -msgstr "隧道" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:361 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:372 -msgid "Backup Count" -msgstr "备用数量" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:368 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:379 -msgid "0 backup tunnels (0 redundancy, no added resource usage)" -msgstr "无备用隧道(无冗余,不增加资源占用)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:372 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:383 -msgid "1 backup tunnel each direction (low redundancy, low resource usage)" -msgstr "备用隧道对x1 (低冗余,低资源占用)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:376 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:387 -msgid "2 backup tunnels each direction (medium redundancy, medium resource usage)" -msgstr "备用隧道对x2 (中冗余,中资源占用)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:380 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:391 -msgid "3 backup tunnels each direction (high redundancy, high resource usage)" -msgstr "备用隧道对x3 (高冗余,高资源占用)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:389 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:400 -msgid "backup tunnels" -msgstr "备用隧道" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:394 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:405 -msgid "I2CP Options" -msgstr "I2CP选项" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:396 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:146 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:407 -msgid "Host" -msgstr "主机" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:400 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:152 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:411 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:244 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:266 -msgid "Port" -msgstr "端口" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:406 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:443 -msgid "Reduce tunnel quantity when idle" -msgstr "空闲时缩减隧道数量" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:408 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:422 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:430 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:442 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:452 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:417 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:433 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:445 -msgid "Enable" -msgstr "启用" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:412 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:449 -msgid "Reduced tunnel count" -msgstr "削减后的隧道数量" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:416 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:436 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:453 -msgid "Idle minutes" -msgstr "空闲时间(分钟)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:420 -msgid "Close tunnels when idle" -msgstr "空闲时关闭隧道" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:426 -msgid "New Keys on Reopen" -msgstr "重新打开隧道时使用新密钥" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:434 -msgid "Disable" -msgstr "禁用" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:440 -msgid "Delay tunnel open until required" -msgstr "仅在请求时打开" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:450 -msgid "Persistent private key" -msgstr "永久私有密钥" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:456 -msgid "File" -msgstr "文件" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:460 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:252 -msgid "Local destination" -msgstr "本地目标" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:464 -msgid "(if known)" -msgstr "(如果已知)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:468 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:489 -msgid "Custom options" -msgstr "自定义选项" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:472 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:493 -msgid "NOTE: If tunnel is currently running, most changes will not take effect until tunnel is stopped and restarted." -msgstr "注意:如果当前隧道已经启动,设置需要【停止】并重新【启动】相应隧道后才能生效。" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:474 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:495 -msgid "Cancel" -msgstr "取消" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:478 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:499 -msgid "Delete" -msgstr "删除" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:480 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:501 -msgid "Save" -msgstr "保存" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:73 -msgid "I2P Tunnel Manager - Edit Server Tunnel" -msgstr "I2P隧道管理器 - 编辑服务器隧道" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:93 -msgid "Edit server settings" -msgstr "服务器隧道设置" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:101 -msgid "New server settings" -msgstr "新建服务器设置" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:214 -msgid "Website name" -msgstr "网站名称" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:218 -msgid "(leave blank for outproxies)" -msgstr "(出口代理这里请置空)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:223 -msgid "Private key file" -msgstr "私钥文件" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:262 -msgid "Add to local addressbook" -msgstr "添加至本地地址簿" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:415 -msgid "Encrypt Leaseset" -msgstr "加密赁集" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:421 -msgid "Encryption Key" -msgstr "加密密钥" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:425 -msgid "Generate New Key" -msgstr "生成新密钥" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:427 -msgid "Generate" -msgstr "生成" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:429 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:487 -msgid "(Tunnel must be stopped first)" -msgstr "(必须先停止隧道)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:431 -msgid "Restricted Access List" -msgstr "限制访问列表" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:437 -msgid "Access List" -msgstr "访问列表" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:441 -msgid "(Restrict to these clients only)" -msgstr "(仅允许这些客户访问)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:457 -msgid "New Certificate type" -msgstr "新建证书类型" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:459 -msgid "None" -msgstr "无" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:463 -msgid "Hashcash (effort)" -msgstr "Hashcash (强度)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:469 -msgid "Hashcash Calc Time" -msgstr "Hashcash 计算时间" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:471 -msgid "Estimate" -msgstr "估算" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:473 -msgid "Hidden" -msgstr "隐藏" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:477 -msgid "Signed (signed by)" -msgstr "签名(签名者)" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:483 -msgid "Modify Certificate" -msgstr "修改证书" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:485 -msgid "Modify" -msgstr "修改" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:71 -msgid "I2P Tunnel Manager - List" -msgstr "I2P隧道管理器 - 列表" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:83 -msgid "Status Messages" -msgstr "状态信息" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:87 -msgid "Refresh" -msgstr "刷新" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:91 -msgid "Stop All" -msgstr "全部停止" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:95 -msgid "Start All" -msgstr "全部启动" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:99 -msgid "Restart All" -msgstr "全部重启" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:103 -msgid "Reload Config" -msgstr "重新载入设置" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:105 -msgid "I2P Server Tunnels" -msgstr "I2P服务端隧道" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:109 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:130 -msgid "Points at" -msgstr "指向" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:111 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:153 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:157 -msgid "Preview" -msgstr "预览" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:113 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:177 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:250 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:278 -msgid "Status" -msgstr "状态" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:163 -msgid "Base32 Address" -msgstr "Base32地址" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:171 -msgid "No Preview" -msgstr "无预览" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:184 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:285 -msgid "Starting..." -msgstr "正在启动..." - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:191 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:205 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:292 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:306 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:320 -msgid "Stop" -msgstr "停止" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:198 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:313 -msgid "Running" -msgstr "运行中" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:212 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:327 -msgid "Stopped" -msgstr "已停止" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:219 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:334 -msgid "Start" -msgstr "启动" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:234 -msgid "New server tunnel" -msgstr "新建服务器隧道" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:236 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:368 -msgid "Standard" -msgstr "标准" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:238 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:370 -msgid "Create" -msgstr "创建" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:240 -msgid "I2P Client Tunnels" -msgstr "I2P客户端隧道" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:248 -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:274 -msgid "Interface" -msgstr "网络接口" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:299 -msgid "Standby" -msgstr "等待" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:346 -msgid "Outproxy" -msgstr "出口代理" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:350 -msgid "Destination" -msgstr "目标" - -#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:366 -msgid "New client tunnel" -msgstr "新建客户隧道" - -#~ msgid "Unimplemented" -#~ msgstr "尚未实现" - +# I2P +# Copyright (C) 2009 The I2P Project +# This file is distributed under the same license as the i2ptunnel package. +# To contribute translations, see http://www.i2p2.de/newdevelopers +# foo , 2009. +# +msgid "" +msgstr "" +"Project-Id-Version: I2P i2ptunnel\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2010-07-01 04:52+0000\n" +"PO-Revision-Date: 2010-05-29 10:57+0800\n" +"Last-Translator: walking \n" +"Language-Team: foo \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Chinese\n" + +#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:493 +#, java-format +msgid "" +"To visit the destination in your host database, click here. To visit the conflicting addresshelper destination, click here." +msgstr "" +"域名冲突:要访问您本地【地址簿】中设置的目标主机(相当与IP),请点击这里。要访问【地址助手】返回的目标主机请点这里。" + +#: ../java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java:909 +msgid "" +"Click a link below to look for an address helper by using a \"jump\" service:" +msgstr "" +"请点击下面的链接通过【跳转(Jump)】服务提供的【地址助手】链接跳转至域名对应的" +"主机:" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:369 +msgid "New Tunnel" +msgstr "新建隧道" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:389 +msgid "Standard client" +msgstr "标准客户端" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:390 +msgid "HTTP client" +msgstr "HTTP 客户端" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:391 +msgid "IRC client" +msgstr "IRC 客户端" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:392 +msgid "Standard server" +msgstr "标准服务器" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:393 +msgid "HTTP server" +msgstr "HTTP 服务器" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:394 +msgid "SOCKS 4/4a/5 proxy" +msgstr "SOCKS4/4A/5 代理" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:395 +msgid "SOCKS IRC proxy" +msgstr "SOCKS IRC 代理" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:396 +msgid "CONNECT/SSL/HTTPS proxy" +msgstr "CONNECT/SSL/HTTPS 代理" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:397 +msgid "IRC server" +msgstr "IRC 服务器" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:398 +msgid "Streamr client" +msgstr "Streamr 客户端" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:399 +msgid "Streamr server" +msgstr "Streamr 服务器" + +#: ../java/src/net/i2p/i2ptunnel/web/IndexBean.java:400 +msgid "HTTP bidir" +msgstr "双向http" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:73 +msgid "I2P Tunnel Manager - Edit Client Tunnel" +msgstr "I2P 隧道管理器 - 编辑客户端隧道" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:93 +msgid "Edit proxy settings" +msgstr "编辑代理设置" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:101 +msgid "New proxy settings" +msgstr "新建代理设置" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:112 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:112 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:107 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:121 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:242 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:257 +msgid "Name" +msgstr "名称" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:116 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:116 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:246 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:270 +msgid "Type" +msgstr "类型" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:120 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:120 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:226 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:358 +msgid "Description" +msgstr "描述" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:126 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:136 +msgid "Target" +msgstr "目标" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:130 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:132 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:167 +msgid "Access Point" +msgstr "接入点" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:137 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:179 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:207 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:157 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:172 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:228 +msgid "required" +msgstr "必要" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:150 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:142 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:183 +msgid "Reachable by" +msgstr "访问地址" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:162 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:195 +msgid "Locally (127.0.0.1)" +msgstr "本地(127.0.0.1)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:166 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:199 +msgid "Everyone (0.0.0.0)" +msgstr "任何人(0.0.0.0)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:170 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:203 +msgid "LAN Hosts (Please specify your LAN address)" +msgstr "局域网(请指定LAN地址)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:186 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:205 +msgid "Other" +msgstr "其他" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:195 +msgid "Outproxies" +msgstr "出口代理" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:202 +msgid "Tunnel Destination" +msgstr "隧道目标" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:214 +msgid "name or destination" +msgstr "名称或描述" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:220 +msgid "Shared Client" +msgstr "共享客户端" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:224 +msgid "" +"(Share tunnels with other clients and irc/httpclients? Change requires " +"restart of client proxy)" +msgstr "(与其他客户端例如IRC/HTTP共享隧道?修改需要重新启动)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:228 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:124 +msgid "Auto Start" +msgstr "自动启动" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:232 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:128 +msgid "(Check the Box for 'YES')" +msgstr "(选中表示\"是\")" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:234 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:249 +msgid "Advanced networking options" +msgstr "高级网络设置" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:236 +msgid "" +"(NOTE: when this client proxy is configured to share tunnels, then these " +"options are for all the shared proxy clients!)" +msgstr "" +"(注意:此客户代理被设置使用共享隧道时,这些设置将影响所有使用共享隧道的客户" +"端!)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:238 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:251 +msgid "Tunnel Options" +msgstr "隧道选项" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:240 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:253 +msgid "Length" +msgstr "长度" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:247 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:260 +msgid "0 hop tunnel (low anonymity, low latency)" +msgstr "直连(匿名性无,延迟低)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:251 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:264 +msgid "1 hop tunnel (medium anonymity, medium latency)" +msgstr "隧道跳点x1(匿名性中,延迟中)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:255 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:268 +msgid "2 hop tunnel (high anonymity, high latency)" +msgstr "隧道跳点x2(匿名性高,延迟高)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:259 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:272 +msgid "3 hop tunnel (very high anonymity, poor performance)" +msgstr "隧道跳点x3(匿名性优,影响性能)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:268 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:281 +msgid "hop tunnel (very poor performance)" +msgstr "跳点隧道(严重影响性能)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:273 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:286 +msgid "Variance" +msgstr "随机变化" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:280 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:293 +msgid "0 hop variance (no randomisation, consistant performance)" +msgstr "隧道长度恒定(随机性无,性能稳定)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:284 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:297 +msgid "" +"+ 0-1 hop variance (medium additive randomisation, subtractive performance)" +msgstr "隧道长度+ 0-1(随机性中,影响性能)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:288 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:301 +msgid "" +"+ 0-2 hop variance (high additive randomisation, subtractive performance)" +msgstr "隧道长度+ 0-2(随机性高,影响性能)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:292 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:305 +msgid "+/- 0-1 hop variance (standard randomisation, standard performance)" +msgstr "隧道长度+/- 0-1(随机性标准,正常性能)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:296 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:309 +msgid "+/- 0-2 hop variance (not recommended)" +msgstr "隧道程度+/- 0-2(不推荐)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:308 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:321 +msgid "hop variance" +msgstr "节点数量" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:313 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:326 +msgid "Count" +msgstr "计数" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:320 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:333 +msgid "1 inbound, 1 outbound tunnel (low bandwidth usage, less reliability)" +msgstr "出/入站隧道x1(带宽低,低可靠性)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:324 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:337 +msgid "" +"2 inbound, 2 outbound tunnels (standard bandwidth usage, standard " +"reliability)" +msgstr "出/入站隧道x2(带宽标准,标准稳定性)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:328 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:341 +msgid "" +"3 inbound, 3 outbound tunnels (higher bandwidth usage, higher reliability)" +msgstr "出/入站隧道x3(带宽高,高稳定性)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:337 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:350 +msgid "tunnels" +msgstr "隧道" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:342 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:355 +msgid "Backup Count" +msgstr "备用数量" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:349 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:362 +msgid "0 backup tunnels (0 redundancy, no added resource usage)" +msgstr "无备用隧道(无冗余,不增加资源占用)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:353 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:366 +msgid "1 backup tunnel each direction (low redundancy, low resource usage)" +msgstr "备用隧道对x1 (低冗余,低资源占用)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:357 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:370 +msgid "" +"2 backup tunnels each direction (medium redundancy, medium resource usage)" +msgstr "备用隧道对x2 (中冗余,中资源占用)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:361 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:374 +msgid "3 backup tunnels each direction (high redundancy, high resource usage)" +msgstr "备用隧道对x3 (高冗余,高资源占用)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:370 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:383 +msgid "backup tunnels" +msgstr "备用隧道" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:377 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:390 +msgid "Profile" +msgstr "连接类型" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:384 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:397 +msgid "interactive connection" +msgstr "速度连接" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:388 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:401 +msgid "bulk connection (downloads/websites/BT)" +msgstr "效率连接(下载/WEB/BT)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:390 +msgid "Delay Connect" +msgstr "连接延迟断开" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:394 +msgid "for request/response connections" +msgstr "单请求/响应连接" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:398 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:405 +msgid "I2CP Options" +msgstr "I2CP选项" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:400 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:146 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:407 +msgid "Host" +msgstr "主机" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:404 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:152 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:411 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:244 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:266 +msgid "Port" +msgstr "端口" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:410 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:443 +msgid "Reduce tunnel quantity when idle" +msgstr "空闲时缩减隧道数量" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:412 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:426 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:434 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:446 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:456 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:417 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:433 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:445 +msgid "Enable" +msgstr "启用" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:416 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:449 +msgid "Reduced tunnel count" +msgstr "削减后的隧道数量" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:420 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:440 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:453 +msgid "Idle minutes" +msgstr "空闲时间(分钟)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:424 +msgid "Close tunnels when idle" +msgstr "空闲时关闭隧道" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:430 +msgid "New Keys on Reopen" +msgstr "重新打开隧道时使用新密钥" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:438 +msgid "Disable" +msgstr "禁用" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:444 +msgid "Delay tunnel open until required" +msgstr "仅在请求时打开" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:454 +msgid "Persistent private key" +msgstr "永久私有密钥" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:460 +msgid "File" +msgstr "文件" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:464 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:235 +msgid "Local destination" +msgstr "本地目标" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:468 +msgid "(if known)" +msgstr "(如果已知)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:472 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:489 +msgid "Custom options" +msgstr "自定义选项" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:476 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:493 +msgid "" +"NOTE: If tunnel is currently running, most changes will not take effect " +"until tunnel is stopped and restarted." +msgstr "" +"注意:如果当前隧道已经启动,设置需要【停止】并重新【启动】相应隧道后才能生" +"效。" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:478 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:495 +msgid "Cancel" +msgstr "取消" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:482 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:499 +msgid "Delete" +msgstr "删除" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editClient_jsp.java:484 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:501 +msgid "Save" +msgstr "保存" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:73 +msgid "I2P Tunnel Manager - Edit Server Tunnel" +msgstr "I2P隧道管理器 - 编辑服务器隧道" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:93 +msgid "Edit server settings" +msgstr "服务器隧道设置" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:101 +msgid "New server settings" +msgstr "新建服务器设置" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:214 +msgid "Website name" +msgstr "网站名称" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:218 +msgid "(leave blank for outproxies)" +msgstr "(出口代理这里请置空)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:223 +msgid "Private key file" +msgstr "私钥文件" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:245 +msgid "Add to local addressbook" +msgstr "添加至本地地址簿" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:415 +msgid "Encrypt Leaseset" +msgstr "加密赁集" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:421 +msgid "Encryption Key" +msgstr "加密密钥" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:425 +msgid "Generate New Key" +msgstr "生成新密钥" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:427 +msgid "Generate" +msgstr "生成" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:429 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:487 +msgid "(Tunnel must be stopped first)" +msgstr "(必须先停止隧道)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:431 +msgid "Restricted Access List" +msgstr "限制访问列表" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:437 +msgid "Access List" +msgstr "访问列表" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:441 +msgid "(Restrict to these clients only)" +msgstr "(仅允许这些客户访问)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:457 +msgid "New Certificate type" +msgstr "新建证书类型" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:459 +msgid "None" +msgstr "无" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:463 +msgid "Hashcash (effort)" +msgstr "Hashcash (强度)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:469 +msgid "Hashcash Calc Time" +msgstr "Hashcash 计算时间" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:471 +msgid "Estimate" +msgstr "估算" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:473 +msgid "Hidden" +msgstr "隐藏" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:477 +msgid "Signed (signed by)" +msgstr "签名(签名者)" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:483 +msgid "Modify Certificate" +msgstr "修改证书" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/editServer_jsp.java:485 +msgid "Modify" +msgstr "修改" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:71 +msgid "I2P Tunnel Manager - List" +msgstr "I2P隧道管理器 - 列表" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:83 +msgid "Status Messages" +msgstr "状态信息" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:87 +msgid "Refresh" +msgstr "刷新" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:91 +msgid "Stop All" +msgstr "全部停止" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:95 +msgid "Start All" +msgstr "全部启动" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:99 +msgid "Restart All" +msgstr "全部重启" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:103 +msgid "Reload Config" +msgstr "重新载入设置" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:105 +msgid "I2P Server Tunnels" +msgstr "I2P服务端隧道" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:109 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:130 +msgid "Points at" +msgstr "指向" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:111 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:153 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:157 +msgid "Preview" +msgstr "预览" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:113 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:177 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:250 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:278 +msgid "Status" +msgstr "状态" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:163 +msgid "Base32 Address" +msgstr "Base32地址" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:171 +msgid "No Preview" +msgstr "无预览" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:184 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:285 +msgid "Starting..." +msgstr "正在启动..." + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:191 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:205 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:292 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:306 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:320 +msgid "Stop" +msgstr "停止" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:198 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:313 +msgid "Running" +msgstr "运行中" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:212 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:327 +msgid "Stopped" +msgstr "已停止" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:219 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:334 +msgid "Start" +msgstr "启动" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:234 +msgid "New server tunnel" +msgstr "新建服务器隧道" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:236 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:368 +msgid "Standard" +msgstr "标准" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:238 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:370 +msgid "Create" +msgstr "创建" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:240 +msgid "I2P Client Tunnels" +msgstr "I2P客户端隧道" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:248 +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:274 +msgid "Interface" +msgstr "网络接口" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:299 +msgid "Standby" +msgstr "等待" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:346 +msgid "Outproxy" +msgstr "出口代理" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:350 +msgid "Destination" +msgstr "目标" + +#: ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/jsp/index_jsp.java:366 +msgid "New client tunnel" +msgstr "新建客户隧道" + +#~ msgid "Unimplemented" +#~ msgstr "尚未实现" diff --git a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java index 393cf1ae2..34dc8ac59 100644 --- a/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java +++ b/apps/ministreaming/java/src/net/i2p/client/streaming/I2PSocketManagerFactory.java @@ -130,16 +130,19 @@ public class I2PSocketManagerFactory { if (!opts.containsKey(name)) opts.setProperty(name, System.getProperty(name)); } - boolean oldLib = DEFAULT_MANAGER.equals(opts.getProperty(PROP_MANAGER, DEFAULT_MANAGER)); - if (oldLib && false) { + //boolean oldLib = DEFAULT_MANAGER.equals(opts.getProperty(PROP_MANAGER, DEFAULT_MANAGER)); + //if (oldLib && false) { // for the old streaming lib - opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED); + // opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_GUARANTEED); //opts.setProperty("tunnels.depthInbound", "0"); - } else { + //} else { // for new streaming lib: - opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT); + //opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_BEST_EFFORT); + // as of 0.8.1 (I2CP default is BestEffort) + if (!opts.containsKey(I2PClient.PROP_RELIABILITY)) + opts.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_NONE); //p.setProperty("tunnels.depthInbound", "0"); - } + //} if (i2cpHost != null) opts.setProperty(I2PClient.PROP_TCP_HOST, i2cpHost); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java index d6eb2edd1..f499b2ea4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java @@ -44,13 +44,16 @@ public class LogsHelper extends HelperBase { } ******/ - private String formatMessages(List msgs) { + /** formats in reverse order */ + private String formatMessages(List msgs) { + if (msgs.isEmpty()) + return "

" + _("No log messages") + "

"; boolean colorize = Boolean.valueOf(_context.getProperty("routerconsole.logs.color")).booleanValue(); StringBuilder buf = new StringBuilder(16*1024); buf.append("