From d998e2e9bb3e846de5ea4953b76c68d0832b2540 Mon Sep 17 00:00:00 2001 From: z3d Date: Fri, 14 Aug 2009 21:00:22 +0000 Subject: [PATCH 01/20] Theme tweaks, minor textual edits and a whole lot less. --- .../src/org/klomp/snark/SnarkManager.java | 12 +++---- .../i2p/router/web/ConfigServiceHandler.java | 8 ++--- .../src/net/i2p/router/web/SummaryHelper.java | 2 +- apps/routerconsole/jsp/summarynoframe.jsp | 2 +- .../themes/console/classic/console.css | 12 +++---- .../resources/themes/console/dark/console.css | 30 +++++++++--------- .../themes/console/images/local_down.png | Bin 512 -> 563 bytes .../console/images/local_inprogress.png | Bin 514 -> 597 bytes .../themes/console/images/local_up.png | Bin 579 -> 640 bytes .../themes/console/light/console.css | 16 +++++----- 10 files changed, 41 insertions(+), 41 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index 950f2e827..e0ff254b8 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -324,7 +324,7 @@ public class SnarkManager implements Snark.CompleteListener { Snark snark = getTorrent(name); if ( (snark != null) && (snark.acceptor != null) ) { snark.acceptor.restart(); - addMessage("I2CP listener restarted for " + snark.meta.getName()); + addMessage("I2CP listener restarted for " + snark.meta.getName()) +"."; } } } @@ -334,8 +334,8 @@ public class SnarkManager implements Snark.CompleteListener { } if (shouldAutoStart() != autoStart) { _config.setProperty(PROP_AUTO_START, autoStart + ""); - addMessage("Adjusted autostart to " + autoStart); - changed = true; + addMessage("Autostart of torrents set to " + autoStart); + changed = true + "."; } if (_util.shouldUseOpenTrackers() != useOpenTrackers) { _config.setProperty(I2PSnarkUtil.PROP_USE_OPENTRACKERS, useOpenTrackers + ""); @@ -391,8 +391,8 @@ public class SnarkManager implements Snark.CompleteListener { try { filename = sfile.getCanonicalPath(); } catch (IOException ioe) { - _log.error("Unable to add the torrent " + filename, ioe); - addMessage("ERR: Could not add the torrent '" + filename + "': " + ioe.getMessage()); + _log.error("Unable to add the torrent " + filename, ioe) + "."; + addMessage("ERR: Could not add the torrent '" + filename + "': " + ioe.getMessage()) + "."; return; } File dataDir = getDataDir(); @@ -431,7 +431,7 @@ public class SnarkManager implements Snark.CompleteListener { } } } catch (IOException ioe) { - addMessage("Torrent in " + sfile.getName() + " is invalid: " + ioe.getMessage()); + addMessage("Torrent in " + sfile.getName() + " is invalid: " + ioe.getMessage()) +"."; if (sfile.exists()) sfile.delete(); return; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java index 195889fad..3601bf38b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java @@ -95,9 +95,9 @@ public class ConfigServiceHandler extends FormHandler { SysTray tray = SysTray.getInstance(); if (tray != null) { tray.show(); - addFormNotice("Systray enabled"); + addFormNotice("System tray icon enabled."); } else { - addFormNotice("Systray not supported on this platform"); + addFormNotice("System tray icon feature not supported on this platform. Sorry!"); } } catch (Throwable t) { addFormError("Warning: unable to contact the systray manager - " + t.getMessage()); @@ -107,9 +107,9 @@ public class ConfigServiceHandler extends FormHandler { SysTray tray = SysTray.getInstance(); if (tray != null) { tray.hide(); - addFormNotice("Systray disabled"); + addFormNotice("System tray icon disabled."); } else { - addFormNotice("Systray not supported on this platform"); + addFormNotice("System tray icon feature not supported on this platform. Sorry!"); } } catch (Throwable t) { addFormError("Warning: unable to contact the systray manager - " + t.getMessage()); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index 8305d64f3..f724c7ed4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -367,7 +367,7 @@ public class SummaryHelper extends HelperBase { if (timeToExpire < 0) { // red or yellow light buf.append("\"Rebuilding…\"\n"); + buf.append(" ago. Rebuilding…\">\n"); } else { // green light buf.append("\"Ready\"\n"); diff --git a/apps/routerconsole/jsp/summarynoframe.jsp b/apps/routerconsole/jsp/summarynoframe.jsp index 2a473d1f5..abfce05fd 100644 --- a/apps/routerconsole/jsp/summarynoframe.jsp +++ b/apps/routerconsole/jsp/summarynoframe.jsp @@ -127,7 +127,7 @@ Total:/K/s Used:/
-

Tunnels in/out


+

Tunnels in/out


diff --git a/installer/resources/themes/console/classic/console.css b/installer/resources/themes/console/classic/console.css index 62296c191..a69454535 100644 --- a/installer/resources/themes/console/classic/console.css +++ b/installer/resources/themes/console/classic/console.css @@ -110,7 +110,7 @@ div.toolbar { div.routersummaryouter { float: left; - width: 205px; + width: 200px; margin: 0; padding: 0; border: 0; @@ -119,7 +119,7 @@ div.routersummaryouter { div.routersummary { background: #ddf; - width: 190px; + width: 185px; color: inherit; margin: 0; padding: 7px 1px; @@ -171,7 +171,7 @@ div.routersummary h4 { div.routersummary table { border: 0; text-align: center !important; - margin: -5px 5px; + margin: -5px 5px -5px 2px; width: 180px !important; overflow: hidden; font-size: 8pt; @@ -225,7 +225,7 @@ div.warning h3 { } div.main { - margin: 0px 0px 0px 196px; + margin: 0px 0px 0px 195px; padding: 15px 15px 15px 15px; background: #eef; border: 5px solid #bbf; @@ -251,7 +251,7 @@ div.main textarea { } div.news { - margin: -5px 0px 0 196px; + margin: -5px 0px 0 195px; padding: -10px 15px 8px 15px; background: #ffffc0; border: 5px solid #bbf; @@ -358,7 +358,7 @@ h1 { text-align: center; border: 5px solid #bbf; padding: 13px 10px 12px 10px; - margin: 0 0px 0 196px; + margin: 0 0px 0 195px; line-height: 93%; text-transform: uppercase; letter-spacing: 0.3em; diff --git a/installer/resources/themes/console/dark/console.css b/installer/resources/themes/console/dark/console.css index fe902cb1e..6986ce9b7 100644 --- a/installer/resources/themes/console/dark/console.css +++ b/installer/resources/themes/console/dark/console.css @@ -1,7 +1,7 @@ /* Not yet complete. Subject to flux and change. dr|z3d - 07.25.09 */ body { - margin: 25px 10px 0 5px; + margin: 20px 5px 0 15px; padding: 0; text-align: center; background: #002; @@ -79,7 +79,7 @@ a:active{ div.routersummaryouter { float: left; width: 200px; - margin: 0 0 10px 20px; + margin: 0 0 10px 5px; padding: 0; border: 0; clear: left;/* fixes a bug in Opera */ @@ -125,7 +125,7 @@ div.routersummary hr { div.routersummary h3 { border: 0; font-size: 10pt; - letter-spacing: 0.05em; + letter-spacing: 0.04em; margin: -7px -9px -10px -9px; padding: 3px 0px 5px 0px; background: #007; @@ -140,8 +140,8 @@ div.routersummary h3 { div.routersummary h4 { border: 0; border-bottom: 0 !important; - font-size: 9pt; - letter-spacing: 0.05em; + font-size: 8.5pt; + letter-spacing: 0.03em; margin: -7px -9px -10px -9px !important; padding: 2px 3px 5px 3px; background: #005; @@ -154,7 +154,7 @@ div.routersummary h4 { div.routersummary table { border: 0; text-align: center !important; - margin: -5px -5px; + margin: -1px -4px -4px -4px; width: 185px !important; overflow: hidden; font-size: 8pt; @@ -178,7 +178,7 @@ div.routersummary p { } div.routersummary a:link, div.routersummary a:visited { - text-shadow: 0px 0px 1px rgba(0, 0, 32, 0.3); + text-shadow: 0px 0px 1px rgba(192, 192, 255, 0.5); } div.routersummary a:hover { @@ -224,7 +224,7 @@ div.warning { } div.main { - margin: 0px 0px 20px 215px; + margin: 0px 0px 20px 195px; padding: 0 15px 15px 25px; background: #002; text-align: left; @@ -240,7 +240,7 @@ div.main textarea { } div.news { - margin: 0px 15px 20px 240px; + margin: 0px 15px 20px 220px; padding: 20px 30px 20px 30px; border: 1px solid #99f; background: #004; @@ -266,7 +266,7 @@ div.news li { div.confignav { padding: 15px 10px !important; - margin: 0 0 25px 0; + margin: 0 0 15px 0; background: #004 url('images/darkbluebg.png'); -moz-border-radius: 4px; -khtml-border-radius: 4px; @@ -325,7 +325,7 @@ div.messages li { } div.graphspanel { - padding: 15px 15px 15px 15px; + padding: 0px 5px 10px 5px; margin: 10px 0px; background: #005; -moz-border-radius: 4px; @@ -497,7 +497,7 @@ h1 { text-align: left; color: #fff; padding: 10px 15px; - margin: 0 15px 25px 240px; + margin: 0 15px 15px 220px; font-size: 16pt; font-weight: bold; font-style: normal; @@ -529,7 +529,7 @@ h2 { -moz-border-radius: 4px; -khtml-border-radius: 4px; vertical-align: middle; - margin: 25px 0 20px 0 !important; + margin: 15px 0 10px 0 !important; -moz-box-shadow: inset 0px 0px 1px 0px #eef; -khtml-box-shadow: inset 0px 0px 1px 0px #eef; box-shadow: inset 0px 0px 1px 0px #eef; @@ -757,8 +757,8 @@ form {} } .joblog { - margin: 25px 0 25px 0; - padding: 20px 30px 20px 30px !important; + margin: 15px 0 15px 0; + padding: 20px !important; border: 1px solid #99f; background-color: #004; background: url("images/darkbluebg.png"); diff --git a/installer/resources/themes/console/images/local_down.png b/installer/resources/themes/console/images/local_down.png index 14c7d4b9294e4109af51437ba8ac18d45710f673..4d056de5da5e89dc55609522bfc9224526665236 100644 GIT binary patch delta 516 zcmV+f0{i`d1hWK?Ie+CzL_t(|oQ;ytOH@%5$3HVPO&V_kv$93u6XQ*blv)f!;i84u zW(bubl-#w-{2P*X6|IUWifK_nZ5yJ9&|MJ}ZCbc8s0=hREvFx7p1$`zXPj44bl`B$ zJ?DGQJ>PQ=)XN;$`prg1?FMXezJvwA@dcQ-*4EQC#AE1Phkpwd8C_lHY;bVdQmGT1 zhs{&+eS_67`W;U4yI8TYve zGq*i(_^(uAoPB?XrPHUZzkh2(z-#^Y2k_oPQ!S~ZV~Y(8JbdTo?|B#0PIEPORrXoo zBVeJ>T!Ax|$(U?&<8T@#`o6h^vf*KSqg}WUBQ`dcj(xY+-kukDb>1c9a%Rb--IaY& zdIdgdjQe5<;~Io29krpM6<65-=hhOOPDmFcUAhH_+$0l@;}ZB^;PZ-J+pb^+T3X$TEH*!5rEP%l&esQe4PKDn{xd`El$00005dV4|Q+L`6`JHJK^G?L3{C92%k?yqUT0o_o)|=e_~@mj%eT zCCkfQDMB;XjI7z3cVE|#3refz+?<%(moO;sU16x11T+T!y=j&(! zI#YGL=w$MUI&8|)Qk_m|0c)b`RS5>mP*uID>e%&%UDRGz&ORw+aZyfe=QUO7Njp1x zx^EcsaT<3vcz=rf9T;?@Zz*%dPc~;={?@0bi^<6?35EU!c7w*oN~$x}wnQQ&Ka6T5 z+%k-V!Dw_InG7cscAfQ|9mK}Rc|Rz)WudmcjR)XtZe?YmpQUK_hA0iiluC&N0&;8* zxYCoZ=%GCarlnA@xaGwLS$zT2SvXGlB<~@y-BKTcbxMve$861EiWdZG6nm9>gi{0U zR~Ea$piyFGG$6vWU0-o{suR>9TSr}-e<^#xDxRF*#%Fy2YZ<|JOqZ9U00000NkvXX Hu0mjfM9|dW diff --git a/installer/resources/themes/console/images/local_inprogress.png b/installer/resources/themes/console/images/local_inprogress.png index d8fcfe44e89f608f35bcee1569d1e8acea324da8..245dc058d8274486f073b53ed73763e97d0e0af5 100644 GIT binary patch delta 552 zcmV+@0@wY51l0tPIDY~MNkl`|dgCJHPWg2e8WC9(Z;mpOb_phwCo#O6S1=zLCBc#eayoIfN|XaGxA*^pX!H z*Zu~ZoA9r$g1Hn@vlgDjJ)4?dbg?1?k>V)Kp}b!T>CjTh5~udiLNf#vRQl| z8p3C>92~^{=qSEOt+yr5uB_nlxmss6TS8?V(06vQZ2e~^!yUk%Rsmuw6h5|OGH7?X zn(hL>22Q!#SASg#NmQT&(9>coKHsx72mv!Q=5v7nekiMvx7x(votxQd!wXCzWwO});KM@-37y0edg-6q%t*;{&i6Cz#1!OSc z+3oE$pWnZj5`I2tYAa+nVlj9GbA^#DoYaw*=E(;%7k|Litt}PYNOPecb7KQ(fqdIo zE(_}w68KUDr&1~*Dr)1z1lZRH%CO_d$EYvCJ3S3I`6#Ad705=QT4H6D#^d1OA$W9z zS`oLM&NKd@hTX^JDDW%dAM~QdQ}xJB+L*Q q_nrQJ^dZR7xc+MlRuMFwa=yR2)q4oS(bA`c5Xnav7OE+J^_6eaqF$IUgN(P^%#< zR88+UAGvf5)YHJizT>3KdL4(B72X0K)6lACB+f`z{u-2NM z#zFgPS2LHF`G56b5V*g04;L4K&rkTf$x9_9RO63Q3WZ;E_G_LyBZvP6?gh;xRGHj~ zC=4Wi0Igb%gA6$;piR01;F=p4q7D?f!`D|Zms9MX<;@aPpjxG(0n1_r(`mQC?PkaN zvfkVvB8+y2RY5w$oq%Eyly*`ov#+iY(HP_D3CGgDs7Y|c`S9lVBQ7=}U4!`V zp%6|aXi6|Erip-jOAXYWN+B$uretgC;QZ@mvspyt=NLSOvc3QnT^n1H4YPFs0000< KMNUMnLSTY;u;KFn diff --git a/installer/resources/themes/console/images/local_up.png b/installer/resources/themes/console/images/local_up.png index 1b70292fe7d3942a6582b9d27d2f4448e0665e46..5b8a3451707baef478833ea6a3411a523bea0661 100644 GIT binary patch delta 595 zcmV-Z0<8VR1b_vQIDY~%NklFvGO;Xle zhSs^@9kwZjA1Mk48A!@x(4=W0M)?~TrM}lI`x2IPi*b~UbLhBah>EJ^k{xi~Vnzf7 zT5)P~4BOjypobINHQvSEq^HDB?TWAkgXH~_YY7cfn7XQ?e2V1aPh4MaQyQh{)I6c2 zZ1Q&9^FQ3{N`Iujz?r{$grN&~1&cnrg=RS{6_bcjlwOc#w&GO?pYfcW4iaSO@nX2d zjeIj7XQlGAtAn1*=lCrxh`p8W+&)IQOiUzs&Pz7LwBw7~N@_P*QJpJ$&abNxb$c|w zS~`N;kwExaie9Z=xM9?HP`Qbs`~9DXf^`z7bt%EOCV#sVD<5zYi=y`B5YVRCe1Lf0 z4yp3Q;D|((F!5_x`=&$oGs$<_$L_rH$8z**E$<_w6O!#N9-~VashB{Tq+F`SBJR70 zF&XtL=SxM;wj3#sNV_CQo?ek-vSoCUXnbPhHYEKCvMr#?6m70fJmxBM2Uu_Ufqiz0 zdG|U(zf7$BbR|>kaB=&^4Hgs|dvXeRJu`=WZUTqZh9ewDX!VilL)aPOoVA66n4j}M hkmTYKTV3jAm%!(|-DZ8ecv{-&YiKtKbP|E49CAwwpXvyUu}hJ>KE6`2lm3`xH8G5SgXO3^>UnSzsO^ zl_v1Q%d6JVG}yn6*==dNzhLUOT6Md`OupsCfQ7WAsx_Z!SJ?H|fnDxI=Y=O5rC2nI zTiu~_;S-k2xPKLeSbRByz;ch0`JF9eMK6)~g zcP&YWM513@4h(hiM=6PgzvyhXF&>yY%izC(>o&@`p_EBac#aXH6-K+k-q2Hf{`Kx~ z^yqQ)3;PED#~aU)Yfs{&42Zlb9<4pY$}-+f96mqjgMThEUQ`v74{m}oMLbQ7v2vp` z1qa1#W%s^E_6~>5+Z<-!HxHzSxcbG^9i^7diIk9*=dMY$ni`z{>TG-t`JPp@9z(HT YPy*A=9uMR|8UO$Q07*qoM6N<$f*mjg>i_@% diff --git a/installer/resources/themes/console/light/console.css b/installer/resources/themes/console/light/console.css index be4f6a3d6..6138ab4c8 100644 --- a/installer/resources/themes/console/light/console.css +++ b/installer/resources/themes/console/light/console.css @@ -119,21 +119,21 @@ div.routersummary hr { } div.routersummary h3 { - border: 0px solid #f00; -/* border-bottom: 1px solid #99f !important;*/ + border: 0; font-size: 10pt; - letter-spacing: 0.05em; + letter-spacing: 0.04em; margin: -7px -9px -7px -9px; padding: 5px 0px 5px 0px; background: #c5d5fb; text-transform: uppercase; + background-image: -moz-linear-gradient(top, bottom, from(#ddf), to(#c5d5fb), color-stop(25%, #c5d5fb), color-stop(100%, #ddf)); } div.routersummary h4 { border: 0px solid #f00; border-bottom: 0 !important; - font-size: 9pt; - letter-spacing: 0.05em; + font-size: 8.5pt; + letter-spacing: 0.02em; margin: -7px -9px -7px -9px !important; padding: 2px 3px 3px 3px; background: #c1d1f7; @@ -145,7 +145,7 @@ div.routersummary h4 { div.routersummary table { border: 0; text-align: center !important; - margin: -5px -5px; + margin: -2px -4px; width: 185px !important; overflow: hidden; font-size: 8pt; @@ -169,11 +169,11 @@ div.routersummary p { } div.routersummary a:link, div.routersummary a:visited { - text-shadow: 0px 0px 1px rgba(0, 0, 32, 0.3); + text-shadow: 0px 0px 1px rgba(0, 0, 32, 0.5); } div.routersummary a:hover { - text-shadow: 0px 0px 1px rgba(255, 96, 0, 0.7); + text-shadow: 0px 0px 0.5px rgba(255, 255, 255, 0.7); color: #f60; } From c466cd77ad0f317bec9cc98f0f654f7ee5c14eaa Mon Sep 17 00:00:00 2001 From: z3d Date: Fri, 14 Aug 2009 21:40:45 +0000 Subject: [PATCH 02/20] Add some tags to our router restart/shutdown event notices. --- .../java/src/net/i2p/router/web/ConfigRestartBean.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java index c9ab42dde..0218c1787 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java @@ -49,16 +49,16 @@ public class ConfigRestartBean { long timeRemaining = ctx.router().getShutdownTimeRemaining(); if (shuttingDown) { if (timeRemaining <= 0) { - return "Shutdown imminent"; + return "
Shutdown imminent
"; } else { - return "Shutdown in " + DataHelper.formatDuration(timeRemaining) + "
" + return "
Shutdown in " + DataHelper.formatDuration(timeRemaining) + "

" + buttons(urlBase, systemNonce, "shutdownImmediate,Shutdown immediately,cancelShutdown,Cancel shutdown"); } } else if (restarting) { if (timeRemaining <= 0) { - return "Restart imminent"; + return "
Restart imminent
"; } else { - return "Restart in " + DataHelper.formatDuration(timeRemaining) + "
" + return "
Restart in " + DataHelper.formatDuration(timeRemaining) + "

" + buttons(urlBase, systemNonce, "restartImmediate,Restart immediately,cancelShutdown,Cancel restart"); } } else { From 335d45f03e9e79bd25dd36ad2f749ea969757880 Mon Sep 17 00:00:00 2001 From: z3d Date: Sat, 15 Aug 2009 01:12:26 +0000 Subject: [PATCH 03/20] Fix borked snarkmanager.java before anyone notices. --- .../src/org/klomp/snark/SnarkManager.java | 1520 ++++++++--------- 1 file changed, 760 insertions(+), 760 deletions(-) diff --git a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java index e0ff254b8..bf7c146cb 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java +++ b/apps/i2psnark/java/src/org/klomp/snark/SnarkManager.java @@ -1,760 +1,760 @@ -package org.klomp.snark; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FilenameFilter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.TreeMap; - -import net.i2p.I2PAppContext; -import net.i2p.data.Base64; -import net.i2p.data.DataHelper; -import net.i2p.util.I2PAppThread; -import net.i2p.util.Log; - -/** - * Manage multiple snarks - */ -public class SnarkManager implements Snark.CompleteListener { - private static SnarkManager _instance = new SnarkManager(); - public static SnarkManager instance() { return _instance; } - - /** map of (canonical) filename to Snark instance (unsynchronized) */ - private final Map _snarks; - private final Object _addSnarkLock; - private /* FIXME final FIXME */ File _configFile; - private Properties _config; - private I2PAppContext _context; - private Log _log; - private final List _messages; - private I2PSnarkUtil _util; - private PeerCoordinatorSet _peerCoordinatorSet; - private ConnectionAcceptor _connectionAcceptor; - - public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost"; - public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort"; - public static final String PROP_I2CP_OPTS = "i2psnark.i2cpOptions"; - public static final String PROP_EEP_HOST = "i2psnark.eepHost"; - public static final String PROP_EEP_PORT = "i2psnark.eepPort"; - public static final String PROP_UPLOADERS_TOTAL = "i2psnark.uploaders.total"; - public static final String PROP_UPBW_MAX = "i2psnark.upbw.max"; - public static final String PROP_DIR = "i2psnark.dir"; - public static final String PROP_META_PREFIX = "i2psnark.zmeta."; - public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield"; - - private static final String CONFIG_FILE = "i2psnark.config"; - public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops - public static final String DEFAULT_AUTO_START = "false"; - public static final String PROP_LINK_PREFIX = "i2psnark.linkPrefix"; - public static final String DEFAULT_LINK_PREFIX = "file:///"; - - public static final int MIN_UP_BW = 2; - public static final int DEFAULT_MAX_UP_BW = 10; - - private SnarkManager() { - _snarks = new HashMap(); - _addSnarkLock = new Object(); - _context = I2PAppContext.getGlobalContext(); - _log = _context.logManager().getLog(SnarkManager.class); - _messages = new ArrayList(16); - _util = new I2PSnarkUtil(_context); - _configFile = new File(CONFIG_FILE); - if (!_configFile.isAbsolute()) - _configFile = new File(_context.getConfigDir(), CONFIG_FILE); - loadConfig(null); - } - - /** Caller _must_ call loadConfig(file) before this if setting new values - * for i2cp host/port or i2psnark.dir - */ - public void start() { - _peerCoordinatorSet = new PeerCoordinatorSet(); - _connectionAcceptor = new ConnectionAcceptor(_util); - int minutes = getStartupDelayMinutes(); - _messages.add("Adding torrents in " + minutes + (minutes == 1 ? " minute" : " minutes")); - I2PAppThread monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor"); - monitor.setDaemon(true); - monitor.start(); - _context.addShutdownTask(new SnarkManagerShutdown()); - } - - /** hook to I2PSnarkUtil for the servlet */ - public I2PSnarkUtil util() { return _util; } - - private static final int MAX_MESSAGES = 5; - public void addMessage(String message) { - synchronized (_messages) { - _messages.add(message); - while (_messages.size() > MAX_MESSAGES) - _messages.remove(0); - } - if (_log.shouldLog(Log.INFO)) - _log.info("MSG: " + message); - } - - /** newest last */ - public List getMessages() { - synchronized (_messages) { - return new ArrayList(_messages); - } - } - - public boolean shouldAutoStart() { - return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue(); - } - public String linkPrefix() { - return _config.getProperty(PROP_LINK_PREFIX, DEFAULT_LINK_PREFIX + getDataDir().getAbsolutePath() + File.separatorChar); - } - private int getStartupDelayMinutes() { return 3; } - public File getDataDir() { - String dir = _config.getProperty(PROP_DIR, "i2psnark"); - File f = new File(dir); - if (!f.isAbsolute()) - f = new File(_context.getAppDir(), dir); - return f; - } - - /** null to set initial defaults */ - public void loadConfig(String filename) { - if (_config == null) - _config = new Properties(); - if (filename != null) { - File cfg = new File(filename); - if (!cfg.isAbsolute()) - cfg = new File(_context.getConfigDir(), filename); - _configFile = cfg; - if (cfg.exists()) { - try { - DataHelper.loadProps(_config, cfg); - } catch (IOException ioe) { - _log.error("Error loading I2PSnark config '" + filename + "'", ioe); - } - } - } - // now add sane defaults - if (!_config.containsKey(PROP_I2CP_HOST)) - _config.setProperty(PROP_I2CP_HOST, "127.0.0.1"); - if (!_config.containsKey(PROP_I2CP_PORT)) - _config.setProperty(PROP_I2CP_PORT, "7654"); - if (!_config.containsKey(PROP_I2CP_OPTS)) - _config.setProperty(PROP_I2CP_OPTS, "inbound.length=2 inbound.lengthVariance=0 outbound.length=2 outbound.lengthVariance=0 inbound.quantity=3 outbound.quantity=3"); - if (!_config.containsKey(PROP_EEP_HOST)) - _config.setProperty(PROP_EEP_HOST, "127.0.0.1"); - if (!_config.containsKey(PROP_EEP_PORT)) - _config.setProperty(PROP_EEP_PORT, "4444"); - if (!_config.containsKey(PROP_UPLOADERS_TOTAL)) - _config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS); - if (!_config.containsKey(PROP_DIR)) - _config.setProperty(PROP_DIR, "i2psnark"); - if (!_config.containsKey(PROP_AUTO_START)) - _config.setProperty(PROP_AUTO_START, DEFAULT_AUTO_START); - updateConfig(); - } - - /** call from DirMonitor since loadConfig() is called before router I2CP is up */ - private void getBWLimit() { - if (!_config.containsKey(PROP_UPBW_MAX)) { - int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort()); - if (limits != null && limits[1] > 0) - _util.setMaxUpBW(limits[1]); - } - } - - private void updateConfig() { - String i2cpHost = _config.getProperty(PROP_I2CP_HOST); - int i2cpPort = getInt(PROP_I2CP_PORT, 7654); - String opts = _config.getProperty(PROP_I2CP_OPTS); - Map i2cpOpts = new HashMap(); - if (opts != null) { - StringTokenizer tok = new StringTokenizer(opts, " "); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split > 0) - i2cpOpts.put(pair.substring(0, split), pair.substring(split+1)); - } - } - if (i2cpHost != null) { - _util.setI2CPConfig(i2cpHost, i2cpPort, i2cpOpts); - _log.debug("Configuring with I2CP options " + i2cpOpts); - } - //I2PSnarkUtil.instance().setI2CPConfig("66.111.51.110", 7654, new Properties()); - String eepHost = _config.getProperty(PROP_EEP_HOST); - int eepPort = getInt(PROP_EEP_PORT, 4444); - if (eepHost != null) - _util.setProxy(eepHost, eepPort); - _util.setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS)); - _util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW)); - getDataDir().mkdirs(); - } - - private int getInt(String prop, int defaultVal) { - String p = _config.getProperty(prop); - try { - if ( (p != null) && (p.trim().length() > 0) ) - return Integer.parseInt(p.trim()); - } catch (NumberFormatException nfe) { - // ignore - } - return defaultVal; - } - - public void updateConfig(String dataDir, boolean autoStart, String seedPct, String eepHost, - String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts, - String upLimit, String upBW, boolean useOpenTrackers, String openTrackers) { - boolean changed = false; - if (eepHost != null) { - int port = _util.getEepProxyPort(); - try { port = Integer.parseInt(eepPort); } catch (NumberFormatException nfe) {} - String host = _util.getEepProxyHost(); - if ( (eepHost.trim().length() > 0) && (port > 0) && - ((!host.equals(eepHost) || (port != _util.getEepProxyPort()) )) ) { - _util.setProxy(eepHost, port); - changed = true; - _config.setProperty(PROP_EEP_HOST, eepHost); - _config.setProperty(PROP_EEP_PORT, eepPort+""); - addMessage("EepProxy location changed to " + eepHost + ":" + port); - } - } - if (upLimit != null) { - int limit = _util.getMaxUploaders(); - try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {} - if ( limit != _util.getMaxUploaders()) { - if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) { - _util.setMaxUploaders(limit); - changed = true; - _config.setProperty(PROP_UPLOADERS_TOTAL, "" + limit); - addMessage("Total uploaders limit changed to " + limit); - } else { - addMessage("Minimum total uploaders limit is " + Snark.MIN_TOTAL_UPLOADERS); - } - } - } - if (upBW != null) { - int limit = _util.getMaxUpBW(); - try { limit = Integer.parseInt(upBW); } catch (NumberFormatException nfe) {} - if ( limit != _util.getMaxUpBW()) { - if ( limit >= MIN_UP_BW ) { - _util.setMaxUpBW(limit); - changed = true; - _config.setProperty(PROP_UPBW_MAX, "" + limit); - addMessage("Up BW limit changed to " + limit + "KBps"); - } else { - addMessage("Minimum Up BW limit is " + MIN_UP_BW + "KBps"); - } - } - } - if (i2cpHost != null) { - int oldI2CPPort = _util.getI2CPPort(); - String oldI2CPHost = _util.getI2CPHost(); - int port = oldI2CPPort; - try { port = Integer.parseInt(i2cpPort); } catch (NumberFormatException nfe) {} - String host = oldI2CPHost; - Map opts = new HashMap(); - if (i2cpOpts == null) i2cpOpts = ""; - StringTokenizer tok = new StringTokenizer(i2cpOpts, " \t\n"); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split > 0) - opts.put(pair.substring(0, split), pair.substring(split+1)); - } - Map oldOpts = new HashMap(); - String oldI2CPOpts = _config.getProperty(PROP_I2CP_OPTS); - if (oldI2CPOpts == null) oldI2CPOpts = ""; - tok = new StringTokenizer(oldI2CPOpts, " \t\n"); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split > 0) - oldOpts.put(pair.substring(0, split), pair.substring(split+1)); - } - - if ( (i2cpHost.trim().length() > 0) && (port > 0) && - ((!host.equals(i2cpHost) || - (port != _util.getI2CPPort()) || - (!oldOpts.equals(opts)))) ) { - boolean snarksActive = false; - Set names = listTorrentFiles(); - for (Iterator iter = names.iterator(); iter.hasNext(); ) { - Snark snark = getTorrent((String)iter.next()); - if ( (snark != null) && (!snark.stopped) ) { - snarksActive = true; - break; - } - } - if (snarksActive) { - addMessage("Cannot change the I2CP settings while torrents are active"); - _log.debug("i2cp host [" + i2cpHost + "] i2cp port " + port + " opts [" + opts - + "] oldOpts [" + oldOpts + "]"); - } else { - if (_util.connected()) { - _util.disconnect(); - addMessage("Disconnecting old I2CP destination"); - } - Properties p = new Properties(); - p.putAll(opts); - addMessage("I2CP settings changed to " + i2cpHost + ":" + port + " (" + i2cpOpts.trim() + ")"); - _util.setI2CPConfig(i2cpHost, port, p); - boolean ok = _util.connect(); - if (!ok) { - addMessage("Unable to connect with the new settings, reverting to the old I2CP settings"); - _util.setI2CPConfig(oldI2CPHost, oldI2CPPort, oldOpts); - ok = _util.connect(); - if (!ok) - addMessage("Unable to reconnect with the old settings!"); - } else { - addMessage("Reconnected on the new I2CP destination"); - _config.setProperty(PROP_I2CP_HOST, i2cpHost.trim()); - _config.setProperty(PROP_I2CP_PORT, "" + port); - _config.setProperty(PROP_I2CP_OPTS, i2cpOpts.trim()); - changed = true; - // no PeerAcceptors/I2PServerSockets to deal with, since all snarks are inactive - for (Iterator iter = names.iterator(); iter.hasNext(); ) { - String name = (String)iter.next(); - Snark snark = getTorrent(name); - if ( (snark != null) && (snark.acceptor != null) ) { - snark.acceptor.restart(); - addMessage("I2CP listener restarted for " + snark.meta.getName()) +"."; - } - } - } - } - changed = true; - } - } - if (shouldAutoStart() != autoStart) { - _config.setProperty(PROP_AUTO_START, autoStart + ""); - addMessage("Autostart of torrents set to " + autoStart); - changed = true + "."; - } - if (_util.shouldUseOpenTrackers() != useOpenTrackers) { - _config.setProperty(I2PSnarkUtil.PROP_USE_OPENTRACKERS, useOpenTrackers + ""); - addMessage((useOpenTrackers ? "En" : "Dis") + "abled open trackers - torrent restart required to take effect."); - changed = true; - } - if (openTrackers != null) { - if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(_util.getOpenTrackerString())) { - _config.setProperty(I2PSnarkUtil.PROP_OPENTRACKERS, openTrackers.trim()); - addMessage("Open Tracker list changed - torrent restart required to take effect."); - changed = true; - } - } - if (changed) { - saveConfig(); - } else { - addMessage("Configuration unchanged."); - } - } - - public void saveConfig() { - try { - synchronized (_configFile) { - DataHelper.storeProps(_config, _configFile); - } - } catch (IOException ioe) { - addMessage("Unable to save the config to '" + _configFile.getAbsolutePath() + "'."); - } - } - - public Properties getConfig() { return _config; } - - /** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */ - private static final int MAX_FILES_PER_TORRENT = 512; - - /** set of filenames that we are dealing with */ - public Set listTorrentFiles() { synchronized (_snarks) { return new HashSet(_snarks.keySet()); } } - /** - * Grab the torrent given the (canonical) filename - */ - public Snark getTorrent(String filename) { synchronized (_snarks) { return (Snark)_snarks.get(filename); } } - public void addTorrent(String filename) { addTorrent(filename, false); } - public void addTorrent(String filename, boolean dontAutoStart) { - if ((!dontAutoStart) && !_util.connected()) { - addMessage("Connecting to I2P"); - boolean ok = _util.connect(); - if (!ok) { - addMessage("Error connecting to I2P - check your I2CP settings!"); - return; - } - } - File sfile = new File(filename); - try { - filename = sfile.getCanonicalPath(); - } catch (IOException ioe) { - _log.error("Unable to add the torrent " + filename, ioe) + "."; - addMessage("ERR: Could not add the torrent '" + filename + "': " + ioe.getMessage()) + "."; - return; - } - File dataDir = getDataDir(); - Snark torrent = null; - synchronized (_snarks) { - torrent = (Snark)_snarks.get(filename); - } - // don't hold the _snarks lock while verifying the torrent - if (torrent == null) { - synchronized (_addSnarkLock) { - // double-check - synchronized (_snarks) { - if(_snarks.get(filename) != null) - return; - } - - FileInputStream fis = null; - try { - fis = new FileInputStream(sfile); - MetaInfo info = new MetaInfo(fis); - fis.close(); - fis = null; - - String rejectMessage = locked_validateTorrent(info); - if (rejectMessage != null) { - sfile.delete(); - addMessage(rejectMessage); - return; - } else { - torrent = new Snark(_util, filename, null, -1, null, null, this, - _peerCoordinatorSet, _connectionAcceptor, - false, dataDir.getPath()); - torrent.completeListener = this; - synchronized (_snarks) { - _snarks.put(filename, torrent); - } - } - } catch (IOException ioe) { - addMessage("Torrent in " + sfile.getName() + " is invalid: " + ioe.getMessage()) +"."; - if (sfile.exists()) - sfile.delete(); - return; - } finally { - if (fis != null) try { fis.close(); } catch (IOException ioe) {} - } - } - } else { - return; - } - // ok, snark created, now lets start it up or configure it further - File f = new File(filename); - if (!dontAutoStart && shouldAutoStart()) { - torrent.startTorrent(); - addMessage("Torrent added and started: '" + f.getName() + "'."); - } else { - addMessage("Torrent added: '" + f.getName() + "'."); - } - } - - /** - * Get the timestamp for a torrent from the config file - */ - public long getSavedTorrentTime(Snark snark) { - MetaInfo metainfo = snark.meta; - byte[] ih = metainfo.getInfoHash(); - String infohash = Base64.encode(ih); - infohash = infohash.replace('=', '$'); - String time = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); - if (time == null) - return 0; - int comma = time.indexOf(','); - if (comma <= 0) - return 0; - time = time.substring(0, comma); - try { return Long.parseLong(time); } catch (NumberFormatException nfe) {} - return 0; - } - - /** - * Get the saved bitfield for a torrent from the config file. - * Convert "." to a full bitfield. - */ - public BitField getSavedTorrentBitField(Snark snark) { - MetaInfo metainfo = snark.meta; - byte[] ih = metainfo.getInfoHash(); - String infohash = Base64.encode(ih); - infohash = infohash.replace('=', '$'); - String bf = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); - if (bf == null) - return null; - int comma = bf.indexOf(','); - if (comma <= 0) - return null; - bf = bf.substring(comma + 1).trim(); - int len = metainfo.getPieces(); - if (bf.equals(".")) { - BitField bitfield = new BitField(len); - for (int i = 0; i < len; i++) - bitfield.set(i); - return bitfield; - } - byte[] bitfield = Base64.decode(bf); - if (bitfield == null) - return null; - if (bitfield.length * 8 < len) - return null; - return new BitField(bitfield, len); - } - - /** - * Save the completion status of a torrent and the current time in the config file - * in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield". - * The config file property key is appended with the Base64 of the infohash, - * with the '=' changed to '$' since a key can't contain '='. - * The time is a standard long converted to string. - * The status is either a bitfield converted to Base64 or "." for a completed - * torrent to save space in the config file and in memory. - */ - public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield) { - byte[] ih = metainfo.getInfoHash(); - String infohash = Base64.encode(ih); - infohash = infohash.replace('=', '$'); - String now = "" + System.currentTimeMillis(); - String bfs; - if (bitfield.complete()) { - bfs = "."; - } else { - byte[] bf = bitfield.getFieldBytes(); - bfs = Base64.encode(bf); - } - _config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs); - saveConfig(); - } - - /** - * Remove the status of a torrent from the config file. - * This may help the config file from growing too big. - */ - public void removeTorrentStatus(MetaInfo metainfo) { - byte[] ih = metainfo.getInfoHash(); - String infohash = Base64.encode(ih); - infohash = infohash.replace('=', '$'); - _config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); - saveConfig(); - } - - private String locked_validateTorrent(MetaInfo info) throws IOException { - String announce = info.getAnnounce(); - // basic validation of url - if ((!announce.startsWith("http://")) || - (announce.indexOf(".i2p/") < 0)) // need to do better than this - return "Non-i2p tracker in " + info.getName() + ", deleting it from our list of trackers!"; - List files = info.getFiles(); - if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) { - return "Too many files in " + info.getName() + " (" + files.size() + "), deleting it!"; - } else if (info.getPieces() <= 0) { - return "No pieces in " + info.getName() + "? deleting it!"; - } else if (info.getPieceLength(0) > Storage.MAX_PIECE_SIZE) { - return "Pieces are too large in " + info.getName() + " (" + DataHelper.formatSize(info.getPieceLength(0)) + - "B), deleting it."; - } else if (info.getTotalLength() > Storage.MAX_TOTAL_SIZE) { - System.out.println("torrent info: " + info.toString()); - List lengths = info.getLengths(); - if (lengths != null) - for (int i = 0; i < lengths.size(); i++) - System.out.println("File " + i + " is " + lengths.get(i) + " long."); - - return "Torrents larger than " + DataHelper.formatSize(Storage.MAX_TOTAL_SIZE) + - "B are not supported yet (because we're paranoid): " + info.getName() + ", deleting it!"; - } else { - // ok - return null; - } - } - - /** - * Stop the torrent, leaving it on the list of torrents unless told to remove it - */ - public Snark stopTorrent(String filename, boolean shouldRemove) { - File sfile = new File(filename); - try { - filename = sfile.getCanonicalPath(); - } catch (IOException ioe) { - _log.error("Unable to remove the torrent " + filename, ioe); - addMessage("ERR: Could not remove the torrent '" + filename + "': " + ioe.getMessage()); - return null; - } - int remaining = 0; - Snark torrent = null; - synchronized (_snarks) { - if (shouldRemove) - torrent = (Snark)_snarks.remove(filename); - else - torrent = (Snark)_snarks.get(filename); - remaining = _snarks.size(); - } - if (torrent != null) { - boolean wasStopped = torrent.stopped; - torrent.stopTorrent(); - if (remaining == 0) { - // should we disconnect/reconnect here (taking care to deal with the other thread's - // I2PServerSocket.accept() call properly?) - ////_util. - } - if (!wasStopped) - addMessage("Torrent stopped: '" + sfile.getName() + "'."); - } - return torrent; - } - /** - * Stop the torrent and delete the torrent file itself, but leaving the data - * behind. - */ - public void removeTorrent(String filename) { - Snark torrent = stopTorrent(filename, true); - if (torrent != null) { - File torrentFile = new File(filename); - torrentFile.delete(); - if (torrent.storage != null) - removeTorrentStatus(torrent.storage.getMetaInfo()); - addMessage("Torrent removed: '" + torrentFile.getName() + "'."); - } - } - - private class DirMonitor implements Runnable { - public void run() { - try { Thread.sleep(60*1000*getStartupDelayMinutes()); } catch (InterruptedException ie) {} - // the first message was a "We are starting up in 1m" - synchronized (_messages) { - if (_messages.size() == 1) - _messages.remove(0); - } - - // here because we need to delay until I2CP is up - // although the user will see the default until then - getBWLimit(); - while (true) { - File dir = getDataDir(); - _log.debug("Directory Monitor loop over " + dir.getAbsolutePath()); - try { - monitorTorrents(dir); - } catch (Exception e) { - _log.error("Error in the DirectoryMonitor", e); - } - try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} - } - } - } - - /** two listeners */ - public void torrentComplete(Snark snark) { - File f = new File(snark.torrent); - long len = snark.meta.getTotalLength(); - addMessage("Download finished: " + f.getName() + " (size: " + DataHelper.formatSize(len) + "B)"); - updateStatus(snark); - } - - public void updateStatus(Snark snark) { - saveTorrentStatus(snark.meta, snark.storage.getBitField()); - } - - private void monitorTorrents(File dir) { - String fileNames[] = dir.list(TorrentFilenameFilter.instance()); - List foundNames = new ArrayList(0); - if (fileNames != null) { - for (int i = 0; i < fileNames.length; i++) { - try { - foundNames.add(new File(dir, fileNames[i]).getCanonicalPath()); - } catch (IOException ioe) { - _log.error("Error resolving '" + fileNames[i] + "' in '" + dir, ioe); - } - } - } - - Set existingNames = listTorrentFiles(); - // lets find new ones first... - for (int i = 0; i < foundNames.size(); i++) { - if (existingNames.contains(foundNames.get(i))) { - // already known. noop - } else { - if (shouldAutoStart() && !_util.connect()) - addMessage("Unable to connect to I2P!"); - addTorrent((String)foundNames.get(i), !shouldAutoStart()); - } - } - // now lets see which ones have been removed... - for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) { - String name = (String)iter.next(); - if (foundNames.contains(name)) { - // known and still there. noop - } else { - // known, but removed. drop it - stopTorrent(name, true); - } - } - } - - private static final String DEFAULT_TRACKERS[] = { -// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/" -// , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/" -// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/" -// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/" -// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/" -// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/" -// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php" -// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/" -// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/" - "POSTMAN", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/" - ,"WELTERDE", "http://BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA.i2p/a=http://tracker.welterde.i2p/stats?mode=top5" - , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/" - - }; - - /** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */ - public static final String PROP_TRACKERS = "i2psnark.trackers"; - private static Map trackerMap = null; - /** sorted map of name to announceURL=baseURL */ - public Map getTrackers() { - if (trackerMap != null) // only do this once, can't be updated while running - return trackerMap; - Map rv = new TreeMap(); - String trackers = _config.getProperty(PROP_TRACKERS); - if ( (trackers == null) || (trackers.trim().length() <= 0) ) - trackers = _context.getProperty(PROP_TRACKERS); - if ( (trackers == null) || (trackers.trim().length() <= 0) ) { - for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) - rv.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]); - } else { - StringTokenizer tok = new StringTokenizer(trackers, ","); - while (tok.hasMoreTokens()) { - String pair = tok.nextToken(); - int split = pair.indexOf('='); - if (split <= 0) - continue; - String name = pair.substring(0, split).trim(); - String url = pair.substring(split+1).trim(); - if ( (name.length() > 0) && (url.length() > 0) ) - rv.put(name, url); - } - } - - trackerMap = rv; - return trackerMap; - } - - private static class TorrentFilenameFilter implements FilenameFilter { - private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter(); - public static TorrentFilenameFilter instance() { return _filter; } - public boolean accept(File dir, String name) { - return (name != null) && (name.endsWith(".torrent")); - } - } - - public class SnarkManagerShutdown extends I2PAppThread { - @Override - public void run() { - Set names = listTorrentFiles(); - for (Iterator iter = names.iterator(); iter.hasNext(); ) { - Snark snark = getTorrent((String)iter.next()); - if ( (snark != null) && (!snark.stopped) ) - snark.stopTorrent(); - } - } - } -} +package org.klomp.snark; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeMap; + +import net.i2p.I2PAppContext; +import net.i2p.data.Base64; +import net.i2p.data.DataHelper; +import net.i2p.util.I2PAppThread; +import net.i2p.util.Log; + +/** + * Manage multiple snarks + */ +public class SnarkManager implements Snark.CompleteListener { + private static SnarkManager _instance = new SnarkManager(); + public static SnarkManager instance() { return _instance; } + + /** map of (canonical) filename to Snark instance (unsynchronized) */ + private final Map _snarks; + private final Object _addSnarkLock; + private /* FIXME final FIXME */ File _configFile; + private Properties _config; + private I2PAppContext _context; + private Log _log; + private final List _messages; + private I2PSnarkUtil _util; + private PeerCoordinatorSet _peerCoordinatorSet; + private ConnectionAcceptor _connectionAcceptor; + + public static final String PROP_I2CP_HOST = "i2psnark.i2cpHost"; + public static final String PROP_I2CP_PORT = "i2psnark.i2cpPort"; + public static final String PROP_I2CP_OPTS = "i2psnark.i2cpOptions"; + public static final String PROP_EEP_HOST = "i2psnark.eepHost"; + public static final String PROP_EEP_PORT = "i2psnark.eepPort"; + public static final String PROP_UPLOADERS_TOTAL = "i2psnark.uploaders.total"; + public static final String PROP_UPBW_MAX = "i2psnark.upbw.max"; + public static final String PROP_DIR = "i2psnark.dir"; + public static final String PROP_META_PREFIX = "i2psnark.zmeta."; + public static final String PROP_META_BITFIELD_SUFFIX = ".bitfield"; + + private static final String CONFIG_FILE = "i2psnark.config"; + public static final String PROP_AUTO_START = "i2snark.autoStart"; // oops + public static final String DEFAULT_AUTO_START = "false"; + public static final String PROP_LINK_PREFIX = "i2psnark.linkPrefix"; + public static final String DEFAULT_LINK_PREFIX = "file:///"; + + public static final int MIN_UP_BW = 2; + public static final int DEFAULT_MAX_UP_BW = 10; + + private SnarkManager() { + _snarks = new HashMap(); + _addSnarkLock = new Object(); + _context = I2PAppContext.getGlobalContext(); + _log = _context.logManager().getLog(SnarkManager.class); + _messages = new ArrayList(16); + _util = new I2PSnarkUtil(_context); + _configFile = new File(CONFIG_FILE); + if (!_configFile.isAbsolute()) + _configFile = new File(_context.getConfigDir(), CONFIG_FILE); + loadConfig(null); + } + + /** Caller _must_ call loadConfig(file) before this if setting new values + * for i2cp host/port or i2psnark.dir + */ + public void start() { + _peerCoordinatorSet = new PeerCoordinatorSet(); + _connectionAcceptor = new ConnectionAcceptor(_util); + int minutes = getStartupDelayMinutes(); + _messages.add("Adding torrents in " + minutes + (minutes == 1 ? " minute" : " minutes")); + I2PAppThread monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor"); + monitor.setDaemon(true); + monitor.start(); + _context.addShutdownTask(new SnarkManagerShutdown()); + } + + /** hook to I2PSnarkUtil for the servlet */ + public I2PSnarkUtil util() { return _util; } + + private static final int MAX_MESSAGES = 5; + public void addMessage(String message) { + synchronized (_messages) { + _messages.add(message); + while (_messages.size() > MAX_MESSAGES) + _messages.remove(0); + } + if (_log.shouldLog(Log.INFO)) + _log.info("MSG: " + message); + } + + /** newest last */ + public List getMessages() { + synchronized (_messages) { + return new ArrayList(_messages); + } + } + + public boolean shouldAutoStart() { + return Boolean.valueOf(_config.getProperty(PROP_AUTO_START, DEFAULT_AUTO_START+"")).booleanValue(); + } + public String linkPrefix() { + return _config.getProperty(PROP_LINK_PREFIX, DEFAULT_LINK_PREFIX + getDataDir().getAbsolutePath() + File.separatorChar); + } + private int getStartupDelayMinutes() { return 3; } + public File getDataDir() { + String dir = _config.getProperty(PROP_DIR, "i2psnark"); + File f = new File(dir); + if (!f.isAbsolute()) + f = new File(_context.getAppDir(), dir); + return f; + } + + /** null to set initial defaults */ + public void loadConfig(String filename) { + if (_config == null) + _config = new Properties(); + if (filename != null) { + File cfg = new File(filename); + if (!cfg.isAbsolute()) + cfg = new File(_context.getConfigDir(), filename); + _configFile = cfg; + if (cfg.exists()) { + try { + DataHelper.loadProps(_config, cfg); + } catch (IOException ioe) { + _log.error("Error loading I2PSnark config '" + filename + "'", ioe); + } + } + } + // now add sane defaults + if (!_config.containsKey(PROP_I2CP_HOST)) + _config.setProperty(PROP_I2CP_HOST, "127.0.0.1"); + if (!_config.containsKey(PROP_I2CP_PORT)) + _config.setProperty(PROP_I2CP_PORT, "7654"); + if (!_config.containsKey(PROP_I2CP_OPTS)) + _config.setProperty(PROP_I2CP_OPTS, "inbound.length=2 inbound.lengthVariance=0 outbound.length=2 outbound.lengthVariance=0 inbound.quantity=3 outbound.quantity=3"); + if (!_config.containsKey(PROP_EEP_HOST)) + _config.setProperty(PROP_EEP_HOST, "127.0.0.1"); + if (!_config.containsKey(PROP_EEP_PORT)) + _config.setProperty(PROP_EEP_PORT, "4444"); + if (!_config.containsKey(PROP_UPLOADERS_TOTAL)) + _config.setProperty(PROP_UPLOADERS_TOTAL, "" + Snark.MAX_TOTAL_UPLOADERS); + if (!_config.containsKey(PROP_DIR)) + _config.setProperty(PROP_DIR, "i2psnark"); + if (!_config.containsKey(PROP_AUTO_START)) + _config.setProperty(PROP_AUTO_START, DEFAULT_AUTO_START); + updateConfig(); + } + + /** call from DirMonitor since loadConfig() is called before router I2CP is up */ + private void getBWLimit() { + if (!_config.containsKey(PROP_UPBW_MAX)) { + int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort()); + if (limits != null && limits[1] > 0) + _util.setMaxUpBW(limits[1]); + } + } + + private void updateConfig() { + String i2cpHost = _config.getProperty(PROP_I2CP_HOST); + int i2cpPort = getInt(PROP_I2CP_PORT, 7654); + String opts = _config.getProperty(PROP_I2CP_OPTS); + Map i2cpOpts = new HashMap(); + if (opts != null) { + StringTokenizer tok = new StringTokenizer(opts, " "); + while (tok.hasMoreTokens()) { + String pair = tok.nextToken(); + int split = pair.indexOf('='); + if (split > 0) + i2cpOpts.put(pair.substring(0, split), pair.substring(split+1)); + } + } + if (i2cpHost != null) { + _util.setI2CPConfig(i2cpHost, i2cpPort, i2cpOpts); + _log.debug("Configuring with I2CP options " + i2cpOpts); + } + //I2PSnarkUtil.instance().setI2CPConfig("66.111.51.110", 7654, new Properties()); + String eepHost = _config.getProperty(PROP_EEP_HOST); + int eepPort = getInt(PROP_EEP_PORT, 4444); + if (eepHost != null) + _util.setProxy(eepHost, eepPort); + _util.setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS)); + _util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW)); + getDataDir().mkdirs(); + } + + private int getInt(String prop, int defaultVal) { + String p = _config.getProperty(prop); + try { + if ( (p != null) && (p.trim().length() > 0) ) + return Integer.parseInt(p.trim()); + } catch (NumberFormatException nfe) { + // ignore + } + return defaultVal; + } + + public void updateConfig(String dataDir, boolean autoStart, String seedPct, String eepHost, + String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts, + String upLimit, String upBW, boolean useOpenTrackers, String openTrackers) { + boolean changed = false; + if (eepHost != null) { + int port = _util.getEepProxyPort(); + try { port = Integer.parseInt(eepPort); } catch (NumberFormatException nfe) {} + String host = _util.getEepProxyHost(); + if ( (eepHost.trim().length() > 0) && (port > 0) && + ((!host.equals(eepHost) || (port != _util.getEepProxyPort()) )) ) { + _util.setProxy(eepHost, port); + changed = true; + _config.setProperty(PROP_EEP_HOST, eepHost); + _config.setProperty(PROP_EEP_PORT, eepPort+""); + addMessage("EepProxy location changed to " + eepHost + ":" + port); + } + } + if (upLimit != null) { + int limit = _util.getMaxUploaders(); + try { limit = Integer.parseInt(upLimit); } catch (NumberFormatException nfe) {} + if ( limit != _util.getMaxUploaders()) { + if ( limit >= Snark.MIN_TOTAL_UPLOADERS ) { + _util.setMaxUploaders(limit); + changed = true; + _config.setProperty(PROP_UPLOADERS_TOTAL, "" + limit); + addMessage("Total uploaders limit changed to " + limit); + } else { + addMessage("Minimum total uploaders limit is " + Snark.MIN_TOTAL_UPLOADERS); + } + } + } + if (upBW != null) { + int limit = _util.getMaxUpBW(); + try { limit = Integer.parseInt(upBW); } catch (NumberFormatException nfe) {} + if ( limit != _util.getMaxUpBW()) { + if ( limit >= MIN_UP_BW ) { + _util.setMaxUpBW(limit); + changed = true; + _config.setProperty(PROP_UPBW_MAX, "" + limit); + addMessage("Up BW limit changed to " + limit + "KBps"); + } else { + addMessage("Minimum Up BW limit is " + MIN_UP_BW + "KBps"); + } + } + } + if (i2cpHost != null) { + int oldI2CPPort = _util.getI2CPPort(); + String oldI2CPHost = _util.getI2CPHost(); + int port = oldI2CPPort; + try { port = Integer.parseInt(i2cpPort); } catch (NumberFormatException nfe) {} + String host = oldI2CPHost; + Map opts = new HashMap(); + if (i2cpOpts == null) i2cpOpts = ""; + StringTokenizer tok = new StringTokenizer(i2cpOpts, " \t\n"); + while (tok.hasMoreTokens()) { + String pair = tok.nextToken(); + int split = pair.indexOf('='); + if (split > 0) + opts.put(pair.substring(0, split), pair.substring(split+1)); + } + Map oldOpts = new HashMap(); + String oldI2CPOpts = _config.getProperty(PROP_I2CP_OPTS); + if (oldI2CPOpts == null) oldI2CPOpts = ""; + tok = new StringTokenizer(oldI2CPOpts, " \t\n"); + while (tok.hasMoreTokens()) { + String pair = tok.nextToken(); + int split = pair.indexOf('='); + if (split > 0) + oldOpts.put(pair.substring(0, split), pair.substring(split+1)); + } + + if ( (i2cpHost.trim().length() > 0) && (port > 0) && + ((!host.equals(i2cpHost) || + (port != _util.getI2CPPort()) || + (!oldOpts.equals(opts)))) ) { + boolean snarksActive = false; + Set names = listTorrentFiles(); + for (Iterator iter = names.iterator(); iter.hasNext(); ) { + Snark snark = getTorrent((String)iter.next()); + if ( (snark != null) && (!snark.stopped) ) { + snarksActive = true; + break; + } + } + if (snarksActive) { + addMessage("Cannot change the I2CP settings while torrents are active"); + _log.debug("i2cp host [" + i2cpHost + "] i2cp port " + port + " opts [" + opts + + "] oldOpts [" + oldOpts + "]"); + } else { + if (_util.connected()) { + _util.disconnect(); + addMessage("Disconnecting old I2CP destination"); + } + Properties p = new Properties(); + p.putAll(opts); + addMessage("I2CP settings changed to " + i2cpHost + ":" + port + " (" + i2cpOpts.trim() + ")"); + _util.setI2CPConfig(i2cpHost, port, p); + boolean ok = _util.connect(); + if (!ok) { + addMessage("Unable to connect with the new settings, reverting to the old I2CP settings"); + _util.setI2CPConfig(oldI2CPHost, oldI2CPPort, oldOpts); + ok = _util.connect(); + if (!ok) + addMessage("Unable to reconnect with the old settings!"); + } else { + addMessage("Reconnected on the new I2CP destination"); + _config.setProperty(PROP_I2CP_HOST, i2cpHost.trim()); + _config.setProperty(PROP_I2CP_PORT, "" + port); + _config.setProperty(PROP_I2CP_OPTS, i2cpOpts.trim()); + changed = true; + // no PeerAcceptors/I2PServerSockets to deal with, since all snarks are inactive + for (Iterator iter = names.iterator(); iter.hasNext(); ) { + String name = (String)iter.next(); + Snark snark = getTorrent(name); + if ( (snark != null) && (snark.acceptor != null) ) { + snark.acceptor.restart(); + addMessage("I2CP listener restarted for " + snark.meta.getName()); + } + } + } + } + changed = true; + } + } + if (shouldAutoStart() != autoStart) { + _config.setProperty(PROP_AUTO_START, autoStart + ""); + addMessage("Adjusted autostart to " + autoStart); + changed = true; + } + if (_util.shouldUseOpenTrackers() != useOpenTrackers) { + _config.setProperty(I2PSnarkUtil.PROP_USE_OPENTRACKERS, useOpenTrackers + ""); + addMessage((useOpenTrackers ? "En" : "Dis") + "abled open trackers - torrent restart required to take effect."); + changed = true; + } + if (openTrackers != null) { + if (openTrackers.trim().length() > 0 && !openTrackers.trim().equals(_util.getOpenTrackerString())) { + _config.setProperty(I2PSnarkUtil.PROP_OPENTRACKERS, openTrackers.trim()); + addMessage("Open Tracker list changed - torrent restart required to take effect."); + changed = true; + } + } + if (changed) { + saveConfig(); + } else { + addMessage("Configuration unchanged."); + } + } + + public void saveConfig() { + try { + synchronized (_configFile) { + DataHelper.storeProps(_config, _configFile); + } + } catch (IOException ioe) { + addMessage("Unable to save the config to '" + _configFile.getAbsolutePath() + "'."); + } + } + + public Properties getConfig() { return _config; } + + /** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */ + private static final int MAX_FILES_PER_TORRENT = 512; + + /** set of filenames that we are dealing with */ + public Set listTorrentFiles() { synchronized (_snarks) { return new HashSet(_snarks.keySet()); } } + /** + * Grab the torrent given the (canonical) filename + */ + public Snark getTorrent(String filename) { synchronized (_snarks) { return (Snark)_snarks.get(filename); } } + public void addTorrent(String filename) { addTorrent(filename, false); } + public void addTorrent(String filename, boolean dontAutoStart) { + if ((!dontAutoStart) && !_util.connected()) { + addMessage("Connecting to I2P"); + boolean ok = _util.connect(); + if (!ok) { + addMessage("Error connecting to I2P - check your I2CP settings!"); + return; + } + } + File sfile = new File(filename); + try { + filename = sfile.getCanonicalPath(); + } catch (IOException ioe) { + _log.error("Unable to add the torrent " + filename, ioe); + addMessage("ERR: Could not add the torrent '" + filename + "': " + ioe.getMessage()); + return; + } + File dataDir = getDataDir(); + Snark torrent = null; + synchronized (_snarks) { + torrent = (Snark)_snarks.get(filename); + } + // don't hold the _snarks lock while verifying the torrent + if (torrent == null) { + synchronized (_addSnarkLock) { + // double-check + synchronized (_snarks) { + if(_snarks.get(filename) != null) + return; + } + + FileInputStream fis = null; + try { + fis = new FileInputStream(sfile); + MetaInfo info = new MetaInfo(fis); + fis.close(); + fis = null; + + String rejectMessage = locked_validateTorrent(info); + if (rejectMessage != null) { + sfile.delete(); + addMessage(rejectMessage); + return; + } else { + torrent = new Snark(_util, filename, null, -1, null, null, this, + _peerCoordinatorSet, _connectionAcceptor, + false, dataDir.getPath()); + torrent.completeListener = this; + synchronized (_snarks) { + _snarks.put(filename, torrent); + } + } + } catch (IOException ioe) { + addMessage("Torrent in " + sfile.getName() + " is invalid: " + ioe.getMessage()); + if (sfile.exists()) + sfile.delete(); + return; + } finally { + if (fis != null) try { fis.close(); } catch (IOException ioe) {} + } + } + } else { + return; + } + // ok, snark created, now lets start it up or configure it further + File f = new File(filename); + if (!dontAutoStart && shouldAutoStart()) { + torrent.startTorrent(); + addMessage("Torrent added and started: '" + f.getName() + "'."); + } else { + addMessage("Torrent added: '" + f.getName() + "'."); + } + } + + /** + * Get the timestamp for a torrent from the config file + */ + public long getSavedTorrentTime(Snark snark) { + MetaInfo metainfo = snark.meta; + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + String time = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); + if (time == null) + return 0; + int comma = time.indexOf(','); + if (comma <= 0) + return 0; + time = time.substring(0, comma); + try { return Long.parseLong(time); } catch (NumberFormatException nfe) {} + return 0; + } + + /** + * Get the saved bitfield for a torrent from the config file. + * Convert "." to a full bitfield. + */ + public BitField getSavedTorrentBitField(Snark snark) { + MetaInfo metainfo = snark.meta; + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + String bf = _config.getProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); + if (bf == null) + return null; + int comma = bf.indexOf(','); + if (comma <= 0) + return null; + bf = bf.substring(comma + 1).trim(); + int len = metainfo.getPieces(); + if (bf.equals(".")) { + BitField bitfield = new BitField(len); + for (int i = 0; i < len; i++) + bitfield.set(i); + return bitfield; + } + byte[] bitfield = Base64.decode(bf); + if (bitfield == null) + return null; + if (bitfield.length * 8 < len) + return null; + return new BitField(bitfield, len); + } + + /** + * Save the completion status of a torrent and the current time in the config file + * in the form "i2psnark.zmeta.$base64infohash=$time,$base64bitfield". + * The config file property key is appended with the Base64 of the infohash, + * with the '=' changed to '$' since a key can't contain '='. + * The time is a standard long converted to string. + * The status is either a bitfield converted to Base64 or "." for a completed + * torrent to save space in the config file and in memory. + */ + public void saveTorrentStatus(MetaInfo metainfo, BitField bitfield) { + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + String now = "" + System.currentTimeMillis(); + String bfs; + if (bitfield.complete()) { + bfs = "."; + } else { + byte[] bf = bitfield.getFieldBytes(); + bfs = Base64.encode(bf); + } + _config.setProperty(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX, now + "," + bfs); + saveConfig(); + } + + /** + * Remove the status of a torrent from the config file. + * This may help the config file from growing too big. + */ + public void removeTorrentStatus(MetaInfo metainfo) { + byte[] ih = metainfo.getInfoHash(); + String infohash = Base64.encode(ih); + infohash = infohash.replace('=', '$'); + _config.remove(PROP_META_PREFIX + infohash + PROP_META_BITFIELD_SUFFIX); + saveConfig(); + } + + private String locked_validateTorrent(MetaInfo info) throws IOException { + String announce = info.getAnnounce(); + // basic validation of url + if ((!announce.startsWith("http://")) || + (announce.indexOf(".i2p/") < 0)) // need to do better than this + return "Non-i2p tracker in " + info.getName() + ", deleting it from our list of trackers!"; + List files = info.getFiles(); + if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) { + return "Too many files in " + info.getName() + " (" + files.size() + "), deleting it!"; + } else if (info.getPieces() <= 0) { + return "No pieces in " + info.getName() + "? deleting it!"; + } else if (info.getPieceLength(0) > Storage.MAX_PIECE_SIZE) { + return "Pieces are too large in " + info.getName() + " (" + DataHelper.formatSize(info.getPieceLength(0)) + + "B), deleting it."; + } else if (info.getTotalLength() > Storage.MAX_TOTAL_SIZE) { + System.out.println("torrent info: " + info.toString()); + List lengths = info.getLengths(); + if (lengths != null) + for (int i = 0; i < lengths.size(); i++) + System.out.println("File " + i + " is " + lengths.get(i) + " long."); + + return "Torrents larger than " + DataHelper.formatSize(Storage.MAX_TOTAL_SIZE) + + "B are not supported yet (because we're paranoid): " + info.getName() + ", deleting it!"; + } else { + // ok + return null; + } + } + + /** + * Stop the torrent, leaving it on the list of torrents unless told to remove it + */ + public Snark stopTorrent(String filename, boolean shouldRemove) { + File sfile = new File(filename); + try { + filename = sfile.getCanonicalPath(); + } catch (IOException ioe) { + _log.error("Unable to remove the torrent " + filename, ioe); + addMessage("ERR: Could not remove the torrent '" + filename + "': " + ioe.getMessage()); + return null; + } + int remaining = 0; + Snark torrent = null; + synchronized (_snarks) { + if (shouldRemove) + torrent = (Snark)_snarks.remove(filename); + else + torrent = (Snark)_snarks.get(filename); + remaining = _snarks.size(); + } + if (torrent != null) { + boolean wasStopped = torrent.stopped; + torrent.stopTorrent(); + if (remaining == 0) { + // should we disconnect/reconnect here (taking care to deal with the other thread's + // I2PServerSocket.accept() call properly?) + ////_util. + } + if (!wasStopped) + addMessage("Torrent stopped: '" + sfile.getName() + "'."); + } + return torrent; + } + /** + * Stop the torrent and delete the torrent file itself, but leaving the data + * behind. + */ + public void removeTorrent(String filename) { + Snark torrent = stopTorrent(filename, true); + if (torrent != null) { + File torrentFile = new File(filename); + torrentFile.delete(); + if (torrent.storage != null) + removeTorrentStatus(torrent.storage.getMetaInfo()); + addMessage("Torrent removed: '" + torrentFile.getName() + "'."); + } + } + + private class DirMonitor implements Runnable { + public void run() { + try { Thread.sleep(60*1000*getStartupDelayMinutes()); } catch (InterruptedException ie) {} + // the first message was a "We are starting up in 1m" + synchronized (_messages) { + if (_messages.size() == 1) + _messages.remove(0); + } + + // here because we need to delay until I2CP is up + // although the user will see the default until then + getBWLimit(); + while (true) { + File dir = getDataDir(); + _log.debug("Directory Monitor loop over " + dir.getAbsolutePath()); + try { + monitorTorrents(dir); + } catch (Exception e) { + _log.error("Error in the DirectoryMonitor", e); + } + try { Thread.sleep(60*1000); } catch (InterruptedException ie) {} + } + } + } + + /** two listeners */ + public void torrentComplete(Snark snark) { + File f = new File(snark.torrent); + long len = snark.meta.getTotalLength(); + addMessage("Download finished: " + f.getName() + " (size: " + DataHelper.formatSize(len) + "B)"); + updateStatus(snark); + } + + public void updateStatus(Snark snark) { + saveTorrentStatus(snark.meta, snark.storage.getBitField()); + } + + private void monitorTorrents(File dir) { + String fileNames[] = dir.list(TorrentFilenameFilter.instance()); + List foundNames = new ArrayList(0); + if (fileNames != null) { + for (int i = 0; i < fileNames.length; i++) { + try { + foundNames.add(new File(dir, fileNames[i]).getCanonicalPath()); + } catch (IOException ioe) { + _log.error("Error resolving '" + fileNames[i] + "' in '" + dir, ioe); + } + } + } + + Set existingNames = listTorrentFiles(); + // lets find new ones first... + for (int i = 0; i < foundNames.size(); i++) { + if (existingNames.contains(foundNames.get(i))) { + // already known. noop + } else { + if (shouldAutoStart() && !_util.connect()) + addMessage("Unable to connect to I2P!"); + addTorrent((String)foundNames.get(i), !shouldAutoStart()); + } + } + // now lets see which ones have been removed... + for (Iterator iter = existingNames.iterator(); iter.hasNext(); ) { + String name = (String)iter.next(); + if (foundNames.contains(name)) { + // known and still there. noop + } else { + // known, but removed. drop it + stopTorrent(name, true); + } + } + } + + private static final String DEFAULT_TRACKERS[] = { +// "Postman", "http://YRgrgTLGnbTq2aZOZDJQ~o6Uk5k6TK-OZtx0St9pb0G-5EGYURZioxqYG8AQt~LgyyI~NCj6aYWpPO-150RcEvsfgXLR~CxkkZcVpgt6pns8SRc3Bi-QSAkXpJtloapRGcQfzTtwllokbdC-aMGpeDOjYLd8b5V9Im8wdCHYy7LRFxhEtGb~RL55DA8aYOgEXcTpr6RPPywbV~Qf3q5UK55el6Kex-6VCxreUnPEe4hmTAbqZNR7Fm0hpCiHKGoToRcygafpFqDw5frLXToYiqs9d4liyVB-BcOb0ihORbo0nS3CLmAwZGvdAP8BZ7cIYE3Z9IU9D1G8JCMxWarfKX1pix~6pIA-sp1gKlL1HhYhPMxwyxvuSqx34o3BqU7vdTYwWiLpGM~zU1~j9rHL7x60pVuYaXcFQDR4-QVy26b6Pt6BlAZoFmHhPcAuWfu-SFhjyZYsqzmEmHeYdAwa~HojSbofg0TMUgESRXMw6YThK1KXWeeJVeztGTz25sL8AAAA.i2p/announce.php=http://tracker.postman.i2p/" +// , "eBook", "http://E71FRom6PZNEqTN2Lr8P-sr23b7HJVC32KoGnVQjaX6zJiXwhJy2HsXob36Qmj81TYFZdewFZa9mSJ533UZgGyQkXo2ahctg82JKYZfDe5uDxAn1E9YPjxZCWJaFJh0S~UwSs~9AZ7UcauSJIoNtpxrtbmRNVFLqnkEDdLZi26TeucfOmiFmIWnVblLniWv3tG1boE9Abd-6j3FmYVrRucYuepAILYt6katmVNOk6sXmno1Eynrp~~MBuFq0Ko6~jsc2E2CRVYXDhGHEMdt-j6JUz5D7S2RIVzDRqQyAZLKJ7OdQDmI31przzmne1vOqqqLC~1xUumZVIvF~yOeJUGNjJ1Vx0J8i2BQIusn1pQJ6UCB~ZtZZLQtEb8EPVCfpeRi2ri1M5CyOuxN0V5ekmPHrYIBNevuTCRC26NP7ZS5VDgx1~NaC3A-CzJAE6f1QXi0wMI9aywNG5KGzOPifcsih8eyGyytvgLtrZtV7ykzYpPCS-rDfITncpn5hliPUAAAA.i2p/pub/bt/announce.php=http://de-ebook-archiv.i2p/pub/bt/" +// , "Gaytorrents", "http://uxPWHbK1OIj9HxquaXuhMiIvi21iK0~ZiG9d8G0840ZXIg0r6CbiV71xlsqmdnU6wm0T2LySriM0doW2gUigo-5BNkUquHwOjLROiETnB3ZR0Ml4IGa6QBPn1aAq2d9~g1r1nVjLE~pcFnXB~cNNS7kIhX1d6nLgYVZf0C2cZopEow2iWVUggGGnAA9mHjE86zLEnTvAyhbAMTqDQJhEuLa0ZYSORqzJDMkQt90MV4YMjX1ICY6RfUSFmxEqu0yWTrkHsTtRw48l~dz9wpIgc0a0T9C~eeWvmBFTqlJPtQZwntpNeH~jF7nlYzB58olgV2HHFYpVYD87DYNzTnmNWxCJ5AfDorm6AIUCV2qaE7tZtI1h6fbmGpGlPyW~Kw5GXrRfJwNvr6ajwAVi~bPVnrBwDZezHkfW4slOO8FACPR28EQvaTu9nwhAbqESxV2hCTq6vQSGjuxHeOuzBOEvRWkLKOHWTC09t2DbJ94FSqETmZopTB1ukEmaxRWbKSIaAAAA.i2p/announce.php=http://gaytorrents.i2p/" +// , "NickyB", "http://9On6d3cZ27JjwYCtyJJbowe054d5tFnfMjv4PHsYs-EQn4Y4mk2zRixatvuAyXz2MmRfXG-NAUfhKr0KCxRNZbvHmlckYfT-WBzwwpiMAl0wDFY~Pl8cqXuhfikSG5WrqdPfDNNIBuuznS0dqaczf~OyVaoEOpvuP3qV6wKqbSSLpjOwwAaQPHjlRtNIW8-EtUZp-I0LT45HSoowp~6b7zYmpIyoATvIP~sT0g0MTrczWhbVTUZnEkZeLhOR0Duw1-IRXI2KHPbA24wLO9LdpKKUXed05RTz0QklW5ROgR6TYv7aXFufX8kC0-DaKvQ5JKG~h8lcoHvm1RCzNqVE-2aiZnO2xH08H-iCWoLNJE-Td2kT-Tsc~3QdQcnEUcL5BF-VT~QYRld2--9r0gfGl-yDrJZrlrihHGr5J7ImahelNn9PpkVp6eIyABRmJHf2iicrk3CtjeG1j9OgTSwaNmEpUpn4aN7Kx0zNLdH7z6uTgCGD9Kmh1MFYrsoNlTp4AAAA.i2p/bittorrent/announce.php=http://nickyb.i2p/bittorrent/" +// , "Orion", "http://gKik1lMlRmuroXVGTZ~7v4Vez3L3ZSpddrGZBrxVriosCQf7iHu6CIk8t15BKsj~P0JJpxrofeuxtm7SCUAJEr0AIYSYw8XOmp35UfcRPQWyb1LsxUkMT4WqxAT3s1ClIICWlBu5An~q-Mm0VFlrYLIPBWlUFnfPR7jZ9uP5ZMSzTKSMYUWao3ejiykr~mtEmyls6g-ZbgKZawa9II4zjOy-hdxHgP-eXMDseFsrym4Gpxvy~3Fv9TuiSqhpgm~UeTo5YBfxn6~TahKtE~~sdCiSydqmKBhxAQ7uT9lda7xt96SS09OYMsIWxLeQUWhns-C~FjJPp1D~IuTrUpAFcVEGVL-BRMmdWbfOJEcWPZ~CBCQSO~VkuN1ebvIOr9JBerFMZSxZtFl8JwcrjCIBxeKPBmfh~xYh16BJm1BBBmN1fp2DKmZ2jBNkAmnUbjQOqWvUcehrykWk5lZbE7bjJMDFH48v3SXwRuDBiHZmSbsTY6zhGY~GkMQHNGxPMMSIAAAA.i2p/bt/announce.php=http://orion.i2p/bt/" +// , "anonymity", "http://8EoJZIKrWgGuDrxA3nRJs1jsPfiGwmFWL91hBrf0HA7oKhEvAna4Ocx47VLUR9retVEYBAyWFK-eZTPcvhnz9XffBEiJQQ~kFSCqb1fV6IfPiV3HySqi9U5Caf6~hC46fRd~vYnxmaBLICT3N160cxBETqH3v2rdxdJpvYt8q4nMk9LUeVXq7zqCTFLLG5ig1uKgNzBGe58iNcsvTEYlnbYcE930ABmrzj8G1qQSgSwJ6wx3tUQNl1z~4wSOUMan~raZQD60lRK70GISjoX0-D0Po9WmPveN3ES3g72TIET3zc3WPdK2~lgmKGIs8GgNLES1cXTolvbPhdZK1gxddRMbJl6Y6IPFyQ9o4-6Rt3Lp-RMRWZ2TG7j2OMcNSiOmATUhKEFBDfv-~SODDyopGBmfeLw16F4NnYednvn4qP10dyMHcUASU6Zag4mfc2-WivrOqeWhD16fVAh8MoDpIIT~0r9XmwdaVFyLcjbXObabJczxCAW3fodQUnvuSkwzAAAA.i2p/anonymityTracker/announce.php=http://anonymityweb.i2p/anonymityTracker/" +// , "The freak's tracker", "http://mHKva9x24E5Ygfey2llR1KyQHv5f8hhMpDMwJDg1U-hABpJ2NrQJd6azirdfaR0OKt4jDlmP2o4Qx0H598~AteyD~RJU~xcWYdcOE0dmJ2e9Y8-HY51ie0B1yD9FtIV72ZI-V3TzFDcs6nkdX9b81DwrAwwFzx0EfNvK1GLVWl59Ow85muoRTBA1q8SsZImxdyZ-TApTVlMYIQbdI4iQRwU9OmmtefrCe~ZOf4UBS9-KvNIqUL0XeBSqm0OU1jq-D10Ykg6KfqvuPnBYT1BYHFDQJXW5DdPKwcaQE4MtAdSGmj1epDoaEBUa9btQlFsM2l9Cyn1hzxqNWXELmx8dRlomQLlV4b586dRzW~fLlOPIGC13ntPXogvYvHVyEyptXkv890jC7DZNHyxZd5cyrKC36r9huKvhQAmNABT2Y~pOGwVrb~RpPwT0tBuPZ3lHYhBFYmD8y~AOhhNHKMLzea1rfwTvovBMByDdFps54gMN1mX4MbCGT4w70vIopS9yAAAA.i2p/bytemonsoon/announce.php" +// , "mastertracker", "http://VzXD~stRKbL3MOmeTn1iaCQ0CFyTmuFHiKYyo0Rd~dFPZFCYH-22rT8JD7i-C2xzYFa4jT5U2aqHzHI-Jre4HL3Ri5hFtZrLk2ax3ji7Qfb6qPnuYkuiF2E2UDmKUOppI8d9Ye7tjdhQVCy0izn55tBaB-U7UWdcvSK2i85sauyw3G0Gfads1Rvy5-CAe2paqyYATcDmGjpUNLoxbfv9KH1KmwRTNH6k1v4PyWYYnhbT39WfKMbBjSxVQRdi19cyJrULSWhjxaQfJHeWx5Z8Ev4bSPByBeQBFl2~4vqy0S5RypINsRSa3MZdbiAAyn5tr5slWR6QdoqY3qBQgBJFZppy-3iWkFqqKgSxCPundF8gdDLC5ddizl~KYcYKl42y9SGFHIukH-TZs8~em0~iahzsqWVRks3zRG~tlBcX2U3M2~OJs~C33-NKhyfZT7-XFBREvb8Szmd~p66jDxrwOnKaku-G6DyoQipJqIz4VHmY9-y5T8RrUcJcM-5lVoMpAAAA.i2p/announce.php=http://tracker.mastertracker.i2p/" +// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/" + "POSTMAN", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/" + ,"WELTERDE", "http://BGKmlDOoH3RzFbPRfRpZV2FjpVj8~3moFftw5-dZfDf2070TOe8Tf2~DAVeaM6ZRLdmFEt~9wyFL8YMLMoLoiwGEH6IGW6rc45tstN68KsBDWZqkTohV1q9XFgK9JnCwE~Oi89xLBHsLMTHOabowWM6dkC8nI6QqJC2JODqLPIRfOVrDdkjLwtCrsckzLybNdFmgfoqF05UITDyczPsFVaHtpF1sRggOVmdvCM66otyonlzNcJbn59PA-R808vUrCPMGU~O9Wys0i-NoqtIbtWfOKnjCRFMNw5ex4n9m5Sxm9e20UkpKG6qzEuvKZWi8vTLe1NW~CBrj~vG7I3Ok4wybUFflBFOaBabxYJLlx4xTE1zJIVxlsekmAjckB4v-cQwulFeikR4LxPQ6mCQknW2HZ4JQIq6hL9AMabxjOlYnzh7kjOfRGkck8YgeozcyTvcDUcUsOuSTk06L4kdrv8h2Cozjbloi5zl6KTbj5ZTciKCxi73Pn9grICn-HQqEAAAA.i2p/a=http://tracker.welterde.i2p/stats?mode=top5" + , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/" + + }; + + /** comma delimited list of name=announceURL=baseURL for the trackers to be displayed */ + public static final String PROP_TRACKERS = "i2psnark.trackers"; + private static Map trackerMap = null; + /** sorted map of name to announceURL=baseURL */ + public Map getTrackers() { + if (trackerMap != null) // only do this once, can't be updated while running + return trackerMap; + Map rv = new TreeMap(); + String trackers = _config.getProperty(PROP_TRACKERS); + if ( (trackers == null) || (trackers.trim().length() <= 0) ) + trackers = _context.getProperty(PROP_TRACKERS); + if ( (trackers == null) || (trackers.trim().length() <= 0) ) { + for (int i = 0; i < DEFAULT_TRACKERS.length; i += 2) + rv.put(DEFAULT_TRACKERS[i], DEFAULT_TRACKERS[i+1]); + } else { + StringTokenizer tok = new StringTokenizer(trackers, ","); + while (tok.hasMoreTokens()) { + String pair = tok.nextToken(); + int split = pair.indexOf('='); + if (split <= 0) + continue; + String name = pair.substring(0, split).trim(); + String url = pair.substring(split+1).trim(); + if ( (name.length() > 0) && (url.length() > 0) ) + rv.put(name, url); + } + } + + trackerMap = rv; + return trackerMap; + } + + private static class TorrentFilenameFilter implements FilenameFilter { + private static final TorrentFilenameFilter _filter = new TorrentFilenameFilter(); + public static TorrentFilenameFilter instance() { return _filter; } + public boolean accept(File dir, String name) { + return (name != null) && (name.endsWith(".torrent")); + } + } + + public class SnarkManagerShutdown extends I2PAppThread { + @Override + public void run() { + Set names = listTorrentFiles(); + for (Iterator iter = names.iterator(); iter.hasNext(); ) { + Snark snark = getTorrent((String)iter.next()); + if ( (snark != null) && (!snark.stopped) ) + snark.stopTorrent(); + } + } + } +} From 35da3f333480bacc5afefd6167c44a1647a2c1d8 Mon Sep 17 00:00:00 2001 From: sponge Date: Sat, 15 Aug 2009 16:08:33 +0000 Subject: [PATCH 04/20] HTML bugfixes in routerconsole pages. --- .../i2p/router/web/ConfigAdvancedHandler.java | 1 + .../i2p/router/web/ConfigAdvancedHelper.java | 1 - .../i2p/router/web/ConfigClientsHandler.java | 7 +- .../i2p/router/web/ConfigClientsHelper.java | 1 - .../i2p/router/web/ConfigKeyringHandler.java | 2 +- .../i2p/router/web/ConfigKeyringHelper.java | 1 - .../i2p/router/web/ConfigLoggingHandler.java | 1 + .../i2p/router/web/ConfigLoggingHelper.java | 3 +- .../net/i2p/router/web/ConfigNetHandler.java | 3 +- .../net/i2p/router/web/ConfigNetHelper.java | 1 - .../net/i2p/router/web/ConfigPeerHandler.java | 5 +- .../net/i2p/router/web/ConfigPeerHelper.java | 1 - .../net/i2p/router/web/ConfigRestartBean.java | 4 +- .../i2p/router/web/ConfigServiceHandler.java | 4 +- .../i2p/router/web/ConfigStatsHandler.java | 1 + .../net/i2p/router/web/ConfigStatsHelper.java | 2 +- .../i2p/router/web/ConfigTunnelsHandler.java | 21 +-- .../i2p/router/web/ConfigTunnelsHelper.java | 3 +- .../net/i2p/router/web/ConfigUIHandler.java | 1 + .../net/i2p/router/web/ConfigUIHelper.java | 2 +- .../i2p/router/web/ConfigUpdateHandler.java | 1 + .../i2p/router/web/ConfigUpdateHelper.java | 1 - .../src/net/i2p/router/web/GraphHelper.java | 14 +- .../net/i2p/router/web/JobQueueHelper.java | 2 - .../src/net/i2p/router/web/LogsHelper.java | 2 +- .../src/net/i2p/router/web/NavHelper.java | 1 - .../src/net/i2p/router/web/NetDbHelper.java | 2 - .../net/i2p/router/web/OldConsoleHelper.java | 2 - .../src/net/i2p/router/web/PeerHelper.java | 2 - .../net/i2p/router/web/ProfilesHelper.java | 1 - .../src/net/i2p/router/web/StatHelper.java | 1 - .../net/i2p/router/web/StatsGenerator.java | 18 +-- .../src/net/i2p/router/web/SummaryHelper.java | 10 +- .../net/i2p/router/web/SummaryListener.java | 2 + .../src/net/i2p/router/web/TunnelHelper.java | 2 - .../i2p/router/web/UnsignedUpdateHandler.java | 5 +- .../src/net/i2p/router/web/UpdateHandler.java | 6 +- apps/routerconsole/jsp/config.jsp | 151 ++++++++---------- apps/routerconsole/jsp/configadvanced.jsp | 17 +- apps/routerconsole/jsp/configclients.jsp | 44 ++--- apps/routerconsole/jsp/configkeyring.jsp | 45 ++---- apps/routerconsole/jsp/configlogging.jsp | 65 +++----- apps/routerconsole/jsp/confignav.jsp | 5 +- apps/routerconsole/jsp/configpeer.jsp | 35 ++-- apps/routerconsole/jsp/configservice.jsp | 34 ++-- apps/routerconsole/jsp/configstats.jsp | 38 ++--- apps/routerconsole/jsp/configtunnels.jsp | 20 +-- apps/routerconsole/jsp/configui.jsp | 19 +-- apps/routerconsole/jsp/configupdate.jsp | 87 ++++------ apps/routerconsole/jsp/css.jsp | 10 +- apps/routerconsole/jsp/dumpprofile.jsp | 8 +- apps/routerconsole/jsp/error.jsp | 10 +- apps/routerconsole/jsp/graphs.jsp | 10 +- apps/routerconsole/jsp/help.jsp | 80 ++++------ apps/routerconsole/jsp/index.jsp | 15 +- apps/routerconsole/jsp/jobs.jsp | 12 +- apps/routerconsole/jsp/logs.jsp | 33 ++-- apps/routerconsole/jsp/netdb.jsp | 6 +- apps/routerconsole/jsp/oldconsole.jsp | 10 +- apps/routerconsole/jsp/oldstats.jsp | 10 +- apps/routerconsole/jsp/peers.jsp | 11 +- apps/routerconsole/jsp/profiles.jsp | 16 +- apps/routerconsole/jsp/summary.jsp | 4 +- apps/routerconsole/jsp/summaryframe.jsp | 15 +- apps/routerconsole/jsp/summarynoframe.jsp | 99 +++++------- apps/routerconsole/jsp/tunnels.jsp | 12 +- apps/routerconsole/jsp/viewstat.jsp | 8 +- 67 files changed, 409 insertions(+), 657 deletions(-) diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java index 3f60e57a9..230e9ec0e 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHandler.java @@ -17,6 +17,7 @@ public class ConfigAdvancedHandler extends FormHandler { private boolean _shouldSave; private String _config; + @Override protected void processForm() { if (_shouldSave) { saveChanges(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHelper.java index 5bffa2a21..a60a3409e 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigAdvancedHelper.java @@ -4,7 +4,6 @@ import java.util.Iterator; import java.util.Set; import java.util.TreeSet; -import net.i2p.router.RouterContext; public class ConfigAdvancedHelper extends HelperBase { public ConfigAdvancedHelper() {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java index 285cdd385..d2f4d8e64 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHandler.java @@ -20,13 +20,14 @@ import org.mortbay.jetty.Server; * Saves changes to clients.config or webapps.config */ public class ConfigClientsHandler extends FormHandler { - private Log _log; + private Log configClient_log; private Map _settings; public ConfigClientsHandler() { - _log = ContextHelper.getContext(null).logManager().getLog(ConfigClientsHandler.class); + configClient_log = ContextHelper.getContext(null).logManager().getLog(ConfigClientsHandler.class); } + @Override protected void processForm() { if (_action.startsWith("Save Client")) { saveClientChanges(); @@ -80,7 +81,7 @@ public class ConfigClientsHandler extends FormHandler { return; } ClientAppConfig ca = (ClientAppConfig) clients.get(i); - LoadClientAppsJob.runClient(ca.className, ca.clientName, LoadClientAppsJob.parseArgs(ca.args), _log); + LoadClientAppsJob.runClient(ca.className, ca.clientName, LoadClientAppsJob.parseArgs(ca.args), configClient_log); addFormNotice("Client " + ca.clientName + " started."); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java index 47b301d28..af71883eb 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigClientsHelper.java @@ -6,7 +6,6 @@ import java.util.Properties; import java.util.Set; import java.util.TreeSet; -import net.i2p.router.RouterContext; import net.i2p.router.startup.ClientAppConfig; public class ConfigClientsHelper extends HelperBase { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHandler.java index b43bc4d1f..9cb3bfceb 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHandler.java @@ -1,6 +1,5 @@ package net.i2p.router.web; -import net.i2p.I2PAppContext; import net.i2p.data.DataFormatException; import net.i2p.data.Hash; import net.i2p.data.SessionKey; @@ -13,6 +12,7 @@ public class ConfigKeyringHandler extends FormHandler { private String _peer; private String _key; + @Override protected void processForm() { if ("Add key".equals(_action)) { if (_peer == null || _key == null) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHelper.java index 85c8ee423..8c147fcdd 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigKeyringHelper.java @@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import net.i2p.router.RouterContext; public class ConfigKeyringHelper extends HelperBase { public ConfigKeyringHelper() {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHandler.java index a09f250a7..347cfdab7 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHandler.java @@ -18,6 +18,7 @@ public class ConfigLoggingHandler extends FormHandler { private String _dateFormat; private String _fileSize; + @Override protected void processForm() { if (_shouldSave) { saveChanges(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java index ab23fce6f..e1e7907b0 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigLoggingHelper.java @@ -4,7 +4,6 @@ import java.util.Iterator; import java.util.Properties; import java.util.TreeSet; -import net.i2p.router.RouterContext; public class ConfigLoggingHelper extends HelperBase { public ConfigLoggingHelper() {} @@ -43,7 +42,7 @@ public class ConfigLoggingHelper extends HelperBase { String level = limits.getProperty(prefix); buf.append(prefix).append('=').append(level).append('\n'); } - buf.append("
\n"); + buf.append("
\n"); buf.append("Add additional logging statements above. Example: net.i2p.router.tunnel=WARN
"); buf.append("Or put entries in the logger.config file. Example: logger.record.net.i2p.router.tunnel=WARN
"); buf.append("Valid levels are DEBUG, INFO, WARN, ERROR, CRIT\n"); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java index 1067eba54..b14bab7f8 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHandler.java @@ -1,12 +1,10 @@ package net.i2p.router.web; -import net.i2p.data.RouterInfo; import net.i2p.router.Router; import net.i2p.router.transport.FIFOBandwidthRefiller; import net.i2p.router.transport.TransportManager; import net.i2p.router.transport.udp.UDPTransport; import net.i2p.router.web.ConfigServiceHandler.UpdateWrapperManagerAndRekeyTask; -import net.i2p.time.Timestamper; /** * Handler to deal with form submissions from the main config form and act @@ -44,6 +42,7 @@ public class ConfigNetHandler extends FormHandler { private static final boolean _ratesOnly = false; // always false - delete me private static final String PROP_HIDDEN = Router.PROP_HIDDEN_HIDDEN; // see Router for other choice + @Override protected void processForm() { if (_saveRequested || ( (_action != null) && ("Save changes".equals(_action)) )) { saveChanges(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java index bf47f3efa..48426e448 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigNetHelper.java @@ -4,7 +4,6 @@ import net.i2p.data.DataHelper; import net.i2p.data.RouterAddress; import net.i2p.router.CommSystemFacade; import net.i2p.router.Router; -import net.i2p.router.RouterContext; import net.i2p.router.transport.Addresses; import net.i2p.router.transport.TransportManager; import net.i2p.router.transport.udp.UDPAddress; 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 48ec6e443..479aeb4c2 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHandler.java @@ -1,12 +1,8 @@ package net.i2p.router.web; -import net.i2p.I2PAppContext; -import net.i2p.data.DataHelper; import net.i2p.data.Hash; import net.i2p.data.Base64; -import net.i2p.router.Router; import net.i2p.router.peermanager.PeerProfile; -import net.i2p.util.Log; /** * @@ -16,6 +12,7 @@ public class ConfigPeerHandler extends FormHandler { private String _speed; private String _capacity; + @Override protected void processForm() { if ("Save Configuration".equals(_action)) { _context.router().saveConfig(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHelper.java index 662a078b8..9db6722b4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigPeerHelper.java @@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import net.i2p.router.RouterContext; public class ConfigPeerHelper extends HelperBase { public ConfigPeerHelper() {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java index c9ab42dde..d9f54e0c9 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigRestartBean.java @@ -51,14 +51,14 @@ public class ConfigRestartBean { if (timeRemaining <= 0) { return "Shutdown imminent"; } else { - return "Shutdown in " + DataHelper.formatDuration(timeRemaining) + "
" + return "Shutdown in " + DataHelper.formatDuration(timeRemaining) + "
" + buttons(urlBase, systemNonce, "shutdownImmediate,Shutdown immediately,cancelShutdown,Cancel shutdown"); } } else if (restarting) { if (timeRemaining <= 0) { return "Restart imminent"; } else { - return "Restart in " + DataHelper.formatDuration(timeRemaining) + "
" + return "Restart in " + DataHelper.formatDuration(timeRemaining) + "
" + buttons(urlBase, systemNonce, "restartImmediate,Restart immediately,cancelShutdown,Cancel restart"); } } else { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java index 195889fad..5271e0066 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigServiceHandler.java @@ -1,13 +1,10 @@ package net.i2p.router.web; -import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.util.List; import net.i2p.apps.systray.SysTray; import net.i2p.apps.systray.UrlLauncher; -import net.i2p.data.DataHelper; import net.i2p.router.Router; import net.i2p.router.startup.ClientAppConfig; @@ -49,6 +46,7 @@ public class ConfigServiceHandler extends FormHandler { } } + @Override protected void processForm() { if (_action == null) return; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java index 00a384e73..1d34a5db4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHandler.java @@ -28,6 +28,7 @@ public class ConfigStatsHandler extends FormHandler { _isFull = false; } + @Override protected void processForm() { saveChanges(); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHelper.java index 3af4ffafb..cb157bea8 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigStatsHelper.java @@ -8,7 +8,6 @@ import java.util.Map; import java.util.Set; import java.util.StringTokenizer; -import net.i2p.router.RouterContext; import net.i2p.stat.FrequencyStat; import net.i2p.stat.Rate; import net.i2p.stat.RateStat; @@ -38,6 +37,7 @@ public class ConfigStatsHelper extends HelperBase { * @param contextId begging few characters of the routerHash, or null to pick * the first one we come across. */ + @Override public void setContextId(String contextId) { try { _context = ContextHelper.getContext(contextId); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHandler.java index 0e59380e1..e54c92616 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHandler.java @@ -14,7 +14,7 @@ import net.i2p.util.Log; * */ public class ConfigTunnelsHandler extends FormHandler { - private Log _log; + private Log configTunnel_log; private Map _settings; private boolean _shouldSave; @@ -22,6 +22,7 @@ public class ConfigTunnelsHandler extends FormHandler { _shouldSave = false; } + @Override protected void processForm() { if (_shouldSave) { saveChanges(); @@ -43,11 +44,11 @@ public class ConfigTunnelsHandler extends FormHandler { * */ private void saveChanges() { - _log = _context.logManager().getLog(ConfigTunnelsHandler.class); + configTunnel_log = _context.logManager().getLog(ConfigTunnelsHandler.class); boolean saveRequired = false; - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Saving changes, with props = " + _settings + "."); + if (configTunnel_log.shouldLog(Log.DEBUG)) + configTunnel_log.debug("Saving changes, with props = " + _settings + "."); int updated = 0; int index = 0; @@ -110,16 +111,16 @@ public class ConfigTunnelsHandler extends FormHandler { } if ("exploratory".equals(poolName)) { - if (_log.shouldLog(Log.DEBUG)) { - _log.debug("Inbound exploratory settings: " + in); - _log.debug("Outbound exploratory settings: " + out); + if (configTunnel_log.shouldLog(Log.DEBUG)) { + configTunnel_log.debug("Inbound exploratory settings: " + in); + configTunnel_log.debug("Outbound exploratory settings: " + out); } _context.tunnelManager().setInboundSettings(in); _context.tunnelManager().setOutboundSettings(out); } else { - if (_log.shouldLog(Log.DEBUG)) { - _log.debug("Inbound settings for " + client.toBase64() + ": " + in); - _log.debug("Outbound settings for " + client.toBase64() + ": " + out); + if (configTunnel_log.shouldLog(Log.DEBUG)) { + configTunnel_log.debug("Inbound settings for " + client.toBase64() + ": " + in); + configTunnel_log.debug("Outbound settings for " + client.toBase64() + ": " + out); } _context.tunnelManager().setInboundSettings(client, in); _context.tunnelManager().setOutboundSettings(client, out); 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 e5e0a2922..6cd4346cc 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigTunnelsHelper.java @@ -5,7 +5,6 @@ import java.util.Properties; import java.util.Set; import net.i2p.data.Destination; -import net.i2p.router.RouterContext; import net.i2p.router.TunnelPoolSettings; public class ConfigTunnelsHelper extends HelperBase { @@ -177,7 +176,7 @@ buf.append("
\n"); -// buf.append("\n"); +// buf.append("\n"); } private void renderOptions(StringBuilder buf, int min, int max, int now, String prefix, String name) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java index ad7c1622e..f6c1e0134 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHandler.java @@ -5,6 +5,7 @@ public class ConfigUIHandler extends FormHandler { private boolean _shouldSave; private String _config; + @Override protected void processForm() { if (_shouldSave) saveChanges(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java index 11830975b..7815f5cba 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUIHelper.java @@ -12,7 +12,7 @@ public class ConfigUIHelper extends HelperBase { buf.append("").append(theme).append("
\n"); + buf.append("value=\"").append(theme).append("\"/>").append(theme).append("
\n"); } return buf.toString(); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java index 256babbe3..e1f6a657c 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHandler.java @@ -49,6 +49,7 @@ public class ConfigUpdateHandler extends FormHandler { public static final String PROP_TRUSTED_KEYS = "router.trustedUpdateKeys"; + @Override protected void processForm() { if ("Check for update now".equals(_action)) { NewsFetcher fetcher = NewsFetcher.getInstance(I2PAppContext.getGlobalContext()); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java index 263e98937..82d8461f1 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ConfigUpdateHelper.java @@ -3,7 +3,6 @@ package net.i2p.router.web; import net.i2p.I2PAppContext; import net.i2p.crypto.TrustedUpdate; import net.i2p.data.DataHelper; -import net.i2p.router.RouterContext; public class ConfigUpdateHelper extends HelperBase { public ConfigUpdateHelper() {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java index e9749750c..a771f52ef 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/GraphHelper.java @@ -1,14 +1,12 @@ package net.i2p.router.web; import java.io.IOException; -import java.io.Writer; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.TreeSet; import net.i2p.data.DataHelper; -import net.i2p.router.RouterContext; import net.i2p.stat.Rate; public class GraphHelper extends HelperBase { @@ -105,17 +103,17 @@ public class GraphHelper extends HelperBase { } public String getForm() { try { - _out.write("

Configure Graph Display

"); + _out.write("

Configure Graph Display

"); _out.write("

[Select Stats to Graph]

"); _out.write("
"); - _out.write("Periods:
\n"); + _out.write("Periods:
\n"); _out.write("Plot averages: "); - _out.write("or plot events:
\n"); + _out.write("or plot events:
\n"); _out.write("Image sizes: width: pixels, height:
\n"); - _out.write("Refresh delay:
\n"); - _out.write("


"); + + "\" />
\n"); + _out.write("Refresh delay:
\n"); + _out.write("
"); } catch (IOException ioe) { ioe.printStackTrace(); } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/JobQueueHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/JobQueueHelper.java index cf8ed2352..633e7db9f 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/JobQueueHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/JobQueueHelper.java @@ -3,9 +3,7 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import java.io.Writer; -import net.i2p.router.RouterContext; public class JobQueueHelper extends HelperBase { public JobQueueHelper() {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java index ca1712f1c..f51c4e772 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/LogsHelper.java @@ -10,7 +10,7 @@ public class LogsHelper extends HelperBase { public String getLogs() { String str = formatMessages(_context.logManager().getBuffer().getMostRecentMessages()); - return "Location: " + _context.logManager().currentFile() + "

" + str; + return "Location: " + _context.logManager().currentFile() + "

" + str; } public String getCriticalLogs() { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java index 1ae302932..cabb68f15 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NavHelper.java @@ -4,7 +4,6 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; -import net.i2p.router.RouterContext; public class NavHelper extends HelperBase { private static Map _apps = new HashMap(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java index 886ba6abb..cffe6f1a7 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/NetDbHelper.java @@ -3,9 +3,7 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import java.io.Writer; -import net.i2p.router.RouterContext; public class NetDbHelper extends HelperBase { private String _routerPrefix; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/OldConsoleHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/OldConsoleHelper.java index f7aa13064..b88187681 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/OldConsoleHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/OldConsoleHelper.java @@ -3,9 +3,7 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import java.io.Writer; -import net.i2p.router.RouterContext; public class OldConsoleHelper extends HelperBase { public OldConsoleHelper() {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/PeerHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/PeerHelper.java index 2504067ac..0648f4c42 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/PeerHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/PeerHelper.java @@ -1,9 +1,7 @@ package net.i2p.router.web; import java.io.IOException; -import java.io.Writer; -import net.i2p.router.RouterContext; public class PeerHelper extends HelperBase { private int _sortFlags; 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 702a63e50..ce2242aa7 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/ProfilesHelper.java @@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import net.i2p.router.RouterContext; public class ProfilesHelper extends HelperBase { public ProfilesHelper() {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/StatHelper.java index ce6fefd5d..2b7e81fb4 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatHelper.java @@ -1,6 +1,5 @@ package net.i2p.router.web; -import java.io.Writer; import java.util.Iterator; import java.util.Set; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java b/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java index 3838245f5..983a6ba8b 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/StatsGenerator.java @@ -80,7 +80,7 @@ public class StatsGenerator { buf.append(stat); buf.append("\">"); buf.append(stat); - buf.append("
"); + buf.append("
"); if (_context.statManager().isFrequency(stat)) renderFrequency(stat, buf); else @@ -88,7 +88,7 @@ public class StatsGenerator { out.write(buf.toString()); buf.setLength(0); } - out.write("
"); + out.write("
"); } out.flush(); } @@ -97,7 +97,7 @@ public class StatsGenerator { FrequencyStat freq = _context.statManager().getFrequency(name); buf.append(""); buf.append(freq.getDescription()); - buf.append("
"); + buf.append("
"); long uptime = _context.router().getUptime(); long periods[] = freq.getPeriods(); Arrays.sort(periods); @@ -124,9 +124,9 @@ public class StatsGenerator { buf.append(" using the lifetime of "); buf.append(curFreq.getEventCount()); buf.append(" events)"); - buf.append("
"); + buf.append("
"); } - buf.append("
"); + buf.append("
"); } private void renderRate(String name, StringBuilder buf) { @@ -135,10 +135,10 @@ public class StatsGenerator { if (! "".equals(d)) { buf.append(""); buf.append(d); - buf.append("
"); + buf.append("
"); } if (rate.getLifetimeEventCount() <= 0) { - buf.append("No lifetime events
 
"); + buf.append("No lifetime events
 
"); return; } long now = _context.clock().now(); @@ -217,9 +217,9 @@ public class StatsGenerator { buf.append(num(rate.getLifetimeAverageValue())); buf.append(" over "); buf.append(rate.getLifetimeEventCount()); - buf.append(" events
"); + buf.append(" events
"); buf.append(""); - buf.append("
"); + buf.append("
"); } private static void renderPeriod(StringBuilder buf, long period, String name) { diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java index 8305d64f3..b26b5770f 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryHelper.java @@ -1,15 +1,12 @@ package net.i2p.router.web; import java.text.Collator; -import java.text.DateFormat; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.Iterator; import java.util.List; -import java.util.Locale; import net.i2p.data.DataHelper; import net.i2p.data.Destination; @@ -18,7 +15,6 @@ import net.i2p.data.LeaseSet; import net.i2p.data.RouterAddress; import net.i2p.router.CommSystemFacade; import net.i2p.router.Router; -import net.i2p.router.RouterContext; import net.i2p.router.RouterVersion; import net.i2p.router.TunnelPoolSettings; import net.i2p.router.networkdb.kademlia.FloodfillNetworkDatabaseFacade; @@ -349,18 +345,18 @@ public class SummaryHelper extends HelperBase { String name = getName(client); Hash h = client.calculateHash(); - buf.append("\n"); + buf.append("\n"); LeaseSet ls = _context.netDb().lookupLeaseSetLocally(h); if (ls != null) { long timeToExpire = ls.getEarliestLeaseDate() - _context.clock().now(); diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java index 6ef9df9db..a7d1995dc 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java @@ -132,9 +132,11 @@ class SummaryListener implements RateSummaryListener { RrdDb getData() { return _db; } long now() { return _context.clock().now(); } + @Override public boolean equals(Object obj) { return ((obj instanceof SummaryListener) && ((SummaryListener)obj)._rate.equals(_rate)); } + @Override public int hashCode() { return _rate.hashCode(); } } diff --git a/apps/routerconsole/java/src/net/i2p/router/web/TunnelHelper.java b/apps/routerconsole/java/src/net/i2p/router/web/TunnelHelper.java index 3cd8a96e3..b605cbf36 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/TunnelHelper.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/TunnelHelper.java @@ -3,9 +3,7 @@ package net.i2p.router.web; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; -import java.io.Writer; -import net.i2p.router.RouterContext; public class TunnelHelper extends HelperBase { public TunnelHelper() {} diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java index 0d812d0ec..a11f86846 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UnsignedUpdateHandler.java @@ -2,7 +2,6 @@ package net.i2p.router.web; import java.io.File; -import net.i2p.I2PAppContext; import net.i2p.router.Router; import net.i2p.router.RouterContext; import net.i2p.util.EepGet; @@ -99,11 +98,11 @@ public class UnsignedUpdateHandler extends UpdateHandler { _context.router().saveConfig(); if ("install".equals(policy)) { _log.log(Log.CRIT, "Update was downloaded, restarting to install it"); - _status = "Update downloaded
Restarting"; + _status = "Update downloaded
Restarting"; restart(); } else { _log.log(Log.CRIT, "Update was downloaded, will be installed at next restart"); - _status = "Update downloaded
"; + _status = "Update downloaded
"; if (System.getProperty("wrapper.version") != null) _status += "Click Restart to install"; else diff --git a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java index f8890482d..fc3b77e05 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/UpdateHandler.java @@ -167,7 +167,7 @@ public class UpdateHandler { synchronized (_pct) { buf.append(_pct.format(pct)); } - buf.append(":
\n" + (currentWrite + alreadyTransferred)); + buf.append(":
\n" + (currentWrite + alreadyTransferred)); buf.append(" transferred"); _status = buf.toString(); } @@ -192,11 +192,11 @@ public class UpdateHandler { _context.router().saveConfig(); if ("install".equals(policy)) { _log.log(Log.CRIT, "Update was VERIFIED, restarting to install it"); - _status = "Update verified
Restarting"; + _status = "Update verified
Restarting"; restart(); } else { _log.log(Log.CRIT, "Update was VERIFIED, will be installed at next restart"); - _status = "Update downloaded
"; + _status = "Update downloaded
"; if (System.getProperty("wrapper.version") != null) _status += "Click Restart to install"; else diff --git a/apps/routerconsole/jsp/config.jsp b/apps/routerconsole/jsp/config.jsp index b91a1ce24..443e8f708 100644 --- a/apps/routerconsole/jsp/config.jsp +++ b/apps/routerconsole/jsp/config.jsp @@ -13,7 +13,7 @@

I2P Network Configuration

<%@include file="confignav.jsp" %> - + " /> @@ -25,45 +25,42 @@ System.setProperty("net.i2p.router.web.ConfigNetHandler.nonce", new java.util.Random().nextLong()+""); %> " /> -

Bandwidth limiter

-

+

Bandwidth limiter

I2P will work best if you configure your rates to match the speed of your internet connection. -

-

-

-
Exploratory:/
Client:/


\"Server\""); else buf.append("client.png\" alt=\"Client\" title=\"Client\" />"); - buf.append(""); if (name.length() < 16) buf.append(name); else buf.append(name.substring(0,15)).append("…"); - buf.append("
-
" /> KBps - In ()
- -
" /> KBps - Out ()
- -
- Share ()
-

+

+ + + + + + +
" /> KBps In + ()
" /> KBps Out + ()
Share() +

<% int share = nethelper.getShareBandwidth(); if (share < 12) { out.print("NOTE: You have configured I2P to share only " + share + "KBps. "); out.print("I2P requires at least 12KBps to enable sharing. "); out.print("Please enable sharing (participating in tunnels) by configuring more bandwidth. "); - out.print("It improves your anonymity by creating cover traffic, and helps the network.
"); + out.print("It improves your anonymity by creating cover traffic, and helps the network.
"); } else { out.print("You have configured I2P to share " + share + "KBps. "); - out.print("The higher the share bandwidth the more you improve your anonymity and help the network.


"); + out.print("The higher the share bandwidth the more you improve your anonymity and help the network.
"); } %> -

+

-

IP and Transport Configuration

-

+

IP and Transport Configuration

The default settings will work for most people. There is help below. -

- UPnP Configuration:
+

UPnP Configuration:
/> Enable UPnP to open firewall ports - UPnP status -

- IP Configuration:
- Externally reachable hostname or IP address:
+

IP Configuration:
+ Externally reachable hostname or IP address:
/> - Use all auto-detect methods
+ Use all auto-detect methods
/> - Disable UPnP IP address detection
+ Disable UPnP IP address detection
/> - Ignore local interface IP address
+ Ignore local interface IP address
/> - Use SSU IP address detection only
+ Use SSU IP address detection only
/> Specify hostname or IP: " /> @@ -109,52 +103,47 @@ out.print("\n"); } %> -
+
/> - Hidden mode - do not publish IP (prevents participating traffic)
-

- UDP Configuration:
+ Hidden mode - do not publish IP (prevents participating traffic)
+

UDP Configuration:
UDP port: - " />
+ " />

- TCP Configuration:
- Externally reachable hostname or IP address:
+ TCP Configuration:
+ Externally reachable hostname or IP address:
/> Use auto-detected IP address (currently ) - if we are not firewalled
+ if we are not firewalled
/> - Always use auto-detected IP address (Not firewalled)
+ Always use auto-detected IP address (Not firewalled)
/> Specify hostname or IP: - " />
+ " />
/> - Disable inbound (Firewalled)
+ Disable inbound (Firewalled)
/> - Completely disable (select only if behind a firewall that throttles or blocks outbound TCP)
+ Completely disable (select only if behind a firewall that throttles or blocks outbound TCP)

- Externally reachable TCP port:
+ Externally reachable TCP port:
/> Use the same port configured for UDP - (currently )
+ (currently )
/> Specify Port: - " />
-

Note: Changing these settings will restart your router. -


+ " />
+

Note: Changing these settings will restart your router.

+
-
-
-

Configuration Help:

-
-

+

Configuration Help:

While I2P will work fine behind most firewalls, your speeds and network integration will generally improve if the I2P port (generally 8887) is forwarded for both UDP and TCP.

@@ -166,30 +155,30 @@

-

+

UPnP is used to communicate with Internet Gateway Devices (IGDs) to detect the external IP address and forward ports. UPnP support is beta, and may not work for any number of reasons: -

    +
    • No UPnP-compatible device present
    • UPnP disabled on the device
    • Software firewall interference with UPnP
    • Bugs in the device's UPnP implementation
    • Multiple firewall/routers in the internet connection path
    • UPnP device change, reset, or address change -

    +

Reviewing the UPnP status may help. UPnP may be enabled or disabled above, but a change requires a router restart to take effect. -

Hostnames entered above will be published in the network database. +

Hostnames entered above will be published in the network database. They are not private. Also, do not enter a private IP address like 127.0.0.1 or 192.168.1.1. If you specify the wrong IP address or hostname, or do not properly configure your NAT or firewall, your network performance will degrade - substantially. When in doubt, leave the settings at the defaults.

-

-

Reachability Help:

-

+ substantially. When in doubt, leave the settings at the defaults. +

+

Reachability Help:

While I2P will work fine behind most firewalls, your speeds and network integration will generally improve if the I2P port (generally 8887) to both UDP and TCP. If you think you have opened up your firewall and I2P still thinks you are firewalled, remember @@ -244,19 +233,17 @@

  • ERR - Client Manager I2CP Error - check logs - This is usually due to a port 7654 conflict. Check the logs to verify. Do you have another I2P instance running? Stop the conflicting program and restart I2P. - -

    -
    +


    - -
  • -
    - - + diff --git a/apps/routerconsole/jsp/configadvanced.jsp b/apps/routerconsole/jsp/configadvanced.jsp index 6fe8723dc..00e4a193a 100644 --- a/apps/routerconsole/jsp/configadvanced.jsp +++ b/apps/routerconsole/jsp/configadvanced.jsp @@ -2,8 +2,7 @@ <%@page pageEncoding="UTF-8"%> - -I2P Router Console - config advanced +I2P Router Console - config advanced <%@include file="css.jsp" %> @@ -30,15 +29,9 @@ " />

    Advanced I2P Configuration

    -

    -
    +

    +
    -
    +
    NOTE: Some changes may require a restart to take effect. -
    - -
    - - - - + diff --git a/apps/routerconsole/jsp/configclients.jsp b/apps/routerconsole/jsp/configclients.jsp index 8921987f4..aa5a8395a 100644 --- a/apps/routerconsole/jsp/configclients.jsp +++ b/apps/routerconsole/jsp/configclients.jsp @@ -2,15 +2,13 @@ <%@page pageEncoding="UTF-8"%> - -I2P Router Console - config clients +I2P Router Console - config clients <%@include file="css.jsp" %> - + <%@include file="summary.jsp" %> @@ -19,31 +17,26 @@ button span.hide{

    I2P Client Configuration

    <%@include file="confignav.jsp" %> - + " /> " /> " /> -
    -
    +
    <% String prev = System.getProperty("net.i2p.router.web.ConfigClientsHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigClientsHandler.noncePrev", prev); System.setProperty("net.i2p.router.web.ConfigClientsHandler.nonce", new java.util.Random().nextLong()+""); %> " /> -

    Client Configuration

    -

    +

    Client Configuration

    The Java clients listed below are started by the router and run in the same JVM. -

    - -

    - All changes require restart to take effect. To change other client options, edit the clients.config file. -


    +

    +

    +

    All changes require restart to take effect. To change other client options, edit the clients.config file. +


    -
    -

    WebApp Configuration

    -

    +

    WebApp Configuration

    The Java web applications listed below are started by the webConsole client and run in the same JVM as the router. They are usually web applications accessible through the router console. They may be complete applications (e.g. i2psnark), @@ -53,18 +46,11 @@ button span.hide{ A web app may also be disabled by removing the .war file from the webapps directory; however the .war file and web app will reappear when you update your router to a newer version, so disabling the web app here is the preferred method. -

    +

    +

    -

    -

    +

    All changes require restart to take effect. To change other webapp options, edit the webapps.config file. -

    -
    +


    -
    - -
    -
    -
    - - +
    diff --git a/apps/routerconsole/jsp/configkeyring.jsp b/apps/routerconsole/jsp/configkeyring.jsp index 7e58f4a15..88957858d 100644 --- a/apps/routerconsole/jsp/configkeyring.jsp +++ b/apps/routerconsole/jsp/configkeyring.jsp @@ -2,8 +2,7 @@ <%@page pageEncoding="UTF-8"%> - -I2P Router Console - config keyring +I2P Router Console - config keyring <%@include file="css.jsp" %> @@ -16,21 +15,16 @@ " /> - - - " /> -
    -

    -

    Keyring

    +

    Keyring

    The router keyring is used to decrypt encrypted leaseSets. The keyring may contain keys for local or remote encrypted destinations. -

    +

    -
    +
    <% String prev = System.getProperty("net.i2p.router.web.ConfigKeyringHandler.nonce"); @@ -41,23 +35,14 @@ Enter keys for encrypted remote destinations here. Keys for local destinations must be entered on the I2PTunnel page.

    -

    - - - - - - - - - -
    Dest. name, hash, or full key:
    Session Key:
    - -
    - - -
    -
    -
    - - +
    + + + + + + + + + +
    Dest. name, hash, or full key:
    Session Key:
    diff --git a/apps/routerconsole/jsp/configlogging.jsp b/apps/routerconsole/jsp/configlogging.jsp index 432acdfb8..31caf5994 100644 --- a/apps/routerconsole/jsp/configlogging.jsp +++ b/apps/routerconsole/jsp/configlogging.jsp @@ -18,7 +18,7 @@ " /> -
    +
    <% String prev = System.getProperty("net.i2p.router.web.ConfigLoggingHandler.nonce"); if (prev != null) System.setProperty("net.i2p.router.web.ConfigLoggingHandler.noncePrev", prev); @@ -28,43 +28,26 @@

    Configure I2P Logging Options

    - - - - - - - - -
    Logging filename: - " /> -
    (the symbol '@' will be replaced during log rotation) -
    Log record format: - " /> -
    (use 'd' = date, 'c' = class, 't' = thread, 'p' = priority, - 'm' = message) -
    Log date format: - " /> -
    ('MM' = month, 'dd' = day, 'HH' = hour, 'mm' = minute, 'ss' - = second, 'SSS' = millisecond) -
    Max log file size: - " /> -
    -
    Default log level: -
    (DEBUG and INFO are not recommended defaults, - as they will drastically slow down your router) -
    Log level overrides: - -

    -
    -
    - - -
    -
    - -
    -
    -
    - - + Logging filename: + " /> +
    (the symbol '@' will be replaced during log rotation) + Log record format: + " /> +
    (use 'd' = date, 'c' = class, 't' = thread, 'p' = priority, + 'm' = message) + Log date format: + " /> +
    ('MM' = month, 'dd' = day, 'HH' = hour, 'mm' = minute, 'ss' + = second, 'SSS' = millisecond) + Max log file size: + " />
    + Default log level: +
    (DEBUG and INFO are not recommended defaults, + as they will drastically slow down your router) + Log level overrides: + +
    +
    + + +
    diff --git a/apps/routerconsole/jsp/confignav.jsp b/apps/routerconsole/jsp/confignav.jsp index 37b6adbd0..bba31052e 100644 --- a/apps/routerconsole/jsp/confignav.jsp +++ b/apps/routerconsole/jsp/confignav.jsp @@ -1,6 +1,6 @@
    -<% if (request.getRequestURI().indexOf("config.jsp") != -1) { +<% if (request.getRequestURI().indexOf("config.jsp") != -1) { %>Network | <% } else { %>Network | <% } String userAgent = request.getHeader("User-Agent"); if (userAgent == null || !userAgent.contains("MSIE")) { @@ -25,5 +25,4 @@ %>Stats | <% } else { %>Stats | <% } if (request.getRequestURI().indexOf("configadvanced.jsp") != -1) { %>Advanced<% } else { %>Advanced<% } %> -
    -
    + diff --git a/apps/routerconsole/jsp/configpeer.jsp b/apps/routerconsole/jsp/configpeer.jsp index cc759d936..b78fff136 100644 --- a/apps/routerconsole/jsp/configpeer.jsp +++ b/apps/routerconsole/jsp/configpeer.jsp @@ -2,8 +2,7 @@ <%@page pageEncoding="UTF-8"%> - -I2P Router Console - config peers +I2P Router Console - config peers <%@include file="css.jsp" %> @@ -11,19 +10,19 @@

    I2P Peer Configuration

    <%@include file="confignav.jsp" %> - + " /> - + " /> <% String peer = ""; - if (request.getParameter("peer") != null) + if (request.getParameter("peer") != null) peer = request.getParameter("peer"); %>
    @@ -40,9 +39,9 @@
    Router Hash:

    Manually Ban / Unban a Peer

    - Shitlisting will prevent the participation of this peer in tunnels you create. -
    -
    + Shitlisting will prevent the participation of this peer in tunnels you create. +
    +
    <% if (! "".equals(peer)) { %> @@ -51,17 +50,17 @@

    Adjust Profile Bonuses

    - Bonuses may be positive or negative, and affect the peer's inclusion in Fast - and High Capacity tiers. Fast peers are used for client tunnels, and High - Capacity peers are used for some exploratory tunnels. Current bonuses are - displayed on the profiles page. + Bonuses may be positive or negative, and affect the peer's inclusion in Fast + and High Capacity tiers. Fast peers are used for client tunnels, and High + Capacity peers are used for some exploratory tunnels. Current bonuses are + displayed on the profiles page.

    <% long speed = 0; long capacity = 0; if (! "".equals(peer)) { // get existing bonus values? } - %> -


    + %> +
    Speed: Capacity: @@ -73,12 +72,8 @@ " /> -
    +
    -
    -
    -
    - - +
    diff --git a/apps/routerconsole/jsp/configservice.jsp b/apps/routerconsole/jsp/configservice.jsp index 942aedf0d..45b5e435f 100644 --- a/apps/routerconsole/jsp/configservice.jsp +++ b/apps/routerconsole/jsp/configservice.jsp @@ -2,8 +2,7 @@ <%@page pageEncoding="UTF-8"%> - -I2P Router Console - config service +I2P Router Console - config service <%@include file="css.jsp" %> @@ -11,7 +10,7 @@

    I2P Service Configuration

    <%@include file="confignav.jsp" %> - + " /> @@ -23,7 +22,7 @@ System.setProperty("net.i2p.router.web.ConfigServiceHandler.nonce", new java.util.Random().nextLong()+""); %> " />

    Shutdown the router

    -

    Graceful shutdown lets the router satisfy the agreements it has already made +

    Graceful shutdown lets the router satisfy the agreements it has already made before shutting down, but may take a few minutes. If you need to kill the router immediately, that option is available as well.


    @@ -32,7 +31,7 @@
    <% if (System.getProperty("wrapper.version") != null) { %> -

    If you want the router to restart itself after shutting down, you can choose one of +

    If you want the router to restart itself after shutting down, you can choose one of the following. This is useful in some situations - for example, if you changed some settings that client applications only read at startup, such as the routerconsole password or the interface it listens on. A graceful restart will take a few minutes (but your peers @@ -45,46 +44,41 @@ <% if ( (System.getProperty("os.name") != null) && (System.getProperty("os.name").startsWith("Win")) ) { %>

    Systray integration

    -

    On the windows platform, there is a small application to sit in the system +

    On the windows platform, there is a small application to sit in the system tray, allowing you to view the router's status (later on, I2P client applications will be able to integrate their own functionality into the system tray as well). If you are on windows, you can either enable or disable that icon here.


    -
    -

    Run on startup

    -

    You can control whether I2P is run on startup or not by selecting one of the +

    Run on startup

    +

    You can control whether I2P is run on startup or not by selecting one of the following options - I2P will install (or remove) a service accordingly. You can - also run the install_i2p_service_winnt.bat (or + also run the install_i2p_service_winnt.bat (or uninstall_i2p_service_winnt.bat) from the command line, if you prefer.


    -

    Note: If you are running I2P as service right now, removing it will shut +

    Note: If you are running I2P as service right now, removing it will shut down your router immediately. You may want to consider shutting down gracefully, as above, then running uninstall_i2p_service_winnt.bat.

    <% } %> <% if (System.getProperty("wrapper.version") != null) { %>

    Debugging

    -

    At times, it may be helpful to debug I2P by getting a thread dump. To do so, - please select the following option and review the thread dumped to +

    At times, it may be helpful to debug I2P by getting a thread dump. To do so, + please select the following option and review the thread dumped to wrapper.log.


    <% } %>
    - +

    Launch browser on router startup?

    I2P's main configuration interface is this web console, so for your convenience - I2P can launch a web browser pointing at + I2P can launch a web browser pointing at http://127.0.0.1:7657/index.jsp whenever the router starts up.


    -
    - - - - + diff --git a/apps/routerconsole/jsp/configstats.jsp b/apps/routerconsole/jsp/configstats.jsp index 9a2435ec4..122d035c3 100644 --- a/apps/routerconsole/jsp/configstats.jsp +++ b/apps/routerconsole/jsp/configstats.jsp @@ -2,8 +2,7 @@ <%@page pageEncoding="UTF-8"%> - -I2P Router Console - config stats +I2P Router Console - config stats <%@include file="css.jsp" %>