forked from I2P_Developers/i2p.i2p
Compare commits
1551 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c74b489d4a | ||
|
|
1661f1e8e8 | ||
|
|
a25719b332 | ||
|
|
b1602f603b | ||
|
|
d64483189b | ||
|
|
793b51c026 | ||
|
|
fbcee7bf0d | ||
|
|
b0e80c0ba0 | ||
|
|
2aaa6c7d1c | ||
|
|
4fcdbebc61 | ||
|
|
0ca2b71783 | ||
|
|
4109992fd0 | ||
|
|
09366fb46e | ||
|
|
a2069da48f | ||
|
|
c079788998 | ||
|
|
f2998831bb | ||
|
|
09baa49370 | ||
|
|
e617059b30 | ||
| 372dbcedfa | |||
| 492056e99e | |||
|
|
6ffdb70e4c | ||
|
|
ddfa8ef3cd | ||
|
|
b0f786e17c | ||
|
|
d7e97a16a2 | ||
|
|
7e9e78fed5 | ||
|
|
085bbbb6e6 | ||
|
|
37cdade492 | ||
|
|
a1949bf612 | ||
|
|
f7d2893751 | ||
|
|
8bfbcf1e92 | ||
|
|
ae84bf4021 | ||
|
|
fed7cacdab | ||
|
|
f04bcd95a1 | ||
|
|
a9b9a4c404 | ||
|
|
30a3806da8 | ||
|
|
62f750062d | ||
|
|
5c28c7f0a4 | ||
|
|
4da55dd3ab | ||
|
|
b57afabc13 | ||
| 247b28606c | |||
| bc5ca78794 | |||
|
|
45f81ede6d | ||
|
|
a2f31c5b55 | ||
|
|
c7d15eb6d1 | ||
|
|
29d131827a | ||
|
|
0e2a88ac16 | ||
|
|
1e5b850a92 | ||
|
|
b2b86b2767 | ||
|
|
c9b17b8cd5 | ||
|
|
2bec64c55a | ||
|
|
115c165bb6 | ||
|
|
049ddb3717 | ||
|
|
914a85492c | ||
|
|
f861886bef | ||
|
|
d1adac5d8d | ||
|
|
7576853c18 | ||
|
|
ad503542b3 | ||
|
|
2ffa17c633 | ||
|
|
1350d7996b | ||
|
|
7d896de3c7 | ||
|
|
8336886db6 | ||
|
|
ef33998a71 | ||
|
|
562e6dfe0d | ||
|
|
ec817d0b40 | ||
|
|
cd368773d3 | ||
|
|
8f1fa4ce99 | ||
|
|
4124d8d7a9 | ||
|
|
2a5a9606b8 | ||
|
|
a5c17022a5 | ||
|
|
5234e06926 | ||
|
|
9154945571 | ||
|
|
86819852e7 | ||
|
|
327b147582 | ||
|
|
910a44484f | ||
|
|
0dbce02d7f | ||
|
|
610baa8e24 | ||
|
|
63e13c8f27 | ||
|
|
4eb70e97f4 | ||
|
|
afe0704e3b | ||
|
|
bca5b65b1a | ||
| 7296bdc32c | |||
|
|
3cb12b66f6 | ||
|
|
f093b56dc3 | ||
|
|
2447310f91 | ||
|
|
a51d64513a | ||
|
|
4beb858d39 | ||
| 7ca36e011a | |||
| 797c578894 | |||
| 702f95b384 | |||
| 4e20380a95 | |||
| 43d68d45ad | |||
|
|
8955397bc0 | ||
|
|
aa4e6e1ec1 | ||
|
|
8ff4797628 | ||
|
|
b4a0f83c00 | ||
|
|
b0597e32b2 | ||
|
|
8ca34cda63 | ||
|
|
12ff0e73c7 | ||
|
|
2f7fe96d67 | ||
| 73a9bf87f2 | |||
| fc728c468e | |||
|
|
5692890239 | ||
| 32d21e5e88 | |||
| f2908b8bc4 | |||
|
|
8d4ddd0f17 | ||
|
|
2285e7ce2f | ||
|
|
2d516512a9 | ||
|
|
eec09d4c9c | ||
|
|
41f678b926 | ||
|
|
934e4e9cdb | ||
|
|
d35faf032b | ||
|
|
a8dbc29dcf | ||
|
|
46e429cd49 | ||
|
|
5a3a7b24af | ||
|
|
181d5da2e2 | ||
|
|
c969274866 | ||
|
|
903d69eb01 | ||
|
|
20df8779bd | ||
|
|
0657c94f72 | ||
|
|
f3397c37b4 | ||
|
|
7ac3804939 | ||
|
|
7b3ab43635 | ||
|
|
ae5104595f | ||
|
|
7e7240a36c | ||
|
|
3ed337a00d | ||
|
|
8d46db382d | ||
|
|
9fdea38d64 | ||
|
|
7a1b17433b | ||
|
|
1d4fb03c24 | ||
|
|
87a49e1abf | ||
|
|
5f748f7a55 | ||
|
|
07d8e27d60 | ||
|
|
65514da874 | ||
|
|
86248df17b | ||
|
|
5ee65a30f8 | ||
|
|
b39741bf52 | ||
|
|
bfb5557099 | ||
|
|
6b6335cef4 | ||
|
|
bdf9d67a06 | ||
|
|
07b64ac7d6 | ||
|
|
73cae644e5 | ||
|
|
6aa6dad5be | ||
|
|
541e456809 | ||
|
|
f84963bf06 | ||
| a8df1402d9 | |||
| 3cc1eb7cc3 | |||
|
|
23f267b67b | ||
| cd02d9f088 | |||
| 1b80039619 | |||
|
|
6601e56281 | ||
|
|
3f2cee1f2c | ||
|
|
94248d2019 | ||
|
|
63326dc48b | ||
|
|
2de39dd445 | ||
|
|
8212f79bc0 | ||
|
|
b97fd8ee04 | ||
|
|
728cbfccb1 | ||
|
|
ae1939aafc | ||
|
|
ce5b1f04b8 | ||
|
|
04390dd8fd | ||
|
|
ecc1f48ace | ||
|
|
8f268f5902 | ||
|
|
c5cd8f0859 | ||
|
|
70d6e126a7 | ||
|
|
889bd30e91 | ||
|
|
c776afd85f | ||
|
|
52beb0251d | ||
|
|
f62c32544e | ||
|
|
1814e3dff6 | ||
|
|
53dc130f30 | ||
|
|
45f614fac2 | ||
|
|
54f3f7a8b2 | ||
|
|
2093131f46 | ||
|
|
dc049899bd | ||
|
|
b100d1a823 | ||
|
|
cad8fe954e | ||
|
|
452968eab0 | ||
|
|
34f0444e06 | ||
|
|
f6fe5b8aa3 | ||
|
|
d49c6d3c85 | ||
|
|
e7818dadeb | ||
|
|
318675923a | ||
|
|
4033191c1c | ||
|
|
e3d3c0b6b4 | ||
|
|
70dfd51559 | ||
|
|
38e6fc5ef2 | ||
|
|
bd1f4c9f6a | ||
|
|
ddfe816d80 | ||
|
|
d765f85515 | ||
|
|
f8394ac82a | ||
|
|
e4aab76045 | ||
|
|
a2dc80e089 | ||
|
|
b573fe461f | ||
|
|
d4f580ee39 | ||
|
|
88fbf0f82a | ||
|
|
14db2f3642 | ||
|
|
c15b29cd4d | ||
|
|
a0f92b2e28 | ||
|
|
5c8ddbe26a | ||
|
|
07cf02e969 | ||
|
|
a2dd0a756d | ||
|
|
aedcd02506 | ||
| 2f0ed24356 | |||
| 4659a922b8 | |||
| 774fd4c2ca | |||
| 02141473ad | |||
|
|
d7fbc79533 | ||
|
|
ab100793dc | ||
| 0ea5e7b762 | |||
| f22bf33bc7 | |||
| 5da12d4db4 | |||
| 6f65f66ba9 | |||
|
|
4b9a0ddcbc | ||
|
|
4f16d9652f | ||
|
|
e0f77851c2 | ||
|
|
7f1c611a1a | ||
|
|
f1db2c198f | ||
|
|
37dfe3936f | ||
|
|
23d8bfa7b8 | ||
|
|
fc3c6eeee6 | ||
|
|
9e18bded7b | ||
|
|
fbd5ddf765 | ||
| 9b9f96dcc1 | |||
| e19eca1d94 | |||
| 74462d5a4f | |||
| eb6e4965b6 | |||
| 34d6bc6a24 | |||
| e2661985c4 | |||
| 3d721b2e5e | |||
| 175824e2f1 | |||
|
|
2f681a5640 | ||
|
|
3714fed115 | ||
|
|
050a52a2ea | ||
|
|
0c19e28a4a | ||
|
|
b71b4a952e | ||
|
|
1d96b5b3df | ||
| a685374fef | |||
| 2d81e843aa | |||
| 22127cb653 | |||
| 7f3db25080 | |||
|
|
168c4ffe4f | ||
|
|
aedb7cd19a | ||
|
|
e479e187da | ||
|
|
12bfcd38d6 | ||
|
|
6f3bc3f5e2 | ||
|
|
f870b2532f | ||
|
|
cadb72457c | ||
|
|
a2cb7ffff9 | ||
|
|
ce00a1148b | ||
|
|
84971f6da9 | ||
|
|
48899bcade | ||
|
|
abc3162db5 | ||
|
|
f4066c2b14 | ||
|
|
ed065474b3 | ||
|
|
e9c0cdbf27 | ||
|
|
e1620742b3 | ||
|
|
4fa1965b11 | ||
|
|
4e9ac43b55 | ||
|
|
177fbad865 | ||
|
|
84dbf53f95 | ||
|
|
3f2bfe8871 | ||
|
|
603bca476a | ||
|
|
b3fc35541c | ||
|
|
44190bb52d | ||
|
|
2facca2308 | ||
|
|
7cf9daa381 | ||
|
|
aa947e7922 | ||
|
|
71992b2af6 | ||
|
|
44f313449a | ||
|
|
74c88636d3 | ||
|
|
c94c49482f | ||
|
|
fbce5a5eaa | ||
|
|
6874488d63 | ||
|
|
5c46ec1385 | ||
|
|
ab943c9914 | ||
|
|
3dd9f4eacf | ||
|
|
6c25b558fd | ||
|
|
d63d08c16c | ||
|
|
e0e7582302 | ||
|
|
0efb0017e8 | ||
|
|
0b31e9504c | ||
|
|
67e57f0391 | ||
|
|
e7d5676233 | ||
|
|
c3730e8b47 | ||
|
|
332411cb8c | ||
|
|
3a0188fcd1 | ||
| 9ef268796b | |||
| 32167c5f8f | |||
|
|
d123aeab0c | ||
|
|
b6fc908190 | ||
| cc3f747076 | |||
| d70f254c9a | |||
| 87086cf315 | |||
|
|
6decc16c41 | ||
|
|
daee078dcf | ||
|
|
78ee4ac3cd | ||
|
|
098931b484 | ||
| eed87b90e0 | |||
| 7db6cac1f6 | |||
| 3cb7e660bc | |||
| b2135214e4 | |||
|
|
b29be88d08 | ||
|
|
33b9317d37 | ||
|
|
22998bc707 | ||
|
|
33d56f5f2e | ||
|
|
84139e40fc | ||
|
|
d4a36675be | ||
|
|
8cf1ebf05d | ||
|
|
8919e38582 | ||
|
|
c0d6c944c3 | ||
|
|
42e856d597 | ||
|
|
f91e6829ad | ||
|
|
d5b627adc1 | ||
|
|
ddb7568ed6 | ||
|
|
0b56bd9f41 | ||
|
|
7f70126c60 | ||
|
|
59be0ecab7 | ||
|
|
1a5a32dd49 | ||
|
|
732cdd4527 | ||
|
|
2ab0e52829 | ||
|
|
b98a81a3e6 | ||
|
|
bc93e1fdf8 | ||
|
|
57eaea8f1e | ||
|
|
f47bfa23ca | ||
|
|
f8cc1b9ce1 | ||
|
|
06302c0f31 | ||
|
|
bbf1e41a7b | ||
|
|
64aa641f9c | ||
|
|
2775e2eabf | ||
|
|
385ad4cb54 | ||
|
|
d9c67ecc2e | ||
|
|
3a18721c52 | ||
|
|
1bc4464444 | ||
|
|
50ec9d34a1 | ||
|
|
bdcbc1e393 | ||
|
|
8b371006fc | ||
|
|
2f0be8b80d | ||
|
|
d693e3b792 | ||
|
|
e98d92b9db | ||
|
|
6e7eb3cb6a | ||
|
|
dcfefdc0e6 | ||
|
|
a7fc9c6b93 | ||
|
|
641dd79bab | ||
|
|
747f8c82b7 | ||
|
|
9e20ba7090 | ||
|
|
cdddc62fdd | ||
|
|
bee407c6a1 | ||
|
|
9bf538ed64 | ||
|
|
1b58933777 | ||
|
|
97fe2bbed9 | ||
|
|
5545e712ad | ||
|
|
663ec385c7 | ||
|
|
3fb70b7412 | ||
|
|
d179194e16 | ||
| c24684cec8 | |||
| 9c1b926a09 | |||
|
|
b6aab62e2a | ||
|
|
27f602819b | ||
|
|
eb10e9251a | ||
|
|
d908109be5 | ||
|
|
ba18e3945d | ||
|
|
6bb6210f70 | ||
|
|
95abb93002 | ||
|
|
139afb670d | ||
|
|
77289b72b7 | ||
|
|
ba939ac382 | ||
|
|
b1069cbb3a | ||
|
|
9c1f58f54d | ||
|
|
2af30251a6 | ||
|
|
92e7ebdf41 | ||
| 74ae210663 | |||
|
|
bf3d160c5e | ||
|
|
f489b03f97 | ||
|
|
593688cb2a | ||
|
|
d3cf3509ca | ||
|
|
b90d6fd34e | ||
|
|
2a4279f8fc | ||
|
|
708bd1b9d5 | ||
|
|
7b97fbf68f | ||
|
|
748ebb5742 | ||
|
|
72e9bba84d | ||
|
|
0af58d7723 | ||
|
|
c01dfb780d | ||
|
|
6575fbfe6a | ||
| 4e99c392f6 | |||
| 83ee28fbdc | |||
|
|
91f5bb3540 | ||
|
|
92a649d655 | ||
| f2dc8ec180 | |||
| 8aca5d0fe2 | |||
| 7040d3202a | |||
| 23937c11de | |||
|
|
3922795f9c | ||
|
|
bdaa9b1be9 | ||
|
|
4b757105ec | ||
|
|
c6e6e7968c | ||
|
|
081a024deb | ||
|
|
1126b0ae4e | ||
|
|
777da8dfb1 | ||
|
|
2482b1dc18 | ||
| 8da5e018d1 | |||
| c54ec4d458 | |||
|
|
fdb75d67df | ||
| 883aab8d5a | |||
| 98b12c904e | |||
| 7ebb3e7784 | |||
| b0db90da49 | |||
|
|
3b28fc3a98 | ||
| 05c9e63bae | |||
| bb48a3d84a | |||
| 1e5d362412 | |||
|
|
ce5c75cb61 | ||
|
|
67f15934b5 | ||
| 39f1f826bb | |||
| f337c1b3c9 | |||
| ba39f58800 | |||
| db52cc7811 | |||
|
|
45403d804a | ||
| 85c07c8eaa | |||
| d70e1fa150 | |||
| 8e66563e1c | |||
| 74f57b874e | |||
| 6a9b9267a3 | |||
| e3b37a64d0 | |||
| 37791e832b | |||
| e5b9f9f134 | |||
|
|
20cbd0ee78 | ||
|
|
dece43d2cf | ||
| e1ae3bce5a | |||
| e25ce7fe84 | |||
| fc8cdfc7a8 | |||
| d6d7044832 | |||
| af24f9122f | |||
| 014d39c097 | |||
|
|
a0d8f5f063 | ||
|
|
23fa8b9295 | ||
|
|
a6231992f2 | ||
| 2dfe24fbca | |||
| e742c117b0 | |||
| 011df13b7f | |||
| 71ff5be656 | |||
| 2efc759908 | |||
| 69da9f4034 | |||
| 5a2eba7426 | |||
|
|
efcaa3f1d4 | ||
|
|
9cf8c2acab | ||
|
|
b86aefb169 | ||
|
|
57b8a44afc | ||
|
|
399507805f | ||
|
|
394a2b1635 | ||
|
|
0b88668b7a | ||
|
|
cb5cdbe00f | ||
|
|
222037cc27 | ||
|
|
de96821e3b | ||
|
|
d2ea6955ff | ||
|
|
6c18981b5b | ||
|
|
2c03586e2d | ||
|
|
44dd19fe82 | ||
|
|
dffa2b7a0d | ||
|
|
1c4aa12e35 | ||
|
|
2a9eb85c2e | ||
|
|
f476b3ed82 | ||
|
|
a4881baf47 | ||
|
|
385f6de3cb | ||
|
|
6b01b22d00 | ||
|
|
e249449817 | ||
|
|
e5e481a21a | ||
|
|
3d95e8608a | ||
|
|
70eaa0974c | ||
|
|
f925d9db0a | ||
|
|
d156c090b5 | ||
|
|
1678715163 | ||
|
|
3736bf2432 | ||
|
|
2dcb628fb7 | ||
|
|
0265987db4 | ||
|
|
ce5cf45f6d | ||
|
|
e5484216d6 | ||
|
|
bd59a00865 | ||
|
|
c5350f17bf | ||
|
|
3c43103b93 | ||
|
|
d30ccce44a | ||
|
|
e49c18a073 | ||
|
|
8af6e8bf9e | ||
|
|
a587e09e24 | ||
|
|
03635ad5c7 | ||
|
|
820d59915d | ||
|
|
9fe78025cd | ||
|
|
90e4c9f33a | ||
|
|
e5d2580010 | ||
|
|
c577b2a05e | ||
|
|
b98b86bb6a | ||
|
|
198a16c76f | ||
|
|
ae1c939403 | ||
|
|
b1f11cc056 | ||
|
|
0c2517e050 | ||
|
|
2203529215 | ||
|
|
c9b1fd1eae | ||
|
|
dee330f1e5 | ||
|
|
78985cd2fd | ||
|
|
143980bc3a | ||
|
|
61fa0e5d8b | ||
|
|
c305530c25 | ||
|
|
5008843b83 | ||
|
|
603613c576 | ||
|
|
f4d22b0c8e | ||
|
|
bdb89581c8 | ||
|
|
fb59d76af8 | ||
|
|
4a7a9aac95 | ||
|
|
206cca210e | ||
|
|
4bb5792104 | ||
|
|
ffe0360650 | ||
|
|
e3493cc717 | ||
|
|
97a8f5249f | ||
|
|
1c4d425420 | ||
|
|
63d7079026 | ||
|
|
26524e3e4b | ||
|
|
7048ba6784 | ||
|
|
894a2d64ba | ||
|
|
f495b86116 | ||
|
|
97cb90ef16 | ||
|
|
d833f53de0 | ||
|
|
4f34308e0f | ||
|
|
84a66eec30 | ||
|
|
c7e46ca52c | ||
|
|
5399aa459f | ||
|
|
63ac981053 | ||
|
|
4897b67197 | ||
|
|
387e4b93a9 | ||
|
|
02aa509701 | ||
|
|
fb09344781 | ||
|
|
5287da1f0f | ||
|
|
3ca7c09914 | ||
|
|
5b70e4cd2c | ||
|
|
d61b8af138 | ||
|
|
42b4f212bd | ||
|
|
9fc2426e83 | ||
|
|
88b3fa1eb3 | ||
|
|
bc5a27f8ac | ||
|
|
02dfdd5eb7 | ||
|
|
9d4bb311af | ||
|
|
be594a50c5 | ||
|
|
70fa743ae0 | ||
| a80f01f7b3 | |||
| e9f3b58b7d | |||
|
|
18b8d05597 | ||
|
|
9b70d4be73 | ||
|
|
761967ed4b | ||
|
|
a08f59d42f | ||
|
|
ecd9140f89 | ||
|
|
bcdd01448f | ||
|
|
725181b0dc | ||
| 62079f8dd5 | |||
| cfa99b40a1 | |||
| 69848474c9 | |||
| b13d9f9769 | |||
| 9667b6469f | |||
| 246d321506 | |||
| 65b74da95d | |||
|
|
e7536715d4 | ||
|
|
3facdaabc7 | ||
|
|
7ab06396a8 | ||
|
|
f8658957b3 | ||
|
|
ed14d07091 | ||
|
|
a0e9b73bb1 | ||
|
|
acccd2edd0 | ||
|
|
676f4ac4a2 | ||
|
|
6ffeb94b83 | ||
|
|
60f817be63 | ||
|
|
b1a403cbed | ||
|
|
096fbc9ff6 | ||
|
|
ec9cf6e0c1 | ||
|
|
12684bffa3 | ||
|
|
a2c5edf6c8 | ||
|
|
4dadfcaab9 | ||
|
|
fa72a246a8 | ||
|
|
11feb84d4a | ||
|
|
f0b1ae9459 | ||
| 44916e8aa1 | |||
| bae6844e5d | |||
|
|
c5650478aa | ||
|
|
d8415f29ca | ||
|
|
878f7b0e46 | ||
|
|
8ce79f32b1 | ||
|
|
ea8b3f00c0 | ||
|
|
57eb706e95 | ||
|
|
3db4f23514 | ||
|
|
93ff5ffa10 | ||
|
|
2ab938629d | ||
|
|
f363f9318e | ||
|
|
204567f16b | ||
|
|
c57ccfa0df | ||
|
|
91458ca9bc | ||
|
|
5e076dc13b | ||
| 1d37db7704 | |||
| 7e8e0b60d0 | |||
|
|
b20954551e | ||
|
|
5f0ac20b64 | ||
|
|
db62206008 | ||
|
|
3ce5f64d75 | ||
|
|
8622b2d42b | ||
| 9d1036935c | |||
| 4ed709aa31 | |||
|
|
291e630482 | ||
|
|
a460ae2ffc | ||
|
|
a320b254ef | ||
|
|
545057314f | ||
| a7a0956157 | |||
|
|
5ea16d9554 | ||
| 31bad7f8c3 | |||
| 49128b5a2c | |||
| e7de354f47 | |||
| 052c9463e0 | |||
| 34bff0806f | |||
| 7a317e5026 | |||
|
|
c74f160b8a | ||
|
|
7595b4259f | ||
|
|
37bb67bf18 | ||
|
|
5ccdaf10d9 | ||
|
|
69e3d521f4 | ||
|
|
e204c50ba3 | ||
|
|
1334de31bb | ||
|
|
8fdd5fc22f | ||
| bf1b4cf502 | |||
|
|
f5e3891abc | ||
|
|
d50e70bdfc | ||
|
|
40fb1cc4cf | ||
|
|
ed77522da6 | ||
|
|
2e32ad8bde | ||
|
|
83794107f3 | ||
|
|
d5462b31f3 | ||
|
|
ec68911568 | ||
|
|
6044d5425c | ||
|
|
82c7e5a362 | ||
|
|
a23e09ca20 | ||
|
|
00e3390437 | ||
|
|
c67ff1376a | ||
|
|
fb8bb645c2 | ||
|
|
2af65243a4 | ||
|
|
de2b122f7b | ||
|
|
0acae98ccd | ||
|
|
a2446e1d0c | ||
|
|
195b4b9155 | ||
|
|
5fe8a3bc82 | ||
|
|
35c4a4cca9 | ||
| cef40151a9 | |||
| 040bc58917 | |||
|
|
8a840f97c7 | ||
|
|
7d0c857eb5 | ||
|
|
79d456a8c3 | ||
|
|
3280dd1878 | ||
|
|
dab30c8c76 | ||
| f590128201 | |||
| df4b3c0d13 | |||
| 0e525b109d | |||
| 8fdad9c7dc | |||
| 93259d5bf9 | |||
| dedfee4c82 | |||
|
|
ccec1162b9 | ||
|
|
dec98e6b8d | ||
|
|
6305e85ce1 | ||
|
|
4c7846be2c | ||
|
|
6ada2f3b5e | ||
|
|
499106c9ae | ||
|
|
6136890616 | ||
|
|
4872eedd83 | ||
| 1ae663c6a5 | |||
|
|
f0b6638466 | ||
|
|
cb4788019b | ||
|
|
d7d51f673f | ||
|
|
d2ab9a7ff4 | ||
| 065ce2886c | |||
| 37eb6d383f | |||
| 1350c71c3d | |||
| 0ba97ed4cd | |||
|
|
60bf83a653 | ||
| 8a1da2ce94 | |||
|
|
d08e82e4f7 | ||
| 1dff57856a | |||
|
|
453f31099d | ||
| 38f629b91c | |||
|
|
d7eb4db806 | ||
|
|
9f99ee66f7 | ||
| 4cf919e3e6 | |||
|
|
324c5be47d | ||
| ef1177689d | |||
|
|
69554e4687 | ||
|
|
3d1cc888fa | ||
|
|
69d5dfc621 | ||
|
|
ded7b6dda9 | ||
|
|
a343f781d0 | ||
|
|
16bfdb4943 | ||
|
|
f9f21ba7f5 | ||
|
|
790584b329 | ||
|
|
92a85b35fe | ||
|
|
9cad050e6b | ||
|
|
d2b8d11645 | ||
|
|
b4c64e2808 | ||
|
|
f184cc32df | ||
|
|
40757b3028 | ||
|
|
aa1697e767 | ||
|
|
c1c8cfc29b | ||
|
|
dc68fdc0a0 | ||
|
|
4e6323453c | ||
|
|
76067312e1 | ||
|
|
7d9eecd05a | ||
|
|
d3ad082a82 | ||
|
|
3d225b6f9f | ||
|
|
88d9d0f9b7 | ||
|
|
2fb4dc415c | ||
|
|
d2e899915b | ||
|
|
79494c2396 | ||
|
|
d233209694 | ||
|
|
3fc704c445 | ||
|
|
d66a7424a7 | ||
|
|
206cc00387 | ||
|
|
0d359bbc1b | ||
|
|
2fcc947a12 | ||
|
|
55b1da881b | ||
|
|
ff94b2423e | ||
|
|
2a3d4e9458 | ||
|
|
cda6416bf9 | ||
|
|
cd6a4ac758 | ||
|
|
40a7149215 | ||
|
|
62c21a8de0 | ||
|
|
5c56856566 | ||
|
|
8fd2235cde | ||
|
|
331b24237f | ||
|
|
5edf9f715b | ||
|
|
eb0c8aaaa9 | ||
|
|
e55e6bc7a2 | ||
|
|
0ac7d69212 | ||
|
|
ace62a1677 | ||
|
|
95c29649bd | ||
|
|
912b534c31 | ||
|
|
b2fea266ee | ||
|
|
c30ad8d386 | ||
|
|
3ce34ed338 | ||
|
|
f3794ecd10 | ||
|
|
0bb220b85d | ||
|
|
badcf76e2f | ||
|
|
90aacc6746 | ||
|
|
f0df5d19ed | ||
|
|
9c5118f763 | ||
|
|
722029d11e | ||
|
|
82aa4e19fb | ||
|
|
63f2ae368c | ||
|
|
785fc52a14 | ||
|
|
997644a06d | ||
|
|
43b4364918 | ||
|
|
f308ebee74 | ||
|
|
687858e73d | ||
|
|
76197ce75d | ||
|
|
18d939bcd4 | ||
|
|
18a3893185 | ||
|
|
058f07c208 | ||
|
|
a9d9c13869 | ||
|
|
af3c32fc46 | ||
|
|
17b4409823 | ||
|
|
85822c48da | ||
|
|
ecc87573e3 | ||
|
|
f66f21434e | ||
|
|
c6d853575d | ||
|
|
53bae90089 | ||
|
|
a50a65ac9f | ||
|
|
ff4b8fc106 | ||
|
|
fe541df2c7 | ||
|
|
4585ec0b4c | ||
|
|
456ab3150a | ||
|
|
b3748395ce | ||
|
|
b582695aa2 | ||
|
|
06b7f75df3 | ||
|
|
e2ca8d3268 | ||
|
|
0d4eec7f7f | ||
|
|
837cb34353 | ||
|
|
8b9cfc4e63 | ||
|
|
7d7768897d | ||
| c8b6e678f8 | |||
|
|
692c73994b | ||
|
|
b5461f3b41 | ||
|
|
37018f6eb0 | ||
|
|
daff55463b | ||
|
|
ab676bf63c | ||
|
|
8a0a533777 | ||
|
|
3c0eb9c52f | ||
|
|
b3188a26a5 | ||
|
|
3ab904f164 | ||
|
|
c71a42859d | ||
|
|
cbe8d3f799 | ||
|
|
ae4d3b5758 | ||
|
|
d12adcd933 | ||
|
|
607613b7fd | ||
|
|
fdd0b6a280 | ||
|
|
0401157703 | ||
|
|
98931bb530 | ||
|
|
38666d2449 | ||
|
|
ed513b6c15 | ||
|
|
11523c79f4 | ||
|
|
4b87f4d2cc | ||
|
|
bbd90a77bc | ||
|
|
0645359cb6 | ||
|
|
9369002418 | ||
|
|
37feda74f7 | ||
|
|
e1da8d13d7 | ||
|
|
a4f36c8e64 | ||
|
|
3636ec7cc6 | ||
|
|
2acdcc5c93 | ||
|
|
b44cb59a48 | ||
|
|
5918613ff4 | ||
|
|
5499b23189 | ||
|
|
601a1c917e | ||
|
|
de978f3a10 | ||
|
|
48598d9c76 | ||
|
|
46af72c529 | ||
|
|
b82cefd904 | ||
|
|
8f0e3d0421 | ||
|
|
6a04eedb9e | ||
|
|
546e51e3d9 | ||
|
|
86cbbd80cf | ||
|
|
18f598bc2c | ||
|
|
69b73d4bc8 | ||
|
|
8ba5cb4d02 | ||
|
|
f9b9633ac0 | ||
|
|
6f80df48e0 | ||
|
|
4a9ca43614 | ||
|
|
afe236c62c | ||
|
|
7a75ea4bef | ||
|
|
78ee005870 | ||
|
|
dbe3445d7b | ||
|
|
cb90139342 | ||
|
|
d6c6b5e092 | ||
|
|
5d3dffbaa0 | ||
|
|
21d39ebc36 | ||
|
|
1f81d35423 | ||
|
|
12239124d6 | ||
|
|
71a1d6dd7b | ||
|
|
4881ac32b6 | ||
|
|
d3e5879068 | ||
|
|
e4e9fe2972 | ||
|
|
56ab3b59a2 | ||
|
|
bc7355d61e | ||
|
|
7834f44973 | ||
|
|
621862afa9 | ||
|
|
af99250a69 | ||
|
|
0bce9d1211 | ||
|
|
8b7f68e6f9 | ||
|
|
6ac08e0929 | ||
|
|
b87fd621b1 | ||
|
|
c94bfe6cd0 | ||
|
|
c08d6b3a18 | ||
|
|
9e2bb1ad0a | ||
|
|
10e0596011 | ||
|
|
6216081259 | ||
|
|
981946c950 | ||
|
|
84e70ba013 | ||
|
|
8ff421143f | ||
|
|
22b5cdf57a | ||
|
|
cc58c96e98 | ||
|
|
3816278a5e | ||
|
|
338985a4cc | ||
|
|
c6fca9da6a | ||
|
|
bdbbe148c3 | ||
|
|
f2b206b1e0 | ||
|
|
c1f83d6ec9 | ||
|
|
c53fe93839 | ||
|
|
190acf7ed2 | ||
|
|
3d71a5404b | ||
|
|
37beb53245 | ||
|
|
019a8b6655 | ||
|
|
652da9ebd5 | ||
|
|
99703d53ba | ||
|
|
de7b8db504 | ||
|
|
1e28557ce2 | ||
|
|
07a796bcf6 | ||
|
|
665e63da5b | ||
|
|
4ef4ae4df5 | ||
|
|
ac50eefe07 | ||
|
|
bd4415ad5c | ||
|
|
86c6800fbd | ||
|
|
124ebe9fdf | ||
|
|
8b0cd9e36b | ||
|
|
1e35f940da | ||
|
|
cc00337ec1 | ||
|
|
5d4c173c31 | ||
|
|
aac8f217e0 | ||
|
|
ac4daeb82c | ||
|
|
9fd31d014f | ||
|
|
bfd7b1a5f5 | ||
|
|
56e00fbe3a | ||
|
|
a27e1393f1 | ||
|
|
fd68634993 | ||
|
|
3831348301 | ||
|
|
9cbd7643db | ||
|
|
4d5a3fc73d | ||
|
|
6117d8822e | ||
|
|
886adb12fc | ||
|
|
542a51658d | ||
|
|
ee055dbdc0 | ||
|
|
33a07f811e | ||
|
|
2dfe05d682 | ||
|
|
ad64e9c21e | ||
|
|
9275c79b39 | ||
|
|
8e4e0050c8 | ||
|
|
87618700b3 | ||
|
|
3d88fab782 | ||
|
|
bec1978861 | ||
|
|
b5bd11ca5a | ||
|
|
ee167b6b74 | ||
|
|
0af5ea883a | ||
|
|
9963503ebf | ||
|
|
be5a10194a | ||
|
|
37104e30bf | ||
|
|
8d019a7275 | ||
|
|
bc43249bba | ||
|
|
3da4369c96 | ||
|
|
8bbddfc336 | ||
|
|
38c839c389 | ||
|
|
b8815fc67b | ||
|
|
537d6ef0d5 | ||
|
|
a86ab694a5 | ||
|
|
9008893308 | ||
|
|
b10cf8f698 | ||
|
|
1b3aed6b6a | ||
|
|
d39d21296f | ||
|
|
0cbbe6297e | ||
|
|
1dbd94d52d | ||
|
|
d45df857d6 | ||
|
|
83677f01fb | ||
|
|
5fbf385805 | ||
|
|
053f261e57 | ||
|
|
eb03e19f03 | ||
|
|
399575aba5 | ||
|
|
19e3122f48 | ||
|
|
acec9b5275 | ||
|
|
522cf05880 | ||
|
|
a3fd28dcf4 | ||
|
|
a4220f7bc6 | ||
|
|
d6891d4b7a | ||
|
|
65d99d2082 | ||
|
|
f3f4cd7a21 | ||
|
|
cf82d3a156 | ||
|
|
2ba106e38e | ||
|
|
c4fd1b610b | ||
|
|
841e277180 | ||
|
|
0bb9984dfa | ||
|
|
f814b85a86 | ||
|
|
904829c1d5 | ||
|
|
b2d78e4724 | ||
|
|
34be58962a | ||
|
|
fb7cd7e3ef | ||
|
|
e1e65546b8 | ||
|
|
a6e8d53b37 | ||
|
|
87fbec3e39 | ||
|
|
a5d649ba2d | ||
|
|
1e34738fca | ||
|
|
433340c11b | ||
|
|
d9a75a5afc | ||
|
|
43090cbc32 | ||
|
|
e70229140b | ||
|
|
b4fb8ba2c9 | ||
|
|
5e23488a96 | ||
|
|
9adbef3f27 | ||
|
|
09a97c31fc | ||
|
|
76d8d9110a | ||
|
|
67c09c69f0 | ||
|
|
513a33abe6 | ||
|
|
b313817399 | ||
|
|
0f7dca99d1 | ||
|
|
c0891c4a4c | ||
|
|
a94382458e | ||
|
|
6856969d01 | ||
|
|
e4fba64fc1 | ||
|
|
0c4fd2dbb1 | ||
|
|
6ad90ca38a | ||
|
|
edfc9b1454 | ||
|
|
6bcc866f38 | ||
|
|
04d0ecc1a7 | ||
|
|
2ad33706e3 | ||
|
|
952d9fd471 | ||
|
|
be7e213736 | ||
|
|
5818f8e26d | ||
|
|
6b1859421f | ||
|
|
4af2122176 | ||
|
|
ec8d0a2f61 | ||
|
|
0792526c16 | ||
|
|
b607304f7b | ||
|
|
f2940146c4 | ||
|
|
0d97dbf534 | ||
|
|
f7d134066d | ||
|
|
dcb8009c63 | ||
|
|
32ffd056a1 | ||
|
|
b5ce70955b | ||
|
|
2b8d3477ce | ||
|
|
d655ad206c | ||
|
|
d16aaab35f | ||
|
|
ba0fee151b | ||
|
|
2ce2b894b7 | ||
|
|
d9979b8f97 | ||
|
|
2d633a0bfd | ||
|
|
fdbdd10a89 | ||
|
|
a6f7f9ec12 | ||
|
|
3dd242c1c7 | ||
|
|
defe514a31 | ||
|
|
31d0bc33d6 | ||
|
|
3580430005 | ||
|
|
ac799b7ffa | ||
|
|
4c8e0149f3 | ||
|
|
150a68a3e0 | ||
|
|
321a21ae9b | ||
|
|
d73be206e5 | ||
|
|
c521d75ef7 | ||
|
|
479ccd57df | ||
|
|
4e174df746 | ||
|
|
a71f62c566 | ||
|
|
5ddb70eaea | ||
|
|
fd58472cc5 | ||
|
|
e9c74c7c45 | ||
|
|
903477e905 | ||
|
|
fd2af4d89c | ||
|
|
ccb01ccf7f | ||
|
|
4d65024977 | ||
|
|
72e2161924 | ||
|
|
7bd220adfc | ||
|
|
6092e35b65 | ||
|
|
51d567ecb4 | ||
|
|
33f9bd8156 | ||
|
|
73d226e7d7 | ||
|
|
f26c616fdc | ||
|
|
db459de0c6 | ||
|
|
ef542d8898 | ||
|
|
58e95dc353 | ||
|
|
cdc61ee6ea | ||
|
|
2d2c8fdc96 | ||
|
|
d9bb3d0b96 | ||
|
|
05d60d70e2 | ||
|
|
67d20d4af5 | ||
|
|
95bf6be670 | ||
|
|
8d132a0ba7 | ||
|
|
bbbc127193 | ||
|
|
21c7ad4a89 | ||
|
|
af5456b846 | ||
|
|
2c955e300f | ||
|
|
138d674662 | ||
|
|
9b0ace19c1 | ||
|
|
3eb4083cb3 | ||
|
|
799944b23b | ||
|
|
8bda9bf804 | ||
|
|
232586c709 | ||
|
|
32a9f47375 | ||
|
|
9d50e4d5ed | ||
| f50f55bb54 | |||
|
|
e71ba76d98 | ||
|
|
4aa6d15933 | ||
|
|
980276b966 | ||
|
|
cf32b7844b | ||
|
|
a112c3a1ed | ||
|
|
9f9a88cf32 | ||
|
|
28a79def5a | ||
|
|
4443fb464a | ||
|
|
08c31aa6f6 | ||
|
|
a393912213 | ||
|
|
20f414c7fa | ||
|
|
580f954254 | ||
|
|
3472871e35 | ||
|
|
803265660e | ||
|
|
4a4ca0cdf0 | ||
|
|
415e31e560 | ||
|
|
dc400c652a | ||
|
|
897ea797cb | ||
|
|
01618c6202 | ||
|
|
337fd36633 | ||
|
|
75e23fd1e3 | ||
|
|
944dff0aa7 | ||
|
|
7425484b55 | ||
|
|
19269dbaf3 | ||
|
|
59afc44c8a | ||
|
|
8ada237bfa | ||
|
|
a77f016288 | ||
|
|
5a6f92bbbf | ||
|
|
2e6a4930a0 | ||
|
|
855bb2af33 | ||
|
|
55e2fae135 | ||
|
|
55f2d782ce | ||
|
|
41e05c8135 | ||
|
|
7fdd3d1711 | ||
|
|
809f927219 | ||
|
|
ad18c98330 | ||
|
|
2451ea31bb | ||
|
|
2e817416d5 | ||
|
|
0fd6c672d3 | ||
|
|
3e4014a6f6 | ||
|
|
706cd5a129 | ||
|
|
974ffabd18 | ||
|
|
d632e08386 | ||
|
|
5e623a349c | ||
|
|
8e7c8cab48 | ||
|
|
1eee60c0ce | ||
|
|
1650ce35d0 | ||
|
|
bdad71bd08 | ||
|
|
2c460e095d | ||
|
|
1b6ece965c | ||
|
|
d0cd620364 | ||
|
|
f8e0ee65f2 | ||
|
|
f67b62a3a1 | ||
|
|
6096fc993c | ||
|
|
6b44254c16 | ||
|
|
b60be22754 | ||
|
|
10b23915f1 | ||
|
|
cb5d7f1f8d | ||
|
|
dfe36b64a5 | ||
|
|
cb5be9530a | ||
|
|
3d54dea3dd | ||
|
|
d726737b23 | ||
|
|
d9a9c17d02 | ||
|
|
84f8506912 | ||
|
|
c2efb40b62 | ||
|
|
cae522f90b | ||
|
|
d036993b23 | ||
|
|
21a90fc2ec | ||
|
|
17aa96ce09 | ||
|
|
d82e2fe5ac | ||
|
|
965f84bbfa | ||
|
|
a825949a8a | ||
|
|
6b2bbda02a | ||
|
|
495d91193c | ||
|
|
50ee30b133 | ||
|
|
c9ea1e1a22 | ||
|
|
98477eef9f | ||
|
|
0d571a5565 | ||
|
|
dae60e5387 | ||
|
|
66567bc618 | ||
|
|
a40adc5465 | ||
|
|
5d259efdd8 | ||
|
|
fb14907fa8 | ||
|
|
77bf7f1658 | ||
|
|
eb5b18ed23 | ||
|
|
8fe9c487d3 | ||
|
|
9b097da22f | ||
|
|
3d4909381c | ||
|
|
8d1d9a020f | ||
|
|
52adc9dc16 | ||
|
|
f02bf9b72b | ||
|
|
907e649647 | ||
|
|
da17c8df52 | ||
|
|
d4155625e4 | ||
|
|
114694434c | ||
|
|
e54f5ffadd | ||
|
|
7b75ee5a0a | ||
|
|
d435e44e5f | ||
|
|
109402cea5 | ||
|
|
73cde7abba | ||
|
|
2f3615e001 | ||
|
|
524b2ab417 | ||
|
|
d43c9d047b | ||
|
|
d774b63d83 | ||
|
|
b54eb9b4d5 | ||
|
|
5947275aae | ||
|
|
f3f669dc2e | ||
|
|
ddd6a37507 | ||
|
|
37e93f6097 | ||
|
|
1e5a69a80b | ||
|
|
e12b3c697d | ||
|
|
0224a0f03b | ||
|
|
f83f467b28 | ||
|
|
bed4563257 | ||
|
|
d2d9a067ce | ||
|
|
8fee843315 | ||
|
|
21d665b812 | ||
|
|
144271e4ca | ||
|
|
24fb6c9347 | ||
|
|
1c29d752bd | ||
|
|
3f1d2f9808 | ||
|
|
166d1ba86b | ||
|
|
64873218ba | ||
|
|
0eb96d6ef0 | ||
|
|
beaeb9c835 | ||
|
|
5b1a023be6 | ||
|
|
c082fc8fa6 | ||
|
|
0e8b757249 | ||
|
|
c1b241ab8f | ||
|
|
ab49a149ba | ||
|
|
f64894ea12 | ||
|
|
a34bf5d408 | ||
|
|
ca569f0739 | ||
|
|
88a66928c1 | ||
|
|
2144486917 | ||
|
|
0f560139f3 | ||
|
|
b610b7a695 | ||
|
|
26f882edd5 | ||
|
|
f00e020f2b | ||
|
|
edd0dd0b0d | ||
|
|
031fa45eb8 | ||
|
|
a2eee5a673 | ||
|
|
45c160f27a | ||
|
|
7ba59b4338 | ||
|
|
554b17fe9a | ||
|
|
64632eed4a | ||
|
|
49299f3f28 | ||
|
|
00774590b0 | ||
|
|
52b640b582 | ||
|
|
911e69e3ae | ||
|
|
d809d6653d | ||
|
|
8df81fc0a1 | ||
|
|
ed76829562 | ||
|
|
4f4044c3f0 | ||
|
|
3a4bfc9c07 | ||
|
|
b25c207e9a | ||
|
|
fcae43547b | ||
|
|
b34b0cc399 | ||
|
|
f4875d12fa | ||
|
|
2f06e9bebf | ||
|
|
9b6dde008d | ||
|
|
6ddaa72a86 | ||
|
|
d064de1913 | ||
|
|
97013f8874 | ||
|
|
39954032d2 | ||
|
|
44f0acead5 | ||
|
|
6d024b49a9 | ||
|
|
8a379d5394 | ||
|
|
972adde7eb | ||
|
|
f3dd06ad1e | ||
|
|
55603782bb | ||
|
|
3d65f93277 | ||
|
|
e35d173982 | ||
|
|
ec6e9b1bfb | ||
|
|
ca6046f821 | ||
|
|
c81b4645a8 | ||
|
|
0687ef8364 | ||
|
|
8d149136fe | ||
|
|
2a83c8f6ee | ||
|
|
689016f48e | ||
|
|
146bbf67f8 | ||
|
|
b606c2084b | ||
|
|
c1efe6daab | ||
|
|
4bdb7d752f | ||
|
|
6d9aca9d9b | ||
|
|
e250531174 | ||
|
|
5948a7dec3 | ||
|
|
4e4718b3b1 | ||
|
|
d94ff6ad86 | ||
|
|
e4a8a6492d | ||
|
|
17695915fa | ||
|
|
69adf84363 | ||
|
|
af8272b970 | ||
|
|
5355ee7740 | ||
|
|
02cd83187b | ||
|
|
f5ca15c28d | ||
|
|
b7db6ae77c | ||
|
|
4aa6ee2308 | ||
|
|
21dc07bf5a | ||
|
|
4a6fe9b291 | ||
|
|
8aef6ce292 | ||
|
|
c9cf208de7 | ||
|
|
097fa34e91 | ||
|
|
c2ffcb8512 | ||
|
|
2432680ed3 | ||
|
|
8e985eb951 | ||
|
|
a18a5136b7 | ||
|
|
73c8ee826e | ||
|
|
2a4ab118de | ||
|
|
70596d0548 | ||
|
|
6ede06cfdf | ||
|
|
8818c78cbd | ||
|
|
9489b41cb7 | ||
|
|
9a9722dd3e | ||
|
|
ec3a88dc34 | ||
|
|
4e21fe74e5 | ||
|
|
9dc8ca4edb | ||
|
|
efc3b847ac | ||
|
|
3701cf9782 | ||
|
|
a171d71bbe | ||
|
|
a6ef362ad7 | ||
|
|
c2f3732469 | ||
|
|
454cd6bda6 | ||
|
|
740c7fad4d | ||
|
|
c875f1d105 | ||
|
|
43945dcbbf | ||
|
|
3c7659277d | ||
|
|
26cffabf86 | ||
|
|
897338b790 | ||
|
|
ac3fc6a0d8 | ||
|
|
20acd7cf61 | ||
|
|
08e95655c1 | ||
|
|
5d27ce3f8d | ||
|
|
1e95c123e5 | ||
|
|
a6536ea48a | ||
|
|
9aa9f7a714 | ||
|
|
723257d6ef | ||
|
|
c5323a8d36 | ||
|
|
67082463e4 | ||
|
|
b3072d9ef3 | ||
|
|
3c4956f0c3 | ||
|
|
d69a65605d | ||
|
|
2bf7d5ddea | ||
|
|
c2edd7e926 | ||
|
|
ed1e705d35 | ||
|
|
fa145ff7c5 | ||
|
|
7610b3842f | ||
|
|
d812f82e92 | ||
|
|
0a87559ba2 | ||
|
|
c248279a03 | ||
|
|
22efde37e3 | ||
|
|
c976b86b6e | ||
|
|
3ef06f88c9 | ||
|
|
2ec0894c35 | ||
|
|
d85d501291 | ||
|
|
e4996a2db6 | ||
|
|
ffc4520382 | ||
|
|
386b259666 | ||
|
|
ee5e3a97ed | ||
|
|
a70c988a07 | ||
|
|
788babeaa0 | ||
|
|
3befe90007 | ||
|
|
bfdf75f45b | ||
|
|
9de618d644 | ||
|
|
cdf778514c | ||
|
|
03f315fc1c | ||
|
|
379227592c | ||
|
|
3d9ded4ab1 | ||
|
|
29c827c076 | ||
|
|
5582814d7c | ||
|
|
43a5998cfd | ||
|
|
d1633938db | ||
|
|
5129665256 | ||
|
|
0d51b2d25f | ||
|
|
ba7b154a09 | ||
|
|
52bb2aea94 | ||
|
|
265804a750 | ||
|
|
74795a83d6 | ||
|
|
0fe437f649 | ||
|
|
a2ec81eaec | ||
|
|
df4be26878 | ||
|
|
06456fb318 | ||
|
|
d9c932ac2e | ||
|
|
d680cfd80c | ||
|
|
4a9f8240db | ||
|
|
266dc09384 | ||
|
|
4dd5e7737b | ||
|
|
af6722c57b | ||
|
|
2ff0a13990 | ||
|
|
cfdc2203fb | ||
|
|
2c53424210 | ||
|
|
8b0edde290 | ||
|
|
a4d3bf285d | ||
|
|
3acc4b754a | ||
|
|
ef08dfad55 | ||
|
|
b9099fbd99 | ||
|
|
c9a6950550 | ||
|
|
80f76e38b4 | ||
|
|
7ea3c430aa | ||
|
|
d467dc28b9 | ||
|
|
8ac78af293 | ||
|
|
e44eeaf5ae | ||
|
|
17cc514bb1 | ||
|
|
86996dde28 | ||
|
|
34789fdb30 | ||
|
|
a74f36358f | ||
|
|
a6ad525197 | ||
|
|
0826b1e228 | ||
|
|
5d3c29fb27 | ||
|
|
8256f61d56 | ||
|
|
ffc5ed8dc2 | ||
|
|
860eb22af7 | ||
|
|
1a050303fa | ||
|
|
ce0c84c5d9 | ||
|
|
b537bd18b0 | ||
|
|
de79f52c81 | ||
|
|
a5bc80da09 | ||
|
|
5f4ad87d10 | ||
|
|
cc56c4b506 | ||
|
|
13efc59916 | ||
|
|
515a9b8d0d | ||
|
|
52958b95d5 | ||
|
|
b36ed7de1a | ||
|
|
693aefe83a | ||
|
|
ed30da0f0f | ||
|
|
81255e19ae | ||
|
|
07dbab9f02 | ||
|
|
bf27bf140d | ||
|
|
3a906a6ce5 | ||
|
|
47e02f7930 | ||
|
|
75b808fcf6 | ||
|
|
5cbdb7d806 | ||
|
|
2c8428d85e | ||
|
|
8fe9d7ac06 | ||
|
|
db8a843e82 | ||
|
|
a730c1acea | ||
|
|
d6aaf3ee3a | ||
|
|
9e4063a161 | ||
|
|
008943f699 | ||
|
|
71a58cb1bf | ||
|
|
4a6f6f8647 | ||
|
|
32bba60bed | ||
|
|
0f3abf0c9e | ||
|
|
5c1b6ba703 | ||
|
|
5e6ec442a7 | ||
|
|
cdf5bec155 | ||
|
|
281bf68098 | ||
|
|
ce2b5639b5 | ||
|
|
4c10b414c4 | ||
|
|
4c15a0e1c4 | ||
|
|
203fbdaa9f | ||
|
|
9431b9cfdc | ||
|
|
2bec84dd88 | ||
|
|
cf7efcada8 | ||
|
|
dda25bf1ed | ||
|
|
04b1bdb453 | ||
|
|
e04d31eb04 | ||
|
|
706ed2ced2 | ||
|
|
bb7278c5f6 | ||
|
|
3edc235104 | ||
|
|
806046df64 | ||
|
|
345c64ebaf | ||
|
|
53eb6ba7e0 | ||
|
|
eaa526583d | ||
|
|
c0b8fe94a8 | ||
|
|
6e5049c1db | ||
|
|
949f619ecc | ||
|
|
f7c3e06db5 | ||
|
|
1a26e1789c | ||
|
|
e40bbc9f18 | ||
|
|
ec72f3cdf6 | ||
|
|
b19998c072 | ||
|
|
66e1c94bee | ||
|
|
0449589406 | ||
|
|
cc85df19aa | ||
|
|
8418bda5a5 | ||
|
|
75492514ca | ||
|
|
e43810f182 | ||
|
|
9d49dc7af7 | ||
|
|
680320dede | ||
|
|
b2d6a091d1 | ||
|
|
5d22a2152a | ||
|
|
acbf849b44 | ||
|
|
7cf9895908 | ||
|
|
d41c39a4d0 | ||
|
|
b1852c127b | ||
|
|
8c59c514b2 | ||
|
|
93493a6d15 | ||
|
|
03e5c6c13c | ||
|
|
826bf3c24f | ||
|
|
68273cd256 | ||
| e130f85a65 | |||
|
|
9385ce7080 | ||
|
|
da190cc24f | ||
|
|
2a6dc58659 | ||
|
|
f4eda0551d | ||
|
|
0560b3221d | ||
|
|
631a6dd2b2 | ||
|
|
0154a87cbf | ||
|
|
4f8ad3b6cb | ||
|
|
458e980e2f | ||
|
|
e08d2f354a | ||
|
|
037e6940a9 | ||
|
|
b3055feff6 | ||
|
|
c520dcb0f6 | ||
|
|
fc88d672c5 | ||
|
|
c62884ef85 | ||
|
|
d9c629a6b1 | ||
|
|
70b7d1204b | ||
|
|
a90bbc3554 | ||
|
|
c2ec6cdeff | ||
|
|
f57abe84bd | ||
|
|
a1ee8220bb | ||
|
|
ce73b9e8da | ||
|
|
e6c3c097b5 | ||
|
|
8961009292 | ||
|
|
de27cb1a46 | ||
|
|
e8afbc5b92 | ||
|
|
587409daa7 | ||
|
|
af5019c8dd | ||
|
|
46bba0fe71 | ||
|
|
049456493f | ||
|
|
2f63762c80 | ||
|
|
ca0d9f5a26 | ||
|
|
aa620f5ed3 | ||
|
|
15bb157126 | ||
|
|
7e3e42ce42 | ||
|
|
981c5e3878 | ||
|
|
393ee71ad9 | ||
|
|
97736cef1c | ||
|
|
25af51faf9 | ||
|
|
a717dfb923 | ||
|
|
e594b9532c | ||
|
|
a7a5b06b5c | ||
|
|
eb72e97c03 | ||
|
|
25cdc988e1 | ||
|
|
3ce669575f | ||
|
|
63aa64f8bb | ||
|
|
a6f61d2bf6 | ||
|
|
9457271ce6 | ||
|
|
22512d3889 | ||
|
|
a7115263f0 | ||
|
|
c4b167b845 | ||
|
|
5e09245234 | ||
|
|
fee38c1c32 | ||
|
|
a1ced67bad | ||
|
|
87f7d470a6 | ||
|
|
32d60858da | ||
|
|
be4ad7eba9 | ||
|
|
7f8fa825ac | ||
|
|
1cd5926f6c | ||
|
|
9c31be66e6 | ||
|
|
0e89b07ae8 | ||
|
|
7b6e6270ba | ||
|
|
9d9310a726 | ||
|
|
0f26baf114 | ||
|
|
5ef93f11a9 | ||
|
|
ce53714ba1 | ||
|
|
50ce3c2856 | ||
|
|
21c1f89249 | ||
|
|
46ef49f2cf | ||
|
|
e53a59b4ac | ||
|
|
a13f2b9768 | ||
|
|
44c30e78fc | ||
|
|
ec63f41b27 | ||
|
|
c19944384e | ||
|
|
0c08a05bce | ||
|
|
7eda9c77af | ||
|
|
66045cebc2 | ||
|
|
2b93dbbf48 | ||
|
|
759f6968f6 | ||
|
|
e3db28542c | ||
|
|
e7f98e9243 | ||
|
|
4908f760d9 | ||
|
|
6bb3657de2 | ||
|
|
dc40755e7c | ||
|
|
140ab47354 | ||
|
|
da887f7c6c | ||
|
|
f4be99ecd0 | ||
|
|
b8407a261e | ||
|
|
969a8a5d8a | ||
|
|
b57d9f2f7e | ||
|
|
c9a97d889b | ||
|
|
51bdd9a283 | ||
|
|
04dd18615c | ||
|
|
265f5ee5df | ||
|
|
9c3f8602da | ||
|
|
74dedcf7f0 | ||
|
|
ae2b99b1c6 | ||
|
|
818ecc3563 | ||
|
|
5ccbeca676 | ||
|
|
a621f56c33 | ||
|
|
1513695768 | ||
|
|
63e202f8f0 | ||
|
|
80535875ad | ||
|
|
f0ad921fd2 | ||
|
|
63f3d88f78 | ||
|
|
9f7f1bbcab | ||
|
|
edc9d6fec5 | ||
|
|
a089156afc | ||
|
|
767a5043ab |
@@ -29,3 +29,4 @@ installer/build
|
||||
router/java/build
|
||||
router/build
|
||||
|
||||
override.properties
|
||||
127
.github/workflows/ant-nightly.yml
vendored
Normal file
127
.github/workflows/ant-nightly.yml
vendored
Normal file
@@ -0,0 +1,127 @@
|
||||
name: Daily Workflow
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# This runs at 00:00 UTC every day
|
||||
# Cron syntax: minute hour day-of-month month day-of-week
|
||||
- cron: '0 * * * *'
|
||||
workflow_dispatch: # Allows manual triggering
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
daily-job:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Ensures this only runs on the master branch
|
||||
if: github.ref == 'refs/heads/master'
|
||||
|
||||
steps:
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
- name : Generate override.properties
|
||||
run: |
|
||||
rm -f override.properties
|
||||
echo "build.built-by=GitHub Actions" >> override.properties
|
||||
echo "noExe=true" >> override.properties
|
||||
- name: build with Ant
|
||||
run: ant distclean pkg
|
||||
- name: Upload installer.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: I2P-install-${{ github.sha }}.jar
|
||||
path: install.jar
|
||||
|
||||
javadoc-latest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
- name : Generate override.properties
|
||||
run: |
|
||||
rm -f override.properties
|
||||
echo "build.built-by=GitHub Actions" >> override.properties
|
||||
echo "noExe=true" >> override.properties
|
||||
- name: test Debian build with Ant
|
||||
run: ant distclean
|
||||
- name: build javadoc with Ant
|
||||
run: ant distclean javadoc updater
|
||||
- name: zip javadoc and place update in javadoc zip
|
||||
run: cp i2pupdate.zip build/javadoc/i2pupdate.zip && zip -r javadoc.zip build/javadoc
|
||||
- name: Upload javadoc.zip
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: I2P-javadoc-${{ github.sha }}.zip
|
||||
path: javadoc.zip
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
# Upload javadocs to github page
|
||||
path: 'build/javadoc'
|
||||
- name: Deploy javadoc and dev build to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
build-java7:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
- name : Generate override.properties
|
||||
run: |
|
||||
git clone https://github.com/eyedeekay/openjdk-7 "$HOME/openjdk-7"
|
||||
rm -f override.properties
|
||||
echo "build.built-by=GitHub Actions" >> override.properties
|
||||
echo "noExe=true" >> override.properties
|
||||
echo "javac.compilerargs=-bootclasspath $HOME/openjdk-7/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar:$HOME/openjdk-7/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jce.jar -Xlint:all" >> override.properties
|
||||
- name: build Maven dev build with Ant
|
||||
run: ./installer/resources/maven-dev-release.sh 1
|
||||
- name: Upload servlet-i2p.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: servlet-i2p-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/servlet-i2p*.jar
|
||||
- name: Upload streaming.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: streaming-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/streaming*.jar
|
||||
- name: Upload mstreaming.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mstreaming-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/mstreaming*.jar
|
||||
- name: Upload router.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: router-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/router*.jar
|
||||
- name: Upload i2p.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2p-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/i2p*.jar
|
||||
98
.github/workflows/ant.yml
vendored
98
.github/workflows/ant.yml
vendored
@@ -5,6 +5,11 @@ name: Java CI
|
||||
|
||||
on: [push]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -12,9 +17,9 @@ jobs:
|
||||
steps:
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@v2
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
@@ -26,9 +31,92 @@ jobs:
|
||||
- name: build with Ant
|
||||
run: ant distclean pkg
|
||||
- name: Upload installer.jar
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: I2P-install.jar-${{ github.sha }}
|
||||
name: I2P-install-${{ github.sha }}.jar
|
||||
path: install.jar
|
||||
|
||||
|
||||
javadoc-latest:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v4
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '21'
|
||||
distribution: 'temurin'
|
||||
- name : Generate override.properties
|
||||
run: |
|
||||
rm -f override.properties
|
||||
echo "build.built-by=GitHub Actions" >> override.properties
|
||||
echo "noExe=true" >> override.properties
|
||||
- name: test Debian build with Ant
|
||||
run: ant distclean
|
||||
- name: build javadoc with Ant
|
||||
run: ant distclean javadoc updater
|
||||
- name: zip javadoc and place update in javadoc zip
|
||||
run: cp i2pupdate.zip build/javadoc/i2pupdate.zip && zip -r javadoc.zip build/javadoc
|
||||
- name: Upload javadoc.zip
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: I2P-javadoc-${{ github.sha }}.zip
|
||||
path: javadoc.zip
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
# Upload javadocs to github page
|
||||
path: 'build/javadoc'
|
||||
- name: Deploy javadoc and dev build to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
build-java7:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: GetText
|
||||
run: sudo apt install gettext
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 8
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'temurin'
|
||||
- name : Generate override.properties
|
||||
run: |
|
||||
git clone https://github.com/eyedeekay/openjdk-7 "$HOME/openjdk-7"
|
||||
rm -f override.properties
|
||||
echo "build.built-by=GitHub Actions" >> override.properties
|
||||
echo "noExe=true" >> override.properties
|
||||
echo "javac.compilerargs=-bootclasspath $HOME/openjdk-7/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar:$HOME/openjdk-7/usr/lib/jvm/java-7-openjdk-amd64/jre/lib/jce.jar -Xlint:all" >> override.properties
|
||||
- name: build Maven dev build with Ant
|
||||
run: ./installer/resources/maven-dev-release.sh 1
|
||||
- name: Upload servlet-i2p.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: servlet-i2p-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/servlet-i2p*.jar
|
||||
- name: Upload streaming.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: streaming-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/streaming*.jar
|
||||
- name: Upload mstreaming.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mstreaming-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/mstreaming*.jar
|
||||
- name: Upload router.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: router-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/router*.jar
|
||||
- name: Upload i2p.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2p-${{ github.sha }}.jar
|
||||
path: pkg-mavencentral/i2p*.jar
|
||||
|
||||
36
.github/workflows/docker.yml
vendored
Normal file
36
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Dockerhub
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'i2p-*.*.*'
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Set env
|
||||
run:
|
||||
sudo apt-get install -y sed;
|
||||
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" | sed 's|master|latest|g' >> $GITHUB_ENV
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: true
|
||||
tags: geti2p/i2p:${{ env.RELEASE_VERSION }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
push: true
|
||||
tags: geti2p/i2p.i2p:${{ env.RELEASE_VERSION }}
|
||||
23
.github/workflows/github-sync.yml
vendored
Normal file
23
.github/workflows/github-sync.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# File: .github/workflows/repo-sync.yml
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "30 * * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
repo-sync:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: repo-sync
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: repo-sync/github-sync@v2
|
||||
with:
|
||||
source_repo: "https://i2pgit.org/i2p-hackers/i2p.i2p"
|
||||
source_branch: "master"
|
||||
destination_branch: "master"
|
||||
github_token: ${{ secrets.PAT }}
|
||||
105
.github/workflows/izpack.yml
vendored
Normal file
105
.github/workflows/izpack.yml
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
name: Java with IzPack Snapshot Setup
|
||||
|
||||
on: [push]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Install Required Packages
|
||||
run: sudo apt install gettext
|
||||
- name: Checkout Main Repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
- name: Set up Maven
|
||||
uses: stCarolas/setup-maven@v4.5
|
||||
with:
|
||||
maven-version: '3.9.9'
|
||||
- name: Clone IzPack Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'izpack/izpack'
|
||||
path: 'izpack-source'
|
||||
- name: Build IzPack Snapshot
|
||||
working-directory: ./izpack-source
|
||||
run: |
|
||||
mvn clean install -DskipTests
|
||||
find . -iname 'izpack*.jar'
|
||||
echo "IZPACK_HOME=$GITHUB_WORKSPACE/izpack-source/izpack-dist/target/IzPack" >> $GITHUB_ENV
|
||||
echo "$GITHUB_WORKSPACE/izpack-source/izpack-dist/target/IzPack/bin" >> $GITHUB_PATH
|
||||
cat > auto-install.xml << EOF
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<AutomatedInstallation langpack="eng">
|
||||
<com.izforge.izpack.panels.HelloPanel/>
|
||||
<com.izforge.izpack.panels.TargetPanel>
|
||||
<installpath>/usr/local/IzPack</installpath>
|
||||
</com.izforge.izpack.panels.TargetPanel>
|
||||
<com.izforge.izpack.panels.InstallPanel/>
|
||||
<com.izforge.izpack.panels.FinishPanel/>
|
||||
</AutomatedInstallation>
|
||||
EOF
|
||||
|
||||
# Create installation directory
|
||||
sudo mkdir -p /usr/local/IzPack
|
||||
sudo chmod 777 /usr/local/IzPack
|
||||
|
||||
# Run the installer in headless mode
|
||||
# java -jar ./izpack-dist/target/izpack-dist-*-SNAPSHOT-installer.jar auto-install.xml
|
||||
|
||||
java -DINSTALL_PATH=/usr/local/IzPack -jar ./izpack-dist/target/izpack-dist-*-SNAPSHOT-installer.jar -options-system
|
||||
|
||||
# Update environment
|
||||
echo "/usr/local/IzPack/bin" >> $GITHUB_PATH
|
||||
echo "IZPACK_HOME=/usr/local/IzPack" >> $GITHUB_ENV
|
||||
- name: Generate Properties
|
||||
run: |
|
||||
rm -f override.properties
|
||||
echo "build.built-by=GitHub Actions" >> override.properties
|
||||
echo "izpack.home=${{ env.IZPACK_HOME }}" >> override.properties
|
||||
echo "izpack5.home=${{ env.IZPACK_HOME }}" >> override.properties
|
||||
echo "izpack5.version=5.2.4-SNAPSHOT" >> override.properties
|
||||
- name: Verify Setup
|
||||
run: |
|
||||
java -version
|
||||
ant -version
|
||||
echo "IzPack installation directory: $IZPACK_HOME"
|
||||
ls -l $IZPACK_HOME/bin
|
||||
- name: Upload IzPack Build
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: izpack-snapshot-${{ github.sha }}
|
||||
path: ${{ env.IZPACK_HOME }}
|
||||
retention-days: 1
|
||||
- name: Cache IzPack Build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: izpack-source
|
||||
key: izpack-snapshot-${{ github.sha }}
|
||||
restore-keys: |
|
||||
izpack-snapshot-
|
||||
- name: build with Ant - Non Windows
|
||||
run: ant distclean pkg installer5-linux
|
||||
- name: find installer artifacts
|
||||
run: find . -iname 'i2p*.jar'
|
||||
- name: Upload i2pinstall.jar
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pinstall-${{ github.sha }}.jar
|
||||
path: i2pinstall*.jar
|
||||
- name: build with Ant - Windows
|
||||
run: ant distclean pkg installer5-windows
|
||||
- name: find installer artifacts
|
||||
run: find . -iname 'i2p*.exe'
|
||||
- name: Upload i2pinstall.exe
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: i2pinstall-${{ github.sha }}.exe
|
||||
path: i2pinstall*.exe
|
||||
75
.github/workflows/mirror-release.yml
vendored
Normal file
75
.github/workflows/mirror-release.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
name: mirror
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'i2p-*.*.*'
|
||||
workflow_dispatch: # Allows manual triggering
|
||||
|
||||
jobs:
|
||||
dl:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: |
|
||||
changelog.txt
|
||||
- name: download release artifacts
|
||||
run: |
|
||||
sudo apt-get install wget ca-certificates gpg sed curl git
|
||||
export I2P_VERSION=$(echo ${{ github.ref_name }} | sed 's|i2p-||g' |sed 's|-.*||')
|
||||
echo "$I2P_VERSION"
|
||||
export ATTEMPTS=0
|
||||
while true; do
|
||||
sleep 60m
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pinstall_"$I2P_VERSION"_windows.exe && break
|
||||
ATTEMPTS=$(( $ATTEMPTS + 1 ))
|
||||
if [ $ATTEMPTS -eq 25 ]; then
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/I2P-Easy-Install-Bundle-"$I2P_VERSION"-signed.exe
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/I2P-Easy-Install-Bundle-"$I2P_VERSION".exe
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pinstall_"$I2P_VERSION".jar
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pinstall_"$I2P_VERSION".jar.sig
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pinstall_"$I2P_VERSION"_windows.exe
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pinstall_"$I2P_VERSION"_windows.exe.sig
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2psource_"$I2P_VERSION".tar.bz2
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2psource_"$I2P_VERSION".tar.bz2.sig
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pupdate-"$I2P_VERSION".su3
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pupdate-"$I2P_VERSION".su3.torrent
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pupdate.su3
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pupdate_"$I2P_VERSION".zip
|
||||
wget -v https://files.i2p-projekt.de/"$I2P_VERSION"/i2pupdate_"$I2P_VERSION".zip.sig'
|
||||
echo ""$I2P_VERSION"" > CHANGES.md
|
||||
echo "===========" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
curl https://raw.githubusercontent.com/i2p/i2p.newsxml/master/data/entries.html | sed -n '/<article/,/<\/article/p' | sed -n '1,/<\/article>/p' | sed -n '/<\/details>/,$p' | sed '1d' | sed 's/<\/\{0,1\}p>//g' | sed 's|<\/article>||g' >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
head -n 25 changelog.txt >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "## Checksums" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
sha256sum * >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
file * >> CHANGES.md
|
||||
echo '```' >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
echo "" >> CHANGES.md
|
||||
cat CHANGES.md
|
||||
- name: Upload artifacts
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "*"
|
||||
skipIfReleaseExists: true
|
||||
bodyFile: "CHANGES.md"
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -61,3 +61,5 @@ sloccount.sc
|
||||
|
||||
# TODO: why does this file appear?
|
||||
apps/routerconsole/jsp/favicon.ico
|
||||
.tx
|
||||
/*.sh
|
||||
@@ -52,6 +52,7 @@ test:ant:
|
||||
- echo junit.home=/usr/share/java >> override.properties
|
||||
- echo hamcrest.home=/usr/share/java >> override.properties
|
||||
- echo mockito.home=/usr/share/java >> override.properties
|
||||
- echo build.built-by=GitHub Actions >> override.properties
|
||||
script:
|
||||
- ant test
|
||||
only:
|
||||
@@ -59,19 +60,55 @@ test:ant:
|
||||
- merge_requests
|
||||
- tags
|
||||
|
||||
test:javadoc:
|
||||
stage: test
|
||||
image: debian:unstable-slim
|
||||
variables:
|
||||
SCALA: https://downloads.lightbend.com/scala/2.12.13/scala-2.12.13.deb
|
||||
LIBPREFIX: /usr/share/scala/lib
|
||||
LIB_SCALATEST: https://repo1.maven.org/maven2/org/scalatest/scalatest_2.12/3.0.4/scalatest_2.12-3.0.4.jar
|
||||
LIB_SCALACTIC: https://repo1.maven.org/maven2/org/scalactic/scalactic_2.12/3.0.4/scalactic_2.12-3.0.4.jar
|
||||
before_script:
|
||||
# Fix bug installing openjdk-11-jdk-headless's manuals
|
||||
- mkdir -p /usr/share/man/man1/
|
||||
- apt-get update -q
|
||||
- apt-get install -y wget gettext
|
||||
ant openjdk-21-jdk-headless
|
||||
libmockito-java libhamcrest-java junit4
|
||||
# Install specific version of scala
|
||||
- wget -qO scala.deb "${SCALA}"
|
||||
- dpkg -i scala.deb
|
||||
# link to the scala libs with the name `ant test` expects
|
||||
- ln -s "${LIBPREFIX}/scala-xml_2.12-1.0.6.jar" "${LIBPREFIX}/scala-xml.jar"
|
||||
# Download required scala libs
|
||||
- wget -qO "${LIBPREFIX}/scalactic.jar" "${LIB_SCALACTIC}"
|
||||
- wget -qO "${LIBPREFIX}/scalatest.jar" "${LIB_SCALATEST}"
|
||||
# Point ant to the right directories
|
||||
- echo scalatest.libs=/usr/share/scala/lib > override.properties
|
||||
- echo junit.home=/usr/share/java >> override.properties
|
||||
- echo hamcrest.home=/usr/share/java >> override.properties
|
||||
- echo mockito.home=/usr/share/java >> override.properties
|
||||
- echo build.built-by=GitHub Actions >> override.properties
|
||||
script:
|
||||
- ant javadoc
|
||||
only:
|
||||
- master
|
||||
- merge_requests
|
||||
- tags
|
||||
|
||||
# Make sure we can build a docker image
|
||||
# It's cached for later jobs
|
||||
build_docker:
|
||||
stage: build
|
||||
image: docker:19.03.12
|
||||
image: docker:24.0.7
|
||||
services:
|
||||
- docker:19.03.12-dind
|
||||
- docker:24.0.7-dind
|
||||
script:
|
||||
# Try to load latest branch image from local tar or from registry
|
||||
- docker load -i ci-exports/$CI_COMMIT_REF_SLUG.tar || docker pull $CI_REGISTRY_IMAGE:latest || true
|
||||
- docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:latest .
|
||||
- mkdir -p ci-exports/
|
||||
- docker save $CI_REGISTRY_IMAGE:latest > ci-exports/$CI_COMMIT_REF_SLUG.tar
|
||||
- echo docker save $CI_REGISTRY_IMAGE:latest > ci-exports/$CI_COMMIT_REF_SLUG.tar
|
||||
variables:
|
||||
# When using dind service, we need to instruct docker to talk with
|
||||
# the daemon started inside of the service. The daemon is available
|
||||
@@ -89,7 +126,7 @@ build_docker:
|
||||
# container, thanks to volume mount from config.toml
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
# Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
|
||||
DOCKER_HOST: tcp://docker:2376
|
||||
# DOCKER_HOST: tcp://docker:2376
|
||||
cache:
|
||||
# The same key should be used across branches
|
||||
key: "$CI_COMMIT_REF_SLUG"
|
||||
|
||||
110
.tx/config
110
.tx/config
@@ -1,7 +1,12 @@
|
||||
;; warning - conversions for all Java bundles:
|
||||
;; id->in, he->iw, iy, yi->ji
|
||||
|
||||
[I2P.i2ptunnel]
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = ru_RU: ru, sv_SE: sv, tr_TR: tr, uk_UA: uk, zh_CN: zh, et_EE: et, id: in, he: iw
|
||||
|
||||
[o:otf:p:I2P:r:i2ptunnel]
|
||||
file_filter = apps/i2ptunnel/locale/messages_<lang>.po
|
||||
source_file = apps/i2ptunnel/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2ptunnel/locale/messages_ar.po
|
||||
@@ -9,9 +14,11 @@ trans.cs = apps/i2ptunnel/locale/messages_cs.po
|
||||
trans.da = apps/i2ptunnel/locale/messages_da.po
|
||||
trans.de = apps/i2ptunnel/locale/messages_de.po
|
||||
trans.es = apps/i2ptunnel/locale/messages_es.po
|
||||
trans.es_AR = apps/i2ptunnel/locale/messages_es_AR.po
|
||||
trans.fa = apps/i2ptunnel/locale/messages_fa.po
|
||||
trans.fi = apps/i2ptunnel/locale/messages_fi.po
|
||||
trans.fr = apps/i2ptunnel/locale/messages_fr.po
|
||||
trans.gan = apps/i2ptunnel/locale/messages_gan.po
|
||||
trans.hu = apps/i2ptunnel/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/i2ptunnel/locale/messages_in.po
|
||||
@@ -35,7 +42,8 @@ trans.vi = apps/i2ptunnel/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2ptunnel/locale/messages_zh.po
|
||||
trans.zh_TW = apps/i2ptunnel/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.proxy]
|
||||
[o:otf:p:I2P:r:proxy]
|
||||
file_filter = apps/i2ptunnel/locale-proxy/messages_<lang>.po
|
||||
source_file = apps/i2ptunnel/locale-proxy/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2ptunnel/locale-proxy/messages_ar.po
|
||||
@@ -43,9 +51,11 @@ trans.cs = apps/i2ptunnel/locale-proxy/messages_cs.po
|
||||
trans.de = apps/i2ptunnel/locale-proxy/messages_de.po
|
||||
trans.el = apps/i2ptunnel/locale-proxy/messages_el.po
|
||||
trans.es = apps/i2ptunnel/locale-proxy/messages_es.po
|
||||
trans.es_AR = apps/i2ptunnel/locale-proxy/messages_es_AR.po
|
||||
trans.fa = apps/i2ptunnel/locale-proxy/messages_fa.po
|
||||
trans.fi = apps/i2ptunnel/locale-proxy/messages_fi.po
|
||||
trans.fr = apps/i2ptunnel/locale-proxy/messages_fr.po
|
||||
trans.gan = apps/i2ptunnel/locale-proxy/messages_gan.po
|
||||
trans.hu = apps/i2ptunnel/locale-proxy/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/i2ptunnel/locale-proxy/messages_in.po
|
||||
@@ -66,8 +76,10 @@ trans.tr_TR = apps/i2ptunnel/locale-proxy/messages_tr.po
|
||||
trans.uk_UA = apps/i2ptunnel/locale-proxy/messages_uk.po
|
||||
trans.vi = apps/i2ptunnel/locale-proxy/messages_vi.po
|
||||
trans.zh_CN = apps/i2ptunnel/locale-proxy/messages_zh.po
|
||||
trans.zh_TW = apps/i2ptunnel/locale-proxy/messages_zh_TW.po
|
||||
|
||||
[I2P.core]
|
||||
[o:otf:p:I2P:r:core]
|
||||
file_filter = core/locale/messages_<lang>.po
|
||||
type = PO
|
||||
source_file = core/locale/messages_en.po
|
||||
source_lang = en
|
||||
@@ -82,6 +94,7 @@ trans.et_EE = core/locale/messages_et.po
|
||||
trans.fa = core/locale/messages_fa.po
|
||||
trans.fi = core/locale/messages_fi.po
|
||||
trans.fr = core/locale/messages_fr.po
|
||||
trans.gan = core/locale/messages_gan.po
|
||||
trans.hu = core/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = core/locale/messages_in.po
|
||||
@@ -105,7 +118,8 @@ trans.vi = core/locale/messages_vi.po
|
||||
trans.zh_CN = core/locale/messages_zh.po
|
||||
trans.zh_TW = core/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.router]
|
||||
[o:otf:p:I2P:r:router]
|
||||
file_filter = router/locale/messages_<lang>.po
|
||||
type = PO
|
||||
source_file = router/locale/messages_en.po
|
||||
source_lang = en
|
||||
@@ -116,10 +130,12 @@ trans.da = router/locale/messages_da.po
|
||||
trans.de = router/locale/messages_de.po
|
||||
trans.el = router/locale/messages_el.po
|
||||
trans.es = router/locale/messages_es.po
|
||||
trans.es_AR = router/locale/messages_es_AR.po
|
||||
trans.et_EE = router/locale/messages_et.po
|
||||
trans.fa = router/locale/messages_fa.po
|
||||
trans.fi = router/locale/messages_fi.po
|
||||
trans.fr = router/locale/messages_fr.po
|
||||
trans.gan = router/locale/messages_gan.po
|
||||
trans.hu = router/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = router/locale/messages_in.po
|
||||
@@ -143,7 +159,8 @@ trans.vi = router/locale/messages_vi.po
|
||||
trans.zh_CN = router/locale/messages_zh.po
|
||||
trans.zh_TW = router/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.routerconsole]
|
||||
[o:otf:p:I2P:r:routerconsole]
|
||||
file_filter = apps/routerconsole/locale/messages_<lang>.po
|
||||
source_file = apps/routerconsole/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/locale/messages_ar.po
|
||||
@@ -153,10 +170,12 @@ trans.da = apps/routerconsole/locale/messages_da.po
|
||||
trans.de = apps/routerconsole/locale/messages_de.po
|
||||
trans.el = apps/routerconsole/locale/messages_el.po
|
||||
trans.es = apps/routerconsole/locale/messages_es.po
|
||||
trans.es_AR = apps/routerconsole/locale/messages_es_AR.po
|
||||
trans.et_EE = apps/routerconsole/locale/messages_et.po
|
||||
trans.fa = apps/routerconsole/locale/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale/messages_fr.po
|
||||
trans.gan = apps/routerconsole/locale/messages_gan.po
|
||||
trans.hu = apps/routerconsole/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/routerconsole/locale/messages_in.po
|
||||
@@ -177,7 +196,8 @@ trans.vi = apps/routerconsole/locale/messages_vi.po
|
||||
trans.zh_CN = apps/routerconsole/locale/messages_zh.po
|
||||
trans.zh_TW = apps/routerconsole/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.welcome]
|
||||
[o:otf:p:I2P:r:welcome]
|
||||
file_filter = apps/routerconsole/locale-news/messages_<lang>.po
|
||||
source_file = apps/routerconsole/locale-news/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/locale-news/messages_ar.po
|
||||
@@ -186,9 +206,11 @@ trans.cs = apps/routerconsole/locale-news/messages_cs.po
|
||||
trans.de = apps/routerconsole/locale-news/messages_de.po
|
||||
trans.el = apps/routerconsole/locale-news/messages_el.po
|
||||
trans.es = apps/routerconsole/locale-news/messages_es.po
|
||||
trans.es_AR = apps/routerconsole/locale-news/messages_es_AR.po
|
||||
trans.fa = apps/routerconsole/locale-news/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale-news/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale-news/messages_fr.po
|
||||
trans.gan = apps/routerconsole/locale-news/messages_gan.po
|
||||
trans.gl = apps/routerconsole/locale-news/messages_gl.po
|
||||
;; Java converts he to iw
|
||||
trans.he = apps/routerconsole/locale-news/messages_iw.po
|
||||
@@ -218,7 +240,8 @@ trans.uk_UA = apps/routerconsole/locale-news/messages_uk.po
|
||||
trans.zh_CN = apps/routerconsole/locale-news/messages_zh.po
|
||||
trans.zh_TW = apps/routerconsole/locale-news/messages_zh_TW.po
|
||||
|
||||
[I2P.countries]
|
||||
[o:otf:p:I2P:r:countries]
|
||||
file_filter = apps/routerconsole/locale-countries/messages_<lang>.po
|
||||
type = PO
|
||||
source_file = apps/routerconsole/locale-countries/messages_en.po
|
||||
source_lang = en
|
||||
@@ -231,6 +254,7 @@ trans.da = apps/routerconsole/locale-countries/messages_da.po
|
||||
trans.de = apps/routerconsole/locale-countries/messages_de.po
|
||||
trans.el = apps/routerconsole/locale-countries/messages_el.po
|
||||
trans.es = apps/routerconsole/locale-countries/messages_es.po
|
||||
trans.es_AR = apps/routerconsole/locale-countries/messages_es_AR.po
|
||||
trans.et_EE = apps/routerconsole/locale-countries/messages_et.po
|
||||
trans.fa = apps/routerconsole/locale-countries/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale-countries/messages_fi.po
|
||||
@@ -267,17 +291,21 @@ trans.vi = apps/routerconsole/locale-countries/messages_vi.po
|
||||
trans.zh_CN = apps/routerconsole/locale-countries/messages_zh.po
|
||||
trans.zh_TW = apps/routerconsole/locale-countries/messages_zh_TW.po
|
||||
|
||||
[I2P.i2psnark]
|
||||
[o:otf:p:I2P:r:i2psnark]
|
||||
file_filter = apps/i2psnark/locale/messages_<lang>.po
|
||||
source_file = apps/i2psnark/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/i2psnark/locale/messages_ar.po
|
||||
trans.cs = apps/i2psnark/locale/messages_cs.po
|
||||
trans.da = apps/i2psnark/locale/messages_da.po
|
||||
trans.de = apps/i2psnark/locale/messages_de.po
|
||||
trans.el = apps/i2psnark/locale/messages_el.po
|
||||
trans.es = apps/i2psnark/locale/messages_es.po
|
||||
trans.es_AR = apps/i2psnark/locale/messages_es_AR.po
|
||||
trans.fa = apps/i2psnark/locale/messages_fa.po
|
||||
trans.fi = apps/i2psnark/locale/messages_fi.po
|
||||
trans.fr = apps/i2psnark/locale/messages_fr.po
|
||||
trans.gan = apps/i2psnark/locale/messages_gan.po
|
||||
trans.hu = apps/i2psnark/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/i2psnark/locale/messages_in.po
|
||||
@@ -300,7 +328,8 @@ trans.vi = apps/i2psnark/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2psnark/locale/messages_zh.po
|
||||
trans.zh_TW = apps/i2psnark/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.susidns]
|
||||
[o:otf:p:I2P:r:susidns]
|
||||
file_filter = apps/susidns/locale/messages_<lang>.po
|
||||
source_file = apps/susidns/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/susidns/locale/messages_ar.po
|
||||
@@ -309,9 +338,11 @@ trans.da = apps/susidns/locale/messages_da.po
|
||||
trans.de = apps/susidns/locale/messages_de.po
|
||||
trans.el = apps/susidns/locale/messages_el.po
|
||||
trans.es = apps/susidns/locale/messages_es.po
|
||||
trans.es_AR = apps/susidns/locale/messages_es_AR.po
|
||||
trans.fa = apps/susidns/locale/messages_fa.po
|
||||
trans.fi = apps/susidns/locale/messages_fi.po
|
||||
trans.fr = apps/susidns/locale/messages_fr.po
|
||||
trans.gan = apps/susidns/locale/messages_gan.po
|
||||
trans.gl = apps/susidns/locale/messages_gl.po
|
||||
trans.hu = apps/susidns/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
@@ -332,7 +363,8 @@ trans.vi = apps/susidns/locale/messages_vi.po
|
||||
trans.zh_CN = apps/susidns/locale/messages_zh.po
|
||||
trans.zh_TW = apps/susidns/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.desktopgui]
|
||||
[o:otf:p:I2P:r:desktopgui]
|
||||
file_filter = apps/desktopgui/locale/messages_<lang>.po
|
||||
source_file = apps/desktopgui/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/desktopgui/locale/messages_ar.po
|
||||
@@ -348,6 +380,7 @@ trans.es_AR = apps/desktopgui/locale/messages_es_AR.po
|
||||
trans.fa = apps/desktopgui/locale/messages_fa.po
|
||||
trans.fi = apps/desktopgui/locale/messages_fi.po
|
||||
trans.fr = apps/desktopgui/locale/messages_fr.po
|
||||
trans.gan = apps/desktopgui/locale/messages_gan.po
|
||||
trans.gl = apps/desktopgui/locale/messages_gl.po
|
||||
trans.hu = apps/desktopgui/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
@@ -376,7 +409,8 @@ trans.vi = apps/desktopgui/locale/messages_vi.po
|
||||
trans.zh_CN = apps/desktopgui/locale/messages_zh.po
|
||||
trans.zh_TW = apps/desktopgui/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.susimail]
|
||||
[o:otf:p:I2P:r:susimail]
|
||||
file_filter = apps/susimail/locale/messages_<lang>.po
|
||||
source_file = apps/susimail/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/susimail/locale/messages_ar.po
|
||||
@@ -388,9 +422,12 @@ trans.da = apps/susimail/locale/messages_da.po
|
||||
trans.de = apps/susimail/locale/messages_de.po
|
||||
trans.el = apps/susimail/locale/messages_el.po
|
||||
trans.es = apps/susimail/locale/messages_es.po
|
||||
trans.es_AR = apps/susimail/locale/messages_es_AR.po
|
||||
trans.et_EE = apps/susimail/locale/messages_et.po
|
||||
trans.fa = apps/susimail/locale/messages_fa.po
|
||||
trans.fi = apps/susimail/locale/messages_fi.po
|
||||
trans.fr = apps/susimail/locale/messages_fr.po
|
||||
trans.gan = apps/susimail/locale/messages_gan.po
|
||||
trans.gl = apps/susimail/locale/messages_gl.po
|
||||
trans.hr = apps/susimail/locale/messages_hr.po
|
||||
trans.hu = apps/susimail/locale/messages_hu.po
|
||||
@@ -401,6 +438,7 @@ trans.id = apps/susimail/locale/messages_in.po
|
||||
trans.it = apps/susimail/locale/messages_it.po
|
||||
trans.ja = apps/susimail/locale/messages_ja.po
|
||||
trans.ko = apps/susimail/locale/messages_ko.po
|
||||
trans.ku = apps/susimail/locale/messages_ku.po
|
||||
trans.mg = apps/susimail/locale/messages_mg.po
|
||||
trans.nb = apps/susimail/locale/messages_nb.po
|
||||
trans.nl = apps/susimail/locale/messages_nl.po
|
||||
@@ -410,6 +448,7 @@ trans.pt_BR = apps/susimail/locale/messages_pt_BR.po
|
||||
trans.ro = apps/susimail/locale/messages_ro.po
|
||||
trans.ru_RU = apps/susimail/locale/messages_ru.po
|
||||
trans.sk = apps/susimail/locale/messages_sk.po
|
||||
trans.sl = apps/susimail/locale/messages_sl.po
|
||||
trans.sq = apps/susimail/locale/messages_sq.po
|
||||
trans.sr = apps/susimail/locale/messages_sr.po
|
||||
trans.sv_SE = apps/susimail/locale/messages_sv.po
|
||||
@@ -419,7 +458,8 @@ trans.vi = apps/susimail/locale/messages_vi.po
|
||||
trans.zh_CN = apps/susimail/locale/messages_zh.po
|
||||
trans.zh_TW = apps/susimail/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.debconf]
|
||||
[o:otf:p:I2P:r:debconf]
|
||||
file_filter = debian/po/<lang>.po
|
||||
source_file = debian/po/templates.pot
|
||||
source_lang = en
|
||||
trans.ar = debian/po/ar.po
|
||||
@@ -428,6 +468,7 @@ trans.cs = debian/po/cs.po
|
||||
trans.de = debian/po/de.po
|
||||
trans.el = debian/po/el.po
|
||||
trans.es = debian/po/es.po
|
||||
trans.es_AR = debian/po/es_AR.po
|
||||
trans.fi = debian/po/fi.po
|
||||
trans.fr = debian/po/fr.po
|
||||
trans.gl = debian/po/gl.po
|
||||
@@ -453,16 +494,21 @@ trans.uk_UA = debian/po/uk.po
|
||||
trans.zh_CN = debian/po/zh.po
|
||||
trans.zh_TW = debian/po/zh_TW.po
|
||||
|
||||
[I2P.i2prouter-script]
|
||||
[o:otf:p:I2P:r:i2prouter-script]
|
||||
file_filter = installer/resources/locale/po/messages_<lang>.po
|
||||
source_file = installer/resources/locale/po/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = installer/resources/locale/po/messages_ar.po
|
||||
trans.az = installer/resources/locale/po/messages_az.po
|
||||
trans.ca = installer/resources/locale/po/messages_ca.po
|
||||
trans.cs = installer/resources/locale/po/messages_cs.po
|
||||
trans.de = installer/resources/locale/po/messages_de.po
|
||||
trans.es = installer/resources/locale/po/messages_es.po
|
||||
trans.es_AR = installer/resources/locale/po/messages_es_AR.po
|
||||
trans.fi = installer/resources/locale/po/messages_fi.po
|
||||
trans.fr = installer/resources/locale/po/messages_fr.po
|
||||
trans.gan = installer/resources/locale/po/messages_gan.po
|
||||
trans.hu = installer/resources/locale/po/messages_hu.po
|
||||
trans.id = installer/resources/locale/po/messages_id.po
|
||||
trans.it = installer/resources/locale/po/messages_it.po
|
||||
trans.ja = installer/resources/locale/po/messages_ja.po
|
||||
@@ -479,8 +525,9 @@ trans.sv_SE = installer/resources/locale/po/messages_sv.po
|
||||
trans.tr_TR = installer/resources/locale/po/messages_tr.po
|
||||
trans.uk_UA = installer/resources/locale/po/messages_uk.po
|
||||
trans.zh_CN = installer/resources/locale/po/messages_zh.po
|
||||
trans.zh_TW = installer/resources/locale/po/messages_zh_TW.po
|
||||
|
||||
[I2P.getopt]
|
||||
[o:otf:p:I2P:r:getopt]
|
||||
;;
|
||||
;; Java properties files (when not read with our DataHelper methods) must be ISO-8859-1 encoded.
|
||||
;; See https://docs.oracle.com/javase/6/docs/api/java/util/Properties.html
|
||||
@@ -497,6 +544,7 @@ trans.zh_CN = installer/resources/locale/po/messages_zh.po
|
||||
;; and should be escaped using native2ascii after downloading:
|
||||
;; gl, pt, pt_BR, sq, sv, tr
|
||||
;;
|
||||
file_filter = core/java/src/gnu/getopt/MessagesBundle_<lang>.properties
|
||||
source_file = core/java/src/gnu/getopt/MessagesBundle.properties
|
||||
source_lang = en
|
||||
type = PROPERTIES
|
||||
@@ -505,6 +553,7 @@ trans.az = core/java/src/gnu/getopt/MessagesBundle_az.properties
|
||||
trans.cs = core/java/src/gnu/getopt/MessagesBundle_cs.properties
|
||||
trans.de = core/java/src/gnu/getopt/MessagesBundle_de.properties
|
||||
trans.es = core/java/src/gnu/getopt/MessagesBundle_es.properties
|
||||
trans.es_AR = core/java/src/gnu/getopt/MessagesBundle_es_AR.properties
|
||||
trans.fi = core/java/src/gnu/getopt/MessagesBundle_fi.properties
|
||||
trans.fr = core/java/src/gnu/getopt/MessagesBundle_fr.properties
|
||||
trans.gl = core/java/src/gnu/getopt/MessagesBundle_gl.properties
|
||||
@@ -532,7 +581,8 @@ trans.uk_UA = core/java/src/gnu/getopt/MessagesBundle_uk.properties
|
||||
trans.zh_CN = core/java/src/gnu/getopt/MessagesBundle_zh.properties
|
||||
trans.zh_TW = core/java/src/gnu/getopt/MessagesBundle_zh_TW.properties
|
||||
|
||||
[I2P.streaming]
|
||||
[o:otf:p:I2P:r:streaming]
|
||||
file_filter = apps/ministreaming/locale/messages_<lang>.po
|
||||
source_file = apps/ministreaming/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/ministreaming/locale/messages_ar.po
|
||||
@@ -541,14 +591,17 @@ trans.ca = apps/ministreaming/locale/messages_ca.po
|
||||
trans.cs = apps/ministreaming/locale/messages_cs.po
|
||||
trans.de = apps/ministreaming/locale/messages_de.po
|
||||
trans.es = apps/ministreaming/locale/messages_es.po
|
||||
trans.es_AR = apps/ministreaming/locale/messages_es_AR.po
|
||||
trans.fa = apps/ministreaming/locale/messages_fa.po
|
||||
trans.fi = apps/ministreaming/locale/messages_fi.po
|
||||
trans.fr = apps/ministreaming/locale/messages_fr.po
|
||||
trans.gan = apps/ministreaming/locale/messages_gan.po
|
||||
trans.gl = apps/ministreaming/locale/messages_gl.po
|
||||
trans.hu = apps/ministreaming/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/ministreaming/locale/messages_in.po
|
||||
trans.it = apps/ministreaming/locale/messages_it.po
|
||||
trans.ja = apps/ministreaming/locale/messages_ja.po
|
||||
trans.ko = apps/ministreaming/locale/messages_ko.po
|
||||
trans.nb = apps/ministreaming/locale/messages_nb.po
|
||||
trans.nl = apps/ministreaming/locale/messages_nl.po
|
||||
@@ -563,12 +616,14 @@ trans.tk = apps/ministreaming/locale/messages_tk.po
|
||||
trans.tr_TR = apps/ministreaming/locale/messages_tr.po
|
||||
trans.uk_UA = apps/ministreaming/locale/messages_uk.po
|
||||
trans.zh_CN = apps/ministreaming/locale/messages_zh.po
|
||||
trans.zh_TW = apps/ministreaming/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.manpages]
|
||||
[o:otf:p:I2P:r:manpages]
|
||||
;;
|
||||
;; after adding languages here, add to debian/*.manpages also
|
||||
;; You must run installer/resources/poupdate-man.sh first.
|
||||
;;
|
||||
file_filter = installer/resources/locale-man/man_<lang>.po
|
||||
type = PO
|
||||
source_file = installer/resources/locale-man/man.pot
|
||||
source_lang = en
|
||||
@@ -576,8 +631,10 @@ trans.ar = installer/resources/locale-man/man_ar.po
|
||||
trans.az = installer/resources/locale-man/man_az.po
|
||||
trans.de = installer/resources/locale-man/man_de.po
|
||||
trans.es = installer/resources/locale-man/man_es.po
|
||||
trans.es_AR = installer/resources/locale-man/man_es_AR.po
|
||||
trans.fi = installer/resources/locale-man/man_fi.po
|
||||
trans.fr = installer/resources/locale-man/man_fr.po
|
||||
trans.gan = installer/resources/locale-man/man_gan.po
|
||||
trans.hu = installer/resources/locale-man/man_hu.po
|
||||
trans.id = installer/resources/locale-man/man_id.po
|
||||
trans.it = installer/resources/locale-man/man_it.po
|
||||
@@ -592,13 +649,15 @@ trans.ru_RU = installer/resources/locale-man/man_ru.po
|
||||
trans.sv_SE = installer/resources/locale-man/man_sv.po
|
||||
trans.tr_TR = installer/resources/locale-man/man_tr.po
|
||||
trans.zh_CN = installer/resources/locale-man/man_zh.po
|
||||
trans.zh_TW = installer/resources/locale-man/man_zh_TW.po
|
||||
|
||||
[I2P.eepsite]
|
||||
[o:otf:p:I2P:r:eepsite]
|
||||
;;
|
||||
;; For any new translations, add links in installer/resources/eepsite/docroot/help/index.html
|
||||
;; and copy new flags in build.xml copyflags-unlesspkg target,
|
||||
;; and add to debian/i2p-router.links and debian-alt/*/i2p-router.links
|
||||
;;
|
||||
file_filter = installer/resources/eepsite/docroot/help/index_<lang>.po
|
||||
type = HTML
|
||||
source_file = installer/resources/eepsite/docroot/help/index.html
|
||||
source_lang = en
|
||||
@@ -608,14 +667,15 @@ source_lang = en
|
||||
trans.az = installer/resources/eepsite/docroot/help/index_az.html
|
||||
trans.de = installer/resources/eepsite/docroot/help/index_de.html
|
||||
trans.el = installer/resources/eepsite/docroot/help/index_el.html
|
||||
;; not yet translated on TX, use old page
|
||||
;;trans.es = installer/resources/eepsite/docroot/help/index_es.html
|
||||
trans.es = installer/resources/eepsite/docroot/help/index_es.html
|
||||
trans.fa = installer/resources/eepsite/docroot/help/index_fa.html
|
||||
trans.fr = installer/resources/eepsite/docroot/help/index_fr.html
|
||||
trans.gan = installer/resources/eepsite/docroot/help/index_gan.html
|
||||
trans.hu = installer/resources/eepsite/docroot/help/index_hu.html
|
||||
;; Java converts id to in
|
||||
trans.id = installer/resources/eepsite/docroot/help/index_in.html
|
||||
trans.it = installer/resources/eepsite/docroot/help/index_it.html
|
||||
trans.ja = installer/resources/eepsite/docroot/help/index_ja.html
|
||||
;; not yet translated on TX, use old page
|
||||
;;trans.nl = installer/resources/eepsite/docroot/help/index_nl.html
|
||||
trans.pl = installer/resources/eepsite/docroot/help/index_pl.html
|
||||
@@ -627,16 +687,22 @@ trans.tr_TR = installer/resources/eepsite/docroot/help/index_tr.html
|
||||
trans.uk_UA = installer/resources/eepsite/docroot/help/index_uk.html
|
||||
trans.zh_CN = installer/resources/eepsite/docroot/help/index_zh.html
|
||||
|
||||
[I2P.readme]
|
||||
[o:otf:p:I2P:r:readme]
|
||||
;;
|
||||
;; Text on /console
|
||||
;;
|
||||
;; NOTE: No support for country suffixes right now.
|
||||
;; See ResourceHelper.java
|
||||
;;
|
||||
file_filter = apps/routerconsole/resources/docs/readme_<lang>.html
|
||||
type = HTML
|
||||
source_file = apps/routerconsole/resources/docs/readme.html
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/resources/docs/readme_ar.html
|
||||
trans.cs = apps/routerconsole/resources/docs/readme_cs.html
|
||||
trans.de = apps/routerconsole/resources/docs/readme_de.html
|
||||
trans.fr = apps/routerconsole/resources/docs/readme_fr.html
|
||||
trans.gan = apps/routerconsole/resources/docs/readme_gan.html
|
||||
trans.hu = apps/routerconsole/resources/docs/readme_hu.html
|
||||
;; Java converts id to in
|
||||
trans.id = apps/routerconsole/resources/docs/readme_in.html
|
||||
@@ -650,7 +716,5 @@ trans.sl = apps/routerconsole/resources/docs/readme_sl.html
|
||||
trans.tr_TR = apps/routerconsole/resources/docs/readme_tr.html
|
||||
trans.uk_UA = apps/routerconsole/resources/docs/readme_uk.html
|
||||
trans.zh_CN = apps/routerconsole/resources/docs/readme_zh.html
|
||||
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
trans.zh_TW = apps/routerconsole/resources/docs/readme_zh_TW.html
|
||||
|
||||
|
||||
44
Docker.md
44
Docker.md
@@ -4,30 +4,47 @@
|
||||
If you just want to give I2P a quick try or are using it on a home network, follow these steps:
|
||||
|
||||
1. Create two directories `i2pconfig` and `i2ptorrents`
|
||||
2. Copy the following text and save it in a file `docker-compose.yml`
|
||||
2. Create an `.env` file containing the `EXT_PORT` environment variable.
|
||||
3. Copy the following text and save it in a file `docker-compose.yml`
|
||||
```
|
||||
version: "3.5"
|
||||
services:
|
||||
i2p:
|
||||
image: geti2p/i2p
|
||||
network_mode: host
|
||||
ports:
|
||||
- 127.0.0.1:4444:4444
|
||||
- 127.0.0.1:6668:6668
|
||||
- 127.0.0.1:7657:7657
|
||||
- "$EXT_PORT":"$EXT_PORT"
|
||||
- "$EXT_PORT":"$EXT_PORT"/udp
|
||||
volumes:
|
||||
- ./i2pconfig:/i2p/.i2p
|
||||
- ./i2ptorrents:/i2psnark
|
||||
```
|
||||
3. Execute `docker-compose up`
|
||||
4. Start a browser and go to `http://127.0.0.1:7657` to complete the setup wizard.
|
||||
4. Execute `docker-compose up`
|
||||
5. Start a browser and go to `http://127.0.0.1:7657` to complete the setup wizard.
|
||||
|
||||
Note that this quick-start approach is not recommended for production deployments on remote servers. Please read the rest of this document for more information.
|
||||
|
||||
### Building an image
|
||||
There is an i2P image available over at [DockerHub](https://hub.docker.com). If you do not want to use that one, you can build one yourself:
|
||||
```
|
||||
docker build -t i2p .
|
||||
docker build -t geti2p/i2p .
|
||||
```
|
||||
|
||||
### Running a container
|
||||
|
||||
#### Environment Variables
|
||||
|
||||
It is possible to set the IP address where the I2P router is accessible by setting
|
||||
the `IP_ADDR` environment variable in your `docker run` command or your `docker-compose`
|
||||
file. For example, if you want to make your I2P router listen on all addresses, then
|
||||
you should pass `-e IP_ADDR=0.0.0.0` to your `docker run` command.
|
||||
|
||||
It is also possible to configure the memory available to the I2P router using
|
||||
environment variables. To do this, use the: `JVM_XMX` environment variable by passing,
|
||||
for example, `-e JVM_XMX=256m`.
|
||||
|
||||
#### Volumes
|
||||
The container requires a volume for the configuration data to be mounted. Optionally, you can mount a separate volume for torrent ("i2psnark") downloads. See the example below.
|
||||
|
||||
@@ -59,16 +76,19 @@ A best-practices guide for cloud deployments is beyond the scope of this documen
|
||||
|
||||
#### Example
|
||||
Here is an example container that mounts `i2phome` as home directory, `i2ptorrents` for torrents, and opens HTTP Proxy, IRC, Router Console and I2NP Protocols. It also limits the memory available to the JVM to 256MB.
|
||||
|
||||
```
|
||||
docker build -t geti2p/i2p .
|
||||
# I2NP port needs TCP and UDP. Change the 54321 to something random, greater than 1024.
|
||||
docker run \
|
||||
-e JVM_XMX=256m \
|
||||
-e EXT_PORT=54321 \
|
||||
-v i2phome:/i2p/.i2p \
|
||||
-v i2ptorrents:/i2psnark \
|
||||
-p 4444:4444 \
|
||||
-p 6668:6668 \
|
||||
-p 7657:7657 \
|
||||
-p 54321:12345 \
|
||||
-p 54321:12345/udp \ # I2NP port needs TCP and UDP. Change the 54321 to something random, greater than 1024.
|
||||
i2p:latest
|
||||
-p 127.0.0.1:4444:4444 \
|
||||
-p 127.0.0.1:6668:6668 \
|
||||
-p 127.0.0.1:7657:7657 \
|
||||
-p "$EXT_PORT":"$EXT_PORT" \
|
||||
-p "$EXT_PORT":"$EXT_PORT"/udp \
|
||||
geti2p/i2p:latest
|
||||
```
|
||||
|
||||
|
||||
16
Dockerfile
16
Dockerfile
@@ -1,24 +1,27 @@
|
||||
FROM jlesage/baseimage:alpine-3.15-glibc as builder
|
||||
FROM alpine:3.17.1 as builder
|
||||
|
||||
ENV APP_HOME="/i2p"
|
||||
|
||||
WORKDIR /tmp/build
|
||||
COPY . .
|
||||
|
||||
RUN add-pkg --virtual build-base gettext tar bzip2 apache-ant openjdk8 \
|
||||
RUN apk add --virtual build-base gettext tar bzip2 apache-ant openjdk17 \
|
||||
&& echo "build.built-by=Docker" >> override.properties \
|
||||
&& ant preppkg-linux-only \
|
||||
&& rm -rf pkg-temp/osid pkg-temp/lib/wrapper pkg-temp/lib/wrapper.* \
|
||||
&& del-pkg build-base gettext tar bzip2 apache-ant openjdk8
|
||||
&& apk del build-base gettext tar bzip2 apache-ant openjdk17
|
||||
|
||||
FROM jlesage/baseimage:alpine-3.15-glibc
|
||||
FROM alpine:3.17.1
|
||||
ENV APP_HOME="/i2p"
|
||||
|
||||
RUN add-pkg openjdk8-jre
|
||||
RUN apk add openjdk17-jre ttf-dejavu
|
||||
|
||||
WORKDIR ${APP_HOME}
|
||||
COPY --from=builder /tmp/build/pkg-temp .
|
||||
|
||||
# "install" i2p by copying over installed files
|
||||
COPY docker/rootfs/ /
|
||||
COPY --chown=root:root docker/rootfs/ /
|
||||
RUN chmod +x /startapp.sh
|
||||
|
||||
# Mount home and snark
|
||||
VOLUME ["${APP_HOME}/.i2p"]
|
||||
@@ -34,3 +37,4 @@ LABEL \
|
||||
org.label-schema.vcs-url="https://github.com/i2p/i2p.i2p" \
|
||||
org.label-schema.schema-version="1.0"
|
||||
|
||||
ENTRYPOINT ["/startapp.sh"]
|
||||
|
||||
25
LICENSE.txt
25
LICENSE.txt
@@ -212,10 +212,6 @@ Applications:
|
||||
Copyright (c) 2006, Matthew Estes
|
||||
See licenses/LICENSE-BlockFile.txt
|
||||
|
||||
BOB (BOB.jar):
|
||||
Copyright (C) sponge
|
||||
See licenses/COPYING-BOB.txt
|
||||
|
||||
Desktopgui (desktopgui.jar):
|
||||
Copyright (c) Mathias De Maré
|
||||
See licenses/LICENSE-DesktopGUI.txt
|
||||
@@ -271,7 +267,7 @@ Applications:
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/LICENSE-ECLIPSE-1.0.html
|
||||
|
||||
RRD4J 3.8 (jrobin.jar):
|
||||
RRD4J 3.10 (jrobin.jar):
|
||||
Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
|
||||
Copyright (c) 2011 The OpenNMS Group, Inc.
|
||||
Copyright 2011 The RRD4J Authors.
|
||||
@@ -320,6 +316,10 @@ Applications:
|
||||
See licenses/LICENSE-NDT.txt
|
||||
Notice: I2P has changed specified portions of the Software, including the package edu.internet2.ndt.
|
||||
|
||||
Router Console Iframe-resizer 4.3.9:
|
||||
Copyright (c) 2013-2023 David J. Bradshaw
|
||||
See licenses/LICENSE-Iframe-resizer.txt
|
||||
|
||||
SAM (sam.jar):
|
||||
Public domain.
|
||||
|
||||
@@ -336,12 +336,19 @@ Applications:
|
||||
GPLv2 (or any later version)
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
SusiMail Pagedown:
|
||||
Original Markdown Copyright (c) 2004-2005 John Gruber
|
||||
Original Showdown code copyright (c) 2007 John Fraser
|
||||
Modifications and bugfixes (c) 2009 Dana Robinson
|
||||
Modifications and bugfixes (c) 2009-2014 Stack Exchange Inc.
|
||||
See licenses/LICENSE-pagedown.txt
|
||||
|
||||
Systray (systray.jar):
|
||||
Public domain.
|
||||
|
||||
Tomcat 9.0.54 (jasper-runtime.jar):
|
||||
Tomcat 9.0.88 (jasper-runtime.jar):
|
||||
(not included in most distribution packages)
|
||||
Copyright 1999-2021 The Apache Software Foundation
|
||||
Copyright 1999-2024 The Apache Software Foundation
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/NOTICE-Tomcat.txt
|
||||
|
||||
@@ -355,7 +362,7 @@ distributions. See the source package for the additional license information.
|
||||
Admin Manager:
|
||||
Public domain
|
||||
|
||||
Gradle wrapper 5.2.1:
|
||||
Gradle wrapper 8.5:
|
||||
(not included in most distribution packages)
|
||||
Copyright (c) 2017 the original author or authors.
|
||||
Copyright (c) 2023 the original author or authors.
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#bob.config
|
||||
#Tue Dec 30 00:00:00 UTC 2008
|
||||
# Please leave this file here for testing.
|
||||
# Thank you,
|
||||
# Sponge
|
||||
i2cp.tcp.port=7654
|
||||
BOB.host=localhost
|
||||
inbound.lengthVariance=0
|
||||
i2cp.messageReliability=BestEffort
|
||||
BOB.port=45678
|
||||
outbound.length=1
|
||||
inbound.length=1
|
||||
outbound.lengthVariance=0
|
||||
i2cp.tcp.host=localhost
|
||||
@@ -1,12 +0,0 @@
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'src'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':apps:ministreaming')
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- You may freely edit this file. See commented blocks below for -->
|
||||
<!-- some examples of how to customize the build. -->
|
||||
<!-- (If you delete it and reopen the project it will be recreated.) -->
|
||||
<!-- By default, only the Clean and Build commands use this build script. -->
|
||||
<!-- Commands such as Run, Debug, and Test only use this build script if -->
|
||||
<!-- the Compile on Save feature is turned off for the project. -->
|
||||
<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
|
||||
<!-- in the project's Project Properties dialog box.-->
|
||||
<project name="BOB" default="default" basedir=".">
|
||||
<description>Builds, tests, and runs the project BOB.</description>
|
||||
<import file="nbproject/build-impl.xml"/>
|
||||
<!--
|
||||
|
||||
There exist several targets which are by default empty and which can be
|
||||
used for execution of your tasks. These targets are usually executed
|
||||
before and after some main targets. They are:
|
||||
|
||||
-pre-init: called before initialization of project properties
|
||||
-post-init: called after initialization of project properties
|
||||
-pre-compile: called before javac compilation
|
||||
-post-compile: called after javac compilation
|
||||
-pre-compile-single: called before javac compilation of single file
|
||||
-post-compile-single: called after javac compilation of single file
|
||||
-pre-compile-test: called before javac compilation of JUnit tests
|
||||
-post-compile-test: called after javac compilation of JUnit tests
|
||||
-pre-compile-test-single: called before javac compilation of single JUnit test
|
||||
-post-compile-test-single: called after javac compilation of single JUunit test
|
||||
-pre-jar: called before JAR building
|
||||
-post-jar: called after JAR building
|
||||
-post-clean: called after cleaning build products
|
||||
|
||||
(Targets beginning with '-' are not intended to be called on their own.)
|
||||
|
||||
Example of inserting an obfuscator after compilation could look like this:
|
||||
|
||||
<target name="-post-compile">
|
||||
<obfuscate>
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
</obfuscate>
|
||||
</target>
|
||||
|
||||
For list of available properties check the imported
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
|
||||
Another way to customize the build is by overriding existing main targets.
|
||||
The targets of interest are:
|
||||
|
||||
-init-macrodef-javac: defines macro for javac compilation
|
||||
-init-macrodef-junit: defines macro for junit execution
|
||||
-init-macrodef-debug: defines macro for class debugging
|
||||
-init-macrodef-java: defines macro for class execution
|
||||
-do-jar-with-manifest: JAR building (if you are using a manifest)
|
||||
-do-jar-without-manifest: JAR building (if you are not using a manifest)
|
||||
run: execution of project
|
||||
-javadoc-build: Javadoc generation
|
||||
test-report: JUnit report generation
|
||||
|
||||
An example of overriding the target for project execution could look like this:
|
||||
|
||||
<target name="run" depends="BOB-impl.jar">
|
||||
<exec dir="bin" executable="launcher.exe">
|
||||
<arg file="${dist.jar}"/>
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
Notice that the overridden target depends on the jar target and not only on
|
||||
the compile target as the regular run target does. Again, for a list of available
|
||||
properties which you can use, check the target you are overriding in the
|
||||
nbproject/build-impl.xml file.
|
||||
|
||||
-->
|
||||
|
||||
<target depends="jar" description="Build BOB into a SINGLE JAR." name="onejar">
|
||||
<!-- Make needed working dirs -->
|
||||
<mkdir dir="${dist.dir}/lib" />
|
||||
<mkdir dir="${dist.dir}/classes" />
|
||||
|
||||
<!-- Copy jars -->
|
||||
<copy todir="${dist.dir}/lib" flatten="true" >
|
||||
<path>
|
||||
<pathelement path="${javac.classpath}" />
|
||||
</path>
|
||||
</copy>
|
||||
<copy todir="${dist.dir}/lib" file="../../build/jbigi.jar" />
|
||||
|
||||
<!-- Extract the classes inside the jar files -->
|
||||
<unjar dest="${dist.dir}/classes" >
|
||||
<fileset dir="${dist.dir}/lib" >
|
||||
<include name="**/*.jar" />
|
||||
</fileset>
|
||||
</unjar>
|
||||
|
||||
<!-- Recombine the classes into a new jar file -->
|
||||
<jar jarfile="${dist.dir}/lib/all-in-one.jar" >
|
||||
<fileset dir="${dist.dir}/classes" />
|
||||
</jar>
|
||||
|
||||
<!-- Clean up work area -->
|
||||
<delete dir="${dist.dir}/classes" followsymlinks="false" includeemptydirs="true"/>
|
||||
|
||||
<!-- Make the single jar file -->
|
||||
<jar jarfile="dist/BOB-one.jar" >
|
||||
<zipfileset src="${dist.jar}" excludes="META-INF/*" />
|
||||
<zipfileset src="${dist.dir}/lib/all-in-one.jar" excludes="**/META-INF/*" />
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.BOB.Main" />
|
||||
</manifest>
|
||||
</jar>
|
||||
|
||||
<!-- Clean up the fake jar file -->
|
||||
<delete file="${dist.dir}/lib/all-in-one.jar" />
|
||||
</target>
|
||||
</project>
|
||||
@@ -1,3 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
X-COMMENT: Main-Class will be added automatically by build
|
||||
|
||||
@@ -1,643 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
*** GENERATED FROM project.xml - DO NOT EDIT ***
|
||||
*** EDIT ../build.xml INSTEAD ***
|
||||
|
||||
For the purpose of easier reading the script
|
||||
is divided into following sections:
|
||||
|
||||
- initialization
|
||||
- compilation
|
||||
- jar
|
||||
- execution
|
||||
- debugging
|
||||
- javadoc
|
||||
- junit compilation
|
||||
- junit execution
|
||||
- junit debugging
|
||||
- applet
|
||||
- cleanup
|
||||
|
||||
-->
|
||||
<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="BOB-impl">
|
||||
<target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
|
||||
<!--
|
||||
======================
|
||||
INITIALIZATION SECTION
|
||||
======================
|
||||
-->
|
||||
<target name="-pre-init">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="-pre-init" name="-init-private">
|
||||
<property file="nbproject/private/config.properties"/>
|
||||
<property file="nbproject/private/configs/${config}.properties"/>
|
||||
<property file="nbproject/private/private.properties"/>
|
||||
</target>
|
||||
<target depends="-pre-init,-init-private" name="-init-user">
|
||||
<property file="${user.properties.file}"/>
|
||||
<!-- The two properties below are usually overridden -->
|
||||
<!-- by the active platform. Just a fallback. -->
|
||||
<property name="default.javac.source" value="1.8"/>
|
||||
<property name="default.javac.target" value="1.8"/>
|
||||
<property name="javac.release" value="8"/>
|
||||
</target>
|
||||
<target depends="-pre-init,-init-private,-init-user" name="-init-project">
|
||||
<property file="nbproject/configs/${config}.properties"/>
|
||||
<property file="nbproject/project.properties"/>
|
||||
</target>
|
||||
<target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
|
||||
<available file="${manifest.file}" property="manifest.available"/>
|
||||
<condition property="manifest.available+main.class">
|
||||
<and>
|
||||
<isset property="manifest.available"/>
|
||||
<isset property="main.class"/>
|
||||
<not>
|
||||
<equals arg1="${main.class}" arg2="" trim="true"/>
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="manifest.available+main.class+mkdist.available">
|
||||
<and>
|
||||
<istrue value="${manifest.available+main.class}"/>
|
||||
<isset property="libs.CopyLibs.classpath"/>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="have.tests">
|
||||
<or>
|
||||
<available file="${test.src.dir}"/>
|
||||
</or>
|
||||
</condition>
|
||||
<condition property="have.sources">
|
||||
<or>
|
||||
<available file="${src.dir}"/>
|
||||
</or>
|
||||
</condition>
|
||||
<condition property="netbeans.home+have.tests">
|
||||
<and>
|
||||
<isset property="netbeans.home"/>
|
||||
<isset property="have.tests"/>
|
||||
</and>
|
||||
</condition>
|
||||
<condition property="no.javadoc.preview">
|
||||
<and>
|
||||
<isset property="javadoc.preview"/>
|
||||
<isfalse value="${javadoc.preview}"/>
|
||||
</and>
|
||||
</condition>
|
||||
<property name="run.jvmargs" value=""/>
|
||||
<property name="javac.compilerargs" value=""/>
|
||||
<property name="work.dir" value="${basedir}"/>
|
||||
<condition property="no.deps">
|
||||
<and>
|
||||
<istrue value="${no.dependencies}"/>
|
||||
</and>
|
||||
</condition>
|
||||
<property name="javac.debug" value="true"/>
|
||||
<property name="javadoc.preview" value="true"/>
|
||||
<property name="application.args" value=""/>
|
||||
<property name="source.encoding" value="${file.encoding}"/>
|
||||
<condition property="javadoc.encoding.used" value="${javadoc.encoding}">
|
||||
<and>
|
||||
<isset property="javadoc.encoding"/>
|
||||
<not>
|
||||
<equals arg1="${javadoc.encoding}" arg2=""/>
|
||||
</not>
|
||||
</and>
|
||||
</condition>
|
||||
<property name="javadoc.encoding.used" value="${source.encoding}"/>
|
||||
<property name="includes" value="**"/>
|
||||
<property name="excludes" value=""/>
|
||||
<property name="do.depend" value="false"/>
|
||||
<condition property="do.depend.true">
|
||||
<istrue value="${do.depend}"/>
|
||||
</condition>
|
||||
<condition else="" property="javac.compilerargs.jaxws" value="-Djava.endorsed.dirs='${jaxws.endorsed.dir}'">
|
||||
<and>
|
||||
<isset property="jaxws.endorsed.dir"/>
|
||||
<available file="nbproject/jaxws-build.xml"/>
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
<target name="-post-init">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
|
||||
<fail unless="src.dir">Must set src.dir</fail>
|
||||
<fail unless="test.src.dir">Must set test.src.dir</fail>
|
||||
<fail unless="build.dir">Must set build.dir</fail>
|
||||
<fail unless="dist.dir">Must set dist.dir</fail>
|
||||
<fail unless="build.classes.dir">Must set build.classes.dir</fail>
|
||||
<fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
|
||||
<fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
|
||||
<fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
|
||||
<fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
|
||||
<fail unless="dist.jar">Must set dist.jar</fail>
|
||||
</target>
|
||||
<target name="-init-macrodef-property">
|
||||
<macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
|
||||
<attribute name="name"/>
|
||||
<attribute name="value"/>
|
||||
<sequential>
|
||||
<property name="@{name}" value="${@{value}}"/>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target name="-init-macrodef-javac">
|
||||
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${src.dir}" name="srcdir"/>
|
||||
<attribute default="${build.classes.dir}" name="destdir"/>
|
||||
<attribute default="${javac.classpath}" name="classpath"/>
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="${javac.debug}" name="debug"/>
|
||||
<attribute default="/does/not/exist" name="sourcepath"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" release="${javac.release}">
|
||||
<classpath>
|
||||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
<compilerarg line="${javac.compilerargs} ${javac.compilerargs.jaxws}"/>
|
||||
<customize/>
|
||||
</javac>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${src.dir}" name="srcdir"/>
|
||||
<attribute default="${build.classes.dir}" name="destdir"/>
|
||||
<attribute default="${javac.classpath}" name="classpath"/>
|
||||
<sequential>
|
||||
<depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
|
||||
<classpath>
|
||||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
</depend>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${build.classes.dir}" name="destdir"/>
|
||||
<sequential>
|
||||
<fail unless="javac.includes">Must set javac.includes</fail>
|
||||
<pathconvert pathsep="," property="javac.includes.binary">
|
||||
<path>
|
||||
<filelist dir="@{destdir}" files="${javac.includes}"/>
|
||||
</path>
|
||||
<globmapper from="*.java" to="*.class"/>
|
||||
</pathconvert>
|
||||
<delete>
|
||||
<files includes="${javac.includes.binary}"/>
|
||||
</delete>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target name="-init-macrodef-junit">
|
||||
<macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${includes}" name="includes"/>
|
||||
<attribute default="${excludes}" name="excludes"/>
|
||||
<attribute default="**" name="testincludes"/>
|
||||
<sequential>
|
||||
<junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" showoutput="true">
|
||||
<batchtest todir="${build.test.results.dir}">
|
||||
<fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
|
||||
<filename name="@{testincludes}"/>
|
||||
</fileset>
|
||||
</batchtest>
|
||||
<classpath>
|
||||
<path path="${run.test.classpath}"/>
|
||||
</classpath>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<formatter type="brief" usefile="false"/>
|
||||
<formatter type="xml"/>
|
||||
<jvmarg line="${run.jvmargs}"/>
|
||||
</junit>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target depends="-init-debug-args" name="-init-macrodef-nbjpda">
|
||||
<macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
|
||||
<attribute default="${main.class}" name="name"/>
|
||||
<attribute default="${debug.classpath}" name="classpath"/>
|
||||
<attribute default="" name="stopclassname"/>
|
||||
<sequential>
|
||||
<nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
|
||||
<classpath>
|
||||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
</nbjpdastart>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
<macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
|
||||
<attribute default="${build.classes.dir}" name="dir"/>
|
||||
<sequential>
|
||||
<nbjpdareload>
|
||||
<fileset dir="@{dir}" includes="${fix.classes}">
|
||||
<include name="${fix.includes}*.class"/>
|
||||
</fileset>
|
||||
</nbjpdareload>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target name="-init-debug-args">
|
||||
<property name="version-output" value="java version "${ant.java.version}"/>
|
||||
<condition property="have-jdk-older-than-1.4">
|
||||
<or>
|
||||
<contains string="${version-output}" substring="java version "1.0"/>
|
||||
<contains string="${version-output}" substring="java version "1.1"/>
|
||||
<contains string="${version-output}" substring="java version "1.2"/>
|
||||
<contains string="${version-output}" substring="java version "1.3"/>
|
||||
</or>
|
||||
</condition>
|
||||
<condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
|
||||
<istrue value="${have-jdk-older-than-1.4}"/>
|
||||
</condition>
|
||||
<condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
|
||||
<os family="windows"/>
|
||||
</condition>
|
||||
<condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
|
||||
<isset property="debug.transport"/>
|
||||
</condition>
|
||||
</target>
|
||||
<target depends="-init-debug-args" name="-init-macrodef-debug">
|
||||
<macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<attribute default="${main.class}" name="classname"/>
|
||||
<attribute default="${debug.classpath}" name="classpath"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<java classname="@{classname}" dir="${work.dir}" fork="true">
|
||||
<jvmarg line="${debug-args-line}"/>
|
||||
<jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
|
||||
<jvmarg line="${run.jvmargs}"/>
|
||||
<classpath>
|
||||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="run-sys-prop."/>
|
||||
<mapper from="run-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<customize/>
|
||||
</java>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target name="-init-macrodef-java">
|
||||
<macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
|
||||
<attribute default="${main.class}" name="classname"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<java classname="@{classname}" dir="${work.dir}" fork="true">
|
||||
<jvmarg line="${run.jvmargs}"/>
|
||||
<classpath>
|
||||
<path path="${run.classpath}"/>
|
||||
</classpath>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="run-sys-prop."/>
|
||||
<mapper from="run-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<customize/>
|
||||
</java>
|
||||
</sequential>
|
||||
</macrodef>
|
||||
</target>
|
||||
<target name="-init-presetdef-jar">
|
||||
<presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
|
||||
<jar compress="${jar.compress}" jarfile="${dist.jar}">
|
||||
<j2seproject1:fileset dir="${build.classes.dir}"/>
|
||||
</jar>
|
||||
</presetdef>
|
||||
</target>
|
||||
<target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-junit,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar" name="init"/>
|
||||
<!--
|
||||
===================
|
||||
COMPILATION SECTION
|
||||
===================
|
||||
-->
|
||||
<target depends="init" name="deps-jar" unless="no.deps"/>
|
||||
<target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
|
||||
<target depends="init" name="-check-automatic-build">
|
||||
<available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
|
||||
</target>
|
||||
<target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
|
||||
<antcall target="clean"/>
|
||||
</target>
|
||||
<target depends="init,deps-jar" name="-pre-pre-compile">
|
||||
<mkdir dir="${build.classes.dir}"/>
|
||||
</target>
|
||||
<target name="-pre-compile">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target if="do.depend.true" name="-compile-depend">
|
||||
<j2seproject3:depend/>
|
||||
</target>
|
||||
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile,-compile-depend" if="have.sources" name="-do-compile">
|
||||
<j2seproject3:javac/>
|
||||
<copy todir="${build.classes.dir}">
|
||||
<fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||
</copy>
|
||||
</target>
|
||||
<target name="-post-compile">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
|
||||
<target name="-pre-compile-single">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
|
||||
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
|
||||
<j2seproject3:force-recompile/>
|
||||
<j2seproject3:javac excludes="" includes="${javac.includes}" sourcepath="${src.dir}"/>
|
||||
</target>
|
||||
<target name="-post-compile-single">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
|
||||
<!--
|
||||
====================
|
||||
JAR BUILDING SECTION
|
||||
====================
|
||||
-->
|
||||
<target depends="init" name="-pre-pre-jar">
|
||||
<dirname file="${dist.jar}" property="dist.jar.dir"/>
|
||||
<mkdir dir="${dist.jar.dir}"/>
|
||||
</target>
|
||||
<target name="-pre-jar">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar" name="-do-jar-without-manifest" unless="manifest.available">
|
||||
<j2seproject1:jar/>
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class">
|
||||
<j2seproject1:jar manifest="${manifest.file}"/>
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
|
||||
<j2seproject1:jar manifest="${manifest.file}">
|
||||
<j2seproject1:manifest>
|
||||
<j2seproject1:attribute name="Main-Class" value="${main.class}"/>
|
||||
</j2seproject1:manifest>
|
||||
</j2seproject1:jar>
|
||||
<echo>To run this application from the command line without Ant, try:</echo>
|
||||
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
|
||||
<property location="${dist.jar}" name="dist.jar.resolved"/>
|
||||
<pathconvert property="run.classpath.with.dist.jar">
|
||||
<path path="${run.classpath}"/>
|
||||
<map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
|
||||
</pathconvert>
|
||||
<echo>java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-jar,-pre-jar" if="manifest.available+main.class+mkdist.available" name="-do-jar-with-libraries">
|
||||
<property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
|
||||
<pathconvert property="run.classpath.without.build.classes.dir">
|
||||
<path path="${run.classpath}"/>
|
||||
<map from="${build.classes.dir.resolved}" to=""/>
|
||||
</pathconvert>
|
||||
<pathconvert pathsep=" " property="jar.classpath">
|
||||
<path path="${run.classpath.without.build.classes.dir}"/>
|
||||
<chainedmapper>
|
||||
<flattenmapper/>
|
||||
<globmapper from="*" to="lib/*"/>
|
||||
</chainedmapper>
|
||||
</pathconvert>
|
||||
<taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
|
||||
<copylibs compress="${jar.compress}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
|
||||
<fileset dir="${build.classes.dir}"/>
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="${main.class}"/>
|
||||
<attribute name="Class-Path" value="${jar.classpath}"/>
|
||||
</manifest>
|
||||
</copylibs>
|
||||
<echo>To run this application from the command line without Ant, try:</echo>
|
||||
<property location="${dist.jar}" name="dist.jar.resolved"/>
|
||||
<echo>java -jar "${dist.jar.resolved}"</echo>
|
||||
</target>
|
||||
<target name="-post-jar">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
|
||||
<!--
|
||||
=================
|
||||
EXECUTION SECTION
|
||||
=================
|
||||
-->
|
||||
<target depends="init,compile" description="Run a main class." name="run">
|
||||
<j2seproject1:java>
|
||||
<customize>
|
||||
<arg line="${application.args}"/>
|
||||
</customize>
|
||||
</j2seproject1:java>
|
||||
</target>
|
||||
<target name="-do-not-recompile">
|
||||
<property name="javac.includes.binary" value=""/>
|
||||
</target>
|
||||
<target depends="init,-do-not-recompile,compile-single" name="run-single">
|
||||
<fail unless="run.class">Must select one file in the IDE or set run.class</fail>
|
||||
<j2seproject1:java classname="${run.class}"/>
|
||||
</target>
|
||||
<!--
|
||||
=================
|
||||
DEBUGGING SECTION
|
||||
=================
|
||||
-->
|
||||
<target depends="init" if="netbeans.home" name="-debug-start-debugger">
|
||||
<j2seproject1:nbjpdastart name="${debug.class}"/>
|
||||
</target>
|
||||
<target depends="init,compile" name="-debug-start-debuggee">
|
||||
<j2seproject3:debug>
|
||||
<customize>
|
||||
<arg line="${application.args}"/>
|
||||
</customize>
|
||||
</j2seproject3:debug>
|
||||
</target>
|
||||
<target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
|
||||
<target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
|
||||
<j2seproject1:nbjpdastart stopclassname="${main.class}"/>
|
||||
</target>
|
||||
<target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
|
||||
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
|
||||
<fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
|
||||
<j2seproject3:debug classname="${debug.class}"/>
|
||||
</target>
|
||||
<target depends="init,-do-not-recompile,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
|
||||
<target depends="init" name="-pre-debug-fix">
|
||||
<fail unless="fix.includes">Must set fix.includes</fail>
|
||||
<property name="javac.includes" value="${fix.includes}.java"/>
|
||||
</target>
|
||||
<target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
|
||||
<j2seproject1:nbjpdareload/>
|
||||
</target>
|
||||
<target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
|
||||
<!--
|
||||
===============
|
||||
JAVADOC SECTION
|
||||
===============
|
||||
-->
|
||||
<target depends="init" name="-javadoc-build">
|
||||
<mkdir dir="${dist.javadoc.dir}"/>
|
||||
<javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
|
||||
<classpath>
|
||||
<path path="${javac.classpath}"/>
|
||||
</classpath>
|
||||
<fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
|
||||
<filename name="**/*.java"/>
|
||||
</fileset>
|
||||
</javadoc>
|
||||
</target>
|
||||
<target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
|
||||
<nbbrowse file="${dist.javadoc.dir}/index.html"/>
|
||||
</target>
|
||||
<target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
|
||||
<!--
|
||||
=========================
|
||||
JUNIT COMPILATION SECTION
|
||||
=========================
|
||||
-->
|
||||
<target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
|
||||
<mkdir dir="${build.test.classes.dir}"/>
|
||||
</target>
|
||||
<target name="-pre-compile-test">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target if="do.depend.true" name="-compile-test-depend">
|
||||
<j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
|
||||
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
|
||||
<copy todir="${build.test.classes.dir}">
|
||||
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||
</copy>
|
||||
</target>
|
||||
<target name="-post-compile-test">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
|
||||
<target name="-pre-compile-test-single">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
|
||||
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
|
||||
<j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
|
||||
<j2seproject3:javac classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
|
||||
<copy todir="${build.test.classes.dir}">
|
||||
<fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||
</copy>
|
||||
</target>
|
||||
<target name="-post-compile-test-single">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
|
||||
<!--
|
||||
=======================
|
||||
JUNIT EXECUTION SECTION
|
||||
=======================
|
||||
-->
|
||||
<target depends="init" if="have.tests" name="-pre-test-run">
|
||||
<mkdir dir="${build.test.results.dir}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
|
||||
<j2seproject3:junit testincludes="**/*Test.java"/>
|
||||
</target>
|
||||
<target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
|
||||
<fail if="tests.failed">Some tests failed; see details above.</fail>
|
||||
</target>
|
||||
<target depends="init" if="have.tests" name="test-report"/>
|
||||
<target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
|
||||
<target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
|
||||
<target depends="init" if="have.tests" name="-pre-test-run-single">
|
||||
<mkdir dir="${build.test.results.dir}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
|
||||
<fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
|
||||
<j2seproject3:junit excludes="" includes="${test.includes}"/>
|
||||
</target>
|
||||
<target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
|
||||
<fail if="tests.failed">Some tests failed; see details above.</fail>
|
||||
</target>
|
||||
<target depends="init,-do-not-recompile,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
|
||||
<!--
|
||||
=======================
|
||||
JUNIT DEBUGGING SECTION
|
||||
=======================
|
||||
-->
|
||||
<target depends="init,compile-test" if="have.tests" name="-debug-start-debuggee-test">
|
||||
<fail unless="test.class">Must select one file in the IDE or set test.class</fail>
|
||||
<property location="${build.test.results.dir}/TEST-${test.class}.xml" name="test.report.file"/>
|
||||
<delete file="${test.report.file}"/>
|
||||
<mkdir dir="${build.test.results.dir}"/>
|
||||
<j2seproject3:debug classname="org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner" classpath="${ant.home}/lib/ant.jar:${ant.home}/lib/ant-junit.jar:${debug.test.classpath}">
|
||||
<customize>
|
||||
<syspropertyset>
|
||||
<propertyref prefix="test-sys-prop."/>
|
||||
<mapper from="test-sys-prop.*" to="*" type="glob"/>
|
||||
</syspropertyset>
|
||||
<arg value="${test.class}"/>
|
||||
<arg value="showoutput=true"/>
|
||||
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.BriefJUnitResultFormatter"/>
|
||||
<arg value="formatter=org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter,${test.report.file}"/>
|
||||
</customize>
|
||||
</j2seproject3:debug>
|
||||
</target>
|
||||
<target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
|
||||
<j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
|
||||
</target>
|
||||
<target depends="init,-do-not-recompile,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
|
||||
<target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
|
||||
<j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
|
||||
</target>
|
||||
<target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
|
||||
<!--
|
||||
=========================
|
||||
APPLET EXECUTION SECTION
|
||||
=========================
|
||||
-->
|
||||
<target depends="init,compile-single" name="run-applet">
|
||||
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
|
||||
<j2seproject1:java classname="sun.applet.AppletViewer">
|
||||
<customize>
|
||||
<arg value="${applet.url}"/>
|
||||
</customize>
|
||||
</j2seproject1:java>
|
||||
</target>
|
||||
<!--
|
||||
=========================
|
||||
APPLET DEBUGGING SECTION
|
||||
=========================
|
||||
-->
|
||||
<target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
|
||||
<fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
|
||||
<j2seproject3:debug classname="sun.applet.AppletViewer">
|
||||
<customize>
|
||||
<arg value="${applet.url}"/>
|
||||
</customize>
|
||||
</j2seproject3:debug>
|
||||
</target>
|
||||
<target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
|
||||
<!--
|
||||
===============
|
||||
CLEANUP SECTION
|
||||
===============
|
||||
-->
|
||||
<target depends="init" name="deps-clean" unless="no.deps"/>
|
||||
<target depends="init" name="-do-clean">
|
||||
<delete dir="${build.dir}"/>
|
||||
<delete dir="${dist.dir}"/>
|
||||
</target>
|
||||
<target name="-post-clean">
|
||||
<!-- Empty placeholder for easier customization. -->
|
||||
<!-- You can override this target in the ../build.xml file. -->
|
||||
</target>
|
||||
<target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
|
||||
</project>
|
||||
@@ -1,8 +0,0 @@
|
||||
build.xml.data.CRC32=209349b6
|
||||
build.xml.script.CRC32=403e69e6
|
||||
build.xml.stylesheet.CRC32=958a1d3e
|
||||
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
|
||||
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
|
||||
nbproject/build-impl.xml.data.CRC32=209349b6
|
||||
nbproject/build-impl.xml.script.CRC32=c51e188e
|
||||
nbproject/build-impl.xml.stylesheet.CRC32=65b8de21
|
||||
@@ -1,84 +0,0 @@
|
||||
application.homepage=http://bob.i2p/
|
||||
application.title=BOB
|
||||
application.vendor=Sponge
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.expand-tabs=false
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.indent-shift-width=8
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.spaces-per-tab=8
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.tab-size=8
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.project.text-limit-width=80
|
||||
auxiliary.org-netbeans-modules-editor-indent.CodeStyle.usedProfile=project
|
||||
build.classes.dir=${build.dir}/classes
|
||||
build.classes.excludes=**/*.java,**/*.form
|
||||
# This directory is removed when the project is cleaned:
|
||||
build.dir=build
|
||||
build.generated.dir=${build.dir}/generated
|
||||
build.generated.sources.dir=${build.dir}/generated-sources
|
||||
# Only compile against the classpath explicitly listed here:
|
||||
build.sysclasspath=ignore
|
||||
build.test.classes.dir=${build.dir}/test/classes
|
||||
build.test.results.dir=${build.dir}/test/results
|
||||
debug.classpath=\
|
||||
${run.classpath}
|
||||
debug.test.classpath=\
|
||||
${run.test.classpath}
|
||||
# This directory is removed when the project is cleaned:
|
||||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/BOB.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=**/*.html,**/*.txt
|
||||
file.reference.build-javadoc=../../i2p.i2p/build/javadoc
|
||||
file.reference.i2p.jar=../../core/java/build/i2p.jar
|
||||
file.reference.mstreaming.jar=../ministreaming/java/build/mstreaming.jar
|
||||
includes=**
|
||||
jar.compress=true
|
||||
javac.classpath=\
|
||||
${file.reference.mstreaming.jar}:\
|
||||
${file.reference.i2p.jar}
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
javac.version=1.8
|
||||
javac.source=${javac.version}
|
||||
javac.target=${javac.version}
|
||||
javac.release=8
|
||||
javac.test.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}:\
|
||||
${libs.junit.classpath}:\
|
||||
${libs.junit_4.classpath}
|
||||
javadoc.additionalparam=
|
||||
javadoc.author=false
|
||||
javadoc.encoding=${source.encoding}
|
||||
javadoc.noindex=false
|
||||
javadoc.nonavbar=false
|
||||
javadoc.notree=false
|
||||
javadoc.private=false
|
||||
javadoc.splitindex=true
|
||||
javadoc.use=true
|
||||
javadoc.version=false
|
||||
javadoc.windowtitle=
|
||||
jaxbwiz.endorsed.dirs="${netbeans.home}/../ide12/modules/ext/jaxb/api"
|
||||
jnlp.codebase.type=local
|
||||
jnlp.codebase.url=file:/usblv/NetBeansProjects/i2p.i2p/apps/BOB/dist
|
||||
jnlp.descriptor=application
|
||||
jnlp.enabled=false
|
||||
jnlp.offline-allowed=false
|
||||
jnlp.signed=false
|
||||
main.class=net.i2p.BOB.Main
|
||||
manifest.file=manifest.mf
|
||||
meta.inf.dir=${src.dir}/META-INF
|
||||
platform.active=default_platform
|
||||
run.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}
|
||||
# Space-separated list of JVM arguments used when running the project
|
||||
# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value
|
||||
# or test-sys-prop.name=value to set system properties for unit tests):
|
||||
run.jvmargs=
|
||||
run.test.classpath=\
|
||||
${javac.test.classpath}:\
|
||||
${build.test.classes.dir}
|
||||
source.encoding=UTF-8
|
||||
src.dir=src
|
||||
test.src.dir=test
|
||||
@@ -1,16 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.java.j2seproject</type>
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>BOB</name>
|
||||
<minimum-ant-version>1.9.8</minimum-ant-version>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
<test-roots>
|
||||
<root id="test.src.dir"/>
|
||||
</test-roots>
|
||||
</data>
|
||||
</configuration>
|
||||
</project>
|
||||
@@ -1,542 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import static net.i2p.app.ClientAppState.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URL;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.*;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.PortMapper;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
/**
|
||||
* <span style="font-size:8px;font-family:courier;color:#EEEEEE;background-color:#000000">
|
||||
* ################################################################################<br>
|
||||
* ############################.#..........#..#..........##########################<br>
|
||||
* #######################......................................###################<br>
|
||||
* ####################...........................#.......#........################<br>
|
||||
* #################..................##...................#.........##############<br>
|
||||
* ###############................###...####.....#..###.....#.........#############<br>
|
||||
* #############...........###..#..###...#####...###.##........#.......############<br>
|
||||
* ###########................#......##...#####...##..##.......#..#........########<br>
|
||||
* ##########.........................#....##.##..#...##.....................######<br>
|
||||
* #########...................................#....#.........................#####<br>
|
||||
* ########.........................................#...............#..........####<br>
|
||||
* ########.........................................#..........#######..........###<br>
|
||||
* #######.................................................############..........##<br>
|
||||
* #######..........................................####################.........##<br>
|
||||
* #######............####################......########################.........##<br>
|
||||
* ######.............###############################################.##.........##<br>
|
||||
* ######............################################################..##........##<br>
|
||||
* ######............################################################..##........##<br>
|
||||
* ######.............##############################################..##.........##<br>
|
||||
* ######............##############################################...##..........#<br>
|
||||
* ######............#..###########################################...##..........#<br>
|
||||
* ######.............#############################################....#..........#<br>
|
||||
* #######...........###############################################..##.........##<br>
|
||||
* #######...........#####.#.#.#.########################.....#.####...##........##<br>
|
||||
* ######............#..............##################.................##.........#<br>
|
||||
* ######................####.........###############........#####......##........#<br>
|
||||
* ######..............####..#.........############.......##.#.######...##.......##<br>
|
||||
* ######.................#.####.........########...........##....###...##.......##<br>
|
||||
* #######....#....###...................#######...............#...###..##.......##<br>
|
||||
* #######.........###..###.....###.......######.##.#####.........####..##.......##<br>
|
||||
* #######.....#...##############.........############......###########.###......##<br>
|
||||
* #######....##...##########.......##...##############......#.############.....###<br>
|
||||
* ########....#..########......######...##################################....####<br>
|
||||
* ########....##.####################...##################################....####<br>
|
||||
* ########..#.##..###################..##################################..#..####<br>
|
||||
* ##########..###..#################...##################################...#.####<br>
|
||||
* #########....##...##############....########..#####.################.##..#.#####<br>
|
||||
* ############.##....##########.......#########.###.......###########..#.#########<br>
|
||||
* ###############.....#######...#.......########.....##.....######.....###########<br>
|
||||
* ###############......###....##..........##.......######....#.........#.#########<br>
|
||||
* ##############............##..................##########..............##########<br>
|
||||
* ##############..............................##########..#.............##########<br>
|
||||
* ###############.......##..................#####..............####....###########<br>
|
||||
* ###############.......#####.......#.............####.....#######.....###########<br>
|
||||
* ################...#...####......##################.....########....############<br>
|
||||
* ################...##..#####.........####.##.....#....##########....############<br>
|
||||
* ##################..##..####...........#####.#....############.....#############<br>
|
||||
* ##################......#####.................################....##############<br>
|
||||
* ###################.....####..........##########..###########....###############<br>
|
||||
* ####################..#..#..........................########.....###############<br>
|
||||
* #####################.##.......###.................########....#################<br>
|
||||
* ######################.........#.......#.##.###############....#################<br>
|
||||
* #############.#######...............#####################....###################<br>
|
||||
* ###..#.....##...####..........#.....####################....####################<br>
|
||||
* ####......##........................##################....######################<br>
|
||||
* #.##...###..............###.........###############......#######################<br>
|
||||
* #...###..##............######...........................########################<br>
|
||||
* ##.......###..........##########....#...#...........############################<br>
|
||||
* ##.........##.......############################################################<br>
|
||||
* ###........##.....##############################################################<br>
|
||||
* ####.............###############################################################<br>
|
||||
* ######.........#################################################################<br>
|
||||
* #########....###################################################################<br>
|
||||
* ################################################################################<br>
|
||||
* </span>
|
||||
* BOB, main command socket listener, launches the command parser engine.
|
||||
*
|
||||
* @author sponge
|
||||
* @deprecated Please port applications to SAMv3
|
||||
*/
|
||||
@Deprecated
|
||||
public class BOB implements Runnable, ClientApp {
|
||||
|
||||
public final static String PROP_CONFIG_LOCATION = "BOB.config";
|
||||
public final static String PROP_BOB_PORT = "BOB.port";
|
||||
public final static String PROP_BOB_HOST = "BOB.host";
|
||||
public final static String PROP_CFG_VER = "BOB.CFG.VER";
|
||||
|
||||
/** unused when started via the ClientApp interface */
|
||||
private static BOB _bob;
|
||||
|
||||
private final NamedDB database;
|
||||
private final Properties props = new Properties();
|
||||
private final AtomicBoolean spin = new AtomicBoolean(true);
|
||||
private static final String P_RUNNING = "RUNNING";
|
||||
private static final String P_STARTING = "STARTING";
|
||||
private static final String P_STOPPING = "STOPPING";
|
||||
private final AtomicBoolean lock = new AtomicBoolean(false);
|
||||
// no longer used.
|
||||
// private static int maxConnections = 0;
|
||||
|
||||
private final I2PAppContext _context;
|
||||
private final Logger _log;
|
||||
private final ClientAppManager _mgr;
|
||||
private final String[] _args;
|
||||
private volatile ClientAppState _state = UNINITIALIZED;
|
||||
|
||||
private volatile ServerSocket listener;
|
||||
private volatile Thread _runner;
|
||||
private volatile boolean _warned;
|
||||
|
||||
/**
|
||||
* Stop BOB gracefully
|
||||
* @deprecated unused
|
||||
*/
|
||||
@Deprecated
|
||||
public synchronized static void stop() {
|
||||
if (_bob != null)
|
||||
_bob.shutdown(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* For ClientApp interface.
|
||||
* Does NOT open the listener socket or start threads; caller must call startup()
|
||||
*
|
||||
* @param mgr may be null
|
||||
* @param args non-null
|
||||
* @since 0.9.10
|
||||
*/
|
||||
public BOB(I2PAppContext context, ClientAppManager mgr, String[] args) {
|
||||
_context = context;
|
||||
// If we were run from command line, log to stdout
|
||||
boolean logToStdout = false;
|
||||
URL classResource = BOB.class.getResource("BOB.class");
|
||||
if (classResource != null) {
|
||||
String classPath = classResource.toString();
|
||||
if (classPath.startsWith("jar")) {
|
||||
String manifestPath = classPath.substring(0, classPath.lastIndexOf('!') + 1) +
|
||||
"/META-INF/MANIFEST.MF";
|
||||
try {
|
||||
Manifest manifest = new Manifest(new URL(manifestPath).openStream());
|
||||
Attributes attrs = manifest.getMainAttributes();
|
||||
String mainClass = attrs.getValue("Main-Class");
|
||||
if ("net.i2p.BOB.Main".equals(mainClass))
|
||||
logToStdout = true;
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
_log = new Logger(context.logManager().getLog(BOB.class), logToStdout);
|
||||
|
||||
_mgr = mgr;
|
||||
_args = args;
|
||||
_state = INITIALIZED;
|
||||
database = new NamedDB();
|
||||
loadConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for incoming connections and handle them
|
||||
*
|
||||
* @param args
|
||||
*/
|
||||
public synchronized static void main(String[] args) {
|
||||
try {
|
||||
_bob = new BOB(I2PAppContext.getGlobalContext(), null, args);
|
||||
_bob.startup();
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void loadConfig() {
|
||||
int i = 0;
|
||||
boolean save = false;
|
||||
// Set up all defaults to be passed forward to other threads.
|
||||
// Re-reading the config file in each thread is pretty damn stupid.
|
||||
String configLocation = System.getProperty(PROP_CONFIG_LOCATION, "bob.config");
|
||||
// This is here just to ensure there is no interference with our threadgroups.
|
||||
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
|
||||
i = Y2.hashCode();
|
||||
{
|
||||
File cfg = new File(configLocation);
|
||||
if (!cfg.isAbsolute()) {
|
||||
cfg = new File(_context.getConfigDir(), configLocation);
|
||||
}
|
||||
FileInputStream fi = null;
|
||||
try {
|
||||
fi = new FileInputStream(cfg);
|
||||
props.load(fi);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
_log.warn("Unable to load up the BOB config file " + cfg.getAbsolutePath() + ", Using defaults.", fnfe);
|
||||
save = true;
|
||||
} catch (IOException ioe) {
|
||||
_log.warn("IOException on BOB config file " + cfg.getAbsolutePath() + ", using defaults.", ioe);
|
||||
} finally {
|
||||
if (fi != null) try { fi.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
// Global router and client API configurations that are missing are set to defaults here.
|
||||
if (!props.containsKey(I2PClient.PROP_TCP_HOST)) {
|
||||
props.setProperty(I2PClient.PROP_TCP_HOST, "localhost");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(I2PClient.PROP_TCP_PORT)) {
|
||||
props.setProperty(I2PClient.PROP_TCP_PORT, Integer.toString(I2PClient.DEFAULT_LISTEN_PORT));
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(PROP_BOB_PORT)) {
|
||||
props.setProperty(PROP_BOB_PORT, "2827"); // 0xB0B
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("inbound.length")) {
|
||||
props.setProperty("inbound.length", "3");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("outbound.length")) {
|
||||
props.setProperty("outbound.length", "3");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("inbound.lengthVariance")) {
|
||||
props.setProperty("inbound.lengthVariance", "0");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey("outbound.lengthVariance")) {
|
||||
props.setProperty("outbound.lengthVariance", "0");
|
||||
save = true;
|
||||
}
|
||||
if (!props.containsKey(PROP_BOB_HOST)) {
|
||||
props.setProperty(PROP_BOB_HOST, "localhost");
|
||||
save = true;
|
||||
}
|
||||
// PROP_RELIABILITY_NONE, PROP_RELIABILITY_BEST_EFFORT, PROP_RELIABILITY_GUARANTEED
|
||||
if (!props.containsKey(PROP_CFG_VER)) {
|
||||
props.setProperty(I2PClient.PROP_RELIABILITY, I2PClient.PROP_RELIABILITY_NONE);
|
||||
props.setProperty(PROP_CFG_VER,"1");
|
||||
save = true;
|
||||
}
|
||||
if (save) {
|
||||
File cfg = new File(configLocation);
|
||||
if (!cfg.isAbsolute()) {
|
||||
cfg = new File(_context.getConfigDir(), configLocation);
|
||||
}
|
||||
FileOutputStream fo = null;
|
||||
try {
|
||||
_log.warn("Writing new defaults file " + cfg.getAbsolutePath());
|
||||
fo = new FileOutputStream(cfg);
|
||||
props.store(fo, cfg.getAbsolutePath());
|
||||
} catch (IOException ioe) {
|
||||
_log.error("IOException on BOB config file " + cfg.getAbsolutePath(), ioe);
|
||||
} finally {
|
||||
if (fo != null) try { fo.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void startListener() throws IOException {
|
||||
listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST)));
|
||||
listener.setSoTimeout(500); // .5 sec
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void startThread() {
|
||||
I2PAppThread t = new I2PAppThread(this, "BOBListener");
|
||||
t.start();
|
||||
_runner = t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
public void run() {
|
||||
if (listener == null) return;
|
||||
changeState(RUNNING);
|
||||
_log.info("BOB is now running.");
|
||||
if (_mgr != null)
|
||||
_mgr.register(this);
|
||||
_context.portMapper().register(PortMapper.SVC_BOB, props.getProperty(PROP_BOB_HOST),
|
||||
Integer.parseInt(props.getProperty(PROP_BOB_PORT)));
|
||||
|
||||
int i = 0;
|
||||
boolean g = false;
|
||||
spin.set(true);
|
||||
try {
|
||||
Socket server = null;
|
||||
|
||||
while (spin.get()) {
|
||||
//DoCMDS connection;
|
||||
|
||||
try {
|
||||
server = listener.accept();
|
||||
server.setKeepAlive(true);
|
||||
g = true;
|
||||
} catch (ConnectException ce) {
|
||||
g = false;
|
||||
} catch (SocketTimeoutException ste) {
|
||||
g = false;
|
||||
}
|
||||
|
||||
if (g) {
|
||||
if (!_warned) {
|
||||
_warned = true;
|
||||
String s = "BOB is deprecated. Please port applications to SAMv3.";
|
||||
_context.logManager().getLog(BOB.class).logAlways(Log.WARN, s);
|
||||
_log.warn(s);
|
||||
}
|
||||
DoCMDS conn_c = new DoCMDS(spin, lock, server, props, database, _log);
|
||||
Thread t = new I2PAppThread(conn_c);
|
||||
t.setName("BOB.DoCMDS " + i);
|
||||
t.start();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
changeState(STOPPING);
|
||||
} catch (Exception e) {
|
||||
if (spin.get())
|
||||
_log.error("Unexpected error while listening for connections", e);
|
||||
else
|
||||
e = null;
|
||||
changeState(STOPPING, e);
|
||||
} finally {
|
||||
_log.info("BOB is now shutting down...");
|
||||
_context.portMapper().unregister(PortMapper.SVC_BOB);
|
||||
// Clean up everything.
|
||||
try {
|
||||
listener.close();
|
||||
} catch (Exception ex) {
|
||||
// nop
|
||||
}
|
||||
// Find all our "BOB.DoCMDS" threads, wait for them to be finished.
|
||||
// We could order them to stop, but that could cause nasty issues in the locks.
|
||||
visitAllThreads();
|
||||
database.getReadLock();
|
||||
NamedDB nickinfo;
|
||||
try {
|
||||
for (Object ndb : database.values()) {
|
||||
nickinfo = (NamedDB) ndb;
|
||||
nickinfo.getReadLock();
|
||||
boolean released = false;
|
||||
try {
|
||||
if (nickinfo.get(P_RUNNING).equals(Boolean.TRUE) && nickinfo.get(P_STOPPING).equals(Boolean.FALSE) && nickinfo.get(P_STARTING).equals(Boolean.FALSE)) {
|
||||
nickinfo.releaseReadLock();
|
||||
released = true;
|
||||
nickinfo.getWriteLock();
|
||||
try {
|
||||
nickinfo.add(P_STOPPING, Boolean.TRUE);
|
||||
} finally {
|
||||
nickinfo.releaseWriteLock();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (!released)
|
||||
nickinfo.releaseReadLock();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
database.releaseReadLock();
|
||||
}
|
||||
changeState(STOPPED);
|
||||
_log.info("BOB is now stopped.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the root thread group,
|
||||
* then find all theads with certain names and wait for them all to be dead.
|
||||
*
|
||||
*/
|
||||
private static void visitAllThreads() {
|
||||
ThreadGroup root = Thread.currentThread().getThreadGroup().getParent();
|
||||
while (root.getParent() != null) {
|
||||
root = root.getParent();
|
||||
}
|
||||
|
||||
// Visit each thread group
|
||||
waitjoin(root, 0, root.getName());
|
||||
}
|
||||
|
||||
private static void waitjoin(ThreadGroup group, int level, String tn) {
|
||||
// Get threads in `group'
|
||||
int numThreads = group.activeCount();
|
||||
Thread[] threads = new Thread[numThreads * 2];
|
||||
numThreads = group.enumerate(threads, false);
|
||||
// Enumerate each thread in `group' and wait for it to stop if it is one of ours.
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
// Get thread
|
||||
Thread thread = threads[i];
|
||||
if (thread.getName().startsWith("BOB.DoCMDS ")) {
|
||||
try {
|
||||
if (thread.isAlive()) {
|
||||
try {
|
||||
thread.join();
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
}
|
||||
} catch (SecurityException se) {
|
||||
//nop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get thread subgroups of `group'
|
||||
int numGroups = group.activeGroupCount();
|
||||
ThreadGroup[] groups = new ThreadGroup[numGroups * 2];
|
||||
numGroups = group.enumerate(groups, false);
|
||||
|
||||
// Recursively visit each subgroup
|
||||
for (int i = 0; i < numGroups; i++) {
|
||||
waitjoin(groups[i], level + 1, groups[i].getName());
|
||||
}
|
||||
}
|
||||
|
||||
////// begin ClientApp interface
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public void startup() throws IOException {
|
||||
if (_state != INITIALIZED)
|
||||
return;
|
||||
changeState(STARTING);
|
||||
try {
|
||||
startListener();
|
||||
} catch (IOException e) {
|
||||
_log.error("Error starting BOB on"
|
||||
+ props.getProperty(PROP_BOB_HOST)
|
||||
+ ":" + props.getProperty(PROP_BOB_PORT), e);
|
||||
changeState(START_FAILED, e);
|
||||
throw e;
|
||||
}
|
||||
startThread();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public void shutdown(String[] args) {
|
||||
if (_state != RUNNING)
|
||||
return;
|
||||
changeState(STOPPING);
|
||||
spin.set(false);
|
||||
if (_runner != null)
|
||||
_runner.interrupt();
|
||||
else
|
||||
changeState(STOPPED);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public ClientAppState getState() {
|
||||
return _state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return "BOB";
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
@Override
|
||||
public String getDisplayName() {
|
||||
return "BOB " + Arrays.toString(_args);
|
||||
}
|
||||
|
||||
////// end ClientApp interface
|
||||
////// begin ClientApp helpers
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private void changeState(ClientAppState state) {
|
||||
changeState(state, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.10
|
||||
*/
|
||||
private synchronized void changeState(ClientAppState state, Exception e) {
|
||||
_state = state;
|
||||
if (_mgr != null)
|
||||
_mgr.notify(this, state, null, e);
|
||||
}
|
||||
|
||||
////// end ClientApp helpers
|
||||
}
|
||||
@@ -1,996 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintStream;
|
||||
import java.net.Socket;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClientFactory;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
|
||||
// needed only for debugging.
|
||||
// import java.util.logging.Level;
|
||||
// import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Simplistic command parser for BOB
|
||||
*
|
||||
* @author sponge
|
||||
*
|
||||
*/
|
||||
public class DoCMDS implements Runnable {
|
||||
|
||||
// FIX ME
|
||||
// I need a better way to do versioning, but this will do for now.
|
||||
public static final String BMAJ = "00", BMIN = "00", BREV = "10", BEXT = "";
|
||||
public static final String BOBversion = BMAJ + "." + BMIN + "." + BREV + BEXT;
|
||||
private final Socket server;
|
||||
private final Properties props;
|
||||
private final NamedDB database;
|
||||
private String line;
|
||||
private Destination d;
|
||||
private ByteArrayOutputStream prikey;
|
||||
private boolean dk, ns, ip, op;
|
||||
private NamedDB nickinfo;
|
||||
private final Logger _log;
|
||||
private final AtomicBoolean LIVE;
|
||||
private final AtomicBoolean lock;
|
||||
/* database strings */
|
||||
private static final String P_DEST = "DESTINATION";
|
||||
private static final String P_INHOST = "INHOST";
|
||||
private static final String P_INPORT = "INPORT";
|
||||
private static final String P_KEYS = "KEYS";
|
||||
private static final String P_NICKNAME = "NICKNAME";
|
||||
private static final String P_OUTHOST = "OUTHOST";
|
||||
private static final String P_OUTPORT = "OUTPORT";
|
||||
private static final String P_PROPERTIES = "PROPERTIES";
|
||||
private static final String P_QUIET = "QUIET";
|
||||
private static final String P_RUNNING = "RUNNING";
|
||||
private static final String P_STARTING = "STARTING";
|
||||
private static final String P_STOPPING = "STOPPING";
|
||||
|
||||
/* command strings */
|
||||
private static final String C_help = "help";
|
||||
private static final String C_clear = "clear";
|
||||
private static final String C_getdest = "getdest";
|
||||
private static final String C_getkeys = "getkeys";
|
||||
private static final String C_getnick = "getnick";
|
||||
private static final String C_inhost = "inhost";
|
||||
private static final String C_inport = "inport";
|
||||
private static final String C_list = "list";
|
||||
private static final String C_lookup = "lookup";
|
||||
private static final String C_newkeys = "newkeys";
|
||||
private static final String C_option = "option";
|
||||
private static final String C_outhost = "outhost";
|
||||
private static final String C_outport = "outport";
|
||||
private static final String C_quiet = "quiet";
|
||||
private static final String C_quit = "quit";
|
||||
private static final String C_setkeys = "setkeys";
|
||||
private static final String C_setnick = "setnick";
|
||||
private static final String C_show = "show";
|
||||
private static final String C_show_props = "showprops";
|
||||
private static final String C_start = "start";
|
||||
private static final String C_status = "status";
|
||||
private static final String C_stop = "stop";
|
||||
private static final String C_verify = "verify";
|
||||
private static final String C_visit = "visit";
|
||||
private static final String C_zap = "zap";
|
||||
|
||||
/* all the commands available, plus description */
|
||||
private static final String C_ALL[][] = {
|
||||
{C_help, C_help + " <command> * Get help on a command."},
|
||||
{C_clear, C_clear + " * Clear the current nickname out of the list."},
|
||||
{C_getdest, C_getdest + " * Return the destination for the current nickname."},
|
||||
{C_getkeys, C_getkeys + " * Return the keypair for the current nickname."},
|
||||
{C_getnick, C_getnick + " tunnelname * Set the nickname from the database."},
|
||||
{C_inhost, C_inhost + " hostname | IP * Set the inbound hostname or IP."},
|
||||
{C_inport, C_inport + " port_number * Set the inbound port number nickname listens on."},
|
||||
{C_list, C_list + " * List all tunnels."},
|
||||
{C_lookup, C_lookup + " * Lookup an i2p address."},
|
||||
{C_newkeys, C_newkeys + " * Generate a new keypair for the current nickname."},
|
||||
{C_option, C_option + " I2CPoption=something * Set an I2CP option. NOTE: Don't use any spaces."},
|
||||
{C_outhost, C_outhost + " hostname | IP * Set the outbound hostname or IP."},
|
||||
{C_outport, C_outport + " port_number * Set the outbound port that nickname contacts."},
|
||||
{C_quiet, C_quiet + " True | False * Don't send to the application the incoming destination."},
|
||||
{C_quit, C_quit + " * Quits this session with BOB."},
|
||||
{C_setkeys, C_setkeys + " BASE64_keypair * Sets the keypair for the current nickname."},
|
||||
{C_setnick, C_setnick + " nickname * Create a new nickname."},
|
||||
{C_show, C_show + " * Display the status of the current nickname."},
|
||||
{C_show_props, C_show_props + " * Display the properties of the current nickname."},
|
||||
{C_start, C_start + " * Start the current nickname tunnel."},
|
||||
{C_status, C_status + " nickname * Display status of a nicknamed tunnel."},
|
||||
{C_stop, C_stop + " * Stops the current nicknamed tunnel."},
|
||||
{C_verify, C_verify + " BASE64_key * Verifies BASE64 destination."},
|
||||
{C_visit, C_visit + " * Thread dump to wrapper.log."},
|
||||
{C_zap, C_zap + " * Shuts down BOB."},
|
||||
{"", "COMMANDS: " + // this is ugly, but...
|
||||
C_help + " " +
|
||||
C_clear + " " +
|
||||
C_getdest + " " +
|
||||
C_getkeys + " " +
|
||||
C_getnick + " " +
|
||||
C_inhost + " " +
|
||||
C_inport + " " +
|
||||
C_list + " " +
|
||||
C_lookup + " " +
|
||||
C_newkeys + " " +
|
||||
C_option + " " +
|
||||
C_outhost + " " +
|
||||
C_outport + " " +
|
||||
C_quiet + " " +
|
||||
C_quit + " " +
|
||||
C_setkeys + " " +
|
||||
C_setnick + " " +
|
||||
C_show + " " +
|
||||
C_show_props + " " +
|
||||
C_start + " " +
|
||||
C_status + " " +
|
||||
C_stop + " " +
|
||||
C_verify + " " +
|
||||
C_visit + " " +
|
||||
C_zap
|
||||
},
|
||||
{" ", " "} // end of list
|
||||
};
|
||||
|
||||
/**
|
||||
* @param LIVE
|
||||
* @param server
|
||||
* @param props
|
||||
* @param database
|
||||
* @param _log
|
||||
*/
|
||||
DoCMDS(AtomicBoolean LIVE, AtomicBoolean lock, Socket server, Properties props, NamedDB database, Logger _log) {
|
||||
this.lock = lock;
|
||||
this.LIVE = LIVE;
|
||||
this.server = server;
|
||||
this.props = new Properties();
|
||||
this.database = database;
|
||||
this._log = _log;
|
||||
Lifted.copyProperties(props, this.props);
|
||||
}
|
||||
|
||||
private void rlock() {
|
||||
rlock(nickinfo);
|
||||
}
|
||||
|
||||
private void rlock(NamedDB Arg) {
|
||||
database.getReadLock();
|
||||
Arg.getReadLock();
|
||||
}
|
||||
|
||||
private void runlock() {
|
||||
runlock(nickinfo);
|
||||
}
|
||||
|
||||
private void runlock(NamedDB Arg) {
|
||||
Arg.releaseReadLock();
|
||||
database.releaseReadLock();
|
||||
}
|
||||
|
||||
private void wlock() {
|
||||
wlock(nickinfo);
|
||||
}
|
||||
|
||||
private void wlock(NamedDB Arg) {
|
||||
database.getWriteLock();
|
||||
Arg.getWriteLock();
|
||||
}
|
||||
|
||||
private void wunlock() {
|
||||
wunlock(nickinfo);
|
||||
}
|
||||
|
||||
private void wunlock(NamedDB Arg) {
|
||||
Arg.releaseWriteLock();
|
||||
database.releaseWriteLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to print info from the database
|
||||
*
|
||||
* @param out
|
||||
* @param info
|
||||
* @param key
|
||||
*/
|
||||
private void trypnt(PrintStream out, NamedDB info, String key) {
|
||||
rlock(info);
|
||||
try {
|
||||
out.print(" " + key + ": ");
|
||||
if (info.exists(key)) {
|
||||
out.print(info.get(key));
|
||||
} else {
|
||||
out.print("not_set");
|
||||
}
|
||||
} finally {
|
||||
runlock(info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print true or false if an object exists
|
||||
*
|
||||
* @param out
|
||||
* @param info
|
||||
* @param key
|
||||
*/
|
||||
private void tfpnt(PrintStream out, NamedDB info, String key) {
|
||||
rlock(info);
|
||||
try {
|
||||
out.print(" " + key + ": ");
|
||||
out.print(info.exists(key));
|
||||
} finally {
|
||||
runlock(info);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an error message
|
||||
*
|
||||
* @param out
|
||||
*/
|
||||
private static void nns(PrintStream out) {
|
||||
out.println("ERROR no nickname has been set");
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump various information from the database
|
||||
*
|
||||
* @param out
|
||||
* @param info
|
||||
*/
|
||||
private void nickprint(PrintStream out, NamedDB info) {
|
||||
trypnt(out, info, P_NICKNAME);
|
||||
trypnt(out, info, P_STARTING);
|
||||
trypnt(out, info, P_RUNNING);
|
||||
trypnt(out, info, P_STOPPING);
|
||||
tfpnt(out, info, P_KEYS);
|
||||
trypnt(out, info, P_QUIET);
|
||||
trypnt(out, info, P_INPORT);
|
||||
trypnt(out, info, P_INHOST);
|
||||
trypnt(out, info, P_OUTPORT);
|
||||
trypnt(out, info, P_OUTHOST);
|
||||
out.println();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump properties information from the database
|
||||
*
|
||||
* @param out
|
||||
* @param info
|
||||
*/
|
||||
private void propprint(PrintStream out, NamedDB info) {
|
||||
trypnt(out, info, P_PROPERTIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print information on a specific record, indicated by NamedDB
|
||||
* @param out
|
||||
* @param Arg
|
||||
*/
|
||||
private void ttlpnt(PrintStream out, String Arg) {
|
||||
database.getReadLock();
|
||||
try {
|
||||
if (database.exists(Arg)) {
|
||||
out.print("DATA");
|
||||
nickprint(out, (NamedDB) database.get(Arg));
|
||||
}
|
||||
} finally {
|
||||
database.releaseReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this NamedDB's tunnel active?
|
||||
*
|
||||
* @param Arg
|
||||
* @return true if the tunnel is active
|
||||
*/
|
||||
private boolean tunnelactive(NamedDB Arg) {
|
||||
boolean retval;
|
||||
rlock(Arg);
|
||||
try {
|
||||
retval = (Arg.get(P_STARTING).equals(Boolean.TRUE) ||
|
||||
Arg.get(P_STOPPING).equals(Boolean.TRUE) ||
|
||||
Arg.get(P_RUNNING).equals(Boolean.TRUE));
|
||||
} finally {
|
||||
runlock();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the base64 information look OK
|
||||
*
|
||||
* @param data
|
||||
* @return OK
|
||||
*/
|
||||
private static boolean is64ok(String data) {
|
||||
try {
|
||||
new Destination(data);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual parser.
|
||||
* It probabbly needs a rewrite into functions, but I kind-of like inline code.
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
dk = ns = ip = op = false;
|
||||
try {
|
||||
try {
|
||||
// Get input from the client
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
|
||||
PrintStream out = new PrintStream(server.getOutputStream());
|
||||
quit:
|
||||
{
|
||||
die:
|
||||
{
|
||||
prikey = new ByteArrayOutputStream();
|
||||
out.println("BOB " + BOBversion);
|
||||
out.println("OK");
|
||||
while ((line = in.readLine()) != null) {
|
||||
StringTokenizer token = new StringTokenizer(line, " "); // use a space as a delimiter
|
||||
String Command = "";
|
||||
String Arg = "";
|
||||
NamedDB info;
|
||||
|
||||
if (token.countTokens() != 0) {
|
||||
Command = token.nextToken();
|
||||
Command =
|
||||
Command.toLowerCase(Locale.US);
|
||||
if (token.countTokens() != 0) {
|
||||
Arg = token.nextToken();
|
||||
} else {
|
||||
Arg = "";
|
||||
}
|
||||
// The rest of the tokens are considered junk,
|
||||
// and discarded without any warnings.
|
||||
if (Command.equals(C_help)) {
|
||||
for (int i = 0; !C_ALL[i][0].equals(" "); i++) {
|
||||
if (C_ALL[i][0].equalsIgnoreCase(Arg)) {
|
||||
out.println("OK " + C_ALL[i][1]);
|
||||
}
|
||||
}
|
||||
} else if (Command.equals(C_visit)) {
|
||||
visitAllThreads();
|
||||
out.println("OK ");
|
||||
} else if (Command.equals(C_lookup)) {
|
||||
Destination dest = null;
|
||||
String reply = null;
|
||||
if (Arg.endsWith(".i2p")) {
|
||||
try {
|
||||
//try {
|
||||
//dest = I2PTunnel.destFromName(Arg);
|
||||
//} catch (DataFormatException ex) {
|
||||
//}
|
||||
dest = I2PAppContext.getGlobalContext().namingService().lookup(Arg);
|
||||
if(dest != null) {
|
||||
reply = dest.toBase64();
|
||||
}
|
||||
} catch (NullPointerException npe) {
|
||||
// Could not find the destination!?
|
||||
}
|
||||
}
|
||||
if (reply == null) {
|
||||
out.println("ERROR Address Not found.");
|
||||
} else {
|
||||
out.println("OK " + reply);
|
||||
}
|
||||
} else if (Command.equals(C_getdest)) {
|
||||
if (ns) {
|
||||
if (dk) {
|
||||
rlock();
|
||||
try {
|
||||
out.println("OK " + nickinfo.get(P_DEST));
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
} finally {
|
||||
runlock();
|
||||
}
|
||||
} else {
|
||||
out.println("ERROR keys not set.");
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_list)) {
|
||||
// Produce a formatted list of all nicknames
|
||||
database.getReadLock();
|
||||
try {
|
||||
for (Object ndb : database.values()) {
|
||||
try {
|
||||
info = (NamedDB) ndb;
|
||||
out.print("DATA");
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
}
|
||||
nickprint(out, info);
|
||||
}
|
||||
} finally {
|
||||
database.releaseReadLock();
|
||||
}
|
||||
out.println("OK Listing done");
|
||||
} else if (Command.equals(C_quit)) {
|
||||
// End the command session
|
||||
break quit;
|
||||
} else if (Command.equals(C_zap)) {
|
||||
// Kill BOB!! (let's hope this works!)
|
||||
LIVE.set(false);
|
||||
// End the command session
|
||||
break quit;
|
||||
} else if (Command.equals(C_newkeys)) {
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
try {
|
||||
// Make a new PublicKey and PrivateKey
|
||||
prikey = new ByteArrayOutputStream();
|
||||
d = I2PClientFactory.createClient().createDestination(prikey);
|
||||
wlock();
|
||||
try {
|
||||
nickinfo.add(P_KEYS, prikey.toByteArray());
|
||||
nickinfo.add(P_DEST, d.toBase64());
|
||||
out.println("OK " + nickinfo.get(P_DEST));
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
dk = true;
|
||||
} catch (I2PException ipe) {
|
||||
_log.error("Error generating keys", ipe);
|
||||
out.println("ERROR generating keys");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_getkeys)) {
|
||||
// Return public key
|
||||
if (dk) {
|
||||
prikey = new ByteArrayOutputStream();
|
||||
rlock();
|
||||
try {
|
||||
prikey.write(((byte[]) nickinfo.get(P_KEYS)));
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
} finally {
|
||||
runlock();
|
||||
}
|
||||
out.println("OK " + net.i2p.data.Base64.encode(prikey.toByteArray()));
|
||||
} else {
|
||||
out.println("ERROR no public key has been set");
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_quiet)) {
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
wlock();
|
||||
try {
|
||||
nickinfo.add(P_QUIET, Boolean.valueOf(Arg));
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
out.println("OK Quiet set");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_verify)) {
|
||||
if (is64ok(Arg)) {
|
||||
out.println("OK");
|
||||
} else {
|
||||
out.println("ERROR not in BASE64 format");
|
||||
}
|
||||
} else if (Command.equals(C_setkeys)) {
|
||||
// Set the NamedDB to a privatekey in BASE64 format
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
try {
|
||||
prikey = new ByteArrayOutputStream();
|
||||
prikey.write(net.i2p.data.Base64.decode(Arg));
|
||||
d = new Destination();
|
||||
d.fromBase64(Arg);
|
||||
} catch (Exception ex) {
|
||||
Arg = "";
|
||||
}
|
||||
|
||||
if ((Arg.length() == 884) && is64ok(Arg)) {
|
||||
wlock();
|
||||
try {
|
||||
nickinfo.add(P_KEYS, prikey.toByteArray());
|
||||
nickinfo.add(P_DEST, d.toBase64());
|
||||
out.println("OK " + nickinfo.get(P_DEST));
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
dk = true;
|
||||
} else {
|
||||
out.println("ERROR not in BASE64 format");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_setnick)) {
|
||||
ns = dk = ip = op = false;
|
||||
database.getReadLock();
|
||||
try {
|
||||
nickinfo = (NamedDB) database.get(Arg);
|
||||
if (!tunnelactive(nickinfo)) {
|
||||
nickinfo = null;
|
||||
ns = true;
|
||||
}
|
||||
|
||||
} catch (Exception b) {
|
||||
nickinfo = null;
|
||||
ns = true;
|
||||
} finally {
|
||||
database.releaseReadLock();
|
||||
}
|
||||
// Clears and Sets the initial NamedDB structure to work with
|
||||
if (ns) {
|
||||
nickinfo = new NamedDB();
|
||||
wlock();
|
||||
try {
|
||||
database.add(Arg, nickinfo);
|
||||
nickinfo.add(P_NICKNAME, Arg);
|
||||
nickinfo.add(P_STARTING, Boolean.FALSE);
|
||||
nickinfo.add(P_RUNNING, Boolean.FALSE);
|
||||
nickinfo.add(P_STOPPING, Boolean.FALSE);
|
||||
nickinfo.add(P_QUIET, Boolean.FALSE);
|
||||
nickinfo.add(P_INHOST, "localhost");
|
||||
nickinfo.add(P_OUTHOST, "localhost");
|
||||
Properties Q = new Properties();
|
||||
Lifted.copyProperties(this.props, Q);
|
||||
Q.setProperty("inbound.nickname", Arg);
|
||||
Q.setProperty("outbound.nickname", Arg);
|
||||
nickinfo.add(P_PROPERTIES, Q);
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
out.println("OK Nickname set to " + Arg);
|
||||
} else {
|
||||
out.println("ERROR tunnel is active");
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_option)) {
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
StringTokenizer otoken = new StringTokenizer(Arg, "="); // use an equal sign as a delimiter
|
||||
if (otoken.countTokens() != 2) {
|
||||
out.println("ERROR too many or no options.");
|
||||
} else {
|
||||
String pname = otoken.nextToken();
|
||||
String pval = otoken.nextToken();
|
||||
wlock();
|
||||
try {
|
||||
Properties Q = (Properties) nickinfo.get(P_PROPERTIES);
|
||||
Q.setProperty(pname, pval);
|
||||
nickinfo.add(P_PROPERTIES, Q);
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
out.println("OK " + pname + " set to " + pval);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_getnick)) {
|
||||
// Get the NamedDB to work with...
|
||||
boolean nsfail = false;
|
||||
database.getReadLock();
|
||||
try {
|
||||
nickinfo = (NamedDB) database.get(Arg);
|
||||
ns = true;
|
||||
} catch (RuntimeException b) {
|
||||
nsfail = true;
|
||||
nns(out);
|
||||
} finally {
|
||||
database.releaseReadLock();
|
||||
}
|
||||
if (ns && !nsfail) {
|
||||
rlock();
|
||||
try {
|
||||
dk = nickinfo.exists(P_KEYS);
|
||||
ip = nickinfo.exists(P_INPORT);
|
||||
op = nickinfo.exists(P_OUTPORT);
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
} finally {
|
||||
runlock();
|
||||
}
|
||||
// Finally say OK.
|
||||
out.println("OK Nickname set to " + Arg);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_inport)) {
|
||||
// Set the NamedDB inbound TO the router port
|
||||
// app --> BOB
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
int prt;
|
||||
wlock();
|
||||
try {
|
||||
nickinfo.kill(P_INPORT);
|
||||
prt = Integer.parseInt(Arg);
|
||||
if (prt > 1 && prt < 65536) {
|
||||
try {
|
||||
nickinfo.add(P_INPORT, Integer.valueOf(prt));
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
}
|
||||
ip = nickinfo.exists(P_INPORT);
|
||||
} catch (NumberFormatException nfe) {
|
||||
out.println("ERROR not a number");
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
if (ip) {
|
||||
out.println("OK inbound port set");
|
||||
} else {
|
||||
out.println("ERROR port out of range");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_outport)) {
|
||||
// Set the NamedDB outbound FROM the router port
|
||||
// BOB --> app
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
int prt;
|
||||
wlock();
|
||||
try {
|
||||
nickinfo.kill(P_OUTPORT);
|
||||
prt = Integer.parseInt(Arg);
|
||||
if (prt > 1 && prt < 65536) {
|
||||
nickinfo.add(P_OUTPORT, Integer.valueOf(prt));
|
||||
}
|
||||
ip = nickinfo.exists(P_OUTPORT);
|
||||
} catch (NumberFormatException nfe) {
|
||||
out.println("ERROR not a number");
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
if (ip) {
|
||||
out.println("OK outbound port set");
|
||||
} else {
|
||||
out.println("ERROR port out of range");
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_inhost)) {
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
wlock();
|
||||
try {
|
||||
nickinfo.add(P_INHOST, Arg);
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
out.println("OK inhost set");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_outhost)) {
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
wlock();
|
||||
try {
|
||||
nickinfo.add(P_OUTHOST, Arg);
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
out.println("OK outhost set");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_show)) {
|
||||
// Get the current NamedDB properties
|
||||
if (ns) {
|
||||
out.print("OK");
|
||||
nickprint(out, nickinfo);
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_show_props)) {
|
||||
// Get the current options properties
|
||||
if (ns) {
|
||||
out.print("OK");
|
||||
propprint(out, nickinfo);
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_start)) {
|
||||
// Start the tunnel, if we have all the information
|
||||
if (ns && dk && (ip || op)) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
MUXlisten tunnel;
|
||||
try {
|
||||
while (!lock.compareAndSet(false, true)) {
|
||||
// wait
|
||||
}
|
||||
tunnel = new MUXlisten(lock, database, nickinfo, _log);
|
||||
Thread t = new I2PAppThread(tunnel);
|
||||
t.start();
|
||||
// try {
|
||||
// Thread.sleep(1000 * 10); // Slow down the startup.
|
||||
// } catch(InterruptedException ie) {
|
||||
// // ignore it
|
||||
// }
|
||||
out.println("OK tunnel starting");
|
||||
} catch (I2PException e) {
|
||||
lock.set(false);
|
||||
out.println("ERROR starting tunnel: " + e);
|
||||
} catch (IOException e) {
|
||||
lock.set(false);
|
||||
out.println("ERROR starting tunnel: " + e);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
|
||||
} else {
|
||||
out.println("ERROR tunnel settings incomplete");
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_stop)) {
|
||||
// Stop the tunnel, if it is running
|
||||
if (ns) {
|
||||
rlock();
|
||||
boolean released = false;
|
||||
try {
|
||||
if (nickinfo.get(P_RUNNING).equals(Boolean.TRUE) && nickinfo.get(P_STOPPING).equals(Boolean.FALSE) && nickinfo.get(P_STARTING).equals(Boolean.FALSE)) {
|
||||
runlock();
|
||||
released = true;
|
||||
wlock();
|
||||
try {
|
||||
nickinfo.add(P_STOPPING, Boolean.TRUE);
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
out.println("OK tunnel stopping");
|
||||
} else {
|
||||
out.println("ERROR tunnel is inactive");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
} finally {
|
||||
if (!released)
|
||||
runlock();
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_clear)) {
|
||||
// Clear use of the NamedDB if stopped
|
||||
if (ns) {
|
||||
try {
|
||||
if (tunnelactive(nickinfo)) {
|
||||
out.println("ERROR tunnel is active");
|
||||
} else {
|
||||
database.getWriteLock();
|
||||
try {
|
||||
database.kill((String) nickinfo.get(P_NICKNAME));
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
database.releaseWriteLock();
|
||||
}
|
||||
dk = ns = ip = op = false;
|
||||
out.println("OK cleared");
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
|
||||
} else if (Command.equals(C_status)) {
|
||||
database.getReadLock();
|
||||
try {
|
||||
if (database.exists(Arg)) {
|
||||
// Show status of a NamedDB
|
||||
out.print("OK ");
|
||||
try {
|
||||
ttlpnt(out, Arg);
|
||||
} catch (Exception e) {
|
||||
out.println(); // this will cause an IOE if IOE
|
||||
break die;
|
||||
}
|
||||
} else {
|
||||
nns(out);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
} finally {
|
||||
database.releaseReadLock();
|
||||
}
|
||||
} else {
|
||||
out.println("ERROR UNKNOWN COMMAND! Try help");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // die
|
||||
out.print("ERROR A really bad error just happened, ");
|
||||
} // quit
|
||||
// Say goodbye.
|
||||
|
||||
out.println("OK Bye!");
|
||||
|
||||
} catch (IOException ioe) {
|
||||
// not really needed, except to debug.
|
||||
// BOB.warn("IOException on socket listen: " + ioe);
|
||||
// ioe.printStackTrace();
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
server.close();
|
||||
} catch (IOException ex) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
}
|
||||
// Debugging... None of this is normally used.
|
||||
|
||||
/**
|
||||
* Find the root thread group and print them all.
|
||||
*
|
||||
*/
|
||||
private void visitAllThreads() {
|
||||
ThreadGroup root = Thread.currentThread().getThreadGroup().getParent();
|
||||
while (root.getParent() != null) {
|
||||
root = root.getParent();
|
||||
}
|
||||
|
||||
// Visit each thread group
|
||||
visit(root, 0, root.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively visits all thread groups under `group' and dumps them.
|
||||
* @param group ThreadGroup to visit
|
||||
* @param level Current level
|
||||
*/
|
||||
private static void visit(ThreadGroup group, int level, String tn) {
|
||||
// Get threads in `group'
|
||||
int numThreads = group.activeCount();
|
||||
Thread[] threads = new Thread[numThreads * 2];
|
||||
numThreads = group.enumerate(threads, false);
|
||||
String indent = "------------------------------------".substring(0, level) + "-> ";
|
||||
// Enumerate each thread in `group' and print it.
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
// Get thread
|
||||
Thread thread = threads[i];
|
||||
System.out.println("BOB: " + indent + tn + ": " + thread.toString());
|
||||
}
|
||||
|
||||
// Get thread subgroups of `group'
|
||||
int numGroups = group.activeGroupCount();
|
||||
ThreadGroup[] groups = new ThreadGroup[numGroups * 2];
|
||||
numGroups = group.enumerate(groups, false);
|
||||
|
||||
// Recursively visit each subgroup
|
||||
for (int i = 0; i < numGroups; i++) {
|
||||
visit(groups[i], level + 1, groups[i].getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
|
||||
/**
|
||||
* Listen on I2P and connect to TCP
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class I2Plistener implements Runnable {
|
||||
|
||||
private final NamedDB info, database;
|
||||
private final Logger _log;
|
||||
private final I2PServerSocket serverSocket;
|
||||
private final AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param SS
|
||||
* @param S unused
|
||||
* @param info
|
||||
* @param database
|
||||
* @param _log
|
||||
*/
|
||||
I2Plistener(I2PServerSocket SS, I2PSocketManager S, NamedDB info, NamedDB database, Logger _log, AtomicBoolean lives) {
|
||||
this.database = database;
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
this.serverSocket = SS;
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply listen on I2P port, and thread connections
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
boolean g = false;
|
||||
I2PSocket sessSocket = null;
|
||||
int conn = 0;
|
||||
try {
|
||||
try {
|
||||
serverSocket.setSoTimeout(50);
|
||||
|
||||
while (lives.get()) {
|
||||
try {
|
||||
sessSocket = serverSocket.accept();
|
||||
g = true;
|
||||
} catch (ConnectException ce) {
|
||||
g = false;
|
||||
} catch (SocketTimeoutException ste) {
|
||||
g = false;
|
||||
}
|
||||
if (g) {
|
||||
g = false;
|
||||
conn++;
|
||||
// toss the connection to a new thread.
|
||||
I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database, lives);
|
||||
Thread t = new I2PAppThread(conn_c, Thread.currentThread().getName() + " I2PtoTCP " + conn);
|
||||
t.start();
|
||||
}
|
||||
|
||||
}
|
||||
} catch (I2PException e) {
|
||||
// bad stuff
|
||||
System.out.println("Exception " + e);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
serverSocket.close();
|
||||
} catch (I2PException ex) {
|
||||
}
|
||||
// System.out.println("I2Plistener: Close");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
|
||||
/**
|
||||
* Process I2P->TCP
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class I2PtoTCP implements Runnable {
|
||||
|
||||
private I2PSocket I2P;
|
||||
private final NamedDB info, database;
|
||||
private Socket sock;
|
||||
private final AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param I2Psock
|
||||
* @param info
|
||||
* @param database
|
||||
*/
|
||||
I2PtoTCP(I2PSocket I2Psock, NamedDB info, NamedDB database, AtomicBoolean lives) {
|
||||
this.I2P = I2Psock;
|
||||
this.info = info;
|
||||
this.database = database;
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
private void rlock() {
|
||||
database.getReadLock();
|
||||
info.getReadLock();
|
||||
}
|
||||
|
||||
private void runlock() {
|
||||
info.releaseReadLock();
|
||||
database.releaseReadLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* I2P stream to TCP stream thread starter
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
String host;
|
||||
int port;
|
||||
boolean tell;
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
InputStream Iin = null;
|
||||
OutputStream Iout = null;
|
||||
Thread t = null;
|
||||
Thread q = null;
|
||||
try {
|
||||
die:
|
||||
{
|
||||
try {
|
||||
rlock();
|
||||
try {
|
||||
host = info.get("OUTHOST").toString();
|
||||
port = Integer.parseInt(info.get("OUTPORT").toString());
|
||||
tell = info.get("QUIET").equals(Boolean.FALSE);
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
} finally {
|
||||
runlock();
|
||||
}
|
||||
sock = new Socket(host, port);
|
||||
sock.setKeepAlive(true);
|
||||
// make readers/writers
|
||||
in = sock.getInputStream();
|
||||
out = sock.getOutputStream();
|
||||
Iin = I2P.getInputStream();
|
||||
Iout = I2P.getOutputStream();
|
||||
I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
|
||||
|
||||
if (tell) {
|
||||
// tell who is connecting
|
||||
out.write(DataHelper.getASCII(I2P.getPeerDestination().toBase64()));
|
||||
out.write(10); // nl
|
||||
out.flush(); // not really needed, but...
|
||||
}
|
||||
// setup to cross the streams
|
||||
TCPio conn_c = new TCPio(in, Iout, lives); // app -> I2P
|
||||
TCPio conn_a = new TCPio(Iin, out, lives); // I2P -> app
|
||||
t = new I2PAppThread(conn_c, Thread.currentThread().getName() + " TCPioA");
|
||||
q = new I2PAppThread(conn_a, Thread.currentThread().getName() + " TCPioB");
|
||||
// Fire!
|
||||
t.start();
|
||||
q.start();
|
||||
while (t.isAlive() && q.isAlive() && lives.get()) { // AND is used here to kill off the other thread
|
||||
try {
|
||||
Thread.sleep(10); //sleep for 10 ms
|
||||
} catch (InterruptedException e) {
|
||||
break die;
|
||||
}
|
||||
}
|
||||
// System.out.println("I2PtoTCP: Going away...");
|
||||
} catch (Exception e) {
|
||||
// System.out.println("I2PtoTCP: Owch! damn!");
|
||||
break die;
|
||||
}
|
||||
} // die
|
||||
} finally {
|
||||
try {
|
||||
in.close();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
try {
|
||||
out.close();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
try {
|
||||
Iin.close();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
try {
|
||||
Iout.close();
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
try {
|
||||
t.interrupt();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
q.interrupt();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
// System.out.println("I2PtoTCP: Close I2P");
|
||||
I2P.close();
|
||||
} catch (Exception e) {
|
||||
tell = false;
|
||||
}
|
||||
//System.out.println("I2PtoTCP: Closed I2P");
|
||||
try {
|
||||
// System.out.println("I2PtoTCP: Close sock");
|
||||
sock.close();
|
||||
} catch (Exception e) {
|
||||
tell = false;
|
||||
}
|
||||
// System.out.println("I2PtoTCP: Done");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Sets of "friendly" utilities to make life easier.
|
||||
* Any "Lifted" code will apear here, and credits given.
|
||||
* It's better to "Lift" a small chunk of "free" code than add in piles of
|
||||
* code we don't need, and don't want.
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class Lifted {
|
||||
|
||||
/**
|
||||
* Copy a set of properties from one Property to another.
|
||||
* Lifted from Apache Derby code svn repository.
|
||||
* Liscenced as follows:
|
||||
* http://svn.apache.org/repos/asf/db/derby/code/trunk/LICENSE
|
||||
*
|
||||
* @param src_prop Source set of properties to copy from.
|
||||
* @param dest_prop Dest Properties to copy into.
|
||||
*
|
||||
**/
|
||||
public static void copyProperties(Properties src_prop, Properties dest_prop) {
|
||||
for (Map.Entry<Object, Object> e : src_prop.entrySet()) {
|
||||
dest_prop.put((String)e.getKey(), (String)e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package net.i2p.BOB;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class Logger {
|
||||
public Log log;
|
||||
private boolean logToStdout;
|
||||
|
||||
public Logger(Log log, boolean logToStdout) {
|
||||
this.log = log;
|
||||
this.logToStdout = logToStdout;
|
||||
}
|
||||
|
||||
public void info(String msg) {
|
||||
if (logToStdout)
|
||||
System.out.println("INFO: " + msg);
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info(msg);
|
||||
}
|
||||
|
||||
public void warn(String msg) {
|
||||
warn(msg, null);
|
||||
}
|
||||
|
||||
public void warn(String msg, Throwable e) {
|
||||
if (logToStdout) {
|
||||
System.out.println("WARNING: " + msg);
|
||||
if (e != null)
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (log.shouldLog(Log.WARN))
|
||||
log.warn(msg, e);
|
||||
}
|
||||
|
||||
public void error(String msg, Throwable e) {
|
||||
if (logToStdout) {
|
||||
System.out.println("ERROR: " + msg);
|
||||
if (e != null)
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (log.shouldLog(Log.ERROR))
|
||||
log.error(msg, e);
|
||||
}
|
||||
}
|
||||
@@ -1,416 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
*
|
||||
* Multiplex listeners for TCP and I2P
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class MUXlisten implements Runnable {
|
||||
|
||||
private final NamedDB database, info;
|
||||
private final Logger _log;
|
||||
private final I2PSocketManager socketManager;
|
||||
private final ByteArrayInputStream prikey;
|
||||
private ThreadGroup tg;
|
||||
private final String N;
|
||||
private ServerSocket listener;
|
||||
private static final int backlog = 50; // should this be more? less?
|
||||
private final boolean go_out;
|
||||
private final boolean come_in;
|
||||
private final AtomicBoolean lock;
|
||||
private final AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor Will fail if INPORT is occupied.
|
||||
*
|
||||
* @param info DB entry for this tunnel
|
||||
* @param database master database of tunnels
|
||||
* @param _log
|
||||
* @throws net.i2p.I2PException
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
MUXlisten(AtomicBoolean lock, NamedDB database, NamedDB info, Logger _log) throws I2PException, IOException, RuntimeException {
|
||||
int port = 0;
|
||||
InetAddress host = null;
|
||||
this.lock = lock;
|
||||
this.tg = null;
|
||||
this.database = database;
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
lives = new AtomicBoolean(false);
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
this.info.add("STARTING", Boolean.TRUE);
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
Properties Q = new Properties();
|
||||
rlock();
|
||||
try {
|
||||
N = this.info.get("NICKNAME").toString();
|
||||
prikey = new ByteArrayInputStream((byte[]) info.get("KEYS"));
|
||||
// Make a new copy so that anything else won't muck with our database.
|
||||
Properties R = (Properties) info.get("PROPERTIES");
|
||||
Lifted.copyProperties(R, Q);
|
||||
|
||||
this.go_out = info.exists("OUTPORT");
|
||||
this.come_in = info.exists("INPORT");
|
||||
if (this.come_in) {
|
||||
port = Integer.parseInt(info.get("INPORT").toString());
|
||||
host = InetAddress.getByName(info.get("INHOST").toString());
|
||||
}
|
||||
} finally {
|
||||
runlock();
|
||||
}
|
||||
|
||||
String i2cpHost = Q.getProperty(I2PClient.PROP_TCP_HOST, "127.0.0.1");
|
||||
int i2cpPort = I2PClient.DEFAULT_LISTEN_PORT;
|
||||
String i2cpPortStr = Q.getProperty(I2PClient.PROP_TCP_PORT);
|
||||
if (i2cpPortStr != null) {
|
||||
try {
|
||||
i2cpPort = Integer.parseInt(i2cpPortStr);
|
||||
} catch (NumberFormatException nfe) {
|
||||
throw new IllegalArgumentException("Invalid I2CP port specified [" + i2cpPortStr + "]");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.come_in) {
|
||||
this.listener = new ServerSocket(port, backlog, host);
|
||||
}
|
||||
socketManager = I2PSocketManagerFactory.createManager(
|
||||
prikey, i2cpHost, i2cpPort, Q);
|
||||
} catch (IOException e) {
|
||||
// Something went bad.
|
||||
wlock();
|
||||
try {
|
||||
this.info.add("STARTING", Boolean.FALSE);
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
throw e;
|
||||
} catch (RuntimeException e) {
|
||||
// Something went bad.
|
||||
wlock();
|
||||
try {
|
||||
this.info.add("STARTING", Boolean.FALSE);
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// Something else went bad.
|
||||
wlock();
|
||||
try {
|
||||
this.info.add("STARTING", Boolean.FALSE);
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void rlock() {
|
||||
database.getReadLock();
|
||||
info.getReadLock();
|
||||
}
|
||||
|
||||
private void runlock() {
|
||||
info.releaseReadLock();
|
||||
database.releaseReadLock();
|
||||
}
|
||||
|
||||
private void wlock() {
|
||||
database.getWriteLock();
|
||||
info.getWriteLock();
|
||||
}
|
||||
|
||||
private void wunlock() {
|
||||
info.releaseWriteLock();
|
||||
database.releaseWriteLock();
|
||||
}
|
||||
|
||||
/**
|
||||
* MUX sockets, fire off a thread to connect, get destination info, and do I/O
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
I2PServerSocket SS = null;
|
||||
Thread t = null;
|
||||
Thread q = null;
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
try {
|
||||
info.add("RUNNING", Boolean.TRUE);
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
return;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
lives.set(true);
|
||||
lock.set(false);
|
||||
quit:
|
||||
{
|
||||
try {
|
||||
tg = new ThreadGroup(N);
|
||||
{
|
||||
// toss the connections to a new threads.
|
||||
// will wrap with TCP and UDP when UDP works
|
||||
|
||||
if (go_out) {
|
||||
// I2P -> TCP
|
||||
SS = socketManager.getServerSocket();
|
||||
I2Plistener conn = new I2Plistener(SS, socketManager, info, database, _log, lives);
|
||||
t = new I2PAppThread(tg, conn, "BOBI2Plistener " + N);
|
||||
t.start();
|
||||
}
|
||||
|
||||
if (come_in) {
|
||||
// TCP -> I2P
|
||||
TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log, lives);
|
||||
q = new I2PAppThread(tg, conn, "BOBTCPlistener " + N);
|
||||
q.start();
|
||||
}
|
||||
|
||||
wlock();
|
||||
try {
|
||||
try {
|
||||
info.add("STARTING", Boolean.FALSE);
|
||||
} catch (Exception e) {
|
||||
break quit;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
break quit;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
boolean spin = true;
|
||||
while (spin && lives.get()) {
|
||||
try {
|
||||
Thread.sleep(1000); //sleep for 1 second
|
||||
} catch (InterruptedException e) {
|
||||
break quit;
|
||||
}
|
||||
rlock();
|
||||
try {
|
||||
try {
|
||||
spin = info.get("STOPPING").equals(Boolean.FALSE);
|
||||
} catch (Exception e) {
|
||||
break quit;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
break quit;
|
||||
} finally {
|
||||
runlock();
|
||||
}
|
||||
}
|
||||
} // die
|
||||
|
||||
} catch (Exception e) {
|
||||
// System.out.println("MUXlisten: Caught an exception" + e);
|
||||
break quit;
|
||||
}
|
||||
} // quit
|
||||
} finally {
|
||||
lives.set(false);
|
||||
// Some grace time.
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
info.add("STARTING", Boolean.FALSE);
|
||||
info.add("STOPPING", Boolean.TRUE);
|
||||
info.add("RUNNING", Boolean.FALSE);
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
// Start cleanup.
|
||||
while (!lock.compareAndSet(false, true)) {
|
||||
// wait
|
||||
}
|
||||
if (SS != null) {
|
||||
try {
|
||||
SS.close();
|
||||
} catch (I2PException ex) {
|
||||
}
|
||||
}
|
||||
if (listener != null) {
|
||||
try {
|
||||
listener.close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
// Some grace time.
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
|
||||
// Hopefully nuke stuff here...
|
||||
{
|
||||
String groupName = tg.getName();
|
||||
try {
|
||||
_log.warn("destroySocketManager " + groupName);
|
||||
socketManager.destroySocketManager();
|
||||
_log.warn("destroySocketManager Successful" + groupName);
|
||||
} catch (Exception e) {
|
||||
// nop
|
||||
_log.warn("destroySocketManager Failed" + groupName);
|
||||
_log.warn(e.toString());
|
||||
}
|
||||
}
|
||||
// zero out everything.
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
info.add("STARTING", Boolean.FALSE);
|
||||
info.add("STOPPING", Boolean.FALSE);
|
||||
info.add("RUNNING", Boolean.FALSE);
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
return;
|
||||
} finally {
|
||||
wunlock();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
lock.set(false); // Should we force waiting for all threads??
|
||||
|
||||
// Wait around till all threads are collected.
|
||||
if (tg != null) {
|
||||
String groupName = tg.getName();
|
||||
// System.out.println("BOB: MUXlisten: Starting thread collection for: " + groupName);
|
||||
_log.warn("BOB: MUXlisten: Starting thread collection for: " + groupName);
|
||||
if (tg.activeCount() + tg.activeGroupCount() != 0) {
|
||||
// visit(tg, 0, groupName);
|
||||
int foo = tg.activeCount() + tg.activeGroupCount();
|
||||
// hopefully no longer needed!
|
||||
// int bar = lives;
|
||||
// System.out.println("BOB: MUXlisten: Waiting on threads for " + groupName);
|
||||
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + groupName);
|
||||
// visit(tg, 0, groupName);
|
||||
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + groupName + "\n");
|
||||
// Happily spin forever :-(
|
||||
while (foo != 0) {
|
||||
foo = tg.activeCount() + tg.activeGroupCount();
|
||||
// if (lives != bar && lives != 0) {
|
||||
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + groupName);
|
||||
// visit(tg, 0, groupName);
|
||||
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + groupName + "\n");
|
||||
// }
|
||||
// bar = lives;
|
||||
try {
|
||||
Thread.sleep(100); //sleep for 100 ms (One tenth second)
|
||||
} catch (InterruptedException ex) {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
}
|
||||
// System.out.println("BOB: MUXlisten: Threads went away. Success: " + groupName);
|
||||
_log.warn("BOB: MUXlisten: Threads went away. Success: " + groupName);
|
||||
tg.destroy();
|
||||
// Zap reference to the ThreadGroup so the JVM can GC it.
|
||||
tg = null;
|
||||
}
|
||||
try {
|
||||
socketManager.destroySocketManager();
|
||||
} catch (Exception e) {
|
||||
// nop
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Debugging... None of this is normally used.
|
||||
/**
|
||||
* Find the root thread group and print them all.
|
||||
*
|
||||
*/
|
||||
private void visitAllThreads() {
|
||||
ThreadGroup root = Thread.currentThread().getThreadGroup().getParent();
|
||||
while (root.getParent() != null) {
|
||||
root = root.getParent();
|
||||
}
|
||||
|
||||
// Visit each thread group
|
||||
visit(root, 0, root.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively visits all thread groups under `group' and dumps them.
|
||||
* @param group ThreadGroup to visit
|
||||
* @param level Current level
|
||||
*/
|
||||
private static void visit(ThreadGroup group, int level, String tn) {
|
||||
// Get threads in `group'
|
||||
int numThreads = group.activeCount();
|
||||
Thread[] threads = new Thread[numThreads * 2];
|
||||
numThreads = group.enumerate(threads, false);
|
||||
String indent = "------------------------------------".substring(0, level) + "-> ";
|
||||
// Enumerate each thread in `group' and print it.
|
||||
for (int i = 0; i < numThreads; i++) {
|
||||
// Get thread
|
||||
Thread thread = threads[i];
|
||||
System.out.println("BOB: MUXlisten: " + tn + ": " + indent + thread.toString());
|
||||
}
|
||||
|
||||
// Get thread subgroups of `group'
|
||||
int numGroups = group.activeGroupCount();
|
||||
ThreadGroup[] groups = new ThreadGroup[numGroups * 2];
|
||||
numGroups = group.enumerate(groups, false);
|
||||
|
||||
// Recursively visit each subgroup
|
||||
for (int i = 0; i < numGroups; i++) {
|
||||
visit(groups[i], level + 1, groups[i].getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
/**
|
||||
* Start from command line
|
||||
*
|
||||
* @author sponge
|
||||
*
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
/**
|
||||
* @param args the command line arguments, these are not used yet
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// THINK THINK THINK THINK THINK THINK
|
||||
SimpleTimer2 Y2 = SimpleTimer2.getInstance();
|
||||
|
||||
BOB.main(args);
|
||||
|
||||
Y2.stop();
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
|
||||
/**
|
||||
* Internal database to relate nicknames to options to values
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class NamedDB {
|
||||
|
||||
private final Map<String, Object> data;
|
||||
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(false);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public NamedDB() {
|
||||
this.data = new HashMap<String, Object>();
|
||||
}
|
||||
|
||||
public void getReadLock() {
|
||||
lock.readLock().lock();
|
||||
}
|
||||
|
||||
public void releaseReadLock() {
|
||||
lock.readLock().unlock();
|
||||
}
|
||||
|
||||
public void getWriteLock() {
|
||||
lock.writeLock().lock();
|
||||
}
|
||||
|
||||
public void releaseWriteLock() {
|
||||
lock.writeLock().unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an object if it exists
|
||||
*
|
||||
* @param key
|
||||
*/
|
||||
public void kill(String key) {
|
||||
data.remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add object, deletes the old one if it exists
|
||||
*
|
||||
* @param key
|
||||
* @param val
|
||||
*/
|
||||
public void add(String key, Object val) {
|
||||
data.put(key, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object, and return it, throws RuntimeException if not found
|
||||
*
|
||||
* @param key non-null
|
||||
* @return Object non-null
|
||||
* @throws java.lang.RuntimeException if not found
|
||||
*/
|
||||
public Object get(String key) throws RuntimeException {
|
||||
Object rv = data.get(key);
|
||||
if (rv != null)
|
||||
return rv;
|
||||
throw new RuntimeException("Key not found");
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if an object exists, else returns false
|
||||
*
|
||||
* @param key
|
||||
* @return true if an object exists, else returns false
|
||||
*/
|
||||
public boolean exists(String key) {
|
||||
return data.containsKey(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.29 replaces getcount() and getnext(int)
|
||||
*/
|
||||
public Collection<Object> values() {
|
||||
return data.values();
|
||||
}
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/**
|
||||
* Shove data from one stream to the other.
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class TCPio implements Runnable {
|
||||
|
||||
private final InputStream Ain;
|
||||
private final OutputStream Aout;
|
||||
private final AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param Ain InputStream
|
||||
* @param Aout OutputStream
|
||||
*
|
||||
* param database
|
||||
*/
|
||||
TCPio(InputStream Ain, OutputStream Aout, AtomicBoolean lives) {
|
||||
this.Ain = Ain;
|
||||
this.Aout = Aout;
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from source to destination...
|
||||
* and yes, we are totally OK to block here on writes,
|
||||
* The OS has buffers, and I intend to use them.
|
||||
* We send an interrupt signal to the threadgroup to
|
||||
* unwedge any pending writes.
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
/*
|
||||
* NOTE:
|
||||
* The write method of OutputStream calls the write method of
|
||||
* one argument on each of the bytes to be written out.
|
||||
* Subclasses are encouraged to override this method and provide
|
||||
* a more efficient implementation.
|
||||
*
|
||||
* So, is this really a performance problem?
|
||||
* Should we expand to several bytes?
|
||||
* I don't believe there would be any gain, since read method
|
||||
* has the same reccomendations. If anyone has a better way to
|
||||
* do this, I'm interested in performance improvements.
|
||||
*
|
||||
* --Sponge
|
||||
*
|
||||
* Tested with 128 bytes, and there was no performance gain.
|
||||
* 8192 bytes did lower load average across many connections.
|
||||
* Should I raise it higer? The correct thing to do would be to
|
||||
* override... perhaps use NTCP, but I2P's streaming lib lacks
|
||||
* anything NTCP compatable.
|
||||
*
|
||||
* --Sponge
|
||||
*/
|
||||
|
||||
int b;
|
||||
byte a[] = new byte[8192];
|
||||
try {
|
||||
try {
|
||||
while (lives.get()) {
|
||||
b = Ain.read(a, 0, 8192);
|
||||
if (b > 0) {
|
||||
Aout.write(a, 0, b);
|
||||
} else if (b == 0) {
|
||||
while(Ain.available() == 0) {
|
||||
Thread.sleep(20);
|
||||
}
|
||||
} else {
|
||||
/* according to the specs:
|
||||
*
|
||||
* The total number of bytes read into the buffer,
|
||||
* or -1 if there is no more data because the end of
|
||||
* the stream has been reached.
|
||||
*
|
||||
*/
|
||||
// System.out.println("TCPio: End Of Stream");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
}
|
||||
// System.out.println("TCPio: Leaving.");
|
||||
} finally {
|
||||
// Eject!!! Eject!!!
|
||||
//System.out.println("TCPio: Caught an exception " + e);
|
||||
try {
|
||||
Ain.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
try {
|
||||
Aout.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
|
||||
/**
|
||||
* Listen on TCP port and connect to I2P
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class TCPlistener implements Runnable {
|
||||
|
||||
private final NamedDB info, database;
|
||||
private final Logger _log;
|
||||
private final I2PSocketManager socketManager;
|
||||
private final ServerSocket listener;
|
||||
private final AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param S
|
||||
* @param info
|
||||
* @param database
|
||||
* @param _log
|
||||
*/
|
||||
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Logger _log, AtomicBoolean lives) {
|
||||
this.database = database;
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
this.socketManager = S;
|
||||
this.listener = listener;
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simply listen on TCP port, and thread connections
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
boolean g = false;
|
||||
int conn = 0;
|
||||
Socket server = null;
|
||||
try {
|
||||
try {
|
||||
listener.setSoTimeout(50); // We don't block, we cycle and check.
|
||||
while (lives.get()) {
|
||||
try {
|
||||
server = listener.accept();
|
||||
server.setKeepAlive(true);
|
||||
g = true;
|
||||
} catch (SocketTimeoutException ste) {
|
||||
g = false;
|
||||
}
|
||||
if (g) {
|
||||
conn++;
|
||||
// toss the connection to a new thread.
|
||||
TCPtoI2P conn_c = new TCPtoI2P(socketManager, server, info, database, lives);
|
||||
Thread t = new I2PAppThread(conn_c, Thread.currentThread().getName() + " TCPtoI2P " + conn);
|
||||
t.start();
|
||||
g = false;
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
listener.close();
|
||||
} catch (IOException ex) {
|
||||
}
|
||||
//System.out.println("TCPlistener: " + Thread.currentThread().getName() + "Done.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,222 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.OutputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.Socket;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
|
||||
/**
|
||||
*
|
||||
* Process TCP->I2P
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class TCPtoI2P implements Runnable {
|
||||
|
||||
private I2PSocket I2P;
|
||||
private final Socket sock;
|
||||
private final I2PSocketManager socketManager;
|
||||
private final AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param i2p
|
||||
* @param socket
|
||||
* @param info unused
|
||||
* @param database unused
|
||||
*/
|
||||
TCPtoI2P(I2PSocketManager i2p, Socket socket, NamedDB info, NamedDB database, AtomicBoolean lives) {
|
||||
this.sock = socket;
|
||||
this.socketManager = i2p;
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a more forgiving readline,
|
||||
* it works on unbuffered streams
|
||||
*
|
||||
* @param in
|
||||
* @return line of text as a String
|
||||
* @throws IOException
|
||||
*/
|
||||
private static String lnRead(InputStream in) throws IOException {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
int b;
|
||||
char c;
|
||||
|
||||
while (true) {
|
||||
b = in.read();
|
||||
if (b == 13) {
|
||||
//skip CR
|
||||
continue;
|
||||
}
|
||||
if (b < 20 || b > 126) {
|
||||
// exit on anything not legal
|
||||
break;
|
||||
}
|
||||
c = (char) (b & 0x7f); // We only care about ASCII
|
||||
builder.append(c);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Print an error message to out
|
||||
*
|
||||
* @param e
|
||||
* @param out
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
private void Emsg(String e, OutputStream out) throws IOException {
|
||||
// Debugging System.out.println("ERROR TCPtoI2P: " + e);
|
||||
out.write("ERROR ".concat(e).getBytes("UTF-8"));
|
||||
out.write(13);
|
||||
out.write(10);
|
||||
out.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* TCP stream to I2P stream thread starter
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
String line, input;
|
||||
InputStream Iin = null;
|
||||
OutputStream Iout = null;
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
Thread t = null;
|
||||
Thread q = null;
|
||||
try {
|
||||
try {
|
||||
|
||||
in = sock.getInputStream();
|
||||
out = sock.getOutputStream();
|
||||
line = lnRead(in);
|
||||
input = line.toLowerCase(Locale.US);
|
||||
Destination dest = null;
|
||||
if (input.endsWith(".i2p")) {
|
||||
//dest = I2PTunnel.destFromName(input);
|
||||
dest = I2PAppContext.getGlobalContext().namingService().lookup(input);
|
||||
if (dest != null) {
|
||||
line = dest.toBase64();
|
||||
} else {
|
||||
Emsg("Can't find destination: " + input, out);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dest = new Destination();
|
||||
dest.fromBase64(line);
|
||||
|
||||
try {
|
||||
// get a client socket
|
||||
I2P = socketManager.connect(dest);
|
||||
I2P.setReadTimeout(0); // temp bugfix, this *SHOULD* be the default
|
||||
// make readers/writers
|
||||
Iin = I2P.getInputStream();
|
||||
Iout = I2P.getOutputStream();
|
||||
// setup to cross the streams
|
||||
TCPio conn_c = new TCPio(in, Iout, lives); // app -> I2P
|
||||
TCPio conn_a = new TCPio(Iin, out, lives); // I2P -> app
|
||||
t = new I2PAppThread(conn_c, Thread.currentThread().getName() + " TCPioA");
|
||||
q = new I2PAppThread(conn_a, Thread.currentThread().getName() + " TCPioB");
|
||||
// Fire!
|
||||
t.start();
|
||||
q.start();
|
||||
while (t.isAlive() && q.isAlive() && lives.get()) { // AND is used here to kill off the other thread
|
||||
Thread.sleep(10); //sleep for 10 ms
|
||||
}
|
||||
} catch (I2PException e) {
|
||||
Emsg(e.toString(), out);
|
||||
} catch (ConnectException e) {
|
||||
Emsg(e.toString(), out);
|
||||
} catch (NoRouteToHostException e) {
|
||||
Emsg(e.toString(), out);
|
||||
}
|
||||
|
||||
} catch (InterruptedIOException e) {
|
||||
// We're breaking away.
|
||||
} catch (InterruptedException e) {
|
||||
// ditto
|
||||
} catch (IOException e) {
|
||||
try {
|
||||
Emsg(e.toString(), out);
|
||||
} catch (IOException ex) {
|
||||
// ditto
|
||||
}
|
||||
} catch (DataFormatException e) {
|
||||
try {
|
||||
Emsg(e.toString(), out);
|
||||
} catch (IOException ex) {
|
||||
// ditto
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
try {
|
||||
t.interrupt();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
q.interrupt();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
out.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
Iin.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
Iout.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
// System.out.println("TCPtoI2P: Close I2P");
|
||||
I2P.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
try {
|
||||
// System.out.println("TCPtoI2P: Close sock");
|
||||
sock.close();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
// System.out.println("TCPtoI2P: Done.");
|
||||
}
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/**
|
||||
* WTFPL
|
||||
* Version 2, December 2004
|
||||
*
|
||||
* Copyright (C) sponge
|
||||
* Planet Earth
|
||||
*
|
||||
* See...
|
||||
*
|
||||
* http://sam.zoy.org/wtfpl/
|
||||
* and
|
||||
* http://en.wikipedia.org/wiki/WTFPL
|
||||
*
|
||||
* ...for any additional details and license questions.
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PSessionListener;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* UDP IO on I2P
|
||||
*
|
||||
* FIX ME: Untested, and incomplete!
|
||||
* I have no personal need to UDP yet,
|
||||
* however alot of p2p apps pretty much demand it.
|
||||
* The skeletal frame is here, just needs to be finished.
|
||||
*
|
||||
* @author sponge
|
||||
* @deprecated incomplete, unused
|
||||
*/
|
||||
@Deprecated
|
||||
public class UDPIOthread implements I2PSessionListener, Runnable {
|
||||
|
||||
private final NamedDB info;
|
||||
private final Log _log;
|
||||
private final Socket socket;
|
||||
private DataInputStream in;
|
||||
private DataOutputStream out;
|
||||
private final I2PSession _session;
|
||||
// FIXME never set
|
||||
private Destination _peerDestination;
|
||||
private boolean up;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* @param info
|
||||
* @param _log
|
||||
* @param socket
|
||||
* @param _session
|
||||
*/
|
||||
UDPIOthread(NamedDB info, Log _log, Socket socket, I2PSession _session) {
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
this.socket = socket;
|
||||
this._session = _session;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void run() {
|
||||
byte data[] = new byte[1024];
|
||||
up = true;
|
||||
try {
|
||||
in = new DataInputStream(socket.getInputStream());
|
||||
out = new DataOutputStream(socket.getOutputStream());
|
||||
while (up) {
|
||||
int c = in.read(data);
|
||||
// Note: could do a loopback test here with a wrapper.
|
||||
boolean ok = _session.sendMessage(_peerDestination, data, 0, c);
|
||||
|
||||
if (!ok) {
|
||||
up = false; // Is this the right thing to do??
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error running", ioe);
|
||||
} catch (I2PSessionException ise) {
|
||||
_log.error("Error communicating", ise);
|
||||
// } catch(DataFormatException dfe) {
|
||||
// _log.error("Peer destination file is not valid", dfe);
|
||||
} finally {
|
||||
if (_session != null) {
|
||||
try {
|
||||
_session.destroySession();
|
||||
} catch (I2PSessionException ise) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param session
|
||||
* @param msgId
|
||||
* @param size
|
||||
*/
|
||||
public void messageAvailable(I2PSession session, int msgId, long size) {
|
||||
// _log.debug("Message available: id = " + msgId + " size = " + size);
|
||||
try {
|
||||
byte msg[] = session.receiveMessage(msgId);
|
||||
if (msg != null) {
|
||||
out.write(msg);
|
||||
out.flush();
|
||||
}
|
||||
} catch (I2PSessionException ise) {
|
||||
up = false;
|
||||
} catch (IOException ioe) {
|
||||
up = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Great, can these be used to kill ourselves.
|
||||
/** required by {@link I2PSessionListener I2PSessionListener} to notify of disconnect */
|
||||
public void disconnected(I2PSession session) {
|
||||
_log.debug("Disconnected");
|
||||
// up = false;
|
||||
}
|
||||
|
||||
/** required by {@link I2PSessionListener I2PSessionListener} to notify of error */
|
||||
public void errorOccurred(I2PSession session, String message, Throwable error) {
|
||||
_log.debug("Error occurred: " + message, error);
|
||||
// up = false;
|
||||
}
|
||||
|
||||
/** required by {@link I2PSessionListener I2PSessionListener} to notify of abuse */
|
||||
public void reportAbuse(I2PSession session, int severity) {
|
||||
_log.debug("Abuse reported of severity " + severity);
|
||||
// up = false;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
Version 2, December 2004
|
||||
|
||||
Copyright (C) sponge
|
||||
Planet Earth
|
||||
Everyone is permitted to copy and distribute verbatim or modified
|
||||
copies of this license document, and changing it is allowed as long
|
||||
as the name is changed.
|
||||
|
||||
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. You just DO WHAT THE FUCK YOU WANT TO.
|
||||
|
||||
See...
|
||||
|
||||
http://sam.zoy.org/wtfpl/
|
||||
and
|
||||
http://en.wikipedia.org/wiki/WTFPL
|
||||
|
||||
...for any additional details and license questions.
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>BOB, the Basic Open Bridge, allows TCP applications to talk over I2P - DEPRECATED - Please port applications to SAMv3.</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,6 +9,7 @@
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.8" />
|
||||
<property name="javac.release" value="8" />
|
||||
<property name="manifest.classpath.name" value="Class-Path" />
|
||||
|
||||
<target name="all" depends="jar, emptyWar"/>
|
||||
|
||||
@@ -57,8 +58,14 @@
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar basedir="${build}" destfile="${dist}/${jar}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.addressbook.Daemon"/>
|
||||
<attribute name="${manifest.classpath.name}" value="i2p.jar" />
|
||||
<attribute name="Main-Class" value="net.i2p.addressbook.CommandLine"/>
|
||||
<attribute name="Specification-Title" value="I2P Address Book" />
|
||||
<attribute name="Specification-Version" value="${api.version}" />
|
||||
<attribute name="Specification-Vendor" value="The I2P Project https://geti2p.net/" />
|
||||
<attribute name="Implementation-Title" value="I2P Java Address Book" />
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
<attribute name="Implementation-Vendor" value="The I2P Project https://geti2p.net/" />
|
||||
<attribute name="Built-By" value="${build.built-by}" />
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
@@ -77,28 +84,36 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<!-- actually the jar -->
|
||||
<target name="warUpToDate">
|
||||
<uptodate property="war.uptodate" targetfile="${dist}/${war}">
|
||||
<srcfiles dir= "." includes="${build}/**/*.class, web.xml"/>
|
||||
<uptodate property="war.uptodate" targetfile="${dist}/${jar}">
|
||||
<srcfiles dir= "." includes="${build}/**/*.class"/>
|
||||
</uptodate>
|
||||
<condition property="shouldListChanges" >
|
||||
<and>
|
||||
<not>
|
||||
<isset property="war.uptodate" />
|
||||
</not>
|
||||
<isset property="mtn.available" />
|
||||
<isset property="git.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
<target name="changes" depends="warUpToDate" if="shouldListChanges" >
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<exec executable="git" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="status" />
|
||||
<arg value="-s" />
|
||||
<arg value="--porcelain" />
|
||||
<arg value="-uno" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<!-- trim flags -->
|
||||
<exec executable="sed" inputstring="${workspace.changes}" outputproperty="workspace.changes.sed" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/^[MTADRCU ]*//" />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<exec executable="tr" inputstring="${workspace.changes.sed}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
|
||||
@@ -136,9 +136,17 @@ class AddressBook implements Iterable<Map.Entry<String, HostTxtEntry>> {
|
||||
File tmp = null;
|
||||
try {
|
||||
tmp = SecureFile.createTempFile("addressbook", null, I2PAppContext.getGlobalContext().getTempDir());
|
||||
// Apache 2.4 mod_deflate etag bug workaround
|
||||
// strip -gzip from the etag
|
||||
// Gitlab #454
|
||||
String loc = subscription.getLocation();
|
||||
String etag = subscription.getEtag();
|
||||
if (loc.startsWith("http://i2p-projekt.i2p/") && etag != null && etag.endsWith("-gzip\""))
|
||||
etag = etag.substring(0, etag.length() - 6) + '"';
|
||||
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
|
||||
proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, tmp.getAbsolutePath(), null,
|
||||
subscription.getLocation(), true, subscription.getEtag(), subscription.getLastModified(), null);
|
||||
loc, true, etag, subscription.getLastModified(), null);
|
||||
if (get.fetch()) {
|
||||
subscription.setEtag(get.getETag());
|
||||
subscription.setLastModified(get.getLastModified());
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
|
||||
/**
|
||||
* Simple command line access to various utilities.
|
||||
* Not a public API. Subject to change.
|
||||
* Apps and plugins should use specific classes.
|
||||
*
|
||||
* @since 0.9.55
|
||||
*/
|
||||
public class CommandLine extends net.i2p.util.CommandLine {
|
||||
|
||||
protected static final List<String> ACLASSES = Arrays.asList(new String[] {
|
||||
"net.i2p.addressbook.HostTxtParser",
|
||||
"net.i2p.router.naming.BlockfileNamingService",
|
||||
"net.metanotion.io.block.BlockFile",
|
||||
});
|
||||
|
||||
protected CommandLine() {}
|
||||
|
||||
public static void main(String args[]) {
|
||||
List<String> classes = new ArrayList<String>(ACLASSES.size() + CLASSES.size());
|
||||
classes.addAll(ACLASSES);
|
||||
classes.addAll(CLASSES);
|
||||
if (args.length > 0) {
|
||||
exec(args, classes);
|
||||
}
|
||||
usage(classes);
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
private static void usage(List<String> classes) {
|
||||
System.err.println("I2P Address book version " + CoreVersion.VERSION + '\n' +
|
||||
"USAGE: java -jar /path/to/addressbook.jar command [args]");
|
||||
printCommands(classes);
|
||||
}
|
||||
}
|
||||
@@ -697,7 +697,7 @@ class Daemon {
|
||||
StringBuilder buf = new StringBuilder(16);
|
||||
final int sz = dests.size();
|
||||
for (int i = 0; i < sz; i++) {
|
||||
buf.append(dests.get(i).toBase64().substring(0, 6));
|
||||
buf.append(dests.get(i).toBase64(), 0, 6);
|
||||
if (i != sz - 1)
|
||||
buf.append(", ");
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.Properties;
|
||||
|
||||
import net.i2p.client.naming.HostTxtEntry;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.SecureFile;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.SystemVersion;
|
||||
@@ -25,9 +26,9 @@ import net.i2p.util.SystemVersion;
|
||||
* Utility class providing methods to parse and write files in a hosts.txt file
|
||||
* format, and subscription file format.
|
||||
*
|
||||
* @since 0.9.26 modified from ConfigParser
|
||||
* @since 0.9.26 modified from ConfigParser, public since 0.9.55 for CLI
|
||||
*/
|
||||
class HostTxtParser {
|
||||
public class HostTxtParser {
|
||||
|
||||
private static final boolean isWindows = SystemVersion.isWindows();
|
||||
|
||||
@@ -255,8 +256,23 @@ class HostTxtParser {
|
||||
System.exit(2);
|
||||
}
|
||||
if (!e.hasValidSig()) {
|
||||
if (!quiet)
|
||||
System.err.println("Bad signature");
|
||||
if (!quiet) {
|
||||
System.err.println("Bad signature for " + e.getName());
|
||||
String dest = e.getDest();
|
||||
try {
|
||||
Destination d = new Destination(dest);
|
||||
System.err.println(dest);
|
||||
System.err.println(d.toString());
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Invalid destination: " + dest);
|
||||
}
|
||||
Properties p = e.getProps();
|
||||
if (p != null) {
|
||||
for (Map.Entry<?,?> m : p.entrySet()) {
|
||||
System.err.println(m.getKey() + "=" + m.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
System.exit(3);
|
||||
}
|
||||
Properties p = e.getProps();
|
||||
@@ -266,14 +282,30 @@ class HostTxtParser {
|
||||
p.containsKey(HostTxtEntry.PROP_OLDNAME) ||
|
||||
p.containsKey(HostTxtEntry.PROP_OLDSIG)) {
|
||||
if (!e.hasValidSig()) {
|
||||
if (!quiet)
|
||||
System.err.println("Bad inner signature");
|
||||
if (!quiet) {
|
||||
System.err.println("Bad inner signature for " + e.getName());
|
||||
for (Map.Entry<?,?> m : p.entrySet()) {
|
||||
System.err.println(m.getKey() + "=" + m.getValue());
|
||||
}
|
||||
}
|
||||
System.exit(4);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!quiet)
|
||||
if (!quiet) {
|
||||
System.err.println("Good signature for " + e.getName());
|
||||
try {
|
||||
String dest = e.getDest();
|
||||
Destination d = new Destination(dest);
|
||||
System.err.println(dest);
|
||||
System.err.println(d.toString());
|
||||
} catch (Exception ex) {}
|
||||
if (p != null) {
|
||||
for (Map.Entry<?,?> m : p.entrySet()) {
|
||||
System.err.println(m.getKey() + "=" + m.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,11 +23,14 @@ package net.i2p.addressbook;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Date;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
|
||||
/**
|
||||
* A simple log with automatic time stamping.
|
||||
*
|
||||
@@ -57,9 +60,9 @@ class Log {
|
||||
public void append(String entry) {
|
||||
BufferedWriter bw = null;
|
||||
try {
|
||||
bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this.file,
|
||||
bw = new BufferedWriter(new OutputStreamWriter(new SecureFileOutputStream(this.file,
|
||||
true), "UTF-8"));
|
||||
String timestamp = new Date().toString();
|
||||
String timestamp = DataHelper.formatTime(I2PAppContext.getGlobalContext().clock().now());
|
||||
bw.write(timestamp + " -- " + entry);
|
||||
bw.newLine();
|
||||
} catch (IOException exp) {
|
||||
|
||||
@@ -762,6 +762,10 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
*/
|
||||
@Override
|
||||
public Destination lookup(String hostname, Properties lookupOptions, Properties storedOptions) {
|
||||
if (hostname.endsWith(".i2p.alt")) {
|
||||
// RFC 9476
|
||||
hostname = hostname.substring(0, hostname.length() - 4);
|
||||
}
|
||||
Destination rv = lookup2(hostname, lookupOptions, storedOptions);
|
||||
if (rv == null) {
|
||||
// if hostname starts with "www.", strip and try again
|
||||
@@ -793,7 +797,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
if (d != null)
|
||||
return d;
|
||||
// Base32 failed?
|
||||
if (hostname.length() == BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p"))
|
||||
if (hostname.length() >= BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p"))
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -844,7 +848,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
*/
|
||||
private List<Destination> lookupAll2(String hostname, Properties lookupOptions, List<Properties> storedOptions) {
|
||||
// only use cache for b32
|
||||
if (hostname.length() == BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
|
||||
if (hostname.length() >= BASE32_HASH_LENGTH + 8 && hostname.toLowerCase(Locale.US).endsWith(".b32.i2p")) {
|
||||
Destination d = super.lookup(hostname, null, null);
|
||||
if (d != null) {
|
||||
if (storedOptions != null)
|
||||
@@ -1431,6 +1435,8 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Broken prior to 0.9.62, would only return one name.
|
||||
*
|
||||
* @param options If non-null and contains the key "list", get
|
||||
* from that list (default "hosts.txt", NOT all lists)
|
||||
* Key "skip": skip that many entries
|
||||
@@ -1502,6 +1508,7 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter.next();
|
||||
if (search != null && key.indexOf(search) < 0)
|
||||
continue;
|
||||
rv.add(key);
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
The BlockfileNamingService based on the Metanotion BlockFile Database.
|
||||
This is the default NamingService for the router.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +1,7 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
@@ -8,10 +12,10 @@ sourceSets {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':router')
|
||||
compile project(':installer')
|
||||
compile project(':apps:systray')
|
||||
api project(':core')
|
||||
api project(':router')
|
||||
api project(':installer')
|
||||
api project(':apps:systray')
|
||||
}
|
||||
|
||||
// Create the java files from the po files. The jar task will compile them.
|
||||
|
||||
@@ -64,17 +64,24 @@
|
||||
</target>
|
||||
|
||||
<target name="listChangedFiles" depends="jarUpToDate" if="shouldListChanges" >
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
<exec executable="git" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="status" />
|
||||
<arg value="-s" />
|
||||
<arg value="--porcelain" />
|
||||
<arg value="-uno" />
|
||||
<arg value="." />
|
||||
</exec>
|
||||
<!-- trim flags -->
|
||||
<exec executable="sed" inputstring="${workspace.changes}" outputproperty="workspace.changes.sed" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/^[MTADRCU ]*//" />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes.sed}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile, bundle, listChangedFiles" unless="jar.uptodate" >
|
||||
@@ -108,7 +115,7 @@
|
||||
<not>
|
||||
<isset property="jar.uptodate" />
|
||||
</not>
|
||||
<isset property="mtn.available" />
|
||||
<isset property="git.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
|
||||
@@ -4,14 +4,15 @@
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# slrslr, 2022
|
||||
# slrslr, 2021
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2021-07-08 09:41+0000\n"
|
||||
"Last-Translator: slrslr\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: slrslr, 2022\n"
|
||||
"Language-Team: Czech (http://www.transifex.com/otf/I2P/language/cs/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -26,69 +27,81 @@ msgstr "Spustit I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P startuje!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Startuji"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Spouštím I2P Browser"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Nastavit I2P Systémovou Lištu"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Zakázat"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Zapnout upozornění"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Vypnout upozornění"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Vypnout ikonu systémové lišty"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr "Restart I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr "Zastavit I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Restartovat I2P Hned"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Zastavit I2P Hned"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Zrušit I2P Zastavení"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Zastavení za {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Vypínání"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr "Síť"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Pravé-kliknutí pro menu"
|
||||
|
||||
@@ -7,14 +7,15 @@
|
||||
# blabla <blabla@trash-mail.com>, 2011
|
||||
# Ettore Atalan <atalanttore@googlemail.com>, 2016
|
||||
# foo <foo@bar>, 2009
|
||||
# Georg Stadler, 2022
|
||||
# Lars Schimmer <echelon@i2pmail.org>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: Lars Schimmer <echelon@i2pmail.org>\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Georg Stadler, 2022\n"
|
||||
"Language-Team: German (http://www.transifex.com/otf/I2P/language/de/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -29,69 +30,81 @@ msgstr "I2P starten"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P startet gerade!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Startend"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P-Browser öffnen"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "I2P System Tray konfigurieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Deaktivieren"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Benachrichtigungen aktivieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Benachrichtigungen deaktivieren"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P neustarten"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P beenden"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "I2P sofort neustarten"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "I2P sofort beenden"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Herunterfahren von I2P abbrechen"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Herunterfahren in {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Herunterfahren bevorstehend"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr "Netzwerk"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Rechtsklick für Menü"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P desktopgui\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2010-06-15 14:09+0100\n"
|
||||
"Last-Translator: duck <duck@mail.i2p>\n"
|
||||
"Language-Team: duck <duck@mail.i2p>\n"
|
||||
@@ -19,87 +19,84 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
msgid "Restart I2P"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
msgid "Stop I2P"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
msgid "Shutdown imminent"
|
||||
msgstr ""
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
msgid "Network"
|
||||
msgstr ""
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr ""
|
||||
|
||||
@@ -6,21 +6,22 @@
|
||||
# Translators:
|
||||
# ducki2p <ducki2p@gmail.com>, 2011
|
||||
# foo <foo@bar>, 2009
|
||||
# punkibastardo <punkibastardo@gmail.com>, 2011
|
||||
# Juan Jaramillo <juanda097@protonmail.ch>, 2022
|
||||
# punkibastardo <transifex.symons@slmail.me>, 2011
|
||||
# strel, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: strel\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Juan Jaramillo <juanda097@protonmail.ch>, 2022\n"
|
||||
"Language-Team: Spanish (http://www.transifex.com/otf/I2P/language/es/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
@@ -29,69 +30,81 @@ msgstr "Iniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P está iniciando!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Iniciando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lanzar navegador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar la bandeja de sistema de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Deshabilitar"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Activar las notificaciones"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Desactivar las notificaciones"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Desactivar la bandeja del sistema"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reiniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr "Detener I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Reiniciar I2P inmediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Detener I2P inmediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar el cierre de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Cierre en {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Cierre inminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr "Red"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Clic secundario para menú"
|
||||
|
||||
@@ -9,15 +9,15 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-11-16 15:29+0000\n"
|
||||
"Last-Translator: kaze kaze <kaze@rlab.be>\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: kaze kaze <kaze@rlab.be>, 2017\n"
|
||||
"Language-Team: Spanish (Argentina) (http://www.transifex.com/otf/I2P/language/es_AR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_AR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
@@ -26,69 +26,81 @@ msgstr "Iniciando I2P..."
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P esta iniciando!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Iniciando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lanzar el Navegador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar la Bandeja de Sistema de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Deshabilitar"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Activar las notificaciones"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Desactivar las notificaciones"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Desactivar la bandeja del sistema"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr "Riniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr "Detener I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr " Reiniciar I2P inmediatamente "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr " Detener I2P inmediatamente "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar el Apagado de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Apagar en {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Apagado inminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr "Red"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P Clic derecho para el menú"
|
||||
|
||||
@@ -13,19 +13,20 @@
|
||||
# AO <ao@localizationlab.org>, 2017
|
||||
# Boxoa590, 2013
|
||||
# Towinet, 2016
|
||||
# vex vex, 2022
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2019-12-03 16:10+0000\n"
|
||||
"Last-Translator: AO <ao@localizationlab.org>\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: vex vex, 2022\n"
|
||||
"Language-Team: French (http://www.transifex.com/otf/I2P/language/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fr\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
@@ -34,69 +35,81 @@ msgstr "Démarrer I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P démarre !"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Démarrage"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lancer le navigateur d’I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurer la zone de notification d’I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Désactiver"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Activer les notifications"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Désactiver les notifications"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Désactiver la zone de notification"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr "Redémarrer I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr "Arrêter I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Redémarrer I2P immédiatement"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Arrêter I2P immédiatement"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Annuler la fermeture d’I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Fermeture dans {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "La fermeture est imminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr "Réseau"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P : clic droit pour obtenir le menu"
|
||||
|
||||
102
apps/desktopgui/locale/messages_gan.po
Normal file
102
apps/desktopgui/locale/messages_gan.po
Normal file
@@ -0,0 +1,102 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: duck <duck@mail.i2p>\n"
|
||||
"Language-Team: Chinese (Gan) (http://app.transifex.com/otf/I2P/language/gan/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: gan\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
msgid "Start I2P"
|
||||
msgstr "啟動I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr " I2P 正在启动!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "開始"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "启动 I2P 浏览器"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "設定I2P系統文件夾"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "禁用系统托盘"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
msgid "Restart I2P"
|
||||
msgstr "重啟I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
msgid "Stop I2P"
|
||||
msgstr "停止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "強制重啟I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "強制終止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "取消停止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "關閉於 {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "強制關閉"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
msgid "Network"
|
||||
msgstr "网络"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P:右鍵開啟選單"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "启用通知"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "禁用通知"
|
||||
@@ -5,13 +5,14 @@
|
||||
#
|
||||
# Translators:
|
||||
# Hunor Paksy <heds@cock.li>, 2018
|
||||
# vargaviktor <viktor.varga@gmail.com>, 2022
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2021-06-20 09:44+0000\n"
|
||||
"Last-Translator: AdminLMH <lehetmashogy@i2pmail.org>\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: vargaviktor <viktor.varga@gmail.com>, 2022\n"
|
||||
"Language-Team: Hungarian (http://www.transifex.com/otf/I2P/language/hu/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -26,69 +27,81 @@ msgstr "I2P indítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P indul!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "indítás"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P Böngésző Indítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "I2P rendszertálca beállítások"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Kikapcsol"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Értesítések engedélyezése"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Értesítések tiltása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Tálcaikon letiltása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P Újraindítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P Leállítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "I2P Azonnali újraindítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "I2P Azonnali megállítása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "I2P leállításának visszavonása"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Kikapcsolás: {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Kikapcsolás hamarosan"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr "Hálózat"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Jobb-klikk a menüért"
|
||||
|
||||
@@ -4,16 +4,17 @@
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Adrian Achyar, 2024
|
||||
# Khairul Agasta <khairuldroids@gmail.com>, 2014
|
||||
# Robert Dafis <robertdafis@gmail.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-07-27 00:14+0000\n"
|
||||
"Last-Translator: Robert Dafis <robertdafis@gmail.com>\n"
|
||||
"Language-Team: Indonesian (http://www.transifex.com/otf/I2P/language/id/)\n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Adrian Achyar, 2024\n"
|
||||
"Language-Team: Indonesian (http://app.transifex.com/otf/I2P/language/id/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -21,75 +22,84 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Mulai I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P sudah memulai!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Memulai"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Luncurkan Peramban I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Ubah pengaturan I2P System Tray"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Matikan"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Nonaktifkan system tray"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
msgid "Restart I2P"
|
||||
msgstr "Mulai ulang I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
msgid "Stop I2P"
|
||||
msgstr "Hentikan I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Ulang kembali I2P sekarang"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Hentikan I2P sekarang"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Batal tutup I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Mematikan I2P dalam {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "I2P sedang dalam proses dimatikan"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
msgid "Network"
|
||||
msgstr "Jaringan"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: klik kanan untuk menampilkan menu"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Aktifkan notifikasi"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Nonaktifkan notifikasi"
|
||||
|
||||
@@ -8,91 +8,101 @@
|
||||
# mkkid <jokjok@hotmail.it>, 2011
|
||||
# Leelium <bovas85@gmail.com>, 2012
|
||||
# mkkid <jokjok@hotmail.it>, 2011
|
||||
# Sebastiano Pistore <SebastianoPistore.info@protonmail.ch>, 2016-2017
|
||||
# SebastianoPistore <SebastianoPistore.info@protonmail.ch>, 2016-2017
|
||||
# V 41bis, 2023
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-07-30 07:04+0000\n"
|
||||
"Last-Translator: Sebastiano Pistore <SebastianoPistore.info@protonmail.ch>\n"
|
||||
"Language-Team: Italian (http://www.transifex.com/otf/I2P/language/it/)\n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: V 41bis, 2023\n"
|
||||
"Language-Team: Italian (http://app.transifex.com/otf/I2P/language/it/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: it\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Avvia I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Avvio di I2P in corso!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Avvio in corso"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lancia il browser I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configura icona di I2P nella Barra di notifica"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Disabilita"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Disattiva l'icona nella barra di Notifica"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
msgid "Restart I2P"
|
||||
msgstr "Riavvia I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
msgid "Stop I2P"
|
||||
msgstr "Arresta I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Riavvia subito I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Arresta subito I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Annulla arresto di I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Arresto in {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Arresto imminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
msgid "Network"
|
||||
msgstr "Rete"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Fai click destro per aprire il menu"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Attiva le notifiche"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Disattiva le notifiche"
|
||||
|
||||
@@ -6,14 +6,15 @@
|
||||
# Translators:
|
||||
# Allan Nordhøy <epost@anotheragency.no>, 2014
|
||||
# Allan Nordhøy <epost@anotheragency.no>, 2017
|
||||
# Imre Kristoffer Eilertsen <imreeil42@gmail.com>, 2022-2023
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-09-19 14:52+0000\n"
|
||||
"Last-Translator: Allan Nordhøy <epost@anotheragency.no>\n"
|
||||
"Language-Team: Norwegian Bokmål (http://www.transifex.com/otf/I2P/language/nb/)\n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Imre Kristoffer Eilertsen <imreeil42@gmail.com>, 2022-2023\n"
|
||||
"Language-Team: Norwegian Bokmål (http://app.transifex.com/otf/I2P/language/nb/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -21,75 +22,84 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Start I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P starter opp!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Starter opp"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Kjør I2P-nettleser"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Sett opp I2P-systemkruv"
|
||||
msgstr "Sett opp I2P-systemkurv"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Skru av"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Skru av systemkurven"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
msgid "Restart I2P"
|
||||
msgstr "Omstart av I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
msgid "Stop I2P"
|
||||
msgstr "Stopp I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Umiddelbar omstart av I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Umiddelbar stopp av I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Avbryt nedstenging av I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Skrur av om {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Skru av med en gang"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
msgid "Network"
|
||||
msgstr "Nettverk"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "Høyreklikk-meny i I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Skru på varsler"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Skru av varsler"
|
||||
|
||||
@@ -6,14 +6,15 @@
|
||||
# Translators:
|
||||
# PolishAnon <b790979@klzlk.com>, 2011
|
||||
# polacco <polacco@i2pmail.org>, 2015
|
||||
# Verdulo :-), 2016
|
||||
# ☆Verdulo, 2016
|
||||
# Waldemar Napora, 2022
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: Verdulo :-)\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Waldemar Napora, 2022\n"
|
||||
"Language-Team: Polish (http://www.transifex.com/otf/I2P/language/pl/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -28,69 +29,81 @@ msgstr "Uruchom I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Uruchamianie I2P!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Uruchamianie"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Uruchom przeglądarkę I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Konfiguruj I2P w zasobniku systemowym"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Wyłącz"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "Włącz powiadomenia"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "Wyłącz powiadomienia"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "Wyłącz zasobnik systemowy"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr "Zrestartuj I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr "Zatrzymaj I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Zrestartuj I2P natychmiast"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Wyłącz I2P natychmiast"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Anuluj zamykanie I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Wyłączenie za {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Zaraz zamknę"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr "Sieć"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: kliknij prawym aby otworzyć menu"
|
||||
|
||||
@@ -4,93 +4,102 @@
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Manuela Silva <manuela.silva@sky.com>, 2016
|
||||
# wicked, 2013
|
||||
# wicked, 2012
|
||||
# Manuela Silva <mmsrs@sky.com>, 2016
|
||||
# 1c13465e24d91aca4d3ddaa1bc3e7027_ae6ba28, 2013
|
||||
# 1c13465e24d91aca4d3ddaa1bc3e7027_ae6ba28, 2012
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: Manuela Silva <manuela.silva@sky.com>\n"
|
||||
"Language-Team: Portuguese (http://www.transifex.com/otf/I2P/language/pt/)\n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Manuela Silva <mmsrs@sky.com>, 2016\n"
|
||||
"Language-Team: Portuguese (http://app.transifex.com/otf/I2P/language/pt/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Iniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P está a iniciar!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "A Iniciar"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Iniciar o browser I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar Bandeja do Sistema do I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Desativar"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Desativar bandeja do sistema"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reiniciar o I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
msgid "Stop I2P"
|
||||
msgstr "Parar o I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Reiniciar o I2P imediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Parar o I2P de imediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar Encerramento do I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Encerramento em {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Encerramento eminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
msgid "Network"
|
||||
msgstr "Rede"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Clique direito para menu"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Ativar notificações"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Desativar notificações"
|
||||
|
||||
@@ -4,94 +4,105 @@
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Cauan Henrique Zorzenon <cauanzorzenon@gmail.com>, 2023
|
||||
# testsubject67 <deborinha97@hotmail.com>, 2014
|
||||
# blueboy, 2013
|
||||
# blueboy, 2015
|
||||
# ce4434973f224b33f2ea48f4556be467_f116f03, 2022
|
||||
# L., 2013
|
||||
# L., 2015
|
||||
# Rafael Ferrari, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: Rafael Ferrari\n"
|
||||
"Language-Team: Portuguese (Brazil) (http://www.transifex.com/otf/I2P/language/pt_BR/)\n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Cauan Henrique Zorzenon <cauanzorzenon@gmail.com>, 2023\n"
|
||||
"Language-Team: Portuguese (Brazil) (http://app.transifex.com/otf/I2P/language/pt_BR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: pt_BR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Conectar-se à I2P"
|
||||
msgstr "Iniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "Conectando-se a I2P!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Conectando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lançar o navegador I2P "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar o ícone de sistema I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Desabilitar"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Desativar bandeja do sistema"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
msgid "Restart I2P"
|
||||
msgstr "Reinicializar o roteador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
msgid "Stop I2P"
|
||||
msgstr "Interromper o roteador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Reinicializar o I2P Imediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Parar o I2P Imediatamente"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar o desligamento do I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Desligando em {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Desligando agora"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
msgid "Network"
|
||||
msgstr "Rede"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Clique com o botão direito para o menu"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Ativar notificações"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Desativar notificações"
|
||||
|
||||
@@ -9,14 +9,15 @@
|
||||
# foo <foo@bar>, 2009
|
||||
# Foster Snowhill, 2013
|
||||
# brianhopes <voganc-12@live.ru>, 2015
|
||||
# Артём Котлубай <artemkotlubai@yandex.ru>, 2023
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: c4sp3r\n"
|
||||
"Language-Team: Russian (Russia) (http://www.transifex.com/otf/I2P/language/ru_RU/)\n"
|
||||
"POT-Creation-Date: 2023-03-06 14:52+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: Артём Котлубай <artemkotlubai@yandex.ru>, 2023\n"
|
||||
"Language-Team: Russian (Russia) (http://app.transifex.com/otf/I2P/language/ru_RU/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -24,75 +25,84 @@ msgstr ""
|
||||
"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Запустить I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P запускается!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "Запускается"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:221
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Запустить браузер I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:242
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Настроить системный трей I2P"
|
||||
msgstr "Настроить область уведомлений"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Отключить"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:88
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:244
|
||||
msgid "Disable system tray"
|
||||
msgstr "Убрать значок из области уведомлений"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:104
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:260
|
||||
msgid "Restart I2P"
|
||||
msgstr "Перезапустить I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:121
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:277
|
||||
msgid "Stop I2P"
|
||||
msgstr "Остановить I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:137
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:293
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Перезапустить I2P немедленно"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:154
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:310
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Остановить I2P немедленно"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:168
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:324
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Отменить выключение I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:381
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Выключение через {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:383
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Неотменяемое выключение"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:388
|
||||
msgid "Network"
|
||||
msgstr "Сеть"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:75
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Правый щелчок для вызова меню"
|
||||
msgstr "I2P: ПКМ для вызова меню"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:310
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:347
|
||||
msgid "Enable notifications"
|
||||
msgstr "Включить уведомления"
|
||||
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:325
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:362
|
||||
msgid "Disable notifications"
|
||||
msgstr "Отключить уведомления"
|
||||
|
||||
@@ -9,9 +9,9 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2018-10-04 00:43+0000\n"
|
||||
"Last-Translator: erinm\n"
|
||||
"POT-Creation-Date: 2022-02-09 19:13+0000\n"
|
||||
"PO-Revision-Date: 2011-02-13 12:05+0000\n"
|
||||
"Last-Translator: 黃彥儒 <r1235613@gmail.com>, 2017\n"
|
||||
"Language-Team: Chinese (Taiwan) (http://www.transifex.com/otf/I2P/language/zh_TW/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -26,69 +26,81 @@ msgstr "啟動I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P已啟動"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
msgid "Starting"
|
||||
msgstr "啟動中"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:65
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:249
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "開啟I2P瀏覽器"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:86
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:270
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "設定I2P系統文件夾"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "停用"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:87
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:271
|
||||
msgid "Enable notifications"
|
||||
msgstr "启用通知"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:101
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:285
|
||||
msgid "Disable notifications"
|
||||
msgstr "禁用通知"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:115
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:299
|
||||
msgid "Disable system tray"
|
||||
msgstr "禁用系统托盘"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:131
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:315
|
||||
msgid "Restart I2P"
|
||||
msgstr "重啟I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:148
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:332
|
||||
msgid "Stop I2P"
|
||||
msgstr "停止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:164
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:348
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "強制重啟I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:181
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "強制終止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:195
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:379
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "取消停止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:437
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "關閉於 {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:439
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "強制關閉"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:444
|
||||
msgid "Network"
|
||||
msgstr "網路"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:73
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P:右鍵開啟選單"
|
||||
|
||||
312
apps/desktopgui/src/net/i2p/desktopgui/ExternalMain.java
Normal file
312
apps/desktopgui/src/net/i2p/desktopgui/ExternalMain.java
Normal file
@@ -0,0 +1,312 @@
|
||||
package net.i2p.desktopgui;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.Toolkit;
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientApp;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import net.i2p.app.MenuCallback;
|
||||
import net.i2p.app.MenuHandle;
|
||||
import net.i2p.app.MenuService;
|
||||
import net.i2p.app.NotificationService;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SystemVersion;
|
||||
|
||||
/**
|
||||
* A simplified Main that does not require router.jar, for App Context only.
|
||||
* Invokes ExternalTrayManager only.
|
||||
* No state tracking, ClientAppManager doesn't care.
|
||||
*
|
||||
* @since 0.9.54
|
||||
*/
|
||||
public class ExternalMain implements ClientApp, NotificationService, MenuService {
|
||||
|
||||
private final I2PAppContext _appContext;
|
||||
private final ClientAppManager _mgr;
|
||||
private final Log log;
|
||||
private TrayManager _trayManager;
|
||||
|
||||
private static final String PROP_SWING = "desktopgui.swing";
|
||||
|
||||
public ExternalMain(I2PAppContext ctx, ClientAppManager mgr, String args[]) {
|
||||
_appContext = ctx;
|
||||
_mgr = mgr;
|
||||
log = _appContext.logManager().getLog(ExternalMain.class);
|
||||
}
|
||||
|
||||
public ExternalMain() {
|
||||
_appContext = I2PAppContext.getGlobalContext();
|
||||
_mgr = _appContext.clientAppManager();
|
||||
log = _appContext.logManager().getLog(ExternalMain.class);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// early check so we can bail out when started via CLI
|
||||
if (!SystemTray.isSupported()) {
|
||||
System.err.println("SystemTray not supported");
|
||||
return;
|
||||
}
|
||||
ExternalMain main = new ExternalMain();
|
||||
main.beginStartup(args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the tray icon code (loads tray icon in the tray area).
|
||||
* @throws AWTException on startup error, including systray not supported
|
||||
*/
|
||||
private synchronized void startUp() throws Exception {
|
||||
boolean useSwingDefault = !(SystemVersion.isWindows() || SystemVersion.isMac());
|
||||
boolean useSwing = _appContext.getProperty(PROP_SWING, useSwingDefault);
|
||||
_trayManager = new ExternalTrayManager(_appContext, useSwing);
|
||||
_trayManager.startManager();
|
||||
if (_mgr != null)
|
||||
_mgr.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main method launching the application.
|
||||
*
|
||||
* @param args unused
|
||||
*/
|
||||
private void beginStartup(String[] args) {
|
||||
String headless = System.getProperty("java.awt.headless");
|
||||
boolean isHeadless = Boolean.parseBoolean(headless);
|
||||
if (isHeadless) {
|
||||
log.warn("Headless environment: not starting desktopgui!");
|
||||
return;
|
||||
}
|
||||
if (SystemVersion.isMac())
|
||||
setMacTrayIcon();
|
||||
launchForeverLoop();
|
||||
|
||||
// We'll be doing GUI work, so let's stay in the event dispatcher thread.
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
startUp();
|
||||
} catch(Exception e) {
|
||||
log.error("Failed while running desktopgui!", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Unless we do this, when we start DesktopGUI we get a Java coffee cup
|
||||
* in the tray.
|
||||
*
|
||||
* Based on code from https://gist.github.com/bchapuis/1562406 , no apparent license.
|
||||
* See also https://stackoverflow.com/questions/6006173/how-do-you-change-the-dock-icon-of-a-java-program
|
||||
*
|
||||
* TODO, if we wanted to add our own menu, see
|
||||
* https://stackoverflow.com/questions/1319805/java-os-x-dock-menu
|
||||
*
|
||||
* TODO, if we want to make it bounce, see
|
||||
* https://stackoverflow.com/questions/15079783/how-to-make-my-app-icon-bounce-in-the-mac-dock
|
||||
*
|
||||
* TODO, if we want to handle Quit, see
|
||||
* https://nakkaya.com/2009/04/19/java-osx-integration/
|
||||
*
|
||||
* @since 0.9.33
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void setMacTrayIcon() {
|
||||
File f = new File(_appContext.getBaseDir(), "docs/themes/console/images/itoopie_sm.png");
|
||||
if (!f.exists())
|
||||
return;
|
||||
try {
|
||||
Class util = Class.forName("com.apple.eawt.Application");
|
||||
Method getApplication = util.getMethod("getApplication", new Class[0]);
|
||||
Object application = getApplication.invoke(util);
|
||||
Class params[] = new Class[1];
|
||||
params[0] = Image.class;
|
||||
Method setDockIconImage = util.getMethod("setDockIconImage", params);
|
||||
URL url = f.toURI().toURL();
|
||||
Image image = Toolkit.getDefaultToolkit().getImage(url);
|
||||
setDockIconImage.invoke(application, image);
|
||||
} catch (Exception e) {
|
||||
if (log.shouldWarn())
|
||||
log.warn("Can't set OSX Dock icon", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Avoids the app terminating because no Window is opened anymore.
|
||||
* More info: http://java.sun.com/javase/6/docs/api/java/awt/doc-files/AWTThreadIssues.html#Autoshutdown
|
||||
*/
|
||||
private static void launchForeverLoop() {
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
Object o = new Object();
|
||||
synchronized (o) {
|
||||
o.wait();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
};
|
||||
Thread t = new Thread(r, "DesktopGUI spinner");
|
||||
t.setDaemon(false);
|
||||
t.start();
|
||||
}
|
||||
|
||||
/////// NotificationService methods
|
||||
|
||||
/**
|
||||
* Send a notification to the user.
|
||||
*
|
||||
* @param source unsupported
|
||||
* @param category unsupported
|
||||
* @param priority unsupported
|
||||
* @param title for the popup, translated
|
||||
* @param message translated
|
||||
* @param path unsupported
|
||||
* @return 0, or -1 on failure
|
||||
*/
|
||||
public int notify(String source, String category, int priority, String title, String message, String path) {
|
||||
TrayManager tm = _trayManager;
|
||||
if (tm == null)
|
||||
return -1;
|
||||
return tm.displayMessage(priority, title, message, path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a notification if possible.
|
||||
* Unsupported.
|
||||
*
|
||||
* @return false always
|
||||
*/
|
||||
public boolean cancel(int id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the text of a notification if possible.
|
||||
* Unsupported.
|
||||
*
|
||||
* @return false always
|
||||
*/
|
||||
public boolean update(int id, String title, String message, String path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/////// MenuService methods
|
||||
|
||||
/**
|
||||
* Menu will start out shown and enabled, in the root menu
|
||||
*
|
||||
* @param message for the menu, translated
|
||||
* @param callback fired on click
|
||||
* @return null on error
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, MenuCallback callback) {
|
||||
return addMenu(message, callback, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu will start out enabled, as a submenu
|
||||
*
|
||||
* @param message for the menu, translated
|
||||
* @param callback fired on click
|
||||
* @param parent the parent menu this will be a submenu of, or null for top level
|
||||
* @return null on error
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, MenuCallback callback, MenuHandle parent) {
|
||||
if (_trayManager == null)
|
||||
return null;
|
||||
return _trayManager.addMenu(message, callback, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void removeMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.removeMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void showMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.showMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void hideMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.hideMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void enableMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.enableMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void disableMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.disableMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void updateMenu(String message, MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.updateMenu(message, item);
|
||||
}
|
||||
|
||||
/////// ClientApp methods
|
||||
|
||||
public synchronized void startup() {
|
||||
beginStartup(null);
|
||||
}
|
||||
|
||||
public synchronized void shutdown(String[] args) {
|
||||
if (_trayManager != null)
|
||||
_trayManager.stopManager();
|
||||
}
|
||||
|
||||
public ClientAppState getState() {
|
||||
return ClientAppState.INITIALIZED;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "desktopgui";
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return "Desktop GUI";
|
||||
}
|
||||
|
||||
/////// end ClientApp methods
|
||||
}
|
||||
@@ -22,8 +22,8 @@ import net.i2p.desktopgui.router.RouterManager;
|
||||
*/
|
||||
class ExternalTrayManager extends TrayManager {
|
||||
|
||||
public ExternalTrayManager(I2PAppContext ctx, Main main, boolean useSwing) {
|
||||
super(ctx, main, useSwing);
|
||||
public ExternalTrayManager(I2PAppContext ctx, boolean useSwing) {
|
||||
super(ctx, useSwing);
|
||||
}
|
||||
|
||||
public PopupMenu getMainMenu() {
|
||||
@@ -51,11 +51,15 @@ class ExternalTrayManager extends TrayManager {
|
||||
}
|
||||
});
|
||||
popup.add(startItem);
|
||||
initializeNotificationItems();
|
||||
popup.add(_notificationItem2);
|
||||
popup.add(_notificationItem1);
|
||||
return popup;
|
||||
}
|
||||
|
||||
public JPopupMenu getSwingMainMenu() {
|
||||
JPopupMenu popup = new JPopupMenu();
|
||||
/*
|
||||
JMenuItem startItem = new JMenuItem(_t("Start I2P"));
|
||||
startItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
@@ -79,6 +83,10 @@ class ExternalTrayManager extends TrayManager {
|
||||
}
|
||||
});
|
||||
popup.add(startItem);
|
||||
*/
|
||||
initializeJNotificationItems();
|
||||
popup.add(_jnotificationItem2);
|
||||
popup.add(_jnotificationItem1);
|
||||
return popup;
|
||||
}
|
||||
|
||||
@@ -86,5 +94,14 @@ class ExternalTrayManager extends TrayManager {
|
||||
* Update the menu
|
||||
* @since 0.9.26
|
||||
*/
|
||||
protected void updateMenu() {}
|
||||
protected void updateMenu() {
|
||||
if (_notificationItem1 != null)
|
||||
_notificationItem1.setEnabled(_showNotifications);
|
||||
if (_notificationItem2 != null)
|
||||
_notificationItem2.setEnabled(!_showNotifications);
|
||||
if (_jnotificationItem1 != null)
|
||||
_jnotificationItem1.setVisible(_showNotifications);
|
||||
if (_jnotificationItem2 != null)
|
||||
_jnotificationItem2.setVisible(!_showNotifications);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,20 +30,20 @@ class InternalTrayManager extends TrayManager {
|
||||
|
||||
private final RouterContext _context;
|
||||
private final Log log;
|
||||
private final Main _main;
|
||||
private MenuItem _statusItem, _browserItem, _configItem, _restartItem, _stopItem,
|
||||
_restartHardItem, _stopHardItem, _cancelItem,
|
||||
_notificationItem1, _notificationItem2;
|
||||
_restartHardItem, _stopHardItem, _cancelItem;
|
||||
private JMenuItem _jstatusItem, _jbrowserItem, _jconfigItem, _jrestartItem, _jstopItem,
|
||||
_jrestartHardItem, _jstopHardItem, _jcancelItem,
|
||||
_jnotificationItem1, _jnotificationItem2;
|
||||
_jrestartHardItem, _jstopHardItem, _jcancelItem;
|
||||
|
||||
private static final boolean CONSOLE_ENABLED = Desktop.isDesktopSupported() &&
|
||||
Desktop.getDesktop().isSupported(Action.BROWSE);
|
||||
private static final String CONSOLE_BUNDLE_NAME = "net.i2p.router.web.messages";
|
||||
|
||||
public InternalTrayManager(RouterContext ctx, Main main, boolean useSwing) {
|
||||
super(ctx, main, useSwing);
|
||||
super(ctx, useSwing);
|
||||
_context = ctx;
|
||||
_main = main;
|
||||
log = ctx.logManager().getLog(InternalTrayManager.class);
|
||||
}
|
||||
|
||||
@@ -84,33 +84,6 @@ class InternalTrayManager extends TrayManager {
|
||||
}
|
||||
|
||||
PopupMenu desktopguiConfigurationLauncher = new PopupMenu(_t("Configure I2P System Tray"));
|
||||
final MenuItem notificationItem2 = new MenuItem(_t("Enable notifications"));
|
||||
notificationItem2.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(true);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
|
||||
final MenuItem notificationItem1 = new MenuItem(_t("Disable notifications"));
|
||||
notificationItem1.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(false);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
|
||||
MenuItem configSubmenu = new MenuItem(_t("Disable system tray"));
|
||||
configSubmenu.addActionListener(new ActionListener() {
|
||||
@@ -212,8 +185,9 @@ class InternalTrayManager extends TrayManager {
|
||||
popup.add(browserLauncher);
|
||||
popup.addSeparator();
|
||||
}
|
||||
desktopguiConfigurationLauncher.add(notificationItem2);
|
||||
desktopguiConfigurationLauncher.add(notificationItem1);
|
||||
initializeNotificationItems();
|
||||
desktopguiConfigurationLauncher.add(_notificationItem2);
|
||||
desktopguiConfigurationLauncher.add(_notificationItem1);
|
||||
desktopguiConfigurationLauncher.add(configSubmenu);
|
||||
popup.add(desktopguiConfigurationLauncher);
|
||||
popup.addSeparator();
|
||||
@@ -228,8 +202,6 @@ class InternalTrayManager extends TrayManager {
|
||||
_statusItem = statusItem;
|
||||
_browserItem = browserLauncher;
|
||||
_configItem = desktopguiConfigurationLauncher;
|
||||
_notificationItem1 = notificationItem1;
|
||||
_notificationItem2 = notificationItem2;
|
||||
_restartItem = restartItem;
|
||||
_stopItem = stopItem;
|
||||
_restartHardItem = restartItem2;
|
||||
@@ -268,33 +240,6 @@ class InternalTrayManager extends TrayManager {
|
||||
}
|
||||
|
||||
JMenu desktopguiConfigurationLauncher = new JMenu(_t("Configure I2P System Tray"));
|
||||
final JMenuItem notificationItem2 = new JMenuItem(_t("Enable notifications"));
|
||||
notificationItem2.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(true);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
|
||||
final JMenuItem notificationItem1 = new JMenuItem(_t("Disable notifications"));
|
||||
notificationItem1.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(false);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
|
||||
JMenuItem configSubmenu = new JMenuItem(_t("Disable system tray"));
|
||||
configSubmenu.addActionListener(new ActionListener() {
|
||||
@@ -396,8 +341,9 @@ class InternalTrayManager extends TrayManager {
|
||||
popup.add(browserLauncher);
|
||||
popup.addSeparator();
|
||||
}
|
||||
desktopguiConfigurationLauncher.add(notificationItem2);
|
||||
desktopguiConfigurationLauncher.add(notificationItem1);
|
||||
initializeJNotificationItems();
|
||||
desktopguiConfigurationLauncher.add(_jnotificationItem2);
|
||||
desktopguiConfigurationLauncher.add(_jnotificationItem1);
|
||||
desktopguiConfigurationLauncher.add(configSubmenu);
|
||||
popup.add(desktopguiConfigurationLauncher);
|
||||
popup.addSeparator();
|
||||
@@ -412,8 +358,6 @@ class InternalTrayManager extends TrayManager {
|
||||
_jstatusItem = statusItem;
|
||||
_jbrowserItem = browserLauncher;
|
||||
_jconfigItem = desktopguiConfigurationLauncher;
|
||||
_jnotificationItem1 = notificationItem1;
|
||||
_jnotificationItem2 = notificationItem2;
|
||||
_jrestartItem = restartItem;
|
||||
_jstopItem = stopItem;
|
||||
_jrestartHardItem = restartItem2;
|
||||
@@ -509,7 +453,8 @@ class InternalTrayManager extends TrayManager {
|
||||
/**
|
||||
* @since 0.9.53
|
||||
*/
|
||||
private void configureNotifications(boolean enable) {
|
||||
@Override
|
||||
protected void configureNotifications(boolean enable) {
|
||||
_showNotifications = enable;
|
||||
String value = Boolean.toString(enable);
|
||||
if (!_context.router().saveConfig(PROP_NOTIFICATIONS, value))
|
||||
|
||||
@@ -17,6 +17,9 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import static net.i2p.app.ClientAppState.*;
|
||||
import net.i2p.app.MenuCallback;
|
||||
import net.i2p.app.MenuHandle;
|
||||
import net.i2p.app.MenuService;
|
||||
import net.i2p.app.NotificationService;
|
||||
import net.i2p.desktopgui.router.RouterManager;
|
||||
import net.i2p.router.RouterContext;
|
||||
@@ -29,7 +32,7 @@ import net.i2p.util.I2PProperties.I2PPropertyCallback;
|
||||
/**
|
||||
* The main class of the application.
|
||||
*/
|
||||
public class Main implements RouterApp, NotificationService {
|
||||
public class Main implements RouterApp, NotificationService, MenuService {
|
||||
|
||||
// non-null
|
||||
private final I2PAppContext _appContext;
|
||||
@@ -57,7 +60,7 @@ public class Main implements RouterApp, NotificationService {
|
||||
*/
|
||||
public Main() {
|
||||
_appContext = I2PAppContext.getGlobalContext();
|
||||
if (_appContext instanceof RouterContext)
|
||||
if (_appContext.isRouterContext())
|
||||
_context = (RouterContext) _appContext;
|
||||
else
|
||||
_context = null;
|
||||
@@ -77,7 +80,7 @@ public class Main implements RouterApp, NotificationService {
|
||||
if (_context != null)
|
||||
trayManager = new InternalTrayManager(_context, this, useSwing);
|
||||
else
|
||||
trayManager = new ExternalTrayManager(_appContext, this, useSwing);
|
||||
trayManager = new ExternalTrayManager(_appContext, useSwing);
|
||||
trayManager.startManager();
|
||||
_trayManager = trayManager;
|
||||
changeState(RUNNING);
|
||||
@@ -245,6 +248,89 @@ public class Main implements RouterApp, NotificationService {
|
||||
return false;
|
||||
}
|
||||
|
||||
/////// MenuService methods
|
||||
|
||||
/**
|
||||
* Menu will start out shown and enabled, in the root menu
|
||||
*
|
||||
* @param message for the menu, translated
|
||||
* @param callback fired on click
|
||||
* @return null on error
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, MenuCallback callback) {
|
||||
return addMenu(message, callback, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu will start out enabled, as a submenu
|
||||
*
|
||||
* @param message for the menu, translated
|
||||
* @param callback fired on click
|
||||
* @param parent the parent menu this will be a submenu of, or null for top level
|
||||
* @return null on error
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, MenuCallback callback, MenuHandle parent) {
|
||||
if (_trayManager == null)
|
||||
return null;
|
||||
return _trayManager.addMenu(message, callback, parent);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void removeMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.removeMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void showMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.showMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void hideMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.hideMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void enableMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.enableMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void disableMenu(MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.disableMenu(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void updateMenu(String message, MenuHandle item) {
|
||||
if (_trayManager == null)
|
||||
return;
|
||||
_trayManager.updateMenu(message, item);
|
||||
}
|
||||
|
||||
/////// ClientApp methods
|
||||
|
||||
/** @since 0.9.26 */
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.awt.AWTException;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.MenuItem;
|
||||
import java.awt.PopupMenu;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.Toolkit;
|
||||
@@ -16,8 +17,12 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.event.MenuKeyEvent;
|
||||
@@ -26,6 +31,8 @@ import javax.swing.event.PopupMenuEvent;
|
||||
import javax.swing.event.PopupMenuListener;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.MenuCallback;
|
||||
import net.i2p.app.MenuHandle;
|
||||
import net.i2p.apps.systray.UrlLauncher;
|
||||
import net.i2p.desktopgui.i18n.DesktopguiTranslator;
|
||||
import net.i2p.util.Log;
|
||||
@@ -37,13 +44,17 @@ import net.i2p.util.SystemVersion;
|
||||
abstract class TrayManager {
|
||||
|
||||
protected final I2PAppContext _appContext;
|
||||
protected final Main _main;
|
||||
protected final boolean _useSwing;
|
||||
///The tray area, or null if unsupported
|
||||
protected SystemTray tray;
|
||||
///Our tray icon, or null if unsupported
|
||||
protected TrayIcon trayIcon;
|
||||
protected volatile boolean _showNotifications;
|
||||
protected MenuItem _notificationItem1, _notificationItem2;
|
||||
protected JMenuItem _jnotificationItem1, _jnotificationItem2;
|
||||
private final AtomicInteger _id = new AtomicInteger();
|
||||
private final List<MenuInternal> _menus;
|
||||
private JPopupMenu _jPopupMenu;
|
||||
|
||||
private static final String PNG_DIR = "/desktopgui/resources/images/";
|
||||
private static final String MAC_ICON = "itoopie_black_24.png";
|
||||
@@ -55,10 +66,10 @@ abstract class TrayManager {
|
||||
/**
|
||||
* Instantiate tray manager.
|
||||
*/
|
||||
protected TrayManager(I2PAppContext ctx, Main main, boolean useSwing) {
|
||||
protected TrayManager(I2PAppContext ctx, boolean useSwing) {
|
||||
_appContext = ctx;
|
||||
_main = main;
|
||||
_useSwing = useSwing;
|
||||
_menus = new ArrayList<MenuInternal>();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -107,6 +118,7 @@ abstract class TrayManager {
|
||||
frame.setMinimumSize(new Dimension(0, 0));
|
||||
frame.setSize(0, 0);
|
||||
final JPopupMenu menu = getSwingMainMenu();
|
||||
_jPopupMenu = menu;
|
||||
menu.setFocusable(true);
|
||||
frame.add(menu);
|
||||
TrayIcon ti = new TrayIcon(getTrayImage(), tooltip, null);
|
||||
@@ -290,6 +302,248 @@ abstract class TrayManager {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not save. See InternalTrayManager.
|
||||
*
|
||||
* @since 0.9.58 moved up from InternalTrayManager
|
||||
*/
|
||||
protected void configureNotifications(boolean enable) {
|
||||
_showNotifications = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes _notificationItem 1 and 2
|
||||
*
|
||||
* @since 0.9.58 pulled out of InternalTrayManager
|
||||
*/
|
||||
protected void initializeNotificationItems() {
|
||||
final MenuItem notificationItem2 = new MenuItem(_t("Enable notifications"));
|
||||
notificationItem2.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(true);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_notificationItem2 = notificationItem2;
|
||||
|
||||
final MenuItem notificationItem1 = new MenuItem(_t("Disable notifications"));
|
||||
notificationItem1.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(false);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_notificationItem1 = notificationItem1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes _jnotificationItem 1 and 2
|
||||
*
|
||||
* @since 0.9.58 pulled out of InternalTrayManager
|
||||
*/
|
||||
protected void initializeJNotificationItems() {
|
||||
final JMenuItem notificationItem2 = new JMenuItem(_t("Enable notifications"));
|
||||
notificationItem2.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(true);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_jnotificationItem2 = notificationItem2;
|
||||
|
||||
final JMenuItem notificationItem1 = new JMenuItem(_t("Disable notifications"));
|
||||
notificationItem1.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
configureNotifications(false);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_jnotificationItem1 = notificationItem1;
|
||||
}
|
||||
|
||||
/////// MenuService delegation methods
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public MenuHandle addMenu(String message, final MenuCallback callback, MenuHandle p) {
|
||||
MenuInternal parent = p != null ? (MenuInternal) p : null;
|
||||
final int id = _id.incrementAndGet();
|
||||
final MenuInternal rv;
|
||||
if (_useSwing) {
|
||||
final JMenuItem m = new JMenuItem(message);
|
||||
rv = new MenuInternal(null, m, callback, id);
|
||||
m.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
rv.cb.clicked(rv);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
_jPopupMenu.add(m);
|
||||
} else {
|
||||
final MenuItem m = new MenuItem(message);
|
||||
rv = new MenuInternal(m, null, callback, id);
|
||||
m.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
new SwingWorker<Object, Object>() {
|
||||
@Override
|
||||
protected Object doInBackground() throws Exception {
|
||||
rv.cb.clicked(rv);
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
trayIcon.getPopupMenu().add(m);
|
||||
}
|
||||
synchronized(_menus) {
|
||||
_menus.add(rv);
|
||||
}
|
||||
updateMenu();
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void removeMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
if (_useSwing) {
|
||||
_jPopupMenu.remove(mi.jm);
|
||||
} else {
|
||||
trayIcon.getPopupMenu().remove(mi.m);
|
||||
}
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void showMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setVisible(true);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void hideMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setVisible(false);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void enableMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setEnabled(true);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void disableMenu(MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setEnabled(false);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
public void updateMenu(String message, MenuHandle item) {
|
||||
MenuInternal mi = (MenuInternal) item;
|
||||
mi.setText(message);
|
||||
updateMenu();
|
||||
}
|
||||
|
||||
/////// MenuService internals
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
private MenuInternal getMenu(int id) {
|
||||
synchronized(_menus) {
|
||||
for (MenuInternal mi : _menus) {
|
||||
if (mi.getID() == id)
|
||||
return mi;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.59
|
||||
*/
|
||||
private static class MenuInternal implements MenuHandle {
|
||||
private final MenuItem m;
|
||||
private final JMenuItem jm;
|
||||
private final MenuCallback cb;
|
||||
private final int id;
|
||||
|
||||
public MenuInternal(MenuItem mm, JMenuItem jmm, MenuCallback cbb, int idd) {
|
||||
m = mm; jm = jmm; cb = cbb; id = idd;
|
||||
}
|
||||
|
||||
public int getID() { return id; }
|
||||
|
||||
private void setEnabled(boolean yes) {
|
||||
if (m != null)
|
||||
m.setEnabled(yes);
|
||||
else
|
||||
jm.setEnabled(yes);
|
||||
}
|
||||
|
||||
private void setVisible(boolean yes) {
|
||||
if (m != null)
|
||||
m.setEnabled(yes);
|
||||
else
|
||||
jm.setVisible(yes);
|
||||
}
|
||||
|
||||
private void setText(String text) {
|
||||
if (m != null)
|
||||
m.setLabel(text);
|
||||
else
|
||||
jm.setText(text);
|
||||
}
|
||||
}
|
||||
|
||||
protected String _t(String s) {
|
||||
return DesktopguiTranslator._t(_appContext, s);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'war'
|
||||
}
|
||||
|
||||
@@ -11,13 +12,15 @@ sourceSets {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
providedCompile project(':router')
|
||||
providedCompile project(':apps:jetty')
|
||||
providedCompile files('../../installer/lib/wrapper/all/wrapper.jar')
|
||||
api project(':router')
|
||||
api project(':apps:jetty')
|
||||
api files('../../installer/lib/wrapper/all/wrapper.jar')
|
||||
api fileTree("../jetty/apache-tomcat-${tomcatVersion}")
|
||||
api fileTree("../jetty/jetty-distribution-${jettyVersion}")
|
||||
}
|
||||
|
||||
war {
|
||||
archiveName 'jsonrpc.war'
|
||||
archiveBaseName.set('jsonrpc')
|
||||
webXml = file('web.xml')
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,29 @@
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
<target name="listChangedFiles" if="git.available" >
|
||||
<exec executable="git" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="status" />
|
||||
<arg value="-s" />
|
||||
<arg value="--porcelain" />
|
||||
<arg value="-uno" />
|
||||
<arg value="." />
|
||||
<arg value="../resources" />
|
||||
</exec>
|
||||
<!-- trim flags -->
|
||||
<exec executable="sed" inputstring="${workspace.changes}" outputproperty="workspace.changes.sed" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/^[MTADRCU ]*//" />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes.sed}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile, listChangedFiles">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar destfile="build/i2pcontrol.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
@@ -108,7 +130,7 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="socketJar" depends="compileSocketJar">
|
||||
<target name="socketJar" depends="compileSocketJar, listChangedFiles">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar destfile="build/i2pcontrol.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
@@ -124,7 +146,7 @@
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="war" depends="compile" >
|
||||
<target name="war" depends="compile, listChangedFiles" >
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<war destfile="build/jsonrpc.war" webxml="web.xml" >
|
||||
|
||||
@@ -162,6 +162,7 @@ public class Dispatcher implements RequestHandler, NotificationHandler {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public JSONRPC2Response dispatch(final JSONRPC2Request request, final MessageContext requestCtx) {
|
||||
|
||||
return process(request, requestCtx);
|
||||
@@ -209,6 +210,7 @@ public class Dispatcher implements RequestHandler, NotificationHandler {
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public void dispatch(final JSONRPC2Notification notification, final MessageContext notificationCtx) {
|
||||
|
||||
process(notification, notificationCtx);
|
||||
|
||||
@@ -12,7 +12,7 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
import net.i2p.apache.http.conn.util.InetAddressUtils;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
|
||||
@@ -170,7 +170,7 @@ public class RouterInfoHandler implements RequestHandler {
|
||||
&& (!_context.router().gracefulShutdownInProgress())
|
||||
&& !_context.clientManager().isAlive())
|
||||
return (NETWORK_STATUS.ERROR_I2CP);
|
||||
long skew = _context.commSystem().getFramedAveragePeerClockSkew(33);
|
||||
long skew = _context.commSystem().getFramedAveragePeerClockSkew(10);
|
||||
// Display the actual skew, not the offset
|
||||
if (Math.abs(skew) > 60 * 1000)
|
||||
return NETWORK_STATUS.ERROR_CLOCK_SKEW;
|
||||
@@ -200,7 +200,7 @@ public class RouterInfoHandler implements RequestHandler {
|
||||
case CommSystemFacade.STATUS_IPV4_DISABLED_IPV6_FIREWALLED:
|
||||
if (_context.router().getRouterInfo().getTargetAddress("NTCP2") != null)
|
||||
return NETWORK_STATUS.WARN_FIREWALLED_WITH_INBOUND_TCP;
|
||||
if (((FloodfillNetworkDatabaseFacade) _context.netDb()).floodfillEnabled())
|
||||
if (_context.netDb().floodfillEnabled())
|
||||
return NETWORK_STATUS.WARN_FIREWALLED_AND_FLOODFILL;
|
||||
if (_context.router().getRouterInfo().getCapabilities().indexOf('O') >= 0)
|
||||
return NETWORK_STATUS.WARN_FIREWALLED_AND_FAST;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
id 'war'
|
||||
}
|
||||
|
||||
@@ -12,11 +13,14 @@ sourceSets {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
providedCompile project(':apps:systray')
|
||||
compile 'gnu.getopt:java-getopt:1.0.13'
|
||||
providedCompile project(':apps:ministreaming')
|
||||
providedCompile project(':apps:jetty')
|
||||
api project(':core')
|
||||
api project(':apps:systray')
|
||||
api 'gnu.getopt:java-getopt:1.0.13'
|
||||
api project(':apps:ministreaming')
|
||||
api project(':apps:jetty')
|
||||
// this is not needed except for standalone,
|
||||
// but we build the standalone classes even for non-standalone
|
||||
api project(':apps:desktopgui')
|
||||
}
|
||||
|
||||
task i2psnarkJar(type: Jar) {
|
||||
|
||||
@@ -4,5 +4,11 @@
|
||||
#
|
||||
# disable browser launch on startup
|
||||
#routerconsole.browser=/bin/false
|
||||
# disable browser launch on startup (Windows)
|
||||
#routerconsole.browser=NUL
|
||||
# change browser
|
||||
#routerconsole.browser=firefox
|
||||
# disable system tray
|
||||
#desktopgui.enabled=false
|
||||
# disable system tray notification popups
|
||||
#desktopgui.showNotifications=false
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
<!-- jsp-api.jar only present for debian builds -->
|
||||
<pathelement location="../../jetty/jettylib/jsp-api.jar" />
|
||||
<!-- following jars only for standalone builds -->
|
||||
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
||||
</classpath>
|
||||
</depend>
|
||||
</target>
|
||||
@@ -60,18 +62,26 @@
|
||||
<pathelement location="../../systray/java/build/systray.jar" />
|
||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
<pathelement location="../../jetty/jettylib/jetty-util.jar" />
|
||||
<pathelement location="../../desktopgui/dist/desktopgui.jar" />
|
||||
</classpath>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="listChangedFiles" depends="jarUpToDate" if="shouldListChanges" >
|
||||
<exec executable="mtn" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="list" />
|
||||
<arg value="changed" />
|
||||
<exec executable="git" outputproperty="workspace.changes" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="status" />
|
||||
<arg value="-s" />
|
||||
<arg value="--porcelain" />
|
||||
<arg value="-uno" />
|
||||
<arg value=".." />
|
||||
</exec>
|
||||
<!-- trim flags -->
|
||||
<exec executable="sed" inputstring="${workspace.changes}" outputproperty="workspace.changes.sed" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-e" />
|
||||
<arg value="s/^[MTADRCU ]*//" />
|
||||
</exec>
|
||||
<!-- \n in an attribute value generates an invalid manifest -->
|
||||
<exec executable="tr" inputstring="${workspace.changes}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<exec executable="tr" inputstring="${workspace.changes.sed}" outputproperty="workspace.changes.tr" errorproperty="mtn.error2" failifexecutionfails="false" >
|
||||
<arg value="-s" />
|
||||
<arg value="[:space:]" />
|
||||
<arg value="," />
|
||||
@@ -108,7 +118,7 @@
|
||||
<not>
|
||||
<isset property="war.uptodate" />
|
||||
</not>
|
||||
<isset property="mtn.available" />
|
||||
<isset property="git.available" />
|
||||
</and>
|
||||
</condition>
|
||||
</target>
|
||||
@@ -236,6 +246,7 @@
|
||||
<zipfileset src="../../streaming/java/build/streaming.jar" />
|
||||
<zipfileset src="../../systray/java/build/systray.jar" />
|
||||
<zipfileset src="../../../build/jbigi.jar" />
|
||||
<zipfileset src="../../desktopgui/dist/desktopgui.jar" />
|
||||
<!-- Countries translations. The i2psnark translations are in the war but it's easier to put these here -->
|
||||
<!-- 300KB just to translate "Brazil", but why not... -->
|
||||
<!--
|
||||
@@ -248,10 +259,17 @@
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
||||
<attribute name="X-Compile-Source-JDK" value="${javac.version}" />
|
||||
<attribute name="X-Compile-Target-JDK" value="${javac.version}" />
|
||||
<!--
|
||||
Suppress JNI warning in JRE 24+, and eventual restriction
|
||||
See https://openjdk.org/jeps/472
|
||||
-->
|
||||
<attribute name="Enable-Native-Access" value="ALL-UNNAMED" />
|
||||
<!-- this is so Jetty will report its version correctly -->
|
||||
<section name="org/eclipse/jetty/server/" >
|
||||
<attribute name="Implementation-Vendor" value="Eclipse.org - Jetty" />
|
||||
<attribute name="Implementation-Version" value="8.1.17.v20150415" />
|
||||
<attribute name="Implementation-Version" value="${jetty.ver}" />
|
||||
</section>
|
||||
</manifest>
|
||||
</jar>
|
||||
@@ -294,6 +312,12 @@
|
||||
value="url(/i2psnark/.resources/themes/ubergine/images/" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
<replace dir="build/standalone-resources/.resources/themes"
|
||||
summary="true"
|
||||
token="url(/themes/console/images/buttons/"
|
||||
value="url(/i2psnark/.resources/icons/" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
|
||||
<!-- Rather than pulling in all the console theme images, let's just specify the ones we need -->
|
||||
<copy file="../../routerconsole/jsp/themes/console/images/transparent.gif"
|
||||
@@ -304,6 +328,8 @@
|
||||
todir="build/standalone-resources/.resources/themes/light/images" />
|
||||
<copy file="../../routerconsole/jsp/themes/console/images/info/errortriangle.png"
|
||||
todir="build/standalone-resources/.resources/themes/ubergine/images" />
|
||||
<copy file="../../routerconsole/jsp/themes/console/images/buttons/search.png"
|
||||
todir="build/standalone-resources/.resources/icons" />
|
||||
|
||||
<mkdir dir="build/standalone-resources/.resources/js" />
|
||||
<copy file="../../routerconsole/jsp/js/ajax.js" todir="build/standalone-resources/.resources/js" />
|
||||
|
||||
@@ -6,6 +6,7 @@ package org.klomp.snark;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PSession;
|
||||
@@ -32,7 +33,9 @@ class BWLimits {
|
||||
session.connect();
|
||||
rv = session.bandwidthLimits();
|
||||
session.destroySession();
|
||||
} catch (I2PSessionException ise) {}
|
||||
} catch (I2PSessionException ise) {
|
||||
I2PAppContext.getGlobalContext().logManager().getLog(BWLimits.class).warn("BWL fail", ise);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
/**
|
||||
* Bandwidth and bandwidth limits
|
||||
*
|
||||
* Maintain three bandwidth estimators:
|
||||
* Sent, received, and requested.
|
||||
*
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public interface BandwidthListener {
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
public long getUploadRate();
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
public long getDownloadRate();
|
||||
|
||||
/**
|
||||
* We unconditionally sent this many bytes
|
||||
*/
|
||||
public void uploaded(int size);
|
||||
|
||||
/**
|
||||
* We unconditionally received this many bytes
|
||||
*/
|
||||
public void downloaded(int size);
|
||||
|
||||
/**
|
||||
* Should we send this many bytes?
|
||||
* Do NOT call uploaded() if this returns true.
|
||||
*/
|
||||
public boolean shouldSend(int size);
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
*/
|
||||
public boolean shouldRequest(Peer peer, int size);
|
||||
|
||||
/**
|
||||
* Current limit in BPS
|
||||
*/
|
||||
public long getUpBWLimit();
|
||||
|
||||
/**
|
||||
* Current limit in BPS
|
||||
*/
|
||||
public long getDownBWLimit();
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
*/
|
||||
public boolean overUpBWLimit();
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
*/
|
||||
public boolean overDownBWLimit();
|
||||
}
|
||||
179
apps/i2psnark/java/src/org/klomp/snark/BandwidthManager.java
Normal file
179
apps/i2psnark/java/src/org/klomp/snark/BandwidthManager.java
Normal file
@@ -0,0 +1,179 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SyntheticREDQueue;
|
||||
|
||||
/**
|
||||
* Bandwidth and bandwidth limits
|
||||
*
|
||||
* Maintain three bandwidth estimators:
|
||||
* Sent, received, and requested.
|
||||
*
|
||||
* There are three layers of BandwidthListeners:
|
||||
*<pre>
|
||||
* BandwidthManager (total)
|
||||
* PeerCoordinator (per-torrent)
|
||||
* Peer/WebPeer (per-connection)
|
||||
*</pre>
|
||||
*
|
||||
* Here at the top, we use SyntheticRedQueues for accurate
|
||||
* and current moving averages of up, down, and requested bandwidth.
|
||||
*
|
||||
* At the lower layers, simple weighted moving averages of
|
||||
* three buckets of 40 seconds each (2 minutes total) are used
|
||||
* for up and down, and requested is delegated here.
|
||||
*
|
||||
* The lower layers must report to the next-higher layer.
|
||||
*
|
||||
* At the Peer layer, we report inbound piece data per-read,
|
||||
* not per-piece, to get a smoother inbound estimate.
|
||||
*
|
||||
* Only the following data are counted by the BandwidthListeners:
|
||||
*<ul><li>Pieces (both Peer and WebPeer)
|
||||
*<li>ut_metadata
|
||||
*</ul>
|
||||
*
|
||||
* No overhead at any layer is accounted for.
|
||||
*
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public class BandwidthManager implements BandwidthListener {
|
||||
|
||||
private final I2PAppContext _context;
|
||||
private final Log _log;
|
||||
private SyntheticREDQueue _up, _down, _req;
|
||||
|
||||
BandwidthManager(I2PAppContext ctx, int upLimit, int downLimit) {
|
||||
_context = ctx;
|
||||
_log = ctx.logManager().getLog(BandwidthManager.class);
|
||||
_up = new SyntheticREDQueue(ctx, upLimit);
|
||||
_down = new SyntheticREDQueue(ctx, downLimit);
|
||||
// Allow down limit a little higher based on testing
|
||||
// Allow req limit a little higher still because it uses RED
|
||||
// so it actually kicks in sooner.
|
||||
_req = new SyntheticREDQueue(ctx, downLimit * 110 / 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
*/
|
||||
void setUpBWLimit(long upLimit) {
|
||||
int limit = (int) Math.min(upLimit, Integer.MAX_VALUE);
|
||||
if (limit != getUpBWLimit())
|
||||
_up = new SyntheticREDQueue(_context, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
*/
|
||||
void setDownBWLimit(long downLimit) {
|
||||
int limit = (int) Math.min(downLimit, Integer.MAX_VALUE);
|
||||
if (limit != getDownBWLimit()) {
|
||||
_down = new SyntheticREDQueue(_context, limit);
|
||||
_req = new SyntheticREDQueue(_context, limit * 110 / 100);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
long getRequestRate() {
|
||||
return (long) (1000f * _req.getBandwidthEstimate());
|
||||
}
|
||||
|
||||
// begin BandwidthListener interface
|
||||
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
public long getUploadRate() {
|
||||
return (long) (1000f * _up.getBandwidthEstimate());
|
||||
}
|
||||
|
||||
/**
|
||||
* The average rate in Bps
|
||||
*/
|
||||
public long getDownloadRate() {
|
||||
return (long) (1000f * _down.getBandwidthEstimate());
|
||||
}
|
||||
|
||||
/**
|
||||
* We unconditionally sent this many bytes
|
||||
*/
|
||||
public void uploaded(int size) {
|
||||
_up.addSample(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* We received this many bytes
|
||||
*/
|
||||
public void downloaded(int size) {
|
||||
_down.addSample(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we send this many bytes?
|
||||
* Do NOT call uploaded() if this returns true.
|
||||
*/
|
||||
public boolean shouldSend(int size) {
|
||||
boolean rv = _up.offer(size, 1.0f);
|
||||
if (!rv && _log.shouldWarn())
|
||||
_log.warn("Deny sending " + size + " bytes, upload rate " + DataHelper.formatSize(getUploadRate()) + "Bps");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
*
|
||||
* @param peer ignored
|
||||
*/
|
||||
public boolean shouldRequest(Peer peer, int size) {
|
||||
boolean rv = !overDownBWLimit() && _req.offer(size, 1.0f);
|
||||
if (!rv && _log.shouldWarn())
|
||||
_log.warn("Deny requesting " + size + " bytes, download rate " + DataHelper.formatSize(getDownloadRate()) + "Bps" +
|
||||
", request rate " + DataHelper.formatSize(getRequestRate()) + "Bps");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in BPS
|
||||
*/
|
||||
public long getUpBWLimit() {
|
||||
return _up.getMaxBandwidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in BPS
|
||||
*/
|
||||
public long getDownBWLimit() {
|
||||
return _down.getMaxBandwidth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
*/
|
||||
public boolean overUpBWLimit() {
|
||||
return getUploadRate() > getUpBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
*/
|
||||
public boolean overDownBWLimit() {
|
||||
return getDownloadRate() > getDownBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* In HTML for debug page
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<br><b>Bandwidth Limiters</b><br><b>Up:</b> " + _up +
|
||||
"<br><b>Down:</b> " + _down +
|
||||
"<br><b>Req:</b> " + _req +
|
||||
"<br>";
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
|
||||
/**
|
||||
* Simple command line access to various utilities.
|
||||
* Not a public API. Subject to change.
|
||||
@@ -38,7 +36,7 @@ public class CommandLine extends net.i2p.util.CommandLine {
|
||||
}
|
||||
|
||||
private static void usage(List<String> classes) {
|
||||
System.err.println("I2PSnark version " + CoreVersion.VERSION + '\n' +
|
||||
System.err.println("I2PSnark version " + SnarkManager.FULL_VERSION + '\n' +
|
||||
"USAGE: java -jar /path/to/i2psnark.jar command [args]");
|
||||
printCommands(classes);
|
||||
}
|
||||
|
||||
@@ -83,4 +83,9 @@ public interface CompleteListener {
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public boolean shouldAutoStart();
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public BandwidthListener getBandwidthListener();
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.RouterRestartException;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
@@ -131,12 +132,13 @@ class ConnectionAcceptor implements Runnable
|
||||
/**
|
||||
* Effectively unused, would only be called if we changed
|
||||
* I2CP host/port, which is hidden in the gui if in router context
|
||||
* FIXME this only works if already running
|
||||
*/
|
||||
public synchronized void restart() {
|
||||
Thread t = thread;
|
||||
if (t != null)
|
||||
t.interrupt();
|
||||
else
|
||||
startAccepting();
|
||||
}
|
||||
|
||||
public int getPort()
|
||||
@@ -201,6 +203,24 @@ class ConnectionAcceptor implements Runnable
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
catch (RouterRestartException rre) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Waiting for router restart", rre);
|
||||
try {
|
||||
Thread.sleep(2*60*1000);
|
||||
} catch (InterruptedException ie) {}
|
||||
while (true) {
|
||||
if (_util.connected())
|
||||
break;
|
||||
if (_util.connect())
|
||||
break;
|
||||
try {
|
||||
Thread.sleep(60*1000);
|
||||
} catch (InterruptedException ie) { break; }
|
||||
}
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Router restarted");
|
||||
}
|
||||
catch (I2PException ioe)
|
||||
{
|
||||
int level = stop ? Log.WARN : Log.ERROR;
|
||||
|
||||
@@ -42,15 +42,5 @@ interface CoordinatorListener
|
||||
*/
|
||||
public boolean overUploadLimit(int uploaders);
|
||||
|
||||
/**
|
||||
* Is i2psnark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit();
|
||||
|
||||
/**
|
||||
* Is a particular peer who has this recent download rate (in Bps) over our upstream bandwidth limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total);
|
||||
|
||||
public void addMessage(String message);
|
||||
}
|
||||
|
||||
@@ -190,6 +190,8 @@ abstract class ExtensionHandler {
|
||||
}
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info("Request chunk " + chk + " from " + peer);
|
||||
// ignore the rv, always request
|
||||
peer.shouldRequest(state.chunkSize(chk));
|
||||
sendRequest(peer, chk);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@@ -230,7 +232,6 @@ abstract class ExtensionHandler {
|
||||
sendPiece(peer, piece, pc, totalSize);
|
||||
// Do this here because PeerConnectionOut only reports for PIECE messages
|
||||
peer.uploaded(pc.length);
|
||||
listener.uploaded(peer, pc.length);
|
||||
} else if (type == TYPE_DATA) {
|
||||
// On close reading of BEP 9, this is the total metadata size.
|
||||
// Prior to 0.9.21, we sent the piece size, so we can't count on it.
|
||||
@@ -245,7 +246,6 @@ abstract class ExtensionHandler {
|
||||
return;
|
||||
int len = is.available();
|
||||
peer.downloaded(len);
|
||||
listener.downloaded(peer, len);
|
||||
// this checks the size
|
||||
done = state.saveChunk(piece, bs, bs.length - len, len);
|
||||
if (log.shouldLog(Log.INFO))
|
||||
@@ -264,6 +264,8 @@ abstract class ExtensionHandler {
|
||||
// get the next chunk
|
||||
if (log.shouldLog(Log.INFO))
|
||||
log.info("Request chunk " + chk + " from " + peer);
|
||||
// ignore the rv, always request
|
||||
peer.shouldRequest(state.chunkSize(chk));
|
||||
sendRequest(peer, chk);
|
||||
}
|
||||
} else if (type == TYPE_REJECT) {
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
@@ -13,6 +20,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
@@ -28,6 +36,7 @@ import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.Base32;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
@@ -36,7 +45,9 @@ import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
import net.i2p.util.SecureFile;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.util.SystemVersion;
|
||||
import net.i2p.util.Translate;
|
||||
|
||||
import org.klomp.snark.dht.DHT;
|
||||
@@ -77,6 +88,7 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
private DHT _dht;
|
||||
private long _startedTime;
|
||||
private final DisconnectListener _discon;
|
||||
private int _maxFilesPerTorrent = SnarkManager.DEFAULT_MAX_FILES_PER_TORRENT;
|
||||
|
||||
private static final int EEPGET_CONNECT_TIMEOUT = 45*1000;
|
||||
private static final int EEPGET_CONNECT_TIMEOUT_SHORT = 5*1000;
|
||||
@@ -102,7 +114,7 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
*/
|
||||
public I2PSnarkUtil(I2PAppContext ctx, String baseName, DisconnectListener discon) {
|
||||
_context = ctx;
|
||||
_log = _context.logManager().getLog(Snark.class);
|
||||
_log = _context.logManager().getLog(I2PSnarkUtil.class);
|
||||
_baseName = baseName;
|
||||
_discon = discon;
|
||||
_opts = new HashMap<String, String>();
|
||||
@@ -242,6 +254,11 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
/** @since 0.9.1 */
|
||||
public File getTempDir() { return _tmpDir; }
|
||||
|
||||
/** @since 0.9.58 */
|
||||
public int getMaxFilesPerTorrent() { return _maxFilesPerTorrent; }
|
||||
/** @since 0.9.58 */
|
||||
public void setMaxFilesPerTorrent(int max) { _maxFilesPerTorrent = Math.max(max, 1); }
|
||||
|
||||
/**
|
||||
* Connect to the router, if we aren't already
|
||||
*/
|
||||
@@ -347,6 +364,10 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
synchronized(this) {
|
||||
_manager = null;
|
||||
_connecting = false;
|
||||
if (_dht != null) {
|
||||
_dht.stop();
|
||||
_dht = null;
|
||||
}
|
||||
}
|
||||
if (_discon != null)
|
||||
_discon.sessionDisconnected();
|
||||
@@ -556,6 +577,9 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full Base64 of Destination
|
||||
*/
|
||||
public String getOurIPString() {
|
||||
Destination dest = getMyDestination();
|
||||
if (dest != null)
|
||||
@@ -822,4 +846,90 @@ public class I2PSnarkUtil implements DisconnectListener {
|
||||
public String getString(int n, String s, String p) {
|
||||
return Translate.getString(n, s, p, _context, BUNDLE_NAME);
|
||||
}
|
||||
|
||||
private static final boolean SHOULD_SYNC = !(SystemVersion.isAndroid() || SystemVersion.isARM());
|
||||
private static final Pattern ILLEGAL_KEY = Pattern.compile("[#=\\r\\n;]");
|
||||
private static final Pattern ILLEGAL_VALUE = Pattern.compile("[\\r\\n]");
|
||||
|
||||
/**
|
||||
* Same as DataHelper.loadProps() but allows '#' in values,
|
||||
* so we can have filenames with '#' in them in torrent config files.
|
||||
* '#' must be in column 1 for a comment.
|
||||
*
|
||||
* @since 0.9.58
|
||||
*/
|
||||
static void loadProps(Properties props, File f) throws IOException {
|
||||
BufferedReader in = null;
|
||||
try {
|
||||
in = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"), 1024);
|
||||
String line = null;
|
||||
while ( (line = in.readLine()) != null) {
|
||||
if (line.trim().length() <= 0) continue;
|
||||
if (line.charAt(0) == '#') continue;
|
||||
if (line.charAt(0) == ';') continue;
|
||||
int split = line.indexOf('=');
|
||||
if (split <= 0) continue;
|
||||
String key = line.substring(0, split);
|
||||
String val = line.substring(split+1).trim();
|
||||
props.setProperty(key, val);
|
||||
}
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as DataHelper.loadProps() but allows '#' in values,
|
||||
* so we can have filenames with '#' in them in torrent config files.
|
||||
* '#' must be in column 1 for a comment.
|
||||
*
|
||||
* @since 0.9.58
|
||||
*/
|
||||
static void storeProps(Properties props, File file) throws IOException {
|
||||
FileOutputStream fos = null;
|
||||
PrintWriter out = null;
|
||||
IOException ioe = null;
|
||||
File tmpFile = new File(file.getPath() + ".tmp");
|
||||
try {
|
||||
fos = new SecureFileOutputStream(tmpFile);
|
||||
out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(fos, "UTF-8")));
|
||||
out.println("# NOTE: This I2P config file must use UTF-8 encoding");
|
||||
out.println("# Last saved: " + DataHelper.formatTime(System.currentTimeMillis()));
|
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) {
|
||||
String name = (String) entry.getKey();
|
||||
String val = (String) entry.getValue();
|
||||
if (ILLEGAL_KEY.matcher(name).find()) {
|
||||
if (ioe == null)
|
||||
ioe = new IOException("Invalid character (one of \"#;=\\r\\n\") in key: \"" +
|
||||
name + "\" = \"" + val + '\"');
|
||||
continue;
|
||||
}
|
||||
if (ILLEGAL_VALUE.matcher(val).find()) {
|
||||
if (ioe == null)
|
||||
ioe = new IOException("Invalid character (one of \"\\r\\n\") in value: \"" +
|
||||
name + "\" = \"" + val + '\"');
|
||||
continue;
|
||||
}
|
||||
out.println(name + "=" + val);
|
||||
}
|
||||
if (SHOULD_SYNC) {
|
||||
out.flush();
|
||||
fos.getFD().sync();
|
||||
}
|
||||
out.close();
|
||||
if (out.checkError()) {
|
||||
out = null;
|
||||
tmpFile.delete();
|
||||
throw new IOException("Failed to write properties to " + tmpFile);
|
||||
}
|
||||
out = null;
|
||||
if (!FileUtil.rename(tmpFile, file))
|
||||
throw new IOException("Failed rename from " + tmpFile + " to " + file);
|
||||
} finally {
|
||||
if (out != null) out.close();
|
||||
if (fos != null) try { fos.close(); } catch (IOException e) {}
|
||||
}
|
||||
if (ioe != null)
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public class MetaInfo
|
||||
private final int piece_length;
|
||||
private final byte[] piece_hashes;
|
||||
private final long length;
|
||||
private final boolean privateTorrent;
|
||||
private final int privateTorrent; // 0: not present; 1: = 1; -1: = 0
|
||||
private final List<List<String>> announce_list;
|
||||
private final String comment;
|
||||
private final String created_by;
|
||||
@@ -97,7 +97,7 @@ public class MetaInfo
|
||||
this.piece_length = piece_length;
|
||||
this.piece_hashes = piece_hashes;
|
||||
this.length = length;
|
||||
this.privateTorrent = privateTorrent;
|
||||
this.privateTorrent = privateTorrent ? 1 : 0;
|
||||
this.announce_list = announce_list;
|
||||
this.comment = comment;
|
||||
this.created_by = created_by;
|
||||
@@ -117,9 +117,72 @@ public class MetaInfo
|
||||
//infoMap = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preserves privateTorrent int value, for main()
|
||||
*
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public MetaInfo(String announce, String name, String name_utf8, List<List<String>> files, List<Long> lengths,
|
||||
int piece_length, byte[] piece_hashes, long length, int privateTorrent,
|
||||
List<List<String>> announce_list, String created_by, List<String> url_list, String comment)
|
||||
{
|
||||
this.announce = announce;
|
||||
this.name = name;
|
||||
this.name_utf8 = name_utf8;
|
||||
this.files = files == null ? null : Collections.unmodifiableList(files);
|
||||
this.files_utf8 = null;
|
||||
this.lengths = lengths == null ? null : Collections.unmodifiableList(lengths);
|
||||
this.piece_length = piece_length;
|
||||
this.piece_hashes = piece_hashes;
|
||||
this.length = length;
|
||||
this.privateTorrent = privateTorrent;
|
||||
this.announce_list = announce_list;
|
||||
this.comment = comment;
|
||||
this.created_by = created_by;
|
||||
this.creation_date = I2PAppContext.getGlobalContext().clock().now();
|
||||
this.url_list = url_list;
|
||||
this.attributes = null;
|
||||
this.info_hash = calculateInfoHash();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will not change infohash.
|
||||
* Retains creation date of old MetaInfo if nonzero.
|
||||
*
|
||||
* @param new_announce may be null
|
||||
* @param new_announce_list may be null
|
||||
* @param new_comment may be null
|
||||
* @param new_created_by may be null
|
||||
* @param new_url_list may be null
|
||||
* @since 0.9.64
|
||||
*/
|
||||
public MetaInfo(MetaInfo old, String new_announce, List<List<String>> new_announce_list, String new_comment,
|
||||
String new_created_by, List<String> new_url_list)
|
||||
{
|
||||
this.announce = new_announce;
|
||||
this.info_hash = old.info_hash;
|
||||
this.name = old.name;
|
||||
this.name_utf8 = old.name_utf8;
|
||||
this.files = old.files;
|
||||
this.files_utf8 = old.files_utf8;
|
||||
this.attributes = old.attributes;
|
||||
this.lengths = old.lengths;
|
||||
this.piece_length = old.piece_length;
|
||||
this.piece_hashes = old.piece_hashes;
|
||||
this.length = old.length;
|
||||
this.privateTorrent = old.privateTorrent;
|
||||
this.announce_list = new_announce_list;
|
||||
this.comment = new_comment;
|
||||
this.created_by = new_created_by;
|
||||
this.creation_date = old.creation_date > 0 ? old.creation_date : I2PAppContext.getGlobalContext().clock().now();
|
||||
this.url_list = new_url_list;
|
||||
this.infoMap = old.infoMap;
|
||||
this.infoBytesLength = old.infoBytesLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MetaInfo from the given InputStream. The
|
||||
* InputStream must start with a correctly bencoded dictonary
|
||||
* InputStream must start with a correctly bencoded dictionary
|
||||
* describing the torrent.
|
||||
* Caller must close the stream.
|
||||
*/
|
||||
@@ -144,7 +207,7 @@ public class MetaInfo
|
||||
|
||||
/**
|
||||
* Creates a new MetaInfo from a Map of BEValues and the SHA1 over
|
||||
* the original bencoded info dictonary (this is a hack, we could
|
||||
* the original bencoded info dictionary (this is a hack, we could
|
||||
* reconstruct the bencoded stream and recalculate the hash). Will
|
||||
* NOT throw a InvalidBEncodingException if the given map does not
|
||||
* contain a valid announce string.
|
||||
@@ -186,11 +249,20 @@ public class MetaInfo
|
||||
if (val == null) {
|
||||
this.url_list = null;
|
||||
} else {
|
||||
List<BEValue> bl1 = val.getList();
|
||||
this.url_list = new ArrayList<String>(bl1.size());
|
||||
for (BEValue bev : bl1) {
|
||||
this.url_list.add(bev.getString());
|
||||
List<String> urllist;
|
||||
try {
|
||||
List<BEValue> bl1 = val.getList();
|
||||
urllist = new ArrayList<String>(bl1.size());
|
||||
for (BEValue bev : bl1) {
|
||||
urllist.add(bev.getString());
|
||||
}
|
||||
} catch (InvalidBEncodingException ibee) {
|
||||
// BEP 19 says it's a list but the example there
|
||||
// is for a single byte string, and we've seen this
|
||||
// in the wild.
|
||||
urllist = Collections.singletonList(val.getString());
|
||||
}
|
||||
this.url_list = urllist;
|
||||
}
|
||||
|
||||
// misc. optional top-level stuff
|
||||
@@ -248,10 +320,11 @@ public class MetaInfo
|
||||
// Transmission does numbers. So does libtorrent.
|
||||
// We handle both as of 0.9.9.
|
||||
// We switch to storing as number as of 0.9.14.
|
||||
privateTorrent = "1".equals(o) ||
|
||||
boolean privat = "1".equals(o) ||
|
||||
((o instanceof Number) && ((Number) o).intValue() == 1);
|
||||
privateTorrent = privat ? 1 : -1;
|
||||
} else {
|
||||
privateTorrent = false;
|
||||
privateTorrent = 0;
|
||||
}
|
||||
|
||||
val = info.get("piece length");
|
||||
@@ -468,6 +541,14 @@ public class MetaInfo
|
||||
* @since 0.9
|
||||
*/
|
||||
public boolean isPrivate() {
|
||||
return privateTorrent > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 0 (default), 1 (set to 1), -1 (set to 0)
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public int getPrivateTrackerStatus() {
|
||||
return privateTorrent;
|
||||
}
|
||||
|
||||
@@ -720,18 +801,19 @@ public class MetaInfo
|
||||
if (infoMap != null)
|
||||
return Collections.unmodifiableMap(infoMap);
|
||||
// we should only get here if serving a magnet on a torrent we created
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Creating new infomap", new Exception());
|
||||
// or on edit torrent save
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Creating new infomap", new Exception());
|
||||
// otherwise we must create it
|
||||
Map<String, BEValue> info = new HashMap<String, BEValue>();
|
||||
info.put("name", new BEValue(DataHelper.getUTF8(name)));
|
||||
if (name_utf8 != null)
|
||||
info.put("name.utf-8", new BEValue(DataHelper.getUTF8(name_utf8)));
|
||||
// BEP 27
|
||||
if (privateTorrent)
|
||||
if (privateTorrent != 0)
|
||||
// switched to number in 0.9.14
|
||||
//info.put("private", new BEValue(DataHelper.getUTF8("1")));
|
||||
info.put("private", new BEValue(Integer.valueOf(1)));
|
||||
info.put("private", new BEValue(Integer.valueOf(privateTorrent > 0 ? 1 : 0)));
|
||||
|
||||
info.put("piece length", new BEValue(Integer.valueOf(piece_length)));
|
||||
info.put("pieces", new BEValue(piece_hashes));
|
||||
@@ -809,7 +891,7 @@ public class MetaInfo
|
||||
String announce = null;
|
||||
List<String> url_list = null;
|
||||
String comment = null;
|
||||
Getopt g = new Getopt("Storage", args, "a:c:m:w:");
|
||||
Getopt g = new Getopt("MetaInfo", args, "a:c:m:w:");
|
||||
try {
|
||||
int c;
|
||||
while ((c = g.getopt()) != -1) {
|
||||
@@ -864,10 +946,7 @@ public class MetaInfo
|
||||
String an = announce != null ? announce : meta.getAnnounce();
|
||||
String cm = comment != null ? comment : meta.getComment();
|
||||
List<String> urls = url_list != null ? url_list : meta.getWebSeedURLs();
|
||||
// changes/adds creation date
|
||||
MetaInfo meta2 = new MetaInfo(an, meta.getName(), null, meta.getFiles(), meta.getLengths(),
|
||||
meta.getPieceLength(0), meta.getPieceHashes(), meta.getTotalLength(), meta.isPrivate(),
|
||||
meta.getAnnounceList(), cb, urls, cm);
|
||||
MetaInfo meta2 = new MetaInfo(meta, an, meta.getAnnounceList(), cm, cb, urls);
|
||||
java.io.File from = new java.io.File(args[i]);
|
||||
java.io.File to = new java.io.File(args[i] + ".bak");
|
||||
if (net.i2p.util.FileUtil.copy(from, to, true, false)) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.klomp.snark;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
@@ -43,6 +44,7 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
private RandomAccessFile raf;
|
||||
private final int pclen;
|
||||
private final File tempDir;
|
||||
private final BitField bitfield;
|
||||
|
||||
private static final int BUFSIZE = PeerState.PARTSIZE;
|
||||
private static final ByteCache _cache = ByteCache.getInstance(16, BUFSIZE);
|
||||
@@ -66,6 +68,7 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
this.pclen = len;
|
||||
//this.createdTime = 0;
|
||||
this.tempDir = tempDir;
|
||||
bitfield = new BitField((len + PeerState.PARTSIZE - 1) / PeerState.PARTSIZE);
|
||||
|
||||
// temps for finals
|
||||
byte[] tbs = null;
|
||||
@@ -98,22 +101,27 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
//tfile = SecureFile.createTempFile("piece", null, tempDir);
|
||||
// debug
|
||||
tempfile = SecureFile.createTempFile("piece_" + piece.getId() + '_', null, tempDir);
|
||||
//I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Created " + tempfile);
|
||||
// tfile.deleteOnExit() ???
|
||||
raf = new RandomAccessFile(tempfile, "rw");
|
||||
// Do not preallocate the file space.
|
||||
// Not necessary to call setLength(), file is extended when written
|
||||
//traf.setLength(len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this PartialPiece to a request for the next chunk.
|
||||
* Used by PeerState only. This depends on the downloaded value
|
||||
* as set by setDownloaded() or read().
|
||||
* Used by PeerState only.
|
||||
*
|
||||
* @return null if complete
|
||||
*/
|
||||
|
||||
public synchronized Request getRequest() {
|
||||
return new Request(this, this.off, Math.min(this.pclen - this.off, PeerState.PARTSIZE));
|
||||
int chunk = off / PeerState.PARTSIZE;
|
||||
int sz = bitfield.size();
|
||||
for (int i = chunk; i < sz; i++) {
|
||||
if (!bitfield.get(i))
|
||||
return new Request(this, off, Math.min(pclen - off, PeerState.PARTSIZE));
|
||||
if (i == sz - 1)
|
||||
off = pclen;
|
||||
else
|
||||
off += PeerState.PARTSIZE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** piece number */
|
||||
@@ -129,27 +137,44 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
}
|
||||
|
||||
/**
|
||||
* How many bytes are good - as set by setDownloaded() or read()
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public synchronized int getDownloaded() {
|
||||
return this.off;
|
||||
public synchronized boolean isComplete() {
|
||||
return bitfield.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this if necessary before returning a PartialPiece to the PeerCoordinator.
|
||||
* We do not use a bitmap to track individual chunks received.
|
||||
* Any chunks after a 'hole' will be lost.
|
||||
* @since 0.9.1
|
||||
* Have any chunks been downloaded?
|
||||
*
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public synchronized void setDownloaded(int offset) {
|
||||
this.off = offset;
|
||||
public synchronized boolean hasData() {
|
||||
return bitfield.count() > 0;
|
||||
}
|
||||
|
||||
/****
|
||||
public long getCreated() {
|
||||
return this.createdTime;
|
||||
/**
|
||||
* Has this chunk been downloaded?
|
||||
*
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public synchronized boolean hasChunk(int chunk) {
|
||||
return bitfield.get(chunk);
|
||||
}
|
||||
|
||||
/**
|
||||
* How many bytes are good - as set by read().
|
||||
* As of 0.9.63, accurately counts good bytes after "holes".
|
||||
*/
|
||||
public synchronized int getDownloaded() {
|
||||
if (bitfield.complete())
|
||||
return pclen;
|
||||
int sz = bitfield.count();
|
||||
int rv = sz * PeerState.PARTSIZE;
|
||||
int rem = pclen % PeerState.PARTSIZE;
|
||||
if (rem != 0 && bitfield.get(sz - 1))
|
||||
rv -= PeerState.PARTSIZE - rem;
|
||||
return rv;
|
||||
}
|
||||
****/
|
||||
|
||||
/**
|
||||
* Piece must be complete.
|
||||
@@ -200,13 +225,47 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
*
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public void read(DataInputStream din, int offset, int len) throws IOException {
|
||||
public void read(DataInputStream din, int offset, int len, BandwidthListener bwl) throws IOException {
|
||||
if (offset % PeerState.PARTSIZE != 0)
|
||||
throw new IOException("Bad offset " + offset);
|
||||
int chunk = offset / PeerState.PARTSIZE;
|
||||
// We read the data before checking if we have the chunk,
|
||||
// because otherwise we'd have to break the peer connection
|
||||
if (bs != null) {
|
||||
din.readFully(bs, offset, len);
|
||||
// Don't use readFully() so we may update the BandwidthListener as we go
|
||||
//in.readFully(bs, offset, len);
|
||||
int offs = offset;
|
||||
int toRead = len;
|
||||
while (toRead > 0) {
|
||||
int numRead = din.read(bs, offs, toRead);
|
||||
if (numRead < 0)
|
||||
throw new EOFException();
|
||||
offs += numRead;
|
||||
toRead -= numRead;
|
||||
bwl.downloaded(numRead);
|
||||
}
|
||||
synchronized (this) {
|
||||
// only works for in-order chunks
|
||||
if (this.off == offset)
|
||||
this.off += len;
|
||||
if (bitfield.get(chunk)) {
|
||||
warn("Already have chunk " + chunk + " on " + this);
|
||||
} else {
|
||||
bitfield.set(chunk);
|
||||
if (this.off == offset) {
|
||||
this.off += len;
|
||||
// if this filled in a hole, advance off
|
||||
int sz = bitfield.size();
|
||||
for (int i = chunk + 1; i < sz; i++) {
|
||||
if (!bitfield.get(i))
|
||||
break;
|
||||
warn("Hole filled in before chunk " + i + " on " + this + ' ' + bitfield);
|
||||
if (i == sz - 1)
|
||||
off = pclen;
|
||||
else
|
||||
off += PeerState.PARTSIZE;
|
||||
}
|
||||
} else {
|
||||
warn("Out of order chunk " + chunk + " on " + this + ' ' + bitfield);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// read in fully before synching on raf
|
||||
@@ -219,15 +278,46 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
ba = null;
|
||||
tmp = new byte[len];
|
||||
}
|
||||
din.readFully(tmp);
|
||||
|
||||
// Don't use readFully() so we may update the BandwidthListener as we go
|
||||
//din.readFully(tmp);
|
||||
int offs = 0;
|
||||
int toRead = len;
|
||||
while (toRead > 0) {
|
||||
int numRead = din.read(tmp, offs, toRead);
|
||||
if (numRead < 0)
|
||||
throw new EOFException();
|
||||
offs += numRead;
|
||||
toRead -= numRead;
|
||||
bwl.downloaded(numRead);
|
||||
}
|
||||
|
||||
synchronized (this) {
|
||||
if (raf == null)
|
||||
createTemp();
|
||||
raf.seek(offset);
|
||||
raf.write(tmp);
|
||||
// only works for in-order chunks
|
||||
if (this.off == offset)
|
||||
this.off += len;
|
||||
if (bitfield.get(chunk)) {
|
||||
warn("Already have chunk " + chunk + " on " + this);
|
||||
} else {
|
||||
if (raf == null)
|
||||
createTemp();
|
||||
raf.seek(offset);
|
||||
raf.write(tmp);
|
||||
bitfield.set(chunk);
|
||||
if (this.off == offset) {
|
||||
this.off += len;
|
||||
// if this filled in a hole, advance off
|
||||
int sz = bitfield.size();
|
||||
for (int i = chunk + 1; i < sz; i++) {
|
||||
if (!bitfield.get(i))
|
||||
break;
|
||||
warn("Hole filled in before chunk " + i + " on " + this + ' ' + bitfield);
|
||||
if (i == sz - 1)
|
||||
off = pclen;
|
||||
else
|
||||
off += PeerState.PARTSIZE;
|
||||
}
|
||||
} else {
|
||||
warn("Out of order chunk " + chunk + " on " + this + ' ' + bitfield);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ba != null)
|
||||
_cache.release(ba, false);
|
||||
@@ -283,8 +373,10 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
public void release() {
|
||||
if (bs == null) {
|
||||
synchronized (this) {
|
||||
if (raf != null)
|
||||
if (raf != null) {
|
||||
locked_release();
|
||||
raf = null;
|
||||
}
|
||||
}
|
||||
//if (raf != null)
|
||||
// I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Released " + tempfile);
|
||||
@@ -300,7 +392,6 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
try {
|
||||
raf.close();
|
||||
} catch (IOException ioe) {
|
||||
I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn("Error closing " + raf, ioe);
|
||||
}
|
||||
tempfile.delete();
|
||||
}
|
||||
@@ -314,7 +405,7 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
int d = this.piece.compareTo(opp.piece);
|
||||
if (d != 0)
|
||||
return d;
|
||||
return opp.off - this.off; // reverse
|
||||
return opp.getDownloaded() - getDownloaded(); // reverse
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -337,6 +428,13 @@ class PartialPiece implements Comparable<PartialPiece> {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Partial(" + piece.getId() + ',' + off + ',' + pclen + ')';
|
||||
return "Partial(" + piece.getId() + ',' + off + ',' + getDownloaded() + ',' + pclen + ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public static void warn(String s) {
|
||||
I2PAppContext.getGlobalContext().logManager().getLog(PartialPiece.class).warn(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ import net.i2p.util.Log;
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
import org.klomp.snark.bencode.InvalidBEncodingException;
|
||||
|
||||
public class Peer implements Comparable<Peer>
|
||||
public class Peer implements Comparable<Peer>, BandwidthListener
|
||||
{
|
||||
protected final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
|
||||
// Identifying property, the peer id of the other side.
|
||||
@@ -96,6 +96,8 @@ public class Peer implements Comparable<Peer>
|
||||
private final boolean _isIncoming;
|
||||
private int _totalCommentsSent;
|
||||
private int _maxPipeline = PeerState.MIN_PIPELINE;
|
||||
private long connected;
|
||||
private long pexLastSent;
|
||||
|
||||
/**
|
||||
* Outgoing connection.
|
||||
@@ -239,7 +241,7 @@ public class Peer implements Comparable<Peer>
|
||||
*
|
||||
* @param uploadOnly if we are complete with skipped files, i.e. a partial seed
|
||||
*/
|
||||
public void runConnection(I2PSnarkUtil util, PeerListener listener, BitField bitfield,
|
||||
public void runConnection(I2PSnarkUtil util, PeerListener listener, BandwidthListener bwl, BitField bitfield,
|
||||
MagnetState mState, boolean uploadOnly) {
|
||||
if (state != null)
|
||||
throw new IllegalStateException("Peer already started");
|
||||
@@ -288,7 +290,7 @@ public class Peer implements Comparable<Peer>
|
||||
|
||||
PeerConnectionIn in = new PeerConnectionIn(this, din);
|
||||
PeerConnectionOut out = new PeerConnectionOut(this, dout);
|
||||
PeerState s = new PeerState(this, listener, metainfo, in, out);
|
||||
PeerState s = new PeerState(this, listener, bwl, metainfo, in, out);
|
||||
|
||||
if ((options & OPTION_EXTENSION) != 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -307,6 +309,7 @@ public class Peer implements Comparable<Peer>
|
||||
// We are up and running!
|
||||
state = s;
|
||||
magnetState = mState;
|
||||
connected = util.getContext().clock().now();
|
||||
listener.connected(this);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -651,12 +654,17 @@ public class Peer implements Comparable<Peer>
|
||||
return (s == null) || s.choked;
|
||||
}
|
||||
|
||||
/////// begin BandwidthListener interface ///////
|
||||
|
||||
/**
|
||||
* Increment the counter.
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void downloaded(int size) {
|
||||
downloaded.addAndGet(size);
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
s.getBandwidthListener().downloaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -665,6 +673,9 @@ public class Peer implements Comparable<Peer>
|
||||
*/
|
||||
public void uploaded(int size) {
|
||||
uploaded.addAndGet(size);
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
s.getBandwidthListener().uploaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -688,13 +699,115 @@ public class Peer implements Comparable<Peer>
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average rate in Bps
|
||||
*/
|
||||
public long getUploadRate()
|
||||
{
|
||||
return PeerCoordinator.getRate(uploaded_old);
|
||||
}
|
||||
|
||||
public long getDownloadRate()
|
||||
{
|
||||
return PeerCoordinator.getRate(downloaded_old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we send this many bytes?
|
||||
* Do NOT call uploaded() after this.
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldSend(int size) {
|
||||
PeerState s = state;
|
||||
if (s != null) {
|
||||
boolean rv = s.getBandwidthListener().shouldSend(size);
|
||||
if (rv)
|
||||
uploaded.addAndGet(size);
|
||||
return rv;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldRequest(int size) {
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().shouldRequest(this, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldRequest(Peer peer, int size) {
|
||||
if (peer != this)
|
||||
return false;
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().shouldRequest(this, size);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public long getUpBWLimit() {
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().getUpBWLimit();
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is snark as a whole over its limit?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean overUpBWLimit()
|
||||
{
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().overUpBWLimit();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public long getDownBWLimit() {
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().getDownBWLimit();
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean overDownBWLimit() {
|
||||
PeerState s = state;
|
||||
if (s != null)
|
||||
return s.getBandwidthListener().overDownBWLimit();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
|
||||
* Resets the downloaded and uploaded counters to zero.
|
||||
*/
|
||||
public void resetCounters()
|
||||
{
|
||||
downloaded.set(0);
|
||||
uploaded.set(0);
|
||||
void setRateHistory() {
|
||||
long up = uploaded.getAndSet(0);
|
||||
PeerCoordinator.setRate(up, uploaded_old);
|
||||
long down = downloaded.getAndSet(0);
|
||||
PeerCoordinator.setRate(down, downloaded_old);
|
||||
}
|
||||
|
||||
/////// end BandwidthListener interface ///////
|
||||
|
||||
public long getInactiveTime() {
|
||||
PeerState s = state;
|
||||
@@ -761,28 +874,6 @@ public class Peer implements Comparable<Peer>
|
||||
return s.bitfield.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
|
||||
*/
|
||||
public void setRateHistory(long up, long down)
|
||||
{
|
||||
PeerCoordinator.setRate(up, uploaded_old);
|
||||
PeerCoordinator.setRate(down, downloaded_old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4-minute-average rate in Bps
|
||||
*/
|
||||
public long getUploadRate()
|
||||
{
|
||||
return PeerCoordinator.getRate(uploaded_old);
|
||||
}
|
||||
|
||||
public long getDownloadRate()
|
||||
{
|
||||
return PeerCoordinator.getRate(downloaded_old);
|
||||
}
|
||||
|
||||
/** @since 0.9.31 */
|
||||
int getTotalCommentsSent() {
|
||||
return _totalCommentsSent;
|
||||
@@ -800,4 +891,28 @@ public class Peer implements Comparable<Peer>
|
||||
public boolean isWebPeer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did handshake complete?
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public long getWhenConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did we last send pex peers?
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public long getPexLastSent() {
|
||||
return pexLastSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* when did we last send pex peers?
|
||||
* @since 0.9.63
|
||||
*/
|
||||
public void setPexLastSent(long now) {
|
||||
pexLastSent = now;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,8 +113,7 @@ class PeerCheckerTask implements Runnable
|
||||
uploaded += upload;
|
||||
long download = peer.getDownloaded();
|
||||
downloaded += download;
|
||||
peer.setRateHistory(upload, download);
|
||||
peer.resetCounters();
|
||||
peer.setRateHistory();
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug(peer + ":"
|
||||
@@ -127,10 +126,9 @@ class PeerCheckerTask implements Runnable
|
||||
}
|
||||
|
||||
// Choke a percentage of them rather than all so it isn't so drastic...
|
||||
// unless this torrent is over the limit all by itself.
|
||||
// choke 5/8 of the time when seeding and 3/8 when leeching
|
||||
// choke 3/8 of the time when seeding and 1/4 when leeching
|
||||
boolean overBWLimitChoke = upload > 0 &&
|
||||
((overBWLimit && (random.nextInt(8) > (coordinator.completed() ? 2 : 4))) ||
|
||||
((overBWLimit && (random.nextInt(8) > (coordinator.completed() ? 4 : 5))) ||
|
||||
(coordinator.overUpBWLimit(uploaded)));
|
||||
|
||||
// If we are at our max uploaders and we have lots of other
|
||||
|
||||
@@ -157,7 +157,7 @@ class PeerConnectionIn implements Runnable
|
||||
Request req = ps.getOutstandingRequest(piece, begin, len);
|
||||
if (req != null)
|
||||
{
|
||||
req.read(din);
|
||||
req.read(din, peer);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Received data(" + piece + "," + begin + ") from " + peer);
|
||||
ps.pieceMessage(req);
|
||||
|
||||
@@ -73,6 +73,7 @@ class PeerConnectionOut implements Runnable
|
||||
{
|
||||
try
|
||||
{
|
||||
boolean shouldThrottleRequests = false;
|
||||
while (!quit && peer.isConnected())
|
||||
{
|
||||
Message m = null;
|
||||
@@ -89,7 +90,7 @@ class PeerConnectionOut implements Runnable
|
||||
|
||||
synchronized(sendQueue)
|
||||
{
|
||||
while (!quit && peer.isConnected() && sendQueue.isEmpty())
|
||||
while (!quit && peer.isConnected() && (shouldThrottleRequests || sendQueue.isEmpty()))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -98,12 +99,13 @@ class PeerConnectionOut implements Runnable
|
||||
// dout.flush();
|
||||
|
||||
// Wait till more data arrives.
|
||||
sendQueue.wait(60*1000);
|
||||
sendQueue.wait(shouldThrottleRequests ? 5000 : 60*1000);
|
||||
}
|
||||
catch (InterruptedException ie)
|
||||
{
|
||||
/* ignored */
|
||||
}
|
||||
shouldThrottleRequests = false;
|
||||
}
|
||||
state = peer.state;
|
||||
if (!quit && state != null && peer.isConnected())
|
||||
@@ -125,7 +127,6 @@ class PeerConnectionOut implements Runnable
|
||||
{
|
||||
if (state.choking) {
|
||||
it.remove();
|
||||
//SimpleTimer.getInstance().removeEvent(nm.expireEvent);
|
||||
if (peer.supportsFast()) {
|
||||
Message r = new Message(Message.REJECT, nm.piece, nm.begin, nm.length);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -135,23 +136,50 @@ class PeerConnectionOut implements Runnable
|
||||
}
|
||||
nm = null;
|
||||
}
|
||||
else if (nm.type == Message.REQUEST && state.choked)
|
||||
else if (nm.type == Message.REQUEST)
|
||||
{
|
||||
it.remove();
|
||||
//SimpleTimer.getInstance().removeEvent(nm.expireEvent);
|
||||
nm = null;
|
||||
if (state.choked) {
|
||||
it.remove();
|
||||
nm = null;
|
||||
} else if (shouldThrottleRequests) {
|
||||
// previous request in queue throttled, skip this one too
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Additional throttle: " + nm + " to " + peer);
|
||||
nm = null;
|
||||
} else if (!peer.shouldRequest(nm.length)) {
|
||||
// request throttle, skip this and all others in this loop
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Throttle: " + nm + " to " + peer);
|
||||
shouldThrottleRequests = true;
|
||||
nm = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (nm != null)
|
||||
{
|
||||
m = nm;
|
||||
//SimpleTimer.getInstance().removeEvent(nm.expireEvent);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
if (m == null) {
|
||||
m = sendQueue.poll();
|
||||
//SimpleTimer.getInstance().removeEvent(m.expireEvent);
|
||||
m = sendQueue.peek();
|
||||
if (m != null && m.type == Message.PIECE) {
|
||||
// bandwidth limiting
|
||||
// Pieces are the last thing in the queue to be sent so we can
|
||||
// simply wait right here and then loop
|
||||
if (!peer.shouldSend(Math.min(m.length, PeerState.PARTSIZE))) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Throttle: " + m + " to " + peer);
|
||||
try {
|
||||
sendQueue.wait(5000);
|
||||
} catch (InterruptedException ie) {}
|
||||
continue;
|
||||
}
|
||||
} else if (m != null && m.type == Message.REQUEST) {
|
||||
if (shouldThrottleRequests)
|
||||
continue;
|
||||
}
|
||||
m = sendQueue.poll();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,17 +206,14 @@ class PeerConnectionOut implements Runnable
|
||||
// only count the rest of the upload after sendMessage().
|
||||
int remainder = 0;
|
||||
if (m.type == Message.PIECE) {
|
||||
if (m.len <= PeerState.PARTSIZE) {
|
||||
state.uploaded(m.len);
|
||||
} else {
|
||||
state.uploaded(PeerState.PARTSIZE);
|
||||
// first PARTSIZE was signalled in shouldSend() above
|
||||
if (m.len > PeerState.PARTSIZE)
|
||||
remainder = m.len - PeerState.PARTSIZE;
|
||||
}
|
||||
}
|
||||
|
||||
m.sendMessage(dout);
|
||||
if (remainder > 0)
|
||||
state.uploaded(remainder);
|
||||
peer.uploaded(remainder);
|
||||
m = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ import org.klomp.snark.dht.DHT;
|
||||
/**
|
||||
* Coordinates what peer does what.
|
||||
*/
|
||||
class PeerCoordinator implements PeerListener
|
||||
class PeerCoordinator implements PeerListener, BandwidthListener
|
||||
{
|
||||
private final Log _log;
|
||||
|
||||
@@ -124,6 +124,12 @@ class PeerCoordinator implements PeerListener
|
||||
/** Timer to handle all periodical tasks. */
|
||||
private final CheckEvent timer;
|
||||
|
||||
// RerequestEvent and related values
|
||||
private final SimpleTimer2.TimedEvent rerequestTimer;
|
||||
private final Object rerequestLock = new Object();
|
||||
private boolean wasRequestAllowed;
|
||||
private boolean isRerequestScheduled;
|
||||
|
||||
private final byte[] id;
|
||||
private final byte[] infohash;
|
||||
|
||||
@@ -145,6 +151,7 @@ class PeerCoordinator implements PeerListener
|
||||
|
||||
private final MagnetState magnetState;
|
||||
private final CoordinatorListener listener;
|
||||
private final BandwidthListener bwListener;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final RandomSource _random;
|
||||
|
||||
@@ -163,7 +170,7 @@ class PeerCoordinator implements PeerListener
|
||||
* @param storage null if in magnet mode
|
||||
*/
|
||||
public PeerCoordinator(I2PSnarkUtil util, byte[] id, byte[] infohash, MetaInfo metainfo, Storage storage,
|
||||
CoordinatorListener listener, Snark torrent)
|
||||
CoordinatorListener listener, Snark torrent, BandwidthListener bwl)
|
||||
{
|
||||
_util = util;
|
||||
_random = util.getContext().random();
|
||||
@@ -174,6 +181,7 @@ class PeerCoordinator implements PeerListener
|
||||
this.storage = storage;
|
||||
this.listener = listener;
|
||||
this.snark = torrent;
|
||||
bwListener = bwl;
|
||||
|
||||
wantedPieces = new ArrayList<Piece>();
|
||||
setWantedPieces();
|
||||
@@ -188,6 +196,9 @@ class PeerCoordinator implements PeerListener
|
||||
timer = new CheckEvent(_util.getContext(), new PeerCheckerTask(_util, this));
|
||||
timer.schedule((CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD));
|
||||
|
||||
// NOT scheduled until needed
|
||||
rerequestTimer = new RerequestEvent();
|
||||
|
||||
// we don't store the last-requested time, so just delay a random amount
|
||||
_commentsLastRequested.set(util.getContext().clock().now() - (COMMENT_REQ_INTERVAL - _random.nextLong(COMMENT_REQ_DELAY)));
|
||||
}
|
||||
@@ -208,6 +219,42 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerequest after unthrottled
|
||||
* @since 0.9.62
|
||||
*/
|
||||
private class RerequestEvent extends SimpleTimer2.TimedEvent {
|
||||
/** caller must schedule */
|
||||
public RerequestEvent() {
|
||||
super(_util.getContext().simpleTimer2());
|
||||
}
|
||||
|
||||
public void timeReached() {
|
||||
if (bwListener.shouldRequest(null, 0)) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Now unthrottled, rerequest timer poking all peers");
|
||||
// so shouldRequest() won't fire us up again
|
||||
synchronized(rerequestLock) {
|
||||
wasRequestAllowed = true;
|
||||
}
|
||||
for (Peer p : peers) {
|
||||
if (p.isInteresting() && !p.isChoked())
|
||||
p.request();
|
||||
}
|
||||
synchronized(rerequestLock) {
|
||||
isRerequestScheduled = false;
|
||||
}
|
||||
} else {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Still throttled, rerequest timer reschedule");
|
||||
synchronized(rerequestLock) {
|
||||
wasRequestAllowed = false;
|
||||
}
|
||||
schedule(2*1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only called externally from Storage after the double-check fails.
|
||||
* Sets wantedBytes too.
|
||||
@@ -279,7 +326,6 @@ class PeerCoordinator implements PeerListener
|
||||
|
||||
/**
|
||||
* Bytes not yet in storage. Does NOT account for skipped files.
|
||||
* Not exact (does not adjust for last piece size).
|
||||
* Returns how many bytes are still needed to get the complete torrent.
|
||||
* @return -1 if in magnet mode
|
||||
*/
|
||||
@@ -287,8 +333,13 @@ class PeerCoordinator implements PeerListener
|
||||
{
|
||||
if (metainfo == null | storage == null)
|
||||
return -1;
|
||||
// XXX - Only an approximation.
|
||||
return ((long) storage.needed()) * metainfo.getPieceLength(0);
|
||||
int psz = metainfo.getPieceLength(0);
|
||||
long rv = ((long) storage.needed()) * psz;
|
||||
int last = metainfo.getPieces() - 1;
|
||||
BitField bf = storage.getBitField();
|
||||
if (bf != null && !bf.get(last))
|
||||
rv -= psz - metainfo.getPieceLength(last);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,6 +375,78 @@ class PeerCoordinator implements PeerListener
|
||||
return downloaded.get();
|
||||
}
|
||||
|
||||
/////// begin BandwidthListener interface ///////
|
||||
|
||||
/**
|
||||
* Called when a peer has uploaded some bytes of a piece.
|
||||
* @since 0.9.62 params changed
|
||||
*/
|
||||
public void uploaded(int size) {
|
||||
uploaded.addAndGet(size);
|
||||
bwListener.uploaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a peer has downloaded some bytes of a piece.
|
||||
* @since 0.9.62 params changed
|
||||
*/
|
||||
public void downloaded(int size) {
|
||||
downloaded.addAndGet(size);
|
||||
bwListener.downloaded(size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we send this many bytes?
|
||||
* Do NOT call uploaded() if this returns true.
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldSend(int size) {
|
||||
boolean rv = bwListener.shouldSend(size);
|
||||
if (rv)
|
||||
uploaded.addAndGet(size);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we request this many bytes?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean shouldRequest(Peer peer, int size) {
|
||||
boolean rv;
|
||||
synchronized(rerequestLock) {
|
||||
rv = bwListener.shouldRequest(peer, size);
|
||||
if (!wasRequestAllowed && rv) {
|
||||
// we weren't allowed and now we are
|
||||
if (isRerequestScheduled) {
|
||||
// just let the timer run when scheduled, do not pull it in
|
||||
// to prevent thrashing
|
||||
//if (_log.shouldWarn())
|
||||
// _log.warn("Now unthrottled, BUT DON'T reschedule rerequest timer");
|
||||
} else {
|
||||
// schedule the timer
|
||||
// we still have to throw it to the timer so we don't loop
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Now unthrottled, schedule rerequest timer");
|
||||
isRerequestScheduled = true;
|
||||
// no rush, wait at little while
|
||||
rerequestTimer.reschedule(1000);
|
||||
}
|
||||
wasRequestAllowed = true;
|
||||
} else if (wasRequestAllowed && !rv) {
|
||||
// we were allowed and now we aren't
|
||||
if (!isRerequestScheduled) {
|
||||
// schedule the timer
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Now throttled, schedule rerequest timer");
|
||||
isRerequestScheduled = true;
|
||||
rerequestTimer.schedule(3*1000);
|
||||
}
|
||||
wasRequestAllowed = false;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the total uploaded/downloaded onto a RATE_DEPTH deep stack
|
||||
*/
|
||||
@@ -398,6 +521,49 @@ class PeerCoordinator implements PeerListener
|
||||
return rate / (factor * CHECK_PERIOD / 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public long getUpBWLimit() {
|
||||
return bwListener.getUpBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is snark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit()
|
||||
{
|
||||
return bwListener.overUpBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a particular peer who has downloaded this many bytes from us
|
||||
* in the last CHECK_PERIOD over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total)
|
||||
{
|
||||
return total * 1000 / CHECK_PERIOD > getUpBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current limit in Bps
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public long getDownBWLimit() {
|
||||
return bwListener.getDownBWLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Are we currently over the limit?
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public boolean overDownBWLimit() {
|
||||
return bwListener.overDownBWLimit();
|
||||
}
|
||||
|
||||
/////// end BandwidthListener interface ///////
|
||||
|
||||
public MetaInfo getMetaInfo()
|
||||
{
|
||||
return metainfo;
|
||||
@@ -448,18 +614,18 @@ class PeerCoordinator implements PeerListener
|
||||
if (metainfo == null)
|
||||
return 6;
|
||||
int pieces = metainfo.getPieces();
|
||||
if (pieces <= 2)
|
||||
return 4;
|
||||
if (pieces <= 5)
|
||||
return 6;
|
||||
//int size = metainfo.getPieceLength(0);
|
||||
int max = _util.getMaxConnections();
|
||||
// Now that we use temp files, no memory concern
|
||||
//if (size <= 512*1024 || completed())
|
||||
return max;
|
||||
//if (size <= 1024*1024)
|
||||
// return (max + max + 2) / 3;
|
||||
//return (max + 2) / 3;
|
||||
if (pieces <= 10) {
|
||||
if (max > 4) max = 4;
|
||||
} else if (pieces <= 25) {
|
||||
if (max > 10) max = 10;
|
||||
} else if (pieces <= 80) {
|
||||
if (max > 16) max = 16;
|
||||
}
|
||||
long bwl = getDownBWLimit();
|
||||
if (bwl < 32*1024)
|
||||
max = Math.min(max, Math.max(6, (int) (I2PSnarkUtil.MAX_CONNECTIONS * bwl / (32*1024))));
|
||||
return max;
|
||||
}
|
||||
|
||||
public boolean halted() { return halted; }
|
||||
@@ -653,7 +819,7 @@ class PeerCoordinator implements PeerListener
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
peer.runConnection(_util, listener, bitfield, magnetState, partialComplete);
|
||||
peer.runConnection(_util, listener, PeerCoordinator.this, bitfield, magnetState, partialComplete);
|
||||
}
|
||||
};
|
||||
String threadName = "Snark peer " + peer.toString();
|
||||
@@ -677,6 +843,8 @@ class PeerCoordinator implements PeerListener
|
||||
{
|
||||
if (storage == null || storage.getBitField().size() == 0)
|
||||
return;
|
||||
if (overUpBWLimit())
|
||||
return;
|
||||
|
||||
// linked list will contain all interested peers that we choke.
|
||||
// At the start are the peers that have us unchoked at the end the
|
||||
@@ -774,15 +942,6 @@ class PeerCoordinator implements PeerListener
|
||||
*/
|
||||
private static final int MAX_PARALLEL_REQUESTS = 4;
|
||||
|
||||
/**
|
||||
* Returns one of pieces in the given BitField that is still wanted or
|
||||
* -1 if none of the given pieces are wanted.
|
||||
*/
|
||||
public int wantPiece(Peer peer, BitField havePieces) {
|
||||
Piece pc = wantPiece(peer, havePieces, true);
|
||||
return pc != null ? pc.getId() : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns one of pieces in the given BitField that is still wanted or
|
||||
* null if none of the given pieces are wanted.
|
||||
@@ -999,28 +1158,6 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a peer has uploaded some bytes of a piece.
|
||||
*/
|
||||
public void uploaded(Peer peer, int size)
|
||||
{
|
||||
uploaded.addAndGet(size);
|
||||
|
||||
//if (listener != null)
|
||||
// listener.peerChange(this, peer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a peer has downloaded some bytes of a piece.
|
||||
*/
|
||||
public void downloaded(Peer peer, int size)
|
||||
{
|
||||
downloaded.addAndGet(size);
|
||||
|
||||
//if (listener != null)
|
||||
// listener.peerChange(this, peer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if the piece is no good (according to the hash).
|
||||
* In that case the peer that supplied the piece should probably be
|
||||
@@ -1155,7 +1292,7 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
if (uploaders.get() < allowedUploaders())
|
||||
{
|
||||
if(peer.isChoking())
|
||||
if(peer.isChoking() && !overUpBWLimit())
|
||||
{
|
||||
uploaders.incrementAndGet();
|
||||
interestedUploaders.incrementAndGet();
|
||||
@@ -1213,7 +1350,7 @@ class PeerCoordinator implements PeerListener
|
||||
* Also mark the piece unrequested if this peer was the only one.
|
||||
*
|
||||
* @param peer partials, must include the zero-offset (empty) ones too.
|
||||
* No dup pieces, piece.setDownloaded() must be set.
|
||||
* No dup pieces.
|
||||
* len field in Requests is ignored.
|
||||
* @since 0.8.2
|
||||
*/
|
||||
@@ -1231,14 +1368,14 @@ class PeerCoordinator implements PeerListener
|
||||
synchronized(wantedPieces) {
|
||||
for (Request req : partials) {
|
||||
PartialPiece pp = req.getPartialPiece();
|
||||
if (req.off > 0) {
|
||||
if (pp.hasData()) {
|
||||
// PartialPiece.equals() only compares piece number, which is what we want
|
||||
int idx = partialPieces.indexOf(pp);
|
||||
if (idx < 0) {
|
||||
partialPieces.add(pp);
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Saving orphaned partial piece (new) " + pp);
|
||||
} else if (idx >= 0 && pp.getDownloaded() > partialPieces.get(idx).getDownloaded()) {
|
||||
} else if (pp.getDownloaded() > partialPieces.get(idx).getDownloaded()) {
|
||||
// replace what's there now
|
||||
partialPieces.get(idx).release();
|
||||
partialPieces.set(idx, pp);
|
||||
@@ -1295,7 +1432,9 @@ class PeerCoordinator implements PeerListener
|
||||
for(Piece piece : wantedPieces) {
|
||||
if (piece.getId() == savedPiece) {
|
||||
if (peer.isCompleted() && piece.getPeerCount() > 1 &&
|
||||
wantedPieces.size() > 2*END_GAME_THRESHOLD) {
|
||||
wantedPieces.size() > 2*END_GAME_THRESHOLD &&
|
||||
partialPieces.size() < 4 &&
|
||||
_random.nextInt(4) != 0) {
|
||||
// Try to preserve rarest-first
|
||||
// by not requesting a partial piece that at least two non-seeders also have
|
||||
// from a seeder
|
||||
@@ -1323,7 +1462,7 @@ class PeerCoordinator implements PeerListener
|
||||
iter.remove();
|
||||
piece.setRequested(peer, true);
|
||||
if (_log.shouldLog(Log.INFO)) {
|
||||
_log.info("Restoring orphaned partial piece " + pp +
|
||||
_log.info("Restoring orphaned partial piece " + pp + " to " + peer +
|
||||
" Partial list size now: " + partialPieces.size());
|
||||
}
|
||||
return pp;
|
||||
@@ -1435,7 +1574,9 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
}
|
||||
} else if (id == ExtensionHandler.ID_HANDSHAKE) {
|
||||
sendPeers(peer);
|
||||
// We may not have the bitfield yet, but if we do, don't send PEX to seeds
|
||||
if (!peer.isCompleted())
|
||||
sendPeers(peer);
|
||||
sendDHT(peer);
|
||||
if (_util.utCommentsEnabled())
|
||||
sendCommentReq(peer);
|
||||
@@ -1444,8 +1585,8 @@ class PeerCoordinator implements PeerListener
|
||||
|
||||
/**
|
||||
* Send a PEX message to the peer, if he supports PEX.
|
||||
* This just sends everybody we are connected to, we don't
|
||||
* track new vs. old peers yet.
|
||||
* This sends everybody we have connected to since the
|
||||
* last time we sent PEX to him.
|
||||
* @since 0.8.4
|
||||
*/
|
||||
void sendPeers(Peer peer) {
|
||||
@@ -1459,14 +1600,25 @@ class PeerCoordinator implements PeerListener
|
||||
return;
|
||||
try {
|
||||
if (bev.getMap().get(ExtensionHandler.TYPE_PEX) != null) {
|
||||
List<Peer> pList = peerList();
|
||||
pList.remove(peer);
|
||||
for (Iterator<Peer> iter = pList.iterator(); iter.hasNext(); ) {
|
||||
if (iter.next().isWebPeer())
|
||||
iter.remove();
|
||||
List<Peer> pList = new ArrayList<Peer>();
|
||||
long t = peer.getPexLastSent();
|
||||
for (Peer p : peers) {
|
||||
if (p.equals(peer))
|
||||
continue;
|
||||
if (p.isWebPeer())
|
||||
continue;
|
||||
if (p.getWhenConnected() > t)
|
||||
pList.add(p);
|
||||
}
|
||||
if (!pList.isEmpty())
|
||||
if (!pList.isEmpty()) {
|
||||
ExtensionHandler.sendPEX(peer, pList);
|
||||
peer.setPexLastSent(_util.getContext().clock().now());
|
||||
//if (_log.shouldDebug())
|
||||
// _log.debug("Pex: sent " + pList.size() + " new peers to " + peer);
|
||||
//} else {
|
||||
//if (_log.shouldDebug())
|
||||
// _log.debug("Pex: no new peers to send to " + peer);
|
||||
}
|
||||
}
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
}
|
||||
@@ -1734,27 +1886,6 @@ class PeerCoordinator implements PeerListener
|
||||
interestedAndChoking.addAndGet(toAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is snark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit()
|
||||
{
|
||||
if (listener != null)
|
||||
return listener.overUpBWLimit();
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a particular peer who has downloaded this many bytes from us
|
||||
* in the last CHECK_PERIOD over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total)
|
||||
{
|
||||
if (listener != null)
|
||||
return listener.overUpBWLimit(total * 1000 / CHECK_PERIOD);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience
|
||||
* @since 0.9.2
|
||||
|
||||
@@ -120,36 +120,6 @@ interface PeerListener
|
||||
*/
|
||||
ByteArray gotRequest(Peer peer, int piece, int off, int len);
|
||||
|
||||
/**
|
||||
* Called when a (partial) piece has been downloaded from the peer.
|
||||
*
|
||||
* @param peer the Peer from which size bytes where downloaded.
|
||||
* @param size the number of bytes that where downloaded.
|
||||
*/
|
||||
void downloaded(Peer peer, int size);
|
||||
|
||||
/**
|
||||
* Called when a (partial) piece has been uploaded to the peer.
|
||||
*
|
||||
* @param peer the Peer to which size bytes where uploaded.
|
||||
* @param size the number of bytes that where uploaded.
|
||||
*/
|
||||
void uploaded(Peer peer, int size);
|
||||
|
||||
/**
|
||||
* Called when we are downloading from the peer and need to ask for
|
||||
* a new piece. Might be called multiple times before
|
||||
* <code>gotPiece()</code> is called.
|
||||
*
|
||||
* @param peer the Peer that will be asked to provide the piece.
|
||||
* @param bitfield a BitField containing the pieces that the other
|
||||
* side has.
|
||||
*
|
||||
* @return one of the pieces from the bitfield that we want or -1 if
|
||||
* we are no longer interested in the peer.
|
||||
*/
|
||||
int wantPiece(Peer peer, BitField bitfield);
|
||||
|
||||
/**
|
||||
* Called when we are downloading from the peer and may need to ask for
|
||||
* a new piece. Returns true if wantPiece() or getPartialPiece() would return a piece.
|
||||
|
||||
@@ -41,6 +41,7 @@ class PeerState implements DataLoader
|
||||
private final Peer peer;
|
||||
/** Fixme, used by Peer.disconnect() to get to the coordinator */
|
||||
final PeerListener listener;
|
||||
private final BandwidthListener bwListener;
|
||||
/** Null before we have it. locking: this */
|
||||
private MetaInfo metainfo;
|
||||
/** Null unless needed. Contains -1 for all. locking: this */
|
||||
@@ -66,7 +67,8 @@ class PeerState implements DataLoader
|
||||
// Outstanding request
|
||||
private final List<Request> outstandingRequests = new ArrayList<Request>();
|
||||
/** the tail (NOT the head) of the request queue */
|
||||
private Request lastRequest = null;
|
||||
private Request lastRequest;
|
||||
private int currentMaxPipeline;
|
||||
|
||||
// FIXME if piece size < PARTSIZE, pipeline could be bigger
|
||||
/** @since 0.9.47 */
|
||||
@@ -81,17 +83,23 @@ class PeerState implements DataLoader
|
||||
/**
|
||||
* @param metainfo null if in magnet mode
|
||||
*/
|
||||
PeerState(Peer peer, PeerListener listener, MetaInfo metainfo,
|
||||
PeerState(Peer peer, PeerListener listener, BandwidthListener bwl, MetaInfo metainfo,
|
||||
PeerConnectionIn in, PeerConnectionOut out)
|
||||
{
|
||||
this.peer = peer;
|
||||
this.listener = listener;
|
||||
bwListener = bwl;
|
||||
this.metainfo = metainfo;
|
||||
|
||||
this.in = in;
|
||||
this.out = out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
BandwidthListener getBandwidthListener() { return bwListener; }
|
||||
|
||||
// NOTE Methods that inspect or change the state synchronize (on this).
|
||||
|
||||
void keepAliveMessage()
|
||||
@@ -389,7 +397,6 @@ class PeerState implements DataLoader
|
||||
void uploaded(int size)
|
||||
{
|
||||
peer.uploaded(size);
|
||||
listener.uploaded(peer, size);
|
||||
}
|
||||
|
||||
// This is used to flag that we have to back up from the firstOutstandingRequest
|
||||
@@ -408,8 +415,8 @@ class PeerState implements DataLoader
|
||||
void pieceMessage(Request req)
|
||||
{
|
||||
int size = req.len;
|
||||
peer.downloaded(size);
|
||||
listener.downloaded(peer, size);
|
||||
// Now reported byte-by-byte in PartialPiece
|
||||
//peer.downloaded(size);
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("got end of Chunk("
|
||||
@@ -417,11 +424,12 @@ class PeerState implements DataLoader
|
||||
+ peer);
|
||||
|
||||
// Last chunk needed for this piece?
|
||||
// FIXME if priority changed to skip, we will think we're done when we aren't
|
||||
if (getFirstOutstandingRequest(req.getPiece()) == -1)
|
||||
PartialPiece pp = req.getPartialPiece();
|
||||
boolean complete = pp.isComplete();
|
||||
if (complete)
|
||||
{
|
||||
// warning - may block here for a while
|
||||
if (listener.gotPiece(peer, req.getPartialPiece()))
|
||||
if (listener.gotPiece(peer, pp))
|
||||
{
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Got " + req.getPiece() + ": " + peer);
|
||||
@@ -442,9 +450,31 @@ class PeerState implements DataLoader
|
||||
synchronized(this) {
|
||||
pendingRequest = null;
|
||||
}
|
||||
|
||||
// getOutstandingRequest() was called by PeerConnectionIn at the start of the chunk;
|
||||
// if the bandwidth limiter throttled us to zero requests then, try again now
|
||||
if (outstandingRequests.isEmpty()) {
|
||||
addRequest();
|
||||
if (!complete) {
|
||||
synchronized(this) {
|
||||
if (outstandingRequests.isEmpty()) {
|
||||
// we MUST return the partial piece to PeerCoordinator,
|
||||
// or else we will lose it and leak the data
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Throttled, returned to coord. w/ data " + req);
|
||||
List<Request> pcs = Collections.singletonList(req);
|
||||
listener.savePartialPieces(this.peer, pcs);
|
||||
lastRequest = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO this is how we tell we got all the chunks in pieceMessage() above.
|
||||
*
|
||||
*
|
||||
* @return index in outstandingRequests or -1
|
||||
*/
|
||||
synchronized private int getFirstOutstandingRequest(int piece)
|
||||
@@ -567,15 +597,8 @@ class PeerState implements DataLoader
|
||||
List<Request> rv = new ArrayList<Request>(pcs.size());
|
||||
for (Integer p : pcs) {
|
||||
Request req = getLowestOutstandingRequest(p.intValue());
|
||||
if (req != null) {
|
||||
PartialPiece pp = req.getPartialPiece();
|
||||
synchronized(pp) {
|
||||
int dl = pp.getDownloaded();
|
||||
if (req.off != dl)
|
||||
req = new Request(pp, dl);
|
||||
}
|
||||
if (req != null)
|
||||
rv.add(req);
|
||||
}
|
||||
}
|
||||
outstandingRequests.clear();
|
||||
pendingRequest = null;
|
||||
@@ -699,12 +722,6 @@ class PeerState implements DataLoader
|
||||
|
||||
/**
|
||||
* BEP 6
|
||||
* If the peer rejects lower chunks but not higher ones, thus creating holes,
|
||||
* we won't figure it out and the piece will fail, since we don't currently
|
||||
* keep a chunk bitmap in PartialPiece.
|
||||
* As long as the peer rejects all the chunks, or rejects only the last chunks,
|
||||
* no holes are created and we will be fine. The reject messages may be in any order,
|
||||
* just don't make a hole when it's over.
|
||||
*
|
||||
* @since 0.9.21
|
||||
*/
|
||||
@@ -728,19 +745,10 @@ class PeerState implements DataLoader
|
||||
}
|
||||
}
|
||||
if (deletedRequest != null && !haveMoreRequests) {
|
||||
// We must return the piece to the coordinator
|
||||
// Create a new fake request so we can set the offset correctly
|
||||
PartialPiece pp = deletedRequest.getPartialPiece();
|
||||
int downloaded = pp.getDownloaded();
|
||||
Request req;
|
||||
if (deletedRequest.off == downloaded)
|
||||
req = deletedRequest;
|
||||
else
|
||||
req = new Request(pp, downloaded, 1);
|
||||
List<Request> pcs = Collections.singletonList(req);
|
||||
List<Request> pcs = Collections.singletonList(deletedRequest);
|
||||
listener.savePartialPieces(this.peer, pcs);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Returned to coord. w/ offset " + pp.getDownloaded() + " due to reject(" + piece + ',' + begin + ',' + length + ") from " + peer);
|
||||
_log.warn("Returned to coord. w/ data " + deletedRequest.getPartialPiece().getDownloaded() + " due to reject(" + piece + ',' + begin + ',' + length + ") from " + peer);
|
||||
}
|
||||
if (lastRequest != null && lastRequest.getPiece() == piece &&
|
||||
lastRequest.off == begin && lastRequest.len == length)
|
||||
@@ -866,72 +874,108 @@ class PeerState implements DataLoader
|
||||
*
|
||||
* This is called from several places:
|
||||
*<pre>
|
||||
* By getOustandingRequest() when the first part of a chunk comes in
|
||||
* By getOutstandingRequest() when the first part of a chunk comes in
|
||||
* By havePiece() when somebody got a new piece completed
|
||||
* By chokeMessage() when we receive an unchoke
|
||||
* By setInteresting() when we are now interested
|
||||
* By PeerCoordinator.updatePiecePriorities()
|
||||
*</pre>
|
||||
*/
|
||||
synchronized void addRequest()
|
||||
void addRequest()
|
||||
{
|
||||
// no bitfield yet? nothing to request then.
|
||||
if (bitfield == null)
|
||||
return;
|
||||
if (metainfo == null)
|
||||
return;
|
||||
boolean more_pieces = true;
|
||||
while (more_pieces)
|
||||
{
|
||||
more_pieces = outstandingRequests.size() < peer.getMaxPipeline();
|
||||
// We want something and we don't have outstanding requests?
|
||||
if (more_pieces && lastRequest == null) {
|
||||
// we have nothing in the queue right now
|
||||
if (!interesting) {
|
||||
// If we need something, set interesting but delay pulling
|
||||
// a request from the PeerCoordinator until unchoked.
|
||||
if (listener.needPiece(this.peer, bitfield)) {
|
||||
setInteresting(true);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() we need something, setting interesting, delaying requestNextPiece()");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() needs nothing");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (choked) {
|
||||
// If choked, delay pulling
|
||||
// a request from the PeerCoordinator until unchoked.
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() we are choked, delaying requestNextPiece()");
|
||||
return;
|
||||
}
|
||||
// huh? rv unused
|
||||
more_pieces = requestNextPiece();
|
||||
} else if (more_pieces) // We want something
|
||||
// Initial bw check. We do the actual accounting in PeerConnectionOut.
|
||||
// Implement a simple AIMD slow-start on the request queue size with
|
||||
// currentMaxPipeline counter.
|
||||
// Avoid cross-peer deadlocks from PeerCoordinator, call this outside the lock
|
||||
if (!bwListener.shouldRequest(peer, 0)) {
|
||||
synchronized(this) {
|
||||
// Due to changes elsewhere we can let this go down to zero now
|
||||
currentMaxPipeline /= 2;
|
||||
}
|
||||
if (_log.shouldWarn())
|
||||
_log.warn(peer + " throttle request, interesting? " + interesting + " choked? " + choked +
|
||||
" reqq: " + outstandingRequests.size() + " maxp: " + currentMaxPipeline);
|
||||
return;
|
||||
}
|
||||
synchronized(this) {
|
||||
// adjust currentMaxPipeline
|
||||
long rate = bwListener.getDownloadRate();
|
||||
long limit = bwListener.getDownBWLimit();
|
||||
if (rate < limit * 7 / 10) {
|
||||
if (currentMaxPipeline < peer.getMaxPipeline())
|
||||
currentMaxPipeline++;
|
||||
} else if (rate > limit * 9 / 10) {
|
||||
currentMaxPipeline = 1;
|
||||
} else if (currentMaxPipeline < 2) {
|
||||
currentMaxPipeline++;
|
||||
}
|
||||
boolean more_pieces = true;
|
||||
while (more_pieces)
|
||||
{
|
||||
int pieceLength;
|
||||
boolean isLastChunk;
|
||||
pieceLength = metainfo.getPieceLength(lastRequest.getPiece());
|
||||
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
|
||||
|
||||
// Last part of a piece?
|
||||
if (isLastChunk)
|
||||
more_pieces = outstandingRequests.size() < currentMaxPipeline;
|
||||
// We want something and we don't have outstanding requests?
|
||||
if (more_pieces && lastRequest == null) {
|
||||
// we have nothing in the queue right now
|
||||
if (!interesting) {
|
||||
// If we need something, set interesting but delay pulling
|
||||
// a request from the PeerCoordinator until unchoked.
|
||||
if (listener.needPiece(this.peer, bitfield)) {
|
||||
setInteresting(true);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() we need something, setting interesting, delaying requestNextPiece()");
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() needs nothing");
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (choked) {
|
||||
// If choked, delay pulling
|
||||
// a request from the PeerCoordinator until unchoked.
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " addRequest() we are choked, delaying requestNextPiece()");
|
||||
return;
|
||||
}
|
||||
more_pieces = requestNextPiece();
|
||||
else
|
||||
} else if (more_pieces) // We want something
|
||||
{
|
||||
int pieceLength;
|
||||
boolean isLastChunk;
|
||||
pieceLength = metainfo.getPieceLength(lastRequest.getPiece());
|
||||
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
|
||||
|
||||
// Last part of a piece?
|
||||
if (isLastChunk) {
|
||||
more_pieces = requestNextPiece();
|
||||
} else {
|
||||
PartialPiece nextPiece = lastRequest.getPartialPiece();
|
||||
int nextBegin = lastRequest.off + PARTSIZE;
|
||||
int maxLength = pieceLength - nextBegin;
|
||||
int nextLength = maxLength > PARTSIZE ? PARTSIZE
|
||||
: maxLength;
|
||||
Request req
|
||||
= new Request(nextPiece,nextBegin, nextLength);
|
||||
outstandingRequests.add(req);
|
||||
if (!choked)
|
||||
out.sendRequest(req);
|
||||
lastRequest = req;
|
||||
while (true) {
|
||||
// don't rerequest chunks we already have
|
||||
if (!nextPiece.hasChunk(nextBegin / PARTSIZE)) {
|
||||
int maxLength = pieceLength - nextBegin;
|
||||
int nextLength = maxLength > PARTSIZE ? PARTSIZE
|
||||
: maxLength;
|
||||
Request req = new Request(nextPiece,nextBegin, nextLength);
|
||||
outstandingRequests.add(req);
|
||||
if (!choked)
|
||||
out.sendRequest(req);
|
||||
lastRequest = req;
|
||||
break;
|
||||
} else {
|
||||
nextBegin += PARTSIZE;
|
||||
if (nextBegin >= pieceLength) {
|
||||
more_pieces = requestNextPiece();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -972,47 +1016,6 @@ class PeerState implements DataLoader
|
||||
pp.release();
|
||||
}
|
||||
}
|
||||
|
||||
/******* getPartialPiece() does it all now
|
||||
// Note that in addition to the bitfield, PeerCoordinator uses
|
||||
// its request tracking and isRequesting() to determine
|
||||
// what piece to give us next.
|
||||
int nextPiece = listener.wantPiece(peer, bitfield);
|
||||
if (nextPiece != -1
|
||||
&& (lastRequest == null || lastRequest.getPiece() != nextPiece)) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " want piece " + nextPiece);
|
||||
// Fail safe to make sure we are interested
|
||||
// When we transition into the end game we may not be interested...
|
||||
if (!interesting) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " transition to end game, setting interesting");
|
||||
interesting = true;
|
||||
out.sendInterest(true);
|
||||
}
|
||||
|
||||
int piece_length = metainfo.getPieceLength(nextPiece);
|
||||
//Catch a common place for OOMs esp. on 1MB pieces
|
||||
byte[] bs;
|
||||
try {
|
||||
bs = new byte[piece_length];
|
||||
} catch (OutOfMemoryError oom) {
|
||||
_log.warn("Out of memory, can't request piece " + nextPiece, oom);
|
||||
return false;
|
||||
}
|
||||
|
||||
int length = Math.min(piece_length, PARTSIZE);
|
||||
Request req = new Request(nextPiece, bs, 0, length);
|
||||
outstandingRequests.add(req);
|
||||
if (!choked)
|
||||
out.sendRequest(req);
|
||||
lastRequest = req;
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " no more pieces to request");
|
||||
}
|
||||
*******/
|
||||
}
|
||||
|
||||
// failsafe
|
||||
|
||||
@@ -74,8 +74,8 @@ class Request
|
||||
/**
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public void read(DataInputStream din) throws IOException {
|
||||
piece.read(din, off, len);
|
||||
public void read(DataInputStream din, BandwidthListener bwl) throws IOException {
|
||||
piece.read(din, off, len, bwl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -252,7 +252,7 @@ public class Snark
|
||||
/**
|
||||
* from main() via parseArguments() single torrent
|
||||
*
|
||||
* @deprecated unused
|
||||
* unused
|
||||
*/
|
||||
/****
|
||||
Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
|
||||
@@ -264,7 +264,7 @@ public class Snark
|
||||
/**
|
||||
* single torrent - via router
|
||||
*
|
||||
* @deprecated unused
|
||||
* unused
|
||||
*/
|
||||
/****
|
||||
public Snark(I2PAppContext ctx, Properties opts, String torrent,
|
||||
@@ -608,7 +608,7 @@ public class Snark
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Starting PeerCoordinator, ConnectionAcceptor, and TrackerClient");
|
||||
activity = "Collecting pieces";
|
||||
coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this);
|
||||
coordinator = new PeerCoordinator(_util, id, infoHash, meta, storage, this, this, completeListener.getBandwidthListener());
|
||||
coordinator.setUploaded(savedUploaded);
|
||||
if (_peerCoordinatorSet != null) {
|
||||
// multitorrent
|
||||
@@ -1259,6 +1259,8 @@ public class Snark
|
||||
*/
|
||||
private void fatalRouter(String s, Throwable t) throws RouterException {
|
||||
_log.error(s, t);
|
||||
if (!_util.getContext().isRouterContext())
|
||||
System.out.println(s);
|
||||
stopTorrent(true);
|
||||
if (completeListener != null)
|
||||
completeListener.fatal(this, s);
|
||||
@@ -1333,6 +1335,9 @@ public class Snark
|
||||
*/
|
||||
public void replaceMetaInfo(MetaInfo metainfo) {
|
||||
meta = metainfo;
|
||||
TrackerClient tc = trackerclient;
|
||||
if (tc != null)
|
||||
tc.reinitialize();
|
||||
}
|
||||
|
||||
///////////// Begin StorageListener methods
|
||||
@@ -1465,31 +1470,6 @@ public class Snark
|
||||
return totalUploaders > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is i2psnark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit() {
|
||||
if (_peerCoordinatorSet == null)
|
||||
return false;
|
||||
long total = 0;
|
||||
for (PeerCoordinator c : _peerCoordinatorSet) {
|
||||
if (!c.halted())
|
||||
total += c.getCurrentUploadRate();
|
||||
}
|
||||
long limit = 1024l * _util.getMaxUpBW();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Total up bw: " + total + " Limit: " + limit);
|
||||
return total > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a particular peer who has this recent download rate (in Bps) over our upstream bandwidth limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total) {
|
||||
long limit = 1024l * _util.getMaxUpBW();
|
||||
return total > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A unique ID for this torrent, useful for RPC
|
||||
* @return positive value unless you wrap around
|
||||
|
||||
@@ -25,10 +25,12 @@ import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.i2p.CoreVersion;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.ClientApp;
|
||||
import net.i2p.app.ClientAppManager;
|
||||
import net.i2p.app.ClientAppState;
|
||||
import net.i2p.app.NavService;
|
||||
import net.i2p.app.NotificationService;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.streaming.I2PSocketManager.DisconnectListener;
|
||||
@@ -85,8 +87,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
private final Log _log;
|
||||
private final UIMessages _messages;
|
||||
private final I2PSnarkUtil _util;
|
||||
private PeerCoordinatorSet _peerCoordinatorSet;
|
||||
private ConnectionAcceptor _connectionAcceptor;
|
||||
private final PeerCoordinatorSet _peerCoordinatorSet;
|
||||
private final ConnectionAcceptor _connectionAcceptor;
|
||||
private final BandwidthManager _bwManager;
|
||||
private Thread _monitor;
|
||||
private volatile boolean _running;
|
||||
private volatile boolean _stopping;
|
||||
@@ -102,6 +105,8 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
//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";
|
||||
/** @since 0.9.62 */
|
||||
public static final String PROP_DOWNBW_MAX = "i2psnark.downbw.max";
|
||||
public static final String PROP_DIR = "i2psnark.dir";
|
||||
private static final String PROP_META_PREFIX = "i2psnark.zmeta.";
|
||||
private static final String PROP_META_RUNNING = "running";
|
||||
@@ -127,7 +132,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
private static final String PROP_META_ACTIVITY = "activity";
|
||||
|
||||
private static final String CONFIG_FILE_SUFFIX = ".config";
|
||||
private static final String CONFIG_FILE = "i2psnark" + CONFIG_FILE_SUFFIX;
|
||||
public static final String CONFIG_FILE = "i2psnark" + CONFIG_FILE_SUFFIX;
|
||||
private static final String COMMENT_FILE_SUFFIX = ".comments.txt.gz";
|
||||
public static final String PROP_FILES_PUBLIC = "i2psnark.filesPublic";
|
||||
public static final String PROP_OLD_AUTO_START = "i2snark.autoStart"; // oops
|
||||
@@ -162,17 +167,25 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
private static final String PROP_COMMENTS = "i2psnark.comments";
|
||||
/** @since 0.9.31 */
|
||||
private static final String PROP_COMMENTS_NAME = "i2psnark.commentsName";
|
||||
/** @since 0.9.58 */
|
||||
public static final String PROP_MAX_FILES_PER_TORRENT = "i2psnark.maxFilesPerTorrent";
|
||||
|
||||
public static final int MIN_UP_BW = 10;
|
||||
public static final int MIN_UP_BW = 5;
|
||||
public static final int MIN_DOWN_BW = 2 * MIN_UP_BW;
|
||||
public static final int DEFAULT_MAX_UP_BW = 25;
|
||||
private static final int DEFAULT_MAX_DOWN_BW = 200;
|
||||
public static final int DEFAULT_STARTUP_DELAY = 3;
|
||||
public static final int DEFAULT_REFRESH_DELAY_SECS = 15;
|
||||
private static final int DEFAULT_PAGE_SIZE = 50;
|
||||
public static final int DEFAULT_TUNNEL_QUANTITY = 3;
|
||||
public static final int DEFAULT_MAX_FILES_PER_TORRENT = 2000;
|
||||
public static final String CONFIG_DIR_SUFFIX = ".d";
|
||||
private static final String SUBDIR_PREFIX = "s";
|
||||
private static final String B64 = Base64.ALPHABET_I2P;
|
||||
private static final int MAX_MESSAGES = 100;
|
||||
private static final String EXTRA = "";
|
||||
/** @since 0.9.58 */
|
||||
public static final String FULL_VERSION = CoreVersion.VERSION + EXTRA;
|
||||
|
||||
/**
|
||||
* "name", "announceURL=websiteURL" pairs
|
||||
@@ -229,7 +242,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
// psi go - unregistered
|
||||
"uajd4nctepxpac4c4bdyrdw7qvja2a5u3x25otfhkptcjgd53ioq.b32.i2p",
|
||||
// Vuze - unregistered
|
||||
"crs2nugpvoqygnpabqbopwyjqettwszth6ubr2fh7whstlos3a6q.b32.i2p"
|
||||
"crs2nugpvoqygnpabqbopwyjqettwszth6ubr2fh7whstlos3a6q.b32.i2p",
|
||||
"opentracker.r4sas.i2p", "punzipidirfqspstvzpj6gb4tkuykqp6quurj6e23bgxcxhdoe7q.b32.i2p",
|
||||
"opentracker.skank.i2p", "by7luzwhx733fhc5ug2o75dcaunblq2ztlshzd7qvptaoa73nqua.b32.i2p"
|
||||
}));
|
||||
|
||||
static {
|
||||
@@ -271,6 +286,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
_log = _context.logManager().getLog(SnarkManager.class);
|
||||
_messages = new UIMessages(MAX_MESSAGES);
|
||||
_util = new I2PSnarkUtil(_context, ctxName, this);
|
||||
_peerCoordinatorSet = new PeerCoordinatorSet();
|
||||
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
|
||||
_bwManager = new BandwidthManager(ctx, DEFAULT_MAX_UP_BW * 1024, DEFAULT_MAX_DOWN_BW * 1024);
|
||||
DEFAULT_AUTO_START = !ctx.isRouterContext();
|
||||
String cfile = ctxName + CONFIG_FILE_SUFFIX;
|
||||
File configFile = new File(cfile);
|
||||
@@ -289,15 +307,22 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
*/
|
||||
public void start() {
|
||||
_running = true;
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if ("i2psnark".equals(_contextName)) {
|
||||
// Register with the ClientAppManager so the rpc plugin can find us
|
||||
// only if default instance
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null)
|
||||
cmgr.register(this);
|
||||
} else {
|
||||
// Register link with NavHelper
|
||||
if (cmgr != null) {
|
||||
NavService nav = (NavService) cmgr.getRegisteredApp("NavHelper");
|
||||
if (nav != null) {
|
||||
String name = DataHelper.stripHTML(_contextPath.substring(1));
|
||||
nav.registerApp(name, name, _contextPath, null, "/themes/console/images/i2psnark.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
_peerCoordinatorSet = new PeerCoordinatorSet();
|
||||
_connectionAcceptor = new ConnectionAcceptor(_util, _peerCoordinatorSet);
|
||||
_monitor = new I2PAppThread(new DirMonitor(), "Snark DirMonitor", true);
|
||||
_monitor.start();
|
||||
// only if default instance
|
||||
@@ -377,11 +402,20 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
_connectionAcceptor.halt();
|
||||
_idleChecker.cancel();
|
||||
stopAllTorrents(true);
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if ("i2psnark".equals(_contextName)) {
|
||||
// only if default instance
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null)
|
||||
cmgr.unregister(this);
|
||||
} else {
|
||||
// Unregister link with NavHelper
|
||||
if (cmgr != null) {
|
||||
NavService nav = (NavService) cmgr.getRegisteredApp("NavHelper");
|
||||
if (nav != null) {
|
||||
String name = DataHelper.stripHTML(_contextPath.substring(1));
|
||||
nav.unregisterApp(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Snark stop() end");
|
||||
@@ -433,6 +467,14 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
/** hook to I2PSnarkUtil for the servlet */
|
||||
public I2PSnarkUtil util() { return _util; }
|
||||
|
||||
/**
|
||||
* The BandwidthManager.
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public BandwidthListener getBandwidthListener() {
|
||||
return _bwManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use if it does not include a link.
|
||||
* Escapes '<' and '>' before queueing
|
||||
@@ -701,7 +743,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
File conf = configFile(_configDir, ih);
|
||||
synchronized(_configLock) { // one lock for all
|
||||
try {
|
||||
DataHelper.loadProps(rv, conf);
|
||||
I2PSnarkUtil.loadProps(rv, conf);
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
return rv;
|
||||
@@ -942,13 +984,21 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
* @return true if we got a response from the router
|
||||
*/
|
||||
private boolean getBWLimit() {
|
||||
boolean shouldSet = !_config.containsKey(PROP_UPBW_MAX);
|
||||
if (shouldSet || !_context.isRouterContext()) {
|
||||
int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort());
|
||||
if (limits == null)
|
||||
return false;
|
||||
if (shouldSet && limits[1] > 0)
|
||||
_util.setMaxUpBW(limits[1]);
|
||||
int[] limits = BWLimits.getBWLimits(_util.getI2CPHost(), _util.getI2CPPort());
|
||||
if (limits == null)
|
||||
return false;
|
||||
int up = limits[1];
|
||||
if (up > 0) {
|
||||
int maxup = getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW);
|
||||
if (maxup > up)
|
||||
maxup = up;
|
||||
_util.setMaxUpBW(maxup);
|
||||
_bwManager.setUpBWLimit(maxup * 1000L);
|
||||
}
|
||||
int down = limits[0];
|
||||
if (down > 0) {
|
||||
int maxdown = getInt(PROP_DOWNBW_MAX, DEFAULT_MAX_DOWN_BW);
|
||||
_bwManager.setDownBWLimit(Math.min(down, maxdown) * 1000L);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -977,6 +1027,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
// _util.setProxy(eepHost, eepPort);
|
||||
_util.setMaxUploaders(getInt(PROP_UPLOADERS_TOTAL, Snark.MAX_TOTAL_UPLOADERS));
|
||||
_util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
|
||||
_util.setMaxFilesPerTorrent(getInt(PROP_MAX_FILES_PER_TORRENT, DEFAULT_MAX_FILES_PER_TORRENT));
|
||||
_util.setStartupDelay(getInt(PROP_STARTUP_DELAY, DEFAULT_STARTUP_DELAY));
|
||||
_util.setFilesPublic(areFilesPublic());
|
||||
_util.setOpenTrackers(getListConfig(PROP_OPENTRACKERS, DEFAULT_OPENTRACKERS));
|
||||
@@ -1019,13 +1070,13 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
public void updateConfig(String dataDir, boolean filesPublic, boolean autoStart, boolean smartSort, String refreshDelay,
|
||||
String startDelay, String pageSize, String seedPct, String eepHost,
|
||||
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
|
||||
String upLimit, String upBW, boolean useOpenTrackers, boolean useDHT, String theme,
|
||||
String upLimit, String upBW, String downBW, boolean useOpenTrackers, boolean useDHT, String theme,
|
||||
String lang, boolean enableRatings, boolean enableComments, String commentName, boolean collapsePanels) {
|
||||
synchronized(_configLock) {
|
||||
locked_updateConfig(dataDir, filesPublic, autoStart, smartSort, refreshDelay,
|
||||
startDelay, pageSize, seedPct, eepHost,
|
||||
eepPort, i2cpHost, i2cpPort, i2cpOpts,
|
||||
upLimit, upBW, useOpenTrackers, useDHT, theme,
|
||||
upLimit, upBW, downBW, useOpenTrackers, useDHT, theme,
|
||||
lang, enableRatings, enableComments, commentName, collapsePanels);
|
||||
}
|
||||
}
|
||||
@@ -1033,7 +1084,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
private void locked_updateConfig(String dataDir, boolean filesPublic, boolean autoStart, boolean smartSort, String refreshDelay,
|
||||
String startDelay, String pageSize, String seedPct, String eepHost,
|
||||
String eepPort, String i2cpHost, String i2cpPort, String i2cpOpts,
|
||||
String upLimit, String upBW, boolean useOpenTrackers, boolean useDHT, String theme,
|
||||
String upLimit, String upBW, String downBW, boolean useOpenTrackers, boolean useDHT, String theme,
|
||||
String lang, boolean enableRatings, boolean enableComments, String commentName, boolean collapsePanels) {
|
||||
boolean changed = false;
|
||||
boolean interruptMonitor = false;
|
||||
@@ -1071,6 +1122,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if ( limit != _util.getMaxUpBW()) {
|
||||
if ( limit >= MIN_UP_BW ) {
|
||||
_util.setMaxUpBW(limit);
|
||||
_bwManager.setUpBWLimit(limit * 1000L);
|
||||
changed = true;
|
||||
_config.setProperty(PROP_UPBW_MAX, Integer.toString(limit));
|
||||
addMessage(_t("Up BW limit changed to {0}KBps", limit));
|
||||
@@ -1079,6 +1131,20 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
}
|
||||
}
|
||||
if (downBW != null) {
|
||||
int limit = (int) (_bwManager.getDownBWLimit() / 1024);
|
||||
try { limit = Integer.parseInt(downBW.trim()); } catch (NumberFormatException nfe) {}
|
||||
if ( limit != _bwManager.getDownBWLimit()) {
|
||||
if ( limit >= MIN_DOWN_BW ) {
|
||||
_bwManager.setDownBWLimit(limit * 1000L);
|
||||
changed = true;
|
||||
_config.setProperty(PROP_DOWNBW_MAX, Integer.toString(limit));
|
||||
//addMessage(_t("Up BW limit changed to {0}KBps", limit));
|
||||
} else {
|
||||
//addMessage(_t("Minimum up bandwidth limit is {0}KBps", MIN_UP_BW));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (startDelay != null && _context.isRouterContext()) {
|
||||
int minutes = _util.getStartupDelay();
|
||||
@@ -1135,7 +1201,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if (dataDir != null && !dataDir.equals(getDataDir().getAbsolutePath())) {
|
||||
dataDir = DataHelper.stripHTML(dataDir.trim());
|
||||
File dd = areFilesPublic() ? new File(dataDir) : new SecureDirectory(dataDir);
|
||||
if (!dd.isAbsolute()) {
|
||||
if (_util.connected()) {
|
||||
addMessage(_t("Stop all torrents before changing data directory"));
|
||||
} else if (!dd.isAbsolute()) {
|
||||
addMessage(_t("Data directory must be an absolute path") + ": " + dataDir);
|
||||
} else if (!dd.exists() && !dd.mkdirs()) {
|
||||
// save this tag for now, may need it again
|
||||
@@ -1151,10 +1219,16 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
addMessage(_t("No write permissions for data directory") + ": " + dataDir);
|
||||
changed = true;
|
||||
interruptMonitor = true;
|
||||
_config.setProperty(PROP_DIR, dataDir);
|
||||
synchronized (_snarks) {
|
||||
for (Snark snark : _snarks.values()) {
|
||||
// leave magnets alone, remove everything else
|
||||
if (snark.getMetaInfo() != null)
|
||||
stopTorrent(snark, true);
|
||||
}
|
||||
_config.setProperty(PROP_DIR, dataDir);
|
||||
}
|
||||
addMessage(_t("Data directory changed to {0}", dataDir));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Standalone (app context) language.
|
||||
@@ -1232,7 +1306,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
Properties p = new Properties();
|
||||
p.putAll(opts);
|
||||
_util.setI2CPConfig(i2cpHost, port, p);
|
||||
_util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
|
||||
int max = getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW);
|
||||
_util.setMaxUpBW(max);
|
||||
_bwManager.setUpBWLimit(max * 1000);
|
||||
addMessage(_t("I2CP and tunnel changes will take effect after stopping all torrents"));
|
||||
} else if (!reconnect) {
|
||||
// The usual case, the other two are if not in router context
|
||||
@@ -1247,7 +1323,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
addMessage(_t("I2CP settings changed to {0}", i2cpHost + ':' + port + ' ' + i2cpOpts));
|
||||
_util.setI2CPConfig(i2cpHost, port, opts);
|
||||
_util.setMaxUpBW(getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW));
|
||||
int max = getInt(PROP_UPBW_MAX, DEFAULT_MAX_UP_BW);
|
||||
_util.setMaxUpBW(max);
|
||||
_bwManager.setUpBWLimit(max * 1000);
|
||||
boolean ok = _util.connect();
|
||||
if (!ok) {
|
||||
addMessage(_t("Unable to connect with the new settings, reverting to the old I2CP settings"));
|
||||
@@ -1456,9 +1534,6 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
}
|
||||
|
||||
/** hardcoded for sanity. perhaps this should be customizable, for people who increase their ulimit, etc. */
|
||||
public static final int MAX_FILES_PER_TORRENT = 2000;
|
||||
|
||||
/**
|
||||
* Set of canonical .torrent filenames that we are dealing with.
|
||||
* An unsynchronized copy.
|
||||
@@ -1718,21 +1793,31 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
String link = linkify(torrent);
|
||||
if (!dontAutoStart && shouldAutoStart() && running) {
|
||||
if (!_util.connected()) {
|
||||
addMessage(_t("Connecting to I2P"));
|
||||
String msg = _t("Connecting to I2P");
|
||||
addMessage(msg);
|
||||
if (!_context.isRouterContext())
|
||||
System.out.println(msg);
|
||||
boolean ok = _util.connect();
|
||||
if (!ok) {
|
||||
if (_context.isRouterContext())
|
||||
if (_context.isRouterContext()) {
|
||||
addMessage(_t("Unable to connect to I2P"));
|
||||
else
|
||||
addMessage(_t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort());
|
||||
} else {
|
||||
msg = _t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort();
|
||||
addMessage(msg);
|
||||
System.out.println(msg);
|
||||
}
|
||||
// this would rename the torrent to .BAD
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
torrent.startTorrent();
|
||||
addMessageNoEscape(_t("Torrent added and started: {0}", link));
|
||||
if (!_context.isRouterContext())
|
||||
System.out.println(_t("Torrent added and started: {0}", torrent.getBaseName()));
|
||||
} else {
|
||||
addMessageNoEscape(_t("Torrent added: {0}", link));
|
||||
if (!_context.isRouterContext())
|
||||
System.out.println(_t("Torrent added: {0}", torrent.getBaseName()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2275,7 +2360,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if (!subdir.exists())
|
||||
subdir.mkdirs();
|
||||
try {
|
||||
DataHelper.storeProps(config, conf);
|
||||
I2PSnarkUtil.storeProps(config, conf);
|
||||
if (_log.shouldInfo())
|
||||
_log.info("Saved config to " + conf /* , new Exception() */ );
|
||||
} catch (IOException ioe) {
|
||||
@@ -2417,8 +2502,11 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
*/
|
||||
private String validateTorrent(MetaInfo info) {
|
||||
List<List<String>> files = info.getFiles();
|
||||
if ( (files != null) && (files.size() > MAX_FILES_PER_TORRENT) ) {
|
||||
return _t("Too many files in \"{0}\" ({1})!", info.getName(), files.size());
|
||||
if (files != null && files.size() > _util.getMaxFilesPerTorrent()) {
|
||||
return _t("Too many files in \"{0}\" ({1})!", info.getName(), files.size()) +
|
||||
" - limit is " + _util.getMaxFilesPerTorrent() + ", zip them or set " +
|
||||
PROP_MAX_FILES_PER_TORRENT + '=' + files.size() + " in " +
|
||||
_configFile.getAbsolutePath() + " and restart";
|
||||
} else if ( (files == null) && (info.getName().endsWith(".torrent")) ) {
|
||||
return _t("Torrent file \"{0}\" cannot end in \".torrent\"!", info.getName());
|
||||
} else if (info.getPieces() <= 0) {
|
||||
@@ -2537,6 +2625,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||
// Remove that first message
|
||||
_messages.clearThrough(id);
|
||||
} else if (_context.isRouterContext()) {
|
||||
// to wait for client manager to be up so we can get bandwidth limits
|
||||
try { Thread.sleep(3000); } catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
// here because we need to delay until I2CP is up
|
||||
@@ -2554,6 +2645,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
// Test if the router is there
|
||||
// For standalone, this will probe the router every 60 seconds if not connected
|
||||
boolean oldOK = routerOK;
|
||||
// standalone, first time only
|
||||
if (doMagnets && !_context.isRouterContext())
|
||||
dtgNotify(Log.INFO, _t("Connecting to I2P") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort());
|
||||
routerOK = getBWLimit();
|
||||
if (routerOK) {
|
||||
autostart = shouldAutoStart();
|
||||
@@ -2564,17 +2658,29 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
String prop = config.getProperty(PROP_META_RUNNING);
|
||||
if (prop == null || Boolean.parseBoolean(prop)) {
|
||||
if (!_util.connected()) {
|
||||
addMessage(_t("Connecting to I2P"));
|
||||
String msg = _t("Connecting to I2P");
|
||||
addMessage(msg);
|
||||
if (!_context.isRouterContext())
|
||||
dtgNotify(Log.INFO, msg + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort());
|
||||
// getBWLimit() was successful so this should work
|
||||
boolean ok = _util.connect();
|
||||
if (!ok) {
|
||||
if (_context.isRouterContext())
|
||||
if (_context.isRouterContext()) {
|
||||
addMessage(_t("Unable to connect to I2P"));
|
||||
else
|
||||
addMessage(_t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort());
|
||||
} else {
|
||||
msg = _t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort();
|
||||
addMessage(msg);
|
||||
dtgNotify(Log.ERROR, msg);
|
||||
}
|
||||
routerOK = false;
|
||||
autostart = false;
|
||||
break;
|
||||
} else {
|
||||
if (!_context.isRouterContext()) {
|
||||
msg = "Connected to I2P at " + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort();
|
||||
addMessage(msg);
|
||||
dtgNotify(Log.INFO, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
addMessageNoEscape(_t("Starting up torrent {0}", linkify(snark)));
|
||||
@@ -2589,7 +2695,8 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
}
|
||||
if (routerOK)
|
||||
addMessage(_t("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
|
||||
addMessage(_t("Down bandwidth limit is {0} KBps", _bwManager.getUpBWLimit() / 1024) + "; " +
|
||||
_t("Up bandwidth limit is {0} KBps", _util.getMaxUpBW()));
|
||||
}
|
||||
} else {
|
||||
autostart = false;
|
||||
@@ -2623,10 +2730,13 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if (ok)
|
||||
cleanupTorrentStatus();
|
||||
if (!routerOK) {
|
||||
if (_context.isRouterContext())
|
||||
if (_context.isRouterContext()) {
|
||||
addMessage(_t("Unable to connect to I2P"));
|
||||
else
|
||||
addMessage(_t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort());
|
||||
} else {
|
||||
String msg = _t("Error connecting to I2P - check your I2CP settings!") + ' ' + _util.getI2CPHost() + ':' + _util.getI2CPPort();
|
||||
addMessage(msg);
|
||||
dtgNotify(Log.ERROR, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
try { Thread.sleep(60*1000); } catch (InterruptedException ie) {}
|
||||
@@ -2646,15 +2756,9 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
return;
|
||||
if (snark.getDownloaded() > 0) {
|
||||
addMessageNoEscape(_t("Download finished: {0}", linkify(snark)));
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null) {
|
||||
NotificationService ns = (NotificationService) cmgr.getRegisteredApp("desktopgui");
|
||||
if (ns != null) {
|
||||
ns.notify("I2PSnark", null, Log.INFO, _t("I2PSnark"),
|
||||
_t("Download finished: {0}", snark.getName()),
|
||||
"/i2psnark/" + linkify(snark));
|
||||
}
|
||||
}
|
||||
dtgNotify(Log.INFO,
|
||||
_t("Download finished: {0}", snark.getName()),
|
||||
"/i2psnark/" + linkify(snark));
|
||||
}
|
||||
updateStatus(snark);
|
||||
}
|
||||
@@ -2745,6 +2849,38 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
|
||||
// End Snark.CompleteListeners
|
||||
|
||||
/**
|
||||
* Send a notification to the user via desktopgui and,
|
||||
* if standalone, on the console.
|
||||
*
|
||||
* @param priority log level
|
||||
* @param message translated
|
||||
* @since 0.9.54
|
||||
*/
|
||||
private void dtgNotify(int priority, String message) {
|
||||
dtgNotify(priority, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification to the user via desktopgui and,
|
||||
* if standalone, on the console.
|
||||
*
|
||||
* @param priority log level
|
||||
* @param message translated
|
||||
* @param path in console for more information, starting with /, must be URL-escaped, or null
|
||||
* @since 0.9.54
|
||||
*/
|
||||
private void dtgNotify(int priority, String message, String path) {
|
||||
ClientAppManager cmgr = _context.clientAppManager();
|
||||
if (cmgr != null) {
|
||||
NotificationService ns = (NotificationService) cmgr.getRegisteredApp("desktopgui");
|
||||
if (ns != null)
|
||||
ns.notify("I2PSnark", null, priority, _t("I2PSnark"), message, path);
|
||||
}
|
||||
if (!_context.isRouterContext())
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* An HTML link to the file if complete and a single file,
|
||||
* to the directory if not complete or not a single file,
|
||||
@@ -2826,6 +2962,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("DirMon found: " + DataHelper.toString(foundNames) + " existing: " + DataHelper.toString(existingNames));
|
||||
// lets find new ones first...
|
||||
int count = 0;
|
||||
for (String name : foundNames) {
|
||||
if (existingNames.contains(name)) {
|
||||
// already known. noop
|
||||
@@ -2853,6 +2990,10 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
disableTorrentFile(name);
|
||||
rv = false;
|
||||
}
|
||||
if (shouldStart && (count++ & 0x0f) == 15) {
|
||||
// try to prevent OOMs at startup
|
||||
try { Thread.sleep(250); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't remove magnet torrents that don't have a torrent file yet
|
||||
@@ -3032,21 +3173,19 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
}
|
||||
|
||||
/**
|
||||
* If not connected, thread it, otherwise inline
|
||||
* Always thread it
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public void startAllTorrents() {
|
||||
if (_util.connected()) {
|
||||
startAll();
|
||||
} else {
|
||||
if (!_util.connected()) {
|
||||
addMessage(_t("Opening the I2P tunnel and starting all torrents."));
|
||||
for (Snark snark : _snarks.values()) {
|
||||
// mark it for the UI
|
||||
snark.setStarting();
|
||||
}
|
||||
(new I2PAppThread(new ThreadedStarter(null), "TorrentStarterAll", true)).start();
|
||||
try { Thread.sleep(200); } catch (InterruptedException ie) {}
|
||||
}
|
||||
(new I2PAppThread(new ThreadedStarter(null), "TorrentStarterAll", true)).start();
|
||||
try { Thread.sleep(200); } catch (InterruptedException ie) {}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3076,6 +3215,7 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
* @since 0.9.1
|
||||
*/
|
||||
private void startAll() {
|
||||
int count = 0;
|
||||
for (Snark snark : _snarks.values()) {
|
||||
if (snark.isStopped()) {
|
||||
try {
|
||||
@@ -3083,6 +3223,10 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
} catch (RuntimeException re) {
|
||||
// Snark.fatal() will log and call fatal() here for user message before throwing
|
||||
}
|
||||
if ((count++ & 0x0f) == 15) {
|
||||
// try to prevent OOMs
|
||||
try { Thread.sleep(250); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3101,7 +3245,29 @@ public class SnarkManager implements CompleteListener, ClientApp, DisconnectList
|
||||
if (finalShutdown && _log.shouldLog(Log.WARN))
|
||||
_log.warn("SnarkManager final shutdown");
|
||||
int count = 0;
|
||||
for (Snark snark : _snarks.values()) {
|
||||
Collection<Snark> snarks = _snarks.values();
|
||||
// We do two passes so we shutdown the high-priority snarks first.
|
||||
// Pass 1: All running, incomplete torrents,
|
||||
// to make sure the status gets saved so there will be no recheck on restart.
|
||||
for (Snark snark : snarks) {
|
||||
if (!snark.isStopped()) {
|
||||
Storage storage = snark.getStorage();
|
||||
if (storage != null && !storage.complete()) {
|
||||
if (count == 0)
|
||||
addMessage(_t("Stopping all torrents and closing the I2P tunnel."));
|
||||
count++;
|
||||
if (finalShutdown)
|
||||
snark.stopTorrent(true);
|
||||
else
|
||||
stopTorrent(snark, false);
|
||||
if (count % 8 == 0) {
|
||||
try { Thread.sleep(20); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pass 2: All the rest of the torrents
|
||||
for (Snark snark : snarks) {
|
||||
if (!snark.isStopped()) {
|
||||
if (count == 0)
|
||||
addMessage(_t("Stopping all torrents and closing the I2P tunnel."));
|
||||
|
||||
@@ -87,7 +87,7 @@ public class Storage implements Closeable
|
||||
/** bigger than this will be rejected */
|
||||
public static final int MAX_PIECE_SIZE = 32*1024*1024;
|
||||
/** The maximum number of pieces in a torrent. */
|
||||
public static final int MAX_PIECES = 32*1024;
|
||||
public static final int MAX_PIECES = 64*1024;
|
||||
public static final long MAX_TOTAL_SIZE = MAX_PIECE_SIZE * (long) MAX_PIECES;
|
||||
public static final int PRIORITY_SKIP = -9;
|
||||
public static final int PRIORITY_NORMAL = 0;
|
||||
@@ -288,9 +288,15 @@ public class Storage implements Closeable
|
||||
* @throws IOException if too many total files
|
||||
*/
|
||||
private void addFiles(List<File> l, File f) throws IOException {
|
||||
int max = _util.getMaxFilesPerTorrent();
|
||||
if (!f.isDirectory()) {
|
||||
if (l.size() >= SnarkManager.MAX_FILES_PER_TORRENT)
|
||||
throw new IOException("Too many files, limit is " + SnarkManager.MAX_FILES_PER_TORRENT + ", zip them?");
|
||||
int sz = l.size() + 1;
|
||||
if (sz > max)
|
||||
throw new IOException(_util.getString("Too many files in \"{0}\" ({1})!",
|
||||
(metainfo != null ? metainfo.getName() : _base.toString()), sz) +
|
||||
" - limit is " + max + ", zip them or set " +
|
||||
SnarkManager.PROP_MAX_FILES_PER_TORRENT + '=' + sz + " in " +
|
||||
SnarkManager.CONFIG_FILE + " and restart");
|
||||
l.add(f);
|
||||
} else {
|
||||
File[] files = f.listFiles();
|
||||
@@ -301,6 +307,13 @@ public class Storage implements Closeable
|
||||
+ "' not a normal file.");
|
||||
return;
|
||||
}
|
||||
int sz = l.size() + files.length;
|
||||
if (sz > max)
|
||||
throw new IOException(_util.getString("Too many files in \"{0}\" ({1})!",
|
||||
(metainfo != null ? metainfo.getName() : _base.toString()), sz) +
|
||||
" - limit is " + max + ", zip them or set " +
|
||||
SnarkManager.PROP_MAX_FILES_PER_TORRENT + '=' + sz + " in " +
|
||||
SnarkManager.CONFIG_FILE + " and restart");
|
||||
for (int i = 0; i < files.length; i++)
|
||||
addFiles(l, files[i]);
|
||||
}
|
||||
@@ -900,7 +913,10 @@ public class Storage implements Closeable
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
// unicode newlines
|
||||
0x2028, 0x2029
|
||||
0x2028, 0x2029,
|
||||
// LTR/RTL
|
||||
// https://security.stackexchange.com/questions/158802/how-can-this-executable-have-an-avi-extension
|
||||
0x202a, 0x202b, 0x202c, 0x202d, 0x202e, 0x200e, 0x200f
|
||||
};
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file
|
||||
|
||||
@@ -94,7 +94,8 @@ public class TrackerClient implements Runnable {
|
||||
private static final Hash DSA_ONLY_TRACKER = ConvertToHash.getHash("cfmqlafjfmgkzbt4r3jsfyhgsr5abgxryl6fnz3d3y5a365di5aa.b32.i2p");
|
||||
|
||||
private final I2PSnarkUtil _util;
|
||||
private final MetaInfo meta;
|
||||
// non-final for reinitialize()
|
||||
private MetaInfo meta;
|
||||
private final String infoHash;
|
||||
private final String peerID;
|
||||
private final String additionalTrackerURL;
|
||||
@@ -266,8 +267,22 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call after editing torrent
|
||||
* @since 0.9.57
|
||||
*/
|
||||
public synchronized void reinitialize() {
|
||||
if (!_initialized || !stop)
|
||||
return;
|
||||
trackers.clear();
|
||||
backupTrackers.clear();
|
||||
meta = snark.getMetaInfo();
|
||||
setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Do this one time only (not every time it is started).
|
||||
* Unless torrent was edited.
|
||||
* @since 0.9.1
|
||||
*/
|
||||
private void setup() {
|
||||
|
||||
@@ -128,7 +128,7 @@ class UDPTrackerClient implements I2PSessionMuxedListener {
|
||||
*
|
||||
* @param ih the Info Hash (torrent)
|
||||
* @param max maximum number of peers to return
|
||||
* @param maxWait the maximum time to wait (ms) must be > 0
|
||||
* @param maxWait the maximum time to wait (ms) must be greater than 0
|
||||
* @param fast if true, don't wait for dest, no retx, ...
|
||||
* @return null on fail or if fast is true
|
||||
*/
|
||||
|
||||
@@ -319,6 +319,13 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
return _smgr.shouldAutoStart();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.62
|
||||
*/
|
||||
public BandwidthListener getBandwidthListener() {
|
||||
return _smgr.getBandwidthListener();
|
||||
}
|
||||
|
||||
//////// end CompleteListener methods
|
||||
|
||||
private static String linkify(String url) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user