diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 52f82fee2e6a5e0307811bf95f7c082a1a761466..82d1d80f4f53789bb8a06c21e709fd57ad261a44 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -179,7 +179,7 @@ public class SnarkManager implements Snark.CompleteListener { if (!_config.containsKey(PROP_STARTUP_DELAY)) _config.setProperty(PROP_STARTUP_DELAY, "" + DEFAULT_STARTUP_DELAY); if (!_config.containsKey(PROP_THEME)) - _config.setProperty(PROP_THEME, "" + DEFAULT_THEME); + _config.setProperty(PROP_THEME, DEFAULT_THEME); updateConfig(); } /** @@ -198,11 +198,9 @@ public class SnarkManager implements Snark.CompleteListener { public String[] getThemes() { String[] themes = null; // "docs/themes/snark/" - String fsc = new String(""+File.separatorChar); - String look = _context.getBaseDir() + fsc + "docs" + fsc +"themes" + fsc + "snark" + fsc; + File dir = new File(_context.getBaseDir(), "docs/themes/snark"); FileFilter fileFilter = new FileFilter() { public boolean accept(File file) { return file.isDirectory(); } }; // Walk the themes dir, collecting the theme names, and append them to the map - File dir = new File(look); File[] dirnames = dir.listFiles(fileFilter); if (dirnames != null) { themes = new String[dirnames.length]; @@ -271,7 +269,7 @@ public class SnarkManager implements Snark.CompleteListener { 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, String Theme) { + String upLimit, String upBW, boolean useOpenTrackers, String openTrackers, String theme) { boolean changed = false; //if (eepHost != null) { // // unused, we use socket eepget @@ -434,10 +432,10 @@ public class SnarkManager implements Snark.CompleteListener { changed = true; } } - if (Theme != null) { - if(!Theme.equals(_config.getProperty(PROP_THEME))) { - _config.setProperty(PROP_THEME, Theme +""); - addMessage (Theme+(_(" theme locked and loaded."))); + if (theme != null) { + if(!theme.equals(_config.getProperty(PROP_THEME))) { + _config.setProperty(PROP_THEME, theme); + addMessage(_("{0} theme loaded, return to main i2psnark page to view.", theme)); changed = true; } } @@ -935,8 +933,8 @@ public class SnarkManager implements Snark.CompleteListener { // , "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" + "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/" }; diff --git a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java index 81e84c3b9027998fa1e9c293cb5ba275e51cbf26..dddb296f4d6fabbdbad7b5a42ef2317e088bd472 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -31,6 +31,7 @@ import net.i2p.data.DataHelper; import net.i2p.util.FileUtil; import net.i2p.util.I2PAppThread; import net.i2p.util.Log; +import net.i2p.util.SecureFileOutputStream; import org.klomp.snark.MetaInfo; import org.klomp.snark.Peer; @@ -55,6 +56,8 @@ public class I2PSnarkServlet extends Default { private SnarkManager _manager; private static long _nonce; private Resource _resourceBase; + private String _themePath; + private String _imgPath; public static final String PROP_CONFIG_FILE = "i2psnark.configFile"; @@ -124,11 +127,13 @@ public class I2PSnarkServlet extends Default { resp.sendError(HttpResponse.__405_Method_Not_Allowed); return; } + _themePath = "/themes/snark/" + _manager.getTheme() + '/'; + _imgPath = _themePath + "images/"; // this is the part after /i2psnark String path = req.getServletPath(); boolean isConfigure = "/configure".equals(path); // index.jsp doesn't work, it is grabbed by the war handler before here - if (!(path == null || path.equals("/") || path.equals("/index.jsp") || path.equals("/index.html") || isConfigure)) { + if (!(path == null || path.equals("/") || path.equals("/index.jsp") || path.equals("/index.html") || path.equals("/_post") || isConfigure)) { if (path.endsWith("/")) { // bypass the horrid Resource.getListHTML() String pathInfo = req.getPathInfo(); @@ -158,8 +163,12 @@ public class I2PSnarkServlet extends Default { resp.setContentType("text/html; charset=UTF-8"); String nonce = req.getParameter("nonce"); - if ( (nonce != null) && (nonce.equals(String.valueOf(_nonce))) ) - processRequest(req); + if (nonce != null) { + if (nonce.equals(String.valueOf(_nonce))) + processRequest(req); + else // nonce is constant, shouldn't happen + _manager.addMessage("Please retry form submission (bad nonce)"); + } String peerParam = req.getParameter("p"); String peerString; @@ -170,8 +179,8 @@ public class I2PSnarkServlet extends Default { } PrintWriter out = resp.getWriter(); - out.write("<html>\n" + - "<head><link rel=\"shortcut icon\" href=\"/themes/snark/" + _manager.getTheme() + "/favicon.ico\">\n" + + out.write(DOCTYPE + "<html>\n" + + "<head><link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">\n" + "<title>"); out.write(_("I2PSnark - Anonymous BitTorrent Client")); if ("2".equals(peerParam)) @@ -180,22 +189,22 @@ public class I2PSnarkServlet extends Default { // we want it to go to the base URI so we don't refresh with some funky action= value if (!isConfigure) - out.write("<meta http-equiv=\"refresh\" content=\"60;" + req.getRequestURI() + peerString + "\">\n"); - out.write(HEADER_A + _manager.getTheme() + HEADER_B); + out.write("<meta http-equiv=\"refresh\" content=\"60;/i2psnark/" + peerString + "\">\n"); + out.write(HEADER_A + _themePath + HEADER_B); out.write("</head><body>"); out.write("<center>"); if (isConfigure) { out.write("<div class=\"snarknavbar\"><a href=\"/i2psnark/\" title=\""); out.write(_("Torrents")); out.write("\" class=\"snarkRefresh\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/arrow_refresh.png\"> "); + out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\"> "); out.write(_("I2PSnark")); out.write("</a>"); } else { - out.write("<div class=\"snarknavbar\"><a href=\"" + req.getRequestURI() + peerString + "\" title=\""); + out.write("<div class=\"snarknavbar\"><a href=\"/i2psnark/" + peerString + "\" title=\""); out.write(_("Refresh page")); out.write("\" class=\"snarkRefresh\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/arrow_refresh.png\"> "); + out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\"> "); out.write(_("I2PSnark")); out.write("</a> <a href=\"http://forum.i2p/viewforum.php?f=21\" class=\"snarkRefresh\" target=\"_blank\">"); out.write(_("Forum")); @@ -244,85 +253,103 @@ public class I2PSnarkServlet extends Default { String uri = req.getRequestURI(); boolean isForm = _manager.util().connected() || !snarks.isEmpty(); if (isForm) { - out.write("<form action=\""); - out.write(uri); - out.write("\" method=\"POST\">\n"); + out.write("<form action=\"_post\" method=\"POST\">\n"); out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n"); // don't lose peer setting if (peerParam != null) out.write("<input type=\"hidden\" name=\"p\" value=\"" + peerParam + "\" >\n"); } out.write(TABLE_HEADER); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/status.png\""); - out.write(" title=\""); + out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "status.png\" > "); out.write(_("Status")); - out.write("\"> "); -// out.write(_("Status")); if (_manager.util().connected() && !snarks.isEmpty()) { - out.write(" <a href=\""); - out.write(req.getRequestURI()); + out.write(" <a href=\"/i2psnark/"); if (peerParam != null) { out.write("\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/showpeers.png\" title=\""); - out.write(_("Hide All Attached Peers [connected/total in swarm]")); + out.write("<img border=\"0\" src=\"" + _imgPath + "hidepeers.png\" title=\""); + out.write(_("Hide Peers")); out.write("\" alt=\""); out.write(_("Hide Peers")); out.write("\">"); } else { out.write("?p=1\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/hidepeers.png\" title=\""); - out.write(_("Show All Attached Peers [connected/total in swarm]")); + out.write("<img border=\"0\" src=\"" + _imgPath + "showpeers.png\" title=\""); + out.write(_("Show Peers")); out.write("\" alt=\""); out.write(_("Show Peers")); out.write("\">"); } out.write("</a><br>\n"); } - out.write("</th>\n<th align=\"left\">"); -// out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/torrent.png\"\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_torrent.png\" title=\""); - out.write(_("Loaded Torrents")); - out.write("\">"); -// out.write(_("Torrent")); - out.write("</th>\n<th align=\"center\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_eta.png\" title=\""); - out.write(_("Estimated Download Time")); - out.write("\">"); // space here would look better but nbsp is too big and thinsp breaks - // out.write(_("ETA")); - out.write("</th>\n<th align=\"center\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_rx.png\" title=\""); + out.write("</th>\n<th colspan=\"3\" align=\"left\">"); + out.write("<img border=\"0\" src=\"" + _imgPath + "torrent.png\" alt=\"\">"); + out.write(_("Torrent")); + out.write("</th>\n<th align=\"right\">"); + if (_manager.util().connected() && !snarks.isEmpty()) { + out.write("<img border=\"0\" src=\"" + _imgPath + "eta.png\" alt=\"\" title=\""); + out.write(_("Estimated time remaining")); + out.write("\">"); + out.write(_("ETA")); + } + out.write("</th>\n<th align=\"right\">"); + out.write("<img border=\"0\" src=\"" + _imgPath + "head_rx.png\" alt=\"\" title=\""); out.write(_("Downloaded")); out.write("\">"); -// out.write(_("RX")); - out.write("</th>\n<th align=\"center\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_tx.png\" title=\""); - out.write(_("Uploaded")); - out.write("\">"); -// out.write(_("TX")); - out.write("</th>\n<th align=\"center\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_rxspeed.png\" title=\""); - out.write(_("Down Rate")); - out.write("\">"); -// out.write(_("Rate")); + out.write(_("RX")); + out.write("</th>\n<th align=\"right\">"); + if (_manager.util().connected() && !snarks.isEmpty()) { + out.write("<img border=\"0\" src=\"" + _imgPath + "head_tx.png\" alt=\"\" title=\""); + out.write(_("Uploaded")); + out.write("\">"); + out.write(_("TX")); + } + out.write("</th>\n<th align=\"right\">"); + if (_manager.util().connected() && !snarks.isEmpty()) { + out.write("<img border=\"0\" src=\"" + _imgPath + "head_rxspeed.png\" title=\""); + out.write(_("Down Rate")); + out.write("\" alt=\""); + out.write(_("RX")); + out.write(" \">"); + out.write(_("Rate")); + } + out.write("</th>\n<th align=\"right\">"); + if (_manager.util().connected() && !snarks.isEmpty()) { + out.write("<img border=\"0\" src=\"" + _imgPath + "head_txspeed.png\" title=\""); + out.write(_("Up Rate")); + out.write("\" alt=\""); + out.write(_("TX")); + out.write(" \">"); + out.write(_("Rate")); + } out.write("</th>\n<th align=\"center\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_txspeed.png\" title=\""); - out.write(_("Up Rate")); - out.write("\">"); -// out.write(_("Rate")); - out.write("</th>\n"); - out.write("<th align=\"center\">"); + + // Opera and text-mode browsers: no   and no input type=image values submitted + String ua = req.getHeader("User-Agent"); + boolean isDegraded = ua != null && (ua.startsWith("Opera") || ua.startsWith("Lynx") || + ua.startsWith("ELinks") || ua.startsWith("Dillo")); + if (_manager.util().connected()) { - out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\""); + if (isDegraded) + out.write("<a href=\"/i2psnark/?action=StopAll&nonce=" + _nonce + "\"><img title=\""); + else + out.write("<input type=\"image\" name=\"action\" value=\"StopAll\" title=\""); out.write(_("Stop all torrents and the I2P tunnel")); - out.write("\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stop_all.png\" alt=\""); + out.write("\" src=\"" + _imgPath + "stop_all.png\" alt=\""); out.write(_("Stop All")); out.write("\">"); + if (isDegraded) + out.write("</a>"); } else if (!snarks.isEmpty()) { - out.write("<input type=\"image\" name=\"action\" value=\"StartAll\" title=\""); + if (isDegraded) + out.write("<a href=\"/i2psnark/?action=StartAll&nonce=" + _nonce + "\"><img title=\""); + else + out.write("<input type=\"image\" name=\"action\" value=\"StartAll\" title=\""); out.write(_("Start all torrents and the I2P tunnel")); - out.write("\" src=\"/themes/snark/" + _manager.getTheme() + "/images/start_all.png\" alt=\""); + out.write("\" src=\"" + _imgPath + "start_all.png\" alt=\""); out.write(_("Start All")); out.write("\">"); + if (isDegraded) + out.write("</a>"); } else { out.write(" "); } @@ -331,55 +358,35 @@ public class I2PSnarkServlet extends Default { Snark snark = (Snark)snarks.get(i); boolean showDebug = "2".equals(peerParam); boolean showPeers = showDebug || "1".equals(peerParam) || Base64.encode(snark.meta.getInfoHash()).equals(peerParam); - displaySnark(out, snark, uri, i, stats, showPeers, showDebug); + displaySnark(out, snark, uri, i, stats, showPeers, isDegraded, showDebug); } if (snarks.isEmpty()) { out.write("<tr class=\"snarkTorrentNoneLoaded\">" + "<td class=\"snarkTorrentNoneLoaded\"" + - " colspan=\"8\"><i>"); + " colspan=\"11\"><i>"); out.write(_("No torrents loaded.")); out.write("</i></td></tr>\n"); } else if (snarks.size() > 1) { out.write("<tfoot><tr>\n" + -// " <th align=\"left\" colspan=\"2\">"); - " <th align=\"left\">"); -// out.write(_("Totals")); -// out.write(" » "); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/status.png\""); - out.write(" title=\""); + " <th align=\"left\" colspan=\"6\">"); out.write(_("Totals")); - out.write("\">"); - out.write(" "); -// out.write(ngettext("1 connected peer", "{0} connected peers", (int) stats[4])); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_peers.png\""); - out.write(" title=\""); + out.write(": "); + out.write(ngettext("1 torrent", "{0} torrents", snarks.size())); + out.write(", "); + out.write(DataHelper.formatSize2(stats[5]) + "B, "); out.write(ngettext("1 connected peer", "{0} connected peers", (int) stats[4])); - out.write("\">"); - out.write(ngettext("1", "{0}", (int) stats[4])); - out.write("</th>"); -// out.write(" "); -// out.write(ngettext("1 torrent", "{0} torrents", snarks.size())); - out.write("<th><img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_snarks.png\""); - out.write(" title=\""); - out.write(ngettext("1 torrent loaded", "{0} torrents loaded", snarks.size())); - out.write("\">"); - out.write(ngettext("1", "{0}", snarks.size())); - out.write(" "); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/head_loaded.png\""); - out.write(" title=\""); - out.write(_("Total download size (pre-allocated): ")); - out.write(DataHelper.formatSize2(stats[5]) + "B"); - out.write("\">"); - out.write(DataHelper.formatSize2(stats[5]) + "B"); - out.write("</th>\n" + - " <th> </th>\n" + - " <th align=\"right\">" + formatSize(stats[0]) + "</th>\n" + + out.write("</th>\n"); + if (_manager.util().connected()) { + out.write(" <th align=\"right\">" + formatSize(stats[0]) + "</th>\n" + " <th align=\"right\">" + formatSize(stats[1]) + "</th>\n" + " <th align=\"right\">" + formatSize(stats[2]) + "ps</th>\n" + " <th align=\"right\">" + formatSize(stats[3]) + "ps</th>\n" + - " <th> </th></tr>\n" + - "</tfoot>\n"); + " <th></th>"); + } else { + out.write("<th colspan=\"5\"></th>"); + } + out.write("</tr></tfoot>\n"); } out.write("</table>"); @@ -393,14 +400,18 @@ public class I2PSnarkServlet extends Default { private void processRequest(HttpServletRequest req) { String action = req.getParameter("action"); if (action == null) { - // noop + _manager.addMessage("No action specified"); return; } - if (!"POST".equals(req.getMethod())) - return; + // sadly, Opera doesn't send value with input type=image, so we have to use GET there + //if (!"POST".equals(req.getMethod())) { + // _manager.addMessage("Action must be with POST"); + // return; + //} if ("Add".equals(action)) { String newFile = req.getParameter("newFile"); String newURL = req.getParameter("newURL"); + /****** // NOTE - newFile currently disabled in HTML form - see below File f = null; if ( (newFile != null) && (newFile.trim().length() > 0) ) @@ -409,6 +420,7 @@ public class I2PSnarkServlet extends Default { _manager.addMessage(_("Torrent file {0} does not exist", newFile)); } if ( (f != null) && (f.exists()) ) { + // NOTE - All this is disabled - load from local file disabled File local = new File(_manager.getDataDir(), f.getName()); String canonical = null; try { @@ -431,7 +443,9 @@ public class I2PSnarkServlet extends Default { } catch (IOException ioe) { _log.warn("hrm: " + local, ioe); } - } else if (newURL != null) { + } else + *****/ + if (newURL != null) { if (newURL.startsWith("http://")) { _manager.addMessage(_("Fetching {0}", urlify(newURL))); I2PAppThread fetch = new I2PAppThread(new FetchAndAdd(_manager, newURL), "Fetch and add"); @@ -616,6 +630,8 @@ public class I2PSnarkServlet extends Default { if (snark.stopped) snark.startTorrent(); } + } else { + _manager.addMessage("Unknown POST action: \"" + action + '\"'); } } @@ -676,8 +692,9 @@ public class I2PSnarkServlet extends Default { } private static final int MAX_DISPLAYED_FILENAME_LENGTH = 50; - private static final int MAX_DISPLAYED_ERROR_LENGTH = 6; - private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers, boolean showDebug) throws IOException { + private static final int MAX_DISPLAYED_ERROR_LENGTH = 43; + private void displaySnark(PrintWriter out, Snark snark, String uri, int row, long stats[], boolean showPeers, + boolean isDegraded, boolean showDebug) throws IOException { String filename = snark.torrent; File f = new File(filename); filename = f.getName(); // the torrent may be the canonical name, so lets just grab the local name @@ -731,97 +748,69 @@ public class I2PSnarkServlet extends Default { knownPeers = Math.max(curPeers, snark.coordinator.trackerSeenPeers); } - String statusString = _("Unknown"); + String rowClass = (row % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd"); + String statusString; if (err != null) { if (isRunning && curPeers > 0 && !showPeers) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/trackererror.png\" title=\"" + _("Tracker Error") + - "\"><a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + - ' ' + curPeers + " / " + - // ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; - ngettext("1", "{0}", knownPeers) + "</a>"; + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") + + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + + curPeers + thinsp(isDegraded) + + ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; else if (isRunning) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/trackererror.png\" title=\"" + _("Tracker Error") + - "\">" + ' ' + curPeers + " / " + - // ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; - ngettext("1", "{0}", knownPeers) + "</a>"; + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") + + ": " + curPeers + thinsp(isDegraded) + + ngettext("1 peer", "{0} peers", knownPeers); else { if (err.length() > MAX_DISPLAYED_ERROR_LENGTH) err = err.substring(0, MAX_DISPLAYED_ERROR_LENGTH) + "…"; - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/trackererror.png\" title=\"" + _("Tracker Error") + - "\"> " + err + "</a>"; + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "trackererror.png\" title=\"" + err + "\"></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Tracker Error") + + "<br>" + err; } } else if (remaining <= 0) { if (isRunning && curPeers > 0 && !showPeers) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/seeding.png\" title=\"" + _("Seeding") + "\">" + - "<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + - ' ' + curPeers + " / " + - // ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; - ngettext("1", "{0}", knownPeers) + "</a>"; + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") + + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + + curPeers + thinsp(isDegraded) + + ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; else if (isRunning) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/seeding.png\" title=\"" + _("Seeding") + "\">" + - ' ' + curPeers + " / " + - // ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; - ngettext("1", "{0}", knownPeers) + "</a>"; + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "seeding.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Seeding") + + ": " + curPeers + thinsp(isDegraded) + + ngettext("1 peer", "{0} peers", knownPeers); else - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/complete.png\" title=\"" + _("Complete") + "\"> " + _("Complete"); + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "complete.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Complete"); } else { if (isRunning && curPeers > 0 && downBps > 0 && !showPeers) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/downloading.png\" title=\"" + _("Downloading") + "\">" + - "<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + - ' ' + curPeers + " / " + - // ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; - ngettext("1", "{0}", knownPeers) + "</a>"; + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") + + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + + curPeers + thinsp(isDegraded) + + ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; else if (isRunning && curPeers > 0 && downBps > 0) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/downloading.png\" title=\"" + _("Downloading") + "\">" + - ' ' + curPeers + " / " + - ngettext("1", "{0}", knownPeers); - // ngettext("1 peer", "{0} peers", knownPeers); + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "downloading.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("OK") + + ": " + curPeers + thinsp(isDegraded) + + ngettext("1 peer", "{0} peers", knownPeers); else if (isRunning && curPeers > 0 && !showPeers) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stalled.png\" title=\"" + _("Stalled") + "\">" + - "<a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + - ' ' + curPeers + " / " + - // ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; - ngettext("1", "{0}", knownPeers) + "</a>"; + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") + + ": <a href=\"" + uri + "?p=" + Base64.encode(snark.meta.getInfoHash()) + "\">" + + curPeers + thinsp(isDegraded) + + ngettext("1 peer", "{0} peers", knownPeers) + "</a>"; else if (isRunning && curPeers > 0) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stalled.png\" title=\"" + _("Stalled") + "\">" + - ' ' + curPeers + " / " + - // ngettext("1 peer", "{0} peers", knownPeers); - ngettext("1", "{0}", knownPeers); + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stalled.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stalled") + + ": " + curPeers + thinsp(isDegraded) + + ngettext("1 peer", "{0} peers", knownPeers); + else if (isRunning && knownPeers > 0) + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers") + + ": 0 / " + knownPeers ; else if (isRunning) - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/nopeers.png\" title=\"" + _("No Peers") + "\">" + - ' ' + curPeers + " / " + - // ngettext("1 peer", "{0} peers", knownPeers); - ngettext("1", "{0}", knownPeers); + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "nopeers.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("No Peers"); else - statusString = "<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stopped.png\" title=\"" + _("Stopped") + "\"> " + _("Stopped"); + statusString = "<img alt=\"\" border=\"0\" src=\"" + _imgPath + "stopped.png\" ></td><td class=\"snarkTorrentStatus " + rowClass + "\">" + _("Stopped"); } - String rowClass = (row % 2 == 0 ? "snarkTorrentEven" : "snarkTorrentOdd"); out.write("<tr class=\"" + rowClass + "\">"); - out.write("<td align=\"center\" class=\"snarkTorrentStatus " + rowClass + "\">"); + out.write("<td class=\"center " + rowClass + "\">"); out.write(statusString + "</td>\n\t"); - out.write("<td align=\"left\" class=\"snarkTorrentName " + rowClass + "\">"); - - if (remaining == 0 || snark.meta.getFiles() != null) { - out.write("<a href=\"" + snark.storage.getBaseName()); - if (snark.meta.getFiles() != null) - out.write("/"); - out.write("\" title=\""); - if (snark.meta.getFiles() != null) - out.write(_("View files")); - else - out.write(_("Open file")); - out.write("\">"); - } - String icon; - if (snark.meta.getFiles() != null) - icon = "folder"; - else - icon = toIcon(snark.meta.getName()); - out.write(toImg(icon)); - out.write(filename); - if (remaining == 0 || snark.meta.getFiles() != null) - out.write("</a>"); + + out.write("<td class=\"" + rowClass + "\">"); // temporarily hardcoded for postman* and anonymity, requires bytemonsoon patch for lookup by info_hash String announce = snark.meta.getAnnounce(); if (announce.startsWith("http://YRgrgTLG") || announce.startsWith("http://8EoJZIKr") || @@ -839,28 +828,62 @@ public class I2PSnarkServlet extends Default { if (e < 0) continue; baseURL = baseURL.substring(e + 1); - out.write(" <a href=\"" + baseURL + "details.php?dllist=1&filelist=1&info_hash="); + out.write("<a href=\"" + baseURL + "details.php?dllist=1&filelist=1&info_hash="); out.write(TrackerClient.urlencode(snark.meta.getInfoHash())); - out.write("\" title=\"" + name + ' ' + _("Tracker") + "\" target=\"_blank\">"); - out.write("<div class=\"infoz\"><img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/details.png\"></div>"); + out.write("\" title=\"" + _("Details at {0} tracker", name) + "\" target=\"_blank\">"); + out.write("<img alt=\"" + _("Info") + "\" border=\"0\" src=\"" + _imgPath + "details.png\">"); out.write("</a>"); break; } } - out.write("</td>\n\t"); - - out.write("<td align=\"center\" class=\"snarkTorrentETA " + rowClass + "\">"); + + out.write("</td>\n<td class=\"" + rowClass + "\">"); + StringBuilder buf = null; + if (remaining == 0 || snark.meta.getFiles() != null) { + buf = new StringBuilder(128); + buf.append("<a href=\"").append(snark.storage.getBaseName()); + if (snark.meta.getFiles() != null) + buf.append('/'); + buf.append("\" title=\""); + if (snark.meta.getFiles() != null) + buf.append(_("View files")); + else + buf.append(_("Open file")); + buf.append("\">"); + out.write(buf.toString()); + } + String icon; + if (snark.meta.getFiles() != null) + icon = "folder"; + else + icon = toIcon(snark.meta.getName()); + if (remaining == 0 || snark.meta.getFiles() != null) { + out.write(toImg(icon, _("Open"))); + out.write("</a>"); + } else { + out.write(toImg(icon)); + } + out.write("</td><td class=\"snarkTorrentName " + rowClass + "\">"); + if (remaining == 0 || snark.meta.getFiles() != null) + out.write(buf.toString()); + out.write(filename); + if (remaining == 0 || snark.meta.getFiles() != null) + out.write("</a>"); + + out.write("<td align=\"right\" class=\"snarkTorrentETA " + rowClass + "\">"); if(isRunning && remainingSeconds > 0) out.write(DataHelper.formatDuration2(remainingSeconds*1000)); // (eta 6h) out.write("</td>\n\t"); out.write("<td align=\"right\" class=\"snarkTorrentDownloaded " + rowClass + "\">"); if (remaining > 0) - out.write(formatSize(total-remaining) + "/" + formatSize(total)); // 18MB/3GB; remove thin space so line does _not_ break. We don't want a break here. + out.write(formatSize(total-remaining) + thinsp(isDegraded) + formatSize(total)); else out.write(formatSize(total)); // 3GB out.write("</td>\n\t"); - out.write("<td align=\"right\" class=\"snarkTorrentUploaded " + rowClass - + "\">" + formatSize(uploaded) + "</td>\n\t"); + out.write("<td align=\"right\" class=\"snarkTorrentUploaded " + rowClass + "\">"); + if(isRunning) + out.write(formatSize(uploaded)); + out.write("</td>\n\t"); out.write("<td align=\"right\" class=\"snarkTorrentRateDown\">"); if(isRunning && remaining > 0) out.write(formatSize(downBps) + "ps"); @@ -875,27 +898,34 @@ public class I2PSnarkServlet extends Default { if (showPeers) parameters = parameters + "&p=1"; if (isRunning) { - out.write("<input type=\"image\" name=\"action\" value=\"Stop_"); - out.write(b64); - out.write("\" title=\""); + if (isDegraded) + out.write("<a href=\"/i2psnark/?action=Stop_" + b64 + "&nonce=" + _nonce + "\"><img title=\""); + else + out.write("<input type=\"image\" name=\"action\" value=\"Stop_" + b64 + "\" title=\""); out.write(_("Stop the torrent")); - out.write("\" src=\"/themes/snark/" + _manager.getTheme() + "/images/stop.png\" alt=\""); + out.write("\" src=\"" + _imgPath + "stop.png\" alt=\""); out.write(_("Stop")); out.write("\">"); + if (isDegraded) + out.write("</a>"); } else { if (isValid) { - out.write("<input type=\"image\" name=\"action\" value=\"Start_"); - out.write(b64); - out.write("\" title=\""); + if (isDegraded) + out.write("<a href=\"/i2psnark/?action=Start_" + b64 + "&nonce=" + _nonce + "\"><img title=\""); + else + out.write("<input type=\"image\" name=\"action\" value=\"Start_" + b64 + "\" title=\""); out.write(_("Start the torrent")); - out.write("\" src=\"/themes/snark/" + _manager.getTheme() + "/images/start.png\" alt=\""); + out.write("\" src=\"" + _imgPath + "start.png\" alt=\""); out.write(_("Start")); out.write("\">"); + if (isDegraded) + out.write("</a>"); } - out.write("<input type=\"image\" name=\"action\" value=\"Remove_"); - out.write(b64); - out.write("\" title=\""); + if (isDegraded) + out.write("<a href=\"/i2psnark/?action=Remove_" + b64 + "&nonce=" + _nonce + "\"><img title=\""); + else + out.write("<input type=\"image\" name=\"action\" value=\"Remove_" + b64 + "\" title=\""); out.write(_("Remove the torrent from the active list, deleting the .torrent file")); out.write("\" onclick=\"if (!confirm('"); // Can't figure out how to escape double quotes inside the onclick string. @@ -903,13 +933,16 @@ public class I2PSnarkServlet extends Default { // Then the remaining single quite must be escaped out.write(_("Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?", fullFilename)); out.write("')) { return false; }\""); - out.write(" src=\"/themes/snark/" + _manager.getTheme() + "/images/remove.png\" alt=\""); + out.write(" src=\"" + _imgPath + "remove.png\" alt=\""); out.write(_("Remove")); out.write("\">"); + if (isDegraded) + out.write("</a>"); - out.write("<input type=\"image\" name=\"action\" value=\"Delete_"); - out.write(b64); - out.write("\" title=\""); + if (isDegraded) + out.write("<a href=\"/i2psnark/?action=Delete_" + b64 + "&nonce=" + _nonce + "\"><img title=\""); + else + out.write("<input type=\"image\" name=\"action\" value=\"Delete_" + b64 + "\" title=\""); out.write(_("Delete the .torrent file and the associated data file(s)")); out.write("\" onclick=\"if (!confirm('"); // Can't figure out how to escape double quotes inside the onclick string. @@ -917,9 +950,11 @@ public class I2PSnarkServlet extends Default { // Then the remaining single quite must be escaped out.write(_("Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?", fullFilename)); out.write("')) { return false; }\""); - out.write(" src=\"/themes/snark/" + _manager.getTheme() + "/images/delete.png\" alt=\""); + out.write(" src=\"" + _imgPath + "delete.png\" alt=\""); out.write(_("Delete")); out.write("\">"); + if (isDegraded) + out.write("</a>"); } out.write("</td>\n</tr>\n"); @@ -930,10 +965,8 @@ public class I2PSnarkServlet extends Default { for (Peer peer : peers) { if (!peer.isConnected()) continue; - out.write("<tr class=\"" + rowClass + "\">"); - out.write("<td align=\"center\" class=\"snarkTorrentStatus " + rowClass + "\">"); - out.write("</td>\n\t"); - out.write("<td align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">"); + out.write("<tr class=\"" + rowClass + "\"><td></td>"); + out.write("<td colspan=\"4\" align=\"right\" class=\"" + rowClass + "\">"); String ch = peer.toString().substring(0, 4); String client; if ("AwMD".equals(ch)) @@ -1006,11 +1039,18 @@ public class I2PSnarkServlet extends Default { out.write("<td class=\"snarkTorrentStatus " + rowClass + "\">"); out.write("</td></tr>\n\t"); if (showDebug) - out.write("<tr><td colspan=\"8\" align=\"right\" class=\"snarkTorrentStatus " + rowClass + "\">" + peer.getSocket() + "</td></tr>"); + out.write("<tr><td></td><td colspan=\"10\" align=\"right\" class=\"" + rowClass + "\">" + peer.getSocket() + "</td></tr>"); } } } + /** @since 0.8.2 */ + private static String thinsp(boolean disable) { + if (disable) + return " / "; + return (" / "); + } + /** * Sort by completeness (seeds first), then by ID * @since 0.8.1 @@ -1034,9 +1074,9 @@ public class I2PSnarkServlet extends Default { //String newFile = req.getParameter("newFile"); //if ( (newFile == null) || (newFile.trim().length() <= 0) ) newFile = ""; - out.write("<span class=\"snarkNewTorrent\">\n"); + out.write("<div class=\"snarkNewTorrent\">\n"); // *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file - out.write("<form action=\"" + uri + "\" method=\"POST\">\n"); + out.write("<form action=\"_post\" method=\"POST\">\n"); out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n"); out.write("<input type=\"hidden\" name=\"action\" value=\"Add\" >\n"); // don't lose peer setting @@ -1044,7 +1084,7 @@ public class I2PSnarkServlet extends Default { if (peerParam != null) out.write("<input type=\"hidden\" name=\"p\" value=\"" + peerParam + "\" >\n"); out.write("<div class=\"addtorrentsection\"><span class=\"snarkConfigTitle\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/add.png\">"); + out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "add.png\"> "); out.write(_("Add Torrent")); out.write("</span><hr>\n<table border=\"0\"><tr><td>"); out.write(_("From URL")); @@ -1062,7 +1102,7 @@ public class I2PSnarkServlet extends Default { out.write("\n"); out.write(_("Removing a .torrent will cause it to stop.")); out.write("<br></span></table>\n"); - out.write("</form>\n</span></div>"); + out.write("</div></form></div>"); } private void writeSeedForm(PrintWriter out, HttpServletRequest req) throws IOException { @@ -1073,9 +1113,9 @@ public class I2PSnarkServlet extends Default { else baseFile = DataHelper.stripHTML(baseFile); // XSS - out.write("<div class=\"newtorrentsection\"><span class=\"snarkNewTorrent\">\n"); + out.write("<div class=\"newtorrentsection\"><div class=\"snarkNewTorrent\">\n"); // *not* enctype="multipart/form-data", so that the input type=file sends the filename, not the file - out.write("<form action=\"" + uri + "\" method=\"POST\">\n"); + out.write("<form action=\"_post\" method=\"POST\">\n"); out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n"); out.write("<input type=\"hidden\" name=\"action\" value=\"Create\" >\n"); // don't lose peer setting @@ -1083,7 +1123,7 @@ public class I2PSnarkServlet extends Default { if (peerParam != null) out.write("<input type=\"hidden\" name=\"p\" value=\"" + peerParam + "\" >\n"); out.write("<span class=\"snarkConfigTitle\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/create.png\">"); + out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "create.png\"> "); out.write(_("Create Torrent")); out.write("</span><hr>\n<table border=\"0\"><tr><td>"); //out.write("From file: <input type=\"file\" name=\"newFile\" size=\"50\" value=\"" + newFile + "\" /><br>\n"); @@ -1116,7 +1156,7 @@ public class I2PSnarkServlet extends Default { out.write("<input type=\"submit\" value=\""); out.write(_("Create torrent")); out.write("\" name=\"foo\" ></table>\n"); - out.write("</form>\n</span></div>"); + out.write("</form></div></div>"); } private void writeConfigForm(PrintWriter out, HttpServletRequest req) throws IOException { @@ -1127,31 +1167,18 @@ public class I2PSnarkServlet extends Default { String openTrackers = _manager.util().getOpenTrackerString(); //int seedPct = 0; - out.write("<form action=\"" + uri + "\" method=\"POST\">\n"); - out.write("<div class=\"configsectionpanel\"><span class=\"snarkConfig\">\n"); + out.write("<form action=\"/i2psnark/configure\" method=\"POST\">\n"); + out.write("<div class=\"configsectionpanel\"><div class=\"snarkConfig\">\n"); out.write("<input type=\"hidden\" name=\"nonce\" value=\"" + _nonce + "\" >\n"); out.write("<input type=\"hidden\" name=\"action\" value=\"Save\" >\n"); out.write("<span class=\"snarkConfigTitle\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/config.png\">"); + out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "config.png\"> "); out.write(_("Configuration")); out.write("</span><hr>\n"); out.write("<table border=\"0\"><tr><td>"); - out.write(_("Theme")); - out.write(": <td><select name='theme'>"); - String theme = _manager.getTheme(); - String[] themes = _manager.getThemes(); - for(int i = 0; i < themes.length; i++) { - if(themes[i].equals(theme)) - out.write("\n<OPTION value='" + themes[i] + "' SELECTED>" + themes[i]); - else - out.write("\n<OPTION value='" + themes[i] + "'>" + themes[i]); - } - out.write("\n</select>\n<tr><td>"); - - out.write(_("Data directory")); - out.write(": <td><code>" + dataDir + "</code> ("); + out.write(": <td><code>" + dataDir + "</code> <i>("); out.write(_("Edit i2psnark.config and restart to change")); out.write(")</i><br>\n"); @@ -1163,6 +1190,19 @@ public class I2PSnarkServlet extends Default { out.write(_("If checked, automatically start torrents that are added")); out.write("\" >"); + out.write("<tr><td>"); + out.write(_("Theme")); + out.write(": <td><select name='theme'>"); + String theme = _manager.getTheme(); + String[] themes = _manager.getThemes(); + for(int i = 0; i < themes.length; i++) { + if(themes[i].equals(theme)) + out.write("\n<OPTION value=\"" + themes[i] + "\" SELECTED>" + themes[i]); + else + out.write("\n<OPTION value=\"" + themes[i] + "\">" + themes[i]); + } + out.write("</select>\n"); + out.write("<tr><td>"); out.write(_("Startup delay")); out.write(": <td><input name=\"startupDelay\" size=\"3\" class=\"r\" value=\"" + _manager.util().getStartupDelay() + "\"> "); @@ -1263,14 +1303,13 @@ public class I2PSnarkServlet extends Default { out.write("<tr><td> <td><input type=\"submit\" value=\""); out.write(_("Save configuration")); out.write("\" name=\"foo\" >\n"); - out.write("</table></span>\n"); - out.write("</form></div>"); + out.write("</table></div></div></form>"); } private void writeConfigLink(PrintWriter out) throws IOException { out.write("<div class=\"configsection\"><span class=\"snarkConfig\">\n"); out.write("<span class=\"snarkConfigTitle\"><a href=\"configure\">"); - out.write("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/config.png\">"); + out.write("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "config.png\"> "); out.write(_("Configuration")); out.write("</a></span></span></div>\n"); } @@ -1346,15 +1385,16 @@ public class I2PSnarkServlet extends Default { return buf.toString(); } - private static final String HEADER_A = "<link href=\"/themes/snark/"; - private static final String HEADER_B = "/snark.css\" rel=\"stylesheet\" type=\"text/css\" >"; + private static final String DOCTYPE = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n"; + private static final String HEADER_A = "<link href=\""; + private static final String HEADER_B = "snark.css\" rel=\"stylesheet\" type=\"text/css\" >"; - private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\" cellpadding=\"0 10px\">\n" + + private static final String TABLE_HEADER = "<table border=\"0\" class=\"snarkTorrents\" width=\"100%\" >\n" + "<thead>\n" + - "<tr><th align=\"center\">"; + "<tr><th colspan=\"2\">"; - private static final String FOOTER = "</div></div></div></center></body></html>"; + private static final String FOOTER = "</div></center></body></html>"; /** * Modded heavily from the Jetty version in Resource.java, @@ -1398,7 +1438,7 @@ public class I2PSnarkServlet extends Default { Arrays.sort(ls, Collator.getInstance()); StringBuilder buf=new StringBuilder(4096); - buf.append("<HTML><HEAD><TITLE>"); + buf.append(DOCTYPE + "<HTML><HEAD><TITLE>"); String title = URI.decodePath(base); if (title.startsWith("/i2psnark/")) title = title.substring("/i2psnark/".length()); @@ -1419,36 +1459,32 @@ public class I2PSnarkServlet extends Default { title = title.substring(0, title.length() - 1); title = _("Torrent") + ": " + title; buf.append(title); - buf.append("</TITLE>").append(HEADER_A).append(_manager.getTheme()).append(HEADER_B).append("<link rel=\"shortcut icon\" href=\"/themes/snark/" + _manager.getTheme() + "/favicon.ico\"></HEAD><BODY>\n<center><div class=\"snarknavbar\"> <a href=\"/i2psnark/\" title=\"Torrents\""); - buf.append(" class=\"snarkRefresh\"><img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/arrow_refresh.png\"> I2PSnark</a>").append("</div>"); + buf.append("</TITLE>").append(HEADER_A).append(_themePath).append(HEADER_B).append("<link rel=\"shortcut icon\" href=\"" + _themePath + "favicon.ico\">" + + "</HEAD><BODY>\n<center><div class=\"snarknavbar\"><a href=\"/i2psnark/\" title=\"Torrents\""); + buf.append(" class=\"snarkRefresh\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "arrow_refresh.png\"> I2PSnark</a></div></center>\n"); - if (parent) - buf.append("</div><div class=\"page\"><div class=\"mainsection\">"); - boolean showPriority = snark != null && !snark.storage.complete(); + if (parent) // always true + buf.append("<div class=\"page\"><div class=\"mainsection\">"); + boolean showPriority = snark != null && !snark.storage.complete(); if (showPriority) buf.append("<form action=\"").append(base).append("\" method=\"POST\">\n"); - buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" cellpadding=\"5px 10px\">" + + buf.append("<TABLE BORDER=0 class=\"snarkTorrents\" >" + "<thead><tr><th>") - .append("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/file.png\" title=\"") - .append(_("File")).append("\" alt=\"").append(_("File")).append("\"> ") + .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "file.png\" > ") .append(title).append("</th><th align=\"right\">") - .append("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/size.png\" title=\"") -// .append(_("FileSize")).append("\" alt=\"").append(_("FileSize")).append("\">").append(_("Size")); - .append(_("FileSize")).append("\" alt=\"").append(_("FileSize")).append("\">"); - buf.append("</th><th class=\"headerstatus\">") - .append("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/status.png\" title=\"") -// .append(_("Download Status")).append("\">").append(_("Status")).append("</th>"); - .append(_("Download Status")).append("\">").append("</th>"); + .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "size.png\" > ") + .append(_("Size")); + buf.append("</th><th class=\"headerstatus\">") + .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "status.png\" > ") + .append(_("Status")).append("</th>"); if (showPriority) buf.append("<th class=\"headerpriority\">") - .append("<img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/priority.png\" title=\"") - .append(_("Priority")).append("\">").append("</th>"); -// .append(_("Priority")).append("</th>"); -// .append("</th>"); - buf.append("</tr></thead>\n"); - buf.append("<tr><td colspan=\"4\" class=\"ParentDir\"><A HREF=\""); - buf.append(URI.addPaths(base,"../")); - buf.append("\"><img border=\"0\" src=\"/themes/snark/" + _manager.getTheme() + "/images/up.png\"> ") + .append("<img alt=\"\" border=\"0\" src=\"" + _imgPath + "priority.png\" > ") + .append(_("Priority")).append("</th>"); + buf.append("</tr></thead>\n"); + buf.append("<tr><td colspan=\"" + (showPriority ? '4' : '3') + "\" class=\"ParentDir\"><A HREF=\""); + buf.append(URI.addPaths(base,"../")); + buf.append("\"><img alt=\"\" border=\"0\" src=\"" + _imgPath + "up.png\"> ") .append(_("Up to higher level directory")).append("</A></td></tr>\n"); @@ -1474,12 +1510,12 @@ public class I2PSnarkServlet extends Default { long length = item.length(); if (item.isDirectory()) { complete = true; - status = toImg("tick") + _("Directory"); + status = toImg("tick") + ' ' + _("Directory"); } else { if (snark == null) { // Assume complete, perhaps he removed a completed torrent but kept a bookmark complete = true; - status = toImg("cancel") + _("Torrent not found?"); + status = toImg("cancel") + ' ' + _("Torrent not found?"); } else { try { File f = item.getFile(); @@ -1487,10 +1523,10 @@ public class I2PSnarkServlet extends Default { long remaining = snark.storage.remaining(f.getCanonicalPath()); if (remaining < 0) { complete = true; - status = toImg("cancel") + _("File not found in torrent?"); + status = toImg("cancel") + ' ' + _("File not found in torrent?"); } else if (remaining == 0 || length <= 0) { complete = true; - status = toImg("tick") + _("Complete"); + status = toImg("tick") + ' ' + _("Complete"); } else { int priority = snark.storage.getPriority(f.getCanonicalPath()); if (priority < 0) @@ -1499,7 +1535,7 @@ public class I2PSnarkServlet extends Default { status = toImg("clock"); else status = toImg("clock_red"); - status += + status += " " + (100 * (length - remaining) / length) + "% " + _("complete") + " (" + DataHelper.formatSize2(remaining) + _("bytes remaining") + ")"; } @@ -1526,13 +1562,13 @@ public class I2PSnarkServlet extends Default { buf.append("<img alt=\"\" border=\"0\" class=\"thumb\" src=\"") .append(path).append("\"></a> "); } else { - buf.append(toImg(icon)); + buf.append(toImg(icon, _("Open"))).append("</a> "); } buf.append("<A HREF=\""); buf.append(path); buf.append("\">"); } else { - buf.append(toImg(icon)); + buf.append(toImg(icon)).append(' '); } buf.append(ls[i]); if (complete) @@ -1640,7 +1676,12 @@ public class I2PSnarkServlet extends Default { /** @since 0.7.14 */ private static String toImg(String icon) { - return "<img alt=\"\" height=\"16\" width=\"16\" src=\"/i2psnark/_icons/" + icon + ".png\"> "; + return "<img alt=\"\" height=\"16\" width=\"16\" src=\"/i2psnark/_icons/" + icon + ".png\">"; + } + + /** @since 0.8.2 */ + private static String toImg(String icon, String altText) { + return "<img alt=\"" + altText + "\" height=\"16\" width=\"16\" src=\"/i2psnark/_icons/" + icon + ".png\">"; } /** @since 0.8.1 */ @@ -1702,8 +1743,13 @@ private static class FetchAndAdd implements Runnable { else _manager.addMessage(_("Torrent already in the queue: {0}", name)); } else { - FileUtil.copy(file.getAbsolutePath(), canonical, true); - _manager.addTorrent(canonical); + boolean success = FileUtil.copy(file.getAbsolutePath(), canonical, false); + if (success) { + SecureFileOutputStream.setPerms(torrentFile); + _manager.addTorrent(canonical); + } else { + _manager.addMessage(_("Failed to copy torrent file to {0}", canonical)); + } } } catch (IOException ioe) { _manager.addMessage(_("Torrent at {0} was not valid", urlify(_url)) + ": " + ioe.getMessage()); diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java index bc7e4ab9056a0425a43d6611bec3f824268ed338..921d8992bf731d3cba65673e0b0d7f1fc3822e97 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPServer.java @@ -15,6 +15,7 @@ import java.util.Properties; import java.util.zip.GZIPOutputStream; import net.i2p.client.streaming.I2PSocket; +import net.i2p.I2PAppContext; import net.i2p.data.DataHelper; import net.i2p.util.EventDispatcher; import net.i2p.util.I2PAppThread; @@ -36,6 +37,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { private static final String HASH_HEADER = "X-I2P-DestHash"; private static final String DEST64_HEADER = "X-I2P-DestB64"; private static final String DEST32_HEADER = "X-I2P-DestB32"; + private static final String[] CLIENT_SKIPHEADERS = {HASH_HEADER, DEST64_HEADER, DEST32_HEADER}; + private static final String SERVER_HEADER = "Server"; + private static final String[] SERVER_SKIPHEADERS = {SERVER_HEADER}; public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) { super(host, port, privData, l, notifyThis, tunnel); @@ -75,7 +79,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { InputStream in = socket.getInputStream(); StringBuilder command = new StringBuilder(128); - Properties headers = readHeaders(in, command); + Properties headers = readHeaders(in, command, + CLIENT_SKIPHEADERS, getTunnel().getContext()); headers.setProperty(HASH_HEADER, socket.getPeerDestination().calculateHash().toBase64()); headers.setProperty(DEST32_HEADER, Base32.encode(socket.getPeerDestination().calculateHash().getData()) + ".b32.i2p" ); headers.setProperty(DEST64_HEADER, socket.getPeerDestination().toBase64()); @@ -118,7 +123,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { useGZIP = true; if (allowGZIP && useGZIP) { - I2PAppThread req = new I2PAppThread(new CompressedRequestor(s, socket, modifiedHeader), Thread.currentThread().getName()+".hc"); + I2PAppThread req = new I2PAppThread( + new CompressedRequestor(s, socket, modifiedHeader, getTunnel().getContext()), + Thread.currentThread().getName()+".hc"); req.start(); } else { new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null); @@ -155,10 +162,12 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { private Socket _webserver; private I2PSocket _browser; private String _headers; - public CompressedRequestor(Socket webserver, I2PSocket browser, String headers) { + private I2PAppContext _ctx; + public CompressedRequestor(Socket webserver, I2PSocket browser, String headers, I2PAppContext ctx) { _webserver = webserver; _browser = browser; _headers = headers; + _ctx = ctx; } public void run() { if (_log.shouldLog(Log.INFO)) @@ -200,8 +209,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { //Change headers to protect server identity StringBuilder command = new StringBuilder(128); - Properties headers = readHeaders(serverin, command); - headers.setProperty("Server", "I2PServer"); + Properties headers = readHeaders(serverin, command, + SERVER_SKIPHEADERS, _ctx); String modifiedHeaders = formatHeaders(headers, command); compressedOut.write(modifiedHeaders.getBytes()); @@ -336,7 +345,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { /** ridiculously long, just to prevent OOM DOS @since 0.7.13 */ private static final int MAX_HEADERS = 60; - private static Properties readHeaders(InputStream in, StringBuilder command) throws IOException { + private static Properties readHeaders(InputStream in, StringBuilder command, String[] skipHeaders, I2PAppContext ctx) throws IOException { Properties headers = new Properties(); StringBuilder buf = new StringBuilder(128); @@ -356,8 +365,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { } } } - //if (trimmed > 0) - // getTunnel().getContext().statManager().addRateData("i2ptunnel.httpNullWorkaround", trimmed, 0); + if (trimmed > 0) + ctx.statManager().addRateData("i2ptunnel.httpNullWorkaround", trimmed, 0); int i = 0; while (true) { @@ -379,16 +388,24 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer { value = buf.substring(split+1).trim(); // ":" else value = ""; + if ("Accept-encoding".equalsIgnoreCase(name)) name = "Accept-encoding"; else if ("X-Accept-encoding".equalsIgnoreCase(name)) name = "X-Accept-encoding"; - else if (HASH_HEADER.equalsIgnoreCase(name)) - continue; // Prevent spoofing - else if (DEST64_HEADER.equalsIgnoreCase(name)) - continue; // Prevent spoofing - else if (DEST32_HEADER.equalsIgnoreCase(name)) - continue; // Prevent spoofing + + //We want to remove certain headers to improve anonymity + boolean skip = false; + for (String skipHeader: skipHeaders) { + if (skipHeader.equalsIgnoreCase(name)) { + skip = true; + break; + } + } + if(skip) { + continue; + } + headers.setProperty(name, value); if (_log.shouldLog(Log.DEBUG)) _log.debug("Read the header [" + name + "] = [" + value + "]"); diff --git a/build.xml b/build.xml index 5d1567ea97f3c1bb5025497ad0a51862bd03ca91..7c75e857aeaa5d2e1dbe523463552a89bcafff2a 100644 --- a/build.xml +++ b/build.xml @@ -23,9 +23,10 @@ <echo message=" dist: pkg and javadoc" /> <echo message=" installer: build the GUI installer" /> <echo message=" tarball: tar the full install into i2p.tar.bz2 (extracts to build a new clean install)" /> - <echo message=" updater: tar the built i2p specific files into an i2pupdate.zip (extracts safely over existing installs)" /> + <echo message=" updater: Package the built files in i2pupdate.zip (extracts safely over existing installs)" /> + <echo message=" updater200: Updater compressed with pack200 (creates i2pupdate200.zip, 60% smaller)" /> <echo message=" updaterWithJavadoc: updater including the javadocs, for display in the console" /> - <echo message=" updaterWithJetty: tar the built i2p specific files and jetty into an i2pupdate.zip (extracts safely over existing installs)" /> + <echo message=" updaterWithJetty: Updater including Jetty" /> <echo message=" updaterWithJettyFixes: updater including local jetty patches" /> <echo message=" updaterWithGeoIP: updater including GeoIP Files" /> <echo message=" updaterWithJettyFixesAndGeoIP" /> @@ -199,7 +200,8 @@ <copy file="installer/lib/jbigi/jbigi.jar" todir="build" /> <copy file="apps/addressbook/dist/addressbook.war" todir="build/" /> </target> - <target name="poupdate"> + <!-- the apps need to compile the jsps to poupdate --> + <target name="poupdate" depends="buildRouter, buildStreaming, buildSystray, buildJetty" > <ant dir="apps/routerconsole/java/" target="poupdate" /> <ant dir="apps/i2psnark/java/" target="poupdate" /> <ant dir="apps/i2ptunnel/java/" target="poupdate" /> diff --git a/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java b/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java index 7309a849b3933ccd97eb1d825b1b7931c9d6094e..28d211fa557720eb4f165d8970711bdb4c804591 100644 --- a/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java +++ b/core/java/src/net/i2p/client/I2PSessionDemultiplexer.java @@ -38,8 +38,13 @@ public class I2PSessionDemultiplexer implements I2PSessionMuxedListener { l.messageAvailable(session, msgId, size, proto, fromport, toport); else { // no listener, throw it out - _log.error("No listener found for proto: " + proto + " port: " + toport + "msg id: " + msgId + - " from pool of " + _listeners.size() + " listeners"); + if (_listeners.isEmpty()) { + if (_log.shouldLog(Log.WARN)) + _log.warn("No listeners for incoming message"); + } else { + _log.error("No listener found for proto: " + proto + " port: " + toport + " msg id: " + msgId + + " from pool of " + _listeners.size() + " listeners"); + } try { session.receiveMessage(msgId); } catch (I2PSessionException ise) {} diff --git a/core/java/src/net/i2p/crypto/TrustedUpdate.java b/core/java/src/net/i2p/crypto/TrustedUpdate.java index 11f267712f88cc0ba15c3c288c83960d2a4bdd13..fdf63697dfbdfc1b2ccc620faff132e778e9a1d0 100644 --- a/core/java/src/net/i2p/crypto/TrustedUpdate.java +++ b/core/java/src/net/i2p/crypto/TrustedUpdate.java @@ -176,23 +176,30 @@ JXQAnA28vDmMMMH/WPbC5ixmJeGGNUiR /** * Duplicate keys or names rejected, * except that duplicate empty names are allowed + * @param key 172 character base64 string + * @param name non-null but "" ok * @since 0.7.12 * @return true if successful */ public boolean addKey(String key, String name) { + String oldName = _trustedKeys.get(key); + // already there? + if (name.equals(oldName)) + return true; + if (oldName != null && !oldName.equals("")) { + _log.error("Key for " + name + " already stored for different name " + oldName + " : " + key); + return false; + } SigningPublicKey signingPublicKey = new SigningPublicKey(); try { - // fromBase64() won't reject a string that is too long - if (key.length() != KEYSIZE_B64_BYTES) - throw new DataFormatException("x"); + // fromBase64() will throw a DFE if length is not right signingPublicKey.fromBase64(key); } catch (DataFormatException dfe) { - _log.error("Bad signing key for " + name + " : " + key); + _log.error("Invalid signing key for " + name + " : " + key, dfe); return false; } - if (_trustedKeys.containsKey(signingPublicKey) || - ((!name.equals("")) && _trustedKeys.containsValue(name))) { - _log.error("Duplicate signing key for " + name + " : " + key); + if ((!name.equals("")) && _trustedKeys.containsValue(name)) { + _log.error("Key mismatch for " + name + ", spoof attempt? : " + key); return false; } _trustedKeys.put(signingPublicKey, name); diff --git a/core/java/src/net/i2p/util/LogRecordFormatter.java b/core/java/src/net/i2p/util/LogRecordFormatter.java index 84a1cb6b8cf7a5acbec2e786d4e687de67525047..52583b63c393290f4da98836635d731219d4cefc 100644 --- a/core/java/src/net/i2p/util/LogRecordFormatter.java +++ b/core/java/src/net/i2p/util/LogRecordFormatter.java @@ -29,6 +29,14 @@ class LogRecordFormatter { private final static int MAX_PRIORITY_LENGTH = 5; public static String formatRecord(LogManager manager, LogRecord rec) { + return formatRecord(manager, rec, true); + } + + /** + * @param showDate if false, skip any date in the format (use when writing to wrapper log) + * @since 0.8.2 + */ + static String formatRecord(LogManager manager, LogRecord rec, boolean showDate) { int size = 128 + rec.getMessage().length(); if (rec.getThrowable() != null) size += 512; @@ -37,7 +45,10 @@ class LogRecordFormatter { for (int i = 0; i < format.length; ++i) { switch (format[i]) { case LogManager.DATE: - buf.append(getWhen(manager, rec)); + if (showDate) + buf.append(getWhen(manager, rec)); + else if (i+1 < format.length && format[i+1] == ' ') + i++; // skip following space break; case LogManager.CLASS: buf.append(getWhere(rec)); diff --git a/core/java/src/net/i2p/util/LogWriter.java b/core/java/src/net/i2p/util/LogWriter.java index f68249ba7a759822047413460eb524faf5d0e60c..51108e18b8841207d06d0f9f1d76654df5f212c2 100644 --- a/core/java/src/net/i2p/util/LogWriter.java +++ b/core/java/src/net/i2p/util/LogWriter.java @@ -17,8 +17,6 @@ import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Queue; -import net.i2p.I2PAppContext; - /** * Log writer thread that pulls log records from the LogManager, writes them to * the current logfile, and rotates the logs as necessary. This also periodically @@ -112,7 +110,7 @@ class LogWriter implements Runnable { } private void writeRecord(LogRecord rec) { - String val = LogRecordFormatter.formatRecord(_manager, rec); + String val = LogRecordFormatter.formatRecord(_manager, rec, true); writeRecord(val); // we always add to the console buffer, but only sometimes write to stdout @@ -121,7 +119,11 @@ class LogWriter implements Runnable { _manager.getBuffer().addCritical(val); if (_manager.getDisplayOnScreenLevel() <= rec.getPriority()) { if (_manager.displayOnScreen()) { - System.out.print(val); + // wrapper log already does time stamps, so reformat without the date + if (System.getProperty("wrapper.version") != null) + System.out.print(LogRecordFormatter.formatRecord(_manager, rec, false)); + else + System.out.print(val); } } } @@ -199,7 +201,7 @@ class LogWriter implements Runnable { File f = new File(pattern); File base = null; if (!f.isAbsolute()) - base = I2PAppContext.getGlobalContext().getLogDir(); + base = _manager.getContext().getLogDir(); if ( (pattern.indexOf('#') < 0) && (pattern.indexOf('@') <= 0) ) { if (base != null) diff --git a/history.txt b/history.txt index a31619ba8d2999a325210ad4c23e1389103d3c15..9450ccca9545576173c2aa4107121d480699b719 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,29 @@ +2010-12-11 zzz + * Build: Fix 'ant distclean poupdate' again + * I2CP: Change a log error to a warning (ticket #353) + * i2psnark: + - Restore text (ticket #273) + - Fix several HTML errors (ticket #273) + - Fix HTML error causing info links to be unclickable in dillo (tiicket #273) + - Fix alt text duplicated or looking bad in text browsers (ticket #273) + - Fix Opera button errors (ticket #332) + - Fix POST resubmission errors (ticket #334) + - Catch FetchAndAdd copy error (ticket #352) + - Set permissions on downloaded torrent files + - Hide some columns when not running + - Lots of spacing cleanups + - Rename images so users don't end up with unused files + - Remove ~15 unused images + - Clean up theme selection speed-coding exercise + - Indent fixes + * Log: Don't double-timestamp CRITS in wrapper.log + * News: XML fixes (ticket #350) + * Plugins: Better handling of signing keys (Ticket #351) + * TunnelPoolManager: Fix rare startup NPE (http://forum.i2p/viewtopic.php?t=5192) + +2010-12-10 Mathiasdm + * I2PTunnel: Fixed up security fix. + 2010-12-07 Mathiasdm * I2PTunnel: Security fix: change server reply to return 'I2PServer' instead of the actual servername. diff --git a/installer/resources/checklist.txt b/installer/resources/checklist.txt index 2527d69cdec2bc320cbb2b93cfaca8cb1a551554..da8b54386f4004be5a0441da27caf49d9bc96a06 100644 --- a/installer/resources/checklist.txt +++ b/installer/resources/checklist.txt @@ -8,7 +8,6 @@ Deploy the Jetty archive, a clean checkout lacks it Change revision in: history.txt - installer/resources/initialNews.xml installer/install.xml installer/resources/news.xml router/java/src/net/i2p/router/RouterVersion.java @@ -21,7 +20,7 @@ Review the complete diff from the last release: Verify that no untrusted revisions were inadvertently blessed by a trusted party: - mtn log --brief --no-graph --to t:i2p-0.7.(xx-1) | cut -d ' ' -f 2- | sort + mtn log --brief --no-graph --to t:i2p-0.8.(xx-1) | cut -d ' ' -f 2 | sort | uniq -c NOTE: Most tasks below here are now automated by 'ant release' diff --git a/installer/resources/initialNews/initialNews.xml b/installer/resources/initialNews/initialNews.xml index d69d6c644a6a6f1cedd43b2eab61bf82b9cd6dfb..49f8a012a5bd73fd1b023cd5c170c86be5bcf025 100644 --- a/installer/resources/initialNews/initialNews.xml +++ b/installer/resources/initialNews/initialNews.xml @@ -1,5 +1,5 @@ <div lang="en"> -<h4><ul><li>Congratulations on getting I2P installed!</li></ul></h4> +<h3>Congratulations on getting I2P installed!</h3> <p> <b>Welcome to I2P!</b> Please <b>have patience</b> as I2P boots up and finds peers. diff --git a/installer/resources/initialNews/initialNews_de.xml b/installer/resources/initialNews/initialNews_de.xml index 38b037fc50a465d6f8e61961c2605a83665a2ea2..6b48359c2645e0b08e052c9e4dc9da0687e24c5e 100644 --- a/installer/resources/initialNews/initialNews_de.xml +++ b/installer/resources/initialNews/initialNews_de.xml @@ -1,5 +1,5 @@ <div lang="de"> -<h4><ul><li>Wir gratulieren zur erfolgreichen Installation von I2P!</li></ul></h4> +<h3>Wir gratulieren zur erfolgreichen Installation von I2P!</h3> <p> <b>Willkommen im I2P!</b> Hab noch <b>etwas Geduld</b>, während I2P startet und weitere I2P-Router findet. diff --git a/installer/resources/initialNews/initialNews_es.xml b/installer/resources/initialNews/initialNews_es.xml index eca5e4918781a71ad4ec30a44ef7aabcdec6e8d2..7fca2669ebc2074bb4506c2240af51dcf7ca6f50 100644 --- a/installer/resources/initialNews/initialNews_es.xml +++ b/installer/resources/initialNews/initialNews_es.xml @@ -1,5 +1,5 @@ <div lang="es"> -<h4><ul><li>¡Felicidades!, has instalado el enrutador I2P con éxito.</li></ul></h4> +<h3>¡Felicidades!, has instalado el enrutador I2P con éxito.</h3> <p> <b>¡Bienvenido a I2P!</b><br> ¡Ten todavía <b>paciencia</b> mientras I2P esté arrancando y encontrando otros enrutadores I2P! diff --git a/installer/resources/initialNews/initialNews_nl.xml b/installer/resources/initialNews/initialNews_nl.xml index a968236d580570ebd10838b7c61a5e145b2dc44b..b888fb2966c47ec0ba6472d3904e88aa1a283695 100644 --- a/installer/resources/initialNews/initialNews_nl.xml +++ b/installer/resources/initialNews/initialNews_nl.xml @@ -1,5 +1,5 @@ <div lang="nl"> -<h4><ul><li>Gefeliciteerd met de installatie van I2P!</li></ul></h4> +<h3>Gefeliciteerd met de installatie van I2P!</h3> <p> <b>Welkom bij I2P!</b> Heb <b>wat geduld</b> terwijl I2P opstart en peers zoekt. diff --git a/installer/resources/initialNews/initialNews_pt.xml b/installer/resources/initialNews/initialNews_pt.xml index 2fe0ea2561611eab456cc9e6958f1fe6a83d1f80..76b553e2dbbd3e76f7e36165eca8400971044523 100644 --- a/installer/resources/initialNews/initialNews_pt.xml +++ b/installer/resources/initialNews/initialNews_pt.xml @@ -1,5 +1,5 @@ <div lang="pt"> -<h4><ul><li>Parabéns, você instalou o roteador I2P com êxito!</li></ul></h4> +<h3>Parabéns, você instalou o roteador I2P com êxito!</h3> <p> <b>Bem-vindo ao I2P!</b><br> Seja <b>paciente</b> enquanto I2P ainda está iniciando-se e enquanto continuam sendo encontrados outros roteadores I2P! diff --git a/installer/resources/initialNews/initialNews_ru.xml b/installer/resources/initialNews/initialNews_ru.xml index 93eb2fd7a87a67f36f0d77e3d44ceae412f7b74e..f82df2c7f730fbfd7ea90bbf4f5d10291d08c8e4 100644 --- a/installer/resources/initialNews/initialNews_ru.xml +++ b/installer/resources/initialNews/initialNews_ru.xml @@ -1,5 +1,5 @@ <div lang="ru"> -<h4><ul><li>ПоздравлÑем Ñ ÑƒÑпешным завершением уÑтановки I2P!</li></ul></h4> +<h3>ПоздравлÑем Ñ ÑƒÑпешным завершением уÑтановки I2P!</h3> <p> <b>Добро пожаловать в I2P!</b> Ðемного терпениÑ! I2P-маршрутизатору потребуетÑÑ Ð¿Ð°Ñ€Ð° минут Ð´Ð»Ñ Ð·Ð°Ð¿ÑƒÑка модулей и первого Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ðº Ñети I2P. </p> diff --git a/installer/resources/news.xml b/installer/resources/news.xml index 91cdd52a97fc906b2811260be2c199d3f0fb2732..ae6b780c0191064a1b6e6013304c5bebe847dce0 100644 --- a/installer/resources/news.xml +++ b/installer/resources/news.xml @@ -3,7 +3,7 @@ <i2p.release version="0.8.1" date="2010/11/15" minVersion="0.6" /> --> <div lang="en"> -<h4><ul><li>2010-11-15: <b>0.8.1 <a href="http://www.i2p2.i2p/release-0.8.1.html">Released</a></b></li></ul></h4> +<h3>2010-11-15: <b>0.8.1 <a href="http://www.i2p2.i2p/release-0.8.1.html">Released</a></b></h3> <p> The 0.8.1 release contains the usual collection of bug fixes, and a newly colorful i2psnark theme by dr|zed. diff --git a/installer/resources/themes/snark/ubergine/images/details_nolink.png b/installer/resources/themes/snark/ubergine/images/details_nolink.png deleted file mode 100644 index 79fd2b72a774a6e7999829dd9ea83b03603c3529..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/ubergine/images/details_nolink.png and /dev/null differ diff --git a/installer/resources/themes/snark/ubergine/images/eta.png b/installer/resources/themes/snark/ubergine/images/eta.png index f4c3f99d90440da920da4cce9ad8b5a21e0bdc59..197bbdd01ee9928724cd54d8a17db42399473f6e 100644 Binary files a/installer/resources/themes/snark/ubergine/images/eta.png and b/installer/resources/themes/snark/ubergine/images/eta.png differ diff --git a/installer/resources/themes/snark/ubergine/images/head_eta.png b/installer/resources/themes/snark/ubergine/images/head_eta.png deleted file mode 100644 index 197bbdd01ee9928724cd54d8a17db42399473f6e..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/ubergine/images/head_eta.png and /dev/null differ diff --git a/installer/resources/themes/snark/ubergine/images/head_loaded.png b/installer/resources/themes/snark/ubergine/images/head_loaded.png deleted file mode 100644 index 91f92b39b809bf0e54ac669f8148f62975643849..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/ubergine/images/head_loaded.png and /dev/null differ diff --git a/installer/resources/themes/snark/ubergine/images/head_peers.png b/installer/resources/themes/snark/ubergine/images/head_peers.png deleted file mode 100644 index 3fc97172f0dd3ba572e4fcbaf4f91e549271bb27..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/ubergine/images/head_peers.png and /dev/null differ diff --git a/installer/resources/themes/snark/ubergine/images/head_snarks.png b/installer/resources/themes/snark/ubergine/images/head_snarks.png deleted file mode 100644 index 9aac1c2ce94fcd922f9e929f21d96f994deae5ed..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/ubergine/images/head_snarks.png and /dev/null differ diff --git a/installer/resources/themes/snark/ubergine/images/head_torrent.png b/installer/resources/themes/snark/ubergine/images/head_torrent.png deleted file mode 100644 index d2a0d59d1101899649162fdea985da262d629115..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/ubergine/images/head_torrent.png and /dev/null differ diff --git a/installer/resources/themes/snark/ubergine/images/snark_thead.png b/installer/resources/themes/snark/ubergine/images/snark_thead.png deleted file mode 100644 index ead40efeac7cebfaf0fed362aadc323c1d61a528..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/ubergine/images/snark_thead.png and /dev/null differ diff --git a/installer/resources/themes/snark/ubergine/images/torrent.png b/installer/resources/themes/snark/ubergine/images/torrent.png index 5894d66cbff96a62c4c14136975c28dd6d2dcbcc..d2a0d59d1101899649162fdea985da262d629115 100644 Binary files a/installer/resources/themes/snark/ubergine/images/torrent.png and b/installer/resources/themes/snark/ubergine/images/torrent.png differ diff --git a/installer/resources/themes/snark/ubergine/snark.css b/installer/resources/themes/snark/ubergine/snark.css index 7d4ef2c333da6ca3999438d7ea9994231ebca432..95b529f1957c4080c390e0a9e499a934fb5063e7 100644 --- a/installer/resources/themes/snark/ubergine/snark.css +++ b/installer/resources/themes/snark/ubergine/snark.css @@ -155,7 +155,6 @@ th { border-bottom: 1px inset #101; color: #ddd; whitespace: nowrap; - font-variant: small-caps !important; letter-spacing: 0.05em; } @@ -238,6 +237,10 @@ td:first-child { font-size: 9.5pt; } +.center { + text-align: center !important; +} + .snarkTorrentName { text-shadow:1px 1px #550000; padding: 2px 0 0; @@ -268,7 +271,6 @@ td:first-child { } .snarkTorrentEven { - background: #545; font-size: 8pt; background: #202; } @@ -323,7 +325,6 @@ td:first-child { } .snarkTorrentOdd { - background: #656; background: #351933; font-size: 8pt; border: 0px inset #101 !important; diff --git a/installer/resources/themes/snark/vanilla/images/eta.png b/installer/resources/themes/snark/vanilla/images/eta.png index f4c3f99d90440da920da4cce9ad8b5a21e0bdc59..8eba678b7022fb00bab64e6537155eb80e56cda4 100644 Binary files a/installer/resources/themes/snark/vanilla/images/eta.png and b/installer/resources/themes/snark/vanilla/images/eta.png differ diff --git a/installer/resources/themes/snark/vanilla/images/head_eta.png b/installer/resources/themes/snark/vanilla/images/head_eta.png deleted file mode 100644 index 8eba678b7022fb00bab64e6537155eb80e56cda4..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/vanilla/images/head_eta.png and /dev/null differ diff --git a/installer/resources/themes/snark/vanilla/images/head_loaded.png b/installer/resources/themes/snark/vanilla/images/head_loaded.png deleted file mode 100644 index 46fc281ffe61828f29cadfdb6613eac975f6d1e4..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/vanilla/images/head_loaded.png and /dev/null differ diff --git a/installer/resources/themes/snark/vanilla/images/head_peers.png b/installer/resources/themes/snark/vanilla/images/head_peers.png deleted file mode 100644 index 8d1918acb6a4bfa80fc7aab84dd724bdb84da2e5..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/vanilla/images/head_peers.png and /dev/null differ diff --git a/installer/resources/themes/snark/vanilla/images/head_snarks.png b/installer/resources/themes/snark/vanilla/images/head_snarks.png deleted file mode 100644 index 10d909e25f48d9364b951862d6a7718df2a023e6..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/vanilla/images/head_snarks.png and /dev/null differ diff --git a/installer/resources/themes/snark/vanilla/images/head_torrent.png b/installer/resources/themes/snark/vanilla/images/head_torrent.png deleted file mode 100644 index c0ec7d2b0434894ba28ea9436098cb391569bb5c..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/vanilla/images/head_torrent.png and /dev/null differ diff --git a/installer/resources/themes/snark/vanilla/images/link.png b/installer/resources/themes/snark/vanilla/images/link.png deleted file mode 100644 index 25eacb7c2524142262d68bf729c5e2b61adfd6d4..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/vanilla/images/link.png and /dev/null differ diff --git a/installer/resources/themes/snark/vanilla/images/snark_thead.png b/installer/resources/themes/snark/vanilla/images/snark_thead.png deleted file mode 100644 index a0ecfb1a78e338cc1d0bc72f0850054809fabb59..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/vanilla/images/snark_thead.png and /dev/null differ diff --git a/installer/resources/themes/snark/vanilla/images/tile3.png b/installer/resources/themes/snark/vanilla/images/tile3.png deleted file mode 100644 index 43aa314de17776c283b2d8d48b5c88beb75f1b68..0000000000000000000000000000000000000000 Binary files a/installer/resources/themes/snark/vanilla/images/tile3.png and /dev/null differ diff --git a/installer/resources/themes/snark/vanilla/images/torrent.png b/installer/resources/themes/snark/vanilla/images/torrent.png index 5894d66cbff96a62c4c14136975c28dd6d2dcbcc..c0ec7d2b0434894ba28ea9436098cb391569bb5c 100644 Binary files a/installer/resources/themes/snark/vanilla/images/torrent.png and b/installer/resources/themes/snark/vanilla/images/torrent.png differ diff --git a/installer/resources/themes/snark/vanilla/snark.css b/installer/resources/themes/snark/vanilla/snark.css index 7ddfb7a7a9c4d4d270bad2e05f5702b891d146ec..8d31ca99136eb8fef9de3ed9e706a0640ee96596 100644 --- a/installer/resources/themes/snark/vanilla/snark.css +++ b/installer/resources/themes/snark/vanilla/snark.css @@ -139,7 +139,6 @@ tr { } thead, tfoot { - text-shadow: 0px 1px 1px #707; background: url("images/bling2.png") repeat-x scroll center center #867; font-weight: bold; color: #503; @@ -161,7 +160,6 @@ th { border-top: 1px outset #604; border-bottom: 1px inset #604; whitespace: nowrap; - font-variant: small-caps !important; letter-spacing: 0.05em; } @@ -244,6 +242,10 @@ td:first-child { font-size: 9.5pt; } +.center { + text-align: center !important; +} + .snarkTorrentName { /* text-shadow:1px 1px #540;*/ padding: 3px 0 0; @@ -270,7 +272,6 @@ td:first-child { } .snarkTorrentEven { - background: #fef; font-size: 8pt; background: #feb; } @@ -328,7 +329,6 @@ td:first-child { } .snarkTorrentOdd { - background: #656; background: #fed; font-size: 8pt; border: 0px inset #fff !important; @@ -490,7 +490,6 @@ input { input.r { text-align: right; - background: /*url('/themes/snark/ubergine/images/graytile.png')*/; } input[type=submit] { @@ -524,7 +523,7 @@ input[type=image] { border-radius: 0px; border: medium none; margin: 0 2px; - opacity: 0.9 !important; + opacity: 0.8 !important; } input[type=image]:hover { @@ -561,7 +560,7 @@ select:hover, textarea:hover { } textarea { - background: #fff; /*/*url('/themes/snark/ubergine/images/graytile.png')*/;*/ + background: #fff; /*url('/themes/snark/ubergine/images/graytile.png');*/ color: #f60; font-weight: bold; padding: 1px 4px 0px; diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java index d246679f34bde1d6b755a37b66b7bb5a91743fb3..3a53be55268765cad58df32105b17e70ac0e0dc0 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPoolManager.java @@ -131,10 +131,14 @@ public class TunnelPoolManager implements TunnelManagerFacade { if (info != null) return info; } - info = _inboundExploratory.getTunnel(id); - if (info != null) return info; - info = _outboundExploratory.getTunnel(id); - if (info != null) return info; + if (_inboundExploratory != null) { + info = _inboundExploratory.getTunnel(id); + if (info != null) return info; + } + if (_outboundExploratory != null) { + info = _outboundExploratory.getTunnel(id); + if (info != null) return info; + } return null; }