diff --git a/apps/addressbook/java/src/addressbook/AddressBook.java b/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java similarity index 99% rename from apps/addressbook/java/src/addressbook/AddressBook.java rename to apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java index d90bf0f1380c06600db6eb9b3a2bf150cbba672b..6249cadaa0c59fb8014099337a2f3aa0162fe64f 100644 --- a/apps/addressbook/java/src/addressbook/AddressBook.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; import java.io.File; import java.io.IOException; diff --git a/apps/addressbook/java/src/addressbook/ConfigParser.java b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java similarity index 99% rename from apps/addressbook/java/src/addressbook/ConfigParser.java rename to apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java index 7fbb214f08b977b05ef11dc82d10f1c11df00297..be74de990f2c65fd3d61ae5afbc042c0f1509598 100644 --- a/apps/addressbook/java/src/addressbook/ConfigParser.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; import java.io.BufferedReader; import java.io.BufferedWriter; diff --git a/apps/addressbook/java/src/addressbook/Daemon.java b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java similarity index 99% rename from apps/addressbook/java/src/addressbook/Daemon.java rename to apps/addressbook/java/src/net/i2p/addressbook/Daemon.java index a8a9a2da6ed54e1ac9b43155857a6c7ba7d178fa..34b550df67140765d9ea7ab0fd1580f1b592e1ac 100644 --- a/apps/addressbook/java/src/addressbook/Daemon.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; import java.io.File; import java.util.HashMap; diff --git a/apps/addressbook/java/src/addressbook/DaemonThread.java b/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java similarity index 98% rename from apps/addressbook/java/src/addressbook/DaemonThread.java rename to apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java index fb869d80713276ad12943d4c6c18ef394205ad82..b5afaaa2f5d6b680032e2c5c118ef0f73f4dbb9a 100644 --- a/apps/addressbook/java/src/addressbook/DaemonThread.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; /** * A thread that waits five minutes, then runs the addressbook daemon. diff --git a/apps/addressbook/java/src/addressbook/Log.java b/apps/addressbook/java/src/net/i2p/addressbook/Log.java similarity index 98% rename from apps/addressbook/java/src/addressbook/Log.java rename to apps/addressbook/java/src/net/i2p/addressbook/Log.java index f608b20e2302b127f440aaaec28cbb946dd6bf53..a1ba1a2fcb9996bf5ef2a12e92b7e175a8424c01 100644 --- a/apps/addressbook/java/src/addressbook/Log.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Log.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; import java.io.BufferedWriter; import java.io.File; diff --git a/apps/addressbook/java/src/addressbook/Servlet.java b/apps/addressbook/java/src/net/i2p/addressbook/Servlet.java similarity index 98% rename from apps/addressbook/java/src/addressbook/Servlet.java rename to apps/addressbook/java/src/net/i2p/addressbook/Servlet.java index 34af69c1ce657eff17985538aba3c8e8bf867a2f..8f26788e4ee58733fdb30e0cbf94691580bce747 100644 --- a/apps/addressbook/java/src/addressbook/Servlet.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Servlet.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; import javax.servlet.GenericServlet; import javax.servlet.ServletConfig; diff --git a/apps/addressbook/java/src/addressbook/Subscription.java b/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java similarity index 99% rename from apps/addressbook/java/src/addressbook/Subscription.java rename to apps/addressbook/java/src/net/i2p/addressbook/Subscription.java index 1847535a965ce4aaa2235d5073873666f435584f..a97635b1285c15ca5f22223badccbf2946ad9191 100644 --- a/apps/addressbook/java/src/addressbook/Subscription.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; /** * A subscription to a remote address book. diff --git a/apps/addressbook/java/src/addressbook/SubscriptionIterator.java b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java similarity index 98% rename from apps/addressbook/java/src/addressbook/SubscriptionIterator.java rename to apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java index 2c3e13b738574046230b076fac17d7dee38a6917..b033181e0011d04f7ead63677ef180c2c63c9b83 100644 --- a/apps/addressbook/java/src/addressbook/SubscriptionIterator.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; import java.util.Iterator; import java.util.List; diff --git a/apps/addressbook/java/src/addressbook/SubscriptionList.java b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java similarity index 99% rename from apps/addressbook/java/src/addressbook/SubscriptionList.java rename to apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java index 77597eef6f0531aedc5172a1526fd8ce233b8212..ac5d3236dcad7f69699a6795e075e5f9f96575e3 100644 --- a/apps/addressbook/java/src/addressbook/SubscriptionList.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -package addressbook; +package net.i2p.addressbook; import java.io.File; import java.io.IOException; diff --git a/apps/addressbook/web.xml b/apps/addressbook/web.xml index 22d0d7d23a13894066c17cd075e429cb498fda11..0c3548c68d4d8dd47f62bb632c96986bd61dd032 100644 --- a/apps/addressbook/web.xml +++ b/apps/addressbook/web.xml @@ -6,11 +6,11 @@ <web-app> <servlet> <servlet-name>addressbook</servlet-name> - <servlet-class>addressbook.Servlet</servlet-class> + <servlet-class>net.i2p.addressbook.Servlet</servlet-class> <init-param> <param-name>home</param-name> <param-value>./addressbook</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> -</web-app> \ No newline at end of file +</web-app> diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 00f9d52be609afe02cca3175b3d2952749c69dc9..d83b5406060208eec3c97fa58aef3f5f3b56c58d 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -714,7 +714,6 @@ public class SnarkManager implements Snark.CompleteListener { "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/" - , "ThePirateBay", "http://tracker.thepiratebay.i2p/announce=http://thepiratebay.i2p/" }; /** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */ 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 01fc3df97b3a804de833d681f539ac21a0556f58..a4ac23b433a2756f398603a2c92cacc294ee8871 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java +++ b/apps/i2psnark/java/src/org/klomp/snark/web/I2PSnarkServlet.java @@ -505,7 +505,6 @@ public class I2PSnarkServlet extends HttpServlet { // 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") || - announce.startsWith("http://4svjpPox") || announce.startsWith("http://tracker.thepiratebay.i2p/") || announce.startsWith("http://lnQ6yoBT") || announce.startsWith("http://tracker2.postman.i2p/")) { Map trackers = _manager.getTrackers(); for (Iterator iter = trackers.entrySet().iterator(); iter.hasNext(); ) { @@ -513,8 +512,7 @@ public class I2PSnarkServlet extends HttpServlet { String name = (String)entry.getKey(); String baseURL = (String)entry.getValue(); if (!(baseURL.startsWith(announce) || // vvv hack for non-b64 announce in list vvv - (announce.startsWith("http://lnQ6yoBT") && baseURL.startsWith("http://tracker2.postman.i2p/")) || - (announce.startsWith("http://4svjpPox") && baseURL.startsWith("http://thepiratebay.i2p/")))) + (announce.startsWith("http://lnQ6yoBT") && baseURL.startsWith("http://tracker2.postman.i2p/")))) continue; int e = baseURL.indexOf('='); if (e < 0) diff --git a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java index 1916b415acf46af15744fb4cf0cbac8bc3d343ad..b729b659bab6e7ce7bcb196b06b0a14a24078f46 100644 --- a/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java +++ b/apps/i2ptunnel/java/src/net/i2p/i2ptunnel/I2PTunnelHTTPClient.java @@ -3,8 +3,10 @@ */ package net.i2p.i2ptunnel; +import java.io.ByteArrayOutputStream; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -15,6 +17,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Properties; import java.util.StringTokenizer; @@ -55,6 +58,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable private HashMap addressHelpers = new HashMap(); + /** + * These are backups if the xxx.ht error page is missing. + */ + private final static byte[] ERR_REQUEST_DENIED = ("HTTP/1.1 403 Access Denied\r\n"+ "Content-Type: text/html; charset=iso-8859-1\r\n"+ @@ -77,6 +84,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable "Could not find the following Destination:<BR><BR><div>") .getBytes(); +/***** private final static byte[] ERR_TIMEOUT = ("HTTP/1.1 504 Gateway Timeout\r\n"+ "Content-Type: text/html; charset=iso-8859-1\r\n"+ @@ -88,6 +96,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable "destination may have issues. Could not get a response from "+ "the following Destination:<BR><BR>") .getBytes(); +*****/ private final static byte[] ERR_NO_OUTPROXY = ("HTTP/1.1 503 Service Unavailable\r\n"+ @@ -108,11 +117,11 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable "The addresshelper link you followed specifies a different destination key "+ "than a host entry in your host database. "+ "Someone could be trying to impersonate another eepsite, "+ - "or people have given two eepsites identical names.<P/>"+ + "or people have given two eepsites identical names.<p>"+ "You can resolve the conflict by considering which key you trust, "+ "and either discarding the addresshelper link, "+ "discarding the host entry from your host database, "+ - "or naming one of them differently.<P/>") + "or naming one of them differently.<p>") .getBytes(); private final static byte[] ERR_BAD_PROTOCOL = @@ -376,22 +385,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable // Did addresshelper key conflict? if (ahelperConflict) { - String str; - byte[] header; - str = FileUtil.readTextFile((new File(_errorDir, "ahelper-conflict-header.ht")).getAbsolutePath(), 100, true); - if (str != null) header = str.getBytes(); - else header = ERR_AHELPER_CONFLICT; if (out != null) { + // Fixme untranslated long alias = I2PAppContext.getGlobalContext().random().nextLong(); String trustedURL = protocol + uriPath + urlEncoding; String conflictURL = protocol + alias + ".i2p/?" + initialFragments; + byte[] header = getErrorPage("ahelper-conflict", ERR_AHELPER_CONFLICT); out.write(header); - out.write(("To visit the destination in your host database, click <a href=\"" + trustedURL + "\">here</a>. To visit the conflicting addresshelper link by temporarily giving it a random alias, click <a href=\"" + conflictURL + "\">here</a>.<P/>").getBytes()); - out.write("</div><div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br />Generated on: ".getBytes()); - out.write(new Date().toString().getBytes()); - out.write("</i></div></body></html>\n".getBytes()); - out.flush(); + out.write(("To visit the destination in your host database, click <a href=\"" + trustedURL + "\">here</a>. To visit the conflicting addresshelper link by temporarily giving it a random alias, click <a href=\"" + conflictURL + "\">here</a>.<p></div>").getBytes()); + writeFooter(out); } s.close(); return; @@ -408,11 +411,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable line = method + " " + request.substring(pos); } else if (host.toLowerCase().equals("localhost") || host.equals("127.0.0.1")) { if (out != null) { - out.write(ERR_LOCALHOST); - out.write("<p /><i>Generated on: ".getBytes()); - out.write(new Date().toString().getBytes()); - out.write("</i></body></html>\n".getBytes()); - out.flush(); + out.write(getErrorPage("localhost", ERR_LOCALHOST)); + writeFooter(out); } s.close(); return; @@ -430,11 +430,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable _log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!"); l.log("No HTTP outproxy found for the request."); if (out != null) { - out.write(ERR_NO_OUTPROXY); - out.write("<p /><i>Generated on: ".getBytes()); - out.write(new Date().toString().getBytes()); - out.write("</i></body></html>\n".getBytes()); - out.flush(); + out.write(getErrorPage("noproxy", ERR_NO_OUTPROXY)); + writeFooter(out); } s.close(); return; @@ -449,11 +446,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable if (pos < 0) { l.log("Invalid request url [" + request + "]"); if (out != null) { - out.write(ERR_REQUEST_DENIED); - out.write("<p /><i>Generated on: ".getBytes()); - out.write(new Date().toString().getBytes()); - out.write("</i></body></html>\n".getBytes()); - out.flush(); + out.write(getErrorPage("denied", ERR_REQUEST_DENIED)); + writeFooter(out); } s.close(); return; @@ -540,13 +534,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable l.log("No HTTP method found in the request."); if (out != null) { if ("http://".equalsIgnoreCase(protocol)) - out.write(ERR_REQUEST_DENIED); + out.write(getErrorPage("denied", ERR_REQUEST_DENIED)); else - out.write(ERR_BAD_PROTOCOL); - out.write("<p /><i>Generated on: ".getBytes()); - out.write(new Date().toString().getBytes()); - out.write("</i></body></html>\n".getBytes()); - out.flush(); + out.write(getErrorPage("protocol", ERR_BAD_PROTOCOL)); + writeFooter(out); } s.close(); return; @@ -568,23 +559,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable //l.log("Could not resolve " + destination + "."); if (_log.shouldLog(Log.WARN)) _log.warn("Unable to resolve " + destination + " (proxy? " + usingWWWProxy + ", request: " + targetRequest); - String str; byte[] header; boolean showAddrHelper = false; if (usingWWWProxy) - str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true); + header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN); else if(ahelper != 0) - str = FileUtil.readTextFile((new File(_errorDir, "dnfb-header.ht")).getAbsolutePath(), 100, true); + header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN); else if (destination.length() == 60 && destination.endsWith(".b32.i2p")) - str = FileUtil.readTextFile((new File(_errorDir, "dnf-header.ht")).getAbsolutePath(), 100, true); + header = getErrorPage("dnf", ERR_DESTINATION_UNKNOWN); else { - str = FileUtil.readTextFile((new File(_errorDir, "dnfh-header.ht")).getAbsolutePath(), 100, true); + header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN); showAddrHelper = true; } - if (str != null) - header = str.getBytes(); - else - header = ERR_DESTINATION_UNKNOWN; writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination, showAddrHelper); s.close(); return; @@ -658,6 +644,64 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable } } + /** + * foo => errordir/foo-header_xx.ht for lang xx, or errordir/foo-header.ht, + * or the backup byte array on fail. + * + * .ht files must be UTF-8 encoded and use \r\n terminators so the + * HTTP headers are conformant. + * We can't use FileUtil.readFile() because it strips \r + * + * @return non-null + */ + private byte[] getErrorPage(String base, byte[] backup) { + return getErrorPage(getTunnel().getContext(), base, backup); + } + + private static byte[] getErrorPage(I2PAppContext ctx, String base, byte[] backup) { + File errorDir = new File(ctx.getBaseDir(), "docs"); + String lang = ctx.getProperty("routerconsole.lang", Locale.getDefault().getLanguage()); + if (lang != null && lang.length() > 0 && !lang.equals("en")) { + File file = new File(errorDir, base + "-header_" + lang + ".ht"); + try { + return readFile(file); + } catch (IOException ioe) { + // try the english version now + } + } + File file = new File(errorDir, base + "-header.ht"); + try { + return readFile(file); + } catch (IOException ioe) { + return backup; + } + } + + private static byte[] readFile(File file) throws IOException { + FileInputStream fis = null; + byte[] buf = new byte[512]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(2048); + try { + int len = 0; + fis = new FileInputStream(file); + while ((len = fis.read(buf)) > 0) { + baos.write(buf, 0, len); + } + return baos.toByteArray(); + } finally { + try { if (fis != null) fis.close(); } catch (IOException foo) {} + } + // we won't ever get here + } + + private static void writeFooter(OutputStream out) throws IOException { + // the css is hiding this div for now, but we'll keep it here anyway + out.write("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes()); + out.write(new Date().toString().getBytes()); + out.write("</i></div></body></html>\n".getBytes()); + out.flush(); + } + private static class OnTimeout implements Runnable { private Socket _socket; private OutputStream _out; @@ -705,9 +749,10 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable out.write("\">http://".getBytes()); out.write(uri.getBytes()); out.write("</a>".getBytes()); - if (usingWWWProxy) out.write(("<br />WWW proxy: " + wwwProxy).getBytes()); + if (usingWWWProxy) out.write(("<br>WWW proxy: " + wwwProxy).getBytes()); if (showAddrHelper) { - out.write("<br /><br />Click a link below to look for an address helper by using a \"jump\" service:<br />".getBytes()); + // Fixme untranslated + out.write("<br><br>Click a link below to look for an address helper by using a \"jump\" service:<br>".getBytes()); for (int i = 0; i < jumpServers.length; i++) { // Skip jump servers we don't know String jumphost = jumpServers[i].substring(7); // "http://" @@ -719,7 +764,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable continue; } - out.write("<br /><a href=\"".getBytes()); + out.write("<br><a href=\"".getBytes()); out.write(jumpServers[i].getBytes()); out.write(uri.getBytes()); out.write("\">".getBytes()); @@ -729,10 +774,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable } } } - out.write("</div><div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br />Generated on: ".getBytes()); - out.write(new Date().toString().getBytes()); - out.write("</i></div></body></html>\n".getBytes()); - out.flush(); + out.write("</div>".getBytes()); + writeFooter(out); } } @@ -744,16 +787,11 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable // _log.warn(getPrefix(requestId) + "Error sending to " + wwwProxy + " (proxy? " + usingWWWProxy + ", request: " + targetRequest, ex); if (out != null) { try { - String str; byte[] header; if (usingWWWProxy) - str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true); - else - str = FileUtil.readTextFile((new File(_errorDir, "dnf-header.ht")).getAbsolutePath(), 100, true); - if (str != null) - header = str.getBytes(); + header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp", ERR_DESTINATION_UNKNOWN); else - header = ERR_DESTINATION_UNKNOWN; + header = getErrorPage(I2PAppContext.getGlobalContext(), "dnf", ERR_DESTINATION_UNKNOWN); writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy, false); } catch (IOException ioe) { // static diff --git a/apps/routerconsole/java/bmsg.sh b/apps/routerconsole/java/bmsg.sh index c63835709be422b91d504b846a6e77c8d30f3c5b..729ea17034efb433245a1c454891aeee9be59a38 100644 --- a/apps/routerconsole/java/bmsg.sh +++ b/apps/routerconsole/java/bmsg.sh @@ -14,89 +14,4 @@ echo $PWD ## except this everything is the same with bundle-message.sh ## walking - public domain :-D - -CLASS=net.i2p.router.web.messages -TMPFILE=build/javafiles.txt -export TZ=UTC - -# -# generate strings/Countries.java from ../../../installer/resources/countries.txt -# -CFILE=../../../installer/resources/countries.txt -JFILE=build/Countries.java -if [ $CFILE -nt $JFILE -o ! -s $JFILE ] -then - mkdir -p build - echo '// Automatically generated pseudo-java for xgettext - do not edit' > $JFILE - echo '// Translators may wish to translate a few of these, do not bother to translate all of them!!' >> $JFILE - sed 's/..,\(..*\)/_("\1");/' $CFILE >> $JFILE -fi - -# list specific files in router/ here, so we don't scan the whole tree -ROUTERFILES="\ - ../../../router/java/src/net/i2p/router/RouterThrottleImpl.java \ - ../../../router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java" -JPATHS="src ../jsp/WEB-INF strings $JFILE $ROUTERFILES" -for i in ../locale/messages_*.po -do - # get language - LG=${i#../locale/messages_} - LG=${LG%.po} - - # make list of java files newer than the .po file - find $JPATHS -name *.java -newer $i > $TMPFILE - if [ -s build/obj/net/i2p/router/web/messages_$LG.class -a \ - build/obj/net/i2p/router/web/messages_$LG.class -nt $i -a \ - ! -s $TMPFILE ] - then - continue - fi - - echo "Generating ${CLASS}_$LG ResourceBundle..." - - # extract strings from java and jsp files, and update messages.po files - # translate calls must be one of the forms: - # _("foo") - # _x("foo") - # intl._("foo") - # intl.title("foo") - # handler._("foo") - # formhandler._("foo") - # net.i2p.router.web.Messages.getString("foo") - # In a jsp, you must use a helper or handler that has the context set. - # To start a new translation, copy the header from an old translation to the new .po file, - # then ant distclean updater. - find $JPATHS -name *.java > $TMPFILE - xgettext -f $TMPFILE -F -L java --from-code=UTF-8 \ - --keyword=_ --keyword=_x --keyword=intl._ --keyword=intl.title \ - --keyword=handler._ --keyword=formhandler._ \ - --keyword=net.i2p.router.web.Messages.getString \ - -o ${i}t - if [ $? -ne 0 ] - then - echo 'Warning - xgettext failed, not updating translations' - rm -f ${i}t - break - fi - msgmerge -U --backup=none $i ${i}t - if [ $? -ne 0 ] - then - echo 'Warning - msgmerge failed, not updating translations' - rm -f ${i}t - break - fi - rm -f ${i}t - # so we don't do this again - touch $i - - # convert to class files in build/obj - msgfmt --java -r $CLASS -l $LG -d build/obj $i - if [ $? -ne 0 ] - then - echo 'Warning - msgfmt failed, not updating translations' - break - fi -done -rm -f $TMPFILE -# todo: return failure -exit 0 +source bundle-messages.sh \ No newline at end of file diff --git a/apps/routerconsole/java/bundle-messages.sh b/apps/routerconsole/java/bundle-messages.sh index fd2a58713b123d21591b097105d59383d8799d6f..7a25d1b047c3d580412732fb6c53e97154b34afe 100755 --- a/apps/routerconsole/java/bundle-messages.sh +++ b/apps/routerconsole/java/bundle-messages.sh @@ -24,7 +24,12 @@ fi # list specific files in router/ here, so we don't scan the whole tree ROUTERFILES="\ ../../../router/java/src/net/i2p/router/RouterThrottleImpl.java \ - ../../../router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java" + ../../../router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java \ + ../../../router/java/src/net/i2p/router/transport/TransportManager.java \ + ../../../router/java/src/net/i2p/router/transport/GetBidsJob.java \ + ../../../router/java/src/net/i2p/router/Blocklist.java \ + ../../../router/java/src/net/i2p/router/transport/ntcp/EstablishState.java" + JPATHS="src ../jsp/WEB-INF strings $JFILE $ROUTERFILES" for i in ../locale/messages_*.po do diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java index b4ca7bb40ab44d4b29fda370243745b066ee2138..514facb098303accf37e87114552eb35b9ad4825 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java @@ -20,7 +20,7 @@ public class ConfigPeerHandler extends FormHandler { } else if (_action.equals(_("Ban peer until restart"))) { Hash h = getHash(); if (h != null) { - _context.shitlist().shitlistRouterForever(h, "Manually banned via <a href=\"configpeer.jsp\">configpeer.jsp</a>"); + _context.shitlist().shitlistRouterForever(h, _("Manually banned via {0}"), "<a href=\"configpeer.jsp\">configpeer.jsp</a>"); addFormNotice(_("Peer") + " " + _peer + " " + _("banned until restart") ); return; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java index 3621604069539316a9b1d00d1c015be0fd7fddd7..108b94e5291f60f607479ba2a0c97e73ece6afab 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java @@ -43,7 +43,7 @@ public class ConfigTunnelsHelper extends HelperBase { String prefix = dest.calculateHash().toBase64().substring(0,4); buf.append("<input type=\"hidden\" name=\"pool.").append(cur).append("\" value=\""); buf.append(dest.calculateHash().toBase64()).append("\" >"); - renderForm(buf, cur, prefix, _("Client tunnels for") + " " + name, in, out); + renderForm(buf, cur, prefix, _("Client tunnels for") + " " + _(name), in, out); cur++; } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java index d2c1827a4570a5f619e9e0d2199b2104c7f7e440..2c5e5dc19125e26a4ae24c4035a999bba02b313e 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbRenderer.java @@ -201,7 +201,7 @@ public class NetDbRenderer { // transports table buf.append("<table>\n"); - buf.append("<tr><th align=\"left\">" + _("Addresses") + "</th><th>" + _("Count") + "</th></tr>\n"); + buf.append("<tr><th align=\"left\">" + _("Transports") + "</th><th>" + _("Count") + "</th></tr>\n"); for (int i = 0; i < 8; i++) { int num = transportCount[i]; if (num > 0) { @@ -276,7 +276,7 @@ public class NetDbRenderer { } for (Iterator iter = info.getAddresses().iterator(); iter.hasNext(); ) { RouterAddress addr = (RouterAddress)iter.next(); - buf.append("<b>").append(DataHelper.stripHTML(addr.getTransportStyle())).append("</b>: "); + buf.append("<b>").append(DataHelper.stripHTML(addr.getTransportStyle())).append(":</b> "); for (Iterator optIter = addr.getOptions().keySet().iterator(); optIter.hasNext(); ) { String name = (String)optIter.next(); String val = addr.getOptions().getProperty(name); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java index fe8a823b2317b7a9ec1831eb21698b5ab9fe5823..55939897aa1ab2c053059e61c0faa8103de7d64b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ProfileOrganizerRenderer.java @@ -234,14 +234,14 @@ class ProfileOrganizerRenderer { } buf.append("</table>"); - buf.append("<h3>").append(_("Thresholds:")).append("</h3>"); + buf.append("<h3>").append(_("Thresholds")).append("</h3>"); buf.append("<p><b>").append(_("Speed")).append(":</b> ").append(num(_organizer.getSpeedThreshold())) .append(" (").append(fast).append(' ').append(_("fast peers")).append(")<br>"); buf.append("<b>").append(_("Capacity")).append(":</b> ").append(num(_organizer.getCapacityThreshold())) .append(" (").append(reliable).append(' ').append(_("high capacity peers")).append(")<br>"); buf.append("<b>").append(_("Integration")).append(":</b> ").append(num(_organizer.getIntegrationThreshold())) .append(" (").append(integrated).append(' ').append(_(" well integrated peers")).append(")</p>"); - buf.append("<h3>").append(_("Definitions")).append(":</h3><ul>"); + buf.append("<h3>").append(_("Definitions")).append("</h3><ul>"); buf.append("<li><b>").append(_("groups")).append("</b>: ").append(_("as determined by the profile organizer")).append("</li>"); buf.append("<li><b>").append(_("caps")).append("</b>: ").append(_("capabilities in the netDb, not used to determine profiles")).append("</li>"); buf.append("<li><b>").append(_("speed")).append("</b>: ").append(_("peak throughput (bytes per second) over a 1 minute period that the peer has sustained in a single tunnel")).append("</li>"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java index 3b02f6b30a9a987dcd0c1a0a6d69d90c06d8910b..ba7a6aa926cbacaa77ca431c0a22cd050d7413c7 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java @@ -20,7 +20,8 @@ public class ProfilesHelper extends HelperBase { /** @return empty string, writes directly to _out */ public String getShitlistSummary() { try { - _context.shitlist().renderStatusHTML(_out); + ShitlistRenderer rend = new ShitlistRenderer(_context); + rend.renderStatusHTML(_out); } catch (IOException ioe) { ioe.printStackTrace(); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java new file mode 100644 index 0000000000000000000000000000000000000000..b1e3ccf30253f15e7a7c40a13832939c2aa93141 --- /dev/null +++ b/apps/routerconsole/java/src/net/i2p/router/web/ShitlistRenderer.java @@ -0,0 +1,99 @@ +package net.i2p.router.web; +/* + * free (adj.): unencumbered; not under the control of others + * Written by jrandom in 2003 and released into the public domain + * with no warranty of any kind, either expressed or implied. + * It probably won't make your computer catch on fire, or eat + * your children, but it might. Use at your own risk. + * + */ + +import java.io.IOException; +import java.io.Writer; +import java.util.Comparator; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import net.i2p.data.DataHelper; +import net.i2p.data.Hash; +import net.i2p.router.RouterContext; +import net.i2p.router.Shitlist; + +/** + * Moved from Shitlist.java + */ +public class ShitlistRenderer { + private RouterContext _context; + + public ShitlistRenderer(RouterContext context) { + _context = context; + } + + private static class HashComparator implements Comparator { + public int compare(Object l, Object r) { + return ((Hash)l).toBase64().compareTo(((Hash)r).toBase64()); + } + } + + public void renderStatusHTML(Writer out) throws IOException { + StringBuilder buf = new StringBuilder(1024); + // move to the jsp + //buf.append("<h2>Banned Peers</h2>"); + Map<Hash, Shitlist.Entry> entries = new TreeMap(new HashComparator()); + + entries.putAll(_context.shitlist().getEntries()); + + buf.append("<ul>"); + + for (Map.Entry<Hash, Shitlist.Entry> e : entries.entrySet()) { + Hash key = e.getKey(); + Shitlist.Entry entry = e.getValue(); + buf.append("<li>").append(_context.commSystem().renderPeerHTML(key)); + buf.append(' '); + long expires = entry.expireOn-_context.clock().now(); + String expireString = DataHelper.formatDuration(expires); + if (expires < 5l*24*60*60*1000) + buf.append(_("Temporary ban expiring in {0}", expireString)); + else + buf.append(_("Banned until restart or in {0}", expireString)); + Set transports = entry.transports; + if ( (transports != null) && (transports.size() > 0) ) + buf.append(" on the following transport: ").append(transports); + if (entry.cause != null) { + buf.append("<br>\n"); + if (entry.causeCode != null) + buf.append(_(entry.cause, entry.causeCode)); + else + buf.append(_(entry.cause)); + } + buf.append(" (<a href=\"configpeer.jsp?peer=").append(key.toBase64()) + .append("#unsh\">").append(_("unban now")).append("</a>)"); + buf.append("</li>\n"); + } + buf.append("</ul>\n"); + out.write(buf.toString()); + out.flush(); + } + + /** translate a string */ + private String _(String s) { + return Messages.getString(s, _context); + } + + /** + * translate a string with a parameter + * This is a lot more expensive than _(s), so use sparingly. + * + * @param s string to be translated containing {0} + * The {0} will be replaced by the parameter. + * Single quotes must be doubled, i.e. ' -> '' in the string. + * @param o parameter, not translated. + * To tranlslate parameter also, use _("foo {0} bar", _("baz")) + * Do not double the single quotes in the parameter. + * Use autoboxing to call with ints, longs, floats, etc. + */ + private String _(String s, Object o) { + return Messages.getString(s, o, _context); + } +} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java index ff4154c7c20d6d0925ec7f536edae4680a7979e5..9091e072f308b034f7542ad1bb2461171ab48b86 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/TunnelRenderer.java @@ -37,7 +37,7 @@ public class TunnelRenderer { } public void renderStatusHTML(Writer out) throws IOException { - out.write("<div class=\"wideload\"><h2><a name=\"exploratory\" ></a>" + _("Exploratory tunnels") + " (<a href=\"/configtunnels.jsp#exploratory\">" + _("config") + "</a>):</h2>\n"); + out.write("<div class=\"wideload\"><h2><a name=\"exploratory\" ></a>" + _("Exploratory tunnels") + " (<a href=\"/configtunnels.jsp#exploratory\">" + _("configure") + "</a>)</h2>\n"); renderPool(out, _context.tunnelManager().getInboundExploratoryPool(), _context.tunnelManager().getOutboundExploratoryPool()); List<Hash> destinations = null; @@ -59,15 +59,15 @@ public class TunnelRenderer { out.write("<h2><a name=\"" + client.toBase64().substring(0,4) + "\" ></a>" + _("Client tunnels for") + ' ' + _(name)); if (_context.clientManager().isLocal(client)) - out.write(" (<a href=\"/configtunnels.jsp#" + client.toBase64().substring(0,4) +"\">" + _("config") + "</a>):</h2>\n"); + out.write(" (<a href=\"/configtunnels.jsp#" + client.toBase64().substring(0,4) +"\">" + _("configure") + "</a>)</h2>\n"); else - out.write(" (dead):</h2>\n"); + out.write(" (" + _("dead") + ")</h2>\n"); renderPool(out, in, outPool); } List participating = _context.tunnelDispatcher().listParticipatingTunnels(); Collections.sort(participating, new TunnelComparator()); - out.write("<h2><a name=\"participating\"></a>" + _("Participating tunnels") + ":</h2><table>\n"); + out.write("<h2><a name=\"participating\"></a>" + _("Participating tunnels") + "</h2><table>\n"); out.write("<tr><th>" + _("Receive on") + "</th><th>" + _("From") + "</th><th>" + _("Send on") + "</th><th>" + _("To") + "</th><th>" + _("Expiration") + "</th>" + "<th>" + _("Usage") + "</th><th>" + _("Rate") + "</th><th>" + _("Role") + "</th></tr>\n"); @@ -104,7 +104,7 @@ public class TunnelRenderer { if (timeLeft > 0) out.write(" <td class=\"cells\" align=\"center\">" + DataHelper.formatDuration(timeLeft) + "</td>"); else - out.write(" <td class=\"cells\" align=\"center\">(grace period)</td>"); + out.write(" <td class=\"cells\" align=\"center\">(" + _("grace period") + ")</td>"); out.write(" <td class=\"cells\" align=\"center\">" + cfg.getProcessedMessagesCount() + "KB</td>"); int lifetime = (int) ((_context.clock().now() - cfg.getCreation()) / 1000); if (lifetime <= 0) @@ -231,7 +231,7 @@ public class TunnelRenderer { List<Hash> peerList = new ArrayList(peers); Collections.sort(peerList, new HashComparator()); - out.write("<h2><a name=\"peers\"></a>" + _("Tunnel Counts By Peer") + ":</h2>\n"); + out.write("<h2><a name=\"peers\"></a>" + _("Tunnel Counts By Peer") + "</h2>\n"); out.write("<table><tr><th>" + _("Peer") + "</th><th>" + _("Expl. + Client") + "</th><th>" + _("% of total") + "</th><th>" + _("Part. from + to") + "</th><th>" + _("% of total") + "</th></tr>\n"); for (Hash h : peerList) { out.write("<tr> <td class=\"cells\" align=\"center\">"); diff --git a/apps/routerconsole/jsp/help.jsp b/apps/routerconsole/jsp/help.jsp index 5e168bccc38b277c86ce3b9fe77e906a1ab235a5..35e4dd05b9e1b196ced584bf3d75b117052b20d5 100644 --- a/apps/routerconsole/jsp/help.jsp +++ b/apps/routerconsole/jsp/help.jsp @@ -19,7 +19,7 @@ help with other aspects of the project, please see the documentation for <ul class="links"> <li class="tidylist"><a href="http://www.i2p2.i2p/faq.html">FAQ on www.i2p2.i2p</a> <li class="tidylist"><a href="http://www.i2p2.i2p/faq_de.html">Deutsch FAQ</a>.</ul> -</p><p>You may also try the <a href="http://forum.i2p/">I2P forum</a> +<br>You may also try the <a href="http://forum.i2p/">I2P forum</a> or IRC.</p> <h2>Summary Bar Information</h2><p> diff --git a/apps/routerconsole/locale/messages_zh.po b/apps/routerconsole/locale/messages_zh.po index 23481f291ca2eb9b6fa8bd7fb716943246cffc33..9f542efdb205e98a934f5ca683393c20782c87f9 100644 --- a/apps/routerconsole/locale/messages_zh.po +++ b/apps/routerconsole/locale/messages_zh.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: I2P routerconsole\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-11-11 11:09+0000\n" +"POT-Creation-Date: 2009-11-12 06:00+0000\n" "PO-Revision-Date: \n" "Last-Translator: walking <walking@mail.i2p>\n" "Language-Team: \n" @@ -18,6 +18,24 @@ msgstr "" "X-Poedit-Language: Chinese\n" "X-Poedit-Country: CHINA\n" +#: ../../../router/java/src/net/i2p/router/Blocklist.java:117 +#, java-format +msgid "Banned by router hash: {0}" +msgstr "按路由器指纹封杀:{0}" + +#: ../../../router/java/src/net/i2p/router/Blocklist.java:119 +msgid "Banned by router hash" +msgstr "路由指纹封锁" + +#: ../../../router/java/src/net/i2p/router/Blocklist.java:664 +msgid "IP banned" +msgstr "IP封锁" + +#: ../../../router/java/src/net/i2p/router/Blocklist.java:734 +#, java-format +msgid "IP banned by blocklist.txt entry {0}" +msgstr "按IP黑名单blocklist.txt封杀的节点{0}" + #: ../../../router/java/src/net/i2p/router/RouterThrottleImpl.java:91 msgid "Rejecting tunnels: Shutting down" msgstr "拒绝共享:准备退出" @@ -54,6 +72,20 @@ msgstr "接收共享隧道" msgid "Rejecting tunnels" msgstr "拒绝参与共享隧道" +#: ../../../router/java/src/net/i2p/router/transport/GetBidsJob.java:70 +msgid "No transports (hidden or starting up?)" +msgstr "无数据传输(隐身或正在启动)" + +#: ../../../router/java/src/net/i2p/router/transport/TransportManager.java:450 +msgid "Unreachable on any transport" +msgstr "各协议均不可达" + +#: ../../../router/java/src/net/i2p/router/transport/ntcp/EstablishState.java:373 +#: ../../../router/java/src/net/i2p/router/transport/ntcp/EstablishState.java:578 +#, java-format +msgid "Excessive clock skew: {0}" +msgstr "严重时滞:{0}" + #: ../../../router/java/src/net/i2p/router/tunnel/pool/BuildHandler.java:128 msgid "Dropping tunnel requests: Too slow" msgstr "忽略共享请求:速度太慢" @@ -836,7 +868,7 @@ msgstr "(建议不要使用 DEBUG 或 INFO 作为默认等级,他们会明显降 #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configlogging_jsp.java:329 msgid "Log level overrides" -msgstr "等级外日志项目" +msgstr "等级外<br>日志项目" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configpeer_jsp.java:106 msgid "config peers" @@ -856,7 +888,7 @@ msgstr "路由器Key(见NetDB)" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configpeer_jsp.java:310 msgid "Manually Ban / Unban a Peer" -msgstr "手动封锁/解封某个节点" +msgstr "手动封杀/解封某个节点" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configpeer_jsp.java:312 msgid "Banning will prevent the participation of this peer in tunnels you create." @@ -865,7 +897,7 @@ msgstr "封锁将阻止节点参与您的隧道创建" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configpeer_jsp.java:314 #: src/net/i2p/router/web/ConfigPeerHandler.java:20 msgid "Ban peer until restart" -msgstr "封锁节点直到重启" +msgstr "封杀节点直到重启" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configpeer_jsp.java:316 #: src/net/i2p/router/web/ConfigPeerHandler.java:28 @@ -1219,15 +1251,15 @@ msgstr "升级策略" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configupdate_jsp.java:326 msgid "Update through the eepProxy?" -msgstr "通过eepProxy更新?" +msgstr "通过I2P代理更新?" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configupdate_jsp.java:330 msgid "eepProxy host" -msgstr "eepProxy主机" +msgstr "I2P代理主机" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configupdate_jsp.java:334 msgid "eepProxy port" -msgstr "eepProxy端口" +msgstr "I2P代理端口" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/configupdate_jsp.java:338 msgid "Update URLs" @@ -1334,7 +1366,7 @@ msgstr "I2P 网络节点信息" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/stats_jsp.java:105 msgid "statistics" -msgstr "统计数据" +msgstr "统计" #: ../jsp/WEB-INF/classes/net/i2p/router/web/jsp/stats_jsp.java:242 msgid "I2P Router Statistics" @@ -2453,7 +2485,7 @@ msgstr "节点" #: src/net/i2p/router/web/NetDbRenderer.java:288 #: src/net/i2p/router/web/SummaryBarRenderer.java:124 msgid "Stats" -msgstr "统计数据" +msgstr "统计" #: src/net/i2p/router/web/ConfigNavHelper.java:20 msgid "Advanced" @@ -2543,6 +2575,11 @@ msgstr "未知" msgid "bits per second" msgstr "比特/秒" +#: src/net/i2p/router/web/ConfigPeerHandler.java:23 +#, java-format +msgid "Manually banned via {0}" +msgstr "通过{0}手动封锁" + #: src/net/i2p/router/web/ConfigPeerHandler.java:24 #: src/net/i2p/router/web/ConfigPeerHandler.java:33 #: src/net/i2p/router/web/ConfigPeerHandler.java:35 @@ -3249,8 +3286,8 @@ msgid "1d Fail Rate" msgstr "1d失败率" #: src/net/i2p/router/web/ProfileOrganizerRenderer.java:237 -msgid "Thresholds:" -msgstr "临界值:" +msgid "Thresholds" +msgstr "临界值" #: src/net/i2p/router/web/ProfileOrganizerRenderer.java:239 msgid "fast peers" @@ -3320,6 +3357,20 @@ msgstr "状态" msgid "n/a" msgstr "" +#: src/net/i2p/router/web/ShitlistRenderer.java:57 +#, java-format +msgid "Temporary ban expiring in {0}" +msgstr "临时封锁{0}后解除" + +#: src/net/i2p/router/web/ShitlistRenderer.java:59 +#, java-format +msgid "Banned until restart or in {0}" +msgstr "封锁直到重启或{0}后" + +#: src/net/i2p/router/web/ShitlistRenderer.java:71 +msgid "unban now" +msgstr "立即解封" + #: src/net/i2p/router/web/StatsGenerator.java:58 msgid "Statistics gathered during this router's uptime" msgstr "路由运行时收集的统计数据" @@ -3366,7 +3417,7 @@ msgstr "内置的匿名Web服务器" #: src/net/i2p/router/web/SummaryBarRenderer.java:68 msgid "Webserver" -msgstr "匿名网站服务器" +msgstr "匿名主页服务器" #: src/net/i2p/router/web/SummaryBarRenderer.java:72 msgid "Configure I2P Router" @@ -3638,9 +3689,13 @@ msgstr "共享客户端" #: src/net/i2p/router/web/TunnelRenderer.java:40 #: src/net/i2p/router/web/TunnelRenderer.java:62 -msgid "config" +msgid "configure" msgstr "设置" +#: src/net/i2p/router/web/TunnelRenderer.java:64 +msgid "dead" +msgstr "失效" + #: src/net/i2p/router/web/TunnelRenderer.java:70 msgid "Participating tunnels" msgstr "共享隧道" @@ -3678,6 +3733,10 @@ msgstr "职能" msgid "Usage" msgstr "使用情况" +#: src/net/i2p/router/web/TunnelRenderer.java:107 +msgid "grace period" +msgstr "过渡期" + #: src/net/i2p/router/web/TunnelRenderer.java:117 msgid "Outbound Endpoint" msgstr "出站终端" @@ -3795,7 +3854,7 @@ msgstr "程序隧道" #: strings/Strings.java:25 msgid "My eepsite web server" -msgstr "我的匿名Web服务器" +msgstr "匿名主页服务器" #: strings/Strings.java:26 msgid "Browser launch at startup" @@ -3807,7 +3866,7 @@ msgstr "BOB 协议桥" #: strings/Strings.java:34 msgid "IRC proxy" -msgstr "IRC 代理" +msgstr "I2P聊天室" #: strings/Strings.java:35 msgid "eepsite" @@ -3819,7 +3878,7 @@ msgstr "I2P代理" #: strings/Strings.java:38 msgid "ircProxy" -msgstr "IRC代理" +msgstr "I2P聊天室" #: strings/Strings.java:40 msgid "I2PSnark" diff --git a/build.xml b/build.xml index d6af47fdd3923fc28679a3d1638cc2e681e3d734..4ea82687db09ab5d63ef91467dee6a803479ecf7 100644 --- a/build.xml +++ b/build.xml @@ -286,8 +286,10 @@ <copy file="history.txt" todir="pkg-temp/" /> <mkdir dir="pkg-temp/scripts" /> <copy file="apps/proxyscript/i2pProxy.pac" todir="pkg-temp/scripts/" /> + <!-- test classes aren't in the jars anymore <copy file="core/perl/i2pbench.sh" todir="pkg-temp/scripts/" /> <copy file="core/perl/i2ptest.sh" todir="pkg-temp/scripts/" /> + --> <!-- polecat: please put your modified toolbar.html in installer/resources/toolbar.html and uncomment the following --> <!-- <copy file="installer/resources/toolbar.html" todir="pkg-temp/docs/" /> --> @@ -333,7 +335,7 @@ --> <!-- Since the logo moved, we have to update the error pages --> <copy todir="pkg-temp/docs/" > - <fileset dir="installer/resources/" includes="*-header.ht" /> + <fileset dir="installer/resources/proxy" /> </copy> <!-- make a "classic" theme --> <copy todir="pkg-temp/docs/themes/console/classic/" > @@ -372,7 +374,7 @@ <target name="prepconsoleDocs" depends="prepgeoupdate"> <copy todir="pkg-temp/docs/" > <fileset dir="." includes="readme*.html" /> - <fileset dir="installer/resources/" includes="*-header.ht" /> + <fileset dir="installer/resources/proxy" /> </copy> </target> <target name="consoleDocs" depends="deletepkg-temp, prepconsoleDocs"> diff --git a/core/java/src/net/i2p/util/FileUtil.java b/core/java/src/net/i2p/util/FileUtil.java index f35898139ef348f675616fa4b976bba910a335dd..fda5066412423d8445a198d5a82fb01ba72558e7 100644 --- a/core/java/src/net/i2p/util/FileUtil.java +++ b/core/java/src/net/i2p/util/FileUtil.java @@ -196,9 +196,14 @@ public class FileUtil { * Read in the last few lines of a (newline delimited) textfile, or null if * the file doesn't exist. * + * Warning - this inefficiently allocates a StringBuilder of size maxNumLines*80, + * so don't make it too big. + * Warning - converts \r\n to \n + * * @param startAtBeginning if true, read the first maxNumLines, otherwise read * the last maxNumLines * @param maxNumLines max number of lines (or -1 for unlimited) + * @return string or null; does not throw IOException. * */ public static String readTextFile(String filename, int maxNumLines, boolean startAtBeginning) { diff --git a/history.txt b/history.txt index 51220dd55ce9de11a311e7d5e1a01127ec78809c..cfdeb9852294ccebdfacf793fb33332106f4037e 100644 --- a/history.txt +++ b/history.txt @@ -1,3 +1,26 @@ +2009-11-16 zzz + * addressbook: Move class to net.i2p.addressbook + * build: Take two test scripts out of the installer + * i2psnark: Bye TPB + * Shitlist: Fix bug from two checkins ago, all were forever + +2009-11-14 zzz + * HTTP Proxy: + - Add support for error page translations + - Add support for external pages for all errors + - Fix lack of \r in error page headers + - HTML transitional fixes + - Cleanups + * UDP PeerTestManager: Throw in some synchronization to + try to fix stuck tests + +2009-11-11 zzz + * Console: Some colon cleansing + * FloodfillPeerSelector: Adjustments + * Shitlist: Move HTML renderer to router console, + add cause parameter for ease of translation, + tag all causes + 2009-11-11 zzz * Addressbook, NamingService: Allow 516 byte dests that end with AA but not AAAA, so we can permit diff --git a/hosts.txt b/hosts.txt index 475a26ccef8279b7a374b2863de6bea2c3d7e757..4b0427a17bd1f1256dcbe3abb3a46ca42d6602d8 100644 --- a/hosts.txt +++ b/hosts.txt @@ -319,5 +319,3 @@ bob.i2p=5uAI6ENnNP8acDkAtYqBjLa-gFqM~uERNZdJBKtRwUvDkuXvIM66pYfYL3-ugTmoR-SIveDl sponge.i2p=VG4Bd~q1RA3BdoF3z5fSR7p0xe1CTVgDMWVGyFchA9Wm2iXUkIR35G45XE31Uc9~IOt-ktNLL2~TYQZ13Vl8udosngDn8RJG1NtVASH4khsbgkkoFLWd6UuvuOjQKBFKjaEPJgxOzh0kxolRPPNHhFuuAGzNLKvz~LI2MTf0P6nwmRg1lBoRIUpSVocEHY4X306nT2VtY07FixbJcPCU~EeRin24yNoiZop-C3Wi1SGwJJK-NS7mnkNzd8ngDJXDJtR-wLP1vNyyBY6NySgqPiIhENHoVeXd5krlR42HORCxEDb4jhoqlbyJq-PrhTJ5HdH4-~gEq09B~~NIHzy7X02XgmBXhTYRtl6HbLMXs6SI5fq9OFgVp5YZWYUklJjMDI7jOrGrEZGSHhnJK9kT6D3CqVIM0cYEhe4ttmTegbZvC~J6DrRTIAX422qRQJBPsTUnv4iFyuJE-8SodP6ikTjRH21Qx73SxqOvmrOiu7Bsp0lvVDa84aoaYLdiGv87AAAA docs.i2p2.i2p=BhSHFwXW7zGTLRVTRuTfgxWC1PxKGDyY2OYpS0IrDnYhQklWVFxHz4xVpw8UXo8LTFXAnAjknrcYdLt6DfHcO-ZkFPo5UbOIfywSsHoet4J6BQ1MOt1MLTAejks4Rkj3~sfK2fJHHvHYTjm1v5~f8c13ZH5fPfQ3A71RRCyiYaeO5-VxC6rqvW~z0dNO~-jakjwD7tHtzQL2vQTqarYT859yUiHmLJ~yw5jXfxNBhlxIxaXg0Nat9S5N2W4Eqemy-UYtSGOM4IUGKoM902JxhVpz~O1~iB5H211E3x-o8dKTt9Yz2G5Qcp1kRB0NCO2Noivsxjnfv~64zoUVbPepyJFQKenRtX844HgOESNcUp~FoVzI~QJne5irJDMLK1dNsua3L1kz0MA-2Aev8byWe4TIXeZCuDpYi4bRK6OPKDETwJG8edw7CFtsQaFI-2wGMFu8GDH7pUL8~1qyDjjFv5c~q1MFhty9q8LRUGHHgWP47u9n8OX4zcS4P1~5z2M3AAAA paste.i2p2.i2p=PbHXL5PXan7siJiFcUAV~VC0JCLxgnoOnZFjyvJ0dbYlQ3fi1K6SD961pjQ51OSeTnbe5iGRzbY2X0~pG4k~hexau4NizxprAdgdiC-4J3-xpVRjZ4IxuMoDXp-V8Nhv8pLCQcxiEXbWft2v7zLvkp2y6uqH7kab8FXL~z568rMMH0DDs8imwAawasyGtLLo77X8n-C0K~7orcWDVZicWABJ-zky1Zlllx~Y~S8RHWyN4dueP6wkH484b81xNbbt3P-HzE3TcKAvUcSV1Bq4J5UNafQYU7DhV7roUtw4HuJYoxiXnlXVeC-uTCGF~bPrjrB-~Yn0KyObmXs5yvAcKHIS2tgmlsP9nahyn1ZOrlZc0L3DEsv4rkfQyzHVBxcCzMUOchWehE09GLy3bviWZ43lB7kU8kRaja7G4xLrD-CXNXq6q7WNYXrqX7EmtsvCo8VDcFn2ODyLb3eyDe~CkO7ES7mv3u8jJxJRQEcjj71pvu7bMzSMh-xN08X6vx9AAAAA -thepiratebay.i2p=9Sng0F-cAyGgPyr1xenqY87Uf2AG~PlTXzUJRQnr7gpYFPUfRlH3OfWOVFat67jUl37ZzWBOSYC7-6YqFzPQV5u~DrTGaoImfa7BsRbnBlPXbSNIaP59C6Vp1RCbhtTpxQ4PvLLn9xzUKWoPkrQ222TCSxPR6-j2ChSuuCIA7bP7EP75BobL6n9hMmekzB4FbmBhC64Kri72Uhv~rMDdMZaDD9cD9-BgnZkyrI5jRtSuOUVnTexKMQ0UiYHanSDlBvNwLRMGdb0AsckOdXHrleKrwPnW4YTp0q89dPGP6fad4sVxgvxLHF6NuoWXGbnD0sYuv5qkegjBzioHOjxI~n52ObdeELVhs~peeiXpRavZcwlu1HzwNKfU8lJrpnLSoQsCuqd4OBFMmjvo3HhovLsTeUAo1W2O1F8gcPeOj3tD0ihInncMIbEUTI7kdbkBTsoMY8~73jKgQYC0c~hiEUb1tG4NLcfdxgAlWF5q9cJPDHFh9jtzDvq63OntBQ5OAAAA -tracker.thepiratebay.i2p=4svjpPox0vc527neBdWyfLiVulEeHtzQrC6IDDB2~rPwnZYWm3xsyrDYTa9gu5~1QrFitr5RMCcj34tzZZCKIg~INFNhi7Zk7UwsOCHtedS0RpRjDi2O3q~T~k8D4P39Rz0So91D624lofDV48itdkX8B3dNUHE0Qq5hCGjb2UVxLUhKh8DYOUAqYPoLaF1RpQx5DT~r-Hf57vA9bW3Q31xYH~Ys6AxCZ8~EmMqdgm0ZMQ57oWldHgkSbtQsoiBn2igJ24GDUDUvBsRVLt7He1nKg1ei2JvqQajKN31cQeS5fjqiGdUTkXjc1FftKB8HC9CbnsMJjPEFT6gvvtSpxULvSQGSJyD6OIzebXvQIYANAapEk1VP1OSIJlteOIwGDXkGj9ZyLpT7~RpUpk92v9L53Zjof~WjJmGqqWWsL~yypl0~nMUw5MLaKv5AJywDnFIJDR-GlkQQj5fECeefge30Y92CHwxgImwj3v7~DwXuU9d5u6KyzJSuByOGRvwVAAAA diff --git a/installer/resources/clients.config b/installer/resources/clients.config index 3f8add8e5fa71afdab6bab433e65023c6ac4d85d..0c7039a8b02dff3e1f72bde8aac20abc27f520ab 100644 --- a/installer/resources/clients.config +++ b/installer/resources/clients.config @@ -8,32 +8,32 @@ # fire up the web console clientApp.0.args=7657 ::1,127.0.0.1 ./webapps/ clientApp.0.main=net.i2p.router.web.RouterConsoleRunner -clientApp.0.name=Web console +clientApp.0.name=I2P Router Console clientApp.0.onBoot=true clientApp.0.startOnLoad=true # SAM bridge clientApp.1.main=net.i2p.sam.SAMBridge -clientApp.1.name=SAM application bridge +clientApp.1.name=SAM Application Bridge clientApp.1.args=sam.keys 127.0.0.1 7656 i2cp.tcp.host=127.0.0.1 i2cp.tcp.port=7654 clientApp.1.startOnLoad=false # poke the i2ptunnels defined in i2ptunnel.config clientApp.2.main=net.i2p.i2ptunnel.TunnelControllerGroup -clientApp.2.name=Application tunnels +clientApp.2.name=Application Tunnels clientApp.2.args=i2ptunnel.config clientApp.2.startOnLoad=true # run our own eepsite with a seperate jetty instance clientApp.3.main=org.mortbay.jetty.Server -clientApp.3.name=My eepsite web server +clientApp.3.name=Local Anonymous I2P Webserver clientApp.3.args="eepsite/jetty.xml" clientApp.3.delay=30 clientApp.3.startOnLoad=true # load a browser pointing at the web console whenever we start up clientApp.4.main=net.i2p.apps.systray.UrlLauncher -clientApp.4.name=Browser launch at startup +clientApp.4.name=Launch web browser and load I2P Router Console at startup clientApp.4.args=http://127.0.0.1:7657/index.jsp clientApp.4.delay=15 clientApp.4.startOnLoad=true diff --git a/installer/resources/eepget.bat b/installer/resources/eepget.bat new file mode 100644 index 0000000000000000000000000000000000000000..c7045952b19ab294dc8ed89d44231d3b0ddb2f9a --- /dev/null +++ b/installer/resources/eepget.bat @@ -0,0 +1,2 @@ +@echo off +java -cp lib/i2p.jar net.i2p.util.EepGet %1 %2 %3 %4 %5 diff --git a/installer/resources/eepsite_index_fr.html b/installer/resources/eepsite_index_fr.html new file mode 100644 index 0000000000000000000000000000000000000000..74400743f93203acfc1e90b197fc4400a4d125c3 --- /dev/null +++ b/installer/resources/eepsite_index_fr.html @@ -0,0 +1,118 @@ +<html> + <head> + <title>I2P serveur web anonyme | Bienvenue à votre eepsite</title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> + <link rel="shortcut icon" href="favicon.ico" /> + <link rel="stylesheet" type="text/css" href="lib/eepsite.css" /> + </head> + <body> +<div class="fairylights"> +<div class="main"> + <h1>Serveur web anonyme I2P</h1> +<div class="langbar"> +<!-- Most of these languages listed here are yet to be translated --> +<a href="index.html"><img src="lib/us.png" title="English" alt="English"></a> +<a href="index_na.html"><img src="lib/cn.png" title="Chinese" alt="Chinese"></a> +<a href="index_de.html"><img src="lib/de.png" title="Deutsch" alt="Deutsch"></a> +<a href="index_fr.html"><img src="lib/fr.png" title="Français" alt="Français"></a> +<a href="index_na.html"><img src="lib/nl.png" title="Nederlands" alt="Nederlands"></a> +<a href="index_na.html"><img src="lib/se.png" title="Svenska" alt="Svenska"></a> + +</div> +<h2>Un mini guide pour faire un serveur web anonyme utilisant I2P</h2> + + <p>C'est votre eepsite qui fonctionne sur votre propre serveur web anonyme I2P. Afin de le mettre en route, simplement éditer les fichiers sous ./eepsite/docroot/ + et ils seront accessibles aux autres internautes dès que vous avez suivi les instructions suivantes. + Avec I2P, on accède aux eepsites en utilisant une 'clé', qui est réprésentée par une chaîne de caractères de base64. + (Cette 'clé' est un analogue d'une adresse IP et elle est montrée sur l'eepsite's I2PTunnel + <a href="http://127.0.0.1:7657/i2ptunnel/edit.jsp?tunnel=3">Page de configuration</a>). + Les instructions ci dessous expliquent comment associer un nom de site tel que "monsite.i2p" à votre clé et ensuite comment lancer votre eepsite.</p> + <p>Vous pouvez accéder votre eepsite localement via + <a href="http://127.0.0.1:7658/">http://127.0.0.1:7658/</a>. +</p> + + <h2>Comment configurer et annoncer votre eepsite</h2> + Votre eepsite ne fonctionne pas par défaut. + Après que vous l'ayez lancé, il sera difficile à trouver pour les internautes, car ils n'ont pas le nom de votre site et votre longue clé base64. + + Vous pourriez simplement distribuer cette très longue clé manuellement. Mais, heureusement il y un carnet d'adresse I2P + et plusieurs manières faciles de faire connaitre votre eepsite. Voici les instructions détaillées : + <ul> + <li>Choissisez un nom pour votre eepsite (<i>quelquechose</i>.i2p). Tout en minuscule. + D'abord, vérifiez dans le carnet d'adresse de votre router + <a href="http://127.0.0.1:7657/susidns/addressbook.jsp?book=router&filter=none">ici</a>, + ou dans le fichier i2p/hosts.txt pour voir si le nom a déjà été pris. + Entrez le nouveau nom de votre eepsite sur le + <a href="http://127.0.0.1:7657/i2ptunnel/edit.jsp?tunnel=3">eepsite i2ptunnel page de configuration</a> + où c'est marqué "Website name". Cela remplacera le nom défaut "mysite.i2p". + En outre, cochez "Auto Start". Votre eepsite démarrera automatiquement chaque fois que vous lancez votre router I2P. + Soyez certain de cliquer sur "Save". + <li>Cliquez sur le bouton marqué "start" + <a href="http://127.0.0.1:7657/i2ptunnel/index.jsp">main i2ptunnel page de configuration</a> pour lancer votre eepsite. + Maintenant vous devriez voir "eepsite" indiqué sous "Local Destinations" sur le côté gauche de votre + <a href="http://127.0.0.1:7657/index.jsp">I2P Router Console</a>. + Votre eepsite fonctionne. + <li>Surlignez la clé de "Local destination" en entier sur le + <a href="http://127.0.0.1:7657/i2ptunnel/edit.jsp?tunnel=3">eepsite i2ptunnel page de configuration</a> + et copiez-la pour la coller plus tard. + Soyez certain de copier la clé entière - elle a plus de 500 octets et elle se termine avec "AAAA". + <li>Entrez le nom et coller la clé de destination dans votre + <a href="http://127.0.0.1:7657/susidns/addressbook.jsp?book=master">master address book</a>. + Cliquez sur "Add" pour ajouter la destination à votre carnet d'adresse. + <li>Dans votre explorateur internet, entrez le nom de votre eepsite (<i>quelquechose</i>.i2p) et vous devriez vous retrouver sur cette page. + Avec un peu de chance - si vous êtes arrivé ici, c'est que ça a marché ! + <li>Avant de parler à tout le monde de votre nouvel eepsite, vous devriez ajouter du contenu. + Allez à i2p/eepsite/docroot et remplacez la page index.html avec votre propre page. Les dossiers virtuels fonctionnent, donc vous pouvez héberger un sous-dossier sans explicitement ajouter des liens vers des fichiers. Si vous avez besoin d'un gabarit pour un site de base, n'hésitez pas à utiliser et à changer <a href="pagetemplate.html">cette page</a> et <a href="lib/">contenu</a>! +</ul> +<h2>Enregistrer votre propre .I2P domaine</h2><ul> + <li>Maintenant il faut ajouter votre eepsite au carnet d'adresse hébergé par un site + tel que <a href="http://stats.i2p/">stats.i2p</a>. + C'est-à-dire, vous devez entrer + votre nom d'eepsite et sa clé dans l'interface web d'un ou plus de ces sites. + Voici <a href="http://stats.i2p/i2p/addkey.html">le formulaire pour l'entrée d'une clé à stats.i2p.</a> + Encore, votre clé est la "Local destination", disponible en entier ici + <a href="http://127.0.0.1:7657/i2ptunnel/edit.jsp?tunnel=3">eepsite i2ptunnel page de configuration.</a> + Prenez toute la clé, souvenez qu'elle se termine en "AAAA". + N'oubliez pas de cliquer sur "add a key". + Vérifiez que le site montre que la clé a été correctement ajoutée. + Comme beaucoup de routers se mettent à jour regulièrement à partir de ces sites, en quelques heures d'autres internautes seront capables de trouver et d'accéder à votre eepsite simplement en tapant <i>quelquechose</i>.i2p dans leurs explorateurs internet. +</ul><h2>Comment ajouter des abonnements au carnet d'adresse.</h2><ul> + <li>En parlant de mises à jour de carnet d'adresse, il serait prudent d'ajouter quelques carnets d'adresses de plus + à votre <a href="http://127.0.0.1:7657/susidns/subscriptions.jsp">subscription list.</a> Allez sur votre page d'abonnements et ajoutez quelques listes directement ci dessous afin que votre liste d'hôtes soit mise à jour automatiquement :<ul> + <li><a href="http://tino.i2p/hosts.txt">http://tino.i2p/hosts.txt</a> + <li><a href="http://stats.i2p/cgi-bin/newhosts.txt">http://stats.i2p/cgi-bin/newhosts.txt</a> + <li><a href="http://i2host.i2p/cgi-bin/i2hostetag">http://i2host.i2p/cgi-bin/i2hostetag</a></ul> + <li>Si vous êtes pressé et que vous ne pouvez pas attendre quelques heures, vous pouvez demander aux autres d'utiliser un "jump" (service d'aide de ré-direction d'adresse). + Cela marchera en quelques minutes après que vous ayez entré votre clé dans le carnet d'adresse sur le même site. + Testez-le vous-même en entrant : + http://stats.i2p/cgi-bin/jump.cgi?a=<i>quelquechose</i>.i2p + ou http://i2host.i2p/cgi-bin/i2hostjump?<i>quelquechose</i>.i2p + dans votre explorateur internet. + Dès que cela fonctionne, vous pouvez en parler aux autres. + <li>Certains personnes vérifient les nouveaux eepsites sur les listes tels que + <a href="http://inproxy.tino.i2p/status.php">inproxy.tino.i2p/status.php</a>. Vous pouvez commencer à avoir + quelques visiteurs. Il y a beaucoup des manières d'informers les autres. Voici quelques idées : + <ul> + <li>Poster un message sur le <a href="http://forum.i2p/viewforum.php?f=16">Eepsite announce forum</a> + sur <a href="http://forum.i2p/">forum.i2p</a>. + <li>Parlez aux autres sur les canaux #i2p ou #i2p-chat sur IRC. + <li>Mettez-le dans un post <a href="http://syndie.i2p2.de/">le nouveau Syndie</a>. + <li>Placez-le sur <a href="http://ugha.i2p/EepsiteIndex">Ugha's Eepsite Index Wiki</a> + </ul> + A noter que certains sites recommandent de coller la clé de destination directement. Vous pouvez si vous voulez, + mais si vous avez déjà réussi à poster la clé sur un service de "add key" (type stats.i2p), et attendu 24 heures pour que le carnet d'adresse + se propage aux autres, cela ne doit pas être nécessaire. </ul> +<h2>Plus d'assistance</h2><ul> + <li>Si vous avez plus de questions, trouvez du soutien à ces endroits : +<ul> + <li>Notre canal IRC de soutien : <ul><li><a href="irc://irc.freenode.net/i2p">#i2p sur Freenode</a> + <li>En anonymat via votre <a href="irc://127.0.0.1:6668/i2p">I2P IRC tunnel</a>.</ul> + <li><a href="http://forum.i2p/viewforum.php?f=10">The technical problems section</a> sur + <a href="http://forum.i2p/">forum.i2p</a>.</ul> + </ul><div class="notify"> +<b>Note:</b> This page, the website and the console all need translating into YOUR language if it's not already been done or in progress. Please consider helping the project grow by <a href="http://www.i2p2.i2p/getinvolved.html">volunteering your time</a> to translate. Contact the project via the IRC channel listed above. Thanks in advance!</div> +<hr><div class="footnote"> +Document last edited: November 2009.</div> +</div></div> + </body> +</html> diff --git a/installer/resources/ahelper-conflict-header.ht b/installer/resources/proxy/ahelper-conflict-header.ht similarity index 85% rename from installer/resources/ahelper-conflict-header.ht rename to installer/resources/proxy/ahelper-conflict-header.ht index 41ae9ac47a4043f8ca86164aab141549639f7592..670a64693c92b85b0dfc7f87b18feb19b5ad9802 100644 --- a/installer/resources/ahelper-conflict-header.ht +++ b/installer/resources/proxy/ahelper-conflict-header.ht @@ -1,17 +1,17 @@ HTTP/1.1 409 Conflict -Content-Type: text/html; charset=iso-8859-1 +Content-Type: text/html; charset=UTF-8 Cache-control: no-cache Connection: close Proxy-Connection: close <html><head> <title>I2P Warning: Destination key conflict</title> -<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" /> -<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" /> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > </head> <body> <div class=logo> - <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"/></a><hr> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/">Addressbook</a> </div> <div class=warning id=warning> @@ -20,9 +20,9 @@ The addresshelper link you followed specifies a different destination key than a host entry in your host database. Someone could be trying to impersonate another eepsite, or people have given two eepsites identical names. -<P/> +<p> You can resolve the conflict by considering which key you trust, and either discarding the addresshelper link, discarding the host entry from your host database, or naming one of them differently. -<P/> +<p> diff --git a/installer/resources/proxy/ahelper-conflict-header_zh.ht b/installer/resources/proxy/ahelper-conflict-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..b537de9350a21e10c3095bfac9932a817e5a867a --- /dev/null +++ b/installer/resources/proxy/ahelper-conflict-header_zh.ht @@ -0,0 +1,26 @@ +HTTP/1.1 409 Conflict +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 目标密钥冲突</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">设置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/">地址簿</a> +</div> +<div class=warning id=warning> +<h3>警告: 目标密钥冲突</h3> +您所打开的地址跳转链接中所指定的目标密钥 +与您I2P路由地址簿中对应匿名站点的密钥地址不同。 +可能有人在伪造匿名地址或有人为自己的匿名网站设定了相同的域名。 +<p> +您需要选择并信任一个目标密钥,才能解决这一冲突, +您可以通过直接输入这个.i2p网址利用地址簿中的目标密钥访问 +或在地址簿删除对应的域名或为其改名来信任当前的跳转链接。 +<p> diff --git a/installer/resources/proxy/denied-header.ht b/installer/resources/proxy/denied-header.ht new file mode 100644 index 0000000000000000000000000000000000000000..65c042e80e0c5a488df9ae4a0d00cb9e5999a8b7 --- /dev/null +++ b/installer/resources/proxy/denied-header.ht @@ -0,0 +1,20 @@ +HTTP/1.1 403 Request Denied +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P Warning: Request Denied</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/">Addressbook</a> +</div> +<div class=warning id=warning> +<h3>Warning: Request Denied</h3> +You attempted to connect to a non-I2P website or location. +</div> diff --git a/installer/resources/proxy/denied-header_zh.ht b/installer/resources/proxy/denied-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..54568ee4974bdff64ec0058d10b65944d6a2faab --- /dev/null +++ b/installer/resources/proxy/denied-header_zh.ht @@ -0,0 +1,20 @@ +HTTP/1.1 403 Request Denied +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 请求被拒绝</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">设置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/">地址簿</a> +</div> +<div class=warning id=warning> +<h3>警告: 请求被拒绝</h3> +您正试图连接非I2P内的网站或地址。 +</div> diff --git a/installer/resources/dnf-header.ht b/installer/resources/proxy/dnf-header.ht similarity index 84% rename from installer/resources/dnf-header.ht rename to installer/resources/proxy/dnf-header.ht index d3adc82611bb7a43a7f2e0190bed3b36bc2e0410..bb00373a00df631d01f5e3ce271031a467e8bce0 100644 --- a/installer/resources/dnf-header.ht +++ b/installer/resources/proxy/dnf-header.ht @@ -1,17 +1,17 @@ HTTP/1.1 504 Gateway Timeout -Content-Type: text/html; charset=iso-8859-1 +Content-Type: text/html; charset=UTF-8 Cache-control: no-cache Connection: close Proxy-Connection: close <html><head> <title>I2P Warning: Eepsite not reachable</title> -<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" /> -<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" /> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > </head> <body> <div class=logo> - <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"/></a><hr> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/index.jsp">Addressbook</a> </div> <div class=warning id=warning> diff --git a/installer/resources/proxy/dnf-header_zh.ht b/installer/resources/proxy/dnf-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..1cf39c2e5e58b34ac77e313b2b8e7e15c047e871 --- /dev/null +++ b/installer/resources/proxy/dnf-header_zh.ht @@ -0,0 +1,24 @@ +HTTP/1.1 504 Gateway Timeout +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 匿名站点不可达</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">设置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/index.jsp">地址簿</a> +</div> +<div class=warning id=warning> +<h3>警告: 匿名站点不可达</h3> +无法打开此匿名站点。 +此匿名站点可能不在线(时区差异、对方路由器繁忙等), +或您的路由器在网络中的整合度不佳。 +你可以尝试 +<a href="javascript: window.location.reload()">重试</a>。 +<hr><b>找不到一下目标:</b><BR><BR> diff --git a/installer/resources/dnfb-header.ht b/installer/resources/proxy/dnfb-header.ht similarity index 85% rename from installer/resources/dnfb-header.ht rename to installer/resources/proxy/dnfb-header.ht index ec17ebfa30f50887a5d127823af34d158365015f..d16ab75bd76c8a863337707d525b4ae50468aba5 100644 --- a/installer/resources/dnfb-header.ht +++ b/installer/resources/proxy/dnfb-header.ht @@ -1,17 +1,17 @@ HTTP/1.1 400 Destination Not Found -Content-Type: text/html; charset=iso-8859-1 +Content-Type: text/html; charset=UTF-8 Cache-control: no-cache Connection: close Proxy-Connection: close <html><head> <title>I2P Warning: Invalid eepsite destination</title> -<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" /> -<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" /> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > </head> <body> <div class=logo> - <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"/></a><hr> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/">Addressbook</a> </div> <div class=warning id=warning> diff --git a/installer/resources/proxy/dnfb-header_zh.ht b/installer/resources/proxy/dnfb-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..8788caed5ac0a4fc49bab272427dcb5277e5cd2a --- /dev/null +++ b/installer/resources/proxy/dnfb-header_zh.ht @@ -0,0 +1,23 @@ +HTTP/1.1 400 Destination Not Found +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 站点目标无效</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">配置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/">地址簿</a> +</div> +<div class=warning id=warning> +<h3>警告: 目标无效</h3> +匿名站点所对应的目标密钥无效因而无法访问。 +或许您复制的Base64字符串有误,或者您所点击的跳转链接有问题。 +也许对方的 I2P 主机目前不在线。您可以选择 +<a href="javascript: window.location.reload()">重试</a>. +<hr><b>找不到以下目标:</b><BR><BR> diff --git a/installer/resources/dnfh-header.ht b/installer/resources/proxy/dnfh-header.ht similarity index 88% rename from installer/resources/dnfh-header.ht rename to installer/resources/proxy/dnfh-header.ht index b387727af8ed5cbb2243548cf28bee00c99113bc..7ff802b5792a453bc7495feebfa8cce3b2ddf99a 100644 --- a/installer/resources/dnfh-header.ht +++ b/installer/resources/proxy/dnfh-header.ht @@ -1,17 +1,17 @@ HTTP/1.1 404 Domain Not Found -Content-Type: text/html; charset=iso-8859-1 +Content-Type: text/html; charset=UTF-8 Cache-control: no-cache Connection: close Proxy-Connection: close <html><head> <title>I2P Warning: Eepsite unknown</title> -<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" /> -<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" /> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > </head> <body> <div class=logo> - <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"/></a><hr> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/index.jsp">Addressbook</a> </div> <div class=warning id=warning> diff --git a/installer/resources/proxy/dnfh-header_zh.ht b/installer/resources/proxy/dnfh-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..122ea6f1cde6096b3d205ec316c091344d0dce20 --- /dev/null +++ b/installer/resources/proxy/dnfh-header_zh.ht @@ -0,0 +1,26 @@ +HTTP/1.1 404 Domain Not Found +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 未知站点</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">设置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/index.jsp">地址簿</a> +</div> +<div class=warning id=warning> +<h3>警告: 地址簿中的找不到此站点</h3> +您所访问的匿名站点(的目标密钥)不存在于您路由器的地址簿中。 +检查链接,或寻找对应的BASE64地址. +如果您知道对应的BASE64地址请通过 +<a href="http://127.0.0.1:7657/susidns/addressbook.jsp?book=master">SusiDNS</a> +将其复制入您的 userhosts.txt 中,直接使用 BASE64 地址访问,或使用下面的跳转链接。<br><br> +经常见到此页面? 请参见 <a href="http://www.i2p2.i2p/faq.html#subscriptions"> FAQ 常见问答</a> +中的 <a href="http://127.0.0.1:7657/susidns/config.jsp">添加更多订阅到地址簿中</a>。<hr> +<b>找不到以下目标:</b><BR><BR> diff --git a/installer/resources/dnfp-header.ht b/installer/resources/proxy/dnfp-header.ht similarity index 87% rename from installer/resources/dnfp-header.ht rename to installer/resources/proxy/dnfp-header.ht index 1cea2df69787757e94c6bb82d4a22f604ce0b59a..9f627bb8d2cce92c3a299d9bde1e166232d9935d 100644 --- a/installer/resources/dnfp-header.ht +++ b/installer/resources/proxy/dnfp-header.ht @@ -1,17 +1,17 @@ HTTP/1.1 504 Gateway Timeout -Content-Type: text/html; charset=iso-8859-1 +Content-Type: text/html; charset=UTF-8 Cache-control: no-cache Connection: close Proxy-Connection: close <html><head> <title>I2P Warning: Outproxy Not Found</title> -<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" /> -<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" /> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > </head> <body> <div class=logo> - <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"/></a><hr> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/">Addressbook</a> </div> <div class=warning id=warning> diff --git a/installer/resources/proxy/dnfp-header_zh.ht b/installer/resources/proxy/dnfp-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..b211c4bf4012d2c941f9302551eb1cded8fac2fe --- /dev/null +++ b/installer/resources/proxy/dnfp-header_zh.ht @@ -0,0 +1,28 @@ +HTTP/1.1 504 Gateway Timeout +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 未找到出口代理</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">设置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/">地址簿</a> +</div> +<div class=warning id=warning> +<h3>警告: I2P 未找到代理</h3> +未找到 WWW 出口代理. +它可能以下线, 或网络拥堵,或你的路由器与网络 +尚未良好整合。您可以 +<a href="javascript: parent.window.location.reload()">重试</a> +这将从所设置的所有出口代理中随机选择一个代理做出口。 +<a href="http://127.0.0.1:7657/i2ptunnel/index.jsp">点此</a> +(如果您设置了超过1个的出口代理地址)。 +如果您总是遇到此错误,你也许需要修改出口代理列表了 +<a href="http://127.0.0.1:7657/i2ptunnel/edit.jsp?tunnel=0">点此</a>. +<hr><b>找不到以下目标:</b><BR><BR> diff --git a/installer/resources/proxy/localhost-header.ht b/installer/resources/proxy/localhost-header.ht new file mode 100644 index 0000000000000000000000000000000000000000..cbb2715cb6ca29effdda10fe0c933ce18ec233a4 --- /dev/null +++ b/installer/resources/proxy/localhost-header.ht @@ -0,0 +1,23 @@ +HTTP/1.1 403 Access Denied +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P Warning: Request Denied</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<!----------------------------- + Let's not infinite loop here.... +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/">Addressbook</a> +</div> +------------------------------> +<div class=warning id=warning> +<h3>Warning: Localhost Access</h3> +Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations. +</div> diff --git a/installer/resources/proxy/localhost-header_zh.ht b/installer/resources/proxy/localhost-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..daed21f2141f975a5e034017d13e674eddb5d19f --- /dev/null +++ b/installer/resources/proxy/localhost-header_zh.ht @@ -0,0 +1,23 @@ +HTTP/1.1 403 Access Denied +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 请求被拒绝</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<!----------------------------- + Let's not infinite loop here.... +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">设置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/">地址簿</a> +</div> +------------------------------> +<div class=warning id=warning> +<h3>警告: 企图访问 Localhost </h3> +您的浏览器配置有误,请不要使I2P代理访问路由器控制台或其他本地(Localhost)地址。 +</div> diff --git a/installer/resources/proxy/noproxy-header.ht b/installer/resources/proxy/noproxy-header.ht new file mode 100644 index 0000000000000000000000000000000000000000..0459c2844e973c8efacff6c34e73d79196bf781f --- /dev/null +++ b/installer/resources/proxy/noproxy-header.ht @@ -0,0 +1,21 @@ +HTTP/1.1 503 Service Unavailable +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P Warning: No outproxy configured</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/">Addressbook</a> +</div> +<div class=warning id=warning> +<h3>Warning: No Outproxy Configured</h3> +Your request was for a site outside of I2P, but you have no +HTTP outproxy configured. Please configure an outproxy in I2PTunnel. +</div> diff --git a/installer/resources/proxy/noproxy-header_zh.ht b/installer/resources/proxy/noproxy-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..92dafdd2572a31d6c3f5fd7b49cef21818e7a65a --- /dev/null +++ b/installer/resources/proxy/noproxy-header_zh.ht @@ -0,0 +1,21 @@ +HTTP/1.1 503 Service Unavailable +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 没有设置出口代理</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">设置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/">地址簿</a> +</div> +<div class=warning id=warning> +<h3>警告: 没有设置出口代理</h3> +你请求的网站在I2P网络外,但您的I2P没有设置HTTP出口代理 +请在 I2P Tunnel(本地目标) 中设置HTTP代理隧道. +</div> diff --git a/installer/resources/proxy/protocol-header.ht b/installer/resources/proxy/protocol-header.ht new file mode 100644 index 0000000000000000000000000000000000000000..12474eb49a4dbc3cfc88362f18f6426307bfee05 --- /dev/null +++ b/installer/resources/proxy/protocol-header.ht @@ -0,0 +1,21 @@ +HTTP/1.1 403 Bad Protocol +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P Warning: Non-HTTP Protocol</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">Configuration</a> <a href="http://127.0.0.1:7657/help.jsp">Help</a> <a href="http://127.0.0.1:7657/susidns/">Addressbook</a> +</div> +<div class=warning id=warning> +<h3>Warning: Non-HTTP Protocol</h3> +The request uses a bad protocol. +The I2P HTTP Proxy supports http:// requests ONLY. Other protocols such as https:// and ftp:// are not allowed. +</div> diff --git a/installer/resources/proxy/protocol-header_zh.ht b/installer/resources/proxy/protocol-header_zh.ht new file mode 100644 index 0000000000000000000000000000000000000000..070f1a46299df240a37054890ec58aa541aa8510 --- /dev/null +++ b/installer/resources/proxy/protocol-header_zh.ht @@ -0,0 +1,21 @@ +HTTP/1.1 403 Bad Protocol +Content-Type: text/html; charset=UTF-8 +Cache-control: no-cache +Connection: close +Proxy-Connection: close + +<html><head> +<title>I2P 警告: 非HTTP请求</title> +<link rel="shortcut icon" href="http://proxy.i2p/themes/console/images/favicon.ico" > +<link href="http://proxy.i2p/themes/console/default/console.css" rel="stylesheet" type="text/css" > +</head> +<body> +<div class=logo> + <a href="http://127.0.0.1:7657/index.jsp" title="Router Console"><img src="http://proxy.i2p/themes/console/images/i2plogo.png" alt="I2P Router Console" border="0"></a><hr> + <a href="http://127.0.0.1:7657/config.jsp">设置</a> <a href="http://127.0.0.1:7657/help.jsp">帮助</a> <a href="http://127.0.0.1:7657/susidns/">地址簿</a> +</div> +<div class=warning id=warning> +<h3>警告: 非HTTP请求</h3> +请求使用了错误的协议 +I2P HTTP 代理【只】支持 http:// 请求,不支持其他协议例如 https:// and ftp:// 。 +</div> diff --git a/installer/resources/themes/console/midnight/console.css b/installer/resources/themes/console/midnight/console.css index acc81de777a73be86f3310ccb429ac988631c28d..80b1cbc14fc838981675f3a730cd5b1c69d44092 100644 --- a/installer/resources/themes/console/midnight/console.css +++ b/installer/resources/themes/console/midnight/console.css @@ -1,5 +1,5 @@ /* I2P Theme: Midnight */ -/* I2P Description: Minimalist Midnight Blue, based on Classic theme.*/ +/* Description: Minimalist Midnight Blue, based on Classic theme.*/ /* Author: Dr|Z3d */ @@ -107,29 +107,38 @@ div.warning hr { } div.warning h3 { + border: 0; border-bottom: 1px solid #fb7; padding-bottom: 10px; + padding-left: 0; + font-variant: small-caps; + text-transform: capitalize; + font-size: 12.5pt; } /* console error messages */ div.sorry { - padding: 20px; + padding: 20px 20px 20px 70px; background: #003; - margin: -2px 1px 0 200px; + margin: 0 5px 0 200px; border: 1px solid #99f; + border-top: 0; text-align: justify; -moz-box-shadow: inset 0px 0px 0px 1px #d00; word-wrap: break-word; font-weight: bold; color: #eef; + background-image: url("../images/errortriangle.png"); + background-position: 15px center; + background-repeat: no-repeat; } div.sorry hr { - color: #eef; - background: #eef; + color: #99f; + background: #99f; height: 1px; - border: 1px solid #99f; + border: 0; margin: 10px 0; } @@ -153,7 +162,7 @@ div.routersummary { width: 190px; color: inherit; margin: 0; - padding: 10px 1px 7px 1px; + padding: 10px 1px 5px 1px; text-align: center !important; border: 1px solid #99f; font-size: 9pt; @@ -174,6 +183,10 @@ div.routersummary hr { margin: 8px -1px 7px -1px; } +div.routersummary hr:last-child { + display: none; +} + div.routersummary h3 { border: 0px solid #f00; font-size: 9.5pt; @@ -251,6 +264,11 @@ div.routersummary form { margin-bottom: -8px !important; } +div.routersummary form:last-child { + padding-top: 3px !important; + margin-bottom: -10px !important; +} + div.refresh { margin-top: 10px !important; margin-bottom: 10px !important; @@ -288,7 +306,6 @@ div.main { text-align: left; color: #eef; min-width: 570px; - -moz-box-shadow: inset 0px 0px 2px 0px #005; } div.main ul { @@ -321,6 +338,11 @@ div.main textarea { div.main h2 { margin-top: 20px; margin-bottom: -5px; + padding-bottom: 10px !important; +} + +table h2 { + padding-bottom: 15px; } div.welcome { @@ -495,33 +517,38 @@ h1 { text-shadow: 0px 0px 2px rgba(255, 255, 255, 0.4); text-align: center; border: 1px solid #99f; - padding: 13px 10px 12px 10px; + padding: 15px 10px 15px 10px; margin: 5px 5px 0 200px; line-height: 93%; text-transform: uppercase; letter-spacing: 0.3em; background: #000008; min-width: 600px; - -moz-box-shadow: inset 0px 0px 4px 2px #00000A; line-height: 100%; color: #fff; } h2 { - font-size: 14pt; + font-size: 13pt; padding: 10px 10px 10px 10px; border: 1px solid #77f; border-top: 1px solid #99f; border-left: 1px solid #99f; - letter-spacing: 0.04em; - background: #00000A; + background: #000008; + background-image: url("images/h2bg.png"); + background-repeat: no-repeat; + background-position: right center; + font-variant: small-caps; + text-transform: capitalize; + letter-spacing: 0.07em; } h3 { - font-size: 12pt; - padding: 0 0px 5px 0px; - border-bottom: 1px solid #99f; - border-top: 0px solid #99f; + font-size: 11pt; + padding: 5px 10px; + border: 1px solid #99f; + border-right: 1px solid #77f; + border-bottom: 1px solid #77f; letter-spacing: 0.04em; margin-bottom: 10px; font-weight: bold !important; @@ -600,11 +627,11 @@ hr { font-size: 8pt; color: #eef; text-align: center; - margin: -7px 0 7px 0; + margin: -5px 0 5px 0; background: #000; border: 1px solid #99f; border-top: 0; - padding: 4px 0 2px 0; + padding: 3px 0; } div.joblog { @@ -722,7 +749,7 @@ p { padding-bottom: -2px; text-align: justify; margin-top: 5px !important; - margin-left:5px !important; + margin-left: 5px !important; } .links li { @@ -786,33 +813,30 @@ tt { } div.graphspanel { - padding: 5px 0px 20px 0px; + padding: 10px 0px 20px 0px; margin: -16px -16px -11px -16px; background: #000012; -moz-border-radius: 4px; -khtml-border-radius: 4px; border-radius: 4px; border: 1px solid #99f; - -moz-box-shadow: inset 0px 0px 1px 0px #002; text-align: center !important; } div.graphspanel img { - border: 1px solid #77f; + border: 1px solid #99f; padding: 2px; margin: 6px; - background: #ccf; - -moz-box-shadow: inset 0px 0px 0px 0px #002; + background: #00000A; opacity: 0.9; } div.graphspanel img:hover { - border: 1px solid #003; + border: 1px solid #f60; padding: 2px; margin: 6px; text-align: center !important; - background: #eef; - -moz-box-shadow: inset 0px 0px 2px 1px #f60; + background: #002; opacity: 1; } diff --git a/installer/resources/themes/console/midnight/images/h2bg.png b/installer/resources/themes/console/midnight/images/h2bg.png new file mode 100644 index 0000000000000000000000000000000000000000..936dada60815acab7288369ec3e63c4506bd877b Binary files /dev/null and b/installer/resources/themes/console/midnight/images/h2bg.png differ diff --git a/router/java/src/net/i2p/router/Blocklist.java b/router/java/src/net/i2p/router/Blocklist.java index e903c364b617273746074a8ccda9ecaa53876765..f0f7603ac5eae48d942f0a3b87e01ad8532828f4 100644 --- a/router/java/src/net/i2p/router/Blocklist.java +++ b/router/java/src/net/i2p/router/Blocklist.java @@ -111,11 +111,13 @@ public class Blocklist { } for (Iterator iter = _peerBlocklist.keySet().iterator(); iter.hasNext(); ) { Hash peer = (Hash) iter.next(); - String reason = "Banned by router hash"; + String reason; String comment = (String) _peerBlocklist.get(peer); if (comment != null) - reason = reason + ": " + comment; - _context.shitlist().shitlistRouterForever(peer, reason); + reason = _x("Banned by router hash: {0}"); + else + reason = _x("Banned by router hash"); + _context.shitlist().shitlistRouterForever(peer, reason, comment); } _peerBlocklist = null; @@ -659,7 +661,7 @@ public class Blocklist { */ public void shitlist(Hash peer) { // Temporary reason, until the job finishes - _context.shitlist().shitlistRouterForever(peer, "IP Banned"); + _context.shitlist().shitlistRouterForever(peer, _x("IP banned")); if (! "true".equals( _context.getProperty(PROP_BLOCKLIST_DETAIL, "true"))) return; boolean shouldRunJob; @@ -729,16 +731,17 @@ public class Blocklist { } if (match(ipint, toEntry(e.ip1, e.ip2))) { try { in.close(); } catch (IOException ioe) {} - String reason = "IP "; - for (int i = 0; i < 4; i++) { - reason = reason + (ip[i] & 0xff); - if (i != 3) - reason = reason + '.'; - } - reason = reason + " banned by " + BLOCKLIST_FILE_DEFAULT + " entry \"" + buf + "\""; + String reason = _x("IP banned by blocklist.txt entry {0}"); + // only one translate parameter for now + //for (int i = 0; i < 4; i++) { + // reason = reason + (ip[i] & 0xff); + // if (i != 3) + // reason = reason + '.'; + //} + //reason = reason + " banned by " + BLOCKLIST_FILE_DEFAULT + " entry \"" + buf + "\""; if (_log.shouldLog(Log.WARN)) _log.warn("Shitlisting " + peer + " " + reason); - _context.shitlist().shitlistRouterForever(peer, reason); + _context.shitlist().shitlistRouterForever(peer, reason, buf.toString()); return; } buf.setLength(0); @@ -791,6 +794,16 @@ public class Blocklist { out.flush(); } + /** + * Mark a string for extraction by xgettext and translation. + * Use this only in static initializers. + * It does not translate! + * @return s + */ + private static final String _x(String s) { + return s; + } + public static void main(String args[]) { Blocklist b = new Blocklist(); if ( (args != null) && (args.length == 1) ) diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 6d9b6bc650a299fdd8a43d04880fbd2a1fb53624..4c8aefc89f6dd4518753c53ae89c5a95738b6c6a 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,7 +18,7 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Monotone"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 15; + public final static long BUILD = 18; /** for example "-test" */ public final static String EXTRA = ""; public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA; diff --git a/router/java/src/net/i2p/router/Shitlist.java b/router/java/src/net/i2p/router/Shitlist.java index 09ee74849e53fe7d2b2b6a9c6088e86a4fccd397..482d4264c0e0a88b6b2e0e37a096e72ba0ef229f 100644 --- a/router/java/src/net/i2p/router/Shitlist.java +++ b/router/java/src/net/i2p/router/Shitlist.java @@ -12,12 +12,11 @@ import java.io.IOException; import java.io.Writer; import java.util.concurrent.ConcurrentHashMap; import java.util.ArrayList; -import java.util.Comparator; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.TreeMap; import net.i2p.data.DataHelper; import net.i2p.data.Hash; @@ -36,13 +35,15 @@ public class Shitlist { private RouterContext _context; private Map<Hash, Entry> _entries; - private static class Entry { + public static class Entry { /** when it should expire, per the i2p clock */ - long expireOn; + public long expireOn; /** why they were shitlisted */ - String cause; + public String cause; + /** separate code so cause can contain {0} for translation */ + public String causeCode; /** what transports they were shitlisted for (String), or null for all transports */ - Set<String> transports; + public Set<String> transports; } public final static long SHITLIST_DURATION_MS = 20*60*1000; @@ -95,17 +96,32 @@ public class Shitlist { return _entries.size(); } + /** for ShitlistRenderer in router console */ + public Map<Hash, Entry> getEntries() { + return new HashMap<Hash, Entry>(_entries); + } + public boolean shitlistRouter(Hash peer) { return shitlistRouter(peer, null); } public boolean shitlistRouter(Hash peer, String reason) { return shitlistRouter(peer, reason, null); } + /** ick have to put the reasonCode in the front to avoid ambiguity */ + public boolean shitlistRouter(String reasonCode, Hash peer, String reason) { + return shitlistRouter(peer, reason, reasonCode, null, false); + } public boolean shitlistRouter(Hash peer, String reason, String transport) { return shitlistRouter(peer, reason, transport, false); } public boolean shitlistRouterForever(Hash peer, String reason) { return shitlistRouter(peer, reason, null, true); } + public boolean shitlistRouterForever(Hash peer, String reason, String reasonCode) { + return shitlistRouter(peer, reason, reasonCode, null, true); + } public boolean shitlistRouter(Hash peer, String reason, String transport, boolean forever) { + return shitlistRouter(peer, reason, null, transport, forever); + } + private boolean shitlistRouter(Hash peer, String reason, String reasonCode, String transport, boolean forever) { if (peer == null) { _log.error("wtf, why did we try to shitlist null?", new Exception("shitfaced")); return false; @@ -137,6 +153,7 @@ public class Shitlist { e.expireOn = _context.clock().now() + period; } e.cause = reason; + e.causeCode = reasonCode; e.transports = null; if (transport != null) { e.transports = new ConcurrentHashSet(1); @@ -150,6 +167,7 @@ public class Shitlist { if (old.expireOn > e.expireOn) { e.expireOn = old.expireOn; e.cause = old.cause; + e.causeCode = old.causeCode; } if (e.transports != null) { if (old.transports != null) @@ -157,6 +175,7 @@ public class Shitlist { else { e.transports = null; e.cause = reason; + e.causeCode = reasonCode; } } } @@ -245,44 +264,7 @@ public class Shitlist { return entry != null && entry.expireOn > _context.clock().now() + SHITLIST_DURATION_MAX; } - class HashComparator implements Comparator { - public int compare(Object l, Object r) { - return ((Hash)l).toBase64().compareTo(((Hash)r).toBase64()); - } - } - + /** @deprecated moved to router console */ public void renderStatusHTML(Writer out) throws IOException { - StringBuilder buf = new StringBuilder(1024); - // move to the jsp - //buf.append("<h2>Banned Peers</h2>"); - Map<Hash, Entry> entries = new TreeMap(new HashComparator()); - - entries.putAll(_entries); - - buf.append("<ul>"); - - for (Map.Entry<Hash, Entry> e : entries.entrySet()) { - Hash key = e.getKey(); - Entry entry = e.getValue(); - buf.append("<li>").append(_context.commSystem().renderPeerHTML(key)); - long expires = entry.expireOn-_context.clock().now(); - if (expires < 5l*24*60*60*1000) - buf.append(" Temporary ban expiring in "); - else - buf.append(" Banned until restart or in "); - buf.append(DataHelper.formatDuration(expires)); - Set transports = entry.transports; - if ( (transports != null) && (transports.size() > 0) ) - buf.append(" on the following transport: ").append(transports); - if (entry.cause != null) { - buf.append("<br>\n"); - buf.append(entry.cause); - } - buf.append(" (<a href=\"configpeer.jsp?peer=").append(key.toBase64()).append("#unsh\">unban now</a>)"); - buf.append("</li>\n"); - } - buf.append("</ul>\n"); - out.write(buf.toString()); - out.flush(); } } diff --git a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java index c7cc209c04ba5ad59f5e8f200feaf3a1466296f8..d2bd15d74a5d9e952cf2f6f73f35c495e2e56b59 100644 --- a/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java +++ b/router/java/src/net/i2p/router/networkdb/kademlia/FloodfillPeerSelector.java @@ -85,24 +85,31 @@ class FloodfillPeerSelector extends PeerSelector { } /** + * Sort the floodfills. The challenge here is to keep the good ones + * at the front and the bad ones at the back. If they are all good or bad, + * searches and stores won't work well. + * * @return all floodfills not shitlisted foreverx * @param key the routing key * @param maxNumRouters max to return * Sorted by closest to the key if > maxNumRouters, otherwise not * The list is in 3 groups - sorted by routing key within each group. - * Group 1: No store or lookup failure in last 15 minutes - * Group 2: No store or lookup failure in last 3 minutes + * Group 1: No store or lookup failure in a long time + * Group 2: No store or lookup failure in a little while or + * success newer than failure * Group 3: All others */ public List<Hash> selectFloodfillParticipants(Hash key, int maxNumRouters, KBucketSet kbuckets) { return selectFloodfillParticipants(key, maxNumRouters, null, kbuckets); } - /** 1.5 * PublishLocalRouterInfoJob.PUBLISH_DELAY */ - private static final int NO_FAIL_STORE_OK = 30*60*1000; + /** .75 * PublishLocalRouterInfoJob.PUBLISH_DELAY */ + private static final int NO_FAIL_STORE_OK = 15*60*1000; private static final int NO_FAIL_STORE_GOOD = NO_FAIL_STORE_OK * 2; + /** this must be longer than the max streaming timeout (60s) */ private static final int NO_FAIL_LOOKUP_OK = 5*60*1000; private static final int NO_FAIL_LOOKUP_GOOD = NO_FAIL_LOOKUP_OK * 3; + private static final int MAX_GOOD_RESP_TIME = 5*1000; public List<Hash> selectFloodfillParticipants(Hash key, int howMany, Set<Hash> toIgnore, KBucketSet kbuckets) { List<Hash> ffs = selectFloodfillParticipants(toIgnore, kbuckets); @@ -110,8 +117,8 @@ class FloodfillPeerSelector extends PeerSelector { sorted.addAll(ffs); List<Hash> rv = new ArrayList(howMany); - List<Hash> okff = new ArrayList(howMany); - List<Hash> badff = new ArrayList(howMany); + List<Hash> okff = new ArrayList(ffs.size()); + List<Hash> badff = new ArrayList(ffs.size()); int found = 0; long now = _context.clock().now(); @@ -125,10 +132,11 @@ class FloodfillPeerSelector extends PeerSelector { if (info != null && now - info.getPublished() > 3*60*60*1000) { badff.add(entry); if (_log.shouldLog(Log.DEBUG)) - _log.debug("Skipping, published a while ago: " + entry); + _log.debug("Old: " + entry); } else { PeerProfile prof = _context.profileOrganizer().getProfile(entry); if (prof != null && prof.getDBHistory() != null + && ((int) prof.getDbResponseTime().getRate(10*60*1000).getAverageValue()) < MAX_GOOD_RESP_TIME && prof.getDBHistory().getLastStoreFailed() < now - NO_FAIL_STORE_GOOD && prof.getDBHistory().getLastLookupFailed() < now - NO_FAIL_LOOKUP_GOOD) { // good @@ -137,8 +145,10 @@ class FloodfillPeerSelector extends PeerSelector { rv.add(entry); found++; } else if (prof != null && prof.getDBHistory() != null - && prof.getDBHistory().getLastStoreFailed() < now - NO_FAIL_STORE_OK - && prof.getDBHistory().getLastLookupFailed() < now - NO_FAIL_LOOKUP_OK) { + && (prof.getDBHistory().getLastStoreFailed() <= prof.getDBHistory().getLastStoreSuccessful() + || prof.getDBHistory().getLastLookupFailed() <= prof.getDBHistory().getLastLookupSuccessful() + || (prof.getDBHistory().getLastStoreFailed() < now - NO_FAIL_STORE_OK + && prof.getDBHistory().getLastLookupFailed() < now - NO_FAIL_LOOKUP_OK))) { if (_log.shouldLog(Log.DEBUG)) _log.debug("OK: " + entry); okff.add(entry); @@ -149,8 +159,8 @@ class FloodfillPeerSelector extends PeerSelector { } } } - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Good: " + rv + " OK: " + okff + " Bad: " + badff); + if (_log.shouldLog(Log.INFO)) + _log.info("Good: " + rv + " OK: " + okff + " Bad: " + badff); // Put the ok floodfills after the good floodfills for (int i = 0; found < howMany && i < okff.size(); i++) { diff --git a/router/java/src/net/i2p/router/transport/GetBidsJob.java b/router/java/src/net/i2p/router/transport/GetBidsJob.java index 46ea0601cffa52942d0f9b042021b5b9891b4bb2..55f8cdb7961bf1c4d27ea53abd5639c2a875d158 100644 --- a/router/java/src/net/i2p/router/transport/GetBidsJob.java +++ b/router/java/src/net/i2p/router/transport/GetBidsJob.java @@ -67,7 +67,7 @@ public class GetBidsJob extends JobImpl { if (failedCount == 0) { context.statManager().addRateData("transport.bidFailNoTransports", msg.getLifetime(), 0); // This used to be "no common transports" but it is almost always no transports at all - context.shitlist().shitlistRouter(to, "No transports (hidden or starting up?)"); + context.shitlist().shitlistRouter(to, _x("No transports (hidden or starting up?)")); } else if (failedCount >= facade.getTransportCount()) { context.statManager().addRateData("transport.bidFailAllTransports", msg.getLifetime(), 0); // fail after all transports were unsuccessful @@ -98,4 +98,14 @@ public class GetBidsJob extends JobImpl { msg.discardData(); } + + /** + * Mark a string for extraction by xgettext and translation. + * Use this only in static initializers. + * It does not translate! + * @return s + */ + private static final String _x(String s) { + return s; + } } diff --git a/router/java/src/net/i2p/router/transport/TransportManager.java b/router/java/src/net/i2p/router/transport/TransportManager.java index 3643d010a74ffdad392c19a127e6b8026ba52838..0b988c03e2af103cff3e1c213ba27d38120df379 100644 --- a/router/java/src/net/i2p/router/transport/TransportManager.java +++ b/router/java/src/net/i2p/router/transport/TransportManager.java @@ -447,7 +447,7 @@ public class TransportManager implements TransportEventListener { // Don't shitlist if we aren't talking to anybody, as we may have a network connection issue if (unreachableTransports >= _transports.size() && countActivePeers() > 0) { _context.statManager().addRateData("transport.shitlistOnUnreachable", msg.getLifetime(), msg.getLifetime()); - _context.shitlist().shitlistRouter(peer, "Unreachable on any transport"); + _context.shitlist().shitlistRouter(peer, _x("Unreachable on any transport")); } } else if (rv == null) { _context.statManager().addRateData("transport.noBidsYetNotAllUnreachable", unreachableTransports, msg.getLifetime()); @@ -493,7 +493,7 @@ public class TransportManager implements TransportEventListener { t.renderStatusHTML(out, urlBase, sortFlags); } StringBuilder buf = new StringBuilder(4*1024); - buf.append("<h3>Router Transport Addresses:</h3><pre>\n"); + buf.append("<h3>Router Transport Addresses</h3><pre>\n"); for (int i = 0; i < _transports.size(); i++) { Transport t = (Transport)_transports.get(i); if (t.getCurrentAddress() != null) @@ -508,4 +508,15 @@ public class TransportManager implements TransportEventListener { buf.append("</p>\n"); out.flush(); } + + /** + * Mark a string for extraction by xgettext and translation. + * Use this only in static initializers. + * It does not translate! + * @return s + */ + private static final String _x(String s) { + return s; + } + } diff --git a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java index e204a5750a0009a4f87f00f77b9864433aebfe8b..9cd5f1ad55a2d78679ba822d190db6a5b9a0ae49 100644 --- a/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java +++ b/router/java/src/net/i2p/router/transport/ntcp/EstablishState.java @@ -368,8 +368,9 @@ public class EstablishState { if (diff >= Router.CLOCK_FUDGE_FACTOR) { _context.statManager().addRateData("ntcp.invalidOutboundSkew", diff, 0); _transport.markReachable(_con.getRemotePeer().calculateHash(), false); - _context.shitlist().shitlistRouter(_con.getRemotePeer().calculateHash(), - "Excessive clock skew: " + DataHelper.formatDuration(diff)); + _context.shitlist().shitlistRouter(DataHelper.formatDuration(diff), + _con.getRemotePeer().calculateHash(), + _x("Excessive clock skew: {0}")); fail("Clocks too skewed (" + diff + " ms)", null, true); return; } else if (_log.shouldLog(Log.DEBUG)) { @@ -572,7 +573,9 @@ public class EstablishState { if (diff >= Router.CLOCK_FUDGE_FACTOR) { _context.statManager().addRateData("ntcp.invalidInboundSkew", diff, 0); _transport.markReachable(alice.calculateHash(), true); - _context.shitlist().shitlistRouter(alice.calculateHash(), "Clock skew of " + diff + " ms"); + _context.shitlist().shitlistRouter(DataHelper.formatDuration(diff), + alice.calculateHash(), + _x("Excessive clock skew: {0}")); fail("Clocks too skewed (" + diff + " ms)", null, true); return; } else if (_log.shouldLog(Log.DEBUG)) { @@ -923,4 +926,15 @@ public class EstablishState { e.printStackTrace(); } } + + /** + * Mark a string for extraction by xgettext and translation. + * Use this only in static initializers. + * It does not translate! + * @return s + */ + private static final String _x(String s) { + return s; + } + } diff --git a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java index 569fe786a38cf8e02cb0e668bb5a3b9ef5bc529c..9be1c26adff8d347968f12c468e65b8e594bbd6f 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerTestManager.java @@ -19,23 +19,99 @@ import net.i2p.util.SimpleScheduler; import net.i2p.util.SimpleTimer; /** - * + * From udp.html on the website: + +<p>The automation of collaborative reachability testing for peers is +enabled by a sequence of PeerTest messages. With its proper +execution, a peer will be able to determine their own reachability +and may update its behavior accordingly. The testing process is +quite simple:</p> + +<pre> + Alice Bob Charlie + PeerTest -------------------> + PeerTest--------------------> + <-------------------PeerTest + <-------------------PeerTest + <------------------------------------------PeerTest + PeerTest------------------------------------------> + <------------------------------------------PeerTest +</pre> + +<p>Each of the PeerTest messages carry a nonce identifying the +test series itself, as initialized by Alice. If Alice doesn't +get a particular message that she expects, she will retransmit +accordingly, and based upon the data received or the messages +missing, she will know her reachability. The various end states +that may be reached are as follows:</p> + +<ul> +<li>If she doesn't receive a response from Bob, she will retransmit +up to a certain number of times, but if no response ever arrives, +she will know that her firewall or NAT is somehow misconfigured, +rejecting all inbound UDP packets even in direct response to an +outbound packet. Alternately, Bob may be down or unable to get +Charlie to reply.</li> + +<li>If Alice doesn't receive a PeerTest message with the +expected nonce from a third party (Charlie), she will retransmit +her initial request to Bob up to a certain number of times, even +if she has received Bob's reply already. If Charlie's first message +still doesn't get through but Bob's does, she knows that she is +behind a NAT or firewall that is rejecting unsolicited connection +attempts and that port forwarding is not operating properly (the +IP and port that Bob offered up should be forwarded).</li> + +<li>If Alice receives Bob's PeerTest message and both of Charlie's +PeerTest messages but the enclosed IP and port numbers in Bob's +and Charlie's second messages don't match, she knows that she is +behind a symmetric NAT, rewriting all of her outbound packets with +different 'from' ports for each peer contacted. She will need to +explicitly forward a port and always have that port exposed for +remote connectivity, ignoring further port discovery.</li> + +<li>If Alice receives Charlie's first message but not his second, +she will retransmit her PeerTest message to Charlie up to a +certain number of times, but if no response is received she knows +that Charlie is either confused or no longer online.</li> +</ul> + +<p>Alice should choose Bob arbitrarily from known peers who seem +to be capable of participating in peer tests. Bob in turn should +choose Charlie arbitrarily from peers that he knows who seem to be +capable of participating in peer tests and who are on a different +IP from both Bob and Alice. If the first error condition occurs +(Alice doesn't get PeerTest messages from Bob), Alice may decide +to designate a new peer as Bob and try again with a different nonce.</p> + +<p>Alice's introduction key is included in all of the PeerTest +messages so that she doesn't need to already have an established +session with Bob and so that Charlie can contact her without knowing +any additional information. Alice may go on to establish a session +with either Bob or Charlie, but it is not required.</p> + */ class PeerTestManager { private RouterContext _context; private Log _log; private UDPTransport _transport; private PacketBuilder _packetBuilder; - /** map of Long(nonce) to PeerTestState for tests currently in progress */ - private final Map _activeTests; - /** current test we are running, or null */ + /** map of Long(nonce) to PeerTestState for tests currently in progress (as Bob/Charlie) */ + private final Map<Long, PeerTestState> _activeTests; + /** current test we are running (as Alice), or null */ private PeerTestState _currentTest; private boolean _currentTestComplete; - private List _recentTests; + /** as Alice */ + private List<Long> _recentTests; /** longest we will keep track of a Charlie nonce for */ private static final int MAX_CHARLIE_LIFETIME = 10*1000; + /** + * Have seen peer tests (as Alice) get stuck (_currentTest != null) + * so I've thrown some synchronizization on the methods; + * don't know the root cause or whether this fixes it + */ public PeerTestManager(RouterContext context, UDPTransport transport) { _context = context; _transport = transport; @@ -54,7 +130,11 @@ class PeerTestManager { private static final int MAX_TEST_TIME = 30*1000; private static final long MAX_NONCE = (1l << 32) - 1l; //public void runTest(InetAddress bobIP, int bobPort, SessionKey bobIntroKey) { - public void runTest(InetAddress bobIP, int bobPort, SessionKey bobCipherKey, SessionKey bobMACKey) { + + /** + * The next few methods are for when we are Alice + */ + public synchronized void runTest(InetAddress bobIP, int bobPort, SessionKey bobCipherKey, SessionKey bobMACKey) { if (_currentTest != null) { if (_log.shouldLog(Log.WARN)) _log.warn("We are already running a test with bob = " + _currentTest.getBobIP() + ", aborting test with bob = " + bobIP); @@ -85,30 +165,33 @@ class PeerTestManager { private class ContinueTest implements SimpleTimer.TimedEvent { public void timeReached() { - PeerTestState state = _currentTest; - if (state == null) { - // already completed - return; - } else if (expired()) { - testComplete(true); - } else if (_context.clock().now() - state.getLastSendTime() >= RESEND_TIMEOUT) { - if (state.getReceiveBobTime() <= 0) { - // no message from Bob yet, send it again - sendTestToBob(); - } else if (state.getReceiveCharlieTime() <= 0) { - // received from Bob, but no reply from Charlie. send it to - // Bob again so he pokes Charlie - sendTestToBob(); - } else { - // received from both Bob and Charlie, but we haven't received a - // second message from Charlie yet - sendTestToCharlie(); + synchronized (PeerTestManager.this) { + PeerTestState state = _currentTest; + if (state == null) { + // already completed + return; + } else if (expired()) { + testComplete(true); + } else if (_context.clock().now() - state.getLastSendTime() >= RESEND_TIMEOUT) { + if (state.getReceiveBobTime() <= 0) { + // no message from Bob yet, send it again + sendTestToBob(); + } else if (state.getReceiveCharlieTime() <= 0) { + // received from Bob, but no reply from Charlie. send it to + // Bob again so he pokes Charlie + sendTestToBob(); + } else { + // received from both Bob and Charlie, but we haven't received a + // second message from Charlie yet + sendTestToCharlie(); + } + SimpleScheduler.getInstance().addEvent(ContinueTest.this, RESEND_TIMEOUT); } - SimpleScheduler.getInstance().addEvent(ContinueTest.this, RESEND_TIMEOUT); } } } + /** call from a synchronized method */ private boolean expired() { PeerTestState state = _currentTest; if (state != null) @@ -117,6 +200,7 @@ class PeerTestManager { return true; } + /** call from a synchronized method */ private void sendTestToBob() { PeerTestState test = _currentTest; if (!expired()) { @@ -128,6 +212,7 @@ class PeerTestManager { _currentTest = null; } } + /** call from a synchronized method */ private void sendTestToCharlie() { PeerTestState test = _currentTest; if (!expired()) { @@ -153,9 +238,9 @@ class PeerTestManager { /** * Receive a PeerTest message which contains the correct nonce for our current - * test + * test. We are Alice. */ - private void receiveTestReply(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo) { + private synchronized void receiveTestReply(RemoteHostId from, UDPPacketReader.PeerTestReader testInfo) { _context.statManager().addRateData("udp.receiveTestReply", 1, 0); PeerTestState test = _currentTest; if (expired()) @@ -208,6 +293,7 @@ class PeerTestManager { if (_log.shouldLog(Log.WARN)) _log.warn("Bob chose a charlie we already have a session to, cancelling the test and rerunning (bob: " + _currentTest + ", charlie: " + from + ")"); + // why are we doing this instead of calling testComplete() ? _currentTestComplete = true; _context.statManager().addRateData("udp.statusKnownCharlie", 1, 0); honorStatus(CommSystemFacade.STATUS_UNKNOWN); @@ -267,6 +353,9 @@ class PeerTestManager { * Evaluate the info we have and act accordingly, since the test has either timed out or * we have successfully received the second PeerTest from a Charlie. * + * @param forgetTest must be true to clear out this test and allow another + * + * call from a synchronized method */ private void testComplete(boolean forgetTest) { _currentTestComplete = true; @@ -324,7 +413,7 @@ class PeerTestManager { * Receive a test message of some sort from the given peer, queueing up any packet * that should be sent in response, or if its a reply to our own current testing, * adjusting our test state. - * + * We could be Alice, Bob, or Charlie. */ public void receiveTest(RemoteHostId from, UDPPacketReader reader) { _context.statManager().addRateData("udp.receiveTest", 1, 0); @@ -334,10 +423,13 @@ class PeerTestManager { long nonce = testInfo.readNonce(); PeerTestState test = _currentTest; if ( (test != null) && (test.getNonce() == nonce) ) { + // we are Alice receiveTestReply(from, testInfo); return; } - + + // we are Bob or Charlie + if ( (testInfo.readIPSize() > 0) && (testPort > 0) ) { testIP = new byte[testInfo.readIPSize()]; testInfo.readIP(testIP, 0); @@ -360,7 +452,7 @@ class PeerTestManager { // initiated test } else { if (_log.shouldLog(Log.DEBUG)) - _log.debug("We are charlie, as te testIP/port is " + RemoteHostId.toString(testIP) + ":" + testPort + " and the state is unknown for " + nonce); + _log.debug("We are charlie, as the testIP/port is " + RemoteHostId.toString(testIP) + ":" + testPort + " and the state is unknown for " + nonce); // we are charlie, since alice never sends us her IP and port, only bob does (and, // erm, we're not alice, since it isn't our nonce) receiveFromBobAsCharlie(from, testInfo, nonce, null); @@ -388,6 +480,8 @@ class PeerTestManager { } } + // Below here are methods for when we are Bob or Charlie + private static final int MAX_RELAYED_PER_TEST = 5; /** diff --git a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java index 2556bdb7be8490b562fbbdb9dd3837152caa547c..a96a4d5075a9e1c31b69a1f7969553ebaae51558 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPTransport.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPTransport.java @@ -2059,7 +2059,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority } } - private static final String KEY = "<h3>Definitions:</h3><div class=\"configure\">" + + private static final String KEY = "<h3>Definitions</h3><div class=\"configure\">" + "<p><b id=\"def.peer\">Peer</b>: the remote peer.<br>\n" + "<b id=\"def.dir\">Dir</b>: v means they offer to introduce us, ^ means we offer to introduce them.<br>\n" + "<b id=\"def.idle\">Idle</b>: the idle time is how long since a packet has been received or sent.<br>\n" +