forked from I2P_Developers/i2p.i2p
Compare commits
1087 Commits
i2p-0.7.5
...
i2p-0.7.12
Author | SHA1 | Date | |
---|---|---|---|
5026cbdc8d | |||
52e2aaa20d | |||
9df87ba167 | |||
![]() |
116be93160 | ||
![]() |
c91218be27 | ||
9eab44128a | |||
f98101afa6 | |||
4fae7a8cb6 | |||
26cf1922db | |||
![]() |
c087b0695f | ||
16930d2004 | |||
33939e7cfb | |||
e759ef5865 | |||
2be1b1ece4 | |||
![]() |
1820a29aed | ||
ee9f85d53c | |||
afbb1dbe86 | |||
9244bd6b0f | |||
6bb4403207 | |||
![]() |
24ebd503d4 | ||
![]() |
285a5eed35 | ||
26aebe6a0f | |||
ca9f174171 | |||
ffbced22b3 | |||
45ca459ceb | |||
![]() |
5a539f0619 | ||
![]() |
c6cef72cb7 | ||
8081d053cc | |||
efdc8e5df0 | |||
b4911a2b2f | |||
7b70210c9a | |||
e3353df8bb | |||
25285fc059 | |||
7720f71e44 | |||
1657ac5357 | |||
299214aa1d | |||
![]() |
5fd4488e08 | ||
87fcaf2651 | |||
f6b9cf6f21 | |||
eae18e61b7 | |||
96735f2543 | |||
![]() |
54459d3b5c | ||
82444f9e7b | |||
3d8365a473 | |||
e2dc9715d2 | |||
d4f1230b37 | |||
7701693d37 | |||
b6704fce4e | |||
39a68d4a2b | |||
94633899d7 | |||
c45bc1554f | |||
![]() |
789c8edc45 | ||
e0b44f43e3 | |||
b45069e377 | |||
c3a156ce4b | |||
ee5cc099ed | |||
f189587153 | |||
a1fb5ef6ed | |||
8c2550c39a | |||
abd96a920f | |||
1d3f0fe96c | |||
49a6cdbda6 | |||
2700028da7 | |||
![]() |
51a1564566 | ||
bd068058c3 | |||
![]() |
4591f77928 | ||
4f70a7d0fe | |||
![]() |
6d67848096 | ||
c145ed103a | |||
f265db4037 | |||
62308f26bc | |||
![]() |
2b4b47eff6 | ||
04ae0e2610 | |||
cada9fae44 | |||
949aea951e | |||
cfc49ab261 | |||
0e853a3119 | |||
a0cad7e8e9 | |||
880f1866dc | |||
05d22344b5 | |||
7212f855d8 | |||
54171e4be2 | |||
a820c01ba5 | |||
9d1ae891bb | |||
2df7247e83 | |||
a109ebef28 | |||
c0135b592d | |||
b7a0aeea34 | |||
66375e25c6 | |||
85482a67f5 | |||
d7e90969d0 | |||
9012baf51e | |||
3c8355790f | |||
e9f1da85e4 | |||
58adccfd4a | |||
040f3e016e | |||
505d5f5cae | |||
2a99e2a295 | |||
49fae646e2 | |||
f7780b6745 | |||
7a59d15e9c | |||
9b141bd9dd | |||
![]() |
d0d062b6f4 | ||
375118fe02 | |||
7b59ceb4ae | |||
3aebe45a7d | |||
7c236c0fa0 | |||
7a7e650ca0 | |||
7a32f8efd6 | |||
2f8b55ceda | |||
b77be20cc1 | |||
101135a99a | |||
746c1bd628 | |||
b0502b1873 | |||
6801fc667a | |||
794db19b6d | |||
d4637818be | |||
33b7dca782 | |||
d7015cf2e6 | |||
5689fa8512 | |||
25e51a945c | |||
bfd1306a56 | |||
839986db22 | |||
ed443fe0d6 | |||
![]() |
390981e10c | ||
56b3e6a993 | |||
f86f2701ff | |||
63d3685652 | |||
0a93466999 | |||
81664bc776 | |||
6d60a6f833 | |||
4186894a39 | |||
![]() |
cfeafacd07 | ||
![]() |
9c2edf5c6a | ||
![]() |
72396f0f96 | ||
![]() |
45388b0d48 | ||
a8ae36c403 | |||
164b39d8df | |||
ccc95087a1 | |||
b97f4f8bd7 | |||
76c1f47b20 | |||
ce74e49236 | |||
977d39aeb1 | |||
a821ea2752 | |||
b97197c0fa | |||
474691927a | |||
81dcbedd17 | |||
4f5cfdee57 | |||
2c7725a8e4 | |||
0ba6482da5 | |||
4c1fd67925 | |||
25683cc0de | |||
087fd5a909 | |||
fdfbab850a | |||
f1c50b7fc3 | |||
959bf4a7f4 | |||
5dda915467 | |||
66d8fd6c2a | |||
![]() |
06efe306c3 | ||
![]() |
15d1b005f5 | ||
7efab75c3c | |||
a9e4248c93 | |||
5338dc5540 | |||
09d3dc8e90 | |||
3bf95e566c | |||
958a5a3c4e | |||
![]() |
7b48f6387f | ||
![]() |
fcd2cdb136 | ||
![]() |
6b59356bc5 | ||
![]() |
1c7f098d9b | ||
![]() |
103c15f000 | ||
![]() |
0fd55f8b07 | ||
![]() |
511c1e7b9d | ||
![]() |
7df3bde2ce | ||
![]() |
25e6b6e6c4 | ||
![]() |
cb81f2c9ba | ||
![]() |
6c25f0fd16 | ||
![]() |
934f3d1814 | ||
![]() |
e883fd6b1b | ||
![]() |
e3b300e978 | ||
![]() |
03a9f69739 | ||
![]() |
be2dca8ee7 | ||
![]() |
5c595ef289 | ||
![]() |
d9534e5f23 | ||
![]() |
00fa3806d8 | ||
![]() |
6c5ef9acdc | ||
2db5914ba0 | |||
35a0dafb83 | |||
5f12688a90 | |||
f8d9af871a | |||
08a2b4bbf0 | |||
27a5793fd0 | |||
![]() |
b1151f82b5 | ||
b6332f8313 | |||
e036cd4332 | |||
174fedc2e6 | |||
4803e60db4 | |||
abb62b93e3 | |||
95bb322cd7 | |||
670b4033cb | |||
715ae13997 | |||
77b88ab59d | |||
64235bd745 | |||
![]() |
0a1960461a | ||
![]() |
11249657ac | ||
188ac4f730 | |||
![]() |
865116b3f4 | ||
9f28c06e9e | |||
3cd6520758 | |||
da1a50bfeb | |||
9ec79f50fa | |||
![]() |
b15392ea85 | ||
b8339e72b0 | |||
![]() |
6eaec7fd44 | ||
![]() |
9e8f2ce771 | ||
![]() |
e8e6f6f531 | ||
![]() |
f16ba8ee06 | ||
76f11859b2 | |||
5be21a19db | |||
043359dd40 | |||
1b95b00b44 | |||
eaaf6af31d | |||
![]() |
d8d50aaf41 | ||
![]() |
5fcddd581e | ||
![]() |
f1a9613a92 | ||
![]() |
a2ce10759c | ||
![]() |
5065aec773 | ||
![]() |
25fc64933a | ||
![]() |
bbdd54efc8 | ||
![]() |
92597baab9 | ||
![]() |
62786dcc09 | ||
![]() |
c012e5bf17 | ||
5ed29b6c27 | |||
2d5decd943 | |||
9d167dc83a | |||
afe8394658 | |||
72db6d1a08 | |||
9d0e300924 | |||
![]() |
4f548b7b27 | ||
![]() |
cbd50372e4 | ||
3caee8bc71 | |||
![]() |
6c64faf0ba | ||
![]() |
65290f1ed7 | ||
![]() |
498af5d203 | ||
883b53de0a | |||
cefc1f130d | |||
b2a137c5bc | |||
62f056f884 | |||
3944ea53d2 | |||
d372ea753f | |||
2528cd205d | |||
afd54fc212 | |||
![]() |
8e7a9fc513 | ||
acb75f4212 | |||
c40b56c19d | |||
98027a06ec | |||
d92dfec1bf | |||
72a588bfbf | |||
213bc4bb71 | |||
1a01aa0ae4 | |||
0b0e3fffe4 | |||
1fc32c5e6f | |||
![]() |
ba9f05ca06 | ||
629d12ade1 | |||
08929752a6 | |||
aaa5b4ca86 | |||
8d7e84494b | |||
99df95697a | |||
a877b21839 | |||
![]() |
3f267693d2 | ||
30b7dbf1f7 | |||
![]() |
f32d162b62 | ||
![]() |
126fa320e5 | ||
ecae0b055d | |||
9bf22fb0d3 | |||
2a1d358141 | |||
579b450029 | |||
72eafe0920 | |||
f226392c9d | |||
2cd5c209f5 | |||
f0d444b32e | |||
4baff9fbab | |||
8e656427d8 | |||
aaa7302e80 | |||
33407fd5be | |||
513b93f789 | |||
08e54c515e | |||
55682810b1 | |||
![]() |
ec893d09d0 | ||
f9b745a671 | |||
43b71a263c | |||
5c4672d1e3 | |||
7ca8e0c3a1 | |||
b530316850 | |||
fa92beae5a | |||
f58f703ecb | |||
6b83fc6b3b | |||
cdb390f7ce | |||
7b1caac9ac | |||
cec75fa60e | |||
eb23306b12 | |||
43f6813609 | |||
ea36b7b153 | |||
448ff4d398 | |||
e16227211f | |||
e07e329c26 | |||
![]() |
a3d79aaa4e | ||
3fa9ae0b82 | |||
![]() |
7feed50af4 | ||
![]() |
0c0eb5765d | ||
![]() |
e87ff25ef6 | ||
![]() |
21e09cb0a5 | ||
![]() |
04d54607ae | ||
![]() |
ad8bfbdaab | ||
![]() |
aca815c4aa | ||
![]() |
24683c19a4 | ||
![]() |
6b8dffc401 | ||
![]() |
c4bb84058a | ||
c3dc76e35f | |||
993fa5c210 | |||
1cec793217 | |||
6029e1a291 | |||
7cc75c0cb9 | |||
e5248b09ab | |||
c39f047703 | |||
4562254862 | |||
8116d88aaf | |||
14362630d7 | |||
9af796a10a | |||
eeb884e8ce | |||
02baf905c6 | |||
df7029d2c2 | |||
c22b7568b1 | |||
![]() |
73537d27d0 | ||
![]() |
449d7ab589 | ||
0ddef91e16 | |||
b205af5a0d | |||
1e32170df2 | |||
f446a5f1fc | |||
fb21fb25ee | |||
deae0e8856 | |||
1cd54dc12e | |||
8ebc8bd209 | |||
![]() |
9d11866f86 | ||
2c456c291a | |||
c5b3c2f430 | |||
e46e747ac0 | |||
e1a88c9426 | |||
![]() |
23d3c33a12 | ||
![]() |
ec8130f443 | ||
![]() |
4b7aeb8418 | ||
![]() |
18a0f01f8b | ||
![]() |
df2e639692 | ||
708b3a662c | |||
4fee7844f8 | |||
![]() |
891416e6b9 | ||
![]() |
978cd2c484 | ||
![]() |
c88c905926 | ||
bda4eb830e | |||
f5c1acc749 | |||
c4e6148b9f | |||
43029de2f3 | |||
7262c014c0 | |||
9f7bd99051 | |||
9e4f04cc18 | |||
![]() |
454b2c8941 | ||
4c812c7bff | |||
f95b5324e0 | |||
64ee1b313b | |||
1ca651e803 | |||
f3a88398f2 | |||
412d641eb6 | |||
d7d058e772 | |||
![]() |
278b917494 | ||
4b6989ef7b | |||
c10ea84ade | |||
![]() |
0642fa8093 | ||
2db7c2bdd8 | |||
8682e7deb5 | |||
ea0747171f | |||
13349777ad | |||
ab0a5a06af | |||
![]() |
6371f66677 | ||
105524d9c0 | |||
95e0492b32 | |||
234c084c2a | |||
94faf74aa4 | |||
e78dd1fdc3 | |||
38045d876d | |||
8433724452 | |||
e9f9e0dabb | |||
6bdf750c19 | |||
647a09b5b9 | |||
6144bfb437 | |||
88dbd7710a | |||
26a71232f0 | |||
f58a1768b9 | |||
![]() |
125e6581e0 | ||
![]() |
54105086ad | ||
![]() |
3674ac2922 | ||
![]() |
18c023e6f7 | ||
312ba2599f | |||
746dc6f884 | |||
edd4d4c114 | |||
56e0c3e047 | |||
![]() |
1e83d1b304 | ||
![]() |
74aa84b183 | ||
![]() |
168c213288 | ||
![]() |
d268a3852c | ||
![]() |
01e87438c3 | ||
![]() |
060f4e6632 | ||
![]() |
3df5540a97 | ||
![]() |
30dec5b9f5 | ||
![]() |
43b437fc58 | ||
8e889cd292 | |||
eceac6def0 | |||
1e3d6776aa | |||
784ca67ddf | |||
![]() |
0f6b49cc31 | ||
![]() |
8cede2a2b2 | ||
![]() |
38ed04bbd8 | ||
c393e70ca9 | |||
1c25c0f408 | |||
![]() |
b7ebce48ee | ||
![]() |
d6814a0489 | ||
![]() |
6f24c74f8c | ||
![]() |
d8389dcc46 | ||
![]() |
9f939553ee | ||
![]() |
529988f394 | ||
![]() |
9f46aa1e18 | ||
![]() |
418c1b6f96 | ||
![]() |
8056fb9502 | ||
![]() |
ab2e21147f | ||
6c00bb20b6 | |||
573ac357d8 | |||
![]() |
5b139f9246 | ||
![]() |
76d75b712e | ||
8bc2fd7e42 | |||
4533a86712 | |||
a6239e2ce3 | |||
1f8e61f480 | |||
c40f845279 | |||
aa74962263 | |||
42cbd6c12b | |||
ee51f69a5a | |||
![]() |
0fb6e9cf6c | ||
e02845076d | |||
2dc3798116 | |||
![]() |
fa252f5e8f | ||
![]() |
580b9b450f | ||
![]() |
f0730cd1c8 | ||
b045fb3a45 | |||
![]() |
6c64111d7e | ||
37a2ccca95 | |||
b4615edfcc | |||
6019cf8148 | |||
e3d945201b | |||
05b17e5a00 | |||
![]() |
13b3edfb07 | ||
![]() |
f61372b2fd | ||
![]() |
f85d8f7060 | ||
a0b4b7db86 | |||
![]() |
827a92ef2f | ||
![]() |
625d76b914 | ||
![]() |
a1de894b64 | ||
413ab6d7e4 | |||
a3b1c79006 | |||
5a7d3ba4c8 | |||
8a1db31184 | |||
![]() |
5190b2db1f | ||
820c573476 | |||
ab40454bce | |||
![]() |
b65865b854 | ||
a5772e62c3 | |||
9976bea03f | |||
7997aeaca5 | |||
ba95084d27 | |||
e952e91b54 | |||
da21c0ddb7 | |||
0133711c3b | |||
![]() |
6eae2cd460 | ||
![]() |
9314eebc4f | ||
428cbdce2a | |||
![]() |
7594c4383b | ||
![]() |
e2f6911e9f | ||
9cdae03069 | |||
![]() |
06946f026e | ||
![]() |
d43dac5c04 | ||
b4d83b18fa | |||
![]() |
f9424dbd6d | ||
e5212937af | |||
aeb6635e71 | |||
e94b478317 | |||
![]() |
88216de42c | ||
![]() |
1fcf707bb2 | ||
![]() |
5101486fe7 | ||
![]() |
7ae4d0e981 | ||
![]() |
c644c128c0 | ||
![]() |
2603f6fe45 | ||
![]() |
957a296ca9 | ||
![]() |
e4f44fa1e9 | ||
![]() |
2b469567bb | ||
a2d90eebea | |||
850a8da0a9 | |||
ac6d711a99 | |||
5aa254a178 | |||
![]() |
ad396adf39 | ||
![]() |
05cce164f7 | ||
![]() |
935b69bc71 | ||
![]() |
61f800999a | ||
![]() |
9833743eb9 | ||
![]() |
ac65bc7302 | ||
![]() |
b36f207bb2 | ||
![]() |
e87a7c7bb4 | ||
![]() |
7e5128bb85 | ||
![]() |
0a178ec35e | ||
a5cd0bdd3f | |||
9cbf9d0422 | |||
![]() |
097a05aab9 | ||
![]() |
0e5b2598fb | ||
![]() |
4f492e33e6 | ||
![]() |
1828b2bd17 | ||
0c74e640df | |||
ffd2721627 | |||
f6ce4cb29f | |||
4863ef3360 | |||
![]() |
9f7807ee10 | ||
![]() |
b2285b0beb | ||
![]() |
8e4f4f82a8 | ||
![]() |
db2158d4c1 | ||
![]() |
1c461bbeda | ||
![]() |
0757f4f309 | ||
![]() |
a2f287cdfe | ||
![]() |
1ef448d518 | ||
![]() |
f44b1a35bc | ||
26f02a4771 | |||
dc3c730937 | |||
77d45e7a3a | |||
45a59f009b | |||
dc6d6ead69 | |||
27693826a2 | |||
8a647b42d5 | |||
eba9f3c03b | |||
eacf46b367 | |||
83cacaad05 | |||
cf10451d14 | |||
![]() |
44069645df | ||
4497463778 | |||
10b84418c3 | |||
![]() |
fadda4ceec | ||
011a32f741 | |||
![]() |
10bb3c100e | ||
![]() |
2738d5851d | ||
219095404a | |||
001c361338 | |||
e21a172e95 | |||
![]() |
4651b7007b | ||
![]() |
5b4be5ba1b | ||
![]() |
9c2c90c0b1 | ||
bdd0c3f961 | |||
b7013361c2 | |||
f73b3e522b | |||
fa6d17a1b8 | |||
![]() |
c3e646ca22 | ||
fdc9e11fb4 | |||
a1ec838282 | |||
7da46517ae | |||
d8e2939307 | |||
8cad72c654 | |||
![]() |
2cfc2bb60d | ||
![]() |
1811e3b9cd | ||
960cd18d0a | |||
405b85c4b4 | |||
![]() |
92e323df51 | ||
![]() |
3f2c34903d | ||
3c260aa333 | |||
da41f3a93b | |||
aeb711acde | |||
![]() |
a46ee9a5b2 | ||
088f9558ec | |||
376d61c155 | |||
285a2b92e5 | |||
![]() |
8939c573ea | ||
![]() |
3839d9873a | ||
116762ebce | |||
7dd8f00e95 | |||
![]() |
29a3db4b5c | ||
![]() |
5d95907996 | ||
![]() |
2f940d01b6 | ||
![]() |
517e170b88 | ||
![]() |
b27fbb9b8e | ||
9b97d32ea8 | |||
d4f3952a90 | |||
![]() |
f7840652ed | ||
![]() |
08634c1ff6 | ||
![]() |
dec4205890 | ||
![]() |
b49ab59e3b | ||
![]() |
7e1171ec9f | ||
![]() |
3eae787957 | ||
![]() |
9ecba4fc5e | ||
![]() |
4fb9eef198 | ||
![]() |
49ecfd8224 | ||
![]() |
09a2854b8b | ||
![]() |
82976e609f | ||
![]() |
b2d6b60300 | ||
90737493e6 | |||
fe3abc79d6 | |||
9931112387 | |||
1cd646afe2 | |||
0d262d28b7 | |||
f33e950780 | |||
7094489536 | |||
2dd650df01 | |||
![]() |
7e8037979f | ||
3a1c042cd2 | |||
ca81c35b3d | |||
6a2dfff34d | |||
![]() |
5eccc01de6 | ||
![]() |
1850e893e9 | ||
![]() |
2341793546 | ||
1f1d089fda | |||
5372a50bcc | |||
83588d9b98 | |||
58e960ceb5 | |||
de07705671 | |||
![]() |
49ff3cfbf3 | ||
e392469835 | |||
7745bd89a9 | |||
01bed932c7 | |||
157190757b | |||
e0f1047d72 | |||
15f0cda41f | |||
9a95122c7c | |||
d868f7c02a | |||
5ca2f306b8 | |||
c714c1a0c9 | |||
e6e6c00497 | |||
62a3da2fa6 | |||
![]() |
f1f97e8ec5 | ||
![]() |
6c361679c6 | ||
![]() |
ae89d2f2ab | ||
8053fb5eae | |||
ebf5eb6e20 | |||
2e2bff3f0a | |||
a3f290e4d8 | |||
e0dd1f13e3 | |||
787def6a1c | |||
1f5d7d7b5b | |||
4bc5215833 | |||
7736545f5b | |||
1ecf4377c6 | |||
593d4dc508 | |||
93d366fea1 | |||
7973f2e8b9 | |||
bb14fa0b4e | |||
95aba0c537 | |||
df4143f036 | |||
![]() |
ed0575e937 | ||
456ed0aab4 | |||
47c8389419 | |||
51fd4d70da | |||
79e32231fb | |||
80f9f857e5 | |||
5a4c2de425 | |||
7e547743c7 | |||
3f3d43df41 | |||
![]() |
0cc72a49c8 | ||
35c9e99914 | |||
![]() |
2e4bd1e440 | ||
22c0b8e524 | |||
faeb58f7e2 | |||
cdc184c5e5 | |||
![]() |
2f9a4f0fa5 | ||
37437da34d | |||
6d3a5856b4 | |||
![]() |
4d4538a346 | ||
327102a254 | |||
3602eb14f5 | |||
![]() |
cf82b51a1f | ||
![]() |
412d3bc2f8 | ||
![]() |
4735508a0a | ||
9225d01b29 | |||
7782970d51 | |||
6f053287d5 | |||
![]() |
7a88f59f08 | ||
![]() |
d56aae8913 | ||
![]() |
a309a14396 | ||
![]() |
b80cbbdd4a | ||
5bc2dab1d2 | |||
![]() |
8bbe7fabb3 | ||
c537d160a6 | |||
475187fcbc | |||
a379e36e24 | |||
a9054a3cab | |||
![]() |
ea7a9c259f | ||
![]() |
2cba48d4d7 | ||
![]() |
42b79c5a20 | ||
be9523f1e4 | |||
![]() |
6a8dd0f053 | ||
![]() |
1b63aa411b | ||
![]() |
33a7f3351b | ||
![]() |
f7af5e1329 | ||
![]() |
3a9a029d70 | ||
![]() |
0aaacc86e2 | ||
![]() |
1b8b7b741c | ||
66831c619b | |||
30628fb5f9 | |||
![]() |
064ff8a7d2 | ||
![]() |
9a18955de3 | ||
![]() |
35da3f3334 | ||
![]() |
335d45f03e | ||
![]() |
c466cd77ad | ||
![]() |
d998e2e9bb | ||
0a20315280 | |||
01753f5aea | |||
bcd22cfbf3 | |||
7e039d0339 | |||
ab08ac70aa | |||
5decf3cd7a | |||
5c6d757e35 | |||
4b75be804f | |||
6515e6ee17 | |||
55e8583663 | |||
![]() |
3fbff71861 | ||
![]() |
e5eea47b66 | ||
b10b0e8f57 | |||
631a367b1c | |||
8ea279fbe2 | |||
089572befd | |||
0f96b9569a | |||
d1114666de | |||
![]() |
f676abc0d4 | ||
![]() |
3492b7219b | ||
![]() |
a12ae6e399 | ||
9b2e18a65b | |||
c52ccf7eef | |||
1282434684 | |||
4e844187f7 | |||
ccd67d658d | |||
62383819cb | |||
3febcf6043 | |||
a431137f45 | |||
![]() |
5a6e14b9df | ||
536bc3112f | |||
![]() |
81b2e6b789 | ||
4cf376ec1d | |||
d3a0c91398 | |||
![]() |
43140d3efd | ||
3dd3bf829d | |||
bdcad06ece | |||
69fdfb0635 | |||
55a8002b9c | |||
![]() |
e36f9b2273 | ||
70ae99f31a | |||
15565ca09c | |||
f188e02a5d | |||
4d005349a7 | |||
c65a97882e | |||
cf880548d9 | |||
b5876e7f04 | |||
![]() |
2436ea1131 | ||
![]() |
5395b6829a | ||
c3af134a5b | |||
![]() |
cce72a5f1b | ||
![]() |
32c143f8d7 | ||
![]() |
895cb1f2e5 | ||
7986f5646e | |||
![]() |
59a5776f9d | ||
![]() |
fc8c0ccfe1 | ||
![]() |
0930ead814 | ||
b5a17637cb | |||
![]() |
460c8a319f | ||
7aa051ef4f | |||
![]() |
c7c132c0ac | ||
d84b1125eb | |||
8d4a1899f2 | |||
![]() |
3a0cdf1388 | ||
d8d76fd327 | |||
![]() |
abf7296de1 | ||
316c20ee44 | |||
13e8c95667 | |||
a14ad423a6 | |||
e1a5d5e19a | |||
![]() |
6e29eddaa7 | ||
![]() |
65ae26a961 | ||
![]() |
1afd946a94 | ||
![]() |
d6820634ac | ||
![]() |
95dd744633 | ||
![]() |
219af36090 | ||
![]() |
24e83398ba | ||
4172ed21a9 | |||
1cba7b8ec1 | |||
0bef85277e | |||
![]() |
2f4c428316 | ||
![]() |
4de0b73cd8 | ||
7ffb3f46b5 | |||
ad6cd05295 | |||
![]() |
6e7ad3ecdb | ||
![]() |
a6243d14c0 | ||
![]() |
b0a477c5ca | ||
![]() |
1d655c7abc | ||
![]() |
abf2bead33 | ||
![]() |
f1103bec7b | ||
![]() |
fb1a6534dc | ||
22b1d5fe75 | |||
d2c939bc09 | |||
![]() |
73f8cb4819 | ||
256bb771e1 | |||
cc533b0431 | |||
![]() |
3c76fda8d9 | ||
![]() |
c5555350ae | ||
![]() |
22744084dc | ||
![]() |
e4b212ec90 | ||
![]() |
4be0af5de5 | ||
d771745981 | |||
![]() |
7628842b0a | ||
![]() |
6bcdb7fd92 | ||
27561fb632 | |||
f6ec3f66f8 | |||
2f0b9a8f94 | |||
![]() |
3fb1a4ebc5 | ||
![]() |
9abb0a1581 | ||
![]() |
e60e29b70f | ||
![]() |
d84352896f | ||
![]() |
ee419454f4 | ||
![]() |
68445fe195 | ||
![]() |
12b2d4c00b | ||
![]() |
fbb4d3a636 | ||
![]() |
ca415376c7 | ||
![]() |
718f73ebb1 | ||
![]() |
fb47eef218 | ||
![]() |
87dd473148 | ||
![]() |
9bbbccee1a | ||
![]() |
0088750b16 | ||
![]() |
0aae2deb58 | ||
![]() |
0d62b37c13 | ||
![]() |
64ece1080c | ||
![]() |
b4256e484a | ||
![]() |
b0ea204be5 | ||
![]() |
118d7fce09 | ||
5e498e0bd6 | |||
c312fa869b | |||
![]() |
fe394b0b46 | ||
6039f3931d | |||
71d72b426f | |||
7d5042c507 | |||
e2b0e14771 | |||
![]() |
0e9bfba84d | ||
![]() |
99f53413a6 | ||
![]() |
f46600d7fe | ||
![]() |
0607a87514 | ||
1658690b97 | |||
eae0f3273b | |||
508beb2fc7 | |||
![]() |
0de2f492d1 | ||
72a7393844 | |||
99f8468f63 | |||
a9e8fc2f1f | |||
e225244887 | |||
cbde15b00f | |||
8e38047d43 | |||
dc1d0195eb | |||
7d7f264bc0 | |||
b3c30b4fd2 | |||
6c87005eeb | |||
8d2a516044 | |||
dc0cc49dbf | |||
![]() |
497bc5a414 | ||
![]() |
2a71baef90 | ||
![]() |
49a74e8610 | ||
![]() |
6340fbb3d4 | ||
![]() |
748203f4e7 | ||
![]() |
a91cc94228 | ||
029ac71e58 | |||
![]() |
e830b46173 | ||
![]() |
a4d053f555 | ||
![]() |
b298796060 | ||
![]() |
895490df3d | ||
![]() |
a09c06849b | ||
![]() |
37c494bf0a | ||
![]() |
d6fccc07be | ||
![]() |
819efc132b | ||
![]() |
8ffdae4182 | ||
efd6dcc8df | |||
70a17ecfaf | |||
![]() |
15dbf67983 | ||
![]() |
a43df30051 | ||
![]() |
1bff5a7b9e | ||
![]() |
ec49d9becf | ||
bc49f51dbb | |||
![]() |
b869860a83 | ||
![]() |
2772a0e5e4 | ||
![]() |
46970f5a4a | ||
![]() |
ccf9cd3f71 | ||
![]() |
b9c464f8cb | ||
![]() |
48510c1157 | ||
![]() |
3035fcf080 | ||
![]() |
930f402eb9 | ||
![]() |
4e93191312 | ||
9bc4f6bacb | |||
![]() |
9b42129fea | ||
![]() |
0650137e32 | ||
![]() |
a13e528972 | ||
![]() |
82f8dd5635 | ||
![]() |
7f93cb22ce | ||
![]() |
e6738053b2 | ||
![]() |
b74ab51438 | ||
![]() |
d7a591ce3a | ||
![]() |
cfe33a8bbd | ||
![]() |
ca7593cdf2 | ||
![]() |
b185d11daf | ||
![]() |
5106c37ac4 | ||
![]() |
5d40ad1749 | ||
![]() |
24edce3daf | ||
![]() |
cfd1ab7d78 | ||
![]() |
bfaa648edd | ||
![]() |
fd19210bce | ||
![]() |
9a3b103324 | ||
0ee5c905e4 | |||
5f22a226cc | |||
![]() |
56b3144c56 | ||
![]() |
dad4bef70c | ||
![]() |
13a04dba71 | ||
![]() |
ab66dfcb65 | ||
![]() |
ab349a5303 | ||
53a68ff5a3 | |||
29f13868b7 | |||
8ce71d724c | |||
![]() |
e3de3dcc1d | ||
![]() |
fa6a6fa4ef | ||
![]() |
e78e4c93c0 | ||
![]() |
0173f5877b | ||
![]() |
32e829da74 | ||
![]() |
68e81fa8c8 | ||
![]() |
9f84d13542 | ||
![]() |
48f591eea8 | ||
![]() |
cb6dce4e03 | ||
![]() |
e5e7f01e84 | ||
![]() |
f90a320d95 | ||
![]() |
96c94a294e | ||
![]() |
ab81887138 | ||
![]() |
d13e3d95d3 | ||
![]() |
64f1fe0b51 | ||
![]() |
0a77f88229 | ||
![]() |
12d34a50ff | ||
92daa920d2 | |||
![]() |
091d03b9d8 | ||
![]() |
f7ee11cb44 | ||
6226b8ae6d | |||
a6a61421d9 | |||
5c20574044 | |||
aca006253a | |||
7a752cc7a2 | |||
de7dc2c1f7 | |||
![]() |
35b5bf187e | ||
![]() |
efbc4c5184 | ||
![]() |
711c2b7dfd | ||
![]() |
a4adb4709b | ||
![]() |
7121b5fa31 | ||
c944648b99 | |||
![]() |
45cdd556c7 | ||
429bd0a4e3 | |||
135f8c1be2 | |||
![]() |
7b7a590e21 | ||
![]() |
95728ef29f | ||
![]() |
021b44724e | ||
![]() |
ba0efe64c7 | ||
1a247d8d3a | |||
21b03e8e8a | |||
03790e3e4d | |||
9af239aa65 | |||
02fc700ac0 | |||
1fb5238642 | |||
461af7d0a2 | |||
cf3efc11ba | |||
b6e24b5094 | |||
0b590763f3 | |||
![]() |
3cc4ee7199 | ||
![]() |
4828cd2f16 | ||
![]() |
45da7e8704 | ||
![]() |
e00b88ca32 | ||
![]() |
e497680ca8 | ||
![]() |
dbb9eefe70 | ||
![]() |
7388fdf820 | ||
![]() |
0c46d561ec | ||
![]() |
4248ab936c | ||
e5139113b1 | |||
0f1a4ad4cd | |||
![]() |
00d99fb1a9 | ||
![]() |
ee8dc4af2d | ||
![]() |
d7b4be1e74 | ||
![]() |
7ed509b76a | ||
![]() |
c616f66e83 | ||
![]() |
e8bfac27aa | ||
![]() |
df3b3bfc8f | ||
![]() |
ac358502ce | ||
![]() |
2b905d2ed5 | ||
![]() |
49c55ae12a | ||
![]() |
d280d7a389 | ||
![]() |
19ccdcd951 | ||
![]() |
cac9b2e1f1 | ||
![]() |
e0e42a0f87 | ||
![]() |
1d845dab03 | ||
![]() |
71b9bb67a6 | ||
![]() |
06be251032 | ||
![]() |
454a6ab177 | ||
![]() |
1e1c3cdff0 | ||
![]() |
52de5e569c | ||
![]() |
2f97942286 | ||
![]() |
4b1eabf1fc | ||
![]() |
6c7f1cbf8a | ||
![]() |
ffc582093b | ||
![]() |
cc833f3ca4 | ||
![]() |
00d0aa7830 | ||
![]() |
54f649a4b4 | ||
![]() |
1c2cd4dcb2 | ||
43d6851199 | |||
9527684cf7 | |||
1965815d7d | |||
cc2be105a6 | |||
e4c599b756 | |||
a8a21ddb73 | |||
![]() |
942c31621b | ||
ca14002bd1 | |||
5eec098e2b | |||
![]() |
37043195ba | ||
![]() |
ab8e2cf34d | ||
![]() |
882e08fc4f | ||
2e5caac8bf | |||
714fe82d2f | |||
1724e5b499 | |||
a5fa6acf5d | |||
59105a9ad6 | |||
abc23e9a49 | |||
72071566e7 | |||
055cd99dde | |||
d2c52e5c94 | |||
![]() |
c7541f819a | ||
7972c0c862 | |||
3fee5a3781 | |||
db45e74fcc | |||
206e45b9e8 | |||
a9345953f3 | |||
eb324d7652 | |||
85adfc40fb | |||
f1bb8910cb | |||
8ca794dc57 | |||
fe3cd65c62 | |||
256c5356fb | |||
0bc6fd246f | |||
77ce768cb4 | |||
b23256dc4e | |||
5906fb7139 | |||
0606050231 | |||
47cd9beefa | |||
a87f8e8687 | |||
978de73351 | |||
a1ec01ec2d | |||
7aa9949332 | |||
71f3cd648f | |||
7f379027ca | |||
279f3e4934 | |||
bdd75793bc | |||
58660bed3c | |||
2ca0ae7529 | |||
3ee09df6ce | |||
9b866b8e06 | |||
4d4954c5b8 | |||
17751ffd57 | |||
e8773f6a98 | |||
112ddc7156 | |||
e5ec72b09b | |||
24daf00616 | |||
718375419e | |||
a16bcf8e51 | |||
5c28125350 | |||
937de87dbf | |||
cadbe2c2c0 | |||
290af4c187 | |||
fd4e57aafc | |||
524a25eb2c | |||
5022575429 | |||
b8f22bf3bf | |||
5a8b3eb8f3 | |||
d26ac84126 | |||
82045b3fde | |||
14ce5a2432 |
@@ -3,9 +3,10 @@ Headless I2P installation instructions
|
||||
1) java -jar i2pinstall.exe -console (you've already done this)
|
||||
|
||||
This will run the installer in text mode, including running the postinstall.sh
|
||||
script, which will start the router and launch a browser.
|
||||
script. After that, you may run 'sh i2prouter start'
|
||||
which will start the router and attempt to launch a browser.
|
||||
|
||||
If you do not have an X server running, the browser launch will fail, and
|
||||
If you do not have an X server running, the browser launch will probably fail, and
|
||||
you may use:
|
||||
lynx http://localhost:7657/index.jsp
|
||||
to configure the router.
|
||||
@@ -13,6 +14,16 @@ to configure the router.
|
||||
If you're having trouble, swing by http://forum.i2p2.de/, check the
|
||||
website at http://www.i2p2.de/, or get on irc://irc.freenode.net/#i2p
|
||||
|
||||
I2P will create and store files and configuration data in the user directory
|
||||
~/.i2p/ on Linux and %APPDATA%\I2P\ on Windows. This directory is created
|
||||
when I2P is run for the first time. It also creates files in the system
|
||||
temporary directory specified by the Java Virtual Machine.
|
||||
To change the location of these directories, or to configure I2P to
|
||||
put all files in this directory (the so-called "portable" configuration),
|
||||
edit the files i2prouter (Linux) and wrapper.config (Linux and Windows)
|
||||
where there are comments labeled "PORTABLE". Do this before you
|
||||
run I2P for the first time.
|
||||
|
||||
To run I2P explicitly:
|
||||
(*nix): sh i2prouter start
|
||||
(win*): I2P.exe
|
||||
|
10
INSTALL.txt
10
INSTALL.txt
@@ -1,10 +1,17 @@
|
||||
I2P source installation instructions
|
||||
|
||||
Prerequisites to build from source:
|
||||
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
|
||||
Apache Ant 1.7.0 or higher
|
||||
Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
|
||||
To build and install I2P from source, you must first build
|
||||
and package up the appropriate installer by running:
|
||||
|
||||
ant pkg
|
||||
|
||||
|
||||
This will produce a few key files:
|
||||
* install.jar: the GUI and console installer
|
||||
* i2pinstall.exe: the GUI and console installer wrapped for cross-platform execution
|
||||
@@ -18,9 +25,6 @@ Or run the GUI installer:
|
||||
|
||||
Or move the update file into an existing installation directory and restart.
|
||||
|
||||
You will need to have ant installed from http://ant.apache.org/
|
||||
(1.7.0 or newer)
|
||||
|
||||
Supported JVMs:
|
||||
Windows: Latest available from http://java.sun.com/ (1.5+ supported)
|
||||
Linux: Latest available from http://java.sun.com/ (1.5+ supported)
|
||||
|
19
LICENSE.txt
19
LICENSE.txt
@@ -76,16 +76,14 @@ Public domain except as listed below:
|
||||
Copyright (C) 2003-2006 Satoshi Konno
|
||||
See licenses/LICENSE-UPnP.txt
|
||||
|
||||
XMLPull library used by UPnP:
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
||||
GeoIP data free to use, courtesy http://ip-to-country.webhosting.info/
|
||||
|
||||
|
||||
Installer:
|
||||
Launch4j 2.0.RC3:
|
||||
Copyright (C) 2005 Grzegorz Kowal
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
Launch4j 3.0.1:
|
||||
Copyright (c) 2004, 2008 Grzegorz Kowal
|
||||
See licenses/LICENSE-Launch4j.txt (in binary packages)
|
||||
See installer/lib/launch4j/LICENSE.txt (in source packages)
|
||||
The following projects are used by Launch4j...
|
||||
MinGW binutils (http://www.mingw.org/)
|
||||
|
||||
@@ -177,7 +175,11 @@ Applications:
|
||||
|
||||
Router console:
|
||||
Public domain.
|
||||
Flag icons public domain, courtesy mjames@gmail.com http://www.famfamfam.com/
|
||||
Flag icons: public domain, courtesy mjames@gmail.com http://www.famfamfam.com/
|
||||
|
||||
GeoIP Data:
|
||||
Copyright (c) 2003 Direct Information Pvt. Ltd. All Rights Reserved.
|
||||
See licenses/LICENSE-GeoIP.txt
|
||||
|
||||
SAM:
|
||||
Public domain.
|
||||
@@ -206,6 +208,9 @@ The following applications and libraries are not used or bundled in
|
||||
binary packages, therefore the licenses are not included in binary
|
||||
distributions. See the source package for the additional license information.
|
||||
|
||||
Admin Manager:
|
||||
Public domain
|
||||
|
||||
Atalk:
|
||||
Public domain
|
||||
|
||||
|
51
Makefile.gcj
51
Makefile.gcj
@@ -5,7 +5,7 @@
|
||||
GCJ=gcj #/usr/local/gcc-4.0.2/bin/gcj
|
||||
EXTRA_LD_PATH= #/usr/local/gcc-4.0.2/lib
|
||||
ANT=ant #/opt/apache-ant-1.6.5/bin/ant
|
||||
ANT_TARGET=buildclean
|
||||
ANT_TARGET=build2
|
||||
NATIVE_DIR=native
|
||||
|
||||
##
|
||||
@@ -24,20 +24,22 @@ JAR_BASE=i2p.jar mstreaming.jar streaming.jar
|
||||
JAR_CLIENTS=i2ptunnel.jar sam.jar
|
||||
JAR_ROUTER=router.jar
|
||||
JAR_JBIGI=jbigi.jar
|
||||
JAR_XML=xml-apis.jar resolver.jar xercesImpl.jar
|
||||
JAR_CONSOLE=\
|
||||
i2psnark.jar \
|
||||
javax.servlet.jar \
|
||||
commons-el.jar \
|
||||
commons-logging.jar \
|
||||
jasper-runtime.jar \
|
||||
ant-apache-bcel.jar \
|
||||
ant.jar \
|
||||
jasper-compiler.jar \
|
||||
org.mortbay.jetty.jar \
|
||||
routerconsole.jar
|
||||
JAR_SUCKER=jdom.jar rome-0.7.jar sucker.jar
|
||||
LIBI2P_JARS=${JAR_BASE} ${JAR_CLIENTS} ${JAR_ROUTER} ${JAR_JBIGI}
|
||||
LIBSAM_JARS=${JAR_BASE} sam.jar
|
||||
LIBROUTER_JARS=i2p.jar ${JAR_ROUTER} ${JAR_JBIGI}
|
||||
LIBCONSOLE_JARS=${LIBROUTER_JARS} ${JAR_CONSOLE}
|
||||
LIBSNARK_JARS=${LIBROUTER_JARS} i2psnark.jar
|
||||
# update:
|
||||
# similar error with gcj 4.3.3.
|
||||
#
|
||||
# unfortunately, its not quite ready for most end users, as the
|
||||
# ${JAR_CONSOLE} fails to compile with:
|
||||
# org/apache/commons/logging/impl/LogKitLogger.java: In class 'org.apache.commons.logging.impl.LogKitLogger':
|
||||
@@ -95,7 +97,36 @@ native_shared: libi2p.so
|
||||
@echo " i2ptunnel will, so it will start all the proxies defined in i2ptunnel.config"
|
||||
|
||||
libi2p.so:
|
||||
@echo "* Building libi2p.so"
|
||||
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/libi2p.so ${LIBI2P_JARS} ; cd .. )
|
||||
@ls -l ${NATIVE_DIR}/libi2p.so
|
||||
@echo "* libi2p.so built"
|
||||
@echo "* Building $@"
|
||||
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/$@ ${LIBI2P_JARS} ; cd .. )
|
||||
@ls -l ${NATIVE_DIR}/$@
|
||||
@echo "* $@ built"
|
||||
|
||||
sam: jars libi2psam.so
|
||||
|
||||
libi2psam.so:
|
||||
@echo "* Building $@"
|
||||
@rm -f ${NATIVE_DIR}/$@
|
||||
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/$@ ${LIBSAM_JARS} ; cd .. )
|
||||
@ls -l ${NATIVE_DIR}/$@
|
||||
@echo "* $@ built"
|
||||
|
||||
router: jars libi2prouter.so
|
||||
|
||||
libi2prouter.so:
|
||||
@echo "* Building $@"
|
||||
@rm -f ${NATIVE_DIR}/$@
|
||||
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/$@ ${LIBROUTER_JARS} ; cd .. )
|
||||
@ls -l ${NATIVE_DIR}/$@
|
||||
@echo "* $@ built"
|
||||
|
||||
console: jars libi2pconsole.so
|
||||
|
||||
# doesn't work, see above
|
||||
libi2pconsole.so:
|
||||
@echo "* Building $@"
|
||||
@rm -f ${NATIVE_DIR}/$@
|
||||
@(cd build ; time ${GCJ} ${OPTIMIZE} -fPIC -fjni -shared -o ../${NATIVE_DIR}/$@ ${LIBCONSOLE_JARS} ; cd .. )
|
||||
@ls -l ${NATIVE_DIR}/$@
|
||||
@echo "* $@ built"
|
||||
|
||||
|
@@ -1,11 +1,13 @@
|
||||
Prerequisites to build from source:
|
||||
Java SDK (preferably Sun) 1.5.0 or higher (1.6 recommended)
|
||||
Apache Ant 1.7.0 or higher
|
||||
Optional, For multilanguage support: The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
|
||||
To build:
|
||||
ant pkg
|
||||
Run 'ant' with no arguments to see other build options.
|
||||
See http://www.i2p2.de/download.html for installation instructions.
|
||||
See INSTALL.txt or http://www.i2p2.de/download.html for installation instructions.
|
||||
|
||||
Documentation:
|
||||
http://www.i2p2.de/
|
||||
|
@@ -1,43 +1,155 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
#
|
||||
# Now in the future we only need to look for '#I2P' and '#/I2P'
|
||||
# for modifications to rc.local and rc.local_shutdown.
|
||||
# I was a moron for not doing it this way in the first place :-) -- Sponge
|
||||
#
|
||||
#
|
||||
|
||||
touch /etc/rc.d/rc.local
|
||||
touch /etc/rc.d/rc.local_shutdown
|
||||
|
||||
I2PRCA=`grep -c /etc/rc.d/rc.local -e i2p`
|
||||
I2PRCB=`grep -c /etc/rc.d/rc.local_shutdown -e i2p`
|
||||
|
||||
echo
|
||||
echo -n "Check 1: /etc/rc.d/rc.local "
|
||||
I2PRCA=`grep -c /etc/rc.d/rc.local -e '/etc/rc.d/rc.i2p'`
|
||||
|
||||
if [ $I2PRCA -eq 0 ] ; then
|
||||
echo '#I2P' >> /etc/rc.d/rc.local
|
||||
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
|
||||
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
|
||||
echo "fi" >> /etc/rc.d/rc.local
|
||||
echo "/etc/rc.d/rc.local modified."
|
||||
echo '#/I2P' >> /etc/rc.d/rc.local
|
||||
echo "modified."
|
||||
else
|
||||
echo "/etc/rc.d/rc.local looks OK"
|
||||
echo -n "looks OK so far,"
|
||||
# Fix old installs, or where people have modified.
|
||||
|
||||
echo -n " Check 1A: "
|
||||
I2PRCC=`grep -c /etc/rc.d/rc.local -e 'i2p-\*\.tmp'`
|
||||
|
||||
if [ $I2PRCC -eq 0 ] ; then
|
||||
DATA=$(cat /etc/rc.d/rc.local | sed -re 's/if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/#I2P\n\( cd \/tmp ; rm -Rf i2p-*.tmp \)\nif \[ -x \/etc\/rc.d\/rc.i2p \] ; then/')
|
||||
echo "${DATA}" > /etc/rc.d/rc.local
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks OK so far,"
|
||||
fi
|
||||
|
||||
echo -n " Check 1B: "
|
||||
I2PRCE=`grep -c /etc/rc.d/rc.local -e 'i2p-\*\.tmp'`
|
||||
if [ $I2PRCE -eq 0 ] ; then
|
||||
DATATOP=$(cat /etc/rc.d/rc.local | sed -n '0,/i2p-\*\.tmp/p' | sed '$d' )
|
||||
DATABOT=$(cat /etc/rc.d/rc.local | sed -n '/i2p-\*\.tmp/,$p' | sed -n '/^fi/,$p' | sed "1d")
|
||||
echo "${DATATOP}" > /etc/rc.d/rc.local
|
||||
echo '#I2P' >> /etc/rc.d/rc.local
|
||||
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
|
||||
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
|
||||
echo "fi" >> /etc/rc.d/rc.local
|
||||
echo '#/I2P' >> /etc/rc.d/rc.local
|
||||
echo "${DATABOT}" >> /etc/rc.d/rc.local
|
||||
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks ok so far,"
|
||||
fi
|
||||
echo -n " Check 1C: "
|
||||
I2PRCF=`grep -c /etc/rc.d/rc.local -e '#/I2P'`
|
||||
if [ $I2PRCF -eq 0 ] ; then
|
||||
DATATOP=$(cat /etc/rc.d/rc.local | sed -n '0,/^#I2P/p' | sed '$d' )
|
||||
DATABOT=$(cat /etc/rc.d/rc.local | sed -n '/^#I2P/,$p' | sed -n '/^fi/,$p' | sed "1d")
|
||||
echo "${DATATOP}" > /etc/rc.d/rc.local
|
||||
echo '#I2P' >> /etc/rc.d/rc.local
|
||||
echo '( cd /tmp ; rm -Rf i2p-*.tmp )' >> /etc/rc.d/rc.local
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local
|
||||
echo " sh /etc/rc.d/rc.i2p start" >> /etc/rc.d/rc.local
|
||||
echo "fi" >> /etc/rc.d/rc.local
|
||||
echo '#/I2P' >> /etc/rc.d/rc.local
|
||||
echo "${DATABOT}" >> /etc/rc.d/rc.local
|
||||
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks ok so far,"
|
||||
fi
|
||||
echo " Done."
|
||||
fi
|
||||
|
||||
echo -n "Check 2: /etc/rc.d/rc.local_shutdown "
|
||||
I2PRCB=`grep -c /etc/rc.d/rc.local_shutdown -e '/etc/rc.d/rc.i2p'`
|
||||
if [ $I2PRCB -eq 0 ] ; then
|
||||
echo "#I2P" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
|
||||
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "fi" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "/etc/rc.d/rc.local_shutdown modified."
|
||||
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "modified."
|
||||
else
|
||||
echo "/etc/rc.d/rc.local_shutdown looks OK"
|
||||
echo -n "looks OK so far,"
|
||||
# Fix old installs
|
||||
|
||||
echo -n " Check 1A: "
|
||||
I2PRCG=`grep -c /etc/rc.d/rc.local_shutdown -e '#I2P'`
|
||||
if [ $I2PRCG -eq 0 ] ; then
|
||||
DATATOP=$(cat /etc/rc.d/rc.local_shutdown | sed -n '0,/^if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/p' | sed '$d' )
|
||||
DATABOT=$(cat /etc/rc.d/rc.local_shutdown | sed -n '/^if \[ -x \/etc\/rc\.d\/rc\.i2p \] ; then/,$p' | sed -n '/^fi/,$p' | sed "1d")
|
||||
echo "${DATATOP}" > /etc/rc.d/rc.local_shutdown
|
||||
echo '#I2P' >> /etc/rc.d/rc.local_shutdown
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
|
||||
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "fi" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "${DATABOT}" >> /etc/rc.d/rc.local_shutdown
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks OK so far,"
|
||||
fi
|
||||
echo -n " Check 1B: "
|
||||
I2PRCH=`grep -c /etc/rc.d/rc.local_shutdown -e '#/I2P'`
|
||||
if [ $I2PRCH -eq 0 ] ; then
|
||||
DATATOP=$(cat /etc/rc.d/rc.local_shutdown | sed -n '0,/^#I2P/p' | sed '$d' )
|
||||
DATABOT=$(cat /etc/rc.d/rc.local_shutdown | sed -n '/^#I2P/,$p' | sed -n '/^fi/,$p' | sed "1d")
|
||||
echo "${DATATOP}" > /etc/rc.d/rc.local_shutdown
|
||||
echo '#I2P' >> /etc/rc.d/rc.local_shutdown
|
||||
echo "if [ -x /etc/rc.d/rc.i2p ] ; then" >> /etc/rc.d/rc.local_shutdown
|
||||
echo " sh /etc/rc.d/rc.i2p stop" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "fi" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "#/I2P" >> /etc/rc.d/rc.local_shutdown
|
||||
echo "${DATABOT}" >> /etc/rc.d/rc.local_shutdown
|
||||
echo -n "additional modifications applied,"
|
||||
else
|
||||
echo -n "looks OK so far,"
|
||||
fi
|
||||
echo " Done."
|
||||
fi
|
||||
|
||||
if [ -f /etc/rc.d/rc.i2p ] ; then
|
||||
if [ -x /etc/rc.d/rc.i2p ] ; then
|
||||
chmod +x /etc/rc.d/rc.i2p.new
|
||||
fi
|
||||
echo
|
||||
# Hopefully get admin's attention.
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -e "\007" ; sleep 0.3
|
||||
echo "It apears that you already have /etc/rc.d/rc.i2p"
|
||||
echo "You may wish to replace it with /etc/rc.d/rc.i2p.new"
|
||||
echo
|
||||
echo "You should replace it with /etc/rc.d/rc.i2p.new as soon as possible"
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -ne "\007" ; sleep 0.3
|
||||
echo -e "\007" ; sleep 0.3
|
||||
else
|
||||
mv /etc/rc.d/rc.i2p.new /etc/rc.d/rc.i2p
|
||||
echo
|
||||
echo "Installation finished. The i2p start/stop script has been"
|
||||
echo "installed on /etc/rc.d directory. You should chmod +x"
|
||||
echo "installed in /etc/rc.d . You should chmod +x"
|
||||
echo '/etc/rc.d/rc.i2p to start it on boot.'
|
||||
echo
|
||||
fi
|
||||
|
@@ -1,42 +1,57 @@
|
||||
#!/bin/sh
|
||||
# Heavily based on the Slackware 12.1 SlackBuild
|
||||
# Slackware build script for i2p
|
||||
|
||||
#
|
||||
# Heavily based on the Slackware 12.2 SlackBuild
|
||||
# Slackware build script for I2P
|
||||
#
|
||||
# PLEASE READ THIS:
|
||||
# Probably you will never have to update i2p packages with upgradepkg,
|
||||
# just because i2p have an auto-update function.
|
||||
# How to start i2p:
|
||||
# After installpkg command, doinst.sh will execute a postinstallation script
|
||||
# needed by i2p. After that you have to chmod +x /etc/rc.d/rc.i2p and start
|
||||
# i2p service with /etc/rc.d/rc.i2p start.
|
||||
# How to start I2P:
|
||||
# After installpkg command, doinst.sh will execute a post-installation script
|
||||
# needed by I2P. After that you have to chmod +x /etc/rc.d/rc.i2p and start
|
||||
# I2P service with /etc/rc.d/rc.i2p start.
|
||||
#
|
||||
# Now tell your browser to user this proxy: localhost on port 4444 and open
|
||||
# this page: http://localhost:7657/index.jsp
|
||||
# Here you can configure i2p, watch network status and navigate anonimously.
|
||||
#
|
||||
# Here you can configure I2P, watch network status and navigate anonimously.
|
||||
# It's suggested to subscribe to various dns host, like i2host.i2p
|
||||
# For any additional information, visit i2host.i2p and forum.i2p
|
||||
#
|
||||
|
||||
CWD=$(pwd)
|
||||
TMP=/tmp
|
||||
PKG=/$TMP/package-base-i2p
|
||||
rm -rf $PKG
|
||||
mkdir -p $PKG
|
||||
# put here installation dir, without first and last /
|
||||
# es: usr/local
|
||||
NAME=i2p-base
|
||||
VERSION=0.0.1
|
||||
BUILD=1sim
|
||||
VERSION=0.0.2
|
||||
BUILD=1sponge
|
||||
ARCH=noarch
|
||||
INSTALL_DIR=opt
|
||||
|
||||
# Less than slackware 13?
|
||||
SLKPLT=$(cat /etc/slackware-version | sed -re "s/(Slackware )([0-9]*)(.*)/\2/")
|
||||
if [ $SLKPLT -lt 13 ] ; then
|
||||
EXT=tgz
|
||||
else
|
||||
EXT=txz
|
||||
fi
|
||||
|
||||
rm -rf $PKG
|
||||
mkdir -p $PKG
|
||||
cd $PKG
|
||||
chown -R root:root .
|
||||
|
||||
mkdir -p $PKG/etc/rc.d
|
||||
mkdir -p $PKG/install
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/i2prouter|g" $CWD/rc.i2p_def > $PKG/etc/rc.d/rc.i2p.new
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/i2prouter|g" "$CWD/rc.i2p_def" > $PKG/etc/rc.d/rc.i2p.new
|
||||
chmod 644 $PKG/etc/rc.d/rc.i2p.new
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/|g" $CWD/doinst.sh > $PKG/install/doinst.sh
|
||||
cat $CWD/slack-desc > $PKG/install/slack-desc
|
||||
cat "$CWD/doinst.sh" > $PKG/install/doinst.sh
|
||||
cat "$CWD/slack-desc" > $PKG/install/slack-desc
|
||||
|
||||
cd $PKG
|
||||
requiredbuilder -v -y -s $CWD $PKG
|
||||
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.tgz
|
||||
#
|
||||
# Not really that important to exec this
|
||||
# as there aren't any deps we don't know.
|
||||
#
|
||||
# requiredbuilder -v -y -s $CWD $PKG
|
||||
#
|
||||
cat "$CWD/slack-required" > $PKG/install/slack-required
|
||||
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.$EXT
|
||||
|
@@ -9,6 +9,22 @@ i2p_stop() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory stop )"
|
||||
}
|
||||
|
||||
i2p_restart() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory restart)"
|
||||
}
|
||||
|
||||
i2p_status() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory status )"
|
||||
}
|
||||
|
||||
i2p_console() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory console )"
|
||||
}
|
||||
|
||||
i2p_dump() {
|
||||
/bin/su - -c "( export PATH=\"$PATH:/usr/lib/java/bin:/usr/lib/java/jre/bin\"; directory dump )"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
'start')
|
||||
i2p_start
|
||||
@@ -17,11 +33,19 @@ case "$1" in
|
||||
i2p_stop
|
||||
;;
|
||||
'restart')
|
||||
i2p_stop
|
||||
i2p_start
|
||||
i2p_restart
|
||||
;;
|
||||
'status')
|
||||
i2p_status
|
||||
;;
|
||||
'console')
|
||||
i2p_console
|
||||
;;
|
||||
'dump')
|
||||
i2p_dump
|
||||
;;
|
||||
*)
|
||||
echo "usage $0 start|stop|restart"
|
||||
echo "usage $0 start|stop|restart|status|console|dump"
|
||||
;;
|
||||
esac
|
||||
|
||||
|
@@ -49,16 +49,21 @@ echo
|
||||
echo "FINISHING I2P INSTALLATION. PLEASE WAIT."
|
||||
|
||||
cd $INST_DIR
|
||||
sh postinstall.sh || (
|
||||
echo "ERROR: failed execution of postinstall.sh. Please"
|
||||
echo "cd into i2p installation directory and run "
|
||||
echo "postinstall.sh manually with ./postinstall.sh"
|
||||
exit 1
|
||||
)
|
||||
|
||||
sleep 10
|
||||
|
||||
sh i2prouter stop || exit 1
|
||||
|
||||
OS_ARCH=`uname -m`
|
||||
X86_64=`echo "$OS_ARCH" | grep x86_64`
|
||||
if [ "X$X86_64" = "X" ]; then
|
||||
wrapperpath="./lib/wrapper/linux"
|
||||
else
|
||||
wrapperpath="./lib/wrapper/linux64"
|
||||
fi
|
||||
cp $wrapperpath/libwrapper.so ./lib/
|
||||
cp $wrapperpath/wrapper.jar ./lib/
|
||||
cp $wrapperpath/i2psvc .
|
||||
rm -rf ./lib/wrapper
|
||||
chmod 744 ./i2psvc
|
||||
|
||||
echo
|
||||
echo "Installation finished."
|
||||
|
@@ -1,28 +1,35 @@
|
||||
#!/bin/sh
|
||||
# Heavily based on the Slackware 12.1 SlackBuild
|
||||
# Slackware build script for i2p
|
||||
|
||||
#
|
||||
# Heavily based on the Slackware 12.2 SlackBuild
|
||||
# Slackware build script for I2P
|
||||
#
|
||||
# PLEASE READ THIS:
|
||||
# Probably you will never have to update i2p packages with upgradepkg,
|
||||
# just because i2p have an auto-update function.
|
||||
# How to start i2p:
|
||||
# After installpkg command, doinst.sh will execute a postinstallation script
|
||||
# needed by i2p. After that you have to chmod +x /etc/rc.d/rc.i2p and start
|
||||
# i2p service with /etc/rc.d/rc.i2p start.
|
||||
# Now tell your browser to user this proxy: localhost on port 4444 and open
|
||||
# this page: http://localhost:7657/index.jsp
|
||||
# Here you can configure i2p, watch network status and navigate anonimously.
|
||||
# It's suggested to subscribe to various dns host, like i2host.i2p
|
||||
# For any additional information, visit i2host.i2p and forum.i2p
|
||||
# Probably you will never have to update I2P packages with upgradepkg,
|
||||
# just because I2P has an auto-update function.
|
||||
# Really you should not ever use any "upgrade" method.
|
||||
#
|
||||
# The correct way to upgrade is to:
|
||||
# 1: install the upgrade
|
||||
# 2: remove the old package
|
||||
#
|
||||
# It is a terrible shame that upgradepkg doesn't do this, infact,
|
||||
# it would actually be the correct way for *any* package!
|
||||
#
|
||||
#
|
||||
|
||||
BUILD=1sim
|
||||
|
||||
# put here installation dir, without first and last /
|
||||
# es: usr/local
|
||||
BUILD=1sponge
|
||||
INSTALL_DIR=opt
|
||||
NAME=i2p
|
||||
ARCH=noarch
|
||||
|
||||
# Less than slackware 13?
|
||||
SLKPLT=$(cat /etc/slackware-version | sed -re "s/(Slackware )([0-9]*)(.*)/\2/")
|
||||
if [ $SLKPLT -lt 13 ] ; then
|
||||
EXT=tgz
|
||||
else
|
||||
EXT=txz
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
# This mess is here due to the totally moronic way i2p does versioning.
|
||||
@@ -64,8 +71,8 @@ mkdir -p $PKG
|
||||
cd $CWD/../../
|
||||
|
||||
ant distclean
|
||||
ant dist
|
||||
|
||||
#ant dist
|
||||
ant tarball
|
||||
|
||||
tar xjvf i2p.tar.bz2 -C $TMP
|
||||
|
||||
@@ -76,6 +83,34 @@ mkdir -p $PKG/$INSTALL_DIR/
|
||||
cp -a ../i2p $PKG/$INSTALL_DIR/
|
||||
|
||||
mkdir -p $PKG/install
|
||||
|
||||
#############################################################################
|
||||
# Preconfigureation to make package smaller
|
||||
#############################################################################
|
||||
cd $PKG/$INSTALL_DIR/i2p
|
||||
|
||||
# wrapper.config $INSTALL_PATH and $SYSTEM_java_io_tmpdir
|
||||
sed "s|\$INSTALL_PATH|$INSTALL_DIR/i2p|g" wrapper.config > a
|
||||
sed "s|\$SYSTEM_java_io_tmpdir|/var/tmp|g" a > wrapper.config
|
||||
# eepget %INSTALL_PATH
|
||||
sed "s|\$INSTALL_PATH|$INSTALL_DIR/i2p|g" eepget > a
|
||||
rm eepget
|
||||
mv a eepget
|
||||
# runplain.sh %INSTALL_PATH and %SYSTEM_java_io_tmpdir
|
||||
sed "s|%INSTALL_PATH|$INSTALL_DIR/i2p|g" runplain.sh > a
|
||||
sed "s|%SYSTEM_java_io_tmpdir|/var/tmp|g" a > runplain.sh
|
||||
# i2prouter %INSTALL_PATH and %SYSTEM_java_io_tmpdir
|
||||
sed "s|%INSTALL_PATH|$INSTALL_DIR/i2p|g" i2prouter > a
|
||||
sed "s|%SYSTEM_java_io_tmpdir|/var/tmp|g" a > i2prouter
|
||||
|
||||
chmod 744 ./i2prouter
|
||||
chmod 744 ./osid
|
||||
chmod 744 ./runplain.sh
|
||||
chmod 744 ./eepget
|
||||
chmod 744 ./scripts/i2pbench.sh
|
||||
chmod 744 ./scripts/i2ptest.sh
|
||||
rm -Rf ./lib/*.dll ./*.bat ./*.exe ./installer ./icons ./a postinstall.sh
|
||||
|
||||
mv $PKG/$INSTALL_DIR/i2p/*.config $PKG/install
|
||||
mv $PKG/$INSTALL_DIR/i2p/blocklist.txt $PKG/$INSTALL_DIR/i2p/blocklist.txt.new
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml $PKG/$INSTALL_DIR/i2p/eepsite/jetty.xml.new
|
||||
@@ -83,6 +118,13 @@ mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/index.html $PKG/$INSTALL_DIR/i2p/eepsit
|
||||
mv $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico $PKG/$INSTALL_DIR/i2p/eepsite/docroot/favicon.ico.new
|
||||
sed "s|directory|/$INSTALL_DIR/i2p/|g" $CWD/doinst.sh > $PKG/install/doinst.sh
|
||||
cat $CWD/slack-desc > $PKG/install/slack-desc
|
||||
|
||||
cd $PKG
|
||||
requiredbuilder -v -y -s $CWD $PKG
|
||||
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.tgz
|
||||
#
|
||||
# requiredbuilder fucks up REALLY bad, and thinks java is perl?!
|
||||
# It also did not catch the shell requirements! BOOOOOOOOOOO! HISSSSSSSS!
|
||||
#
|
||||
# requiredbuilder -v -y -s $CWD $PKG
|
||||
#
|
||||
cat $CWD/slack-required > $PKG/install/slack-required
|
||||
makepkg -l y -c n $CWD/${NAME}-$VERSION-$ARCH-$BUILD.$EXT
|
||||
|
@@ -1,2 +1,4 @@
|
||||
glibc >= 2.7-i486-17 | glibc-solibs >= 2.7-i486-17
|
||||
perl >= 5.10.0-i486-1
|
||||
jre >= 5
|
||||
i2p-base >= 0.0.1
|
||||
bash >= 3.1.017
|
||||
|
||||
|
19
android/AndroidManifest.xml
Normal file
19
android/AndroidManifest.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="net.i2p.router"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0.0">
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<!-- 3 = 1.5, 2 = 1.1, 1 = 1.0; would probably work with 1 but don't have a 1.0 SDK to test against -->
|
||||
<uses-sdk android:minSdkVersion="2" />
|
||||
<application android:label="@string/app_name">
|
||||
<activity android:name=".I2PAndroid"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTask" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
38
android/README.txt
Normal file
38
android/README.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
These instructions are for a recent Android SDK (1.6 or later)..
|
||||
Should also still work with a 1.5 SDK.
|
||||
The build file is not compatible with the 1.1 SDK any more.
|
||||
|
||||
#Download the SDK from http://developer.android.com/sdk/index.html
|
||||
#Unzip the android SDK in ../../
|
||||
#So then the android tools will be in ../../android-sdk-linux_86/tools/
|
||||
#
|
||||
# now go to the available packages tab, check the box and click refresh,
|
||||
# and download an SDK Platform
|
||||
# Since I2P is configured to run on 1.1 or higher
|
||||
# (API 2) download that one. Otherwise you must change the
|
||||
# target in default.properties from android-2 to andriod-x
|
||||
# where x is the API version.
|
||||
|
||||
# create a file local.properties with the following line:
|
||||
# sdk-location=/path/to/your/android-sdk-linux_86
|
||||
|
||||
#then build the android apk file:
|
||||
ant debug
|
||||
|
||||
# Create the android 1.1 (API 2) virtual device
|
||||
# (don't make a custom hardware profile)
|
||||
# A AVD created with the 1.5 SDK will not work with the newer tools
|
||||
../../android-sdk-linux_86/tools/android create avd --name i2p --target 2
|
||||
|
||||
#then run the emulator:
|
||||
../../android-sdk-linux_86/tools/emulator -avd i2p &
|
||||
|
||||
#then wait a couple minutes until the emulator is up
|
||||
#then install the I2P app
|
||||
ant install
|
||||
|
||||
#then run the debugger
|
||||
../../android-sdk-linux_86/tools/ddms &
|
||||
|
||||
#to rebuild and reinstall to emulator:
|
||||
ant reinstall
|
356
android/build.xml
Normal file
356
android/build.xml
Normal file
@@ -0,0 +1,356 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name=".I2PAndroid" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contain the path to the SDK. It should *NOT* be checked in in Version
|
||||
Control Systems. -->
|
||||
<property file="local.properties"/>
|
||||
|
||||
<!-- The build.properties file can be created by you and is never touched
|
||||
by the 'android' tool. This is the place to change some of the default property values
|
||||
used by the Ant rules.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
application-package
|
||||
the name of your application package as defined in the manifest. Used by the
|
||||
'uninstall' rule.
|
||||
source-folder
|
||||
the name of the source folder. Default is 'src'.
|
||||
out-folder
|
||||
the name of the output folder. Default is 'bin'.
|
||||
|
||||
Properties related to the SDK location or the project target should be updated
|
||||
using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your application and
|
||||
should be checked in in Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="build.properties"/>
|
||||
|
||||
<!-- The default.properties file is created and updated by the 'android' tool, as well
|
||||
as ADT.
|
||||
This file is an integral part of the build system for your application and
|
||||
should be checked in in Version Control Systems. -->
|
||||
<property file="default.properties"/>
|
||||
|
||||
<!-- Custom Android task to deal with the project target, and import the proper rules.
|
||||
This requires ant 1.6.0 or above. -->
|
||||
<path id="android.antlibs">
|
||||
<pathelement path="${sdk-location}/tools/lib/anttasks.jar" />
|
||||
<pathelement path="${sdk-location}/tools/lib/sdklib.jar" />
|
||||
<pathelement path="${sdk-location}/tools/lib/androidprefs.jar" />
|
||||
<pathelement path="${sdk-location}/tools/lib/apkbuilder.jar" />
|
||||
<pathelement path="${sdk-location}/tools/lib/jarutils.jar" />
|
||||
</path>
|
||||
|
||||
<taskdef name="setup"
|
||||
classname="com.android.ant.SetupTask"
|
||||
classpathref="android.antlibs"/>
|
||||
|
||||
<!-- Execute the Android Setup task that will setup some properties specific to the target,
|
||||
and import the rules files.
|
||||
To customize the rules, copy/paste them below the task, and disable import by setting
|
||||
the import attribute to false:
|
||||
<setup import="false" />
|
||||
|
||||
This will ensure that the properties are setup correctly but that your customized
|
||||
targets are used.
|
||||
-->
|
||||
<setup import="false" />
|
||||
|
||||
<!--
|
||||
================================================================================
|
||||
New I2P rules
|
||||
================================================================================
|
||||
-->
|
||||
|
||||
<target name="buildrouter" depends="dirs" >
|
||||
<!-- build router and core -->
|
||||
<ant dir=".." target="buildrouter" />
|
||||
|
||||
<!-- router -->
|
||||
<copy file="../build/router.jar" todir="${external-libs-folder}" />
|
||||
|
||||
<!-- core -->
|
||||
<mkdir dir="tmp" />
|
||||
<unjar src="../build/i2p.jar" dest="tmp/" />
|
||||
<delete file="tmp/net/i2p/util/LogWriter.class" />
|
||||
<!-- org.bouncycastle.crypto already in android
|
||||
but we need a little trickery because our HMac is incompatible...
|
||||
and the libs aren't in the SDK to compile against??? -->
|
||||
<jar destfile="${external-libs-folder}/crypto.jar" >
|
||||
<fileset dir="tmp/" >
|
||||
<include name="org/bouncycastle/crypto/Digest.class" />
|
||||
<include name="org/bouncycastle/crypto/Mac.class" />
|
||||
<include name="org/bouncycastle/crypto/digests/GeneralDigest.class" />
|
||||
<include name="org/bouncycastle/crypto/digests/MD5Digest.class" />
|
||||
</fileset>
|
||||
</jar>
|
||||
<delete>
|
||||
<fileset dir="tmp/" >
|
||||
<include name="org/bouncycastle/crypto/Digest.class" />
|
||||
<include name="org/bouncycastle/crypto/Mac.class" />
|
||||
<include name="org/bouncycastle/crypto/digests/GeneralDigest.class" />
|
||||
<include name="org/bouncycastle/crypto/digests/MD5Digest.class" />
|
||||
</fileset>
|
||||
</delete>
|
||||
<!--
|
||||
<delete dir="tmp/org/bouncycastle/" />
|
||||
<delete file="tmp/net/i2p/crypto/HMACGenerator.class" />
|
||||
-->
|
||||
<delete file="tmp/org/bouncycastle/" />
|
||||
<!-- lots of unneeded stuff could be deleted here -->
|
||||
<jar destfile="${external-libs-folder}/i2p.jar" basedir="tmp/" />
|
||||
|
||||
<!-- some resources -->
|
||||
<mkdir dir="res/drawable/" />
|
||||
<copy file="../installer/resources/themes/console/images/i2plogo.png" todir="res/drawable/" />
|
||||
<copy file="../installer/resources/blocklist.txt" tofile="res/raw/blocklist_txt" />
|
||||
</target>
|
||||
|
||||
<target name="hackcleanup">
|
||||
<delete file="${external-libs-folder}/crypto.jar" />
|
||||
</target>
|
||||
|
||||
<!-- fix for property name change sometime after SDK 1.5 -->
|
||||
<property name="android-jar" value="${android.jar}" />
|
||||
<property name="android-aidl" value="${android.aidl}" />
|
||||
|
||||
<!--
|
||||
================================================================================
|
||||
From here down copied from SDK platforms/android-1.1/templates/android_rules.xml
|
||||
and then modified
|
||||
================================================================================
|
||||
-->
|
||||
|
||||
<!--
|
||||
This rules file is meant to be imported by the custom Ant task:
|
||||
com.android.ant.AndroidInitTask
|
||||
|
||||
The following properties are put in place by the importing task:
|
||||
android-jar, android-aidl, aapt, aidl, and dx
|
||||
|
||||
Additionnaly, the task sets up the following classpath reference:
|
||||
android.target.classpath
|
||||
This is used by the compiler task as the boot classpath.
|
||||
-->
|
||||
|
||||
<!-- Custom tasks -->
|
||||
<taskdef name="aaptexec"
|
||||
classname="com.android.ant.AaptExecLoopTask"
|
||||
classpathref="android.antlibs"/>
|
||||
|
||||
<taskdef name="apkbuilder"
|
||||
classname="com.android.ant.ApkBuilderTask"
|
||||
classpathref="android.antlibs"/>
|
||||
|
||||
<!-- Properties -->
|
||||
|
||||
<property name="android-tools" value="${sdk-location}/tools" />
|
||||
|
||||
<!-- Input directories -->
|
||||
<property name="source-folder" value="src" />
|
||||
<property name="gen-folder" value="gen" />
|
||||
<property name="resource-folder" value="res" />
|
||||
<property name="asset-folder" value="assets" />
|
||||
<property name="source-location" value="${basedir}/${source-folder}" />
|
||||
|
||||
<!-- folder for the 3rd party java libraries -->
|
||||
<property name="external-libs-folder" value="libs" />
|
||||
|
||||
<!-- folder for the native libraries -->
|
||||
<property name="native-libs-folder" value="libs" />
|
||||
|
||||
<!-- Output directories -->
|
||||
<property name="gen-folder" value="gen" />
|
||||
<property name="out-folder" value="bin" />
|
||||
<property name="out-classes" value="${out-folder}/classes" />
|
||||
<property name="out-classes-location" value="${basedir}/${out-classes}"/>
|
||||
<!-- out folders for a parent project if this project is an instrumentation project -->
|
||||
<property name="main-out-folder" value="../${out-folder}" />
|
||||
<property name="main-out-classes" value="${main-out-folder}/classes"/>
|
||||
|
||||
<!-- Intermediate files -->
|
||||
<property name="dex-file" value="classes.dex" />
|
||||
<property name="intermediate-dex" value="${out-folder}/${dex-file}" />
|
||||
<!-- dx does not properly support incorrect / or \ based on the platform
|
||||
and Ant cannot convert them because the parameter is not a valid path.
|
||||
Because of this we have to compute different paths depending on the platform. -->
|
||||
<condition property="intermediate-dex-location"
|
||||
value="${basedir}\${intermediate-dex}"
|
||||
else="${basedir}/${intermediate-dex}" >
|
||||
<os family="windows"/>
|
||||
</condition>
|
||||
|
||||
<!-- The final package file to generate -->
|
||||
<property name="out-debug-package" value="${out-folder}/${ant.project.name}-debug.apk"/>
|
||||
|
||||
<!-- Tools -->
|
||||
<condition property="exe" value=".exe" else=""><os family="windows"/></condition>
|
||||
<property name="adb" value="${android-tools}/adb${exe}"/>
|
||||
|
||||
<!-- rules -->
|
||||
|
||||
<!-- Create the output directories if they don't exist yet. -->
|
||||
<target name="dirs">
|
||||
<echo>Creating output directories if needed...</echo>
|
||||
<mkdir dir="${resource-folder}" />
|
||||
<mkdir dir="${external-libs-folder}" />
|
||||
<mkdir dir="${gen-folder}" />
|
||||
<mkdir dir="${out-folder}" />
|
||||
<mkdir dir="${out-classes}" />
|
||||
</target>
|
||||
|
||||
<!-- Generate the R.java file for this project's resources. -->
|
||||
<target name="resource-src" depends="dirs">
|
||||
<echo>Generating R.java / Manifest.java from the resources...</echo>
|
||||
<exec executable="${aapt}" failonerror="true">
|
||||
<arg value="package" />
|
||||
<arg value="-m" />
|
||||
<arg value="-J" />
|
||||
<arg path="${gen-folder}" />
|
||||
<arg value="-M" />
|
||||
<arg path="AndroidManifest.xml" />
|
||||
<arg value="-S" />
|
||||
<arg path="${resource-folder}" />
|
||||
<arg value="-I" />
|
||||
<arg path="${android-jar}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Generate java classes from .aidl files. -->
|
||||
<target name="aidl" depends="dirs">
|
||||
<echo>Compiling aidl files into Java classes...</echo>
|
||||
<apply executable="${aidl}" failonerror="true">
|
||||
<arg value="-p${android-aidl}" />
|
||||
<arg value="-I${source-folder}" />
|
||||
<arg value="-o${gen-folder}" />
|
||||
<fileset dir="${source-folder}">
|
||||
<include name="**/*.aidl"/>
|
||||
</fileset>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<!-- Compile this project's .java files into .class files. -->
|
||||
<!-- I2P add buildrouter -->
|
||||
<target name="compile" depends="buildrouter, resource-src, aidl">
|
||||
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
|
||||
destdir="${out-classes}"
|
||||
bootclasspathref="android.target.classpath">
|
||||
<src path="${source-folder}" />
|
||||
<src path="${gen-folder}" />
|
||||
<classpath>
|
||||
<fileset dir="${external-libs-folder}" includes="*.jar"/>
|
||||
<pathelement path="${main-out-classes}"/>
|
||||
</classpath>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<!-- Convert this project's .class files into .dex files. -->
|
||||
<!-- I2P add hackcleanup -->
|
||||
<target name="dex" depends="compile, hackcleanup">
|
||||
<echo>Converting compiled files and external libraries into ${out-folder}/${dex-file}...</echo>
|
||||
<apply executable="${dx}" failonerror="true" parallel="true">
|
||||
<!-- I2P this is a bad sign that we need this -->
|
||||
<arg value="-JXmx256m" />
|
||||
<arg value="--dex" />
|
||||
<arg value="--output=${intermediate-dex-location}" />
|
||||
<arg path="${out-classes-location}" />
|
||||
<fileset dir="${external-libs-folder}" includes="*.jar"/>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<!-- Put the project's resources into the output package file
|
||||
This actually can create multiple resource package in case
|
||||
Some custom apk with specific configuration have been
|
||||
declared in default.properties.
|
||||
-->
|
||||
<target name="package-resources">
|
||||
<echo>Packaging resources</echo>
|
||||
<aaptexec executable="${aapt}"
|
||||
command="package"
|
||||
manifest="AndroidManifest.xml"
|
||||
resources="${resource-folder}"
|
||||
assets="${asset-folder}"
|
||||
androidjar="${android-jar}"
|
||||
outfolder="${out-folder}"
|
||||
basename="${ant.project.name}" />
|
||||
</target>
|
||||
|
||||
<!-- Package the application and sign it with a debug key.
|
||||
This is the default target when building. It is used for debug. -->
|
||||
<target name="debug" depends="dex, package-resources">
|
||||
<apkbuilder
|
||||
outfolder="${out-folder}"
|
||||
basename="${ant.project.name}"
|
||||
signed="true"
|
||||
verbose="false">
|
||||
<file path="${intermediate-dex}" />
|
||||
<sourcefolder path="${source-folder}" />
|
||||
<jarfolder path="${external-libs-folder}" />
|
||||
<nativefolder path="${native-libs-folder}" />
|
||||
</apkbuilder>
|
||||
</target>
|
||||
|
||||
<!-- Package the application without signing it.
|
||||
This allows for the application to be signed later with an official publishing key. -->
|
||||
<target name="release" depends="dex, package-resources">
|
||||
<apkbuilder
|
||||
outfolder="${out-folder}"
|
||||
basename="${ant.project.name}"
|
||||
signed="false"
|
||||
verbose="false">
|
||||
<file path="${intermediate-dex}" />
|
||||
<sourcefolder path="${source-folder}" />
|
||||
<jarfolder path="${external-libs-folder}" />
|
||||
<nativefolder path="${native-libs-folder}" />
|
||||
</apkbuilder>
|
||||
<echo>All generated packages need to be signed with jarsigner before they are published.</echo>
|
||||
</target>
|
||||
|
||||
<!-- Install the package on the default emulator -->
|
||||
<target name="install" depends="debug">
|
||||
<echo>Installing ${out-debug-package} onto default emulator...</echo>
|
||||
<exec executable="${adb}" failonerror="true">
|
||||
<arg value="install" />
|
||||
<arg path="${out-debug-package}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="reinstall" depends="debug">
|
||||
<echo>Installing ${out-debug-package} onto default emulator...</echo>
|
||||
<exec executable="${adb}" failonerror="true">
|
||||
<arg value="install" />
|
||||
<arg value="-r" />
|
||||
<arg path="${out-debug-package}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<!-- Uinstall the package from the default emulator -->
|
||||
<target name="uninstall">
|
||||
<echo>Uninstalling ${application-package} from the default emulator...</echo>
|
||||
<exec executable="${adb}" failonerror="true">
|
||||
<arg value="uninstall" />
|
||||
<arg path="${application-package}" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="help">
|
||||
<!-- displays starts at col 13
|
||||
|13 80| -->
|
||||
<echo>Android Ant Build. Available targets:</echo>
|
||||
<echo> help: Displays this help.</echo>
|
||||
<echo> debug: Builds the application and sign it with a debug key.</echo>
|
||||
<echo> release: Builds the application. The generated apk file must be</echo>
|
||||
<echo> signed before it is published.</echo>
|
||||
<echo> install: Installs the debug package onto a running emulator or</echo>
|
||||
<echo> device. This can only be used if the application has </echo>
|
||||
<echo> not yet been installed.</echo>
|
||||
<echo> reinstall: Installs the debug package on a running emulator or</echo>
|
||||
<echo> device that already has the application.</echo>
|
||||
<echo> The signatures must match.</echo>
|
||||
<echo> uninstall: uninstall the application from a running emulator or</echo>
|
||||
<echo> device.</echo>
|
||||
</target>
|
||||
</project>
|
11
android/default.properties
Normal file
11
android/default.properties
Normal file
@@ -0,0 +1,11 @@
|
||||
# This file is automatically generated by Android Tools.
|
||||
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||
#
|
||||
# This file must be checked in Version Control Systems.
|
||||
#
|
||||
# To customize properties used by the Ant build system use,
|
||||
# "build.properties", and override values to adapt the script to your
|
||||
# project structure.
|
||||
|
||||
# Project target.
|
||||
target=android-2
|
18
android/res/layout/main.xml
Normal file
18
android/res/layout/main.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
>
|
||||
<TextView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Hello World, I2PAndroid"
|
||||
/>
|
||||
<ImageView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/i2plogo"
|
||||
/>
|
||||
</LinearLayout>
|
||||
|
3
android/res/raw/logger_config
Normal file
3
android/res/raw/logger_config
Normal file
@@ -0,0 +1,3 @@
|
||||
logger.defaultLevel=INFO
|
||||
logger.record.net.i2p.router.transport.FIFOBandwidthRefiller=ERROR
|
||||
logger.record.net.i2p.stat.Rate=ERROR
|
22
android/res/raw/router_config
Normal file
22
android/res/raw/router_config
Normal file
@@ -0,0 +1,22 @@
|
||||
# initial router.config
|
||||
# temp directory
|
||||
i2p.dir.temp=/data/data/net.i2p.router/files/tmp
|
||||
i2p.dir.pid=/data/data/net.i2p.router/files/tmp
|
||||
# save memory
|
||||
prng.buffers=2
|
||||
router.decayingBloomFilterM=20
|
||||
stat.full=false
|
||||
i2np.udp.maxConnections=30
|
||||
# no I2CP
|
||||
i2p.dummyClientFacade=true
|
||||
# for now
|
||||
#i2np.ntcp.enable=false
|
||||
#
|
||||
# UDP crashes the JVM, don't know why
|
||||
#
|
||||
i2np.udp.enable=false
|
||||
# no COMM at all!!!
|
||||
#i2p.vmCommSystem=true
|
||||
# not on android
|
||||
i2np.upnp.enable=false
|
||||
routerconsole.geoip.enable=false
|
4
android/res/values/strings.xml
Normal file
4
android/res/values/strings.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">I2PAndroid</string>
|
||||
</resources>
|
142
android/src/net/i2p/router/I2PAndroid.java
Normal file
142
android/src/net/i2p/router/I2PAndroid.java
Normal file
@@ -0,0 +1,142 @@
|
||||
package net.i2p.router;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.router.Router;
|
||||
import net.i2p.router.RouterLaunch;
|
||||
// import net.i2p.util.NativeBigInteger;
|
||||
|
||||
public class I2PAndroid extends Activity
|
||||
{
|
||||
static Context _context;
|
||||
private static final String DIR = "/data/data/net.i2p.router/files";
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
_context = this; // Activity extends Context
|
||||
debugStuff();
|
||||
initialize();
|
||||
// 300ms per run
|
||||
// 5x slower than java on my server and 50x slower than native on my server
|
||||
// NativeBigInteger.main(null);
|
||||
}
|
||||
|
||||
public void onRestart()
|
||||
{
|
||||
System.err.println("onRestart called");
|
||||
super.onRestart();
|
||||
}
|
||||
|
||||
public void onStart()
|
||||
{
|
||||
System.err.println("onStart called");
|
||||
super.onStart();
|
||||
RouterLaunch.main(null);
|
||||
System.err.println("Router.main finished");
|
||||
}
|
||||
|
||||
public void onResume()
|
||||
{
|
||||
System.err.println("onResume called");
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
public void onPause()
|
||||
{
|
||||
System.err.println("onPause called");
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
public void onStop()
|
||||
{
|
||||
System.err.println("onStop called");
|
||||
super.onStop();
|
||||
|
||||
// from routerconsole ContextHelper
|
||||
List contexts = RouterContext.listContexts();
|
||||
if ( (contexts == null) || (contexts.size() <= 0) )
|
||||
throw new IllegalStateException("No contexts. This is usually because the router is either starting up or shutting down.");
|
||||
RouterContext ctx = (RouterContext)contexts.get(0);
|
||||
|
||||
// shutdown() doesn't return so use shutdownGracefully()
|
||||
ctx.router().shutdownGracefully(Router.EXIT_HARD);
|
||||
System.err.println("shutdown complete");
|
||||
}
|
||||
|
||||
public void onDestroy()
|
||||
{
|
||||
System.err.println("onDestroy called");
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public static Context getContext() {
|
||||
return _context;
|
||||
}
|
||||
|
||||
private void debugStuff() {
|
||||
System.err.println("java.io.tmpdir" + ": " + System.getProperty("java.io.tmpdir"));
|
||||
System.err.println("java.vendor" + ": " + System.getProperty("java.vendor"));
|
||||
System.err.println("java.version" + ": " + System.getProperty("java.version"));
|
||||
System.err.println("os.arch" + ": " + System.getProperty("os.arch"));
|
||||
System.err.println("os.name" + ": " + System.getProperty("os.name"));
|
||||
System.err.println("os.version" + ": " + System.getProperty("os.version"));
|
||||
System.err.println("user.dir" + ": " + System.getProperty("user.dir"));
|
||||
System.err.println("user.home" + ": " + System.getProperty("user.home"));
|
||||
System.err.println("user.name" + ": " + System.getProperty("user.name"));
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
// Until we can edit the router.config on the device,
|
||||
// copy it from the resource every time.
|
||||
// File f = new I2PFile("router.config");
|
||||
// if (!f.exists()) {
|
||||
copyResourceToFile(R.raw.router_config, "router.config");
|
||||
copyResourceToFile(R.raw.logger_config, "logger.config");
|
||||
copyResourceToFile(R.raw.blocklist_txt, "blocklist.txt");
|
||||
// }
|
||||
|
||||
// Set up the locations so Router and WorkingDir can find them
|
||||
System.setProperty("i2p.dir.base", DIR);
|
||||
System.setProperty("i2p.dir.config", DIR);
|
||||
System.setProperty("wrapper.logfile", DIR + "/wrapper.log");
|
||||
}
|
||||
|
||||
private void copyResourceToFile(int resID, String f) {
|
||||
InputStream in = null;
|
||||
FileOutputStream out = null;
|
||||
|
||||
System.err.println("Creating file " + f + " from resource");
|
||||
byte buf[] = new byte[4096];
|
||||
try {
|
||||
// Context methods
|
||||
in = getResources().openRawResource(resID);
|
||||
out = openFileOutput(f, 0);
|
||||
|
||||
int read = 0;
|
||||
while ( (read = in.read(buf)) != -1)
|
||||
out.write(buf, 0, read);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
} catch (Resources.NotFoundException nfe) {
|
||||
} finally {
|
||||
if (in != null) try { in.close(); } catch (IOException ioe) {}
|
||||
if (out != null) try { out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
163
android/src/net/i2p/util/LogWriter.java
Normal file
163
android/src/net/i2p/util/LogWriter.java
Normal file
@@ -0,0 +1,163 @@
|
||||
package net.i2p.util;
|
||||
|
||||
/*
|
||||
* public domain
|
||||
*
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* bridge to android logging
|
||||
*
|
||||
* @author zzz
|
||||
*/
|
||||
class LogWriter implements Runnable {
|
||||
private final static long CONFIG_READ_ITERVAL = 10 * 1000;
|
||||
private long _lastReadConfig = 0;
|
||||
private long _numBytesInCurrentFile = 0;
|
||||
private OutputStream _currentOut; // = System.out
|
||||
private int _rotationNum = -1;
|
||||
private String _logFilenamePattern;
|
||||
private File _currentFile;
|
||||
private LogManager _manager;
|
||||
|
||||
private boolean _write;
|
||||
|
||||
private LogWriter() { // nop
|
||||
}
|
||||
|
||||
public LogWriter(LogManager manager) {
|
||||
_manager = manager;
|
||||
}
|
||||
|
||||
public void stopWriting() {
|
||||
_write = false;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
_write = true;
|
||||
try {
|
||||
while (_write) {
|
||||
flushRecords();
|
||||
rereadConfig();
|
||||
}
|
||||
System.err.println("Done writing");
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error writing the logs: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void flushRecords() { flushRecords(true); }
|
||||
public void flushRecords(boolean shouldWait) {
|
||||
try {
|
||||
List records = _manager._removeAll();
|
||||
if (records == null) return;
|
||||
for (int i = 0; i < records.size(); i++) {
|
||||
LogRecord rec = (LogRecord) records.get(i);
|
||||
writeRecord(rec);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
} finally {
|
||||
if (shouldWait) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
this.wait(10*1000);
|
||||
}
|
||||
} catch (InterruptedException ie) { // nop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String currentFile() {
|
||||
return _currentFile != null ? _currentFile.getAbsolutePath() : "uninitialized";
|
||||
}
|
||||
|
||||
private void rereadConfig() {
|
||||
long now = Clock.getInstance().now();
|
||||
if (now - _lastReadConfig > CONFIG_READ_ITERVAL) {
|
||||
_manager.rereadConfig();
|
||||
_lastReadConfig = now;
|
||||
}
|
||||
}
|
||||
|
||||
private void writeRecord(LogRecord rec) {
|
||||
if (rec.getThrowable() == null)
|
||||
log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage());
|
||||
else
|
||||
log(rec.getPriority(), rec.getSource(), rec.getSourceName(), rec.getThreadName(), rec.getMessage(), rec.getThrowable());
|
||||
}
|
||||
|
||||
public void log(int priority, Class src, String name, String threadName, String msg) {
|
||||
if (src != null) {
|
||||
String tag = src.getName();
|
||||
int dot = tag.lastIndexOf(".");
|
||||
if (dot >= 0)
|
||||
tag = tag.substring(dot + 1);
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
tag,
|
||||
'[' + threadName + "] " + msg);
|
||||
} else if (name != null)
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
name,
|
||||
'[' + threadName + "] " + msg);
|
||||
else
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
threadName, msg);
|
||||
}
|
||||
|
||||
public void log(int priority, Class src, String name, String threadName, String msg, Throwable t) {
|
||||
if (src != null) {
|
||||
String tag = src.getName();
|
||||
int dot = tag.lastIndexOf(".");
|
||||
if (dot >= 0)
|
||||
tag = tag.substring(dot + 1);
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
tag,
|
||||
'[' + threadName + "] " + msg +
|
||||
' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
|
||||
} else if (name != null)
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
name,
|
||||
'[' + threadName + "] " + msg +
|
||||
' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
|
||||
else
|
||||
android.util.Log.println(toAndroidLevel(priority),
|
||||
threadName,
|
||||
msg + ' ' + t.toString() + ' ' + android.util.Log.getStackTraceString(t));
|
||||
}
|
||||
|
||||
private static int toAndroidLevel(int level) {
|
||||
switch (level) {
|
||||
case Log.DEBUG:
|
||||
return android.util.Log.DEBUG;
|
||||
case Log.INFO:
|
||||
return android.util.Log.INFO;
|
||||
case Log.WARN:
|
||||
return android.util.Log.WARN;
|
||||
case Log.ERROR:
|
||||
case Log.CRIT:
|
||||
default:
|
||||
return android.util.Log.ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String replace(String pattern, int num) {
|
||||
char c[] = pattern.toCharArray();
|
||||
StringBuffer buf = new StringBuffer();
|
||||
for (int i = 0; i < c.length; i++) {
|
||||
if ( (c[i] != '#') && (c[i] != '@') )
|
||||
buf.append(c[i]);
|
||||
else
|
||||
buf.append(num);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
@@ -71,4 +71,44 @@
|
||||
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="../../installer/lib/jbigi/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>
|
||||
|
@@ -3,5 +3,6 @@ do.depend=false
|
||||
do.jar=true
|
||||
javac.debug=true
|
||||
javadoc.preview=true
|
||||
jaxbwiz.endorsed.dirs=/usr/local/netbeans-6.8/ide12/modules/ext/jaxb/api
|
||||
jaxws.endorsed.dir=/usr/local/netbeans-6.5/java2/modules/ext/jaxws21/api:/usr/local/netbeans-6.5/ide10/modules/ext/jaxb/api
|
||||
user.properties.file=/root/.netbeans/6.5/build.properties
|
||||
|
@@ -1,5 +1,6 @@
|
||||
application.homepage=http://bob.i2p/
|
||||
application.title=BOB
|
||||
application.vendor=root
|
||||
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
|
||||
@@ -11,6 +12,7 @@ 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
|
||||
@@ -23,6 +25,7 @@ debug.test.classpath=\
|
||||
dist.dir=dist
|
||||
dist.jar=${dist.dir}/BOB.jar
|
||||
dist.javadoc.dir=${dist.dir}/javadoc
|
||||
endorsed.classpath=
|
||||
excludes=
|
||||
file.reference.build-javadoc=../../i2p.i2p/build/javadoc
|
||||
file.reference.i2p.jar=../../core/java/build/i2p.jar
|
||||
@@ -33,7 +36,7 @@ file.reference.router.jar=../../router/java/build/router.jar
|
||||
file.reference.streaming.jar=../streaming/java/build/streaming.jar
|
||||
file.reference.wrapper.jar=../../installer/lib/wrapper/linux/wrapper.jar
|
||||
includes=**
|
||||
jar.compress=false
|
||||
jar.compress=true
|
||||
javac.classpath=\
|
||||
${file.reference.router.jar}:\
|
||||
${file.reference.i2ptunnel.jar}:\
|
||||
@@ -63,8 +66,9 @@ 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:/root/NetBeansProjects/i2p.i2p/apps/BOB/dist/
|
||||
jnlp.codebase.url=file:/usblv/NetBeansProjects/i2p.i2p/apps/BOB/dist
|
||||
jnlp.descriptor=application
|
||||
jnlp.enabled=false
|
||||
jnlp.offline-allowed=false
|
||||
|
@@ -23,6 +23,7 @@
|
||||
*/
|
||||
package net.i2p.BOB;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -34,6 +35,8 @@ import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.streaming.RetransmissionTimer;
|
||||
import net.i2p.util.Log;
|
||||
@@ -163,6 +166,7 @@ public class BOB {
|
||||
public static void stop() {
|
||||
spin.set(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for incoming connections and handle them
|
||||
*
|
||||
@@ -185,16 +189,20 @@ public class BOB {
|
||||
i = Y2.hashCode();
|
||||
try {
|
||||
{
|
||||
File cfg = new File(configLocation);
|
||||
if (!cfg.isAbsolute()) {
|
||||
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
|
||||
}
|
||||
try {
|
||||
FileInputStream fi = new FileInputStream(configLocation);
|
||||
FileInputStream fi = new FileInputStream(cfg);
|
||||
props.load(fi);
|
||||
fi.close();
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
warn("Unable to load up the BOB config file " + configLocation + ", Using defaults.");
|
||||
warn("Unable to load up the BOB config file " + cfg.getAbsolutePath() + ", Using defaults.");
|
||||
warn(fnfe.toString());
|
||||
save = true;
|
||||
} catch (IOException ioe) {
|
||||
warn("IOException on BOB config file " + configLocation + ", using defaults.");
|
||||
warn("IOException on BOB config file " + cfg.getAbsolutePath() + ", using defaults.");
|
||||
warn(ioe.toString());
|
||||
}
|
||||
}
|
||||
@@ -227,13 +235,17 @@ public class BOB {
|
||||
props.setProperty(PROP_BOB_HOST, "localhost");
|
||||
}
|
||||
if (save) {
|
||||
File cfg = new File(configLocation);
|
||||
if (!cfg.isAbsolute()) {
|
||||
cfg = new File(I2PAppContext.getGlobalContext().getConfigDir(), configLocation);
|
||||
}
|
||||
try {
|
||||
warn("Writing new defaults file " + configLocation);
|
||||
FileOutputStream fo = new FileOutputStream(configLocation);
|
||||
props.store(fo, configLocation);
|
||||
warn("Writing new defaults file " + cfg.getAbsolutePath());
|
||||
FileOutputStream fo = new FileOutputStream(cfg);
|
||||
props.store(fo, cfg.getAbsolutePath());
|
||||
fo.close();
|
||||
} catch (IOException ioe) {
|
||||
error("IOException on BOB config file " + configLocation + ", " + ioe);
|
||||
error("IOException on BOB config file " + cfg.getAbsolutePath() + ", " + ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,11 +256,13 @@ public class BOB {
|
||||
listener = new ServerSocket(Integer.parseInt(props.getProperty(PROP_BOB_PORT)), 10, InetAddress.getByName(props.getProperty(PROP_BOB_HOST)));
|
||||
Socket server = null;
|
||||
listener.setSoTimeout(500); // .5 sec
|
||||
|
||||
while (spin.get()) {
|
||||
//DoCMDS connection;
|
||||
|
||||
try {
|
||||
server = listener.accept();
|
||||
server.setKeepAlive(true);
|
||||
g = true;
|
||||
} catch (ConnectException ce) {
|
||||
g = false;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,7 @@ 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;
|
||||
@@ -43,6 +44,7 @@ public class I2Plistener implements Runnable {
|
||||
// private int tgwatch;
|
||||
public I2PSocketManager socketManager;
|
||||
public I2PServerSocket serverSocket;
|
||||
private AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -52,23 +54,13 @@ public class I2Plistener implements Runnable {
|
||||
* @param database
|
||||
* @param _log
|
||||
*/
|
||||
I2Plistener(I2PServerSocket SS, I2PSocketManager S, NamedDB info, NamedDB database, Log _log) {
|
||||
I2Plistener(I2PServerSocket SS, I2PSocketManager S, NamedDB info, NamedDB database, Log _log, AtomicBoolean lives) {
|
||||
this.database = database;
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
this.socketManager = S;
|
||||
serverSocket = SS;
|
||||
// tgwatch = 1;
|
||||
}
|
||||
|
||||
private void rlock() throws Exception {
|
||||
database.getReadLock();
|
||||
info.getReadLock();
|
||||
}
|
||||
|
||||
private void runlock() throws Exception {
|
||||
database.releaseReadLock();
|
||||
info.releaseReadLock();
|
||||
this.serverSocket = SS;
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,50 +72,31 @@ public class I2Plistener implements Runnable {
|
||||
I2PSocket sessSocket = null;
|
||||
int conn = 0;
|
||||
try {
|
||||
die:
|
||||
{
|
||||
|
||||
try {
|
||||
serverSocket.setSoTimeout(50);
|
||||
boolean spin = true;
|
||||
while (spin) {
|
||||
|
||||
while (lives.get()) {
|
||||
try {
|
||||
rlock();
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
sessSocket = serverSocket.accept();
|
||||
g = true;
|
||||
} catch (ConnectException ce) {
|
||||
g = false;
|
||||
} catch (SocketTimeoutException ste) {
|
||||
g = false;
|
||||
}
|
||||
try {
|
||||
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
runlock();
|
||||
} catch (Exception e2) {
|
||||
break die;
|
||||
}
|
||||
break die;
|
||||
if (g) {
|
||||
g = false;
|
||||
conn++;
|
||||
// toss the connection to a new thread.
|
||||
I2PtoTCP conn_c = new I2PtoTCP(sessSocket, info, database, lives);
|
||||
Thread t = new Thread(conn_c, Thread.currentThread().getName() + " I2PtoTCP " + conn);
|
||||
t.start();
|
||||
}
|
||||
try {
|
||||
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);
|
||||
Thread t = new Thread(conn_c, Thread.currentThread().getName() + " I2PtoTCP " + conn);
|
||||
t.start();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
// System.out.println("Exception " + e);
|
||||
}
|
||||
}
|
||||
} catch (I2PException e) {
|
||||
// bad shit
|
||||
System.out.println("Exception " + e);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
|
@@ -26,6 +26,7 @@ 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;
|
||||
|
||||
/**
|
||||
@@ -38,6 +39,7 @@ public class I2PtoTCP implements Runnable {
|
||||
private I2PSocket I2P;
|
||||
private NamedDB info, database;
|
||||
private Socket sock;
|
||||
private AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -46,10 +48,11 @@ public class I2PtoTCP implements Runnable {
|
||||
* @param info
|
||||
* @param database
|
||||
*/
|
||||
I2PtoTCP(I2PSocket I2Psock, NamedDB info, NamedDB 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() {
|
||||
@@ -99,6 +102,7 @@ public class I2PtoTCP implements Runnable {
|
||||
break die;
|
||||
}
|
||||
sock = new Socket(host, port);
|
||||
sock.setKeepAlive(true);
|
||||
// make readers/writers
|
||||
in = sock.getInputStream();
|
||||
out = sock.getOutputStream();
|
||||
@@ -113,35 +117,19 @@ public class I2PtoTCP implements Runnable {
|
||||
out.flush(); // not really needed, but...
|
||||
}
|
||||
// setup to cross the streams
|
||||
TCPio conn_c = new TCPio(in, Iout /*, info, database */); // app -> I2P
|
||||
TCPio conn_a = new TCPio(Iin, out /* , info, database */); // I2P -> app
|
||||
TCPio conn_c = new TCPio(in, Iout, lives); // app -> I2P
|
||||
TCPio conn_a = new TCPio(Iin, out, lives); // I2P -> app
|
||||
t = new Thread(conn_c, Thread.currentThread().getName() + " TCPioA");
|
||||
q = new Thread(conn_a, Thread.currentThread().getName() + " TCPioB");
|
||||
// Fire!
|
||||
t.start();
|
||||
q.start();
|
||||
boolean spin = true;
|
||||
while (t.isAlive() && q.isAlive() && spin) { // AND is used here to kill off the other thread
|
||||
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;
|
||||
}
|
||||
try {
|
||||
rlock();
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
}
|
||||
try {
|
||||
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
runlock();
|
||||
} catch (Exception e2) {
|
||||
break die;
|
||||
}
|
||||
break die;
|
||||
}
|
||||
}
|
||||
// System.out.println("I2PtoTCP: Going away...");
|
||||
} catch (Exception e) {
|
||||
@@ -150,14 +138,6 @@ public class I2PtoTCP implements Runnable {
|
||||
}
|
||||
} // die
|
||||
} finally {
|
||||
try {
|
||||
t.interrupt();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
q.interrupt();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
in.close();
|
||||
} catch (Exception ex) {
|
||||
@@ -174,6 +154,14 @@ public class I2PtoTCP implements Runnable {
|
||||
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();
|
||||
|
@@ -43,7 +43,7 @@ import net.i2p.util.Log;
|
||||
*/
|
||||
public class MUXlisten implements Runnable {
|
||||
|
||||
private NamedDB database, info;
|
||||
private NamedDB database, info;
|
||||
private Log _log;
|
||||
private I2PSocketManager socketManager;
|
||||
private ByteArrayInputStream prikey;
|
||||
@@ -54,6 +54,7 @@ public class MUXlisten implements Runnable {
|
||||
boolean go_out;
|
||||
boolean come_in;
|
||||
private AtomicBoolean lock;
|
||||
private AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor Will fail if INPORT is occupied.
|
||||
@@ -65,47 +66,84 @@ public class MUXlisten implements Runnable {
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
MUXlisten(AtomicBoolean lock, NamedDB database, NamedDB info, Log _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;
|
||||
try {
|
||||
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);
|
||||
|
||||
this.database.getReadLock();
|
||||
this.info.getReadLock();
|
||||
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");
|
||||
Properties Q = new Properties();
|
||||
Lifted.copyProperties(R, Q);
|
||||
this.database.releaseReadLock();
|
||||
this.info.releaseReadLock();
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(true));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
this.database.getReadLock();
|
||||
this.info.getReadLock();
|
||||
|
||||
this.database.getReadLock();
|
||||
this.info.getReadLock();
|
||||
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());
|
||||
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");
|
||||
Properties Q = new Properties();
|
||||
Lifted.copyProperties(R, Q);
|
||||
this.database.releaseReadLock();
|
||||
this.info.releaseReadLock();
|
||||
|
||||
this.database.getReadLock();
|
||||
this.info.getReadLock();
|
||||
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());
|
||||
}
|
||||
this.database.releaseReadLock();
|
||||
this.info.releaseReadLock();
|
||||
|
||||
if (this.come_in) {
|
||||
this.listener = new ServerSocket(port, backlog, host);
|
||||
}
|
||||
socketManager = I2PSocketManagerFactory.createManager(prikey, Q);
|
||||
// I2PException, IOException, RuntimeException
|
||||
// To bad we can't just catch and enumerate....
|
||||
// } catch (I2PException e) {
|
||||
// Something went bad.
|
||||
// this.database.getWriteLock();
|
||||
// this.info.getWriteLock();
|
||||
// this.info.add("STARTING", new Boolean(false));
|
||||
// this.info.releaseWriteLock();
|
||||
// this.database.releaseWriteLock();
|
||||
// throw new I2PException(e);
|
||||
} catch (IOException e) {
|
||||
// Something went bad.
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(false));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
throw new IOException(e.toString());
|
||||
} catch (RuntimeException e) {
|
||||
// Something went bad.
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(false));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
throw new RuntimeException(e);
|
||||
} catch (Exception e) {
|
||||
// Something else went bad.
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(false));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
this.database.releaseReadLock();
|
||||
this.info.releaseReadLock();
|
||||
|
||||
socketManager = I2PSocketManagerFactory.createManager(prikey, Q);
|
||||
if (this.come_in) {
|
||||
this.listener = new ServerSocket(port, backlog, host);
|
||||
}
|
||||
|
||||
// Everything is OK as far as we can tell.
|
||||
this.database.getWriteLock();
|
||||
this.info.getWriteLock();
|
||||
this.info.add("STARTING", new Boolean(true));
|
||||
this.info.releaseWriteLock();
|
||||
this.database.releaseWriteLock();
|
||||
}
|
||||
|
||||
private void rlock() throws Exception {
|
||||
@@ -142,18 +180,22 @@ public class MUXlisten implements Runnable {
|
||||
try {
|
||||
info.add("RUNNING", new Boolean(true));
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
wunlock();
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
wunlock();
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
return;
|
||||
}
|
||||
// socketManager.addDisconnectListener(new DisconnectListener());
|
||||
lives.set(true);
|
||||
lock.set(false);
|
||||
quit:
|
||||
{
|
||||
@@ -166,14 +208,14 @@ public class MUXlisten implements Runnable {
|
||||
if (go_out) {
|
||||
// I2P -> TCP
|
||||
SS = socketManager.getServerSocket();
|
||||
I2Plistener conn = new I2Plistener(SS, socketManager, info, database, _log);
|
||||
I2Plistener conn = new I2Plistener(SS, socketManager, info, database, _log, lives);
|
||||
t = new Thread(tg, conn, "BOBI2Plistener " + N);
|
||||
t.start();
|
||||
}
|
||||
|
||||
if (come_in) {
|
||||
// TCP -> I2P
|
||||
TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log);
|
||||
TCPlistener conn = new TCPlistener(listener, socketManager, info, database, _log, lives);
|
||||
q = new Thread(tg, conn, "BOBTCPlistener " + N);
|
||||
q.start();
|
||||
}
|
||||
@@ -195,7 +237,7 @@ public class MUXlisten implements Runnable {
|
||||
break quit;
|
||||
}
|
||||
boolean spin = true;
|
||||
while (spin) {
|
||||
while (spin && lives.get()) {
|
||||
try {
|
||||
Thread.sleep(1000); //sleep for 1 second
|
||||
} catch (InterruptedException e) {
|
||||
@@ -226,26 +268,30 @@ public class MUXlisten implements Runnable {
|
||||
}
|
||||
} // quit
|
||||
} finally {
|
||||
// Start cleanup.
|
||||
while (!lock.compareAndSet(false, true)) {
|
||||
// wait
|
||||
lives.set(false);
|
||||
// Some grace time.
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
|
||||
// zero out everything.
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
info.add("STARTING", new Boolean(false));
|
||||
info.add("STOPPING", new Boolean(false));
|
||||
info.add("STOPPING", new Boolean(true));
|
||||
info.add("RUNNING", new Boolean(false));
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
wunlock();
|
||||
return;
|
||||
}
|
||||
wunlock();
|
||||
} catch (Exception e) {
|
||||
}
|
||||
|
||||
// Start cleanup.
|
||||
while (!lock.compareAndSet(false, true)) {
|
||||
// wait
|
||||
}
|
||||
if (SS != null) {
|
||||
try {
|
||||
SS.close();
|
||||
@@ -261,11 +307,28 @@ public class MUXlisten implements Runnable {
|
||||
|
||||
// Some grace time.
|
||||
try {
|
||||
Thread.sleep(250);
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException ex) {
|
||||
}
|
||||
|
||||
// zero out everything.
|
||||
try {
|
||||
wlock();
|
||||
try {
|
||||
info.add("STARTING", new Boolean(false));
|
||||
info.add("STOPPING", new Boolean(false));
|
||||
info.add("RUNNING", new Boolean(false));
|
||||
} catch (Exception e) {
|
||||
lock.set(false);
|
||||
wunlock();
|
||||
return;
|
||||
}
|
||||
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 boner = tg.getName();
|
||||
@@ -276,7 +339,7 @@ public class MUXlisten implements Runnable {
|
||||
// visit(tg, 0, boner);
|
||||
int foo = tg.activeCount() + tg.activeGroupCount();
|
||||
// hopefully no longer needed!
|
||||
// int bar = foo;
|
||||
// int bar = lives;
|
||||
// System.out.println("BOB: MUXlisten: Waiting on threads for " + boner);
|
||||
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
|
||||
// visit(tg, 0, boner);
|
||||
@@ -284,12 +347,12 @@ public class MUXlisten implements Runnable {
|
||||
// Happily spin forever :-(
|
||||
while (foo != 0) {
|
||||
foo = tg.activeCount() + tg.activeGroupCount();
|
||||
// if (foo != bar && foo != 0) {
|
||||
// if (lives != bar && lives != 0) {
|
||||
// System.out.println("\nBOB: MUXlisten: ThreadGroup dump BEGIN " + boner);
|
||||
// visit(tg, 0, boner);
|
||||
// System.out.println("BOB: MUXlisten: ThreadGroup dump END " + boner + "\n");
|
||||
// }
|
||||
// bar = foo;
|
||||
// bar = lives;
|
||||
try {
|
||||
Thread.sleep(100); //sleep for 100 ms (One tenth second)
|
||||
} catch (InterruptedException ex) {
|
||||
@@ -356,5 +419,4 @@ public class MUXlisten implements Runnable {
|
||||
visit(groups[i], level + 1, groups[i].getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ package net.i2p.BOB;
|
||||
import net.i2p.client.streaming.RetransmissionTimer;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
/**
|
||||
* Start from command line
|
||||
*
|
||||
|
@@ -43,10 +43,10 @@ public class NamedDB {
|
||||
}
|
||||
|
||||
synchronized public void getReadLock() {
|
||||
while((writersWaiting != 0)) {
|
||||
while ((writersWaiting != 0)) {
|
||||
try {
|
||||
wait();
|
||||
} catch(InterruptedException ie) {
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
readers++;
|
||||
@@ -59,10 +59,10 @@ public class NamedDB {
|
||||
|
||||
synchronized public void getWriteLock() {
|
||||
writersWaiting++;
|
||||
while(readers != 0 && writersWaiting != 1 ) {
|
||||
while (readers != 0 && writersWaiting != 1) {
|
||||
try {
|
||||
wait();
|
||||
} catch(InterruptedException ie) {
|
||||
} catch (InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,8 +79,8 @@ public class NamedDB {
|
||||
* @throws ArrayIndexOutOfBoundsException when key does not exist
|
||||
*/
|
||||
public int idx(Object key) throws ArrayIndexOutOfBoundsException {
|
||||
for(int i = 0; i < index; i++) {
|
||||
if(key.equals(data[i][0])) {
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (key.equals(data[i][0])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -100,17 +100,17 @@ public class NamedDB {
|
||||
|
||||
try {
|
||||
k = idx(key);
|
||||
} catch(ArrayIndexOutOfBoundsException b) {
|
||||
} catch (ArrayIndexOutOfBoundsException b) {
|
||||
return;
|
||||
}
|
||||
olddata = new Object[index + 2][2];
|
||||
// copy to olddata, skipping 'k'
|
||||
for(i = 0 , l = 0; l < index; i++, l++) {
|
||||
if(i == k) {
|
||||
for (i = 0, l = 0; l < index; i++, l++) {
|
||||
if (i == k) {
|
||||
l++;
|
||||
didsomething++;
|
||||
}
|
||||
for(j = 0; j < 2; j++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
olddata[i][j] = data[l][j];
|
||||
}
|
||||
}
|
||||
@@ -132,13 +132,13 @@ public class NamedDB {
|
||||
|
||||
olddata = new Object[index + 2][2];
|
||||
// copy to olddata
|
||||
for(i = 0; i < index; i++) {
|
||||
for(j = 0; j < 2; j++) {
|
||||
for (i = 0; i < index; i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
olddata[i][j] = data[i][j];
|
||||
}
|
||||
}
|
||||
data = olddata;
|
||||
data[index++] = new Object[] {key, val};
|
||||
data[index++] = new Object[]{key, val};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -149,8 +149,8 @@ public class NamedDB {
|
||||
* @throws java.lang.RuntimeException
|
||||
*/
|
||||
public Object get(Object key) throws RuntimeException {
|
||||
for(int i = 0; i < index; i++) {
|
||||
if(key.equals(data[i][0])) {
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (key.equals(data[i][0])) {
|
||||
return data[i][1];
|
||||
}
|
||||
}
|
||||
@@ -164,8 +164,8 @@ public class NamedDB {
|
||||
* @return true if an object exists, else returns false
|
||||
*/
|
||||
public boolean exists(Object key) {
|
||||
for(int i = 0; i < index; i++) {
|
||||
if(key.equals(data[i][0])) {
|
||||
for (int i = 0; i < index; i++) {
|
||||
if (key.equals(data[i][0])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -180,7 +180,7 @@ public class NamedDB {
|
||||
* @throws java.lang.RuntimeException
|
||||
*/
|
||||
public Object getnext(int i) throws RuntimeException {
|
||||
if(i < index && i > -1) {
|
||||
if (i < index && i > -1) {
|
||||
return data[i][1];
|
||||
}
|
||||
throw new RuntimeException("No more data");
|
||||
|
@@ -26,6 +26,7 @@ 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.
|
||||
@@ -36,7 +37,7 @@ public class TCPio implements Runnable {
|
||||
|
||||
private InputStream Ain;
|
||||
private OutputStream Aout;
|
||||
// private NamedDB info, database;
|
||||
private AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -46,11 +47,10 @@ public class TCPio implements Runnable {
|
||||
*
|
||||
* param database
|
||||
*/
|
||||
TCPio(InputStream Ain, OutputStream Aout /*, NamedDB info , NamedDB database */) {
|
||||
TCPio(InputStream Ain, OutputStream Aout, AtomicBoolean lives) {
|
||||
this.Ain = Ain;
|
||||
this.Aout = Aout;
|
||||
// this.info = info;
|
||||
// this.database = database;
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,17 +78,20 @@ public class TCPio implements Runnable {
|
||||
* --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[1];
|
||||
boolean spin = true;
|
||||
byte a[] = new byte[8192];
|
||||
try {
|
||||
try {
|
||||
while (spin) {
|
||||
b = Ain.read(a, 0, 1);
|
||||
while (lives.get()) {
|
||||
b = Ain.read(a, 0, 8192);
|
||||
if (b > 0) {
|
||||
Aout.write(a, 0, b);
|
||||
} else if (b == 0) {
|
||||
@@ -105,9 +108,6 @@ public class TCPio implements Runnable {
|
||||
*
|
||||
*/
|
||||
// System.out.println("TCPio: End Of Stream");
|
||||
// Ain.close();
|
||||
// Aout.close();
|
||||
//return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
// import net.i2p.client.I2PSession;
|
||||
// import net.i2p.client.I2PSessionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.util.Log;
|
||||
@@ -45,6 +46,7 @@ public class TCPlistener implements Runnable {
|
||||
public I2PSocketManager socketManager;
|
||||
public I2PServerSocket serverSocket;
|
||||
private ServerSocket listener;
|
||||
private AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -53,22 +55,13 @@ public class TCPlistener implements Runnable {
|
||||
* @param database
|
||||
* @param _log
|
||||
*/
|
||||
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Log _log) {
|
||||
TCPlistener(ServerSocket listener, I2PSocketManager S, NamedDB info, NamedDB database, Log _log, AtomicBoolean lives) {
|
||||
this.database = database;
|
||||
this.info = info;
|
||||
this._log = _log;
|
||||
this.socketManager = S;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
private void rlock() throws Exception {
|
||||
database.getReadLock();
|
||||
info.getReadLock();
|
||||
}
|
||||
|
||||
private void runlock() throws Exception {
|
||||
database.releaseReadLock();
|
||||
info.releaseReadLock();
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,47 +70,29 @@ public class TCPlistener implements Runnable {
|
||||
*/
|
||||
public void run() {
|
||||
boolean g = false;
|
||||
boolean spin = true;
|
||||
int conn = 0;
|
||||
Socket server = null;
|
||||
try {
|
||||
die:
|
||||
{
|
||||
try {
|
||||
Socket server = new Socket();
|
||||
listener.setSoTimeout(50); // We don't block, we cycle and check.
|
||||
while (spin) {
|
||||
try {
|
||||
rlock();
|
||||
} catch (Exception e) {
|
||||
break die;
|
||||
}
|
||||
try {
|
||||
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
runlock();
|
||||
} catch (Exception e2) {
|
||||
break die;
|
||||
}
|
||||
break die;
|
||||
}
|
||||
try {
|
||||
server = listener.accept();
|
||||
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);
|
||||
Thread t = new Thread(conn_c, Thread.currentThread().getName() + " TCPtoI2P " + conn);
|
||||
t.start();
|
||||
g = false;
|
||||
}
|
||||
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 Thread(conn_c, Thread.currentThread().getName() + " TCPtoI2P " + conn);
|
||||
t.start();
|
||||
g = false;
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
|
@@ -30,6 +30,7 @@ import java.io.OutputStream;
|
||||
import java.net.ConnectException;
|
||||
import java.net.NoRouteToHostException;
|
||||
import java.net.Socket;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
@@ -49,6 +50,7 @@ public class TCPtoI2P implements Runnable {
|
||||
private NamedDB info, database;
|
||||
private Socket sock;
|
||||
private I2PSocketManager socketManager;
|
||||
private AtomicBoolean lives;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -57,11 +59,12 @@ public class TCPtoI2P implements Runnable {
|
||||
* param info
|
||||
* param database
|
||||
*/
|
||||
TCPtoI2P(I2PSocketManager i2p, Socket socket , NamedDB info, NamedDB database) {
|
||||
TCPtoI2P(I2PSocketManager i2p, Socket socket, NamedDB info, NamedDB database, AtomicBoolean lives) {
|
||||
this.sock = socket;
|
||||
this.info = info;
|
||||
this.database = database;
|
||||
this.socketManager = i2p;
|
||||
this.lives = lives;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,8 +146,14 @@ public class TCPtoI2P implements Runnable {
|
||||
input = line.toLowerCase();
|
||||
Destination dest = null;
|
||||
if (input.endsWith(".i2p")) {
|
||||
dest = I2PTunnel.destFromName(input);
|
||||
line = dest.toBase64();
|
||||
try {
|
||||
dest = I2PTunnel.destFromName(input);
|
||||
line = dest.toBase64();
|
||||
} catch (NullPointerException npe) {
|
||||
// Could not find the destination!?
|
||||
Emsg("Can't find destination: " + input, out);
|
||||
return;
|
||||
}
|
||||
}
|
||||
dest = new Destination();
|
||||
dest.fromBase64(line);
|
||||
@@ -157,19 +166,15 @@ public class TCPtoI2P implements Runnable {
|
||||
Iin = I2P.getInputStream();
|
||||
Iout = I2P.getOutputStream();
|
||||
// setup to cross the streams
|
||||
TCPio conn_c = new TCPio(in, Iout /*, info, database */); // app -> I2P
|
||||
TCPio conn_a = new TCPio(Iin, out /*, info, database */); // I2P -> app
|
||||
TCPio conn_c = new TCPio(in, Iout, lives); // app -> I2P
|
||||
TCPio conn_a = new TCPio(Iin, out, lives); // I2P -> app
|
||||
t = new Thread(conn_c, Thread.currentThread().getName() + " TCPioA");
|
||||
q = new Thread(conn_a, Thread.currentThread().getName() + " TCPioB");
|
||||
// Fire!
|
||||
t.start();
|
||||
q.start();
|
||||
boolean spin = true;
|
||||
while (t.isAlive() && q.isAlive()) { // AND is used here to kill off the other thread
|
||||
while (t.isAlive() && q.isAlive() && lives.get()) { // AND is used here to kill off the other thread
|
||||
Thread.sleep(10); //sleep for 10 ms
|
||||
rlock();
|
||||
spin = info.get("RUNNING").equals(Boolean.TRUE);
|
||||
runlock();
|
||||
}
|
||||
} catch (I2PException e) {
|
||||
Emsg(e.toString(), out);
|
||||
|
@@ -78,26 +78,26 @@ public class UDPIOthread implements I2PSessionListener, Runnable {
|
||||
try {
|
||||
in = new DataInputStream(socket.getInputStream());
|
||||
out = new DataOutputStream(socket.getOutputStream());
|
||||
while(up) {
|
||||
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) {
|
||||
if (!ok) {
|
||||
up = false; // Is this the right thing to do??
|
||||
}
|
||||
}
|
||||
} catch(IOException ioe) {
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error running", ioe);
|
||||
} catch(I2PSessionException ise) {
|
||||
} catch (I2PSessionException ise) {
|
||||
_log.error("Error communicating", ise);
|
||||
// } catch(DataFormatException dfe) {
|
||||
// _log.error("Peer destination file is not valid", dfe);
|
||||
} finally {
|
||||
if(_session != null) {
|
||||
if (_session != null) {
|
||||
try {
|
||||
_session.destroySession();
|
||||
} catch(I2PSessionException ise) {
|
||||
} catch (I2PSessionException ise) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
@@ -116,9 +116,9 @@ public class UDPIOthread implements I2PSessionListener, Runnable {
|
||||
byte msg[] = session.receiveMessage(msgId);
|
||||
out.write(msg);
|
||||
out.flush();
|
||||
} catch(I2PSessionException ise) {
|
||||
} catch (I2PSessionException ise) {
|
||||
up = false;
|
||||
} catch(IOException ioe) {
|
||||
} catch (IOException ioe) {
|
||||
up = false;
|
||||
}
|
||||
}
|
||||
|
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004 Ragnarok
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
|
||||
import javax.servlet.GenericServlet;
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
|
||||
/**
|
||||
* A wrapper for addressbook to allow it to be started as a web application.
|
||||
*
|
||||
* @author Ragnarok
|
||||
*
|
||||
*/
|
||||
public class Servlet extends GenericServlet {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||
*/
|
||||
public void service(ServletRequest request, ServletResponse response) {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
|
||||
*/
|
||||
@Override
|
||||
public void init(ServletConfig config) {
|
||||
try {
|
||||
super.init(config);
|
||||
} catch (ServletException exp) {
|
||||
}
|
||||
String[] args = new String[1];
|
||||
args[0] = config.getInitParameter("home");
|
||||
DaemonThread thread = new DaemonThread(args);
|
||||
thread.setDaemon(true);
|
||||
thread.setName("Addressbook");
|
||||
thread.start();
|
||||
System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
|
||||
System.out.println("INFO: config root under " + args[0]);
|
||||
}
|
||||
|
||||
}
|
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -94,20 +94,21 @@ public class AddressBook {
|
||||
* @param proxyPort port number of proxy
|
||||
*/
|
||||
public AddressBook(Subscription subscription, String proxyHost, int proxyPort) {
|
||||
File tmp = new File(I2PAppContext.getGlobalContext().getTempDir(), "addressbook.tmp");
|
||||
this.location = subscription.getLocation();
|
||||
EepGet get = new EepGet(I2PAppContext.getGlobalContext(), true,
|
||||
proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, "addressbook.tmp", null,
|
||||
proxyHost, proxyPort, 0, -1l, MAX_SUB_SIZE, tmp.getAbsolutePath(), null,
|
||||
subscription.getLocation(), true, subscription.getEtag(), subscription.getLastModified(), null);
|
||||
if (get.fetch()) {
|
||||
subscription.setEtag(get.getETag());
|
||||
subscription.setLastModified(get.getLastModified());
|
||||
}
|
||||
try {
|
||||
this.addresses = ConfigParser.parse(new File("addressbook.tmp"));
|
||||
this.addresses = ConfigParser.parse(tmp);
|
||||
} catch (IOException exp) {
|
||||
this.addresses = new HashMap();
|
||||
}
|
||||
new File("addressbook.tmp").delete();
|
||||
tmp.delete();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +193,8 @@ public class AddressBook {
|
||||
(! host.endsWith(".router.i2p")) &&
|
||||
(! host.endsWith(".console.i2p")) &&
|
||||
|
||||
((dest.length() == MIN_DEST_LENGTH && dest.endsWith("AAAA")) ||
|
||||
// null cert ends with AAAA but other zero-length certs would be AA
|
||||
((dest.length() == MIN_DEST_LENGTH && dest.endsWith("AA")) ||
|
||||
(dest.length() > MIN_DEST_LENGTH && dest.length() <= MAX_DEST_LENGTH)) &&
|
||||
dest.replaceAll("[a-zA-Z0-9~-]", "").length() == 0
|
||||
;
|
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
@@ -39,6 +39,9 @@ import java.util.Map;
|
||||
* Utility class providing methods to parse and write files in config file
|
||||
* format, and subscription file format.
|
||||
*
|
||||
* TODO: Change file encoding from default to UTF-8?
|
||||
* Or switch to the DataHelper loadProps/storeProps methods?
|
||||
*
|
||||
* @author Ragnarok
|
||||
*/
|
||||
public class ConfigParser {
|
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
@@ -28,6 +28,8 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
|
||||
/**
|
||||
* Main class of addressbook. Performs updates, and runs the main loop.
|
||||
*
|
||||
@@ -125,11 +127,13 @@ public class Daemon {
|
||||
|
||||
public void run(String[] args) {
|
||||
String settingsLocation = "config.txt";
|
||||
String home;
|
||||
File homeFile;
|
||||
if (args.length > 0) {
|
||||
home = args[0];
|
||||
homeFile = new File(args[0]);
|
||||
if (!homeFile.isAbsolute())
|
||||
homeFile = new File(I2PAppContext.getGlobalContext().getRouterDir(), args[0]);
|
||||
} else {
|
||||
home = ".";
|
||||
homeFile = new File(System.getProperty("user.dir"));
|
||||
}
|
||||
|
||||
Map defaultSettings = new HashMap();
|
||||
@@ -145,7 +149,6 @@ public class Daemon {
|
||||
defaultSettings.put("last_modified", "last_modified");
|
||||
defaultSettings.put("update_delay", "12");
|
||||
|
||||
File homeFile = new File(home);
|
||||
if (!homeFile.exists()) {
|
||||
boolean created = homeFile.mkdirs();
|
||||
if (created)
|
||||
@@ -169,7 +172,7 @@ public class Daemon {
|
||||
delay = 1;
|
||||
}
|
||||
|
||||
update(settings, home);
|
||||
update(settings, homeFile.getAbsolutePath());
|
||||
try {
|
||||
synchronized (this) {
|
||||
wait(delay * 60 * 60 * 1000);
|
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
package net.i2p.addressbook;
|
||||
|
||||
/**
|
||||
* A thread that waits five minutes, then runs the addressbook daemon.
|
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
91
apps/addressbook/java/src/net/i2p/addressbook/Servlet.java
Normal file
91
apps/addressbook/java/src/net/i2p/addressbook/Servlet.java
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2004 Ragnarok
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* A wrapper for addressbook to allow it to be started as a web application.
|
||||
*
|
||||
* This was a GenericServlet, we make it an HttpServlet solely to provide a hook
|
||||
* for SusiDNS to wake us up when the subscription list changes.
|
||||
*
|
||||
* @author Ragnarok
|
||||
*
|
||||
*/
|
||||
public class Servlet extends HttpServlet {
|
||||
private Thread thread;
|
||||
private String nonce;
|
||||
private static final String PROP_NONCE = "addressbook.nonce";
|
||||
|
||||
/**
|
||||
* Hack to allow susidns to kick the daemon when the subscription list changes.
|
||||
* URL must be /addressbook/ with wakeup param set, and nonce param set from system property.
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* see javax.servlet.Servlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
|
||||
*/
|
||||
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
//System.err.println("Got request nonce = " + request.getParameter("nonce"));
|
||||
if (this.thread != null && request.getParameter("wakeup") != null &&
|
||||
this.nonce != null && this.nonce.equals(request.getParameter("nonce"))) {
|
||||
//System.err.println("Sending interrupt");
|
||||
this.thread.interrupt();
|
||||
// no output
|
||||
} else {
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write("I2P addressbook OK");
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
|
||||
*/
|
||||
@Override
|
||||
public void init(ServletConfig config) {
|
||||
try {
|
||||
super.init(config);
|
||||
} catch (ServletException exp) {
|
||||
System.err.println("Addressbook init exception: " + exp);
|
||||
}
|
||||
this.nonce = "" + Math.abs((new Random()).nextLong());
|
||||
// put the nonce where susidns can get it
|
||||
System.setProperty(PROP_NONCE, this.nonce);
|
||||
String[] args = new String[1];
|
||||
args[0] = config.getInitParameter("home");
|
||||
this.thread = new DaemonThread(args);
|
||||
this.thread.setDaemon(true);
|
||||
this.thread.setName("Addressbook");
|
||||
this.thread.start();
|
||||
System.out.println("INFO: Starting Addressbook " + Daemon.VERSION);
|
||||
//System.out.println("INFO: config root under " + args[0]);
|
||||
}
|
||||
|
||||
}
|
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
package net.i2p.addressbook;
|
||||
|
||||
/**
|
||||
* A subscription to a remote address book.
|
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
@@ -19,7 +19,7 @@
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
package addressbook;
|
||||
package net.i2p.addressbook;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
@@ -6,11 +6,17 @@
|
||||
<web-app>
|
||||
<servlet>
|
||||
<servlet-name>addressbook</servlet-name>
|
||||
<servlet-class>addressbook.Servlet</servlet-class>
|
||||
<servlet-class>net.i2p.addressbook.Servlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>home</param-name>
|
||||
<param-value>./addressbook</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
</web-app>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>addressbook</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
||||
|
@@ -73,7 +73,7 @@ class AdminRunner implements Runnable {
|
||||
}
|
||||
|
||||
private void reply(OutputStream out, String content) throws IOException {
|
||||
StringBuffer reply = new StringBuffer(10240);
|
||||
StringBuilder reply = new StringBuilder(10240);
|
||||
reply.append("HTTP/1.1 200 OK\n");
|
||||
reply.append("Connection: close\n");
|
||||
reply.append("Cache-control: no-cache\n");
|
||||
@@ -90,7 +90,7 @@ class AdminRunner implements Runnable {
|
||||
}
|
||||
|
||||
private void replyText(OutputStream out, String content) throws IOException {
|
||||
StringBuffer reply = new StringBuffer(10240);
|
||||
StringBuilder reply = new StringBuilder(10240);
|
||||
reply.append("HTTP/1.1 200 OK\n");
|
||||
reply.append("Connection: close\n");
|
||||
reply.append("Cache-control: no-cache\n");
|
@@ -1 +1,7 @@
|
||||
# NOTE: This I2P config file must use UTF-8 encoding
|
||||
#
|
||||
# If you have a 'split' directory installation, with configuration
|
||||
# files in ~/.i2p (Linux) or %APPDATA%\I2P (Windows), be sure to
|
||||
# edit the file in the configuration directory, NOT the install directory.
|
||||
#
|
||||
i2psnark.dir=i2psnark
|
||||
|
17
apps/i2psnark/java/bmsg.sh
Normal file
17
apps/i2psnark/java/bmsg.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Update messages_xx.po and messages_xx.class files,
|
||||
# from both java and jsp sources.
|
||||
# Requires installed programs xgettext, msgfmt, msgmerge, and find.
|
||||
# zzz - public domain
|
||||
#
|
||||
|
||||
## launching sh.exe with -login parameter will open a shell with the current path always pointing to \bin\
|
||||
## need to cd into our orignal path - where we call sh.exe from.
|
||||
|
||||
cd $CALLFROM
|
||||
## echo $PWD
|
||||
|
||||
## except this everything is the same with bundle-message.sh
|
||||
## walking - public domain :-D
|
||||
|
||||
source bundle-messages.sh $PARAS
|
@@ -37,50 +37,72 @@
|
||||
</javac>
|
||||
</target>
|
||||
<target name="jar" depends="builddep, compile">
|
||||
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/*Servlet.class">
|
||||
<jar destfile="./build/i2psnark.jar" basedir="./build/obj" includes="**/*.class" excludes="**/I2PSnarkServlet*.class **/messages_*.class">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="org.klomp.snark.Snark" />
|
||||
<attribute name="Class-Path" value="i2p.jar mstreaming.jar streaming.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
<target name="war" depends="jar">
|
||||
<!-- Ideally we would include
|
||||
- only include the servlet, everything else is in the jar.
|
||||
- However, the wrapper.config classpath in existing installs
|
||||
- does not include i2psnark.jar.
|
||||
- So we must continue to duplicate everything in the war.
|
||||
<classes dir="./build/obj" includes="**/I2PSnarkServlet*.class" />
|
||||
-->
|
||||
<target name="war" depends="jar, bundle">
|
||||
<war destfile="../i2psnark.war" webxml="../web.xml">
|
||||
<classes dir="./build/obj" includes="**/*" />
|
||||
<!-- include only the web stuff, as of 0.7.12 the router will add i2psnark.jar to the classpath for the war -->
|
||||
<classes dir="./build/obj" includes="**/web/*.class" />
|
||||
</war>
|
||||
</target>
|
||||
|
||||
<target name="bundle" depends="compile">
|
||||
<!-- Update the messages_*.po files.
|
||||
We need to supply the bat file for windows, and then change the fail property to true -->
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="false" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="false" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<exec executable="cmd" osfamily="windows" failifexecutionfails="false" >
|
||||
<arg value="/c" />
|
||||
<arg value="bundle-messages.bat" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="poupdate" depends="compile">
|
||||
<!-- Update the messages_*.po files. -->
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
<exec executable="cmd" osfamily="windows" failifexecutionfails="true" >
|
||||
<arg value="/c" />
|
||||
<arg value="bundle-messages.bat" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="standalone" depends="standalone_prep">
|
||||
<zip destfile="i2psnark-standalone.zip">
|
||||
<zipfileset dir="./dist/" prefix="i2psnark/" />
|
||||
</zip>
|
||||
</target>
|
||||
<target name="standalone_prep" depends="war">
|
||||
<javac debug="true" deprecation="on" source="1.5" target="1.5"
|
||||
destdir="./build" srcdir="src/" includes="org/klomp/snark/web/RunStandalone.java" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
<classpath>
|
||||
<pathelement location="../../jetty/jettylib/commons-logging.jar" />
|
||||
<pathelement location="../../jetty/jettylib/commons-el.jar" />
|
||||
<pathelement location="../../jetty/jettylib/org.mortbay.jetty.jar" />
|
||||
<pathelement location="../../jetty/jettylib/javax.servlet.jar" />
|
||||
<pathelement location="../../../core/java/build/i2p.jar" />
|
||||
</classpath>
|
||||
</javac>
|
||||
|
||||
<jar destfile="./build/launch-i2psnark.jar" basedir="./build/" includes="org/klomp/snark/web/RunStandalone.class">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="org.klomp.snark.web.RunStandalone" />
|
||||
<attribute name="Class-Path" value="lib/i2p.jar lib/mstreaming.jar lib/streaming.jar lib/commons-el.jar lib/commons-logging.jar lib/jasper-compiler.jar lib/jasper-runtime.jar lib/javax.servlet.jar lib/org.mortbay.jetty.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
|
||||
<delete dir="./dist" />
|
||||
<mkdir dir="./dist" />
|
||||
<copy file="./build/launch-i2psnark.jar" tofile="./dist/launch-i2psnark.jar" />
|
||||
<copy file="../launch-i2psnark" todir="./dist/" />
|
||||
<mkdir dir="./dist/webapps" />
|
||||
<copy file="../i2psnark.war" tofile="./dist/webapps/i2psnark.war" />
|
||||
<mkdir dir="./dist/lib" />
|
||||
<copy file="./build/i2psnark.jar" tofile="./dist/lib/i2psnark.jar" />
|
||||
<copy file="../../../core/java/build/i2p.jar" tofile="./dist/lib/i2p.jar" />
|
||||
<copy file="../../jetty/jettylib/commons-el.jar" tofile="./dist/lib/commons-el.jar" />
|
||||
<copy file="../../jetty/jettylib/commons-logging.jar" tofile="./dist/lib/commons-logging.jar" />
|
||||
@@ -92,7 +114,6 @@
|
||||
<copy file="../../streaming/java/build/streaming.jar" tofile="./dist/lib/streaming.jar" />
|
||||
<copy file="../jetty-i2psnark.xml" tofile="./dist/jetty-i2psnark.xml" />
|
||||
<copy file="../readme-standalone.txt" tofile="./dist/readme.txt" />
|
||||
<mkdir dir="./dist/work" />
|
||||
<mkdir dir="./dist/logs" />
|
||||
|
||||
<zip destfile="i2psnark-standalone.zip">
|
||||
@@ -104,11 +125,10 @@
|
||||
<delete dir="./build" />
|
||||
<delete file="../i2psnark.war" />
|
||||
<delete file="./i2psnark-standalone.zip" />
|
||||
<delete dir="./dist" />
|
||||
</target>
|
||||
<target name="cleandep" depends="clean">
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
<target name="distclean" depends="clean">
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
</project>
|
||||
|
26
apps/i2psnark/java/bundle-messages.bat
Normal file
26
apps/i2psnark/java/bundle-messages.bat
Normal file
@@ -0,0 +1,26 @@
|
||||
@echo off
|
||||
set Callfrom=%cd%
|
||||
set Paras=%1
|
||||
|
||||
rem before calling make sure you have msys and mingw 's "bin" path
|
||||
rem in your current searching path
|
||||
rem type "set path" to check
|
||||
if not exist ..\locale\*.only goto updateALL
|
||||
|
||||
rem put a messages_xx.only(eg messages_zh.only) into locale folder
|
||||
rem this script will only touch the po file(eg zh) you specified, leaving other po files untact.
|
||||
|
||||
for %%i in (..\locale\*.only) do set PO=%%~ni
|
||||
echo [Notice] Yu choose to Ony update the choosen file: %PO%.po
|
||||
for %%i in (..\locale\*.po) do if not %%~ni==%PO% ren %%i %%~ni.po-
|
||||
|
||||
call sh --login %cd%\bmsg.sh
|
||||
|
||||
for %%i in (..\locale\*.po-) do if not %%~ni==%PO% ren %%i %%~ni.po
|
||||
goto end
|
||||
|
||||
:updateALL
|
||||
call sh --login %cd%\bmsg.sh
|
||||
|
||||
:end
|
||||
echo End of Message Bundling
|
85
apps/i2psnark/java/bundle-messages.sh
Executable file
85
apps/i2psnark/java/bundle-messages.sh
Executable file
@@ -0,0 +1,85 @@
|
||||
#
|
||||
# Update messages_xx.po and messages_xx.class files,
|
||||
# from both java and jsp sources.
|
||||
# Requires installed programs xgettext, msgfmt, msgmerge, and find.
|
||||
#
|
||||
# usage:
|
||||
# bundle-messages.sh (generates the resource bundle from the .po file)
|
||||
# bundle-messages.sh -p (updates the .po file from the source tags, then generates the resource bundle)
|
||||
#
|
||||
# zzz - public domain
|
||||
#
|
||||
CLASS=org.klomp.snark.web.messages
|
||||
TMPFILE=build/javafiles.txt
|
||||
export TZ=UTC
|
||||
|
||||
if [ "$1" = "-p" ]
|
||||
then
|
||||
POUPDATE=1
|
||||
fi
|
||||
|
||||
# add ../java/ so the refs will work in the po file
|
||||
JPATHS="../java/src"
|
||||
for i in ../locale/messages_*.po
|
||||
do
|
||||
# get language
|
||||
LG=${i#../locale/messages_}
|
||||
LG=${LG%.po}
|
||||
|
||||
if [ "$POUPDATE" = "1" ]
|
||||
then
|
||||
# make list of java files newer than the .po file
|
||||
find $JPATHS -name *.java -newer $i > $TMPFILE
|
||||
fi
|
||||
|
||||
if [ -s build/obj/org/klomp/snark/web/messages_$LG.class -a \
|
||||
build/obj/org/klomp/snark/web/messages_$LG.class -nt $i -a \
|
||||
! -s $TMPFILE ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$POUPDATE" = "1" ]
|
||||
then
|
||||
echo "Updating the $i file from the tags..."
|
||||
# extract strings from java and jsp files, and update messages.po files
|
||||
# translate calls must be one of the forms:
|
||||
# _("foo")
|
||||
# _x("foo")
|
||||
# To start a new translation, copy the header from an old translation to the new .po file,
|
||||
# then ant distclean poupdate.
|
||||
find $JPATHS -name *.java > $TMPFILE
|
||||
xgettext -f $TMPFILE -F -L java --from-code=UTF-8 \
|
||||
--keyword=_ --keyword=_x \
|
||||
-o ${i}t
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - xgettext failed, not updating translations'
|
||||
rm -f ${i}t
|
||||
break
|
||||
fi
|
||||
msgmerge -U --backup=none $i ${i}t
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - msgmerge failed, not updating translations'
|
||||
rm -f ${i}t
|
||||
break
|
||||
fi
|
||||
rm -f ${i}t
|
||||
# so we don't do this again
|
||||
touch $i
|
||||
fi
|
||||
|
||||
echo "Generating ${CLASS}_$LG ResourceBundle..."
|
||||
|
||||
# convert to class files in build/obj
|
||||
msgfmt --java --statistics -r $CLASS -l $LG -d build/obj $i
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - msgfmt failed, not updating translations'
|
||||
break
|
||||
fi
|
||||
done
|
||||
rm -f $TMPFILE
|
||||
# todo: return failure
|
||||
exit 0
|
@@ -7,7 +7,6 @@ package org.klomp.snark;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.I2PSessionException;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.client.I2PSession;
|
||||
|
@@ -137,10 +137,11 @@ public class BitField
|
||||
return count >= size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
// Not very efficient
|
||||
StringBuffer sb = new StringBuffer("BitField(");
|
||||
StringBuilder sb = new StringBuilder("BitField(");
|
||||
sb.append(size).append(")[");
|
||||
for (int i = 0; i < size; i++)
|
||||
if (get(i))
|
||||
|
@@ -17,6 +17,7 @@ import net.i2p.I2PException;
|
||||
import net.i2p.client.I2PSession;
|
||||
import net.i2p.client.streaming.I2PServerSocket;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketEepGet;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.data.DataFormatException;
|
||||
@@ -27,6 +28,7 @@ import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
import net.i2p.util.Translate;
|
||||
|
||||
/**
|
||||
* I2P specific helpers for I2PSnark
|
||||
@@ -46,7 +48,7 @@ public class I2PSnarkUtil {
|
||||
private Map _opts;
|
||||
private I2PSocketManager _manager;
|
||||
private boolean _configured;
|
||||
private Set _shitlist;
|
||||
private final Set _shitlist;
|
||||
private int _maxUploaders;
|
||||
private int _maxUpBW;
|
||||
private int _maxConnections;
|
||||
@@ -73,7 +75,7 @@ public class I2PSnarkUtil {
|
||||
// This is used for both announce replies and .torrent file downloads,
|
||||
// so it must be available even if not connected to I2CP.
|
||||
// so much for multiple instances
|
||||
_tmpDir = new File("tmp", "i2psnark");
|
||||
_tmpDir = new File(ctx.getTempDir(), "i2psnark");
|
||||
FileUtil.rmdir(_tmpDir, false);
|
||||
_tmpDir.mkdirs();
|
||||
}
|
||||
@@ -231,7 +233,13 @@ public class I2PSnarkUtil {
|
||||
if (rewrite)
|
||||
fetchURL = rewriteAnnounce(url);
|
||||
//_log.debug("Rewritten url [" + fetchURL + "]");
|
||||
EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, retries, out.getAbsolutePath(), fetchURL);
|
||||
//EepGet get = new EepGet(_context, _shouldProxy, _proxyHost, _proxyPort, retries, out.getAbsolutePath(), fetchURL);
|
||||
// Use our tunnel for announces and .torrent fetches too! Make sure we're connected first...
|
||||
if (!connected()) {
|
||||
if (!connect())
|
||||
return null;
|
||||
}
|
||||
EepGet get = new I2PSocketEepGet(_context, _manager, retries, out.getAbsolutePath(), fetchURL);
|
||||
if (get.fetch()) {
|
||||
_log.debug("Fetch successful [" + url + "]: size=" + out.length());
|
||||
return out;
|
||||
@@ -327,6 +335,11 @@ public class I2PSnarkUtil {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/** @param ot non-null */
|
||||
public void setOpenTrackerString(String ot) {
|
||||
_opts.put(PROP_OPENTRACKERS, ot);
|
||||
}
|
||||
|
||||
public String getOpenTrackerString() {
|
||||
String rv = (String) _opts.get(PROP_OPENTRACKERS);
|
||||
if (rv == null)
|
||||
@@ -390,4 +403,32 @@ public class I2PSnarkUtil {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static final String BUNDLE_NAME = "org.klomp.snark.web.messages";
|
||||
|
||||
/** lang in routerconsole.lang property, else current locale */
|
||||
public String getString(String key) {
|
||||
return Translate.getString(key, _context, BUNDLE_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* translate a string with a parameter
|
||||
* This is a lot more expensive than getString(s, ctx), so use sparingly.
|
||||
*
|
||||
* @param s string to be translated containing {0}
|
||||
* The {0} will be replaced by the parameter.
|
||||
* Single quotes must be doubled, i.e. ' -> '' in the string.
|
||||
* @param o parameter, not translated.
|
||||
* To tranlslate parameter also, use _("foo {0} bar", _("baz"))
|
||||
* Do not double the single quotes in the parameter.
|
||||
* Use autoboxing to call with ints, longs, floats, etc.
|
||||
*/
|
||||
public String getString(String s, Object o) {
|
||||
return Translate.getString(s, o, _context, BUNDLE_NAME);
|
||||
}
|
||||
|
||||
/** {0} and {1} */
|
||||
public String getString(String s, Object o, Object o2) {
|
||||
return Translate.getString(s, o, o2, _context, BUNDLE_NAME);
|
||||
}
|
||||
}
|
||||
|
@@ -110,6 +110,7 @@ class Message
|
||||
dos.write(data, off, len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
switch (type)
|
||||
|
@@ -345,6 +345,7 @@ public class MetaInfo
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "MetaInfo[info_hash='" + hexencode(info_hash)
|
||||
@@ -362,7 +363,7 @@ public class MetaInfo
|
||||
*/
|
||||
private static String hexencode(byte[] bs)
|
||||
{
|
||||
StringBuffer sb = new StringBuffer(bs.length*2);
|
||||
StringBuilder sb = new StringBuilder(bs.length*2);
|
||||
for (int i = 0; i < bs.length; i++)
|
||||
{
|
||||
int c = bs[i] & 0xFF;
|
||||
@@ -432,7 +433,7 @@ public class MetaInfo
|
||||
private byte[] calculateInfoHash()
|
||||
{
|
||||
Map info = createInfoMap();
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
buf.append("info: ");
|
||||
for (Iterator iter = info.entrySet().iterator(); iter.hasNext(); ) {
|
||||
Map.Entry entry = (Map.Entry)iter.next();
|
||||
|
@@ -106,6 +106,7 @@ public class Peer implements Comparable
|
||||
/**
|
||||
* Returns the String representation of the peerID.
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (peerID != null)
|
||||
@@ -125,6 +126,7 @@ public class Peer implements Comparable
|
||||
/**
|
||||
* The hash code of a Peer is the hash code of the peerID.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return peerID.hashCode() ^ (2 << _id);
|
||||
@@ -134,6 +136,7 @@ public class Peer implements Comparable
|
||||
* Two Peers are equal when they have the same PeerID.
|
||||
* All other properties are ignored.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o instanceof Peer)
|
||||
|
@@ -105,8 +105,8 @@ class PeerCheckerTask extends TimerTask
|
||||
peer.resetCounters();
|
||||
|
||||
_util.debug(peer + ":", Snark.DEBUG);
|
||||
_util.debug(" ul: " + upload/KILOPERSECOND
|
||||
+ " dl: " + download/KILOPERSECOND
|
||||
_util.debug(" ul: " + upload*1024/KILOPERSECOND
|
||||
+ " dl: " + download*1024/KILOPERSECOND
|
||||
+ " i: " + peer.isInterested()
|
||||
+ " I: " + peer.isInteresting()
|
||||
+ " c: " + peer.isChoking()
|
||||
|
@@ -41,7 +41,7 @@ class PeerConnectionOut implements Runnable
|
||||
private boolean quit;
|
||||
|
||||
// Contains Messages.
|
||||
private List sendQueue = new ArrayList();
|
||||
private final List sendQueue = new ArrayList();
|
||||
|
||||
private static long __id = 0;
|
||||
private long _id;
|
||||
@@ -151,7 +151,11 @@ class PeerConnectionOut implements Runnable
|
||||
{
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Send " + peer + ": " + m + " on " + peer.metainfo.getName());
|
||||
m.sendMessage(dout);
|
||||
|
||||
// This can block for quite a while.
|
||||
// To help get slow peers going, and track the bandwidth better,
|
||||
// move this _after_ state.uploaded() and see how it works.
|
||||
//m.sendMessage(dout);
|
||||
lastSent = System.currentTimeMillis();
|
||||
|
||||
// Remove all piece messages after sending a choke message.
|
||||
@@ -162,6 +166,7 @@ class PeerConnectionOut implements Runnable
|
||||
if (m.type == Message.PIECE)
|
||||
state.uploaded(m.len);
|
||||
|
||||
m.sendMessage(dout);
|
||||
m = null;
|
||||
}
|
||||
}
|
||||
|
@@ -236,10 +236,21 @@ public class PeerCoordinator implements PeerListener
|
||||
{
|
||||
synchronized(peers)
|
||||
{
|
||||
return !halted && peers.size() < _util.getMaxConnections();
|
||||
return !halted && peers.size() < getMaxConnections();
|
||||
}
|
||||
}
|
||||
|
||||
/** reduce max if huge pieces to keep from ooming */
|
||||
private int getMaxConnections() {
|
||||
int size = metainfo.getPieceLength(0);
|
||||
int max = _util.getMaxConnections();
|
||||
if (size <= 1024*1024)
|
||||
return max;
|
||||
if (size <= 2*1024*1024)
|
||||
return (max + 1) / 2;
|
||||
return (max + 3) / 4;
|
||||
}
|
||||
|
||||
public boolean halted() { return halted; }
|
||||
|
||||
public void halt()
|
||||
@@ -294,7 +305,7 @@ public class PeerCoordinator implements PeerListener
|
||||
peer.disconnect(false); // Don't deregister this connection/peer.
|
||||
}
|
||||
// This is already checked in addPeer() but we could have gone over the limit since then
|
||||
else if (peers.size() >= _util.getMaxConnections())
|
||||
else if (peers.size() >= getMaxConnections())
|
||||
{
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Already at MAX_CONNECTIONS in connected() with peer: " + peer);
|
||||
@@ -350,7 +361,7 @@ public class PeerCoordinator implements PeerListener
|
||||
peersize = peers.size();
|
||||
// This isn't a strict limit, as we may have several pending connections;
|
||||
// thus there is an additional check in connected()
|
||||
need_more = (!peer.isConnected()) && peersize < _util.getMaxConnections();
|
||||
need_more = (!peer.isConnected()) && peersize < getMaxConnections();
|
||||
// Check if we already have this peer before we build the connection
|
||||
Peer old = peerIDInList(peer.getPeerID(), peers);
|
||||
need_more = need_more && ((old == null) || (old.getInactiveTime() > 8*60*1000));
|
||||
@@ -378,7 +389,7 @@ public class PeerCoordinator implements PeerListener
|
||||
if (peer.isConnected())
|
||||
_log.info("Add peer already connected: " + peer);
|
||||
else
|
||||
_log.info("Connections: " + peersize + "/" + _util.getMaxConnections()
|
||||
_log.info("Connections: " + peersize + "/" + getMaxConnections()
|
||||
+ " not accepting extra peer: " + peer);
|
||||
}
|
||||
return false;
|
||||
@@ -405,7 +416,7 @@ public class PeerCoordinator implements PeerListener
|
||||
count++;
|
||||
if (uploaders < maxUploaders)
|
||||
{
|
||||
if (!peer.isChoked())
|
||||
if (peer.isInteresting() && !peer.isChoked())
|
||||
interested.add(unchokedCount++, peer);
|
||||
else
|
||||
interested.add(peer);
|
||||
|
@@ -12,7 +12,7 @@ import java.util.Set;
|
||||
* from it there too)
|
||||
*/
|
||||
public class PeerCoordinatorSet {
|
||||
private Set _coordinators;
|
||||
private final Set _coordinators;
|
||||
|
||||
public PeerCoordinatorSet() {
|
||||
_coordinators = new HashSet();
|
||||
|
@@ -107,6 +107,7 @@ public class PeerID implements Comparable
|
||||
/**
|
||||
* The hash code of a PeerID is the exclusive or of all id bytes.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return hash;
|
||||
@@ -127,6 +128,7 @@ public class PeerID implements Comparable
|
||||
/**
|
||||
* Two PeerIDs are equal when they have the same id, address and port.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o instanceof PeerID)
|
||||
@@ -171,6 +173,7 @@ public class PeerID implements Comparable
|
||||
* and address is the base64 dest (was the base64 hash of the dest) which
|
||||
* should match what the bytemonsoon tracker reports on its web pages.
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
int nonZero = 0;
|
||||
@@ -190,7 +193,7 @@ public class PeerID implements Comparable
|
||||
{
|
||||
boolean leading_zeros = true;
|
||||
|
||||
StringBuffer sb = new StringBuffer(bs.length*2);
|
||||
StringBuilder sb = new StringBuilder(bs.length*2);
|
||||
for (int i = 0; i < bs.length; i++)
|
||||
{
|
||||
int c = bs[i] & 0xFF;
|
||||
|
@@ -151,7 +151,7 @@ public interface PeerListener
|
||||
*
|
||||
* @param state the PeerState for the peer
|
||||
*/
|
||||
void savePeerPartial(PeerState state);
|
||||
void savePeerPartial(PeerState state); /* FIXME Exporting non-public type through public API FIXME */
|
||||
|
||||
/**
|
||||
* Called when a peer has connected and there may be a partially
|
||||
@@ -161,7 +161,7 @@ public interface PeerListener
|
||||
*
|
||||
* @return request (contains the partial data and valid length)
|
||||
*/
|
||||
Request getPeerPartial(BitField havePieces);
|
||||
Request getPeerPartial(BitField havePieces); /* FIXME Exporting non-public type through public API FIXME */
|
||||
|
||||
/** Mark a peer's requested pieces unrequested when it is disconnected
|
||||
* This prevents premature end game
|
||||
|
@@ -20,13 +20,20 @@ public class Piece implements Comparable {
|
||||
return this.peers.size() - ((Piece)o).peers.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null) return false;
|
||||
try {
|
||||
if (o instanceof Piece) {
|
||||
if (o == null) return false;
|
||||
return this.id == ((Piece)o).id;
|
||||
} catch (ClassCastException cce) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 5;
|
||||
hash = 31 * hash + this.id;
|
||||
return hash;
|
||||
}
|
||||
|
||||
public int getId() { return this.id; }
|
||||
@@ -36,6 +43,7 @@ public class Piece implements Comparable {
|
||||
public boolean isRequested() { return this.requested; }
|
||||
public void setRequested(boolean requested) { this.requested = requested; }
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(id);
|
||||
}
|
||||
|
@@ -51,11 +51,13 @@ class Request
|
||||
throw new IndexOutOfBoundsException("Illegal Request " + toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return piece ^ off ^ len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o instanceof Request)
|
||||
@@ -67,6 +69,7 @@ class Request
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "(" + piece + "," + off + "," + len + ")";
|
||||
|
@@ -28,7 +28,6 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Random;
|
||||
import java.util.StringTokenizer;
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -36,6 +36,7 @@ public class SnarkShutdown extends I2PAppThread
|
||||
|
||||
private final ShutdownListener listener;
|
||||
|
||||
/* FIXME Exporting non-public type through public API FIXME */
|
||||
public SnarkShutdown(Storage storage,
|
||||
PeerCoordinator coordinator,
|
||||
ConnectionAcceptor acceptor,
|
||||
@@ -49,6 +50,7 @@ public class SnarkShutdown extends I2PAppThread
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
//Snark.debug("Shutting down...", Snark.NOTICE);
|
||||
|
@@ -46,7 +46,7 @@ public class Storage
|
||||
private final StorageListener listener;
|
||||
private I2PSnarkUtil _util;
|
||||
|
||||
private BitField bitfield; // BitField to represent the pieces
|
||||
private /* FIXME final FIXME */ BitField bitfield; // BitField to represent the pieces
|
||||
private int needed; // Number of pieces needed
|
||||
private boolean _probablyComplete; // use this to decide whether to open files RO
|
||||
|
||||
@@ -57,7 +57,8 @@ public class Storage
|
||||
|
||||
/** The default piece size. */
|
||||
private static final int MIN_PIECE_SIZE = 256*1024;
|
||||
public static final int MAX_PIECE_SIZE = 1024*1024;
|
||||
/** note that we start reducing max number of peer connections above 1MB */
|
||||
public static final int MAX_PIECE_SIZE = 2*1024*1024;
|
||||
/** The maximum number of pieces in a torrent. */
|
||||
public static final int MAX_PIECES = 10*1024;
|
||||
public static final long MAX_TOTAL_SIZE = MAX_PIECE_SIZE * (long) MAX_PIECES;
|
||||
@@ -190,6 +191,9 @@ public class Storage
|
||||
}
|
||||
*/
|
||||
|
||||
/** FIXME we can run out of fd's doing this,
|
||||
* maybe some sort of global close-RAF-right-away flag
|
||||
* would do the trick */
|
||||
private void fast_digestCreate() throws IOException {
|
||||
// Calculate piece_hashes
|
||||
SHA1 digest = new SHA1();
|
||||
@@ -416,13 +420,29 @@ public class Storage
|
||||
}
|
||||
}
|
||||
|
||||
private static final char[] ILLEGAL = new char[] {
|
||||
'<', '>', ':', '"', '/', '\\', '|', '?', '*',
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 };
|
||||
|
||||
/**
|
||||
* Removes 'suspicious' characters from the give file name.
|
||||
* Removes 'suspicious' characters from the given file name.
|
||||
* http://msdn.microsoft.com/en-us/library/aa365247%28VS.85%29.aspx
|
||||
*/
|
||||
private static String filterName(String name)
|
||||
{
|
||||
// XXX - Is this enough?
|
||||
return name.replace(File.separatorChar, '_');
|
||||
if (name.equals(".") || name.equals(" "))
|
||||
return "_";
|
||||
String rv = name;
|
||||
if (rv.startsWith("."))
|
||||
rv = '_' + rv.substring(1);
|
||||
if (rv.endsWith(".") || rv.endsWith(" "))
|
||||
rv = rv.substring(0, rv.length() - 1) + '_';
|
||||
for (int i = 0; i < ILLEGAL.length; i++) {
|
||||
if (rv.indexOf(ILLEGAL[i]) >= 0)
|
||||
rv = rv.replace(ILLEGAL[i], '_');
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
private File createFileFromNames(File base, List names) throws IOException
|
||||
@@ -573,6 +593,9 @@ public class Storage
|
||||
if (rafs == null) return;
|
||||
for (int i = 0; i < rafs.length; i++)
|
||||
{
|
||||
// if we had an IOE in check(), the RAFlock may be null
|
||||
if (RAFlock[i] == null)
|
||||
continue;
|
||||
try {
|
||||
synchronized(RAFlock[i]) {
|
||||
closeRAF(i);
|
||||
|
@@ -24,6 +24,8 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
@@ -81,6 +83,7 @@ public class TrackerClient extends I2PAppThread
|
||||
started = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (stop) throw new RuntimeException("Dont rerun me, create a copy");
|
||||
super.start();
|
||||
@@ -109,6 +112,7 @@ public class TrackerClient extends I2PAppThread
|
||||
return !stop && _util.connected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
String infoHash = urlencode(meta.getInfoHash());
|
||||
@@ -121,13 +125,19 @@ public class TrackerClient extends I2PAppThread
|
||||
// followed by the secondary open trackers
|
||||
// It's painful, but try to make sure if an open tracker is also
|
||||
// the primary tracker, that we don't add it twice.
|
||||
// todo: check for b32 matches as well
|
||||
trackers = new ArrayList(2);
|
||||
trackers.add(new Tracker(meta.getAnnounce(), true));
|
||||
String primary = meta.getAnnounce();
|
||||
if (isValidAnnounce(primary)) {
|
||||
trackers.add(new Tracker(meta.getAnnounce(), true));
|
||||
} else {
|
||||
_log.warn("Skipping invalid or non-i2p announce: " + primary);
|
||||
}
|
||||
List tlist = _util.getOpenTrackers();
|
||||
if (tlist != null) {
|
||||
for (int i = 0; i < tlist.size(); i++) {
|
||||
String url = (String)tlist.get(i);
|
||||
if (!url.startsWith("http://")) {
|
||||
if (!isValidAnnounce(url)) {
|
||||
_log.error("Bad announce URL: [" + url + "]");
|
||||
continue;
|
||||
}
|
||||
@@ -136,22 +146,29 @@ public class TrackerClient extends I2PAppThread
|
||||
_log.error("Bad announce URL: [" + url + "]");
|
||||
continue;
|
||||
}
|
||||
if (meta.getAnnounce().startsWith(url.substring(0, slash)))
|
||||
if (primary.startsWith(url.substring(0, slash)))
|
||||
continue;
|
||||
String dest = _util.lookup(url.substring(7, slash));
|
||||
if (dest == null) {
|
||||
_log.error("Announce host unknown: [" + url + "]");
|
||||
continue;
|
||||
}
|
||||
if (meta.getAnnounce().startsWith("http://" + dest))
|
||||
if (primary.startsWith("http://" + dest))
|
||||
continue;
|
||||
if (meta.getAnnounce().startsWith("http://i2p/" + dest))
|
||||
if (primary.startsWith("http://i2p/" + dest))
|
||||
continue;
|
||||
trackers.add(new Tracker(url, false));
|
||||
_log.debug("Additional announce: [" + url + "] for infoHash: " + infoHash);
|
||||
}
|
||||
}
|
||||
|
||||
if (tlist.size() <= 0) {
|
||||
// FIXME really need to get this message to the gui
|
||||
stop = true;
|
||||
_log.error("No valid trackers for infoHash: " + infoHash);
|
||||
return;
|
||||
}
|
||||
|
||||
long uploaded = coordinator.getUploaded();
|
||||
long downloaded = coordinator.getDownloaded();
|
||||
long left = coordinator.getLeft();
|
||||
@@ -162,7 +179,7 @@ public class TrackerClient extends I2PAppThread
|
||||
try
|
||||
{
|
||||
if (!verifyConnected()) return;
|
||||
boolean started = false;
|
||||
boolean runStarted = false;
|
||||
boolean firstTime = true;
|
||||
int consecutiveFails = 0;
|
||||
Random r = new Random();
|
||||
@@ -178,7 +195,7 @@ public class TrackerClient extends I2PAppThread
|
||||
if (firstTime) {
|
||||
delay = r.nextInt(30*1000);
|
||||
firstTime = false;
|
||||
} else if (completed && started)
|
||||
} else if (completed && runStarted)
|
||||
delay = 3*SLEEP*60*1000 + random;
|
||||
else if (coordinator.trackerProblems != null && ++consecutiveFails < MAX_CONSEC_FAILS)
|
||||
delay = INITIAL_SLEEP;
|
||||
@@ -221,7 +238,7 @@ public class TrackerClient extends I2PAppThread
|
||||
Tracker tr = (Tracker)iter.next();
|
||||
if ((!stop) && (!tr.stop) &&
|
||||
(completed || coordinator.needPeers()) &&
|
||||
(event == COMPLETED_EVENT || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
|
||||
(event.equals(COMPLETED_EVENT) || System.currentTimeMillis() > tr.lastRequestTime + tr.interval))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -237,7 +254,7 @@ public class TrackerClient extends I2PAppThread
|
||||
tr.consecutiveFails = 0;
|
||||
if (tr.isPrimary)
|
||||
consecutiveFails = 0;
|
||||
started = true;
|
||||
runStarted = true;
|
||||
tr.started = true;
|
||||
|
||||
Set peers = info.getPeers();
|
||||
@@ -296,7 +313,7 @@ public class TrackerClient extends I2PAppThread
|
||||
|
||||
// we could try and total the unique peers but that's too hard for now
|
||||
coordinator.trackerSeenPeers = maxSeenPeers;
|
||||
if (!started)
|
||||
if (!runStarted)
|
||||
_util.debug(" Retrying in one minute...", Snark.DEBUG);
|
||||
} // *** end of while loop
|
||||
} // try
|
||||
@@ -311,9 +328,9 @@ public class TrackerClient extends I2PAppThread
|
||||
try
|
||||
{
|
||||
// try to contact everybody we can
|
||||
// We don't need I2CP connection for eepget
|
||||
// if (!verifyConnected()) return;
|
||||
// Don't try to restart I2CP connection just to say goodbye
|
||||
for (Iterator iter = trackers.iterator(); iter.hasNext(); ) {
|
||||
if (!_util.connected()) return;
|
||||
Tracker tr = (Tracker)iter.next();
|
||||
if (tr.started && (!tr.stop) && tr.trackerProblems == null)
|
||||
doRequest(tr, infoHash, peerID, uploaded,
|
||||
@@ -338,7 +355,7 @@ public class TrackerClient extends I2PAppThread
|
||||
+ "&uploaded=" + uploaded
|
||||
+ "&downloaded=" + downloaded
|
||||
+ "&left=" + left
|
||||
+ ((event != NO_EVENT) ? ("&event=" + event) : "");
|
||||
+ ((! event.equals(NO_EVENT)) ? ("&event=" + event) : "");
|
||||
_util.debug("Sending TrackerClient request: " + s, Snark.INFO);
|
||||
|
||||
tr.lastRequestTime = System.currentTimeMillis();
|
||||
@@ -368,24 +385,51 @@ public class TrackerClient extends I2PAppThread
|
||||
}
|
||||
|
||||
/**
|
||||
* Very lazy byte[] to URL encoder. Just encodes everything, even
|
||||
* "normal" chars.
|
||||
* Very lazy byte[] to URL encoder. Just encodes almost everything, even
|
||||
* some "normal" chars.
|
||||
* By not encoding about 1/4 of the chars, we make random data like hashes about 16% smaller.
|
||||
*
|
||||
* RFC1738: 0-9a-zA-Z$-_.+!*'(),
|
||||
* Us: 0-9a-zA-Z
|
||||
*
|
||||
*/
|
||||
public static String urlencode(byte[] bs)
|
||||
{
|
||||
StringBuffer sb = new StringBuffer(bs.length*3);
|
||||
StringBuilder sb = new StringBuilder(bs.length*3);
|
||||
for (int i = 0; i < bs.length; i++)
|
||||
{
|
||||
int c = bs[i] & 0xFF;
|
||||
sb.append('%');
|
||||
if (c < 16)
|
||||
sb.append('0');
|
||||
sb.append(Integer.toHexString(c));
|
||||
if ((c >= '0' && c <= '9') ||
|
||||
(c >= 'A' && c <= 'Z') ||
|
||||
(c >= 'a' && c <= 'z')) {
|
||||
sb.append((char)c);
|
||||
} else {
|
||||
sb.append('%');
|
||||
if (c < 16)
|
||||
sb.append('0');
|
||||
sb.append(Integer.toHexString(c));
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true for i2p hosts only
|
||||
* @since 0.7.12
|
||||
*/
|
||||
static boolean isValidAnnounce(String ann) {
|
||||
URL url;
|
||||
try {
|
||||
url = new URL(ann);
|
||||
} catch (MalformedURLException mue) {
|
||||
return false;
|
||||
}
|
||||
return url.getProtocol().equals("http") &&
|
||||
(url.getHost().endsWith(".i2p") || url.getHost().equals("i2p")) &&
|
||||
url.getPort() < 0;
|
||||
}
|
||||
|
||||
private class Tracker
|
||||
{
|
||||
String announce;
|
||||
|
@@ -125,6 +125,7 @@ public class TrackerInfo
|
||||
return interval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (failure_reason != null)
|
||||
|
@@ -279,7 +279,9 @@ public class BDecoder
|
||||
public BEValue bdecodeMap() throws IOException
|
||||
{
|
||||
int c = getNextIndicator();
|
||||
if (c != 'd')
|
||||
if (c == '<')
|
||||
throw new InvalidBEncodingException("Expected a .torrent metainfo file but found HTML? Check URL or file!");
|
||||
else if (c != 'd')
|
||||
throw new InvalidBEncodingException("Expected 'd', not '"
|
||||
+ (char)c + "'");
|
||||
indicator = 0;
|
||||
|
@@ -172,13 +172,14 @@ public class BEValue
|
||||
/** return the untyped value */
|
||||
public Object getValue() { return value; }
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String valueString;
|
||||
if (value instanceof byte[])
|
||||
{
|
||||
byte[] bs = (byte[])value;
|
||||
// XXX - Stupid heuristic...
|
||||
// XXX - Stupid heuristic... and not UTF-8
|
||||
if (bs.length <= 12)
|
||||
valueString = new String(bs);
|
||||
else
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@ package org.klomp.snark.web;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.util.FileUtil;
|
||||
|
||||
import org.mortbay.jetty.Server;
|
||||
@@ -22,7 +23,7 @@ public class RunStandalone {
|
||||
}
|
||||
|
||||
public void start() {
|
||||
File workDir = new File("work");
|
||||
File workDir = new File(I2PAppContext.getGlobalContext().getTempDir(), "jetty-work");
|
||||
boolean workDirRemoved = FileUtil.rmdir(workDir, false);
|
||||
if (!workDirRemoved)
|
||||
System.err.println("ERROR: Unable to remove Jetty temporary work directory");
|
||||
@@ -32,6 +33,8 @@ public class RunStandalone {
|
||||
|
||||
try {
|
||||
_server = new Server("jetty-i2psnark.xml");
|
||||
// just blow up NPE if we don't have a context
|
||||
(_server.getContexts()[0]).setTempDirectory(workDir);
|
||||
_server.start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@@ -1,6 +1,12 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure 1.2//EN" "http://jetty.mortbay.org/configure_1_2.dtd">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- This is the configuration for a standalone i2psnark and -->
|
||||
<!-- jetty instance connecting to a router in another jvm. -->
|
||||
<!-- Run it with the launch-i2psnark script. -->
|
||||
<!-- i2psnark will be accessed at http://127.0.0.1:8002/ -->
|
||||
<!-- =============================================================== -->
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Jetty Server -->
|
||||
@@ -12,7 +18,7 @@
|
||||
<!-- =============================================================== -->
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add and configure a HTTP listener to port 8080 -->
|
||||
<!-- Add and configure a HTTP listener to port 8002 -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<Call name="addListener">
|
||||
<Arg>
|
||||
@@ -23,7 +29,7 @@
|
||||
<Set name="port">8002</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
<Set name="MinThreads">3</Set>
|
||||
<Set name="MinThreads">1</Set>
|
||||
<Set name="MaxThreads">10</Set>
|
||||
<Set name="MaxIdleTimeMs">30000</Set>
|
||||
<Set name="LowResourcePersistTimeMs">1000</Set>
|
||||
@@ -34,45 +40,6 @@
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add a HTTPS SSL listener on port 8443 -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- UNCOMMENT TO ACTIVATE
|
||||
<Call name="addListener">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.SunJsseListener">
|
||||
<Set name="Port">8443</Set>
|
||||
<Set name="PoolName">main</Set>
|
||||
<Set name="Keystore"><SystemProperty name="jetty.home" default="."/>/etc/demokeystore</Set>
|
||||
<Set name="Password">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
|
||||
<Set name="KeyPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
|
||||
<Set name="NonPersistentUserAgent">MSIE 5</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
-->
|
||||
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!-- Add a AJP13 listener on port 8009 -->
|
||||
<!-- This protocol can be used with mod_jk in apache, IIS etc. -->
|
||||
<!-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -->
|
||||
<!--
|
||||
<Call name="addListener">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.ajp.AJP13Listener">
|
||||
<Set name="PoolName">ajp</Set>
|
||||
<Set name="Port">8009</Set>
|
||||
<Set name="MinThreads">3</Set>
|
||||
<Set name="MaxThreads">20</Set>
|
||||
<Set name="MaxIdleTimeMs">0</Set>
|
||||
<Set name="confidentialPort">443</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
-->
|
||||
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Contexts -->
|
||||
<!-- =============================================================== -->
|
||||
@@ -91,20 +58,23 @@
|
||||
<Arg>webapps/i2psnark.war</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Request Log -->
|
||||
<!-- =============================================================== -->
|
||||
<Set name="RequestLog">
|
||||
<New class="org.mortbay.http.NCSARequestLog">
|
||||
<Arg>./logs/yyyy_mm_dd.i2psnark-request.log</Arg>
|
||||
<Set name="retainDays">90</Set>
|
||||
<Set name="append">true</Set>
|
||||
<Set name="extended">false</Set>
|
||||
<Set name="buffered">false</Set>
|
||||
<Set name="LogTimeZone">GMT</Set>
|
||||
</New>
|
||||
</Set>
|
||||
|
||||
<!-- this is so we can find the css -->
|
||||
<Call name="addContext">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.HttpContext">
|
||||
<Set name="contextPath">/themes</Set>
|
||||
<Set name="resourceBase">./docs/themes</Set>
|
||||
<Call name="addHandler">
|
||||
<Arg>
|
||||
<New class="org.mortbay.http.handler.ResourceHandler">
|
||||
<Set name="redirectWelcome">FALSE</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Other Server Options -->
|
||||
<!-- =============================================================== -->
|
||||
|
8
apps/i2psnark/launch-i2psnark
Executable file
8
apps/i2psnark/launch-i2psnark
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This launches i2psnark and jetty in a separate jvm.
|
||||
# The file jetty-i2psnark.xml must be present in the current directory.
|
||||
# i2psnark will be accessed at http://127.0.0.1:8002/
|
||||
#
|
||||
I2P="."
|
||||
java -cp "$I2P/lib/i2psnark.jar:$I2P/lib/i2p.jar:$I2P/lib/mstreaming.jar:$I2P/lib/streaming.jar:$I2P/lib/commons-el.jar:$I2P/lib/commons-logging.jar:$I2P/lib/jasper-compiler.jar:$I2P/lib/jasper-runtime.jar:$I2P/lib/javax.servlet.jar:$I2P/lib/org.mortbay.jetty.jar" org.klomp.snark.web.RunStandalone "$@"
|
655
apps/i2psnark/locale/messages_de.po
Normal file
655
apps/i2psnark/locale/messages_de.po
Normal file
@@ -0,0 +1,655 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the i2psnark package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P i2psnark\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-12-10 17:41+0000\n"
|
||||
"PO-Revision-Date: 2009-10-19 12:50+0000\n"
|
||||
"Last-Translator: foo <foo@bar>\n"
|
||||
"Language-Team: foo <foo@bar>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-Language: German\n"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:84
|
||||
#, java-format
|
||||
msgid "Adding torrents in {0} minutes"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:241
|
||||
#, java-format
|
||||
msgid "Total uploaders limit changed to {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:243
|
||||
#, java-format
|
||||
msgid "Minimum total uploaders limit is {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:255
|
||||
#, java-format
|
||||
msgid "Up BW limit changed to {0}KBps"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:257
|
||||
#, java-format
|
||||
msgid "Minimum up bandwidth limit is {0}KBps"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:301
|
||||
msgid "Cannot change the I2CP settings while torrents are active"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:307
|
||||
msgid "Disconnecting old I2CP destination"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:311
|
||||
#, java-format
|
||||
msgid "I2CP settings changed to {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:315
|
||||
msgid ""
|
||||
"Unable to connect with the new settings, reverting to the old I2CP settings"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:319
|
||||
msgid "Unable to reconnect with the old settings!"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:321
|
||||
msgid "Reconnected on the new I2CP destination"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:332
|
||||
#, java-format
|
||||
msgid "I2CP listener restarted for \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:343
|
||||
msgid "Enabled autostart"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:345
|
||||
msgid "Disabled autostart"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:351
|
||||
msgid "Enabled open trackers - torrent restart required to take effect."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:353
|
||||
msgid "Disabled open trackers - torrent restart required to take effect."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:360
|
||||
msgid "Open Tracker list changed - torrent restart required to take effect."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:367
|
||||
msgid "Configuration unchanged."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:377
|
||||
#, java-format
|
||||
msgid "Unable to save the config to {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:395
|
||||
msgid "Connecting to I2P"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:398
|
||||
msgid "Error connecting to I2P - check your I2CP settings!"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:407
|
||||
#, java-format
|
||||
msgid "Error: Could not add the torrent {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:446
|
||||
#, java-format
|
||||
msgid "Torrent in \"{0}\" is invalid"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:461
|
||||
#, java-format
|
||||
msgid "Torrent added and started: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:463
|
||||
#, java-format
|
||||
msgid "Torrent added: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:559
|
||||
#, java-format
|
||||
msgid "Non-i2p tracker in \"{0}\", deleting it from our list of trackers!"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:562
|
||||
#, java-format
|
||||
msgid "Too many files in \"{0}\" ({1}), deleting it!"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:564
|
||||
#, java-format
|
||||
msgid "Torrent file \"{0}\" cannot end in '.torrent', deleting it!"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:566
|
||||
#, java-format
|
||||
msgid "No pieces in \"{0}\", deleting it!"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:568
|
||||
#, java-format
|
||||
msgid "Too many pieces in \"{0}\", limit is {1}, deleting it!"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:570
|
||||
#, java-format
|
||||
msgid "Pieces are too large in \"{0}\" ({1}B), deleting it."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:571
|
||||
#, java-format
|
||||
msgid "Limit is {0}B"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:579
|
||||
#, java-format
|
||||
msgid "Torrents larger than {0}B are not supported yet, deleting \"{1}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:595
|
||||
#, java-format
|
||||
msgid "Error: Could not remove the torrent {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:616
|
||||
#, java-format
|
||||
msgid "Torrent stopped: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:631
|
||||
#, java-format
|
||||
msgid "Torrent removed: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:664
|
||||
#, java-format
|
||||
msgid "Download finished: \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:664
|
||||
#, java-format
|
||||
msgid "size: {0}B"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:692
|
||||
msgid "Unable to connect to I2P!"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:86
|
||||
msgid "I2PSnark - Anonymous BitTorrent Client"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:95
|
||||
msgid "Refresh page"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:97
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:655
|
||||
msgid "I2PSnark"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:99
|
||||
msgid "Forum"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:125
|
||||
msgid "Status"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:132
|
||||
msgid "Hide Peers"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:134
|
||||
msgid "Show Peers"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:138
|
||||
msgid "Torrent"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:140
|
||||
msgid "ETA"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:142
|
||||
msgid "Downloaded"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:144
|
||||
msgid "Uploaded"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:146
|
||||
msgid "Down Rate"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:148
|
||||
msgid "Up Rate"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:155
|
||||
msgid "Stop all torrents and the I2P tunnel"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:157
|
||||
msgid "Stop All"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:162
|
||||
msgid "Start all torrents and the I2P tunnel"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:164
|
||||
msgid "Start All"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:181
|
||||
msgid "No torrents loaded."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:186
|
||||
msgid "Totals"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:188
|
||||
#, java-format
|
||||
msgid "{0} torrents"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:191
|
||||
#, java-format
|
||||
msgid "{0} connected peers"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:218
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:748
|
||||
msgid "Add torrent"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:226
|
||||
#, java-format
|
||||
msgid "Torrent file {0} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:236
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:985
|
||||
#, java-format
|
||||
msgid "Torrent already running: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:238
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:987
|
||||
#, java-format
|
||||
msgid "Torrent already in the queue: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:242
|
||||
#, java-format
|
||||
msgid "Copying torrent to {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:245
|
||||
#, java-format
|
||||
msgid "Unable to copy the torrent to {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:245
|
||||
#, java-format
|
||||
msgid "from {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:253
|
||||
#, java-format
|
||||
msgid "Fetching {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:257
|
||||
msgid "Invalid URL - must start with http://"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:262
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:615
|
||||
msgid "Stop"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:277
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:623
|
||||
msgid "Start"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:287
|
||||
#, java-format
|
||||
msgid "Starting up torrent {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:307
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:325
|
||||
#, java-format
|
||||
msgid "Torrent file deleted: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:331
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:341
|
||||
#, java-format
|
||||
msgid "Data file deleted: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:333
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:343
|
||||
#, java-format
|
||||
msgid "Data file could not be deleted: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:352
|
||||
#, java-format
|
||||
msgid "Data dir deleted: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:359
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:913
|
||||
msgid "Save configuration"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:373
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:799
|
||||
msgid "Create torrent"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:383
|
||||
msgid "Error creating torrent - you must select a tracker"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:398
|
||||
#, java-format
|
||||
msgid "Torrent created for \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:401
|
||||
#, java-format
|
||||
msgid ""
|
||||
"Many I2P trackers require you to register new torrents before seeding - "
|
||||
"please do so before starting \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:403
|
||||
#, java-format
|
||||
msgid "Error creating a torrent for \"{0}\""
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:406
|
||||
#, java-format
|
||||
msgid "Cannot create a torrent for the nonexistent data: {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:409
|
||||
msgid "Error creating torrent - you must enter a file or directory"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:412
|
||||
msgid "Stopping all torrents and closing the I2P tunnel."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:421
|
||||
msgid "I2P tunnel closed."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:424
|
||||
msgid "Opening the I2P tunnel and starting all torrents."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:501
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:669
|
||||
msgid "Unknown"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:504
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:508
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512
|
||||
msgid "TrackerErr"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:506
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:508
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:518
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:527
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:529
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:533
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:858
|
||||
msgid "peers"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:516
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:520
|
||||
msgid "Seeding"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:522
|
||||
msgid "Complete"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:525
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:529
|
||||
msgid "OK"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:531
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535
|
||||
msgid "Stalled"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:537
|
||||
msgid "No Peers"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:539
|
||||
msgid "Stopped"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:552
|
||||
msgid "View files"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:554
|
||||
msgid "Open file"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:578
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:778
|
||||
msgid "Tracker"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:579
|
||||
msgid "Details"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:613
|
||||
msgid "Stop the torrent"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:621
|
||||
msgid "Start the torrent"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:628
|
||||
msgid "Remove the torrent from the active list, deleting the .torrent file"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:630
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:634
|
||||
msgid "Delete the .torrent file and the associated data file(s)"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:636
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:679
|
||||
msgid "Seed"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:697
|
||||
msgid "Uninteresting"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:699
|
||||
msgid "Choked"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:713
|
||||
msgid "Uninterested"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:715
|
||||
msgid "Choking"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:741
|
||||
msgid "Add Torrent"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:743
|
||||
msgid "From URL"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:751
|
||||
#, java-format
|
||||
msgid "Alternately, you can copy .torrent files to {0} ."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:753
|
||||
msgid "Removing a .torrent file will cause the torrent to stop."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:769
|
||||
msgid "Create Torrent"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:772
|
||||
msgid "Data to seed"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:776
|
||||
msgid "File to seed (must be within the specified path)"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:780
|
||||
msgid "Select a tracker"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:793
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796
|
||||
msgid "Custom tracker URL"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:816
|
||||
msgid "Configuration"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:819
|
||||
msgid "Data directory"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:822
|
||||
msgid "Directory to store torrents and data"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:824
|
||||
msgid "Edit i2psnark.config and restart to change"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:828
|
||||
msgid "Auto start"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:832
|
||||
msgid "If checked, automatically start torrents that are added"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:855
|
||||
msgid "Total uploader limit"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:862
|
||||
msgid "Up bandwidth limit"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:865
|
||||
msgid "Half available bandwidth< recommended."
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:867
|
||||
msgid "Configure"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:871
|
||||
msgid "Use open trackers also"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:875
|
||||
msgid ""
|
||||
"If checked, announce torrents to open trackers as well as the tracker listed "
|
||||
"in the torrent file"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879
|
||||
msgid "Open tracker announce URLs"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:890
|
||||
msgid "I2CP host"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:895
|
||||
msgid "I2CP port"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:908
|
||||
msgid "I2CP options"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:966
|
||||
#, java-format
|
||||
msgid "Torrent fetched from {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:993
|
||||
#, java-format
|
||||
msgid "Torrent at {0} was not valid"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:998
|
||||
#, java-format
|
||||
msgid "Torrent was not retrieved from {0}"
|
||||
msgstr ""
|
668
apps/i2psnark/locale/messages_ru.po
Normal file
668
apps/i2psnark/locale/messages_ru.po
Normal file
@@ -0,0 +1,668 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the i2psnark package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P i2psnark\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-03-13 09:42+0000\n"
|
||||
"PO-Revision-Date: 2010-03-13 09:44+0000\n"
|
||||
"Last-Translator: 4get <forget@mail.i2p>\n"
|
||||
"Language-Team: foo <foo@bar>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-Language: Russian\n"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:84
|
||||
#, java-format
|
||||
msgid "Adding torrents in {0} minutes"
|
||||
msgstr "Торренты будут подгружены через {0} минут(ы)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:242
|
||||
#, java-format
|
||||
msgid "Total uploaders limit changed to {0}"
|
||||
msgstr "Новое значение лимита количества слотов отдачи: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:244
|
||||
#, java-format
|
||||
msgid "Minimum total uploaders limit is {0}"
|
||||
msgstr "Минимально допустимое значение для количества слотов: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:256
|
||||
#, java-format
|
||||
msgid "Up BW limit changed to {0}KBps"
|
||||
msgstr "Новое значение лимита скорости отдачи: {0} KBps"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:258
|
||||
#, java-format
|
||||
msgid "Minimum up bandwidth limit is {0}KBps"
|
||||
msgstr "Минимально допустимое значение для лимита скорости отдачи: {0} KBps"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:302
|
||||
msgid "Cannot change the I2CP settings while torrents are active"
|
||||
msgstr "Невозможно изменить настройки I2CP пока есть активные торренты"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:308
|
||||
msgid "Disconnecting old I2CP destination"
|
||||
msgstr "Рассоединяемся по старому адресу I2CP"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:312
|
||||
#, java-format
|
||||
msgid "I2CP settings changed to {0}"
|
||||
msgstr "Новые параметры I2CP: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:316
|
||||
msgid "Unable to connect with the new settings, reverting to the old I2CP settings"
|
||||
msgstr "Не удалось соединиться с использованием новых настроек I2CP, возвращаемся к старым настройкам"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:320
|
||||
msgid "Unable to reconnect with the old settings!"
|
||||
msgstr "Не удалось пересоединиться с использованием старых настроек I2CP!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:322
|
||||
msgid "Reconnected on the new I2CP destination"
|
||||
msgstr "Пересоединились по новому адресу I2CP"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:333
|
||||
#, java-format
|
||||
msgid "I2CP listener restarted for \"{0}\""
|
||||
msgstr "I2CP-приёмник перезапущен для \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:344
|
||||
msgid "Enabled autostart"
|
||||
msgstr "Автостарт включен"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:346
|
||||
msgid "Disabled autostart"
|
||||
msgstr "Автостарт выключен"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:352
|
||||
msgid "Enabled open trackers - torrent restart required to take effect."
|
||||
msgstr "Включено использование открытых трекеров. Требуется перезапуск торрента, чтобы изменения вступили в силу."
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:354
|
||||
msgid "Disabled open trackers - torrent restart required to take effect."
|
||||
msgstr "Отключено использование открытых трекеров. Требуется перезапуск торрента, чтобы изменения вступили в силу."
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:361
|
||||
msgid "Open Tracker list changed - torrent restart required to take effect."
|
||||
msgstr "Изменен список открытых трекеров. Требуется перезапуск торрента, чтобы изменения вступили в силу."
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:368
|
||||
msgid "Configuration unchanged."
|
||||
msgstr "Настройки не изменились."
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:378
|
||||
#, java-format
|
||||
msgid "Unable to save the config to {0}"
|
||||
msgstr "Не удалось сохранить настройки в {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:396
|
||||
msgid "Connecting to I2P"
|
||||
msgstr "Устанавливается соединение с I2P"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:399
|
||||
msgid "Error connecting to I2P - check your I2CP settings!"
|
||||
msgstr "Ошибка соединения с I2P, проверьте настройки I2CP!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:408
|
||||
#, java-format
|
||||
msgid "Error: Could not add the torrent {0}"
|
||||
msgstr "Ошибка: Не удалось добавить торрент {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:430
|
||||
#, java-format
|
||||
msgid "Cannot open \"{0}\""
|
||||
msgstr "Не удалось открыть \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:443
|
||||
#, java-format
|
||||
msgid "Warning - Ignoring non-i2p tracker in \"{0}\", will announce to i2p open trackers only"
|
||||
msgstr "Внимание: указанные в \"{0}\" не-i2p трекеры будут проигнорированы, будут использоваться только открытые i2p трекеры"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:445
|
||||
#, java-format
|
||||
msgid "Warning - Ignoring non-i2p tracker in \"{0}\", and open trackers are disabled, you must enable open trackers before starting the torrent!"
|
||||
msgstr "Внимание: указанные в \"{0}\" не-i2p трекеры будут проигнорированы, однако использование открытых i2p трекеров отключено, Вы должны включить поддержку открытых i2p трекеров перед запуском этого торрента!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:464
|
||||
#, java-format
|
||||
msgid "Torrent in \"{0}\" is invalid"
|
||||
msgstr "Торрент в \"{0}\" некорректен"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:479
|
||||
#, java-format
|
||||
msgid "Torrent added and started: \"{0}\""
|
||||
msgstr "Торрент добавлен и запущен: \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:481
|
||||
#, java-format
|
||||
msgid "Torrent added: \"{0}\""
|
||||
msgstr "Торрент добавлен: \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:578
|
||||
#, java-format
|
||||
msgid "Too many files in \"{0}\" ({1}), deleting it!"
|
||||
msgstr "Слишком много файлов в торренте \"{0}\" ({1}), удаляем его!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:580
|
||||
#, java-format
|
||||
msgid "Torrent file \"{0}\" cannot end in \".torrent\", deleting it!"
|
||||
msgstr "Торрент \"{0}\" содержит единственный файл заканчивающийся на \".torrent\", удаляем его!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:582
|
||||
#, java-format
|
||||
msgid "No pieces in \"{0}\", deleting it!"
|
||||
msgstr "В торренте \"{0}\" не оказалось ни одной части, удаляем его!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:584
|
||||
#, java-format
|
||||
msgid "Too many pieces in \"{0}\", limit is {1}, deleting it!"
|
||||
msgstr "Слишком много частей в торренте \"{0}\" (наш предел {1}), удаляем его!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:586
|
||||
#, java-format
|
||||
msgid "Pieces are too large in \"{0}\" ({1}B), deleting it."
|
||||
msgstr "Слишком крупные части в торренте \"{0}\" ({1}B), удаляем его."
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:587
|
||||
#, java-format
|
||||
msgid "Limit is {0}B"
|
||||
msgstr "Наш предел {0}B"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:595
|
||||
#, java-format
|
||||
msgid "Torrents larger than {0}B are not supported yet, deleting \"{1}\""
|
||||
msgstr "Торренты крупнее чем {0}B пока не поддерживается, удаляем \"{1}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:611
|
||||
#, java-format
|
||||
msgid "Error: Could not remove the torrent {0}"
|
||||
msgstr "Ошибка: Невозможно удалить торрент {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:632
|
||||
#, java-format
|
||||
msgid "Torrent stopped: \"{0}\""
|
||||
msgstr "Торрент остановлен: \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:647
|
||||
#, java-format
|
||||
msgid "Torrent removed: \"{0}\""
|
||||
msgstr "Торрент удален: \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:680
|
||||
#, java-format
|
||||
msgid "Download finished: \"{0}\""
|
||||
msgstr "Завершена загрузка: \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:680
|
||||
#, java-format
|
||||
msgid "size: {0}B"
|
||||
msgstr "размер: {0}B"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:708
|
||||
msgid "Unable to connect to I2P!"
|
||||
msgstr "Не удалось установить соединение с I2P!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:86
|
||||
msgid "I2PSnark - Anonymous BitTorrent Client"
|
||||
msgstr "I2PSnark — Анонимный BitTorrent Клиент"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:95
|
||||
msgid "Refresh page"
|
||||
msgstr "Обновить страницу"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:97
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:669
|
||||
msgid "I2PSnark"
|
||||
msgstr "I2PSnark"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:99
|
||||
msgid "Forum"
|
||||
msgstr "Форум"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:125
|
||||
msgid "Status"
|
||||
msgstr "Статус"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:131
|
||||
msgid "Hide Peers"
|
||||
msgstr "спрятать список пиров"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:134
|
||||
msgid "Show Peers"
|
||||
msgstr "показать список пиров"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:139
|
||||
msgid "Torrent"
|
||||
msgstr "Торрент"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:141
|
||||
msgid "ETA"
|
||||
msgstr "Осталось"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:143
|
||||
msgid "Downloaded"
|
||||
msgstr "Получено"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:145
|
||||
msgid "Uploaded"
|
||||
msgstr "Отдано"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:147
|
||||
msgid "Down Rate"
|
||||
msgstr "Скорость загрузки"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:149
|
||||
msgid "Up Rate"
|
||||
msgstr "Скорость отдачи"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:156
|
||||
msgid "Stop all torrents and the I2P tunnel"
|
||||
msgstr "Остановить все торренты и закрыть соединение с I2P"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:158
|
||||
msgid "Stop All"
|
||||
msgstr "Остановить все"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:163
|
||||
msgid "Start all torrents and the I2P tunnel"
|
||||
msgstr "Запустить все торренты и открыть соединение с I2P"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:165
|
||||
msgid "Start All"
|
||||
msgstr "Запустить все"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:182
|
||||
msgid "No torrents loaded."
|
||||
msgstr "Нет загруженных торрентов."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:187
|
||||
msgid "Totals"
|
||||
msgstr "Всего"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:189
|
||||
#, java-format
|
||||
msgid "{0} torrents"
|
||||
msgstr "{0} торрентов"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:192
|
||||
#, java-format
|
||||
msgid "{0} connected peers"
|
||||
msgstr "{0} подсоединенных пиров"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:227
|
||||
#, java-format
|
||||
msgid "Torrent file {0} does not exist"
|
||||
msgstr "Торрент {0} не существует"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:237
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1003
|
||||
#, java-format
|
||||
msgid "Torrent already running: {0}"
|
||||
msgstr "Торрент уже запущен: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:239
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1005
|
||||
#, java-format
|
||||
msgid "Torrent already in the queue: {0}"
|
||||
msgstr "Торрент уже в очереди: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:243
|
||||
#, java-format
|
||||
msgid "Copying torrent to {0}"
|
||||
msgstr "Копируем торрент в: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246
|
||||
#, java-format
|
||||
msgid "Unable to copy the torrent to {0}"
|
||||
msgstr "Не удалось скопировать торрент в: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246
|
||||
#, java-format
|
||||
msgid "from {0}"
|
||||
msgstr "из: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:254
|
||||
#, java-format
|
||||
msgid "Fetching {0}"
|
||||
msgstr "Получение торрента: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:258
|
||||
msgid "Invalid URL - must start with http://"
|
||||
msgstr "Некорректный URL, должен начинаться с http://"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:288
|
||||
#, java-format
|
||||
msgid "Starting up torrent {0}"
|
||||
msgstr "Запускаем торрент: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:308
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:326
|
||||
#, java-format
|
||||
msgid "Torrent file deleted: {0}"
|
||||
msgstr "Удален торрент: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:332
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:342
|
||||
#, java-format
|
||||
msgid "Data file deleted: {0}"
|
||||
msgstr "Файл удален: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:334
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:344
|
||||
#, java-format
|
||||
msgid "Data file could not be deleted: {0}"
|
||||
msgstr "Не удалось удалить файл: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:353
|
||||
#, java-format
|
||||
msgid "Data dir deleted: {0}"
|
||||
msgstr "Директория удалена: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:384
|
||||
msgid "Error creating torrent - you must select a tracker"
|
||||
msgstr "Торрент не создан — вы должны указать трекер"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:399
|
||||
#, java-format
|
||||
msgid "Torrent created for \"{0}\""
|
||||
msgstr "Создан торрент для \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:402
|
||||
#, java-format
|
||||
msgid "Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\""
|
||||
msgstr "Многие I2P трекеры требуют зарегистрировать на них торрент перед началом раздачи — пожалуйста проверьте требуется ли это перед запуском \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:404
|
||||
#, java-format
|
||||
msgid "Error creating a torrent for \"{0}\""
|
||||
msgstr "Ошибка при создании торрента для: \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:407
|
||||
#, java-format
|
||||
msgid "Cannot create a torrent for the nonexistent data: {0}"
|
||||
msgstr "Невозможно создать торрент для несуществующего файла или директории: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:410
|
||||
msgid "Error creating torrent - you must enter a file or directory"
|
||||
msgstr "Торрент не создан — вы должны указать файл или директорию"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:413
|
||||
msgid "Stopping all torrents and closing the I2P tunnel."
|
||||
msgstr "Останавливаем все торренты и закрываем соединение с I2P"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:422
|
||||
msgid "I2P tunnel closed."
|
||||
msgstr "Соединение с I2P закрыто."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:425
|
||||
msgid "Opening the I2P tunnel and starting all torrents."
|
||||
msgstr "Соединяемся с I2P и запускаем все торренты."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:505
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:683
|
||||
msgid "Unknown"
|
||||
msgstr "Неизвестный"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:508
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:516
|
||||
msgid "TrackerErr"
|
||||
msgstr "ОшибкаТрекера"
|
||||
|
||||
# TODO should replace "uploader limit NN peers" with "global number of upload slots: NN"
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:510
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:522
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:524
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:531
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:533
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:537
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:539
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:875
|
||||
msgid "peers"
|
||||
msgstr "пир."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:520
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:524
|
||||
msgid "Seeding"
|
||||
msgstr "Раздается"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:526
|
||||
msgid "Complete"
|
||||
msgstr "Завершен"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:529
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:533
|
||||
msgid "OK"
|
||||
msgstr "Загружается"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:539
|
||||
msgid "Stalled"
|
||||
msgstr "Простаивает"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:541
|
||||
msgid "No Peers"
|
||||
msgstr "Нет Пиров"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:543
|
||||
msgid "Stopped"
|
||||
msgstr "Остановлен"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:556
|
||||
msgid "View files"
|
||||
msgstr "Открыть директорию"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:558
|
||||
msgid "Open file"
|
||||
msgstr "Открыть файл"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:582
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:794
|
||||
msgid "Tracker"
|
||||
msgstr "Трекер"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:583
|
||||
msgid "Details"
|
||||
msgstr "Подробнее"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:617
|
||||
msgid "Stop the torrent"
|
||||
msgstr "Остановить торрент"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:619
|
||||
msgid "Stop"
|
||||
msgstr "Остановить"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:625
|
||||
msgid "Start the torrent"
|
||||
msgstr "Запустить торрент"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:627
|
||||
msgid "Start"
|
||||
msgstr "Запустить"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:632
|
||||
msgid "Remove the torrent from the active list, deleting the .torrent file"
|
||||
msgstr "Удалить торрент из списка и с диска"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:637
|
||||
#, java-format
|
||||
msgid "Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?"
|
||||
msgstr "Вы действительно хотите удалить \\''{0}.torrent\\''? (загруженные файлы удаляться НЕ будут)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:639
|
||||
msgid "Remove"
|
||||
msgstr "Удалить"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:643
|
||||
msgid "Delete the .torrent file and the associated data file(s)"
|
||||
msgstr "Удалить торрент и стереть загруженные файлы"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:648
|
||||
#, java-format
|
||||
msgid "Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?"
|
||||
msgstr "Вы действительно хотите удалить торрент \\''{0}\\'' и все загруженные файлы?"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:650
|
||||
msgid "Delete"
|
||||
msgstr "Стереть"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:693
|
||||
msgid "Seed"
|
||||
msgstr "Сид"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:711
|
||||
msgid "Uninteresting (The peer has no pieces we need)"
|
||||
msgstr "Uninteresting (У пира нет нужных нам частей торрента)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:713
|
||||
msgid "Choked (The peer is not allowing us to request pieces)"
|
||||
msgstr "Choked (Этот пир не позволяет нам запрашивать части торрента)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:727
|
||||
msgid "Uninterested (We have no pieces the peer needs)"
|
||||
msgstr "Uninterested (У нас нужных этому пиру частей торрента)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:729
|
||||
msgid "Choking (We are not allowing the peer to request pieces)"
|
||||
msgstr "Choking (Мы не позволяем этому пиру запрашивать у нас части торрента)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:756
|
||||
msgid "Add Torrent"
|
||||
msgstr "Добавить Торрент"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:758
|
||||
msgid "From URL"
|
||||
msgstr "Из URL"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:763
|
||||
msgid "Add torrent"
|
||||
msgstr "Добавить торрент"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:766
|
||||
#, java-format
|
||||
msgid "Alternately, you can copy .torrent files to the directory {0}."
|
||||
msgstr "Ну или вы можете скопировать .torrent-файлы в директорию {0}."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:768
|
||||
msgid "Removing a .torrent file will cause the torrent to stop."
|
||||
msgstr "Удаление .torrent-файла приведет к остановке торрента."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:785
|
||||
msgid "Create Torrent"
|
||||
msgstr "Создать Торрент"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:788
|
||||
msgid "Data to seed"
|
||||
msgstr "Файлы для раздачи"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:792
|
||||
msgid "File or directory to seed (must be within the specified path)"
|
||||
msgstr "Файл или директория для раздачи (вводите только название файла или директории, указание абсолютных путей не поддерживается)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796
|
||||
msgid "Select a tracker"
|
||||
msgstr "Выбрать трекер"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:809
|
||||
msgid "or"
|
||||
msgstr "или"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:812
|
||||
msgid "Specify custom tracker announce URL"
|
||||
msgstr "Задать URL анонсера вручную"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:815
|
||||
msgid "Create torrent"
|
||||
msgstr "Создать торрент"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:833
|
||||
msgid "Configuration"
|
||||
msgstr "Настройки"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:836
|
||||
msgid "Data directory"
|
||||
msgstr "Директория для файлов"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:839
|
||||
msgid "Directory to store torrents and data"
|
||||
msgstr "Директория, где будут храниться торренты и загружаемые файлы"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:841
|
||||
msgid "Edit i2psnark.config and restart to change"
|
||||
msgstr "Для изменения отредактируйте файл i2psnark.config и перезагрузите I2PSnark"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:845
|
||||
msgid "Auto start"
|
||||
msgstr "Автозапуск"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:849
|
||||
msgid "If checked, automatically start torrents that are added"
|
||||
msgstr "Автоматически запускать торренты после добавления"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:872
|
||||
msgid "Total uploader limit"
|
||||
msgstr "Ограничение количества слотов отдачи"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879
|
||||
msgid "Up bandwidth limit"
|
||||
msgstr "Ограничение скорости отдачи"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:882
|
||||
msgid "Half available bandwidth recommended."
|
||||
msgstr "Рекомендуется использовать половину от доступной пропускной способности."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:884
|
||||
msgid "View or change router bandwidth"
|
||||
msgstr "Посмотреть/настроить ограничения скорости в маршрутизаторе I2P"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:888
|
||||
msgid "Use open trackers also"
|
||||
msgstr "Дополнительно использовать открытые трекеры"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:892
|
||||
msgid "If checked, announce torrents to open trackers as well as the tracker listed in the torrent file"
|
||||
msgstr "Анонсировать торренты на открытых трекерах, дополнительно к тем, что указаны внутри торрента"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:896
|
||||
msgid "Open tracker announce URLs"
|
||||
msgstr "URL открытых трекеров"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:907
|
||||
msgid "I2CP host"
|
||||
msgstr "Адрес I2CP"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:912
|
||||
msgid "I2CP port"
|
||||
msgstr "Порт I2CP"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:925
|
||||
msgid "I2CP options"
|
||||
msgstr "Параметры I2CP"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:930
|
||||
msgid "Save configuration"
|
||||
msgstr "Сохранить настройки"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:983
|
||||
#, java-format
|
||||
msgid "Torrent fetched from {0}"
|
||||
msgstr "Получен торрент из: {0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1011
|
||||
#, java-format
|
||||
msgid "Torrent at {0} was not valid"
|
||||
msgstr "Торрент полученный из {0} некорректен"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1016
|
||||
#, java-format
|
||||
msgid "Torrent was not retrieved from {0}"
|
||||
msgstr "Не удалось получить торрент из: {0}"
|
||||
|
675
apps/i2psnark/locale/messages_zh.po
Normal file
675
apps/i2psnark/locale/messages_zh.po
Normal file
@@ -0,0 +1,675 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the i2psnark package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
# foo <foo@bar>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P i2psnark\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2010-03-05 12:41+0000\n"
|
||||
"PO-Revision-Date: 2010-03-05 21:58+0800\n"
|
||||
"Last-Translator: walking <walking@mail.i2p>\n"
|
||||
"Language-Team: foo <foo@bar>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Poedit-Language: Chinese\n"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:84
|
||||
#, java-format
|
||||
msgid "Adding torrents in {0} minutes"
|
||||
msgstr "{0}分钟内完成添加"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:242
|
||||
#, java-format
|
||||
msgid "Total uploaders limit changed to {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:244
|
||||
#, java-format
|
||||
msgid "Minimum total uploaders limit is {0}"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:256
|
||||
#, java-format
|
||||
msgid "Up BW limit changed to {0}KBps"
|
||||
msgstr "上传带宽限制改为 {0} KBps"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:258
|
||||
#, java-format
|
||||
msgid "Minimum up bandwidth limit is {0}KBps"
|
||||
msgstr "最小上传带宽限制为 {0} KBps"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:302
|
||||
msgid "Cannot change the I2CP settings while torrents are active"
|
||||
msgstr "正在下载/上传,无法更改I2CP设置"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:308
|
||||
msgid "Disconnecting old I2CP destination"
|
||||
msgstr "正在断开旧的I2CP目标"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:312
|
||||
#, java-format
|
||||
msgid "I2CP settings changed to {0}"
|
||||
msgstr "I2CP设置改为{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:316
|
||||
msgid "Unable to connect with the new settings, reverting to the old I2CP settings"
|
||||
msgstr "无法通过新设置连接,恢复I2CP的旧设置"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:320
|
||||
msgid "Unable to reconnect with the old settings!"
|
||||
msgstr "旧设置也无法连接!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:322
|
||||
msgid "Reconnected on the new I2CP destination"
|
||||
msgstr "重新连接新I2CP目标"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:333
|
||||
#, java-format
|
||||
msgid "I2CP listener restarted for \"{0}\""
|
||||
msgstr "\"{0}\"的I2CP监听端口已启动"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:344
|
||||
msgid "Enabled autostart"
|
||||
msgstr "启用自动启动"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:346
|
||||
msgid "Disabled autostart"
|
||||
msgstr "禁用自动启动"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:352
|
||||
msgid "Enabled open trackers - torrent restart required to take effect."
|
||||
msgstr "启用OpenTracker-重新启动种子后生效"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:354
|
||||
msgid "Disabled open trackers - torrent restart required to take effect."
|
||||
msgstr "禁用OpenTracker - 重新启动种子后生效"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:361
|
||||
msgid "Open Tracker list changed - torrent restart required to take effect."
|
||||
msgstr "OpenTracker列表已改变 - 重新启动种子后生效"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:368
|
||||
msgid "Configuration unchanged."
|
||||
msgstr "设置未改变"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:378
|
||||
#, java-format
|
||||
msgid "Unable to save the config to {0}"
|
||||
msgstr "无法保存设置到{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:396
|
||||
msgid "Connecting to I2P"
|
||||
msgstr "正在连接到I2P"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:399
|
||||
msgid "Error connecting to I2P - check your I2CP settings!"
|
||||
msgstr "连接I2P时发生错误 - 请检查I2CP设置!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:408
|
||||
#, java-format
|
||||
msgid "Error: Could not add the torrent {0}"
|
||||
msgstr "错误:无法添加种子{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:430
|
||||
#, java-format
|
||||
msgid "Cannot open \"{0}\""
|
||||
msgstr "无法打开 \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:443
|
||||
#, java-format
|
||||
msgid "Warning - Ignoring non-i2p tracker in \"{0}\", will announce to i2p open trackers only"
|
||||
msgstr "警告 - 忽略\"{0}\"文件中I2P网络外的Tracker服务器,文件将仅发布至 I2P 内的 Open Tracker 服务器。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:445
|
||||
#, java-format
|
||||
msgid "Warning - Ignoring non-i2p tracker in \"{0}\", and open trackers are disabled, you must enable open trackers before starting the torrent!"
|
||||
msgstr "警告 - 忽略\"{0}\"文件中I2P网络外的Tracker服务器,OpenTracker已禁用,启动此种子前您必须启用OpenTracker。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:464
|
||||
#, java-format
|
||||
msgid "Torrent in \"{0}\" is invalid"
|
||||
msgstr "无效种子 \"{0}\" "
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:479
|
||||
#, java-format
|
||||
msgid "Torrent added and started: \"{0}\""
|
||||
msgstr "已添加并启动种子:\"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:481
|
||||
#, java-format
|
||||
msgid "Torrent added: \"{0}\""
|
||||
msgstr "已添加种子:\"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:578
|
||||
#, java-format
|
||||
msgid "Too many files in \"{0}\" ({1}), deleting it!"
|
||||
msgstr "\"{0}\" ({1}) 含有太多文件,删除之!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:580
|
||||
#, java-format
|
||||
msgid "Torrent file \"{0}\" cannot end in \".torrent\", deleting it!"
|
||||
msgstr "种子文件 \"{0}\" 不以 \".torrent\"结尾,正在删除!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:582
|
||||
#, java-format
|
||||
msgid "No pieces in \"{0}\", deleting it!"
|
||||
msgstr "\"{0}\" 中没有数据片,删除之!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:584
|
||||
#, java-format
|
||||
msgid "Too many pieces in \"{0}\", limit is {1}, deleting it!"
|
||||
msgstr "\"{0}\" 中文件分片太多,限额为{1},删除之!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:586
|
||||
#, java-format
|
||||
msgid "Pieces are too large in \"{0}\" ({1}B), deleting it."
|
||||
msgstr "\"{0}\" ({1}B) 中文件分片过大,删除之。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:587
|
||||
#, java-format
|
||||
msgid "Limit is {0}B"
|
||||
msgstr "限额为 {0}B"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:595
|
||||
#, java-format
|
||||
msgid "Torrents larger than {0}B are not supported yet, deleting \"{1}\""
|
||||
msgstr "目前不支持大于{0}B 的种子,正在删除\"{1}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:611
|
||||
#, java-format
|
||||
msgid "Error: Could not remove the torrent {0}"
|
||||
msgstr "错误:无法删除种子{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:632
|
||||
#, java-format
|
||||
msgid "Torrent stopped: \"{0}\""
|
||||
msgstr "种子已停止:\"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:647
|
||||
#, java-format
|
||||
msgid "Torrent removed: \"{0}\""
|
||||
msgstr "种子已删除:\"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:680
|
||||
#, java-format
|
||||
msgid "Download finished: \"{0}\""
|
||||
msgstr "下载已完成:\"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:680
|
||||
#, java-format
|
||||
msgid "size: {0}B"
|
||||
msgstr "大小:{0}B"
|
||||
|
||||
#: ../java/src/org/klomp/snark/SnarkManager.java:708
|
||||
msgid "Unable to connect to I2P!"
|
||||
msgstr "无法连接至I2P!"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:86
|
||||
msgid "I2PSnark - Anonymous BitTorrent Client"
|
||||
msgstr "I2PSnark - 匿名BitTorrent客户端"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:95
|
||||
msgid "Refresh page"
|
||||
msgstr "刷新页面"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:97
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:669
|
||||
msgid "I2PSnark"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:99
|
||||
msgid "Forum"
|
||||
msgstr "论坛"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:125
|
||||
msgid "Status"
|
||||
msgstr "状态"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:131
|
||||
msgid "Hide Peers"
|
||||
msgstr "隐藏用户"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:134
|
||||
msgid "Show Peers"
|
||||
msgstr "显示用户"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:139
|
||||
msgid "Torrent"
|
||||
msgstr "种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:141
|
||||
msgid "ETA"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:143
|
||||
msgid "Downloaded"
|
||||
msgstr "已下载"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:145
|
||||
msgid "Uploaded"
|
||||
msgstr "已上传"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:147
|
||||
msgid "Down Rate"
|
||||
msgstr "下载速度"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:149
|
||||
msgid "Up Rate"
|
||||
msgstr "上传速度"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:156
|
||||
msgid "Stop all torrents and the I2P tunnel"
|
||||
msgstr "停止全部种子及I2P隧道"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:158
|
||||
msgid "Stop All"
|
||||
msgstr "停止全部"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:163
|
||||
msgid "Start all torrents and the I2P tunnel"
|
||||
msgstr "启动全部种子及I2P隧道"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:165
|
||||
msgid "Start All"
|
||||
msgstr "启动全部"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:182
|
||||
msgid "No torrents loaded."
|
||||
msgstr "未载入任何种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:187
|
||||
msgid "Totals"
|
||||
msgstr "总计"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:189
|
||||
#, java-format
|
||||
msgid "{0} torrents"
|
||||
msgstr "{0} 个种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:192
|
||||
#, java-format
|
||||
msgid "{0} connected peers"
|
||||
msgstr "{0} 已连接用户"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:227
|
||||
#, java-format
|
||||
msgid "Torrent file {0} does not exist"
|
||||
msgstr "种子文件{0}不存在"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:237
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1003
|
||||
#, java-format
|
||||
msgid "Torrent already running: {0}"
|
||||
msgstr "种子已启动:{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:239
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1005
|
||||
#, java-format
|
||||
msgid "Torrent already in the queue: {0}"
|
||||
msgstr "种子排队中:{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:243
|
||||
#, java-format
|
||||
msgid "Copying torrent to {0}"
|
||||
msgstr "正在复制种子到{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246
|
||||
#, java-format
|
||||
msgid "Unable to copy the torrent to {0}"
|
||||
msgstr "无法复制种子文件到{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:246
|
||||
#, java-format
|
||||
msgid "from {0}"
|
||||
msgstr "来源{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:254
|
||||
#, java-format
|
||||
msgid "Fetching {0}"
|
||||
msgstr "正在获取{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:258
|
||||
msgid "Invalid URL - must start with http://"
|
||||
msgstr "无效链接 - 必须以http:// 开头"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:288
|
||||
#, java-format
|
||||
msgid "Starting up torrent {0}"
|
||||
msgstr "正在启动种子{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:308
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:326
|
||||
#, java-format
|
||||
msgid "Torrent file deleted: {0}"
|
||||
msgstr "种子文件已删除:{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:332
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:342
|
||||
#, java-format
|
||||
msgid "Data file deleted: {0}"
|
||||
msgstr "数据文件已删除:{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:334
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:344
|
||||
#, java-format
|
||||
msgid "Data file could not be deleted: {0}"
|
||||
msgstr "无法删除数据文件:{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:353
|
||||
#, java-format
|
||||
msgid "Data dir deleted: {0}"
|
||||
msgstr "数据文件夹已删除:{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:384
|
||||
msgid "Error creating torrent - you must select a tracker"
|
||||
msgstr "创建种子时发生错误 - 您必须选择一个Tracker"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:399
|
||||
#, java-format
|
||||
msgid "Torrent created for \"{0}\""
|
||||
msgstr "种子创建成功\"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:402
|
||||
#, java-format
|
||||
msgid "Many I2P trackers require you to register new torrents before seeding - please do so before starting \"{0}\""
|
||||
msgstr "多数I2PTracker需要用户在做种前注册新种子 - 请在启动 \"{0}\"前到所使用的Tracker进行注册。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:404
|
||||
#, java-format
|
||||
msgid "Error creating a torrent for \"{0}\""
|
||||
msgstr "创建种子时发生错误 \"{0}\""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:407
|
||||
#, java-format
|
||||
msgid "Cannot create a torrent for the nonexistent data: {0}"
|
||||
msgstr "无法为不存在的数据文件创建种子:{0}"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:410
|
||||
msgid "Error creating torrent - you must enter a file or directory"
|
||||
msgstr "创建种子时发生错误 - 必须指定文件或文件夹"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:413
|
||||
msgid "Stopping all torrents and closing the I2P tunnel."
|
||||
msgstr "正在停用所有种子并关闭I2P隧道。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:422
|
||||
msgid "I2P tunnel closed."
|
||||
msgstr "I2P隧道已关闭"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:425
|
||||
msgid "Opening the I2P tunnel and starting all torrents."
|
||||
msgstr "正在打开I2P隧道并启动所有种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:505
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:683
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:508
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:516
|
||||
msgid "TrackerErr"
|
||||
msgstr "Tracker错误"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:510
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:512
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:522
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:524
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:531
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:533
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:537
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:539
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:875
|
||||
msgid "peers"
|
||||
msgstr "用户"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:520
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:524
|
||||
msgid "Seeding"
|
||||
msgstr "正做种"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:526
|
||||
msgid "Complete"
|
||||
msgstr "完成"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:529
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:533
|
||||
msgid "OK"
|
||||
msgstr "确定"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:535
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:539
|
||||
msgid "Stalled"
|
||||
msgstr "等待"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:541
|
||||
msgid "No Peers"
|
||||
msgstr "没有用户"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:543
|
||||
msgid "Stopped"
|
||||
msgstr "已停用"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:556
|
||||
msgid "View files"
|
||||
msgstr "浏览文件"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:558
|
||||
msgid "Open file"
|
||||
msgstr "打开文件"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:582
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:794
|
||||
msgid "Tracker"
|
||||
msgstr "Tracker服务器"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:583
|
||||
msgid "Details"
|
||||
msgstr "详情"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:617
|
||||
msgid "Stop the torrent"
|
||||
msgstr "停止种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:619
|
||||
msgid "Stop"
|
||||
msgstr "停止"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:625
|
||||
msgid "Start the torrent"
|
||||
msgstr "启动种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:627
|
||||
msgid "Start"
|
||||
msgstr "启动"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:632
|
||||
msgid "Remove the torrent from the active list, deleting the .torrent file"
|
||||
msgstr "取消下载任务并删除对应种子文件。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:637
|
||||
#, java-format
|
||||
msgid "Are you sure you want to delete the file \\''{0}.torrent\\'' (downloaded data will not be deleted) ?"
|
||||
msgstr "您确定要删除文件“{0}.torrent”(下载的数据文件不会被删除)?"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:639
|
||||
msgid "Remove"
|
||||
msgstr "移除"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:643
|
||||
msgid "Delete the .torrent file and the associated data file(s)"
|
||||
msgstr "删除种子及所下载的文件"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:648
|
||||
#, java-format
|
||||
msgid "Are you sure you want to delete the torrent \\''{0}\\'' and all downloaded data?"
|
||||
msgstr "您确定要删除种子“{0}”(下载的数据文件会一并被删除)?"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:650
|
||||
msgid "Delete"
|
||||
msgstr "删除"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:693
|
||||
msgid "Seed"
|
||||
msgstr "种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:711
|
||||
msgid "Uninteresting (The peer has no pieces we need)"
|
||||
msgstr "无需要部分"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:713
|
||||
msgid "Choked (The peer is not allowing us to request pieces)"
|
||||
msgstr "拒绝请求"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:727
|
||||
msgid "Uninterested (We have no pieces the peer needs)"
|
||||
msgstr "无需要部分"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:729
|
||||
msgid "Choking (We are not allowing the peer to request pieces)"
|
||||
msgstr "拒绝请求"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:756
|
||||
msgid "Add Torrent"
|
||||
msgstr "添加种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:758
|
||||
msgid "From URL"
|
||||
msgstr "从URL"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:763
|
||||
msgid "Add torrent"
|
||||
msgstr "添加种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:766
|
||||
#, java-format
|
||||
msgid "Alternately, you can copy .torrent files to the directory {0}."
|
||||
msgstr "或者您可以将.torrent文件复制到以下目录{0}."
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:768
|
||||
msgid "Removing a .torrent file will cause the torrent to stop."
|
||||
msgstr "删除种子文件将导致中止该下载任务。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:785
|
||||
msgid "Create Torrent"
|
||||
msgstr "创建种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:788
|
||||
msgid "Data to seed"
|
||||
msgstr "做种数据"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:792
|
||||
msgid "File or directory to seed (must be within the specified path)"
|
||||
msgstr "做种文件或文件夹(必须下面为Snark指定的文件夹中)"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:796
|
||||
msgid "Select a tracker"
|
||||
msgstr "选择一个Tracker"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:809
|
||||
msgid "or"
|
||||
msgstr "或"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:812
|
||||
msgid "Specify custom tracker announce URL"
|
||||
msgstr "指定Open Tracker发布链接"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:815
|
||||
msgid "Create torrent"
|
||||
msgstr "创建种子"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:833
|
||||
msgid "Configuration"
|
||||
msgstr "设置"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:836
|
||||
msgid "Data directory"
|
||||
msgstr "数据文件夹"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:839
|
||||
msgid "Directory to store torrents and data"
|
||||
msgstr "种子及被做种文件的保存位置。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:841
|
||||
msgid "Edit i2psnark.config and restart to change"
|
||||
msgstr "编辑 i2psnark.config 并重启Snark后生效"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:845
|
||||
msgid "Auto start"
|
||||
msgstr "自动启动"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:849
|
||||
msgid "If checked, automatically start torrents that are added"
|
||||
msgstr "选中后Snark将自动启动已添加的所有种子。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:872
|
||||
msgid "Total uploader limit"
|
||||
msgstr ""
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:879
|
||||
msgid "Up bandwidth limit"
|
||||
msgstr "上传带宽限制"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:882
|
||||
msgid "Half available bandwidth recommended."
|
||||
msgstr "推荐设置为可用带宽的一半。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:884
|
||||
msgid "View or change router bandwidth"
|
||||
msgstr "浏览或修改路由器带宽"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:888
|
||||
msgid "Use open trackers also"
|
||||
msgstr "同时使用OpenTracker"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:892
|
||||
msgid "If checked, announce torrents to open trackers as well as the tracker listed in the torrent file"
|
||||
msgstr "选择后在OpenTracker及种子文件中的Tracker上同时发布。"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:896
|
||||
msgid "Open tracker announce URLs"
|
||||
msgstr "Open Tracker发布链接"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:907
|
||||
msgid "I2CP host"
|
||||
msgstr "I2CP主机"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:912
|
||||
msgid "I2CP port"
|
||||
msgstr "I2CP端口"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:925
|
||||
msgid "I2CP options"
|
||||
msgstr "I2CP选项"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:930
|
||||
msgid "Save configuration"
|
||||
msgstr "保存设置"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:983
|
||||
#, java-format
|
||||
msgid "Torrent fetched from {0}"
|
||||
msgstr "从{0}获取种子成功"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1011
|
||||
#, java-format
|
||||
msgid "Torrent at {0} was not valid"
|
||||
msgstr "{0}的种子中有错误"
|
||||
|
||||
#: ../java/src/org/klomp/snark/web/I2PSnarkServlet.java:1016
|
||||
#, java-format
|
||||
msgid "Torrent was not retrieved from {0}"
|
||||
msgstr "从{0}获得种子失败"
|
||||
|
||||
#~ msgid "Non-i2p tracker in \"{0}\", deleting it from our list of trackers!"
|
||||
#~ msgstr ""
|
||||
#~ "【匿名性警告】\"{0}\" 中含有非I2P Tracker,程序将从Tracker列表中将其删除。"
|
||||
#~ msgid "Custom tracker URL"
|
||||
#~ msgstr "自定义TrackerURL"
|
||||
#~ msgid "Configure"
|
||||
#~ msgstr "设置"
|
||||
|
@@ -1,6 +1,6 @@
|
||||
To run I2PSnark from the command line, run "java -jar lib/i2psnark.jar", but
|
||||
to run it with the web UI, run "java -jar launch-i2psnark.jar". I2PSnark is
|
||||
to run it with the web UI, run "launch-i2psnark". I2PSnark is
|
||||
GPL'ed software, based on Snark (http://www.klomp.org/) to run on top of I2P
|
||||
(http://www.i2p.net/) within a webserver (such as the bundled Jetty from
|
||||
(http://www.i2p2.de/) within a webserver (such as the bundled Jetty from
|
||||
http://jetty.mortbay.org/). For more information about I2PSnark, get in touch
|
||||
with the folks at http://forum.i2p.net/
|
||||
with the folks at http://forum.i2p2.de/
|
||||
|
17
apps/i2ptunnel/java/bmsg.sh
Normal file
17
apps/i2ptunnel/java/bmsg.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#
|
||||
# Update messages_xx.po and messages_xx.class files,
|
||||
# from both java and jsp sources.
|
||||
# Requires installed programs xgettext, msgfmt, msgmerge, and find.
|
||||
# zzz - public domain
|
||||
#
|
||||
|
||||
## launching sh.exe with -login parameter will open a shell with the current path always pointing to \bin\
|
||||
## need to cd into our orignal path - where we call sh.exe from.
|
||||
|
||||
cd $CALLFROM
|
||||
## echo $PWD
|
||||
|
||||
## except this everything is the same with bundle-message.sh
|
||||
## walking - public domain :-D
|
||||
|
||||
source bundle-messages.sh $PARAS
|
@@ -41,13 +41,48 @@
|
||||
<attribute name="Class-Path" value="i2p.jar mstreaming.jar" />
|
||||
</manifest>
|
||||
</jar>
|
||||
<ant target="bundle" />
|
||||
<ant target="war" />
|
||||
</target>
|
||||
|
||||
<target name="bundle" depends="compile, precompilejsp">
|
||||
<!-- Update the messages_*.po files.
|
||||
We need to supply the bat file for windows, and then change the fail property to true -->
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="false" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="false" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<exec executable="cmd" osfamily="windows" failifexecutionfails="false" >
|
||||
<arg value="/c" />
|
||||
<arg value="bundle-messages.bat" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="poupdate" depends="compile, precompilejsp">
|
||||
<!-- Update the messages_*.po files. -->
|
||||
<exec executable="sh" osfamily="unix" failifexecutionfails="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
<exec executable="sh" osfamily="mac" failifexecutionfails="true" >
|
||||
<arg value="./bundle-messages.sh" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
<exec executable="cmd" osfamily="windows" failifexecutionfails="true" >
|
||||
<arg value="/c" />
|
||||
<arg value="bundle-messages.bat" />
|
||||
<arg value="-p" />
|
||||
</exec>
|
||||
</target>
|
||||
|
||||
<target name="war" depends="precompilejsp">
|
||||
<war destfile="build/i2ptunnel.war" webxml="../jsp/web-out.xml"
|
||||
basedir="../jsp/" excludes="web.xml, **/*.java, *.jsp">
|
||||
</war>
|
||||
</target>
|
||||
|
||||
<target name="precompilejsp" unless="precompilejsp.uptodate">
|
||||
<delete dir="../jsp/WEB-INF/" />
|
||||
<delete file="../jsp/web-fragment.xml" />
|
||||
@@ -113,11 +148,7 @@
|
||||
<delete file="../jsp/web-out.xml" />
|
||||
</target>
|
||||
<target name="cleandep" depends="clean">
|
||||
<!-- ministreaming will clean core -->
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
<target name="distclean" depends="clean">
|
||||
<!-- ministreaming will clean core -->
|
||||
<ant dir="../../ministreaming/java/" target="distclean" />
|
||||
</target>
|
||||
</project>
|
||||
|
26
apps/i2ptunnel/java/bundle-messages.bat
Normal file
26
apps/i2ptunnel/java/bundle-messages.bat
Normal file
@@ -0,0 +1,26 @@
|
||||
@echo off
|
||||
set Callfrom=%cd%
|
||||
set Paras=%1
|
||||
|
||||
rem before calling make sure you have msys and mingw 's "bin" path
|
||||
rem in your current searching path
|
||||
rem type "set path" to check
|
||||
if not exist ..\locale\*.only goto updateALL
|
||||
|
||||
rem put a messages_xx.only(eg messages_zh.only) into locale folder
|
||||
rem this script will only touch the po file(eg zh) you specified, leaving other po files untact.
|
||||
|
||||
for %%i in (..\locale\*.only) do set PO=%%~ni
|
||||
echo [Notice] Yu choose to Ony update the choosen file: %PO%.po
|
||||
for %%i in (..\locale\*.po) do if not %%~ni==%PO% ren %%i %%~ni.po-
|
||||
|
||||
call sh --login %cd%\bmsg.sh
|
||||
|
||||
for %%i in (..\locale\*.po-) do if not %%~ni==%PO% ren %%i %%~ni.po
|
||||
goto end
|
||||
|
||||
:updateALL
|
||||
call sh --login %cd%\bmsg.sh
|
||||
|
||||
:end
|
||||
echo End of Message Bundling
|
87
apps/i2ptunnel/java/bundle-messages.sh
Executable file
87
apps/i2ptunnel/java/bundle-messages.sh
Executable file
@@ -0,0 +1,87 @@
|
||||
#
|
||||
# Update messages_xx.po and messages_xx.class files,
|
||||
# from both java and jsp sources.
|
||||
# Requires installed programs xgettext, msgfmt, msgmerge, and find.
|
||||
#
|
||||
# usage:
|
||||
# bundle-messages.sh (generates the resource bundle from the .po file)
|
||||
# bundle-messages.sh -p (updates the .po file from the source tags, then generates the resource bundle)
|
||||
#
|
||||
# zzz - public domain
|
||||
#
|
||||
CLASS=net.i2p.i2ptunnel.web.messages
|
||||
TMPFILE=build/javafiles.txt
|
||||
export TZ=UTC
|
||||
|
||||
if [ "$1" = "-p" ]
|
||||
then
|
||||
POUPDATE=1
|
||||
fi
|
||||
|
||||
# add ../java/ so the refs will work in the po file
|
||||
JPATHS="../java/src ../jsp/WEB-INF"
|
||||
for i in ../locale/messages_*.po
|
||||
do
|
||||
# get language
|
||||
LG=${i#../locale/messages_}
|
||||
LG=${LG%.po}
|
||||
|
||||
if [ "$POUPDATE" = "1" ]
|
||||
then
|
||||
# make list of java files newer than the .po file
|
||||
find $JPATHS -name *.java -newer $i > $TMPFILE
|
||||
fi
|
||||
if [ -s ../jsp/WEB-INF/classes/net/i2p/i2ptunnel/web/messages_$LG.class -a \
|
||||
../jsp/WEB-INF/classes/net/i2p/i2ptunnel/web/messages_$LG.class -nt $i -a \
|
||||
! -s $TMPFILE ]
|
||||
then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [ "$POUPDATE" = "1" ]
|
||||
then
|
||||
echo "Updating the $i file from the tags..."
|
||||
# extract strings from java and jsp files, and update messages.po files
|
||||
# translate calls must be one of the forms:
|
||||
# _("foo")
|
||||
# _x("foo")
|
||||
# intl._("foo")
|
||||
# intl.title("foo")
|
||||
# In a jsp, you must use a helper or handler that has the context set.
|
||||
# To start a new translation, copy the header from an old translation to the new .po file,
|
||||
# then ant distclean updater.
|
||||
find $JPATHS -name *.java > $TMPFILE
|
||||
xgettext -f $TMPFILE -F -L java --from-code=UTF-8 \
|
||||
--keyword=_ --keyword=_x --keyword=intl._ --keyword=intl.title \
|
||||
-o ${i}t
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - xgettext failed, not updating translations'
|
||||
rm -f ${i}t
|
||||
break
|
||||
fi
|
||||
msgmerge -U --backup=none $i ${i}t
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - msgmerge failed, not updating translations'
|
||||
rm -f ${i}t
|
||||
break
|
||||
fi
|
||||
rm -f ${i}t
|
||||
# so we don't do this again
|
||||
touch $i
|
||||
fi
|
||||
|
||||
echo "Generating ${CLASS}_$LG ResourceBundle..."
|
||||
|
||||
# convert to class files in build/obj
|
||||
msgfmt --java --statistics -r $CLASS -l $LG -d ../jsp/WEB-INF/classes $i
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo 'Warning - msgfmt failed, not updating translations'
|
||||
break
|
||||
fi
|
||||
done
|
||||
rm -f $TMPFILE
|
||||
# todo: return failure
|
||||
exit 0
|
@@ -1,72 +0,0 @@
|
||||
/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
|
||||
* (c) 2003 - 2004 mihi
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* Read what i2ptunnel logs, and expose it in a buffer
|
||||
*
|
||||
*/
|
||||
class BufferLogger implements Logging {
|
||||
private final static Log _log = new Log(BufferLogger.class);
|
||||
private ByteArrayOutputStream _baos; // should be final and use a factory. LINT
|
||||
private boolean _ignore;
|
||||
|
||||
/**
|
||||
* Constructs a buffered logger.
|
||||
*/
|
||||
public BufferLogger() {
|
||||
_baos = new ByteArrayOutputStream(512);
|
||||
_ignore = false;
|
||||
}
|
||||
|
||||
private final static String EMPTY = "";
|
||||
|
||||
/**
|
||||
* Retrieves the buffer
|
||||
* @return the buffer
|
||||
*/
|
||||
public String getBuffer() {
|
||||
if (_ignore)
|
||||
return EMPTY;
|
||||
|
||||
return new String(_baos.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* We don't care about anything else the logger receives. This is useful
|
||||
* for loggers passed in to servers and clients, since they will continue
|
||||
* to add info to the logger, but if we're instantiated by the tunnel manager,
|
||||
* its likely we only care about the first few messages it sends us.
|
||||
*
|
||||
*/
|
||||
public void ignoreFurtherActions() {
|
||||
_ignore = true;
|
||||
synchronized (_baos) {
|
||||
_baos.reset();
|
||||
}
|
||||
_baos = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass in some random data
|
||||
* @param s String containing what we're logging.
|
||||
*/
|
||||
public void log(String s) {
|
||||
if (_ignore) return;
|
||||
if (s != null) {
|
||||
_log.debug("logging [" + s + "]");
|
||||
try {
|
||||
_baos.write(s.getBytes());
|
||||
_baos.write('\n');
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Error logging [" + s + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -20,7 +20,7 @@ import java.util.zip.GZIPInputStream;
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.ByteArray;
|
||||
import net.i2p.util.ByteCache;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
@@ -219,7 +219,7 @@ class HTTPResponseOutputStream extends FilterOutputStream {
|
||||
//out.flush();
|
||||
PipedInputStream pi = new PipedInputStream();
|
||||
PipedOutputStream po = new PipedOutputStream(pi);
|
||||
new I2PThread(new Pusher(pi, out), "HTTP decompresser").start();
|
||||
new I2PAppThread(new Pusher(pi, out), "HTTP decompresser").start();
|
||||
out = po;
|
||||
}
|
||||
|
||||
|
@@ -61,6 +61,7 @@ import net.i2p.data.Base64;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.i2ptunnel.socks.I2PSOCKSIRCTunnel;
|
||||
import net.i2p.i2ptunnel.socks.I2PSOCKSTunnel;
|
||||
import net.i2p.i2ptunnel.streamr.StreamrConsumer;
|
||||
import net.i2p.i2ptunnel.streamr.StreamrProducer;
|
||||
@@ -236,6 +237,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
runServer(args, l);
|
||||
} else if ("httpserver".equals(cmdname)) {
|
||||
runHttpServer(args, l);
|
||||
} else if ("httpbidirserver".equals(cmdname)) {
|
||||
runHttpBidirServer(args, l);
|
||||
} else if ("ircserver".equals(cmdname)) {
|
||||
runIrcServer(args, l);
|
||||
} else if ("textserver".equals(cmdname)) {
|
||||
@@ -300,6 +303,7 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
l.log("ping <args>");
|
||||
l.log("server <host> <port> <privkeyfile>");
|
||||
l.log("httpserver <host> <port> <spoofedhost> <privkeyfile>");
|
||||
l.log("httpbidirserver <host> <port> <proxyport> <spoofedhost> <privkeyfile>");
|
||||
l.log("textserver <host> <port> <privkey>");
|
||||
l.log("genkeys <privkeyfile> [<pubkeyfile>]");
|
||||
l.log("gentextkeys");
|
||||
@@ -372,6 +376,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
}
|
||||
|
||||
privKeyFile = new File(args[2]);
|
||||
if (!privKeyFile.isAbsolute())
|
||||
privKeyFile = new File(_context.getConfigDir(), args[2]);
|
||||
if (!privKeyFile.canRead()) {
|
||||
l.log("private key file does not exist");
|
||||
_log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[2]);
|
||||
@@ -419,6 +425,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
}
|
||||
|
||||
privKeyFile = new File(args[2]);
|
||||
if (!privKeyFile.isAbsolute())
|
||||
privKeyFile = new File(_context.getConfigDir(), args[2]);
|
||||
if (!privKeyFile.canRead()) {
|
||||
l.log("private key file does not exist");
|
||||
_log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[2]);
|
||||
@@ -476,6 +484,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
String spoofedHost = args[2];
|
||||
|
||||
privKeyFile = new File(args[3]);
|
||||
if (!privKeyFile.isAbsolute())
|
||||
privKeyFile = new File(_context.getConfigDir(), args[3]);
|
||||
if (!privKeyFile.canRead()) {
|
||||
l.log("private key file does not exist");
|
||||
_log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[3]);
|
||||
@@ -497,6 +507,80 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the HTTP server pointing at the host and port specified using the private i2p
|
||||
* destination loaded from the specified file, replacing the HTTP headers
|
||||
* so that the Host: specified is the one spoofed. Also runs an HTTP proxy for
|
||||
* bidirectional communications on the same tunnel destination.<p />
|
||||
*
|
||||
* Sets the event "serverTaskId" = Integer(taskId) after the tunnel has been started (or -1 on error)
|
||||
* Also sets the event "openServerResult" = "ok" or "error" (displaying "Ready!" on the logger after
|
||||
* 'ok'). So, success = serverTaskId != -1 and openServerResult = ok.
|
||||
*
|
||||
* @param args {hostname, portNumber, proxyPortNumber, spoofedHost, privKeyFilename}
|
||||
* @param l logger to receive events and output
|
||||
*/
|
||||
public void runHttpBidirServer(String args[], Logging l) {
|
||||
if (args.length == 5) {
|
||||
InetAddress serverHost = null;
|
||||
int portNum = -1;
|
||||
int port2Num = -1;
|
||||
File privKeyFile = null;
|
||||
try {
|
||||
serverHost = InetAddress.getByName(args[0]);
|
||||
} catch (UnknownHostException uhe) {
|
||||
l.log("unknown host");
|
||||
_log.error(getPrefix() + "Error resolving " + args[0], uhe);
|
||||
notifyEvent("serverTaskId", Integer.valueOf(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
portNum = Integer.parseInt(args[1]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[1], nfe);
|
||||
notifyEvent("serverTaskId", Integer.valueOf(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
port2Num = Integer.parseInt(args[2]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[2], nfe);
|
||||
notifyEvent("serverTaskId", Integer.valueOf(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
String spoofedHost = args[3];
|
||||
|
||||
privKeyFile = new File(args[4]);
|
||||
if (!privKeyFile.isAbsolute())
|
||||
privKeyFile = new File(_context.getConfigDir(), args[4]);
|
||||
if (!privKeyFile.canRead()) {
|
||||
l.log("private key file does not exist");
|
||||
_log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[4]);
|
||||
notifyEvent("serverTaskId", Integer.valueOf(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
I2PTunnelHTTPBidirServer serv = new I2PTunnelHTTPBidirServer(serverHost, portNum, port2Num, privKeyFile, args[3], spoofedHost, l, (EventDispatcher) this, this);
|
||||
serv.setReadTimeout(readTimeout);
|
||||
serv.startRunning();
|
||||
addtask(serv);
|
||||
notifyEvent("serverTaskId", Integer.valueOf(serv.getId()));
|
||||
return;
|
||||
} else {
|
||||
l.log("httpserver <host> <port> <proxyport> <spoofedhost> <privkeyfile>");
|
||||
l.log(" creates a bidirectional HTTP server that sends all incoming data\n"
|
||||
+ " of its destination to host:port., filtering the HTTP\n"
|
||||
+ " headers so it looks like the request is to the spoofed host,"
|
||||
+ " and listens to host:proxyport to proxy HTTP requests.");
|
||||
notifyEvent("serverTaskId", Integer.valueOf(-1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the server pointing at the host and port specified using the private i2p
|
||||
* destination loaded from the given base64 stream. <p />
|
||||
@@ -812,6 +896,39 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run an SOCKS IRC tunnel on the given port number
|
||||
* @since 0.7.12
|
||||
*/
|
||||
public void runSOCKSIRCTunnel(String args[], Logging l) {
|
||||
if (args.length >= 1 && args.length <= 2) {
|
||||
int _port = -1;
|
||||
try {
|
||||
_port = Integer.parseInt(args[0]);
|
||||
} catch (NumberFormatException nfe) {
|
||||
l.log("invalid port");
|
||||
_log.error(getPrefix() + "Port specified is not valid: " + args[0], nfe);
|
||||
notifyEvent("sockstunnelTaskId", Integer.valueOf(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isShared = false;
|
||||
if (args.length > 1)
|
||||
isShared = "true".equalsIgnoreCase(args[1].trim());
|
||||
|
||||
ownDest = !isShared;
|
||||
I2PTunnelTask task;
|
||||
task = new I2PSOCKSIRCTunnel(_port, l, ownDest, (EventDispatcher) this, this);
|
||||
addtask(task);
|
||||
notifyEvent("sockstunnelTaskId", Integer.valueOf(task.getId()));
|
||||
} else {
|
||||
l.log("sockstunnel <port>");
|
||||
l.log(" creates a tunnel that distributes SOCKS requests.");
|
||||
notifyEvent("sockstunnelTaskId", Integer.valueOf(-1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Streamr client
|
||||
*
|
||||
@@ -870,6 +987,8 @@ public class I2PTunnel implements Logging, EventDispatcher {
|
||||
}
|
||||
|
||||
File privKeyFile = new File(args[1]);
|
||||
if (!privKeyFile.isAbsolute())
|
||||
privKeyFile = new File(_context.getConfigDir(), args[1]);
|
||||
if (!privKeyFile.canRead()) {
|
||||
l.log("private key file does not exist");
|
||||
_log.error(getPrefix() + "Private key file does not exist or is not readable: " + args[3]);
|
||||
|
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
@@ -26,7 +27,7 @@ import net.i2p.client.streaming.I2PSocketManagerFactory;
|
||||
import net.i2p.client.streaming.I2PSocketOptions;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.SimpleScheduler;
|
||||
import net.i2p.util.SimpleTimer;
|
||||
@@ -66,7 +67,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
// private Object conLock = new Object();
|
||||
|
||||
/** List of Socket for those accept()ed but not yet started up */
|
||||
private List _waitingSockets = new ArrayList(); // should be final and use a factory. LINT
|
||||
protected final List _waitingSockets = new ArrayList(4); // FIXME should be final and use a factory. FIXME
|
||||
/** How many connections will we allow to be in the process of being built at once? */
|
||||
private int _numConnectionBuilders;
|
||||
/** How long will we allow sockets to sit in the _waitingSockets map before killing them? */
|
||||
@@ -88,12 +89,52 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
|
||||
private static final int DEFAULT_NUM_CONNECTION_BUILDERS = 5;
|
||||
private static final int DEFAULT_MAX_WAIT_TIME = 30*1000;
|
||||
|
||||
//public I2PTunnelClientBase(int localPort, boolean ownDest,
|
||||
// Logging l) {
|
||||
// I2PTunnelClientBase(localPort, ownDest, l, (EventDispatcher)null);
|
||||
//}
|
||||
|
||||
// true if we are chained from a server.
|
||||
private boolean chained = false;
|
||||
|
||||
public I2PTunnelClientBase(int localPort, Logging l, I2PSocketManager sktMgr,
|
||||
I2PTunnel tunnel, EventDispatcher notifyThis, long clientId )
|
||||
throws IllegalArgumentException {
|
||||
super(localPort + " (uninitialized)", notifyThis, tunnel);
|
||||
chained = true;
|
||||
sockMgr = sktMgr;
|
||||
_clientId = clientId;
|
||||
this.localPort = localPort;
|
||||
this.l = l;
|
||||
this.handlerName = handlerName + _clientId;
|
||||
_ownDest = true; // == ! shared client
|
||||
_context = tunnel.getContext();
|
||||
_context.statManager().createRateStat("i2ptunnel.client.closeBacklog", "How many pending sockets remain when we close one due to backlog?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.closeNoBacklog", "How many pending sockets remain when it was removed prior to backlog timeout?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
|
||||
Thread t = new I2PAppThread(this);
|
||||
t.setName("Client " + _clientId);
|
||||
listenerReady = false;
|
||||
t.start();
|
||||
open = true;
|
||||
synchronized (this) {
|
||||
while (!listenerReady && open) {
|
||||
try {
|
||||
wait();
|
||||
} catch (InterruptedException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurePool(tunnel);
|
||||
|
||||
if (open && listenerReady) {
|
||||
l.log("Ready! Port " + getLocalPort());
|
||||
notifyEvent("openBaseClientResult", "ok");
|
||||
} else {
|
||||
l.log("Error listening - please see the logs!");
|
||||
notifyEvent("openBaseClientResult", "error");
|
||||
}
|
||||
}
|
||||
public I2PTunnelClientBase(int localPort, boolean ownDest, Logging l,
|
||||
EventDispatcher notifyThis, String handlerName,
|
||||
I2PTunnel tunnel) throws IllegalArgumentException {
|
||||
@@ -114,7 +155,6 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
this.localPort = localPort;
|
||||
this.l = l;
|
||||
this.handlerName = handlerName + _clientId;
|
||||
this.privKeyFile = pkf;
|
||||
_ownDest = ownDest; // == ! shared client
|
||||
|
||||
|
||||
@@ -124,6 +164,14 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
_context.statManager().createRateStat("i2ptunnel.client.manageTime", "How long it takes to accept a socket and fire it into an i2ptunnel runner (or queue it for the pool)?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
_context.statManager().createRateStat("i2ptunnel.client.buildRunTime", "How long it takes to run a queued socket into an i2ptunnel runner?", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 60*60*1000 });
|
||||
|
||||
// normalize path so we can find it
|
||||
if (pkf != null) {
|
||||
File keyFile = new File(pkf);
|
||||
if (!keyFile.isAbsolute())
|
||||
keyFile = new File(_context.getConfigDir(), pkf);
|
||||
this.privKeyFile = keyFile.getAbsolutePath();
|
||||
}
|
||||
|
||||
// no need to load the netDb with leaseSets for destinations that will never
|
||||
// be looked up
|
||||
tunnel.getClientOptions().setProperty("i2cp.dontPublishLeaseSet", "true");
|
||||
@@ -145,7 +193,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
|
||||
} // else delay creating session until createI2PSocket() is called
|
||||
|
||||
Thread t = new I2PThread(this);
|
||||
Thread t = new I2PAppThread(this);
|
||||
t.setName("Client " + _clientId);
|
||||
listenerReady = false;
|
||||
t.start();
|
||||
@@ -180,7 +228,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
*
|
||||
*/
|
||||
private void configurePool(I2PTunnel tunnel) {
|
||||
_waitingSockets = new ArrayList(4);
|
||||
//_waitingSockets = new ArrayList(4);
|
||||
|
||||
Properties opts = tunnel.getClientOptions();
|
||||
String maxWait = opts.getProperty(PROP_MAX_WAIT_TIME, DEFAULT_MAX_WAIT_TIME+"");
|
||||
@@ -199,7 +247,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
|
||||
for (int i = 0; i < _numConnectionBuilders; i++) {
|
||||
String name = "ClientBuilder" + _clientId + '.' + i;
|
||||
I2PThread b = new I2PThread(new TunnelConnectionBuilder(), name);
|
||||
I2PAppThread b = new I2PAppThread(new TunnelConnectionBuilder(), name);
|
||||
b.setDaemon(true);
|
||||
b.start();
|
||||
}
|
||||
@@ -277,6 +325,8 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel) {
|
||||
return buildSocketManager(tunnel, null);
|
||||
}
|
||||
|
||||
/** @param pkf absolute path or null */
|
||||
protected static I2PSocketManager buildSocketManager(I2PTunnel tunnel, String pkf) {
|
||||
Properties props = new Properties();
|
||||
props.putAll(tunnel.getClientOptions());
|
||||
@@ -340,7 +390,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
* called by derived classes after initialization.
|
||||
*
|
||||
*/
|
||||
public final void startRunning() {
|
||||
public void startRunning() {
|
||||
synchronized (startLock) {
|
||||
startRunning = true;
|
||||
startLock.notify();
|
||||
@@ -480,7 +530,7 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
protected void manageConnection(Socket s) {
|
||||
if (s == null) return;
|
||||
if (_numConnectionBuilders <= 0) {
|
||||
new I2PThread(new BlockingRunner(s), "Clinet run").start();
|
||||
new I2PAppThread(new BlockingRunner(s), "Clinet run").start();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -549,10 +599,12 @@ public abstract class I2PTunnelClientBase extends I2PTunnelTask implements Runna
|
||||
}
|
||||
return false;
|
||||
}
|
||||
I2PSession session = sockMgr.getSession();
|
||||
if (session != null) {
|
||||
getTunnel().removeSession(session);
|
||||
}
|
||||
if (!chained) {
|
||||
I2PSession session = sockMgr.getSession();
|
||||
if (session != null) {
|
||||
getTunnel().removeSession(session);
|
||||
}
|
||||
} // else the app chaining to this one closes it!
|
||||
}
|
||||
l.log("Closing client " + toString());
|
||||
open = false;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -106,6 +107,8 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
|
||||
/** used to assign unique IDs to the threads / clients. no logic or functionality */
|
||||
private static volatile long __clientId = 0;
|
||||
|
||||
private static final File _errorDir = new File(I2PAppContext.getGlobalContext().getBaseDir(), "docs");
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
||||
* valid config to contact the router
|
||||
@@ -150,6 +153,7 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
|
||||
* create the default options (using the default timeout, etc)
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected I2PSocketOptions getDefaultOptions() {
|
||||
Properties defaultOpts = getTunnel().getClientOptions();
|
||||
if (!defaultOpts.contains(I2PSocketOptions.PROP_READ_TIMEOUT))
|
||||
@@ -176,7 +180,7 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
|
||||
out = s.getOutputStream();
|
||||
in = s.getInputStream();
|
||||
String line, method = null, host = null, destination = null, restofline = null;
|
||||
StringBuffer newRequest = new StringBuffer();
|
||||
StringBuilder newRequest = new StringBuilder();
|
||||
int ahelper = 0;
|
||||
while (true) {
|
||||
// Use this rather than BufferedReader because we can't have readahead,
|
||||
@@ -256,14 +260,14 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
|
||||
return;
|
||||
}
|
||||
|
||||
Destination dest = I2PTunnel.destFromName(destination);
|
||||
if (dest == null) {
|
||||
Destination clientDest = I2PTunnel.destFromName(destination);
|
||||
if (clientDest == null) {
|
||||
String str;
|
||||
byte[] header;
|
||||
if (usingWWWProxy)
|
||||
str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true);
|
||||
str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true);
|
||||
else
|
||||
str = FileUtil.readTextFile("docs/dnfh-header.ht", 100, true);
|
||||
str = FileUtil.readTextFile((new File(_errorDir, "dnfh-header.ht")).getAbsolutePath(), 100, true);
|
||||
if (str != null)
|
||||
header = str.getBytes();
|
||||
else
|
||||
@@ -273,7 +277,7 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
|
||||
return;
|
||||
}
|
||||
|
||||
I2PSocket i2ps = createI2PSocket(dest, getDefaultOptions());
|
||||
I2PSocket i2ps = createI2PSocket(clientDest, getDefaultOptions());
|
||||
byte[] data = null;
|
||||
byte[] response = null;
|
||||
if (usingWWWProxy)
|
||||
@@ -341,7 +345,7 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
|
||||
if (targetRequest != null) {
|
||||
out.write(targetRequest.getBytes());
|
||||
if (usingWWWProxy)
|
||||
out.write(("<br>WWW proxy: " + wwwProxy).getBytes());
|
||||
out.write(("<br />WWW proxy: " + wwwProxy).getBytes());
|
||||
}
|
||||
out.write("</div>".getBytes());
|
||||
out.write("\n</body></html>\n".getBytes());
|
||||
@@ -357,9 +361,9 @@ public class I2PTunnelConnectClient extends I2PTunnelClientBase implements Runna
|
||||
String str;
|
||||
byte[] header;
|
||||
if (usingWWWProxy)
|
||||
str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true);
|
||||
str = FileUtil.readTextFile((new File(_errorDir, "dnfp-header.ht")).getAbsolutePath(), 100, true);
|
||||
else
|
||||
str = FileUtil.readTextFile("docs/dnf-header.ht", 100, true);
|
||||
str = FileUtil.readTextFile((new File(_errorDir, "dnf-header.ht")).getAbsolutePath(), 100, true);
|
||||
if (str != null)
|
||||
header = str.getBytes();
|
||||
else
|
||||
|
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* 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 liscense questions.
|
||||
*/
|
||||
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
// import java.util.ArrayList;
|
||||
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
|
||||
|
||||
/**
|
||||
* Reuse HTTP server's I2PSocketManager for a proxy with no outproxy capability.
|
||||
*
|
||||
* @author sponge
|
||||
*/
|
||||
public class I2PTunnelHTTPBidirProxy extends I2PTunnelHTTPClient implements Runnable {
|
||||
|
||||
|
||||
/**
|
||||
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
||||
* valid config to contact the router
|
||||
*/
|
||||
public I2PTunnelHTTPBidirProxy(int localPort, Logging l, I2PSocketManager sockMgr, I2PTunnel tunnel, EventDispatcher notifyThis, long clientId) {
|
||||
super(localPort, l, sockMgr, tunnel, notifyThis, clientId);
|
||||
// proxyList = new ArrayList();
|
||||
|
||||
setName(getLocalPort() + " -> HTTPClient [NO PROXIES]");
|
||||
startRunning();
|
||||
|
||||
notifyEvent("openHTTPClientResult", "ok");
|
||||
}
|
||||
}
|
@@ -0,0 +1,44 @@
|
||||
/* I2PTunnel is GPL'ed (with the exception mentioned in I2PTunnel.java)
|
||||
* (c) 2003 - 2004 mihi
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.InetAddress;
|
||||
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelHTTPBidirServer extends I2PTunnelHTTPServer {
|
||||
private final static Log log = new Log(I2PTunnelHTTPBidirServer.class);
|
||||
|
||||
public I2PTunnelHTTPBidirServer(InetAddress host, int port, int proxyport, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privData, spoofHost, l, notifyThis, tunnel);
|
||||
finishSetupI2PTunnelHTTPBidirServer(l, proxyport);
|
||||
}
|
||||
|
||||
public I2PTunnelHTTPBidirServer(InetAddress host, int port, int proxyport, File privkey, String privkeyname, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privkey, privkeyname, spoofHost, l, notifyThis, tunnel);
|
||||
finishSetupI2PTunnelHTTPBidirServer(l, proxyport);
|
||||
}
|
||||
|
||||
public I2PTunnelHTTPBidirServer(InetAddress host, int port, int proxyport, InputStream privData, String privkeyname, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privData, privkeyname, spoofHost, l, notifyThis, tunnel);
|
||||
finishSetupI2PTunnelHTTPBidirServer(l, proxyport);
|
||||
}
|
||||
|
||||
private void finishSetupI2PTunnelHTTPBidirServer(Logging l, int proxyport) {
|
||||
|
||||
localPort = proxyport;
|
||||
bidir = true;
|
||||
|
||||
/* start the httpclient */
|
||||
task = new I2PTunnelHTTPBidirProxy(localPort, l, sockMgr, getTunnel(), getEventDispatcher(), __serverId);
|
||||
sockMgr.setName("Server"); // TO-DO: Need to change this to "Bidir"!
|
||||
getTunnel().addSession(sockMgr.getSession());
|
||||
l.log("Ready!");
|
||||
notifyEvent("openServerResult", "ok");
|
||||
}
|
||||
}
|
||||
|
@@ -3,7 +3,10 @@
|
||||
*/
|
||||
package net.i2p.i2ptunnel;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
@@ -14,13 +17,16 @@ import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.I2PException;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
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;
|
||||
@@ -28,6 +34,8 @@ import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import net.i2p.util.Translate;
|
||||
|
||||
/**
|
||||
* Act as a mini HTTP proxy, handling various different types of requests,
|
||||
* forwarding them through I2P appropriately, and displaying the reply. Supported
|
||||
@@ -36,11 +44,17 @@ import net.i2p.util.Log;
|
||||
* or
|
||||
* $method $path $protocolVersion\nHost: $site
|
||||
* or
|
||||
* $method http://i2p/$site/$path $protocolVersion
|
||||
* or
|
||||
* $method http://i2p/$b64key/$path $protocolVersion
|
||||
* or
|
||||
* $method /$site/$path $protocolVersion
|
||||
* or (deprecated)
|
||||
* $method /eepproxy/$site/$path $protocolVersion
|
||||
* </pre>
|
||||
*
|
||||
* Note that http://i2p/$b64key/... and /eepproxy/$site/... are not recommended
|
||||
* in browsers or other user-visible applications, as relative links will not
|
||||
* resolve correctly, cookies won't work, etc.
|
||||
*
|
||||
* If the $site resolves with the I2P naming service, then it is directed towards
|
||||
* that eepsite, otherwise it is directed towards this client's outproxy (typically
|
||||
* "squid.i2p"). Only HTTP is supported (no HTTPS, ftp, mailto, etc). Both GET
|
||||
@@ -50,10 +64,14 @@ import net.i2p.util.Log;
|
||||
public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable {
|
||||
private static final Log _log = new Log(I2PTunnelHTTPClient.class);
|
||||
|
||||
private final List proxyList;
|
||||
protected final List proxyList = new ArrayList();
|
||||
|
||||
private HashMap addressHelpers = new HashMap();
|
||||
|
||||
/**
|
||||
* These are backups if the xxx.ht error page is missing.
|
||||
*/
|
||||
|
||||
private final static byte[] ERR_REQUEST_DENIED =
|
||||
("HTTP/1.1 403 Access Denied\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
@@ -62,7 +80,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
|
||||
"You attempted to connect to a non-I2P website or location.<BR>")
|
||||
.getBytes();
|
||||
|
||||
|
||||
private final static byte[] ERR_DESTINATION_UNKNOWN =
|
||||
("HTTP/1.1 503 Service Unavailable\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
@@ -72,10 +90,11 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"That I2P Destination was not found. Perhaps you pasted in the "+
|
||||
"wrong BASE64 I2P Destination or the link you are following is "+
|
||||
"bad. The host (or the WWW proxy, if you're using one) could also "+
|
||||
"be temporarily offline. You may want to <b>retry</b>. "+
|
||||
"be temporarily offline. You may want to <b>retry</b>. "+
|
||||
"Could not find the following Destination:<BR><BR><div>")
|
||||
.getBytes();
|
||||
|
||||
|
||||
/*****
|
||||
private final static byte[] ERR_TIMEOUT =
|
||||
("HTTP/1.1 504 Gateway Timeout\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
@@ -87,6 +106,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"destination may have issues. Could not get a response from "+
|
||||
"the following Destination:<BR><BR>")
|
||||
.getBytes();
|
||||
*****/
|
||||
|
||||
private final static byte[] ERR_NO_OUTPROXY =
|
||||
("HTTP/1.1 503 Service Unavailable\r\n"+
|
||||
@@ -97,7 +117,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"Your request was for a site outside of I2P, but you have no "+
|
||||
"HTTP outproxy configured. Please configure an outproxy in I2PTunnel")
|
||||
.getBytes();
|
||||
|
||||
|
||||
private final static byte[] ERR_AHELPER_CONFLICT =
|
||||
("HTTP/1.1 409 Conflict\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
@@ -107,13 +127,13 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"The addresshelper link you followed specifies a different destination key "+
|
||||
"than a host entry in your host database. "+
|
||||
"Someone could be trying to impersonate another eepsite, "+
|
||||
"or people have given two eepsites identical names.<P/>"+
|
||||
"or people have given two eepsites identical names.<p>"+
|
||||
"You can resolve the conflict by considering which key you trust, "+
|
||||
"and either discarding the addresshelper link, "+
|
||||
"discarding the host entry from your host database, "+
|
||||
"or naming one of them differently.<P/>")
|
||||
"or naming one of them differently.<p>")
|
||||
.getBytes();
|
||||
|
||||
|
||||
private final static byte[] ERR_BAD_PROTOCOL =
|
||||
("HTTP/1.1 403 Bad Protocol\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
@@ -123,7 +143,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"The request uses a bad protocol. "+
|
||||
"The I2P HTTP Proxy supports http:// requests ONLY. Other protocols such as https:// and ftp:// are not allowed.<BR>")
|
||||
.getBytes();
|
||||
|
||||
|
||||
private final static byte[] ERR_LOCALHOST =
|
||||
("HTTP/1.1 403 Access Denied\r\n"+
|
||||
"Content-Type: text/html; charset=iso-8859-1\r\n"+
|
||||
@@ -132,20 +152,31 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
"<html><body><H1>I2P ERROR: REQUEST DENIED</H1>"+
|
||||
"Your browser is misconfigured. Do not use the proxy to access the router console or other localhost destinations.<BR>")
|
||||
.getBytes();
|
||||
|
||||
|
||||
/** used to assign unique IDs to the threads / clients. no logic or functionality */
|
||||
private static volatile long __clientId = 0;
|
||||
|
||||
private static final File _errorDir = new File(I2PAppContext.getGlobalContext().getBaseDir(), "docs");
|
||||
|
||||
public I2PTunnelHTTPClient(int localPort, Logging l, I2PSocketManager sockMgr, I2PTunnel tunnel, EventDispatcher notifyThis, long clientId) {
|
||||
super(localPort, l, sockMgr, tunnel, notifyThis, clientId);
|
||||
// proxyList = new ArrayList();
|
||||
|
||||
setName(getLocalPort() + " -> HTTPClient [NO PROXIES]");
|
||||
startRunning();
|
||||
|
||||
notifyEvent("openHTTPClientResult", "ok");
|
||||
}
|
||||
/**
|
||||
* @throws IllegalArgumentException if the I2PTunnel does not contain
|
||||
* valid config to contact the router
|
||||
*/
|
||||
public I2PTunnelHTTPClient(int localPort, Logging l, boolean ownDest,
|
||||
String wwwProxy, EventDispatcher notifyThis,
|
||||
public I2PTunnelHTTPClient(int localPort, Logging l, boolean ownDest,
|
||||
String wwwProxy, EventDispatcher notifyThis,
|
||||
I2PTunnel tunnel) throws IllegalArgumentException {
|
||||
super(localPort, ownDest, l, notifyThis, "HTTPHandler " + (++__clientId), tunnel);
|
||||
|
||||
proxyList = new ArrayList();
|
||||
//proxyList = new ArrayList(); // We won't use outside of i2p
|
||||
if (waitEventValue("openBaseClientResult").equals("error")) {
|
||||
notifyEvent("openHTTPClientResult", "error");
|
||||
return;
|
||||
@@ -165,7 +196,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
private String getPrefix(long requestId) { return "Client[" + _clientId + "/" + requestId + "]: "; }
|
||||
|
||||
|
||||
private String selectProxy() {
|
||||
synchronized (proxyList) {
|
||||
int size = proxyList.size();
|
||||
@@ -182,11 +213,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
private static final int DEFAULT_READ_TIMEOUT = 60*1000;
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* create the default options (using the default timeout, etc)
|
||||
* unused?
|
||||
*/
|
||||
@Override
|
||||
protected I2PSocketOptions getDefaultOptions() {
|
||||
Properties defaultOpts = getTunnel().getClientOptions();
|
||||
if (!defaultOpts.contains(I2PSocketOptions.PROP_READ_TIMEOUT))
|
||||
@@ -198,11 +230,12 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
opts.setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);
|
||||
return opts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* create the default options (using the default timeout, etc)
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected I2PSocketOptions getDefaultOptions(Properties overrides) {
|
||||
Properties defaultOpts = getTunnel().getClientOptions();
|
||||
defaultOpts.putAll(overrides);
|
||||
@@ -218,46 +251,75 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
return opts;
|
||||
}
|
||||
|
||||
private InternalSocketRunner isr;
|
||||
|
||||
/**
|
||||
* Actually start working on incoming connections.
|
||||
* Overridden to start an internal socket too.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void startRunning() {
|
||||
super.startRunning();
|
||||
this.isr = new InternalSocketRunner(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to close internal socket too.
|
||||
*/
|
||||
@Override
|
||||
public boolean close(boolean forced) {
|
||||
boolean rv = super.close(forced);
|
||||
if (this.isr != null)
|
||||
this.isr.stopRunning();
|
||||
return rv;
|
||||
}
|
||||
|
||||
private static final boolean DEFAULT_GZIP = true;
|
||||
// all default to false
|
||||
public static final String PROP_REFERER = "i2ptunnel.httpclient.sendReferer";
|
||||
public static final String PROP_USER_AGENT = "i2ptunnel.httpclient.sendUserAgent";
|
||||
public static final String PROP_VIA = "i2ptunnel.httpclient.sendVia";
|
||||
|
||||
public static final String PROP_JUMP_SERVERS = "i2ptunnel.httpclient.jumpServers";
|
||||
|
||||
private static long __requestId = 0;
|
||||
protected void clientConnectionRun(Socket s) {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
String targetRequest = null;
|
||||
boolean usingWWWProxy = false;
|
||||
boolean usingInternalServer = false;
|
||||
String currentProxy = null;
|
||||
long requestId = ++__requestId;
|
||||
try {
|
||||
out = s.getOutputStream();
|
||||
InputReader reader = new InputReader(s.getInputStream());
|
||||
String line, method = null, protocol = null, host = null, destination = null;
|
||||
StringBuffer newRequest = new StringBuffer();
|
||||
StringBuilder newRequest = new StringBuilder();
|
||||
int ahelper = 0;
|
||||
while ((line = reader.readLine(method)) != null) {
|
||||
line = line.trim();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + "Line=[" + line + "]");
|
||||
|
||||
|
||||
String lowercaseLine = line.toLowerCase();
|
||||
if (lowercaseLine.startsWith("connection: ") ||
|
||||
lowercaseLine.startsWith("keep-alive: ") ||
|
||||
if (lowercaseLine.startsWith("connection: ") ||
|
||||
lowercaseLine.startsWith("keep-alive: ") ||
|
||||
lowercaseLine.startsWith("proxy-connection: "))
|
||||
continue;
|
||||
|
||||
|
||||
if (method == null) { // first line (GET /base64/realaddr)
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + "Method is null for [" + line + "]");
|
||||
|
||||
_log.debug(getPrefix(requestId) + "First line [" + line + "]");
|
||||
|
||||
int pos = line.indexOf(" ");
|
||||
if (pos == -1) break;
|
||||
method = line.substring(0, pos);
|
||||
// TODO use Java URL class to make all this simpler and more robust
|
||||
// That will also fix IPV6 [a:b:c]
|
||||
String request = line.substring(pos + 1);
|
||||
if (request.startsWith("/") && getTunnel().getClientOptions().getProperty("i2ptunnel.noproxy") != null) {
|
||||
// what is this for ???
|
||||
request = "http://i2p" + request;
|
||||
} else if (request.startsWith("/eepproxy/")) {
|
||||
// /eepproxy/foo.i2p/bar/baz.html HTTP/1.0
|
||||
@@ -269,6 +331,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
// "http://" + "foo.i2p/bar/baz.html" + " HTTP/1.0"
|
||||
request = "http://" + uri + subRequest.substring(protopos);
|
||||
} else if (request.toLowerCase().startsWith("http://i2p/")) {
|
||||
// http://i2p/b64key/bar/baz.html HTTP/1.0
|
||||
String subRequest = request.substring("http://i2p/".length());
|
||||
int protopos = subRequest.indexOf(" ");
|
||||
String uri = subRequest.substring(0, protopos);
|
||||
if (uri.indexOf("/") == -1) {
|
||||
uri = uri + "/";
|
||||
}
|
||||
// "http://" + "b64key/bar/baz.html" + " HTTP/1.0"
|
||||
request = "http://" + uri + subRequest.substring(protopos);
|
||||
}
|
||||
|
||||
pos = request.indexOf("//");
|
||||
@@ -281,13 +353,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
|
||||
targetRequest = request;
|
||||
|
||||
// pos is the start of the path
|
||||
pos = request.indexOf("/");
|
||||
if (pos == -1) {
|
||||
method = null;
|
||||
break;
|
||||
}
|
||||
host = request.substring(0, pos);
|
||||
|
||||
|
||||
// parse port
|
||||
int posPort = host.indexOf(":");
|
||||
int port = 80;
|
||||
@@ -300,9 +373,25 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
// TODO: log this
|
||||
}
|
||||
}
|
||||
|
||||
// Quick hack for foo.bar.i2p
|
||||
if (host.toLowerCase().endsWith(".i2p")) {
|
||||
|
||||
// Go through the various types of host names, set
|
||||
// the host and destination variables accordingly,
|
||||
// and transform the first line.
|
||||
// For all i2p network hosts, ensure that the host is a
|
||||
// Base 32 hostname so that we do not reveal our name for it
|
||||
// in our addressbook (all naming is local),
|
||||
// and it is removed from the request line.
|
||||
|
||||
if (host.length() >= 516 && host.indexOf(".") < 0) {
|
||||
// http://b64key/bar/baz.html
|
||||
destination = host;
|
||||
host = getHostName(destination);
|
||||
line = method + ' ' + request.substring(pos);
|
||||
} else if (host.toLowerCase().equals("proxy.i2p")) {
|
||||
// so we don't do any naming service lookups
|
||||
destination = host;
|
||||
usingInternalServer = true;
|
||||
} else if (host.toLowerCase().endsWith(".i2p")) {
|
||||
// Destination gets the host name
|
||||
destination = host;
|
||||
// Host becomes the destination key
|
||||
@@ -314,7 +403,7 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
// and split the request into it's component parts for rebuilding later
|
||||
String ahelperKey = null;
|
||||
boolean ahelperConflict = false;
|
||||
|
||||
|
||||
String fragments = request.substring(pos2 + 1);
|
||||
String uriPath = request.substring(0, pos2);
|
||||
pos2 = fragments.indexOf(" ");
|
||||
@@ -328,15 +417,16 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
pos2 = fragments.indexOf("&");
|
||||
fragment = fragments.substring(0, pos2);
|
||||
fragments = fragments.substring(pos2 + 1);
|
||||
|
||||
|
||||
// Fragment looks like addresshelper key
|
||||
if (fragment.startsWith("i2paddresshelper=")) {
|
||||
pos2 = fragment.indexOf("=");
|
||||
ahelperKey = fragment.substring(pos2 + 1);
|
||||
|
||||
|
||||
// Key contains data, lets not ignore it
|
||||
if (ahelperKey != null) {
|
||||
|
||||
// ahelperKey will be validated later
|
||||
|
||||
// Host resolvable only with addresshelper
|
||||
if ( (host == null) || ("i2p".equals(host)) )
|
||||
{
|
||||
@@ -345,12 +435,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
} else {
|
||||
// Host resolvable from database, verify addresshelper key
|
||||
// Silently bypass correct keys, otherwise alert
|
||||
if (!host.equals(ahelperKey))
|
||||
String destB64 = null;
|
||||
try {
|
||||
Destination dest = I2PTunnel.destFromName(host);
|
||||
if (dest != null)
|
||||
destB64 = dest.toBase64();
|
||||
} catch (DataFormatException dfe) {}
|
||||
if (destB64 != null && !destB64.equals(ahelperKey))
|
||||
{
|
||||
// Conflict: handle when URL reconstruction done
|
||||
ahelperConflict = true;
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn(getPrefix(requestId) + "Addresshelper key conflict for site [" + destination + "], trusted key [" + host + "], specified key [" + ahelperKey + "].");
|
||||
_log.warn(getPrefix(requestId) + "Addresshelper key conflict for site [" + destination + "], trusted key [" + destB64 + "], specified key [" + ahelperKey + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -360,32 +456,34 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
if ("".equals(urlEncoding)) {
|
||||
urlEncoding = "?" + fragment;
|
||||
} else {
|
||||
urlEncoding = urlEncoding + "&" + fragment;
|
||||
urlEncoding = urlEncoding + "&" + fragment;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reconstruct the request minus the i2paddresshelper GET var
|
||||
request = uriPath + urlEncoding + " " + protocolVersion;
|
||||
|
||||
|
||||
// Did addresshelper key conflict?
|
||||
if (ahelperConflict)
|
||||
{
|
||||
String str;
|
||||
byte[] header;
|
||||
str = FileUtil.readTextFile("docs/ahelper-conflict-header.ht", 100, true);
|
||||
if (str != null) header = str.getBytes();
|
||||
else header = ERR_AHELPER_CONFLICT;
|
||||
|
||||
if (out != null) {
|
||||
long alias = I2PAppContext.getGlobalContext().random().nextLong();
|
||||
String trustedURL = protocol + uriPath + urlEncoding;
|
||||
String conflictURL = protocol + alias + ".i2p/?" + initialFragments;
|
||||
out.write(header);
|
||||
out.write(("To visit the destination in your host database, click <a href=\"" + trustedURL + "\">here</a>. To visit the conflicting addresshelper link by temporarily giving it a random alias, click <a href=\"" + conflictURL + "\">here</a>.<P/>").getBytes());
|
||||
out.write("</div><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
// convert ahelperKey to b32
|
||||
String alias = getHostName(ahelperKey);
|
||||
if (alias.equals("i2p")) {
|
||||
// bad ahelperKey
|
||||
byte[] header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
|
||||
writeErrorMessage(header, out, targetRequest, false, destination, null);
|
||||
} else {
|
||||
String trustedURL = protocol + uriPath + urlEncoding;
|
||||
// Fixme - any path is lost
|
||||
String conflictURL = protocol + alias + '/' + urlEncoding;
|
||||
byte[] header = getErrorPage("ahelper-conflict", ERR_AHELPER_CONFLICT);
|
||||
out.write(header);
|
||||
out.write(_("To visit the destination in your host database, click <a href=\"{0}\">here</a>. To visit the conflicting addresshelper destination, click <a href=\"{1}\">here</a>.", trustedURL, conflictURL).getBytes("UTF-8"));
|
||||
out.write(("<p></div>").getBytes());
|
||||
writeFooter(out);
|
||||
}
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
@@ -398,8 +496,15 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
host = getHostName(destination);
|
||||
ahelper = 1;
|
||||
}
|
||||
|
||||
|
||||
line = method + " " + request.substring(pos);
|
||||
} else if (host.toLowerCase().equals("localhost") || host.equals("127.0.0.1")) {
|
||||
if (out != null) {
|
||||
out.write(getErrorPage("localhost", ERR_LOCALHOST));
|
||||
writeFooter(out);
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
} else if (host.indexOf(".") != -1) {
|
||||
// rebuild host
|
||||
host = host + ":" + port;
|
||||
@@ -414,11 +519,8 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
_log.warn(getPrefix(requestId) + "Host wants to be outproxied, but we dont have any!");
|
||||
l.log("No HTTP outproxy found for the request.");
|
||||
if (out != null) {
|
||||
out.write(ERR_NO_OUTPROXY);
|
||||
out.write("<p /><i>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
out.write(getErrorPage("noproxy", ERR_NO_OUTPROXY));
|
||||
writeFooter(out);
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
@@ -427,57 +529,67 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
usingWWWProxy = true;
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + "Host doesnt end with .i2p and it contains a period [" + host + "]: wwwProxy!");
|
||||
} else if (host.toLowerCase().startsWith("localhost:")) {
|
||||
if (out != null) {
|
||||
out.write(ERR_LOCALHOST);
|
||||
out.write("<p /><i>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
} else {
|
||||
// what is left for here? a hostname with no dots, and != "i2p"
|
||||
// and not a destination ???
|
||||
// Perhaps something in privatehosts.txt ...
|
||||
request = request.substring(pos + 1);
|
||||
pos = request.indexOf("/");
|
||||
if (pos < 0) {
|
||||
l.log("Invalid request url [" + request + "]");
|
||||
if (out != null) {
|
||||
out.write(ERR_REQUEST_DENIED);
|
||||
out.write("<p /><i>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
|
||||
writeFooter(out);
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
destination = request.substring(0, pos);
|
||||
host = getHostName(destination);
|
||||
line = method + " " + request.substring(pos);
|
||||
} // end host name processing
|
||||
|
||||
if (port != 80 && !usingWWWProxy) {
|
||||
if (out != null) {
|
||||
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
|
||||
writeFooter(out);
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean isValid = usingWWWProxy || isSupportedAddress(host, protocol);
|
||||
boolean isValid = usingWWWProxy || usingInternalServer || isSupportedAddress(host, protocol);
|
||||
if (!isValid) {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "notValid(" + host + ")");
|
||||
method = null;
|
||||
destination = null;
|
||||
break;
|
||||
} else if (!usingWWWProxy) {
|
||||
if (_log.shouldLog(Log.INFO)) _log.info(getPrefix(requestId) + "host=getHostName(" + destination + ")");
|
||||
host = getHostName(destination); // hide original host
|
||||
}
|
||||
|
||||
// don't do this, it forces yet another hostname lookup,
|
||||
// and in all cases host was already set above
|
||||
//if ((!usingWWWProxy) && (!usingInternalServer)) {
|
||||
// String oldhost = host;
|
||||
// host = getHostName(destination); // hide original host
|
||||
// if (_log.shouldLog(Log.INFO))
|
||||
// _log.info(getPrefix(requestId) + " oldhost " + oldhost + " newhost " + host + " dest " + destination);
|
||||
//}
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG)) {
|
||||
_log.debug(getPrefix(requestId) + "METHOD:" + method + ":");
|
||||
_log.debug(getPrefix(requestId) + "PROTOC:" + protocol + ":");
|
||||
_log.debug(getPrefix(requestId) + "HOST :" + host + ":");
|
||||
_log.debug(getPrefix(requestId) + "DEST :" + destination + ":");
|
||||
_log.debug(getPrefix(requestId) + "METHOD: \"" + method + "\"");
|
||||
_log.debug(getPrefix(requestId) + "PROTOC: \"" + protocol + "\"");
|
||||
_log.debug(getPrefix(requestId) + "HOST : \"" + host + "\"");
|
||||
_log.debug(getPrefix(requestId) + "DEST : \"" + destination + "\"");
|
||||
}
|
||||
|
||||
|
||||
// end first line processing
|
||||
|
||||
} else {
|
||||
if (lowercaseLine.startsWith("host: ") && !usingWWWProxy) {
|
||||
// Note that we only pass the original Host: line through to the outproxy
|
||||
// But we don't create a Host: line if it wasn't sent to us
|
||||
line = "Host: " + host;
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info(getPrefix(requestId) + "Setting host = " + host);
|
||||
} else if (lowercaseLine.startsWith("user-agent: ") &&
|
||||
!Boolean.valueOf(getTunnel().getClientOptions().getProperty(PROP_USER_AGENT)).booleanValue()) {
|
||||
@@ -505,14 +617,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
continue; // completely strip the line
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (line.length() == 0) {
|
||||
|
||||
|
||||
String ok = getTunnel().getClientOptions().getProperty("i2ptunnel.gzip");
|
||||
boolean gzip = DEFAULT_GZIP;
|
||||
if (ok != null)
|
||||
gzip = Boolean.valueOf(ok).booleanValue();
|
||||
if (gzip) {
|
||||
if (gzip && !usingInternalServer) {
|
||||
// according to rfc2616 s14.3, this *should* force identity, even if
|
||||
// an explicit q=0 for gzip doesn't. tested against orion.i2p, and it
|
||||
// seems to work.
|
||||
@@ -526,63 +638,75 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
} else {
|
||||
newRequest.append(line).append("\r\n"); // HTTP spec
|
||||
}
|
||||
}
|
||||
} // end header processing
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + "NewRequest header: [" + newRequest.toString() + "]");
|
||||
|
||||
if (method == null || destination == null) {
|
||||
l.log("No HTTP method found in the request.");
|
||||
//l.log("No HTTP method found in the request.");
|
||||
if (out != null) {
|
||||
if ("http://".equalsIgnoreCase(protocol))
|
||||
out.write(ERR_REQUEST_DENIED);
|
||||
out.write(getErrorPage("denied", ERR_REQUEST_DENIED));
|
||||
else
|
||||
out.write(ERR_BAD_PROTOCOL);
|
||||
out.write("<p /><i>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
out.write(getErrorPage("protocol", ERR_BAD_PROTOCOL));
|
||||
writeFooter(out);
|
||||
}
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(getPrefix(requestId) + "Destination: " + destination);
|
||||
|
||||
Destination dest = I2PTunnel.destFromName(destination);
|
||||
if (dest == null) {
|
||||
|
||||
// Serve local proxy files (images, css linked from error pages)
|
||||
// Ignore all the headers
|
||||
if (usingInternalServer) {
|
||||
serveLocalFile(out, method, targetRequest);
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// If the host is "i2p", the getHostName() lookup failed, don't try to
|
||||
// look it up again as the naming service does not do negative caching
|
||||
// so it will be slow.
|
||||
|
||||
Destination clientDest;
|
||||
if ("i2p".equals(host))
|
||||
clientDest = null;
|
||||
else
|
||||
clientDest = I2PTunnel.destFromName(destination);
|
||||
|
||||
if (clientDest == null) {
|
||||
//l.log("Could not resolve " + destination + ".");
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Unable to resolve " + destination + " (proxy? " + usingWWWProxy + ", request: " + targetRequest);
|
||||
String str;
|
||||
byte[] header;
|
||||
boolean showAddrHelper = false;
|
||||
String jumpServers = null;
|
||||
if (usingWWWProxy)
|
||||
str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true);
|
||||
header = getErrorPage("dnfp", ERR_DESTINATION_UNKNOWN);
|
||||
else if(ahelper != 0)
|
||||
str = FileUtil.readTextFile("docs/dnfb-header.ht", 100, true);
|
||||
header = getErrorPage("dnfb", ERR_DESTINATION_UNKNOWN);
|
||||
else if (destination.length() == 60 && destination.endsWith(".b32.i2p"))
|
||||
str = FileUtil.readTextFile("docs/dnf-header.ht", 100, true);
|
||||
header = getErrorPage("dnf", ERR_DESTINATION_UNKNOWN);
|
||||
else {
|
||||
str = FileUtil.readTextFile("docs/dnfh-header.ht", 100, true);
|
||||
showAddrHelper = true;
|
||||
header = getErrorPage("dnfh", ERR_DESTINATION_UNKNOWN);
|
||||
jumpServers = getTunnel().getClientOptions().getProperty(PROP_JUMP_SERVERS);
|
||||
if (jumpServers == null)
|
||||
jumpServers = DEFAULT_JUMP_SERVERS;
|
||||
}
|
||||
if (str != null)
|
||||
header = str.getBytes();
|
||||
else
|
||||
header = ERR_DESTINATION_UNKNOWN;
|
||||
writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination, showAddrHelper);
|
||||
writeErrorMessage(header, out, targetRequest, usingWWWProxy, destination, jumpServers);
|
||||
s.close();
|
||||
return;
|
||||
}
|
||||
String remoteID;
|
||||
|
||||
|
||||
Properties opts = new Properties();
|
||||
//opts.setProperty("i2p.streaming.inactivityTimeout", ""+120*1000);
|
||||
// 1 == disconnect. see ConnectionOptions in the new streaming lib, which i
|
||||
// dont want to hard link to here
|
||||
//opts.setProperty("i2p.streaming.inactivityTimeoutAction", ""+1);
|
||||
I2PSocket i2ps = createI2PSocket(dest, getDefaultOptions(opts));
|
||||
I2PSocket i2ps = createI2PSocket(clientDest, getDefaultOptions(opts));
|
||||
byte[] data = newRequest.toString().getBytes("ISO-8859-1");
|
||||
Runnable onTimeout = new OnTimeout(s, s.getOutputStream(), targetRequest, usingWWWProxy, currentProxy, requestId);
|
||||
I2PTunnelRunner runner = new I2PTunnelHTTPClientRunner(s, i2ps, sockLock, data, mySockets, onTimeout);
|
||||
@@ -633,17 +757,81 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return b32hash.b32.i2p, or "i2p" on lookup failure.
|
||||
* Prior to 0.7.12, returned b64 key
|
||||
*/
|
||||
private final static String getHostName(String host) {
|
||||
if (host == null) return null;
|
||||
if (host.length() == 60 && host.toLowerCase().endsWith(".b32.i2p"))
|
||||
return host;
|
||||
try {
|
||||
Destination dest = I2PTunnel.destFromName(host);
|
||||
if (dest == null) return "i2p";
|
||||
return dest.toBase64();
|
||||
return Base32.encode(dest.calculateHash().getData()) + ".b32.i2p";
|
||||
} catch (DataFormatException dfe) {
|
||||
return "i2p";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* foo => errordir/foo-header_xx.ht for lang xx, or errordir/foo-header.ht,
|
||||
* or the backup byte array on fail.
|
||||
*
|
||||
* .ht files must be UTF-8 encoded and use \r\n terminators so the
|
||||
* HTTP headers are conformant.
|
||||
* We can't use FileUtil.readFile() because it strips \r
|
||||
*
|
||||
* @return non-null
|
||||
*/
|
||||
private byte[] getErrorPage(String base, byte[] backup) {
|
||||
return getErrorPage(getTunnel().getContext(), base, backup);
|
||||
}
|
||||
|
||||
private static byte[] getErrorPage(I2PAppContext ctx, String base, byte[] backup) {
|
||||
File errorDir = new File(ctx.getBaseDir(), "docs");
|
||||
String lang = ctx.getProperty("routerconsole.lang", Locale.getDefault().getLanguage());
|
||||
if (lang != null && lang.length() > 0 && !lang.equals("en")) {
|
||||
File file = new File(errorDir, base + "-header_" + lang + ".ht");
|
||||
try {
|
||||
return readFile(file);
|
||||
} catch (IOException ioe) {
|
||||
// try the english version now
|
||||
}
|
||||
}
|
||||
File file = new File(errorDir, base + "-header.ht");
|
||||
try {
|
||||
return readFile(file);
|
||||
} catch (IOException ioe) {
|
||||
return backup;
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] readFile(File file) throws IOException {
|
||||
FileInputStream fis = null;
|
||||
byte[] buf = new byte[512];
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
|
||||
try {
|
||||
int len = 0;
|
||||
fis = new FileInputStream(file);
|
||||
while ((len = fis.read(buf)) > 0) {
|
||||
baos.write(buf, 0, len);
|
||||
}
|
||||
return baos.toByteArray();
|
||||
} finally {
|
||||
try { if (fis != null) fis.close(); } catch (IOException foo) {}
|
||||
}
|
||||
// we won't ever get here
|
||||
}
|
||||
|
||||
private static void writeFooter(OutputStream out) throws IOException {
|
||||
// the css is hiding this div for now, but we'll keep it here anyway
|
||||
out.write("<div class=\"proxyfooter\"><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></div></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
}
|
||||
|
||||
private static class OnTimeout implements Runnable {
|
||||
private Socket _socket;
|
||||
private OutputStream _out;
|
||||
@@ -662,21 +850,22 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
public void run() {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Timeout occured requesting " + _target);
|
||||
handleHTTPClientException(new RuntimeException("Timeout"), _out,
|
||||
handleHTTPClientException(new RuntimeException("Timeout"), _out,
|
||||
_target, _usingProxy, _wwwProxy, _requestId);
|
||||
closeSocket(_socket);
|
||||
}
|
||||
}
|
||||
|
||||
private static String jumpServers[] = {
|
||||
"http://i2host.i2p/cgi-bin/i2hostjump?",
|
||||
// "http://orion.i2p/jump/",
|
||||
"http://stats.i2p/cgi-bin/jump.cgi?a=",
|
||||
// "http://trevorreznik.i2p/cgi-bin/jump.php?hostname=",
|
||||
"http://i2jump.i2p/"
|
||||
};
|
||||
|
||||
private static String DEFAULT_JUMP_SERVERS =
|
||||
"http://i2host.i2p/cgi-bin/i2hostjump?," +
|
||||
"http://stats.i2p/cgi-bin/jump.cgi?a=," +
|
||||
"http://i2jump.i2p/";
|
||||
|
||||
/**
|
||||
* @param jumpServers comma- or space-separated list, or null
|
||||
*/
|
||||
private static void writeErrorMessage(byte[] errMessage, OutputStream out, String targetRequest,
|
||||
boolean usingWWWProxy, String wwwProxy, boolean showAddrHelper) throws IOException {
|
||||
boolean usingWWWProxy, String wwwProxy, String jumpServers) throws IOException {
|
||||
if (out != null) {
|
||||
out.write(errMessage);
|
||||
if (targetRequest != null) {
|
||||
@@ -692,11 +881,18 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
out.write(uri.getBytes());
|
||||
out.write("</a>".getBytes());
|
||||
if (usingWWWProxy) out.write(("<br>WWW proxy: " + wwwProxy).getBytes());
|
||||
if (showAddrHelper) {
|
||||
out.write("<br><br>Click a link below to look for an address helper by using a \"jump\" service:<br>".getBytes());
|
||||
for (int i = 0; i < jumpServers.length; i++) {
|
||||
if (jumpServers != null && jumpServers.length() > 0) {
|
||||
out.write("<br><br>".getBytes());
|
||||
out.write(_("Click a link below to look for an address helper by using a \"jump\" service:").getBytes("UTF-8"));
|
||||
out.write("<br>".getBytes());
|
||||
|
||||
StringTokenizer tok = new StringTokenizer(jumpServers, ", ");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String jurl = tok.nextToken();
|
||||
if (!jurl.startsWith("http://"))
|
||||
continue;
|
||||
// Skip jump servers we don't know
|
||||
String jumphost = jumpServers[i].substring(7); // "http://"
|
||||
String jumphost = jurl.substring(7); // "http://"
|
||||
jumphost = jumphost.substring(0, jumphost.indexOf('/'));
|
||||
try {
|
||||
Destination dest = I2PTunnel.destFromName(jumphost);
|
||||
@@ -706,41 +902,34 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
out.write("<br><a href=\"".getBytes());
|
||||
out.write(jumpServers[i].getBytes());
|
||||
out.write(jurl.getBytes());
|
||||
out.write(uri.getBytes());
|
||||
out.write("\">".getBytes());
|
||||
out.write(jumpServers[i].getBytes());
|
||||
out.write(jurl.getBytes());
|
||||
out.write(uri.getBytes());
|
||||
out.write("</a>".getBytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
out.write("</div><p><i>I2P HTTP Proxy Server<br>Generated on: ".getBytes());
|
||||
out.write(new Date().toString().getBytes());
|
||||
out.write("</i></body></html>\n".getBytes());
|
||||
out.flush();
|
||||
out.write("</div>".getBytes());
|
||||
writeFooter(out);
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleHTTPClientException(Exception ex, OutputStream out, String targetRequest,
|
||||
boolean usingWWWProxy, String wwwProxy, long requestId) {
|
||||
|
||||
|
||||
// static
|
||||
//if (_log.shouldLog(Log.WARN))
|
||||
// _log.warn(getPrefix(requestId) + "Error sending to " + wwwProxy + " (proxy? " + usingWWWProxy + ", request: " + targetRequest, ex);
|
||||
if (out != null) {
|
||||
try {
|
||||
String str;
|
||||
byte[] header;
|
||||
if (usingWWWProxy)
|
||||
str = FileUtil.readTextFile("docs/dnfp-header.ht", 100, true);
|
||||
header = getErrorPage(I2PAppContext.getGlobalContext(), "dnfp", ERR_DESTINATION_UNKNOWN);
|
||||
else
|
||||
str = FileUtil.readTextFile("docs/dnf-header.ht", 100, true);
|
||||
if (str != null)
|
||||
header = str.getBytes();
|
||||
else
|
||||
header = ERR_DESTINATION_UNKNOWN;
|
||||
writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy, false);
|
||||
header = getErrorPage(I2PAppContext.getGlobalContext(), "dnf", ERR_DESTINATION_UNKNOWN);
|
||||
writeErrorMessage(header, out, targetRequest, usingWWWProxy, wwwProxy, null);
|
||||
} catch (IOException ioe) {
|
||||
// static
|
||||
//_log.warn(getPrefix(requestId) + "Error writing out the 'destination was unknown' " + "message", ioe);
|
||||
@@ -753,8 +942,14 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
|
||||
private final static String SUPPORTED_HOSTS[] = { "i2p", "www.i2p.com", "i2p."};
|
||||
|
||||
/** @param host ignored */
|
||||
private static boolean isSupportedAddress(String host, String protocol) {
|
||||
if ((host == null) || (protocol == null)) return false;
|
||||
|
||||
/****
|
||||
* Let's not look up the name _again_
|
||||
* and now that host is a b32, this was failing
|
||||
*
|
||||
boolean found = false;
|
||||
String lcHost = host.toLowerCase();
|
||||
for (int i = 0; i < SUPPORTED_HOSTS.length; i++) {
|
||||
@@ -771,7 +966,97 @@ public class I2PTunnelHTTPClient extends I2PTunnelClientBase implements Runnable
|
||||
} catch (DataFormatException dfe) {
|
||||
}
|
||||
}
|
||||
|
||||
****/
|
||||
return protocol.equalsIgnoreCase("http://");
|
||||
}
|
||||
|
||||
private final static byte[] ERR_404 =
|
||||
("HTTP/1.1 404 Not Found\r\n"+
|
||||
"Content-Type: text/plain\r\n"+
|
||||
"\r\n"+
|
||||
"HTTP Proxy local file not found")
|
||||
.getBytes();
|
||||
|
||||
/**
|
||||
* Very simple web server.
|
||||
*
|
||||
* Serve local files in the docs/ directory, for CSS and images in
|
||||
* error pages, using the reserved address proxy.i2p
|
||||
* (similar to p.p in privoxy).
|
||||
* This solves the problems with including links to the router console,
|
||||
* as assuming the router console is at 127.0.0.1 leads to broken
|
||||
* links if it isn't.
|
||||
*
|
||||
* Ignore all request headers (If-Modified-Since, etc.)
|
||||
*
|
||||
* There is basic protection here -
|
||||
* FileUtil.readFile() prevents traversal above the base directory -
|
||||
* but inproxy/gateway ops would be wise to block proxy.i2p to prevent
|
||||
* exposing the docs/ directory or perhaps other issues through
|
||||
* uncaught vulnerabilities.
|
||||
* Restrict to the /themes/ directory for now.
|
||||
*
|
||||
* @param targetRequest "proxy.i2p/themes/foo.png HTTP/1.1"
|
||||
*/
|
||||
private static void serveLocalFile(OutputStream out, String method, String targetRequest) {
|
||||
// a home page message for the curious...
|
||||
if (targetRequest.startsWith("proxy.i2p/ ")) {
|
||||
try {
|
||||
out.write(("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nCache-Control: max-age=86400\r\n\r\nI2P HTTP proxy OK").getBytes());
|
||||
out.flush();
|
||||
} catch (IOException ioe) {}
|
||||
return;
|
||||
}
|
||||
if ((method.equals("GET") || method.equals("HEAD")) &&
|
||||
targetRequest.startsWith("proxy.i2p/themes/") &&
|
||||
!targetRequest.contains("..")) {
|
||||
int space = targetRequest.indexOf(' ');
|
||||
String filename = null;
|
||||
try {
|
||||
filename = targetRequest.substring(17, space); // "proxy.i2p/themes/".length
|
||||
} catch (IndexOutOfBoundsException ioobe) {}
|
||||
// theme hack
|
||||
if (filename.startsWith("console/default/"))
|
||||
filename = filename.replaceFirst("default", I2PAppContext.getGlobalContext().getProperty("routerconsole.theme", "light"));
|
||||
File themesDir = new File(_errorDir, "themes");
|
||||
File file = new File(themesDir, filename);
|
||||
if (file.exists() && !file.isDirectory()) {
|
||||
String type;
|
||||
if (filename.endsWith(".css"))
|
||||
type = "text/css";
|
||||
else if (filename.endsWith(".ico"))
|
||||
type = "image/x-icon";
|
||||
else if (filename.endsWith(".png"))
|
||||
type = "image/png";
|
||||
else if (filename.endsWith(".jpg"))
|
||||
type = "image/jpeg";
|
||||
else type = "text/html";
|
||||
try {
|
||||
out.write("HTTP/1.1 200 OK\r\nContent-Type: ".getBytes());
|
||||
out.write(type.getBytes());
|
||||
out.write("\r\nCache-Control: max-age=86400\r\n\r\n".getBytes());
|
||||
FileUtil.readFile(filename, themesDir.getAbsolutePath(), out);
|
||||
return;
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
try {
|
||||
out.write(ERR_404);
|
||||
out.flush();
|
||||
} catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
|
||||
private static final String BUNDLE_NAME = "net.i2p.i2ptunnel.web.messages";
|
||||
|
||||
/** lang in routerconsole.lang property, else current locale */
|
||||
public static String _(String key) {
|
||||
return Translate.getString(key, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
|
||||
}
|
||||
|
||||
/** {0} and {1} */
|
||||
public static String _(String key, Object o, Object o2) {
|
||||
return Translate.getString(key, o, o2, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -17,8 +17,9 @@ import java.util.zip.GZIPOutputStream;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.data.Base32;
|
||||
|
||||
/**
|
||||
* Simple extension to the I2PTunnelServer that filters the HTTP
|
||||
@@ -33,24 +34,26 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
/** what Host: should we seem to be to the webserver? */
|
||||
private String _spoofHost;
|
||||
private static final String HASH_HEADER = "X-I2P-DestHash";
|
||||
private static final String DEST64_HEADER = "X-I2P-DestB64";
|
||||
private static final String DEST32_HEADER = "X-I2P-DestB32";
|
||||
|
||||
public I2PTunnelHTTPServer(InetAddress host, int port, String privData, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privData, l, notifyThis, tunnel);
|
||||
_spoofHost = spoofHost;
|
||||
getTunnel().getContext().statManager().createRateStat("i2ptunnel.httpserver.blockingHandleTime", "how long the blocking handle takes to complete", "I2PTunnel", new long[] { 60*1000, 10*60*1000, 3*60*60*1000 });
|
||||
getTunnel().getContext().statManager().createRateStat("i2ptunnel.httpNullWorkaround", "How often an http server works around a streaming lib or i2ptunnel bug", "I2PTunnel", new long[] { 60*1000, 10*60*1000 });
|
||||
setupI2PTunnelHTTPServer(spoofHost);
|
||||
}
|
||||
|
||||
public I2PTunnelHTTPServer(InetAddress host, int port, File privkey, String privkeyname, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privkey, privkeyname, l, notifyThis, tunnel);
|
||||
_spoofHost = spoofHost;
|
||||
getTunnel().getContext().statManager().createRateStat("i2ptunnel.httpserver.blockingHandleTime", "how long the blocking handle takes to complete", "I2PTunnel.HTTPServer", new long[] { 60*1000, 10*60*1000, 3*60*60*1000 });
|
||||
getTunnel().getContext().statManager().createRateStat("i2ptunnel.httpNullWorkaround", "How often an http server works around a streaming lib or i2ptunnel bug", "I2PTunnel.HTTPServer", new long[] { 60*1000, 10*60*1000 });
|
||||
setupI2PTunnelHTTPServer(spoofHost);
|
||||
}
|
||||
|
||||
public I2PTunnelHTTPServer(InetAddress host, int port, InputStream privData, String privkeyname, String spoofHost, Logging l, EventDispatcher notifyThis, I2PTunnel tunnel) {
|
||||
super(host, port, privData, privkeyname, l, notifyThis, tunnel);
|
||||
_spoofHost = spoofHost;
|
||||
setupI2PTunnelHTTPServer(spoofHost);
|
||||
}
|
||||
|
||||
private void setupI2PTunnelHTTPServer(String spoofHost) {
|
||||
_spoofHost = spoofHost;
|
||||
getTunnel().getContext().statManager().createRateStat("i2ptunnel.httpserver.blockingHandleTime", "how long the blocking handle takes to complete", "I2PTunnel.HTTPServer", new long[] { 60*1000, 10*60*1000, 3*60*60*1000 });
|
||||
getTunnel().getContext().statManager().createRateStat("i2ptunnel.httpNullWorkaround", "How often an http server works around a streaming lib or i2ptunnel bug", "I2PTunnel.HTTPServer", new long[] { 60*1000, 10*60*1000 });
|
||||
}
|
||||
@@ -71,9 +74,12 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
|
||||
InputStream in = socket.getInputStream();
|
||||
|
||||
StringBuffer command = new StringBuffer(128);
|
||||
StringBuilder command = new StringBuilder(128);
|
||||
Properties headers = readHeaders(in, command);
|
||||
headers.setProperty(HASH_HEADER, socket.getPeerDestination().calculateHash().toBase64());
|
||||
headers.setProperty(DEST32_HEADER, Base32.encode(socket.getPeerDestination().calculateHash().getData()) + ".b32.i2p" );
|
||||
headers.setProperty(DEST64_HEADER, socket.getPeerDestination().toBase64());
|
||||
|
||||
if ( (_spoofHost != null) && (_spoofHost.trim().length() > 0) )
|
||||
headers.setProperty("Host", _spoofHost);
|
||||
headers.setProperty("Connection", "close");
|
||||
@@ -112,7 +118,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
useGZIP = true;
|
||||
|
||||
if (allowGZIP && useGZIP) {
|
||||
I2PThread req = new I2PThread(new CompressedRequestor(s, socket, modifiedHeader), Thread.currentThread().getName()+".hc");
|
||||
I2PAppThread req = new I2PAppThread(new CompressedRequestor(s, socket, modifiedHeader), Thread.currentThread().getName()+".hc");
|
||||
req.start();
|
||||
} else {
|
||||
new I2PTunnelRunner(s, socket, slock, null, modifiedHeader.getBytes(), null);
|
||||
@@ -168,7 +174,7 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
_log.info("request headers: " + _headers);
|
||||
serverout.write(_headers.getBytes());
|
||||
browserin = _browser.getInputStream();
|
||||
I2PThread sender = new I2PThread(new Sender(serverout, browserin, "server: browser to server"), Thread.currentThread().getName() + "hcs");
|
||||
I2PAppThread sender = new I2PAppThread(new Sender(serverout, browserin, "server: browser to server"), Thread.currentThread().getName() + "hcs");
|
||||
sender.start();
|
||||
|
||||
browserout = _browser.getOutputStream();
|
||||
@@ -303,8 +309,8 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
}
|
||||
}
|
||||
|
||||
private String formatHeaders(Properties headers, StringBuffer command) {
|
||||
StringBuffer buf = new StringBuffer(command.length() + headers.size() * 64);
|
||||
private String formatHeaders(Properties headers, StringBuilder command) {
|
||||
StringBuilder buf = new StringBuilder(command.length() + headers.size() * 64);
|
||||
buf.append(command.toString().trim()).append("\r\n");
|
||||
for (Iterator iter = headers.keySet().iterator(); iter.hasNext(); ) {
|
||||
String name = (String)iter.next();
|
||||
@@ -315,9 +321,9 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private Properties readHeaders(InputStream in, StringBuffer command) throws IOException {
|
||||
private Properties readHeaders(InputStream in, StringBuilder command) throws IOException {
|
||||
Properties headers = new Properties();
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
|
||||
boolean ok = DataHelper.readLine(in, command);
|
||||
if (!ok) throw new IOException("EOF reached while reading the HTTP command [" + command.toString() + "]");
|
||||
@@ -361,6 +367,10 @@ public class I2PTunnelHTTPServer extends I2PTunnelServer {
|
||||
name = "X-Accept-encoding";
|
||||
else if (HASH_HEADER.equalsIgnoreCase(name))
|
||||
continue; // Prevent spoofing
|
||||
else if (DEST64_HEADER.equalsIgnoreCase(name))
|
||||
continue; // Prevent spoofing
|
||||
else if (DEST32_HEADER.equalsIgnoreCase(name))
|
||||
continue; // Prevent spoofing
|
||||
headers.setProperty(name, value);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Read the header [" + name + "] = [" + value + "]");
|
||||
|
@@ -14,7 +14,7 @@ import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.data.DataFormatException;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.EventDispatcher;
|
||||
import net.i2p.util.I2PThread;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable {
|
||||
@@ -77,15 +77,15 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
protected void clientConnectionRun(Socket s) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("got a connection.");
|
||||
Destination dest = pickDestination();
|
||||
Destination clientDest = pickDestination();
|
||||
I2PSocket i2ps = null;
|
||||
try {
|
||||
i2ps = createI2PSocket(dest);
|
||||
i2ps = createI2PSocket(clientDest);
|
||||
i2ps.setReadTimeout(readTimeout);
|
||||
StringBuffer expectedPong = new StringBuffer();
|
||||
Thread in = new I2PThread(new IrcInboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " in");
|
||||
Thread in = new I2PAppThread(new IrcInboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " in", true);
|
||||
in.start();
|
||||
Thread out = new I2PThread(new IrcOutboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " out");
|
||||
Thread out = new I2PAppThread(new IrcOutboundFilter(s,i2ps, expectedPong), "IRC Client " + __clientId + " out", true);
|
||||
out.start();
|
||||
} catch (Exception ex) {
|
||||
if (_log.shouldLog(Log.ERROR))
|
||||
@@ -117,13 +117,13 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
/*************************************************************************
|
||||
*
|
||||
*/
|
||||
private class IrcInboundFilter implements Runnable {
|
||||
public static class IrcInboundFilter implements Runnable {
|
||||
|
||||
private Socket local;
|
||||
private I2PSocket remote;
|
||||
private StringBuffer expectedPong;
|
||||
|
||||
IrcInboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
|
||||
public IrcInboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
|
||||
local=_local;
|
||||
remote=_remote;
|
||||
expectedPong=pong;
|
||||
@@ -191,13 +191,13 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
/*************************************************************************
|
||||
*
|
||||
*/
|
||||
private class IrcOutboundFilter implements Runnable {
|
||||
public static class IrcOutboundFilter implements Runnable {
|
||||
|
||||
private Socket local;
|
||||
private I2PSocket remote;
|
||||
private StringBuffer expectedPong;
|
||||
|
||||
IrcOutboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
|
||||
public IrcOutboundFilter(Socket _local, I2PSocket _remote, StringBuffer pong) {
|
||||
local=_local;
|
||||
remote=_remote;
|
||||
expectedPong=pong;
|
||||
@@ -266,7 +266,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
*
|
||||
*/
|
||||
|
||||
public String inboundFilter(String s, StringBuffer expectedPong) {
|
||||
public static String inboundFilter(String s, StringBuffer expectedPong) {
|
||||
|
||||
String field[]=s.split(" ",4);
|
||||
String command;
|
||||
@@ -353,7 +353,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
return null;
|
||||
}
|
||||
|
||||
public String outboundFilter(String s, StringBuffer expectedPong) {
|
||||
public static String outboundFilter(String s, StringBuffer expectedPong) {
|
||||
|
||||
String field[]=s.split(" ",3);
|
||||
String command;
|
||||
@@ -378,7 +378,8 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
"KICK",
|
||||
"HELPME",
|
||||
"RULES",
|
||||
"TOPIC"
|
||||
"TOPIC",
|
||||
"ISON" // jIRCii uses this for a ping (response is 303)
|
||||
};
|
||||
|
||||
if(field[0].length()==0)
|
||||
@@ -390,7 +391,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
|
||||
command = field[0].toUpperCase();
|
||||
|
||||
if ("PING".equalsIgnoreCase(command)) {
|
||||
if ("PING".equals(command)) {
|
||||
// Most clients just send a PING and are happy with any old PONG. Others,
|
||||
// like BitchX, actually expect certain behavior. It sends two different pings:
|
||||
// "PING :irc.freshcoffee.i2p" and "PING 1234567890 127.0.0.1" (where the IP is the proxy)
|
||||
@@ -426,19 +427,19 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
|
||||
return rv;
|
||||
}
|
||||
if ("PONG".equalsIgnoreCase(command))
|
||||
if ("PONG".equals(command))
|
||||
return "PONG 127.0.0.1"; // no way to know what the ircd to i2ptunnel server con is, so localhost works
|
||||
|
||||
// Allow all allowedCommands
|
||||
for(int i=0;i<allowedCommands.length;i++)
|
||||
{
|
||||
if(allowedCommands[i].equalsIgnoreCase(command))
|
||||
if(allowedCommands[i].equals(command))
|
||||
return s;
|
||||
}
|
||||
|
||||
// mIRC sends "NOTICE user :DCC Send file (IP)"
|
||||
// in addition to the CTCP version
|
||||
if("NOTICE".equalsIgnoreCase(command))
|
||||
if("NOTICE".equals(command))
|
||||
{
|
||||
String msg = field[2];
|
||||
if(msg.startsWith(":DCC "))
|
||||
@@ -447,7 +448,7 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
}
|
||||
|
||||
// Allow PRIVMSG, but block CTCP (except ACTION).
|
||||
if("PRIVMSG".equalsIgnoreCase(command) || "NOTICE".equalsIgnoreCase(command))
|
||||
if("PRIVMSG".equals(command) || "NOTICE".equals(command))
|
||||
{
|
||||
String msg;
|
||||
msg = field[2];
|
||||
@@ -465,14 +466,16 @@ public class I2PTunnelIRCClient extends I2PTunnelClientBase implements Runnable
|
||||
return s;
|
||||
}
|
||||
|
||||
if("USER".equalsIgnoreCase(command)) {
|
||||
if("USER".equals(command)) {
|
||||
int idx = field[2].lastIndexOf(":");
|
||||
if(idx<0)
|
||||
return "USER user hostname localhost :realname";
|
||||
String realname = field[2].substring(idx+1);
|
||||
String ret = "USER "+field[1]+" hostname localhost :"+realname;
|
||||
return ret;
|
||||
} else if ("QUIT".equalsIgnoreCase(command)) {
|
||||
}
|
||||
|
||||
if ("QUIT".equals(command)) {
|
||||
return "QUIT :leaving";
|
||||
}
|
||||
|
||||
|
@@ -135,7 +135,7 @@ public class I2PTunnelIRCServer extends I2PTunnelServer implements Runnable {
|
||||
|
||||
/** keep reading until we see USER or SERVER */
|
||||
private String filterRegistration(InputStream in, String newHostname) throws IOException {
|
||||
StringBuffer buf = new StringBuffer(128);
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
int lineCount = 0;
|
||||
|
||||
while (true) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user