From 2ca8fc6e62d6ee33b232086accdcdc41dba03b7d Mon Sep 17 00:00:00 2001 From: zzz Date: Sat, 11 Dec 2010 13:57:14 +0000 Subject: [PATCH] * 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 --- .../src/org/klomp/snark/SnarkManager.java | 20 +- .../org/klomp/snark/web/I2PSnarkServlet.java | 574 ++++++++++-------- history.txt | 22 + .../snark/ubergine/images/details_nolink.png | Bin 805 -> 0 bytes .../themes/snark/ubergine/images/eta.png | Bin 561 -> 1304 bytes .../themes/snark/ubergine/images/head_eta.png | Bin 1304 -> 0 bytes .../snark/ubergine/images/head_loaded.png | Bin 867 -> 0 bytes .../snark/ubergine/images/head_peers.png | Bin 1022 -> 0 bytes .../snark/ubergine/images/head_snarks.png | Bin 854 -> 0 bytes .../snark/ubergine/images/head_torrent.png | Bin 2753 -> 0 bytes .../snark/ubergine/images/snark_thead.png | Bin 121 -> 0 bytes .../themes/snark/ubergine/images/torrent.png | Bin 543 -> 2753 bytes .../resources/themes/snark/ubergine/snark.css | 7 +- .../themes/snark/vanilla/images/eta.png | Bin 561 -> 1522 bytes .../themes/snark/vanilla/images/head_eta.png | Bin 1522 -> 0 bytes .../snark/vanilla/images/head_loaded.png | Bin 877 -> 0 bytes .../snark/vanilla/images/head_peers.png | Bin 1014 -> 0 bytes .../snark/vanilla/images/head_snarks.png | Bin 833 -> 0 bytes .../snark/vanilla/images/head_torrent.png | Bin 2871 -> 0 bytes .../themes/snark/vanilla/images/link.png | Bin 343 -> 0 bytes .../snark/vanilla/images/snark_thead.png | Bin 182 -> 0 bytes .../themes/snark/vanilla/images/tile3.png | Bin 175 -> 0 bytes .../themes/snark/vanilla/images/torrent.png | Bin 543 -> 2871 bytes .../resources/themes/snark/vanilla/snark.css | 13 +- .../src/net/i2p/router/RouterVersion.java | 2 +- 25 files changed, 352 insertions(+), 286 deletions(-) delete mode 100644 installer/resources/themes/snark/ubergine/images/details_nolink.png delete mode 100644 installer/resources/themes/snark/ubergine/images/head_eta.png delete mode 100644 installer/resources/themes/snark/ubergine/images/head_loaded.png delete mode 100644 installer/resources/themes/snark/ubergine/images/head_peers.png delete mode 100644 installer/resources/themes/snark/ubergine/images/head_snarks.png delete mode 100644 installer/resources/themes/snark/ubergine/images/head_torrent.png delete mode 100644 installer/resources/themes/snark/ubergine/images/snark_thead.png delete mode 100644 installer/resources/themes/snark/vanilla/images/head_eta.png delete mode 100644 installer/resources/themes/snark/vanilla/images/head_loaded.png delete mode 100644 installer/resources/themes/snark/vanilla/images/head_peers.png delete mode 100644 installer/resources/themes/snark/vanilla/images/head_snarks.png delete mode 100644 installer/resources/themes/snark/vanilla/images/head_torrent.png delete mode 100644 installer/resources/themes/snark/vanilla/images/link.png delete mode 100644 installer/resources/themes/snark/vanilla/images/snark_thead.png delete mode 100644 installer/resources/themes/snark/vanilla/images/tile3.png diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 52f82fee2e..82d1d80f4f 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 81e84c3b90..dddb296f4d 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("\n" + - "\n" + + out.write(DOCTYPE + "\n" + + "\n" + ""); 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(_("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_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("</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("").append(HEADER_A).append(_manager.getTheme()).append(HEADER_B).append("\n
I2PSnark").append("
"); + buf.append("").append(HEADER_A).append(_themePath).append(HEADER_B).append("" + + "\n
\n"); - if (parent) - buf.append("
"); - boolean showPriority = snark != null && !snark.storage.complete(); + if (parent) // always true + buf.append("
"); + boolean showPriority = snark != null && !snark.storage.complete(); if (showPriority) buf.append("
\n"); - buf.append("" + + buf.append("
" + ""); - .append(_("Download Status")).append("\">").append(""); + .append("\"\" ") + .append(_("Size")); + buf.append(""); if (showPriority) buf.append(""); -// .append(_("Priority")).append(""); -// .append(""); - buf.append("\n"); - buf.append("\n"); + buf.append("\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("\"\" "); } else { - buf.append(toImg(icon)); + buf.append(toImg(icon, _("Open"))).append(" "); } 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 "\"\" "; + return "\"\""; + } + + /** @since 0.8.2 */ + private static String toImg(String icon, String altText) { + return "\"""; } /** @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/history.txt b/history.txt index 50b82c381e..71882dc1a3 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,25 @@ +2010-12-11 zzz + * Build: Fix 'ant distclean poupdate' again + * 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 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 GIT binary patch literal 0 HcmV?d00001 literal 805 zcmV+=1KRwFP)pH*GWV{RCt`NRL^S@K@|RWX4`B@n>4izt&L5gjjd2jp%f7m1$!zA zB6ul+H+vEB-g@-p(WBtOU$^`T;-P{d3awaZm8LO?wQXX4G`}}HJIF2wRg# zmg1<}bqFC~`79g`l+QE}$HT>Yiy?yyPpP9=v2*r>QTfqekZrp{y3!2Ud^DzC= zFbthUmBxb+%m(K*v)H#cIJ6HmQ<7RLl{BcD?YSW_)I&Yd0Q8b7P#~Q*_P?lSOP)~7 z$X}^cP%IXa%jGoNR#TZICV%pWd3d}Ym}cwR5Swas4}uAOuDkXzKsKAz1t|s&QU^Gw znF{G=Vk=Rx0+zR{t4sHVCO|<_x*DWXDI=4~XaE8txln4PkgusGR~II4=FL&= j+sf9Ie?5iN-szlwIgpFiDmO!N00000NkvXXu0mjfODB0= diff --git a/installer/resources/themes/snark/ubergine/images/eta.png b/installer/resources/themes/snark/ubergine/images/eta.png index f4c3f99d90440da920da4cce9ad8b5a21e0bdc59..197bbdd01ee9928724cd54d8a17db42399473f6e 100644 GIT binary patch delta 1299 zcmV+u1?>8<1egjTiBL{Q4GJ0x0000DNk~Le0000Y0000P2nGNE095+?tdSuXe+0@& zL_t(|oV8YMY?D zUx0|WkO?o!Xz=9@JCd3^0hb$?ngU!L04C^x!Ym*+6+=}2iES71aZFhS&s_r|D)BgH z_WjlcgBd{HBw+0Wz@lsw&<=v%sZ`KofB!{3USf4dE&)Zfzz=wpD+K@_%?lSEmww2yDUq~FzGFX4e#u~!@H z5f8Su_rb9Hq&5gCY5wy~BVnz!(0LbWx|f_Poy$(V0a(467UDt`Yqwx#nqA#8Fr@Q) zLpr>y`Uuc{O&f$1=@BW}$>DWwUZY=-{fb-}$DB<=YanU!Km(ite|n+UT~UVu9?7|SB7;a~*v|6j5SdS&o6UT{ z>T-iuHONDpV;(8qOCW5msU0wy7-Ek;q`g^ZFT972V)Ylof6aAIaik~Uk&CGb&`4D` zMS3h}J2~(284f31jJma73e+1c(52l&=1vJ#7;*yNHsaNTZZw=jIY*Ak;ea134`=&W zA4#Nn#Rx;j@MbptI)V%K2|K4 z0;lXds}!*?3o`G{jd%){ZX*|WwQhtU$HoPM1yLM-e?bK?z=N&#Z~X*ILN~K97ka>kg3QXMAZr zoao82qUk_QiCT;JhQl_*V~4Uyt#0E7qJpUcs|Meod<_mT?05dcNbK-sP#M1RJtFJQ zG6E=HX#h-~s4hEA-@JXufvRmO@3os6lprPjCJRxEq>)3w2RZm9? z;Eq841@tyjc|Jamk;|6J6)g0y5uA-c&l5l!-awzCXjYXm%Rm3w+I^l0;sO8w002ov JPDHLkV1kTqW_ADo delta 550 zcmV+>0@?kT3b6zsiBL{Q4GJ0x0000DNk~Le0000C0000C2nGNE09JKe=aC^7e*xo3 zL_t(|oLx~(YZFlvJ@Yb|3GFzcn1)bFg)R&fyD4ln|&pm+k{v z|3Qg%Q-e?n#TKQlO(lkiqj56%n2$^oXXcG}G!^l{ecX3A@7{CY6)?tjaa+vZ%;r1w z&fWf(-lFrviP?tp-fWs>ZC`s{e?-xbbV790Ue;2gEN*_ZoT#!9U zk&<@H-g6CorHH475LH%_>h4M9WT9TIxBZd-m}<-m5Hcac9WfqzBCGPW-q8==VSkBn zhvyq_8&^M9>pCCtTnVKO23!&lPDeTS!rZVw)FnvQ6exMtYxM4a|M1Q9e@1?Rd>Z4C z(jkPYD2ccr;Ds1s)(~g+MC+@$V7G0~z&6i6fFsP%aB&jfpsPz!3Bf%VXO~5*W&Pwn z=_B133_>adl0-eCP7MxTrVs{jnAmOhPGv<}Bx04c8-Hw+=J5~Ku(s;J7In0bm$qx6VC!Tdh5taDLcjIwdn+a07*qoM6N<$f(Oj~jsO4v 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 GIT binary patch literal 0 HcmV?d00001 literal 1304 zcmV+z1?T#SP)X1^@s6RQmj^00009a7bBm000id z000id0mpBsWB>pJ%1J~)RCt`VR&8vPRTO^SZrxa2*w&SO2pb)NZ3;68@-b0}0T&FS z*`fqOVj?pm1YKf`AqK>4PECkH2r(-DaLOD+gZRPJI9Y%JQwO%&OoZ`e*jI<^U~HwV zYkPg}+g2!jTh@suxq07v@45Fp_uS{4bAc#DR3J9mHDeKF42Dh6VI~9~qjny@)A=3X z_bjKI`ENx!I+XPo{a=8Hw~z@h%4qQA4m*;XI{}v)n3@7y8~`Thfx;{xHx)xv|A}oE z@^MUA1@&!0D<6C5Ae5x)>Z&7)dMLBz=Ih;-Xvh{1Hhte70?cX z->Fp4WB)~jfFi0;=Bb3cdMU)b$@B+;TT^N1SV0EFmL(8e=M`_Fj@N09)^;%Qs!-$w zJ}mzpO05+b90^uVi~|bNLpN!+0T<|l-XSQvpT?Sv^)OSfAR`fpT1K62j5c4wcOHQ? z?7D)0sGRWNtLnp0YAk@m6}o|u*O4>3USyA7n&-_r`{V}Q;<6t9*;el7NR~zgR54N`V!La+JHV7$c{_{;EVXd~%c^7HAmz*k{%TBxjSiPAR;zAW` zw_s+PUEMM;r1N`2I=rm<2+(~^8-x_;5h>Zp;dO3ar=-s?+mJ?chpbb9km-e&9nc;9 zE4%?ICWG&rlcGJZV+_v8WF(nx1)|kFFmkUYX1r(6GZz8(#`?iOTSu4Lh9d)!9vR_b z@=e5mLTiaFVL&g>-Z`52j% zVoA~&GnnxbAQT6;jtNzq%1oF*?$~;v*IiME0v^e^dgIPOmQLgTT(Q^;y#FLKEcdWq z2m0B1dHC%ofRg)1F)x>_UA`EK?z#{8?efSR;G_iumOoMYH6)UE0)BJF=putiX4ua1 z=Mb4so}0~l!0K{?S2f5(oMRp--b)~Ct*IR_niyh_KBT=_XD_^mj$-u}!p(J0aik~U zk&CGb&`4D`MS3h}J2~(284f31jJma73e+1c(52l&=1vJ#7;*yNHsaNTZZw=jIY*Ak z;ea134`=&WA4#NR*3vbq182-#?Tgy*ICG` z(70hfRxFqTr|dhc6tOT1GVjifcnX$oBNunIZiFDm#sz`}Q5=6k1u?*bt@m&J1WQ6U zvvIflACpT(HRf{@$L|{;vXY_$k)8&`L)C|>|fo~SN6P2aqW416}8hjjSIa|PcDI14+M 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 GIT binary patch literal 0 HcmV?d00001 literal 867 zcmV-p1DyPcP)pI6-h)vRCt_ylxt`dR}{y8_s(P!V$g`e^^uCEqD7++qmY33h$$ka zAXO2y4{eR4R6n#8gqCWge)5BU5Q_9e5o0OV6dx#s)+epeYSUD!ltz-OSWL&lY zW1;O49qo^JU0z$Vf<(c%IbYLyegpX2qBL-_4`1j%lW{AT3NuN6mGAWV6rGiKr za-#18?k9>fASIETRE=stE5?K_e@NV1fpxiq5ZAbz>WvVM4Jzp$&~$qR8K8*;HdV1Z zh0vQrw9s%u;wyCOt3!=8l&)B*9h3GD_v3g^ybKHCLHfI+SofAr3YnLRAN*167k5?A zw%AaapLY0OoPmBX!va4ITIgAtmKpYT<6+q7imXB}VD=9uEiE+=anc~q3q^sSky;Q> zq}K0OL!S)7tb^ozypg#{X{m~eQe4q@u45Lb+RJ5A9)TIi0A09KLR05^teW1)?4nx) zgE=LaM4sTncNKdYVbLo$m^rG2p57p9YO$UK718UIM{l$K7(}n)W}pYl<#%paKmLto?HTDv7_g=C zS0dqKy#9e98yo3n)4VGjx^CE2B1%3}yx%POTN;tD2=FF;-j^#YZ$14=nY^OtOWi)egQJI%_fpMKbb#`VQl3tF=D*p{04g z<<-%OUs@+HV?rmD4bc9hL+xYBo}Y|y4gctn1yY`e&mY>Ngv(*sQ1!FL?l^!t{Wi&S z#nMAix<#=~TRSO+3N=Ta1nW~ZCi^vl-N_q$xqNc&CJVnji{nTEwl9L}*YIU-&g2K| tR@=ESJSHn>n8N=rHiuq9I$w0LJq3ArYezq@4H^Id002ovPDHLkV1hsEn7aS~ 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 GIT binary patch literal 0 HcmV?d00001 literal 1022 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 Hu0mjftc5nn 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 GIT binary patch literal 0 HcmV?d00001 literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^%s?#5!2~29OmhTrI14-?iy0XB4ude`@%$AjKtXL! z7srr_ImuJRCZ#bjPpkj`&oT1<|G(`U{~eCxF%au=F`VS!>}<=k0E QfZ7;5UHx3vIVCg!01BEU6aWAK diff --git a/installer/resources/themes/snark/ubergine/images/torrent.png b/installer/resources/themes/snark/ubergine/images/torrent.png index 5894d66cbff96a62c4c14136975c28dd6d2dcbcc..d2a0d59d1101899649162fdea985da262d629115 100644 GIT binary patch literal 2753 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 Hu0mjftc5nn delta 532 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 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 GIT binary patch literal 0 HcmV?d00001 literal 1522 zcmVX1^@s6RQmj^00009a7bBm000id z000id0mpBsWB>pKq)9|URCt`tmw9YdMI6V!@9oj;wYxpH?b1q{mX-pRwj6DmU?LH) z9D<_82nDgCVq+szh;pbAY$z2dBC%S+9cTbKS}YiY5Tis3ln`hD>19vcZI`lTukL%# z-z-O_`8_5QH?I z!YSt<;|yw?w*~@8l|eR(04C7SG;-a5F8$jWCy}xolvV~P$+>uvk1e#0&X-YVKFFKn2CHBDOXyH+SaEA$wa1xBrhNpig=l% zP0Y3;Yl0G!o(o4xLa2+h>_B9<&na2w#~Y71(rEZ9&U?$+k$7cu{Xdc;S+ z25p!YmETnQRG{ow8FF%SVhN^={g&T_NT$boaz9DKlvuKGn8)DWUeTqBCsQhTZ2vYD z+m8jJuBH)jW73iP*>bmjLcbH0iweZFf*rx-IbGvev&&21^aui2Ot)}tcLh>LCt>d5xxZ7@aXG1B zV2x(8?<8ag zYJ$y*Yghxf1YN*}=({DA%Uzv|t@61|85PR>1@fv8@ z1$DlwL5`n(>GnOzBigb>%Q1cabSWh*5uLj?!C~k`Z|!MxpE!W5Nmk&4z&aa2%oqs4?EZphAY(Y?N~OdLqsGs)Vsmkd&&2fv@#b4sVQCCuNAD}= zaPBaxr*q=P_NMj<8GT_z#YN>4M2)BTfgeWW>9LPshQ??2p{zI&`e@al5C@MMP+ZbM zmr*E#SV|D<8N(yL#Xt~dq)Z|m``^))p2&rok&z=q{+wux%}_to&t?~~V{a#p9lwdj zIyqEgfQ=M=oxaYh9v8wR2(xTt``clkLIbnRPPonYAvl7Lbvn}hR2pIA4x<(RCt_)lx;{;Q5?pfdv|rqY3W+!d>a^9KJ!Td6-wa*6P3M z4{A8SVF{YfH~ke-Us4a7(FM;}eeC|rXZeyiM8K$G;+h6{~e z^j|rGpKnIM1N>Q7;@-4#?wV#SqI-w$|}* zDjJqYpb2?#bjwj_Cumhc9M35=M(r1@E7Rld^Hi{~N<2%h=lh5TFQ#q5u^JEho<7Hc z^#>3a!?e7~(8;IQPbggnSG2iIao>Med z>{RLS=EKUjp4A4TzFV|u$tGGjapCLHnTm8pjsm`b-t@j9y0eWAEy$t5ghJ}>=pF^N zx3trIem=F>vWV{OC+3p^WqpmKAl8volvL!e$g7|qfdEC%FQ%HTSyXH+R^TqDi)=|Y zs>{uz_~lX>_6o!+Fm^>Of*?G|o{=paxx5Q0H&&pkITe$q=Og$n zh?su>ZM(zxyyy~kR39YoJ8wi3#RV+Y?ms}X=3;JvPN(aNMPq4It7f8j;&s%W%T>O$ zZs^BN|59{xzLHOMFcOZG{DzDJ$;wB5vR=?PYIWMWIi|tvTKgd6AIj;wCOq?I^o4`r z6M9MC>V$LTk65S%=GO|Ru)vyl@KOYk4{o@J)oOnNQ8ZlEfQ>i-00000NkvXXu0mjf DKt`%0 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 GIT binary patch literal 0 HcmV?d00001 literal 1014 zcmVpIs7XXYRCt_?RBdciRTzHmN83wTyKWTdy0x2bY>h>v+X~rmCZGh9 z{qXz8{DTT1CMr&iM8ii2k&uxrgM^Uy!z>1afJTi888V_FGdS3W0!|iT;j8Tm-3D8~ zd)s?>&)r%k#DtSPIq!R(d!GA#oO1*`H0n|RiU{#N23AAv-!yle$N4_aHK3uMrX7Uk zw0@nw`)Uw_hvx1V<~ogN++vV(9UrU>qRf`T<=}jD_c=7igjb0kCy`&*gbZMJVbg!SHYY*uaJPh^8d`G-&7MIjY|;#||#U z#BGDlWmN&c_gE1L8K#LlRmju_pOZq~M>Y?80YPbNx`X#$2;!r|)i^h5)uYP?Q0-0P z%TxcN=i5?re(cIeH$mtpvt4k zh@$g#z9a&pCQ5fElT2E~H(iU-f7043lfQV8HG?X93W{+i5J_Ov5Wuw{4c>xcXBH>{ z+$Cw9Hz^t%t_)OlroL)g(0v+Zf*<~7s=gOUvUHk$zrLn#SF@VTc;GE`o@x zKw5>AiU@KkvMO-rUp z)KcT{sBSJ+T$;nr-F7&uGH7X?Du`B~;z$UgSU$S#o2u&A-OprptKG!bS9th!V@F#T zvU{J)?8c`GyES5Bu}O*T`=p$6xz{~j7QSv|lVdV_cTFv$cVKVfVAHjW-Al;05}t=` z-#>v%0rMGJ+t_u&h2wvfVk#yfaMgr^JDfPw=@=)j@!E*;^@bJ?!Z(dD&C}>Kuvx8{ z2+cGdCOl6cA5S8=aTvofy7cYj^XICBUkIlIjF5#K>;TgbdfHEunNvjIHD k5WVmk|BqaSRhGH_eJy}&M8o>z8~^|S07*qoM6N<$f>EyFXaE2J 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 GIT binary patch literal 0 HcmV?d00001 literal 833 zcmV-H1HSx;P)pH^GQTORCt`NlwXKcRUF4Z=iGbeuQSZ3ySgK*hAT;$WQn_*i=_rxT zPDr(>Yt@8|NEcsAw7UiA?n3&j(RdUi=Ws;Aeozy z=CblFM5PnEwgVBGX7##h);4EQ)?u=RJB&{K%0i_SfYP!+No8VnRd&531Mrohi|Q^c z14yke^74UWv~BD}shUye&^y#B0WOpC`R;i8s36M_7_; z`7f}xMTsO6)Fxbp#(t!106|Ir@F#%y=FoC?VA+a;FTI9z9DZxQLdS=1Qma%b&(D+2 zWJvAHFz`+v`SI}p)QF%PN((I2%9{0I+BUZ{!ZmjH9OXuDFCTSv@xk7`e0t&pEnBzp zN>2}dkfR?{;>V@XaWWfP@KlB93n^xElUz7;irJZ&AmQfa%jAz7VLF>N4*E|*v>!Ho zmBeBR%C!X&8=A-t4^t`@gUbyM?hXz<+CN@SP1HNDDOctR*)ddA5lyAQvX%jjH{chu@FN`obcaKG{WZsCx z!r|**zNP>Eorizz*(W>6~n`u6^Q)<3=I4U$RKhL<$@|Z00000 LNkvXXu0mjf!atE^ 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 GIT binary patch literal 0 HcmV?d00001 literal 2871 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 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 GIT binary patch literal 0 HcmV?d00001 literal 182 zcmeAS@N?(olHy`uVBq!ia0vp^%s{-1g9%7Zn7wE#km4-xh%9Dc;5!V$jK}j=qyPmo zJY5_^D&{1=@j98xz^uk5A(7g<$u08828pvGQxtW?)Rz5U@-j8?i2iAhMSOpjC0ssz zs3DU*Y%j}|hsE-Y@kxe~CvBAOy059%{0#K&1cx 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 GIT binary patch literal 0 HcmV?d00001 literal 175 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1SJ0&Eu0OcI14-?iy0XB4ude`@%$AjK*2;$ z7srr_Idd<1^ED_4umq}{P**g(^Iu2KOE^(NaF6rXf4RHNa+f<6hl+UZwwiK~MWd8s z%4JK9+EW32&zp)KX>AnIaE;eED;41Odf}U(g)#S>cB=n+n`1sDK0Dx8jloam8(a!+ UHJHBt1X{-6>FVdQ&MBb@07JGr?f?J) diff --git a/installer/resources/themes/snark/vanilla/images/torrent.png b/installer/resources/themes/snark/vanilla/images/torrent.png index 5894d66cbff96a62c4c14136975c28dd6d2dcbcc..c0ec7d2b0434894ba28ea9436098cb391569bb5c 100644 GIT binary patch literal 2871 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
") - .append("\"").append(_("File")).append("\" ") + .append("\"\" ") .append(title).append("") - .append("\"").append(_("FileSize")).append("\"").append(_("Size")); - .append(_("FileSize")).append("\" alt=\"").append(_("FileSize")).append("\">"); - buf.append("") - .append("").append(_("Status")).append("") + .append("\"\" ") + .append(_("Status")).append("") - .append("").append("
") + .append("\"\" ") + .append(_("Priority")).append(""); + buf.append("
\"\" ") .append(_("Up to higher level directory")).append("