forked from I2P_Developers/i2p.i2p
Compare commits
1468 Commits
i2p-0.9.39
...
build-debi
| Author | SHA1 | Date | |
|---|---|---|---|
| c0a0aa7700 | |||
| 4a9131c39d | |||
| b47269f14e | |||
| fb317b44ba | |||
| e64e12b3fb | |||
| f71e59a049 | |||
| 169fb59d7d | |||
|
|
922178b2c7 | ||
|
|
74a9193ba5 | ||
|
|
335409f1d2 | ||
|
|
d6edb9e96c | ||
| f150855f1c | |||
|
|
655ce09796 | ||
|
|
91ebec15d5 | ||
|
|
b17d321503 | ||
|
|
a6398d88a9 | ||
|
|
59969db16c | ||
|
|
b68a5ea7fd | ||
|
|
c2234685b9 | ||
|
|
ce7daaa02a | ||
|
|
b19999f95a | ||
|
|
92ecc9f8e8 | ||
|
|
aa2ba92db8 | ||
|
|
5f3c41244b | ||
|
|
bf29132898 | ||
|
|
a424331b78 | ||
|
|
ccb0c279f7 | ||
|
|
7fe01fb9a7 | ||
|
|
66c4c10a78 | ||
|
|
163967311e | ||
|
|
75734448c5 | ||
|
|
aed1de84b8 | ||
|
|
51560a8ec8 | ||
|
|
ec89a80e80 | ||
|
|
41c7b7382a | ||
|
|
b4e1fbd857 | ||
|
|
517ff4fa24 | ||
|
|
106b1a696d | ||
|
|
6cab545c45 | ||
|
|
619923dbf8 | ||
|
|
ed0ecdf253 | ||
|
|
d42ef2223d | ||
|
|
e461004ed9 | ||
|
|
2e180d4c60 | ||
|
|
152ad1659b | ||
|
|
888311e34f | ||
|
|
2df5fb972a | ||
|
|
a481255adb | ||
|
|
139594df8f | ||
|
|
659ab97f69 | ||
|
|
963a4fe89c | ||
|
|
4c4dbae107 | ||
|
|
6978049416 | ||
|
|
46fe1ba74a | ||
|
|
13bd5e4938 | ||
|
|
bbacf85245 | ||
|
|
68f011f344 | ||
|
|
8bd2384ac8 | ||
|
|
54dda1a15f | ||
|
|
3f44a555ba | ||
|
|
86cbb2ed4e | ||
|
|
2569123055 | ||
|
|
afa4b9e66d | ||
|
|
67bd5a32fd | ||
|
|
ada3629507 | ||
|
|
dcb7314306 | ||
|
|
e3c2ad6354 | ||
|
|
178ea252d5 | ||
|
|
7e4ba4eb31 | ||
|
|
de43de17f6 | ||
|
|
2ceb9c429a | ||
|
|
0b59f53fe9 | ||
|
|
62fce859b9 | ||
|
|
9fc97764c5 | ||
|
|
2813d9412d | ||
|
|
a0bf76a4b1 | ||
|
|
d2a79e8837 | ||
|
|
738ef496d4 | ||
|
|
a2734ffa72 | ||
|
|
8606d30e9a | ||
|
|
a45084cfc3 | ||
|
|
eeaf6f3514 | ||
|
|
9e18ff1cd1 | ||
|
|
665239fd37 | ||
|
|
12f9a7187e | ||
|
|
8835351b99 | ||
|
|
a3c44912f2 | ||
|
|
db9f735376 | ||
|
|
875a7242d4 | ||
|
|
51ecdc64a4 | ||
|
|
7b785ea454 | ||
|
|
8f5fc44755 | ||
|
|
010dbfa6f2 | ||
|
|
e20a19c358 | ||
|
|
387e513949 | ||
|
|
5e005e6520 | ||
|
|
e88f40cd95 | ||
|
|
82e93a53a3 | ||
| fee5668c1c | |||
|
|
abb8cbe75d | ||
|
|
340df51429 | ||
|
|
bec8feb05a | ||
|
|
d86ccded53 | ||
|
|
db7d92a5cd | ||
|
|
30ffdd03c7 | ||
| 251d8de943 | |||
|
|
5e8de68746 | ||
|
|
8ae29c8c00 | ||
|
|
542efa0d9a | ||
|
|
23c80accfa | ||
|
|
b909430725 | ||
|
|
20b413bc67 | ||
|
|
a9b6b86183 | ||
|
|
66b724759d | ||
|
|
56059448c5 | ||
|
|
1c52eeb910 | ||
|
|
4aefe4bf7a | ||
|
|
b9444cdc51 | ||
|
|
eb72e4c9f5 | ||
|
|
aa181ee43f | ||
|
|
ab04f92072 | ||
|
|
0830329eaf | ||
|
|
2d154cc90e | ||
|
|
183280871f | ||
|
|
067ee80ba0 | ||
|
|
804e2f39f9 | ||
|
|
0ad7e52b71 | ||
|
|
e15110bbe1 | ||
|
|
2cffda6974 | ||
| 2300f6c226 | |||
| 1ed8a1b6f3 | |||
| c4ed7719e8 | |||
| a98fe45204 | |||
| 5a3e26453f | |||
| c259000cdb | |||
| d683f0d9eb | |||
| 48b8886224 | |||
| 1097220d31 | |||
| fdeae72d38 | |||
| f870bc2ccd | |||
| ec3bfa3cb7 | |||
| c3f7c5d154 | |||
| 127b93c1e2 | |||
| cd019f258f | |||
| 889b7361fe | |||
| 99f6d4aba4 | |||
| 69deddcbc7 | |||
| 58020b4b58 | |||
| df43e72a08 | |||
| 326e2c630c | |||
| 36fdfd529f | |||
| 94bdc9c5b3 | |||
| c60e51514c | |||
| 7dcbbf17c3 | |||
| 5551deb246 | |||
| 6e8fd42efd | |||
| 5020100ef8 | |||
| 6c2c6abfb9 | |||
|
|
4940c34779 | ||
|
|
6d5aebeaa0 | ||
| d8924119b5 | |||
| 4b445e7d35 | |||
| 17e47a0c93 | |||
| 2ffb570850 | |||
| aef2fb8ce0 | |||
| 875fcdfb94 | |||
|
|
151f856b0a | ||
| 337787be0e | |||
| 798521466d | |||
| 678c035fa3 | |||
| ccb4210f8b | |||
| 7e5dc6ad64 | |||
| 31622d0458 | |||
| f9b18545f9 | |||
|
|
e67eccd1eb | ||
|
|
cefe212a17 | ||
|
|
8a76d71bd5 | ||
|
|
806df95114 | ||
|
|
c6c0b9ce8a | ||
| 00a0970c95 | |||
| cb1bd95f2b | |||
| d12b52f82a | |||
| 891ffaac09 | |||
| 36fbf0e332 | |||
| e811238d60 | |||
| c9e6bef825 | |||
| 0f002b9b69 | |||
| f179a057bc | |||
| 6f5042be8f | |||
| 2044474549 | |||
| 0b0b93f26f | |||
| 595f8762ab | |||
| 8644eb431e | |||
| 223afdfc7e | |||
| de41cab08e | |||
| 3606a42ea8 | |||
| 6887c7edae | |||
|
|
4a00691385 | ||
|
|
1d0a2c4fac | ||
|
|
d0016380e5 | ||
| 29dc311c6a | |||
| 7aa78a1aed | |||
| 989f64192f | |||
| c908c6bd05 | |||
|
|
9f51b72cab | ||
| a2fd817915 | |||
| 5bafdd05a9 | |||
|
|
e18708bdbe | ||
|
|
f6687c1f88 | ||
|
|
b9eabca403 | ||
|
|
9ec2c62f2f | ||
| d4152ea546 | |||
| 8cc62b5b42 | |||
| e242015145 | |||
| 35da97936d | |||
| bfe21176ea | |||
| d1dd9ab517 | |||
| c18dbe974a | |||
| f69563da75 | |||
| 057eca56d5 | |||
| a21a64e0c6 | |||
| 751af5bcd8 | |||
| c8605009ba | |||
| 5625caebda | |||
| fc0a78dd7b | |||
| 90aab37002 | |||
| 5c1a529df0 | |||
| 6fa015c410 | |||
| 2d1e68b53b | |||
| 35012a3bad | |||
| 190b76d7fd | |||
|
|
8d0b1214d2 | ||
| 70eb2a49f9 | |||
| f231ea0951 | |||
| f9ffdd5137 | |||
|
|
38f9955391 | ||
| 517ff9af28 | |||
| 62a91acb40 | |||
| 69a5266675 | |||
| e671741329 | |||
| ab55f27ea4 | |||
| cf88b3057a | |||
| af97eedcbb | |||
| 7823001594 | |||
| a49f87179a | |||
| b52f85ac38 | |||
| 470bc77551 | |||
| a0822a6b71 | |||
| 15da2f85ad | |||
| 9b3ff9e615 | |||
| df1db163f0 | |||
| 4a4d814a17 | |||
|
|
c84360ba4b | ||
| 6a6064d614 | |||
| 49565a99f9 | |||
| ee27bc3bbf | |||
| 25899d41d5 | |||
| 35f6a2e2bf | |||
| 9ae5cbbc87 | |||
| 0ace93cec7 | |||
| d387448794 | |||
| 4d82917b94 | |||
|
|
7a77f48963 | ||
| dee5dfc682 | |||
| 5ed6f834c1 | |||
| 3b8e5f0763 | |||
| 7c1798513d | |||
| e54950e02e | |||
| b2f060795c | |||
| 940ad61ccc | |||
| c1f531ea92 | |||
| 0ebca7e8e3 | |||
| d301669726 | |||
| 010bb0a2fe | |||
| f028002c11 | |||
| 11e1747ffc | |||
| 5dc9333bb6 | |||
| f77acb6db6 | |||
| 22abf09bd7 | |||
| 9a1d7a2ae3 | |||
| 98e5908557 | |||
| 9e36fe090c | |||
| b4b6968ede | |||
| 999c4c51a2 | |||
| 8737a6a4fd | |||
| a9a5d13e06 | |||
|
|
ca1e2ba91e | ||
| 2e34969bbc | |||
| cead0b2fb8 | |||
|
|
9d566aea68 | ||
| 2d9933a4a9 | |||
| cd699c587b | |||
| 4108007b26 | |||
| b31b42a557 | |||
| c3f187abcb | |||
| 2989d955d9 | |||
| ea4409897d | |||
| 7dd7f021b0 | |||
| 2cb53ec45c | |||
|
|
8fa3e45e47 | ||
| c4a5d111e7 | |||
| dca45a9b18 | |||
| 6ffebbd5c1 | |||
| aa07775a32 | |||
| 30244f9d9b | |||
| 19d4a5ce26 | |||
| e4cb730c1b | |||
| 3b18e54545 | |||
| 2fbbd8e7d1 | |||
| e466331407 | |||
| 5d1f46e6c4 | |||
| 36318def69 | |||
| 72e4b16c1a | |||
| 8a10c3a097 | |||
| d402300dba | |||
| ada6753255 | |||
| ceb0749e0d | |||
| 4863ab3711 | |||
| c745cc8aa1 | |||
| 273902f616 | |||
| bb761aea96 | |||
| d13a7d2872 | |||
| 49b2ca061c | |||
|
|
3e23ec8d27 | ||
| 22eeb90b81 | |||
| 6a69cef2a8 | |||
| c1fef302f3 | |||
| bd370cf407 | |||
| feba993019 | |||
| 623a11dd8f | |||
| ba7fb00450 | |||
| 20b4186331 | |||
| 2479645d22 | |||
|
|
8585e2e955 | ||
|
|
14518dc396 | ||
| ccd64b6f07 | |||
| 21efdb9bd0 | |||
| 94778c74dc | |||
|
|
929c09fecc | ||
| c067f38123 | |||
| 046d1e01b0 | |||
| cc6247fe7e | |||
|
|
797a31924d | ||
| 87f9b619e5 | |||
|
|
4ac89e7024 | ||
| fceda68cd8 | |||
| 07fc66ccff | |||
| d7b512ca9a | |||
|
|
926f88585a | ||
| 717e1c58fa | |||
| 4b3dbd8915 | |||
|
|
9d31a41ffe | ||
|
|
217571118b | ||
|
|
b03e919cbe | ||
|
|
482b305065 | ||
|
|
27776cddb2 | ||
|
|
029e082cfc | ||
|
|
6087a46a0b | ||
| b78f6a645c | |||
| f8b04e398e | |||
| 097f178e2a | |||
| d221846c31 | |||
| fa08d2f946 | |||
| 336563e7c0 | |||
| f4ac8e02f6 | |||
| 29d2051a34 | |||
| e52359c4c0 | |||
| d73b327fd0 | |||
|
|
d1bdeae596 | ||
|
|
fa8bd4310c | ||
| 4f8f8b659b | |||
| 5a9eb68160 | |||
|
|
b97ec8da90 | ||
| a3fe0092ac | |||
| 896dbfbacf | |||
| 4d3561c92a | |||
|
|
3c7b658a59 | ||
|
|
6482437795 | ||
| 12e2dabaa8 | |||
| e05545ab7c | |||
| f0bcab2e2c | |||
| 075ac7ab43 | |||
| 31d7d7d9bb | |||
|
|
ed14aa130c | ||
| 81007c1a03 | |||
| 2e3ff679f3 | |||
| a84996399e | |||
|
|
7b872474fd | ||
|
|
531b7c2ae9 | ||
|
|
95f16c99bd | ||
|
|
462180f9a4 | ||
|
|
505c49ad01 | ||
|
|
16d6cf0177 | ||
| 112beb552b | |||
|
|
b53cdafc84 | ||
| 365b9053ec | |||
|
|
aadc9a13aa | ||
|
|
39f3e3a92c | ||
|
|
9a6374c79b | ||
| 3a392e84a9 | |||
| c119de6188 | |||
| 066833819b | |||
| c840f223cd | |||
| 4c2bf3e42f | |||
| 6ec95a7f13 | |||
| 670e57b9e5 | |||
|
|
d441ead884 | ||
|
|
38f654edd9 | ||
| 25b4d136b8 | |||
| 2b9783028d | |||
| 6c0e18d3e2 | |||
| e23f671ca3 | |||
| 2af7066074 | |||
| 220f641ba6 | |||
| 76493b398f | |||
| f1a277c4d7 | |||
| ac76d544b9 | |||
| cd77461fba | |||
| 326178ad47 | |||
| 0fce24479f | |||
| 3f895d32dd | |||
| 2af26f7d5b | |||
| 765d4ea725 | |||
| ec231ecd78 | |||
| 957767c985 | |||
| 3cc7374984 | |||
| 6461c8e880 | |||
| edfbc4081b | |||
| 317bf1e9db | |||
| f985004be0 | |||
| 4fd834d13e | |||
| 370f96acfb | |||
| d8b308dd9d | |||
| 3ad8f9b9a5 | |||
| 4fe9a27e2e | |||
| 686fe88e61 | |||
| 9b5e4373d4 | |||
| 03b1a4dfc0 | |||
| 27e422f81d | |||
| f3e821a65d | |||
| 3fac44874e | |||
| f8df7eba7f | |||
| 4574ebd8a9 | |||
| a00b9bb0c7 | |||
| e091eeae90 | |||
| 0a98147315 | |||
| e9cc4a4357 | |||
| 0ab4730002 | |||
| 31d7b6fb7d | |||
| 26e5f4c482 | |||
| 766649bd54 | |||
| bb6641ed96 | |||
| 6aa81f7ec6 | |||
|
|
a3fc8af1dd | ||
|
|
05082e3ffa | ||
|
|
4b655070d4 | ||
| f25037447d | |||
| df3a03afc5 | |||
| ded4bde905 | |||
|
|
e1d8e360a5 | ||
|
|
b373e253c9 | ||
| a9d84da3b3 | |||
| 4b7c62aa9c | |||
| e16c0a3271 | |||
| ef66457181 | |||
| 093c46c937 | |||
| d48d16d237 | |||
| 65cd84dd2e | |||
| c457ef68c7 | |||
| f00b86475d | |||
| 90bc00436c | |||
| 1af32bfe79 | |||
| 25338019ca | |||
| 878c11b36f | |||
| c6c9ba76d9 | |||
| a0261e8fd7 | |||
| d493028c1e | |||
| 3992ea235d | |||
| 31b527a4c4 | |||
| 09b647f283 | |||
| 40b312d7c1 | |||
| fad9d0e3da | |||
| 31a57b1a60 | |||
| 50e44ece54 | |||
| f233416bf6 | |||
| 1b3885720a | |||
| 82dd9435a3 | |||
| bc89d247ec | |||
| fe36482063 | |||
| a47f6d1b2e | |||
| 8aa23c7dc7 | |||
| 0eef0dd21b | |||
| a12a26f65c | |||
| 1ebed8b6aa | |||
| deb0fe338c | |||
| 005f79c95f | |||
| eeee8d7600 | |||
| 13cfdf0d5a | |||
| e77c3f23d3 | |||
| d157daea10 | |||
| 9aa36562b9 | |||
| 6a36b79a95 | |||
| 2cd2f25c56 | |||
| 8631db8769 | |||
| 7da2ac9ef3 | |||
| 4da58258f5 | |||
| 4f78040569 | |||
| 0738d1d1fb | |||
| e99e15209a | |||
|
|
96a8aa9d0c | ||
|
|
0bbd747f82 | ||
| e31b837a7f | |||
| ab7e428624 | |||
| 565e7f4d67 | |||
| 910de68495 | |||
| e904c9981e | |||
| ddc372f58c | |||
| 4ff234c110 | |||
| 69ef47e68c | |||
| 59901ec7c3 | |||
| 13e38f3d3e | |||
| 4b85f06951 | |||
| 08df2ba907 | |||
| 7a192b4961 | |||
| d18f622458 | |||
| 8a482659e0 | |||
| eeecede382 | |||
| d49741c2db | |||
| 2ac2850cd4 | |||
| 3d56545210 | |||
| 5de76252ea | |||
| 778d6a2809 | |||
|
|
f90cbaba5a | ||
| 6510e07b8b | |||
| 4996c05361 | |||
| 78effe14ad | |||
| 122b12fa31 | |||
| 438703a29b | |||
| 467a48cfe1 | |||
| 2b1c6a9d8f | |||
| f1307614c6 | |||
| ea8e340895 | |||
| 26af857dc7 | |||
| f04526d83a | |||
| a255a60944 | |||
| b4de0cfaf9 | |||
| 2188d6b222 | |||
| 0528e4109d | |||
| 47f09479ad | |||
| 80d24fa70d | |||
|
|
bef9ea11bf | ||
|
|
278090a772 | ||
| eab688b0bc | |||
| 788c72c331 | |||
| 90d9843acc | |||
| d7095b69b9 | |||
| dd96e29213 | |||
| fd3e181b7c | |||
| d7b5783674 | |||
| 634802c008 | |||
| 9e233b42a5 | |||
| 4cf8bfbe0d | |||
| e1beeb3653 | |||
| 82a918b37d | |||
| b6ecad3c0f | |||
| e9d56d85af | |||
| b874bb2ba0 | |||
| 7f179551b7 | |||
| 10be87bb59 | |||
| 5173d24c72 | |||
| f4a37ce75f | |||
|
|
ff4cfd3eb0 | ||
|
|
8b6d8507ec | ||
|
|
65356f09a6 | ||
|
|
b0c6c845bf | ||
|
|
6859baba9f | ||
|
|
c14541f4a3 | ||
|
|
1083d2939b | ||
| 2a8f23602a | |||
| da5c92a599 | |||
| baa26aec26 | |||
| 9da290831b | |||
| 882f853b1d | |||
| a7de9a7f24 | |||
| f2f6dfbf18 | |||
| 5e2db982dd | |||
| bc11e66429 | |||
| da8f49a712 | |||
| a97085ac67 | |||
| eb7211660f | |||
| b182562c80 | |||
| 25a80c78b5 | |||
| c69af8308f | |||
| 0cc1861649 | |||
| 57cd4c5843 | |||
| cd035e1247 | |||
| 73886d06e8 | |||
|
|
ae199581be | ||
| bf425d8ac9 | |||
|
|
823dc72eaa | ||
| 3716ccc3ef | |||
| 108b3a2363 | |||
| 35bb5896a1 | |||
| da9bfd48c0 | |||
|
|
0bd3df6d98 | ||
|
|
0656abd101 | ||
|
|
5299eb365f | ||
| 53eb0fe7f8 | |||
| 4cdaa11024 | |||
| e642d8e538 | |||
| cc5f13fc5e | |||
| 80f66113c4 | |||
| b3d5accca2 | |||
| 12ac06d5ba | |||
| 7b47d3f314 | |||
| 0d2dbcc8fc | |||
| e2cc62a21f | |||
| 689b26102b | |||
| c989addadc | |||
| 5e00bc6510 | |||
| 828311a24f | |||
| 5976d4952f | |||
| 80ae2ccea6 | |||
| 370b7f1124 | |||
| 26b90b9d17 | |||
| c8647fc3a5 | |||
| 3fa15824ee | |||
| 1752291ffd | |||
|
|
4edb9bbf7f | ||
|
|
e88a585703 | ||
| 928c0e9b91 | |||
| 83a4f5f2f0 | |||
| f54db66f77 | |||
| f16981d844 | |||
| f6b5a2d493 | |||
| 14b33a1e4c | |||
| c99adeeb61 | |||
| b979a97905 | |||
| 916b296ee0 | |||
| f9f64a441b | |||
| 2482df7121 | |||
| f9d7cfa7e1 | |||
| 5229c0e811 | |||
| 1ca9674f3f | |||
| c77e41c59e | |||
| 8c4410277d | |||
| 2ec9a4ab64 | |||
| 6b05acff8d | |||
| 471b53698a | |||
| 7404bdc4fd | |||
| 9307cc8a0c | |||
| 6dd0b23c61 | |||
| 97f002bfb5 | |||
| 22ca4d0e44 | |||
| 86fc6478f5 | |||
| dee92b5290 | |||
| b19b529afe | |||
| 0c4cf5d3cd | |||
| eeb7ea4cae | |||
| 23634afbc9 | |||
| acf3abb19b | |||
| c5435410ba | |||
| 786d68ce9a | |||
| 0170ff2337 | |||
| a5c0448053 | |||
| 7a1e2865fc | |||
| 0c19216c4c | |||
| f2787a8df6 | |||
| 7654a0af42 | |||
| 5c1700c2ab | |||
| 6487fb0516 | |||
| 42fb3bb2e9 | |||
|
|
f57876dc3b | ||
|
|
0a7027dd9b | ||
|
|
1154d28be7 | ||
| 0e68df6ba4 | |||
| 7707c4bb94 | |||
|
|
56639fa7d2 | ||
| f0a15d084a | |||
| de6cee8f6a | |||
| 8b075f26bf | |||
| 5455820a74 | |||
| d38c660c36 | |||
| 3f629ce1af | |||
| 29f9986f40 | |||
| d505a2fe76 | |||
| 3eb573295b | |||
| 0b9babab42 | |||
| c190ddd6b0 | |||
| 53118fa9c6 | |||
| 8cf241f6da | |||
| 6774af6910 | |||
| eb73f0aae2 | |||
| 0bec84a3b1 | |||
|
|
75c2d24c45 | ||
|
|
53e77df77d | ||
| 326a85ea4f | |||
| e567f7b460 | |||
| ab28ee960e | |||
| 88a4261b03 | |||
| e7a66659e9 | |||
| 44a935d086 | |||
| 1e5414f74f | |||
| 357d400bc6 | |||
| 594f1c7f8b | |||
| 4a845f0b73 | |||
| bc791f91ab | |||
| f938090d6a | |||
| d9ea6b1f9c | |||
| 5bed4a0d7f | |||
| 4826bbd333 | |||
| 0540c76c51 | |||
| f081e88420 | |||
| 4030d0b427 | |||
| c5f6c9a498 | |||
| 403440bab8 | |||
| 8ed7a029d7 | |||
| ec6807cd2c | |||
| 226494028a | |||
| 4bcd896829 | |||
| 2524a7a69d | |||
| 2805388a4c | |||
| 631a082ebd | |||
| 24b98b86c2 | |||
| 5ee903765e | |||
| c0db50ed0f | |||
| 3403ea3b51 | |||
| daf595ab7e | |||
| fd958df118 | |||
| dd794ceee4 | |||
| c19a63c6a2 | |||
| 84bea6438f | |||
| d3bd2ce190 | |||
| e82f420ee6 | |||
| a035901f0a | |||
| e73ddb548a | |||
| fd87c609f2 | |||
| 17060c0100 | |||
| fe16ccb434 | |||
| a46100bde5 | |||
| 0478ac75e9 | |||
| d42235486e | |||
| dd3dbbf7f9 | |||
|
|
efe85cc30a | ||
|
|
0b3e6acb97 | ||
|
|
aa6c218122 | ||
|
|
033c37f4a0 | ||
| e7ddee5509 | |||
| f8283c04ca | |||
| 0f7bcbf4bb | |||
|
|
c4fce448c3 | ||
| c4c75c0ce5 | |||
| 2988e58cb2 | |||
|
|
21ae518102 | ||
| 8bebb884c3 | |||
| 4401265200 | |||
|
|
094613b8de | ||
|
|
6e38cce149 | ||
|
|
9c626a07c5 | ||
|
|
80db2faeb7 | ||
|
|
b31eb3f53b | ||
|
|
b572a330ed | ||
| 98f7f30864 | |||
| 23d24a48b5 | |||
| 064e4046a6 | |||
|
|
50c86147b0 | ||
| 3c9e78bd76 | |||
| f65cfbf92c | |||
|
|
4ad4e579d8 | ||
|
|
1f6b3c1107 | ||
| a2a646e1f5 | |||
| ea05af42fa | |||
|
|
520faf477d | ||
|
|
cf2a4ba053 | ||
| 1a0b25a6ef | |||
| 23598ab011 | |||
| 7ac189696b | |||
| ecdccac37e | |||
| e865f451ca | |||
| 3d80f0122f | |||
| 0a34f3d5dd | |||
|
|
b588297458 | ||
|
|
b524e91888 | ||
|
|
29f8fec912 | ||
| 09d31cb107 | |||
| fa9f60bcd9 | |||
| 63b48e30be | |||
| e714e7082e | |||
| 9966c40d28 | |||
| 9dbec9fbb5 | |||
| aa472feea9 | |||
| c7a6584481 | |||
| ae994e3230 | |||
| fcd8a3ae69 | |||
| ccaf4ce4b9 | |||
| 5772b7d9ae | |||
| 61ec10ff47 | |||
| c3138793fe | |||
| c5904b080b | |||
| 7d10ef7a19 | |||
| 938410d68b | |||
| dd0d84fece | |||
| b2aa649c2a | |||
| 74020ae5a3 | |||
| 6f3cfd83cd | |||
| 10b8c92fdb | |||
| 520da91735 | |||
| d73fc85c34 | |||
| 4eca698584 | |||
| 3fa3b69cbc | |||
| bf94460420 | |||
| d054652952 | |||
| ad3c978c7c | |||
| 3277ea4854 | |||
| 7b6e25db8b | |||
| 1974cc5559 | |||
| 9c534fda7b | |||
| a5efce883a | |||
| 6197454225 | |||
| 64e9e2aebe | |||
| faf130cf38 | |||
| 831c1945a5 | |||
| 26ecf364a6 | |||
| 74b61a7ba6 | |||
| d65208b917 | |||
| bf70a1520b | |||
| 3a3416d2a5 | |||
| 00667151da | |||
| a9abf3babf | |||
| cad3c46ea6 | |||
| 9289a6daa9 | |||
|
|
f2f29d6a6c | ||
|
|
3e888f8936 | ||
|
|
cbccba8dc2 | ||
| 7cfc16ca36 | |||
| f7a2d23f1e | |||
| 31e8ff8f45 | |||
| 3a7ee4f211 | |||
| cc3c2d4d1a | |||
| 11d89e248e | |||
| 2bb94bea80 | |||
| 2bfd421b19 | |||
| 4c9c83231b | |||
| 32044f1682 | |||
| 51f7348d8a | |||
|
|
ae345cfb85 | ||
|
|
52edc35275 | ||
|
|
d5bc948bb4 | ||
|
|
86ff3420b5 | ||
| 6b0e3750c9 | |||
| 600c681143 | |||
| e1189b9c9f | |||
| 9feeb76d6c | |||
| 9f02b27c4a | |||
| 345cdd3eb0 | |||
| def1e2ec68 | |||
| 62c9ae67d0 | |||
| 10b756b726 | |||
| bf9d136a2b | |||
|
|
9ffd71e0b8 | ||
| 6fa13313f0 | |||
| 27fa991783 | |||
|
|
09f6429b5f | ||
|
|
252a7972a1 | ||
|
|
131ebc4d5a | ||
| 4e81e48d64 | |||
| 7b391fa17a | |||
| 5e67f4232a | |||
| 398b4ceade | |||
| 03f4624f91 | |||
| 79334afcbc | |||
| c711d48835 | |||
| 394db0b307 | |||
| 8bb1347e6e | |||
| e22810fd93 | |||
| 8218d55874 | |||
| 652b75a749 | |||
| 620917cd70 | |||
| b8ed77da9a | |||
| 65b3cdbb12 | |||
| cecf255706 | |||
| a854ccee69 | |||
| 6e2ad50e16 | |||
| fdb3c68d3f | |||
| d2e2109799 | |||
| 9f0c3ee345 | |||
| 725509fe5c | |||
| 13318a12da | |||
| e8bf2ee30d | |||
|
|
eda91af7c7 | ||
| 9ddb655a88 | |||
| 9d46a5d838 | |||
|
|
f7471713da | ||
|
|
b5d7f3e460 | ||
|
|
7b53b0d3ad | ||
|
|
ff293d50a9 | ||
| 552100da17 | |||
| a2b23f96e8 | |||
| 14499c2993 | |||
| dfc533b6e8 | |||
| 2738b3d29c | |||
| 07b7ab4262 | |||
| b7f6cfbf46 | |||
| ebc8dbe947 | |||
| 01d6cea017 | |||
| 160bcd7da8 | |||
| bc40978297 | |||
| 656dd42276 | |||
| 4d1d11d1d4 | |||
| 3ae5b90c98 | |||
| 2846c33b40 | |||
| b5f6c58a0b | |||
| 3ba48fda86 | |||
| 7c4569816f | |||
| 0cd8073f39 | |||
| 71411be6d9 | |||
| a51ee8e745 | |||
| 3719081469 | |||
| 2216a58143 | |||
| dc29525e5c | |||
|
|
e5163c6ee5 | ||
|
|
c5db5f0de3 | ||
| 3d75b3dc31 | |||
| 591b994b75 | |||
| 135e9ad31f | |||
| eee9e47cac | |||
| df6465f802 | |||
| 0c256d30c7 | |||
| 43c93bceed | |||
| f021abcae0 | |||
| 7b28640e91 | |||
| 6a47319b66 | |||
| ee46678955 | |||
| 8c498069d8 | |||
| 7389216560 | |||
| 129e474ecb | |||
| 3ed8620e5a | |||
| 436a8b8720 | |||
| 5d8871c17c | |||
| d84fc4f0c8 | |||
| 2c2f90089b | |||
| 236354e5a8 | |||
| aa3d2f39b1 | |||
| fb67ebb38d | |||
| a9d4798bfe | |||
| 8484a22fc4 | |||
| 0f7ebf2f71 | |||
| db37745a1c | |||
| b12e7214c8 | |||
| 079d464629 | |||
| 6dd2e9bb6b | |||
| 413eb7d0eb | |||
| 68a03b835a | |||
| eef6c5cb33 | |||
| 652f9bb6a0 | |||
| ab7b85cc1a | |||
| 2335f547f7 | |||
| 701f777035 | |||
| 77259293a8 | |||
| 4e231b26c3 | |||
| 9889d1adcb | |||
|
|
2377b1adde | ||
| 47aa6101d4 | |||
| 7161785c5b | |||
| 2ca9fe2050 | |||
| 1095a140de | |||
|
|
0485e690c6 | ||
|
|
20103957a9 | ||
| 9670858095 | |||
|
|
2bc8d58476 | ||
| 70fd0c6f6a | |||
| 2b1a7015e4 | |||
| e8404a75fb | |||
| 05c30b4f1d | |||
| 29eabc4706 | |||
| 049b34f7cf | |||
| 31f2c51e7e | |||
| 71cc55fa7d | |||
|
|
68a65d5cac | ||
|
|
e4c5c4862f | ||
|
|
cb2544157f | ||
| 612bdda281 | |||
| db5dd6a626 | |||
|
|
16db73b092 | ||
|
|
c259abc82c | ||
|
|
99b33fabe6 | ||
|
|
81133a1a95 | ||
|
|
9b3380cef3 | ||
|
|
87ba8577e9 | ||
| aca5617935 | |||
|
|
e44a7c5054 | ||
| 142508c872 | |||
| 788e041939 | |||
| 3563fdf9e4 | |||
| ea8ac884fa | |||
| bf33e8432d | |||
| 18ed1a6bb3 | |||
| 830e08065b | |||
| c1722a9f82 | |||
| e5475bc229 | |||
|
|
d81bf6a417 | ||
| 3710ff9aa1 | |||
|
|
679aa1afac | ||
| 320569ef7f | |||
| 4f0d764540 | |||
| a768afe05b | |||
| d15e068123 | |||
| c1431565ed | |||
| 2b6cb2099a | |||
| f9a2193e2f | |||
| 0d325d5a28 | |||
| 520da24e0c | |||
| 69638caa7b | |||
| 62914d7678 | |||
| 94c96b09e9 | |||
| 0c2a8e9244 | |||
| 67cd6409a0 | |||
| 65d0ea3f0b | |||
| f1b725a320 | |||
| 9e39cbe502 | |||
| 8d104f7fea | |||
| e66d64d89b | |||
| 9d28b17a04 | |||
| 43f055ec28 | |||
| b4a5cc07c2 | |||
| 479461ab3b | |||
| c99a42f0b1 | |||
| 65698aa0da | |||
| 7f75d0254c | |||
| 331ecf0625 | |||
| 32d420e76f | |||
| ee5a22be24 | |||
| b51962aeac | |||
| e73640bb8d | |||
| 92515179e9 | |||
| c5f126c196 | |||
| bb88555a63 | |||
| e03a94647c | |||
| 8eda9abab7 | |||
| aed6d433c8 | |||
| 71376d53c5 | |||
| 9a84f77fab | |||
| 2590fd8253 | |||
| ea3bddbcd6 | |||
| d04f0dae37 | |||
| 3504bddea4 | |||
| b3a5f1f8c1 | |||
| 0f2f7e2454 | |||
| b119d0be43 | |||
| 566221b732 | |||
| 81ab35abe6 | |||
| b2e37243ab | |||
| a6e3621c06 | |||
| 96d8385f49 | |||
| 912d25b775 | |||
| 55cdd81017 | |||
| a1c18fd0aa | |||
| 5f3da69acc | |||
| e6dcfaee15 | |||
| f724b2208b | |||
| 89b70895d7 | |||
|
|
cff2ae3ac9 | ||
| ec0f8566b6 | |||
| 2ebe59436a | |||
| dcf6983607 | |||
| 1779202ff9 | |||
| 6483abe7cf | |||
| 6618561237 | |||
| d8c9b0942f | |||
| 9938e50528 | |||
| 232b7f30d5 | |||
| adba7e4c25 | |||
| 764f89f5c5 | |||
| 87180e0e2d | |||
|
|
6789a735e3 | ||
|
|
65eb9b17db | ||
| 64ba43c007 | |||
| b2dec2f4b2 | |||
| 789f482373 | |||
| a667c36d2d | |||
| 65e2132a25 | |||
| 5e76118ffd | |||
| 131a70057e | |||
|
|
21ace66a46 | ||
|
|
459eb7fdcd | ||
|
|
8586c28b5f | ||
|
|
f32c863ba8 | ||
|
|
ee84e7e3e1 | ||
|
|
cf4298f759 | ||
|
|
13190931b9 | ||
| 08be6a4f4a | |||
| 7f015c4794 | |||
| 7b46d43492 | |||
| a4bcff093f | |||
| fb7b3c2793 | |||
| 397bf43147 | |||
| 49af26d958 | |||
| 0ce4811dec | |||
| d3e3ec4d35 | |||
| 8ed0dd2a5c | |||
| 8158753dac | |||
| e3481f6730 | |||
| 165beb3fbd | |||
| 5d367940d5 | |||
| 617294b7fa | |||
| 240d59393f | |||
| 6b94dc2dbd | |||
| 3a0873c991 | |||
| 72ef065ab7 | |||
| 66ecdb2f7a | |||
| e2980603b7 | |||
| 885e0468b2 | |||
| 3bfbb6aef6 | |||
| 365820172a | |||
| d73058fd65 | |||
| 7374484ccb | |||
|
|
7d4229acab | ||
|
|
41128f1457 | ||
|
|
61f45b3a3a | ||
|
|
aaacb2e558 | ||
|
|
9c2dc47a8a | ||
|
|
2db0a65425 | ||
| fd781f4894 | |||
|
|
4a099854f7 | ||
|
|
ff379c36cb | ||
|
|
d5970f17de | ||
|
|
595e43b8a4 | ||
| 6adc665fd3 | |||
| 1be569db7a | |||
| 63e75ed307 | |||
| 6b990689cc | |||
| 3e48bf80f1 | |||
| 5341166e95 | |||
| 685088ccca | |||
| 7a64505139 | |||
| df223af23d | |||
| 8d74a196cf | |||
| 26d74620a9 | |||
| e458361193 | |||
| fea35512a7 | |||
| d5dda73742 | |||
| 86fd8ce391 | |||
| e24333206e | |||
| 0231d5eec2 | |||
| 258aea136e | |||
|
|
44e1b6058f | ||
| 051e18f9c7 | |||
| a66fb815a6 | |||
| 3e8386382b | |||
| 87109c8fef | |||
| 7ecee9dfdb | |||
| 9dc24d5f27 | |||
| e6b5fc8fd4 | |||
| b52e8d6b5c | |||
| ce6551dacd | |||
| f7d785b6d2 | |||
| 27e060eee5 | |||
| cf1c1bb3f7 | |||
| 85a2c9026a | |||
| d084f93506 | |||
| 8433f658f8 | |||
| 2cdb86fa1e | |||
| d8e06a0d14 | |||
| c1418a1c2e | |||
| b99f239f3d | |||
| 1a030c3f92 | |||
| 41e9bfc6b7 | |||
| f40655fc2f | |||
| 845e5ed37c | |||
| 019c3171c4 | |||
| 93a3f09971 | |||
| 51457bd873 | |||
| ebe95fc575 | |||
| 6d8431a77e | |||
| a8f2745169 | |||
| 61cdc7c7d2 | |||
| 3aeadaa719 | |||
| a542b182ea | |||
| 1ddc651b11 | |||
| b0bca2f16c | |||
| d9775a5f10 | |||
| ea2ef7b127 | |||
| 6d9aa92ed0 | |||
| 0c54b6d9da | |||
| 5ede0a139c | |||
|
|
2918d6006f | ||
| 2c97dc2bcd | |||
| 7e6a92ab7b | |||
| 46ad48d5d1 | |||
| 2c24a68135 | |||
|
|
357feca7b1 | ||
|
|
920a83ddab | ||
|
|
42e3406529 | ||
|
|
7336f64c26 | ||
|
|
c1731f68fa | ||
| 5ed953e11e | |||
|
|
e4892c6d5c | ||
| 1a200a16cc | |||
| e50bf00fa8 | |||
| e75881d6cc | |||
| 75ace4266e | |||
| e82a547bce | |||
| 6d72aeed8c | |||
| c01bf47c8a | |||
| 4bd0f06cd6 | |||
| aab6529f62 | |||
| 11c8e8e794 | |||
| 0d1dbc7992 | |||
| 7cd60bb0e7 | |||
| 697b617c7a | |||
| fe6c7cd41f | |||
| eea0990b54 | |||
| aa0bafb8a8 | |||
| c4ebc7357d | |||
| 471c5d49d1 | |||
| eff2bdbf87 | |||
| b5de81582f | |||
| 500246ebed | |||
|
|
38f135ceb9 | ||
|
|
0a1a2ed82a | ||
| 0a774c6c58 | |||
| f44a8e49c5 | |||
| 1109331dfc | |||
| 8a4c4694ec | |||
| b4f331e621 | |||
| 67224858b7 | |||
| 447e29e381 | |||
| aae81a7b5f | |||
| f049319500 | |||
| 6b3896c1f8 | |||
| 652c3d5dc2 | |||
| 4d29bfefde | |||
| 16ac93c36b | |||
| 040e092153 | |||
|
|
098bde2a32 | ||
|
|
f94d2d5578 | ||
| 30a34acd41 | |||
| dca04f7f60 | |||
| 307a8239fb | |||
| e189236e3e | |||
| a3fe7467c3 | |||
| 973aab8f53 | |||
| 0c7c19451c | |||
| 73b00eb206 | |||
| 90e6458428 | |||
|
|
4fdcd25671 | ||
| c2e2cc2e57 | |||
| 2abd59e6d4 | |||
|
|
65481ad61e | ||
| 47c64c2eef | |||
| 7bdfd071ae | |||
| 7858dbe757 | |||
|
|
8466cdc675 | ||
| ea5ddfcf36 | |||
| 332898351c | |||
| 2ec34f4827 | |||
| 7489a64e6c | |||
| 06fa817bde | |||
| cb762356da | |||
| 62649a6343 | |||
| a6434fb71e | |||
| a8f11d1834 | |||
| 67e7e45779 | |||
| cafdca9a7b | |||
| 7efb290f13 | |||
| b3cb09481c | |||
| f543a45a72 | |||
| 099cacd3e3 | |||
| b89720e710 | |||
| 1ffc006b2e | |||
| f2f5df0db4 | |||
| 10354df425 | |||
| 03bd3e2db3 | |||
| 11b391bc35 | |||
| a6e6d29d33 | |||
| 6600f373da | |||
| efa72dbb56 | |||
| 4e267f690d | |||
| 05318013e2 | |||
| 8840532ed0 | |||
| 48a92ca1e7 | |||
| ff71540428 | |||
| f04b41c99a | |||
| 847ebda3e2 | |||
| e174a46801 | |||
| 04a985cd8c | |||
| adb1c6f58e | |||
| 9eec35713c | |||
|
|
f6efdceaca | ||
| c1adcfcc19 | |||
| 0a7330393d | |||
| 63b2f29633 | |||
| d8980d10a4 | |||
| c7d052646e | |||
| de8a079cb4 | |||
| fc8b55df27 | |||
| be6b200945 | |||
| cbeaca66a2 | |||
| 585778cddc | |||
| cb0235bb5d | |||
| 558592a87f | |||
| 41e8b6dfbb | |||
|
|
5aae625788 | ||
| 16d2bdc1db | |||
| edb352b9d0 | |||
| ffbf3d2023 | |||
| 0147f003c4 | |||
| 50d93b1993 | |||
| a39549a3d9 | |||
|
|
9adabadeb9 | ||
|
|
61303bfd0b | ||
|
|
e45963dbcb | ||
|
|
5f689ccbd4 | ||
|
|
17bb36deee | ||
|
|
0b50c36c8a | ||
|
|
feaa82181f | ||
|
|
803447b4c3 | ||
|
|
e93fb5c084 | ||
|
|
6a418ebcab | ||
|
|
67ca6e6552 | ||
|
|
540e7c37e0 | ||
|
|
7cb0c9bbb4 | ||
|
|
66deb5dc7e | ||
|
|
3e10745717 | ||
|
|
84419bbf0b | ||
|
|
d81f993f81 | ||
|
|
8453c5cce0 | ||
|
|
b2b047b4aa | ||
|
|
7aa68c0a2b | ||
|
|
811d1ccf9d | ||
|
|
2af1f68d84 | ||
|
|
56eb11bc17 | ||
|
|
214efb8ef9 | ||
|
|
d1631643a5 | ||
|
|
315d7728d8 | ||
|
|
647f9e728f | ||
|
|
fa2897d2f8 | ||
|
|
539f880f9b | ||
|
|
9caa7a61b0 | ||
| 52b14142bb | |||
| 7f60ee9f8b | |||
| b9726a0af8 | |||
| bb86c56e77 | |||
| 8cdeff74c7 | |||
| acf5c314de | |||
| 20413f00c0 | |||
| aa551acec4 | |||
| f088ea1263 | |||
| 46e31746b4 | |||
| 981737f8ed | |||
|
|
5f01796bae | ||
| b2575643a8 | |||
| baeaa65829 | |||
| 5afa32a393 | |||
| ca0f12782b | |||
| 148ed1e3a0 | |||
| 6f86522c2b | |||
| 5db67f13e1 | |||
| 21504f1539 | |||
|
|
fd311c7e1a | ||
|
|
7c71ff106b | ||
|
|
d13bf0b72a | ||
|
|
9e0934f958 | ||
|
|
1cc330ba66 | ||
|
|
967dde4395 | ||
|
|
278870606b | ||
|
|
e70a2c765b | ||
| 31856e8895 | |||
| 22aefa2042 | |||
|
|
aeded8c495 | ||
| 3248a15d59 | |||
| 5c81c00a18 | |||
| ea7ddaf6d5 | |||
| a8ad30b335 | |||
| 67570db664 | |||
| 87d8d69a20 | |||
|
|
e967b26f5a | ||
|
|
e5540d051f | ||
|
|
7ce81db9a8 | ||
| e42e04c0f0 | |||
| d32d5b5f29 | |||
| 8d00774b5e | |||
|
|
89b38f4fff | ||
| 0dbc809111 | |||
| 64c7625524 | |||
| 071e702e56 | |||
| 363317fc26 | |||
| f4d7a6d0d4 | |||
| b5a4f1626f | |||
| 73790e2353 | |||
| dd5f8b45ef | |||
| 2960156b33 | |||
| 9a72c4b2d1 | |||
| 7d4acb62d0 | |||
| cddace2a1d | |||
| 859584c2b3 | |||
| 6237fc89ad | |||
| cde53537af | |||
| 5490de1d61 | |||
|
|
488e89a0b4 | ||
|
|
4774cf6c37 | ||
| 7c7b0cb7fd | |||
|
|
6aeb89ccd0 | ||
| 6cc39a2672 | |||
|
|
cca68f9b79 | ||
|
|
904bf2a90b | ||
|
|
8a001adf59 | ||
|
|
2c602fa46b | ||
|
|
1c90985f93 | ||
|
|
3498ab05f4 | ||
|
|
d809b592c9 | ||
| c3aa459872 | |||
| d389b3b57c | |||
|
|
76ee5774c4 | ||
|
|
b7d980df06 | ||
|
|
491cd0aa46 | ||
|
|
e380b26798 | ||
|
|
4790a14542 | ||
|
|
194df9d88c | ||
| 567bccb51c | |||
| 0e8e3688f7 | |||
| d3170de74a | |||
| 908bf26151 | |||
|
|
e55702b219 | ||
|
|
c0c95827ef | ||
|
|
fc9ad32878 | ||
| 7d40dfe1e5 | |||
|
|
2304e9b558 | ||
| 944fe4794e | |||
| 7501e3feea | |||
| eb0920e2c7 | |||
|
|
956a714d6e | ||
|
|
3f990b0bc8 | ||
|
|
3dbe8f2003 | ||
|
|
d90fc421fd | ||
|
|
85db853d74 | ||
|
|
440d5571fa | ||
|
|
910a0d859d | ||
|
|
c5f9aea557 | ||
|
|
84ea533b11 | ||
|
|
fd2819c754 | ||
|
|
fd6cb07e5d | ||
|
|
6d2270a1ed | ||
|
|
94bde1d821 | ||
| ba801be24f | |||
|
|
e919271247 | ||
|
|
d2bdbcd27d | ||
|
|
97eb5a56ab | ||
|
|
473ced4d4a | ||
|
|
c7771095d3 | ||
| ea127d3fd4 | |||
|
|
b35762b4bb | ||
|
|
3f6fc7c0fb | ||
| 82eea0a8f9 | |||
|
|
670016e79c | ||
| 14492d7269 | |||
| de9d968b76 | |||
| 7bb7677604 | |||
|
|
841b16ef72 | ||
|
|
0d0dd1e241 | ||
|
|
62f7b2cece | ||
|
|
a5e568ffa1 | ||
| 64039ee3c2 | |||
| ce043943d9 | |||
| fea5bd4ada | |||
| 00d4525325 | |||
| f17776ec54 | |||
| 05845481d1 |
31
.dockerignore
Normal file
31
.dockerignore
Normal file
@@ -0,0 +1,31 @@
|
||||
.idea
|
||||
.git
|
||||
Dockerfile
|
||||
|
||||
|
||||
# Gradle
|
||||
.gradle
|
||||
build
|
||||
apps/BOB/build
|
||||
apps/addressbook/build
|
||||
apps/desktopgui/build
|
||||
apps/i2pcontrol/build
|
||||
apps/i2psnark/build
|
||||
apps/i2ptunnel/build
|
||||
apps/imagegen/build
|
||||
apps/jetty/build
|
||||
apps/jrobin/build
|
||||
apps/ministreaming/java/build
|
||||
apps/ministreaming/build
|
||||
apps/routerconsole/build
|
||||
apps/sam/build
|
||||
apps/streaming/build
|
||||
apps/susidns/build
|
||||
apps/susimail/build
|
||||
apps/systray/build
|
||||
core/java/build
|
||||
core/build
|
||||
installer/build
|
||||
router/java/build
|
||||
router/build
|
||||
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -54,4 +54,10 @@ sloccount.sc
|
||||
.settings/
|
||||
# IDEA
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# Gradle
|
||||
.gradle
|
||||
|
||||
# TODO: why does this file appear?
|
||||
apps/routerconsole/jsp/favicon.ico
|
||||
|
||||
66
.gitlab-ci.yml
Normal file
66
.gitlab-ci.yml
Normal file
@@ -0,0 +1,66 @@
|
||||
image: openjdk:8-alpine
|
||||
|
||||
stages:
|
||||
- test
|
||||
|
||||
cache:
|
||||
key: ${CI_COMMIT_REF_SLUG}
|
||||
paths:
|
||||
- $HOME/.gradle/caches/
|
||||
- $HOME/.gradle/wrapper/
|
||||
- .gradle
|
||||
|
||||
test:
|
||||
stage: test
|
||||
coverage: '/Total.*?([0-9]{1,3})%/'
|
||||
before_script:
|
||||
- apk add --no-cache grep
|
||||
script:
|
||||
- ./gradlew codeCoverageReport
|
||||
# The actual output that will be parsed by the code coverage
|
||||
- grep -oP "Total.*?%" build/reports/jacoco/html/index.html
|
||||
only:
|
||||
- merge_requests
|
||||
- tags
|
||||
|
||||
# Make sure we can build a docker image
|
||||
# It's cached for later jobs
|
||||
build_docker:
|
||||
stage: test
|
||||
image: docker:19.03.12
|
||||
services:
|
||||
- docker:19.03.12-dind
|
||||
script:
|
||||
# Try to load latest branch image from local tar or from registry
|
||||
- docker load -i ci-exports/$CI_COMMIT_REF_SLUG.tar || docker pull $CI_REGISTRY_IMAGE:latest || true
|
||||
- docker build --cache-from $CI_REGISTRY_IMAGE:latest --tag $CI_REGISTRY_IMAGE:latest .
|
||||
- mkdir -p ci-exports/
|
||||
- docker save $CI_REGISTRY_IMAGE:latest > ci-exports/$CI_COMMIT_REF_SLUG.tar
|
||||
variables:
|
||||
# When using dind service, we need to instruct docker to talk with
|
||||
# the daemon started inside of the service. The daemon is available
|
||||
# with a network connection instead of the default
|
||||
# /var/run/docker.sock socket. Docker 19.03 does this automatically
|
||||
# by setting the DOCKER_HOST in
|
||||
# https://github.com/docker-library/docker/blob/d45051476babc297257df490d22cbd806f1b11e4/19.03/docker-entrypoint.sh#L23-L29
|
||||
#
|
||||
# The 'docker' hostname is the alias of the service container as described at
|
||||
# https://docs.gitlab.com/ee/ci/docker/using_docker_images.html#accessing-the-services.
|
||||
#
|
||||
# Specify to Docker where to create the certificates, Docker will
|
||||
# create them automatically on boot, and will create
|
||||
# `/certs/client` that will be shared between the service and job
|
||||
# container, thanks to volume mount from config.toml
|
||||
DOCKER_TLS_CERTDIR: "/certs"
|
||||
# Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled
|
||||
DOCKER_HOST: tcp://docker:2376
|
||||
cache:
|
||||
# The same key should be used across branches
|
||||
key: "$CI_COMMIT_REF_SLUG"
|
||||
paths:
|
||||
- ci-exports/*.tar
|
||||
only:
|
||||
- master
|
||||
- merge_requests
|
||||
- tags
|
||||
|
||||
6
.idea/ant.xml
generated
6
.idea/ant.xml
generated
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AntConfiguration">
|
||||
<buildFile url="file://$PROJECT_DIR$/build.xml" />
|
||||
</component>
|
||||
</project>
|
||||
41
.idea/compiler.xml
generated
41
.idea/compiler.xml
generated
@@ -1,41 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel>
|
||||
<module name="addressbook_main" target="1.7" />
|
||||
<module name="addressbook_test" target="1.7" />
|
||||
<module name="BOB_main" target="1.7" />
|
||||
<module name="BOB_test" target="1.7" />
|
||||
<module name="core_main" target="1.7" />
|
||||
<module name="core_test" target="1.7" />
|
||||
<module name="desktopgui_main" target="1.7" />
|
||||
<module name="desktopgui_test" target="1.7" />
|
||||
<module name="i2psnark_main" target="1.7" />
|
||||
<module name="i2psnark_test" target="1.7" />
|
||||
<module name="i2ptunnel_main" target="1.7" />
|
||||
<module name="i2ptunnel_test" target="1.7" />
|
||||
<module name="installer_main" target="1.7" />
|
||||
<module name="installer_test" target="1.7" />
|
||||
<module name="jetty_main" target="1.7" />
|
||||
<module name="jetty_test" target="1.7" />
|
||||
<module name="jrobin_main" target="1.7" />
|
||||
<module name="jrobin_test" target="1.7" />
|
||||
<module name="ministreaming_main" target="1.7" />
|
||||
<module name="ministreaming_test" target="1.7" />
|
||||
<module name="router_main" target="1.7" />
|
||||
<module name="router_test" target="1.7" />
|
||||
<module name="routerconsole_main" target="1.7" />
|
||||
<module name="routerconsole_test" target="1.7" />
|
||||
<module name="sam_main" target="1.7" />
|
||||
<module name="sam_test" target="1.7" />
|
||||
<module name="streaming_main" target="1.7" />
|
||||
<module name="streaming_test" target="1.7" />
|
||||
<module name="susidns_main" target="1.7" />
|
||||
<module name="susidns_test" target="1.7" />
|
||||
<module name="susimail_main" target="1.7" />
|
||||
<module name="susimail_test" target="1.7" />
|
||||
<module name="systray_main" target="1.7" />
|
||||
<module name="systray_test" target="1.7" />
|
||||
</bytecodeTargetLevel>
|
||||
</component>
|
||||
</project>
|
||||
3
.idea/copyright/profiles_settings.xml
generated
3
.idea/copyright/profiles_settings.xml
generated
@@ -1,3 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="" />
|
||||
</component>
|
||||
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="javax.servlet.jsp-2.2.0.v201112011158">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jsp/javax.servlet.jsp-2.2.0.v201112011158.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
22
.idea/libraries/jettylib.xml
generated
22
.idea/libraries/jettylib.xml
generated
@@ -1,22 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="jettylib">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-security-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-servlets-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-deploy-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-util-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-servlet-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-http-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-xml-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-server-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/servlet-api-3.0.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-jmx-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-webapp-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-io-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-continuation-8.1.17.v20150415.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/lib/jetty-rewrite-8.1.17.v20150415.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/jrobin_1_5_9_1.xml
generated
9
.idea/libraries/jrobin_1_5_9_1.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="jrobin-1.5.9.1">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/apps/jrobin/jrobin-1.5.9.1.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
10
.idea/libraries/lib.xml
generated
10
.idea/libraries/lib.xml
generated
@@ -1,10 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="lib">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/apps/susidns/src/lib/jstl.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/susidns/src/lib/standard.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/start.xml
generated
9
.idea/libraries/start.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="start">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/jetty-distribution-8.1.17.v20150415/start.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/systray4j.xml
generated
9
.idea/libraries/systray4j.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="systray4j">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/apps/systray/java/lib/systray4j.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/tomcat_coyote_util.xml
generated
9
.idea/libraries/tomcat_coyote_util.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="tomcat-coyote-util">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/apache-tomcat/lib/tomcat-coyote-util.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
12
.idea/libraries/tomcat_lib.xml
generated
12
.idea/libraries/tomcat_lib.xml
generated
@@ -1,12 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="tomcat-lib">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/apache-tomcat-deployer/lib/tomcat-juli.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/apache-tomcat-deployer/lib/el-api.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/apache-tomcat-deployer/lib/jasper.jar!/" />
|
||||
<root url="jar://$PROJECT_DIR$/apps/jetty/apache-tomcat-deployer/lib/jasper-el.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/wrapper.xml
generated
9
.idea/libraries/wrapper.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="wrapper">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/installer/lib/wrapper/all/wrapper.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
9
.idea/libraries/wrapper_win.xml
generated
9
.idea/libraries/wrapper_win.xml
generated
@@ -1,9 +0,0 @@
|
||||
<component name="libraryTable">
|
||||
<library name="wrapper-win">
|
||||
<CLASSES>
|
||||
<root url="jar://$PROJECT_DIR$/installer/lib/wrapper/win-all/wrapper.jar!/" />
|
||||
</CLASSES>
|
||||
<JAVADOC />
|
||||
<SOURCES />
|
||||
</library>
|
||||
</component>
|
||||
57
.idea/misc.xml
generated
57
.idea/misc.xml
generated
@@ -1,57 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ClientPropertiesManager">
|
||||
<properties class="javax.swing.AbstractButton">
|
||||
<property name="hideActionText" class="java.lang.Boolean" />
|
||||
</properties>
|
||||
<properties class="javax.swing.JComponent">
|
||||
<property name="html.disable" class="java.lang.Boolean" />
|
||||
</properties>
|
||||
<properties class="javax.swing.JEditorPane">
|
||||
<property name="JEditorPane.w3cLengthUnits" class="java.lang.Boolean" />
|
||||
<property name="JEditorPane.honorDisplayProperties" class="java.lang.Boolean" />
|
||||
<property name="charset" class="java.lang.String" />
|
||||
</properties>
|
||||
<properties class="javax.swing.JList">
|
||||
<property name="List.isFileList" class="java.lang.Boolean" />
|
||||
</properties>
|
||||
<properties class="javax.swing.JPasswordField">
|
||||
<property name="JPasswordField.cutCopyAllowed" class="java.lang.Boolean" />
|
||||
</properties>
|
||||
<properties class="javax.swing.JSlider">
|
||||
<property name="Slider.paintThumbArrowShape" class="java.lang.Boolean" />
|
||||
<property name="JSlider.isFilled" class="java.lang.Boolean" />
|
||||
</properties>
|
||||
<properties class="javax.swing.JTable">
|
||||
<property name="Table.isFileList" class="java.lang.Boolean" />
|
||||
<property name="JTable.autoStartsEdit" class="java.lang.Boolean" />
|
||||
<property name="terminateEditOnFocusLost" class="java.lang.Boolean" />
|
||||
</properties>
|
||||
<properties class="javax.swing.JToolBar">
|
||||
<property name="JToolBar.isRollover" class="java.lang.Boolean" />
|
||||
</properties>
|
||||
<properties class="javax.swing.JTree">
|
||||
<property name="JTree.lineStyle" class="java.lang.String" />
|
||||
</properties>
|
||||
<properties class="javax.swing.text.JTextComponent">
|
||||
<property name="caretAspectRatio" class="java.lang.Double" />
|
||||
<property name="caretWidth" class="java.lang.Integer" />
|
||||
</properties>
|
||||
</component>
|
||||
<component name="EntryPointsManager">
|
||||
<entry_points version="2.0" />
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||
<OptionsSetting value="true" id="Add" />
|
||||
<OptionsSetting value="true" id="Remove" />
|
||||
<OptionsSetting value="true" id="Checkout" />
|
||||
<OptionsSetting value="true" id="Update" />
|
||||
<OptionsSetting value="true" id="Status" />
|
||||
<OptionsSetting value="true" id="Edit" />
|
||||
<ConfirmationsSetting value="0" id="Add" />
|
||||
<ConfirmationsSetting value="0" id="Remove" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.7" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build" />
|
||||
</component>
|
||||
</project>
|
||||
80
.idea/modules.xml
generated
80
.idea/modules.xml
generated
@@ -1,80 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB.iml" group="apps/BOB" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/BOB/BOB.iml" filepath="$PROJECT_DIR$/apps/BOB/BOB.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_main.iml" group="apps/BOB" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/BOB/BOB_test.iml" group="apps/BOB" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook.iml" group="apps/addressbook" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/addressbook/addressbook.iml" filepath="$PROJECT_DIR$/apps/addressbook/addressbook.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_main.iml" group="apps/addressbook" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/addressbook/addressbook_test.iml" group="apps/addressbook" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/admin/admin.iml" filepath="$PROJECT_DIR$/apps/admin/admin.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/apps.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/apps.iml" group="apps" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core.iml" group="core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/core/core.iml" filepath="$PROJECT_DIR$/core/core.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core_main.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core_main.iml" group="core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/core/core_test.iml" filepath="$PROJECT_DIR$/.idea/modules/core/core_test.iml" group="core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui.iml" group="apps/desktopgui" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/desktopgui/desktopgui.iml" filepath="$PROJECT_DIR$/apps/desktopgui/desktopgui.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_main.iml" group="apps/desktopgui" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/desktopgui/desktopgui_test.iml" group="apps/desktopgui" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/i2p.i2p.sl.iml" filepath="$PROJECT_DIR$/.idea/modules/i2p.i2p.sl.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark.iml" group="apps/i2psnark" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/i2psnark/i2psnark.iml" filepath="$PROJECT_DIR$/apps/i2psnark/i2psnark.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_main.iml" group="apps/i2psnark" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2psnark/i2psnark_test.iml" group="apps/i2psnark" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel.iml" group="apps/i2ptunnel" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/i2ptunnel/i2ptunnel.iml" filepath="$PROJECT_DIR$/apps/i2ptunnel/i2ptunnel.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_main.iml" group="apps/i2ptunnel" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/i2ptunnel/i2ptunnel_test.iml" group="apps/i2ptunnel" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/imagegen/identicon/identicon.iml" filepath="$PROJECT_DIR$/apps/imagegen/identicon/identicon.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/imagegen/imagegen/imagegen.iml" filepath="$PROJECT_DIR$/apps/imagegen/imagegen/imagegen.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer.iml" group="installer" />
|
||||
<module fileurl="file://$PROJECT_DIR$/installer/installer.iml" filepath="$PROJECT_DIR$/installer/installer.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer_main.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer_main.iml" group="installer" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/installer/installer_test.iml" filepath="$PROJECT_DIR$/.idea/modules/installer/installer_test.iml" group="installer" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty.iml" group="apps/jetty" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/jetty/jetty.iml" filepath="$PROJECT_DIR$/apps/jetty/jetty.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_main.iml" group="apps/jetty" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jetty/jetty_test.iml" group="apps/jetty" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin.iml" group="apps/jrobin" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_main.iml" group="apps/jrobin" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/jrobin/jrobin_test.iml" group="apps/jrobin" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming.iml" group="apps/ministreaming" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/ministreaming/ministreaming.iml" filepath="$PROJECT_DIR$/apps/ministreaming/ministreaming.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_main.iml" group="apps/ministreaming" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/ministreaming/ministreaming_test.iml" group="apps/ministreaming" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router.iml" group="router" />
|
||||
<module fileurl="file://$PROJECT_DIR$/router/router.iml" filepath="$PROJECT_DIR$/router/router.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router_main.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router_main.iml" group="router" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/router/router_test.iml" filepath="$PROJECT_DIR$/.idea/modules/router/router_test.iml" group="router" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole.iml" group="apps/routerconsole" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/routerconsole/routerconsole.iml" filepath="$PROJECT_DIR$/apps/routerconsole/routerconsole.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_main.iml" group="apps/routerconsole" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/routerconsole/routerconsole_test.iml" group="apps/routerconsole" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam.iml" group="apps/sam" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/sam/sam.iml" filepath="$PROJECT_DIR$/apps/sam/sam.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam_main.iml" group="apps/sam" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/sam/sam_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/sam/sam_test.iml" group="apps/sam" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming.iml" group="apps/streaming" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/streaming/streaming.iml" filepath="$PROJECT_DIR$/apps/streaming/streaming.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_main.iml" group="apps/streaming" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/streaming/streaming_test.iml" group="apps/streaming" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns.iml" group="apps/susidns" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/susidns/susidns.iml" filepath="$PROJECT_DIR$/apps/susidns/susidns.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_main.iml" group="apps/susidns" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susidns/susidns_test.iml" group="apps/susidns" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail.iml" group="apps/susimail" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/susimail/susimail.iml" filepath="$PROJECT_DIR$/apps/susimail/susimail.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_main.iml" group="apps/susimail" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/susimail/susimail_test.iml" group="apps/susimail" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray.iml" group="apps/systray" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/systray/systray.iml" filepath="$PROJECT_DIR$/apps/systray/systray.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray_main.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray_main.iml" group="apps/systray" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/apps/systray/systray_test.iml" filepath="$PROJECT_DIR$/.idea/modules/apps/systray/systray_test.iml" group="apps/systray" />
|
||||
<module fileurl="file://$PROJECT_DIR$/apps/imagegen/zxing/zxing.iml" filepath="$PROJECT_DIR$/apps/imagegen/zxing/zxing.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/runConfigurations/updater.xml
generated
6
.idea/runConfigurations/updater.xml
generated
@@ -1,6 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="updater" type="AntRunConfiguration" factoryName="Ant Target">
|
||||
<antsettings antfile="file://$PROJECT_DIR$/build.xml" target="updater" />
|
||||
<method />
|
||||
</configuration>
|
||||
</component>
|
||||
33
.travis.yml
33
.travis.yml
@@ -1,35 +1,18 @@
|
||||
language: java
|
||||
dist: bionic
|
||||
|
||||
jdk:
|
||||
- oraclejdk11
|
||||
- oraclejdk9
|
||||
- openjdk11
|
||||
- openjdk10
|
||||
- openjdk9
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- jdk: oraclejdk8
|
||||
- jdk: oraclejdk11
|
||||
addons:
|
||||
sonarcloud:
|
||||
organization: "i2p"
|
||||
before_install:
|
||||
- export JAVA7_HOME=$(jdk_switcher home openjdk7)
|
||||
- sed -i "1iplugins {\n id 'org.sonarqube' version '2.6.1'\n}\n" build.gradle
|
||||
- sed -i "1iplugins {\n id 'org.sonarqube' version '3.0'\n}\n" build.gradle
|
||||
- jdk: openjdk8
|
||||
before_install:
|
||||
- export JAVA7_HOME=$(jdk_switcher home openjdk7)
|
||||
- jdk: openjdk7
|
||||
sudo: required
|
||||
before_install: # Work around missing crypto in openjdk7
|
||||
- export JAVA7_HOME=$(jdk_switcher home openjdk7)
|
||||
- sudo wget "https://bouncycastle.org/download/bcprov-ext-jdk15on-158.jar" -O "${JAVA_HOME}/jre/lib/ext/bcprov-ext-jdk15on-158.jar"
|
||||
- sudo perl -pi.bak -e 's/^(security\.provider\.)([0-9]+)/$1.($2+1)/ge' /etc/java-7-openjdk/security/java.security
|
||||
- echo "security.provider.1=org.bouncycastle.jce.provider.BouncyCastleProvider" | sudo tee -a /etc/java-7-openjdk/security/java.security
|
||||
install:
|
||||
- export TARGET_JAVA_HOME=$JAVA_HOME
|
||||
- jdk_switcher use oraclejdk8
|
||||
- ./gradlew assemble
|
||||
|
||||
before_cache:
|
||||
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
|
||||
@@ -41,13 +24,11 @@ cache:
|
||||
- $HOME/.sonar/cache/
|
||||
- .gradle
|
||||
|
||||
env:
|
||||
- SONAR_SCANNER_OPTS="-Xmx2048m"
|
||||
|
||||
script:
|
||||
- |
|
||||
if [ "$TRAVIS_JDK_VERSION" == "oraclejdk8" ]; then
|
||||
./gradlew sonarqube codeCoverageReport
|
||||
else
|
||||
./gradlew check codeCoverageReport
|
||||
fi
|
||||
- travis_wait 45 ./tests/scripts/travis.sh
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
153
.tx/config
153
.tx/config
@@ -1,3 +1,6 @@
|
||||
;; warning - conversions for all Java bundles:
|
||||
;; id->in, he->iw, iy, yi->ji
|
||||
|
||||
[I2P.i2ptunnel]
|
||||
source_file = apps/i2ptunnel/locale/messages_en.po
|
||||
source_lang = en
|
||||
@@ -6,6 +9,7 @@ trans.cs = apps/i2ptunnel/locale/messages_cs.po
|
||||
trans.da = apps/i2ptunnel/locale/messages_da.po
|
||||
trans.de = apps/i2ptunnel/locale/messages_de.po
|
||||
trans.es = apps/i2ptunnel/locale/messages_es.po
|
||||
trans.fa = apps/i2ptunnel/locale/messages_fa.po
|
||||
trans.fi = apps/i2ptunnel/locale/messages_fi.po
|
||||
trans.fr = apps/i2ptunnel/locale/messages_fr.po
|
||||
trans.hu = apps/i2ptunnel/locale/messages_hu.po
|
||||
@@ -23,6 +27,7 @@ trans.pt_BR = apps/i2ptunnel/locale/messages_pt_BR.po
|
||||
trans.ro = apps/i2ptunnel/locale/messages_ro.po
|
||||
trans.ru_RU = apps/i2ptunnel/locale/messages_ru.po
|
||||
trans.sk = apps/i2ptunnel/locale/messages_sk.po
|
||||
trans.sq = apps/i2ptunnel/locale/messages_sq.po
|
||||
trans.sv_SE = apps/i2ptunnel/locale/messages_sv.po
|
||||
trans.tr_TR = apps/i2ptunnel/locale/messages_tr.po
|
||||
trans.uk_UA = apps/i2ptunnel/locale/messages_uk.po
|
||||
@@ -38,6 +43,7 @@ trans.cs = apps/i2ptunnel/locale-proxy/messages_cs.po
|
||||
trans.de = apps/i2ptunnel/locale-proxy/messages_de.po
|
||||
trans.el = apps/i2ptunnel/locale-proxy/messages_el.po
|
||||
trans.es = apps/i2ptunnel/locale-proxy/messages_es.po
|
||||
trans.fa = apps/i2ptunnel/locale-proxy/messages_fa.po
|
||||
trans.fi = apps/i2ptunnel/locale-proxy/messages_fi.po
|
||||
trans.fr = apps/i2ptunnel/locale-proxy/messages_fr.po
|
||||
trans.hu = apps/i2ptunnel/locale-proxy/messages_hu.po
|
||||
@@ -60,16 +66,92 @@ trans.uk_UA = apps/i2ptunnel/locale-proxy/messages_uk.po
|
||||
trans.vi = apps/i2ptunnel/locale-proxy/messages_vi.po
|
||||
trans.zh_CN = apps/i2ptunnel/locale-proxy/messages_zh.po
|
||||
|
||||
[I2P.core]
|
||||
type = PO
|
||||
source_file = core/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = core/locale/messages_ar.po
|
||||
trans.az = core/locale/messages_az.po
|
||||
trans.cs = core/locale/messages_cs.po
|
||||
trans.da = core/locale/messages_da.po
|
||||
trans.de = core/locale/messages_de.po
|
||||
trans.el = core/locale/messages_el.po
|
||||
trans.es = core/locale/messages_es.po
|
||||
trans.et_EE = core/locale/messages_et.po
|
||||
trans.fa = core/locale/messages_fa.po
|
||||
trans.fi = core/locale/messages_fi.po
|
||||
trans.fr = core/locale/messages_fr.po
|
||||
trans.hu = core/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = core/locale/messages_in.po
|
||||
trans.it = core/locale/messages_it.po
|
||||
trans.ja = core/locale/messages_ja.po
|
||||
trans.ko = core/locale/messages_ko.po
|
||||
trans.ku = core/locale/messages_ku.po
|
||||
trans.nb = core/locale/messages_nb.po
|
||||
trans.nl = core/locale/messages_nl.po
|
||||
trans.pl = core/locale/messages_pl.po
|
||||
trans.pt = core/locale/messages_pt.po
|
||||
trans.pt_BR = core/locale/messages_pt_BR.po
|
||||
trans.ro = core/locale/messages_ro.po
|
||||
trans.ru_RU = core/locale/messages_ru.po
|
||||
trans.sv_SE = core/locale/messages_sv.po
|
||||
trans.tk = core/locale/messages_tk.po
|
||||
trans.tr_TR = core/locale/messages_tr.po
|
||||
trans.uk_UA = core/locale/messages_uk.po
|
||||
trans.vi = core/locale/messages_vi.po
|
||||
trans.zh_CN = core/locale/messages_zh.po
|
||||
trans.zh_TW = core/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.router]
|
||||
type = PO
|
||||
source_file = router/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = router/locale/messages_ar.po
|
||||
trans.az = router/locale/messages_az.po
|
||||
trans.cs = router/locale/messages_cs.po
|
||||
trans.da = router/locale/messages_da.po
|
||||
trans.de = router/locale/messages_de.po
|
||||
trans.el = router/locale/messages_el.po
|
||||
trans.es = router/locale/messages_es.po
|
||||
trans.et_EE = router/locale/messages_et.po
|
||||
trans.fa = router/locale/messages_fa.po
|
||||
trans.fi = router/locale/messages_fi.po
|
||||
trans.fr = router/locale/messages_fr.po
|
||||
trans.hu = router/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = router/locale/messages_in.po
|
||||
trans.it = router/locale/messages_it.po
|
||||
trans.ja = router/locale/messages_ja.po
|
||||
trans.ko = router/locale/messages_ko.po
|
||||
trans.ku = router/locale/messages_ku.po
|
||||
trans.nb = router/locale/messages_nb.po
|
||||
trans.nl = router/locale/messages_nl.po
|
||||
trans.pl = router/locale/messages_pl.po
|
||||
trans.pt = router/locale/messages_pt.po
|
||||
trans.pt_BR = router/locale/messages_pt_BR.po
|
||||
trans.ro = router/locale/messages_ro.po
|
||||
trans.ru_RU = router/locale/messages_ru.po
|
||||
trans.sv_SE = router/locale/messages_sv.po
|
||||
trans.tk = router/locale/messages_tk.po
|
||||
trans.tr_TR = router/locale/messages_tr.po
|
||||
trans.uk_UA = router/locale/messages_uk.po
|
||||
trans.vi = router/locale/messages_vi.po
|
||||
trans.zh_CN = router/locale/messages_zh.po
|
||||
trans.zh_TW = router/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.routerconsole]
|
||||
source_file = apps/routerconsole/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/locale/messages_ar.po
|
||||
trans.az = apps/routerconsole/locale/messages_az.po
|
||||
trans.cs = apps/routerconsole/locale/messages_cs.po
|
||||
trans.da = apps/routerconsole/locale/messages_da.po
|
||||
trans.de = apps/routerconsole/locale/messages_de.po
|
||||
trans.el = apps/routerconsole/locale/messages_el.po
|
||||
trans.es = apps/routerconsole/locale/messages_es.po
|
||||
trans.et_EE = apps/routerconsole/locale/messages_et.po
|
||||
trans.fa = apps/routerconsole/locale/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale/messages_fr.po
|
||||
trans.hu = apps/routerconsole/locale/messages_hu.po
|
||||
@@ -101,15 +183,18 @@ trans.cs = apps/routerconsole/locale-news/messages_cs.po
|
||||
trans.de = apps/routerconsole/locale-news/messages_de.po
|
||||
trans.el = apps/routerconsole/locale-news/messages_el.po
|
||||
trans.es = apps/routerconsole/locale-news/messages_es.po
|
||||
trans.fa = apps/routerconsole/locale-news/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale-news/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale-news/messages_fr.po
|
||||
trans.gl = apps/routerconsole/locale-news/messages_gl.po
|
||||
trans.he = apps/routerconsole/locale-news/messages_he.po
|
||||
;; Java converts he to iw
|
||||
trans.he = apps/routerconsole/locale-news/messages_iw.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/routerconsole/locale-news/messages_in.po
|
||||
trans.it = apps/routerconsole/locale-news/messages_it.po
|
||||
trans.ja = apps/routerconsole/locale-news/messages_ja.po
|
||||
trans.ko = apps/routerconsole/locale-news/messages_ko.po
|
||||
trans.ku = apps/routerconsole/locale-news/messages_ku.po
|
||||
trans.mg = apps/routerconsole/locale-news/messages_mg.po
|
||||
trans.nb = apps/routerconsole/locale-news/messages_nb.po
|
||||
trans.nl = apps/routerconsole/locale-news/messages_nl.po
|
||||
@@ -122,6 +207,7 @@ trans.sk = apps/routerconsole/locale-news/messages_sk.po
|
||||
trans.sq = apps/routerconsole/locale-news/messages_sq.po
|
||||
trans.sr = apps/routerconsole/locale-news/messages_sr.po
|
||||
trans.sv_SE = apps/routerconsole/locale-news/messages_sv.po
|
||||
trans.tk = apps/routerconsole/locale-news/messages_tk.po
|
||||
trans.tr_TR = apps/routerconsole/locale-news/messages_tr.po
|
||||
trans.uk_UA = apps/routerconsole/locale-news/messages_uk.po
|
||||
trans.zh_CN = apps/routerconsole/locale-news/messages_zh.po
|
||||
@@ -133,7 +219,9 @@ source_file = apps/routerconsole/locale-countries/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/routerconsole/locale-countries/messages_ar.po
|
||||
trans.az = apps/routerconsole/locale-countries/messages_az.po
|
||||
trans.bg = apps/routerconsole/locale-countries/messages_bg.po
|
||||
trans.ca = apps/routerconsole/locale-countries/messages_ca.po
|
||||
trans.cs = apps/routerconsole/locale-countries/messages_cs.po
|
||||
trans.da = apps/routerconsole/locale-countries/messages_da.po
|
||||
trans.de = apps/routerconsole/locale-countries/messages_de.po
|
||||
trans.el = apps/routerconsole/locale-countries/messages_el.po
|
||||
@@ -143,13 +231,17 @@ trans.fa = apps/routerconsole/locale-countries/messages_fa.po
|
||||
trans.fi = apps/routerconsole/locale-countries/messages_fi.po
|
||||
trans.fr = apps/routerconsole/locale-countries/messages_fr.po
|
||||
trans.gl = apps/routerconsole/locale-countries/messages_gl.po
|
||||
trans.hi = apps/routerconsole/locale-countries/messages_hi.po
|
||||
trans.hr = apps/routerconsole/locale-countries/messages_hr.po
|
||||
trans.hu = apps/routerconsole/locale-countries/messages_hu.po
|
||||
;; Java converts he to iw
|
||||
trans.he = apps/routerconsole/locale-countries/messages_iw.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/routerconsole/locale-countries/messages_in.po
|
||||
trans.it = apps/routerconsole/locale-countries/messages_it.po
|
||||
trans.ja = apps/routerconsole/locale-countries/messages_ja.po
|
||||
trans.ko = apps/routerconsole/locale-countries/messages_ko.po
|
||||
trans.ku = apps/routerconsole/locale-countries/messages_ku.po
|
||||
trans.mg = apps/routerconsole/locale-countries/messages_mg.po
|
||||
trans.nb = apps/routerconsole/locale-countries/messages_nb.po
|
||||
trans.nl = apps/routerconsole/locale-countries/messages_nl.po
|
||||
@@ -160,7 +252,9 @@ trans.ro = apps/routerconsole/locale-countries/messages_ro.po
|
||||
trans.ru_RU = apps/routerconsole/locale-countries/messages_ru.po
|
||||
trans.sk = apps/routerconsole/locale-countries/messages_sk.po
|
||||
trans.sq = apps/routerconsole/locale-countries/messages_sq.po
|
||||
trans.sr = apps/routerconsole/locale-countries/messages_sr.po
|
||||
trans.sv_SE = apps/routerconsole/locale-countries/messages_sv.po
|
||||
trans.tk = apps/routerconsole/locale-countries/messages_tk.po
|
||||
trans.tr_TR = apps/routerconsole/locale-countries/messages_tr.po
|
||||
trans.uk_UA = apps/routerconsole/locale-countries/messages_uk.po
|
||||
trans.vi = apps/routerconsole/locale-countries/messages_vi.po
|
||||
@@ -175,6 +269,7 @@ trans.cs = apps/i2psnark/locale/messages_cs.po
|
||||
trans.de = apps/i2psnark/locale/messages_de.po
|
||||
trans.el = apps/i2psnark/locale/messages_el.po
|
||||
trans.es = apps/i2psnark/locale/messages_es.po
|
||||
trans.fa = apps/i2psnark/locale/messages_fa.po
|
||||
trans.fi = apps/i2psnark/locale/messages_fi.po
|
||||
trans.fr = apps/i2psnark/locale/messages_fr.po
|
||||
trans.hu = apps/i2psnark/locale/messages_hu.po
|
||||
@@ -197,6 +292,7 @@ trans.tr_TR = apps/i2psnark/locale/messages_tr.po
|
||||
trans.uk_UA = apps/i2psnark/locale/messages_uk.po
|
||||
trans.vi = apps/i2psnark/locale/messages_vi.po
|
||||
trans.zh_CN = apps/i2psnark/locale/messages_zh.po
|
||||
trans.zh_TW = apps/i2psnark/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.susidns]
|
||||
source_file = apps/susidns/locale/messages_en.po
|
||||
@@ -207,6 +303,7 @@ trans.da = apps/susidns/locale/messages_da.po
|
||||
trans.de = apps/susidns/locale/messages_de.po
|
||||
trans.el = apps/susidns/locale/messages_el.po
|
||||
trans.es = apps/susidns/locale/messages_es.po
|
||||
trans.fa = apps/susidns/locale/messages_fa.po
|
||||
trans.fi = apps/susidns/locale/messages_fi.po
|
||||
trans.fr = apps/susidns/locale/messages_fr.po
|
||||
trans.gl = apps/susidns/locale/messages_gl.po
|
||||
@@ -241,6 +338,7 @@ trans.da = apps/desktopgui/locale/messages_da.po
|
||||
trans.de = apps/desktopgui/locale/messages_de.po
|
||||
trans.el = apps/desktopgui/locale/messages_el.po
|
||||
trans.es = apps/desktopgui/locale/messages_es.po
|
||||
trans.es_AR = apps/desktopgui/locale/messages_es_AR.po
|
||||
trans.fa = apps/desktopgui/locale/messages_fa.po
|
||||
trans.fi = apps/desktopgui/locale/messages_fi.po
|
||||
trans.fr = apps/desktopgui/locale/messages_fr.po
|
||||
@@ -251,6 +349,7 @@ trans.id = apps/desktopgui/locale/messages_in.po
|
||||
trans.it = apps/desktopgui/locale/messages_it.po
|
||||
trans.ja = apps/desktopgui/locale/messages_ja.po
|
||||
trans.ko = apps/desktopgui/locale/messages_ko.po
|
||||
trans.ku = apps/desktopgui/locale/messages_ku.po
|
||||
trans.mg = apps/desktopgui/locale/messages_mg.po
|
||||
trans.nb = apps/desktopgui/locale/messages_nb.po
|
||||
trans.nl = apps/desktopgui/locale/messages_nl.po
|
||||
@@ -260,27 +359,36 @@ trans.pt_BR = apps/desktopgui/locale/messages_pt_BR.po
|
||||
trans.ro = apps/desktopgui/locale/messages_ro.po
|
||||
trans.ru_RU = apps/desktopgui/locale/messages_ru.po
|
||||
trans.sk = apps/desktopgui/locale/messages_sk.po
|
||||
trans.sr = apps/desktopgui/locale/messages_sr.po
|
||||
trans.sv_SE = apps/desktopgui/locale/messages_sv.po
|
||||
trans.sq = apps/desktopgui/locale/messages_sq.po
|
||||
trans.uk_UA = apps/desktopgui/locale/messages_uk.po
|
||||
trans.tk = apps/desktopgui/locale/messages_tk.po
|
||||
trans.tr_TR = apps/desktopgui/locale/messages_tr.po
|
||||
trans.vi = apps/desktopgui/locale/messages_vi.po
|
||||
trans.zh_CN = apps/desktopgui/locale/messages_zh.po
|
||||
trans.zh_TW = apps/desktopgui/locale/messages_zh_TW.po
|
||||
|
||||
[I2P.susimail]
|
||||
source_file = apps/susimail/locale/messages_en.po
|
||||
source_lang = en
|
||||
trans.ar = apps/susimail/locale/messages_ar.po
|
||||
trans.az = apps/susimail/locale/messages_az.po
|
||||
trans.bg = apps/susimail/locale/messages_bg.po
|
||||
trans.ca = apps/susimail/locale/messages_ca.po
|
||||
trans.cs = apps/susimail/locale/messages_cs.po
|
||||
trans.da = apps/susimail/locale/messages_da.po
|
||||
trans.de = apps/susimail/locale/messages_de.po
|
||||
trans.el = apps/susimail/locale/messages_el.po
|
||||
trans.es = apps/susimail/locale/messages_es.po
|
||||
trans.fa = apps/susimail/locale/messages_fa.po
|
||||
trans.fi = apps/susimail/locale/messages_fi.po
|
||||
trans.fr = apps/susimail/locale/messages_fr.po
|
||||
trans.gl = apps/susimail/locale/messages_gl.po
|
||||
trans.hr = apps/susimail/locale/messages_hr.po
|
||||
trans.hu = apps/susimail/locale/messages_hu.po
|
||||
;; Java converts he to iw
|
||||
trans.he = apps/susimail/locale/messages_iw.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/susimail/locale/messages_in.po
|
||||
trans.it = apps/susimail/locale/messages_it.po
|
||||
@@ -296,6 +404,7 @@ trans.ro = apps/susimail/locale/messages_ro.po
|
||||
trans.ru_RU = apps/susimail/locale/messages_ru.po
|
||||
trans.sk = apps/susimail/locale/messages_sk.po
|
||||
trans.sq = apps/susimail/locale/messages_sq.po
|
||||
trans.sr = apps/susimail/locale/messages_sr.po
|
||||
trans.sv_SE = apps/susimail/locale/messages_sv.po
|
||||
trans.tr_TR = apps/susimail/locale/messages_tr.po
|
||||
trans.uk_UA = apps/susimail/locale/messages_uk.po
|
||||
@@ -330,6 +439,7 @@ trans.ru_RU = debian/po/ru.po
|
||||
trans.sk = debian/po/sk.po
|
||||
trans.sq = debian/po/sq.po
|
||||
trans.sv_SE = debian/po/sv.po
|
||||
trans.tk = debian/po/tk.po
|
||||
trans.tr_TR = debian/po/tr.po
|
||||
trans.uk_UA = debian/po/uk.po
|
||||
trans.zh_CN = debian/po/zh.po
|
||||
@@ -396,6 +506,7 @@ trans.id = core/java/src/gnu/getopt/MessagesBundle_in.properties
|
||||
trans.it = core/java/src/gnu/getopt/MessagesBundle_it.properties
|
||||
trans.ja = core/java/src/gnu/getopt/MessagesBundle_ja.properties
|
||||
trans.ko = core/java/src/gnu/getopt/MessagesBundle_ko.properties
|
||||
trans.ku = core/java/src/gnu/getopt/MessagesBundle_ku.properties
|
||||
trans.nb = core/java/src/gnu/getopt/MessagesBundle_nb.properties
|
||||
trans.nl = core/java/src/gnu/getopt/MessagesBundle_nl.properties
|
||||
trans.pl = core/java/src/gnu/getopt/MessagesBundle_pl.properties
|
||||
@@ -421,9 +532,11 @@ trans.ca = apps/ministreaming/locale/messages_ca.po
|
||||
trans.cs = apps/ministreaming/locale/messages_cs.po
|
||||
trans.de = apps/ministreaming/locale/messages_de.po
|
||||
trans.es = apps/ministreaming/locale/messages_es.po
|
||||
trans.fa = apps/ministreaming/locale/messages_fa.po
|
||||
trans.fi = apps/ministreaming/locale/messages_fi.po
|
||||
trans.fr = apps/ministreaming/locale/messages_fr.po
|
||||
trans.gl = apps/ministreaming/locale/messages_gl.po
|
||||
trans.hu = apps/ministreaming/locale/messages_hu.po
|
||||
;; Java converts id to in
|
||||
trans.id = apps/ministreaming/locale/messages_in.po
|
||||
trans.it = apps/ministreaming/locale/messages_it.po
|
||||
@@ -436,6 +549,7 @@ trans.pt_BR = apps/ministreaming/locale/messages_pt_BR.po
|
||||
trans.ro = apps/ministreaming/locale/messages_ro.po
|
||||
trans.ru_RU = apps/ministreaming/locale/messages_ru.po
|
||||
trans.sv_SE = apps/ministreaming/locale/messages_sv.po
|
||||
trans.tk = apps/ministreaming/locale/messages_tk.po
|
||||
trans.tr_TR = apps/ministreaming/locale/messages_tr.po
|
||||
trans.uk_UA = apps/ministreaming/locale/messages_uk.po
|
||||
trans.zh_CN = apps/ministreaming/locale/messages_zh.po
|
||||
@@ -443,6 +557,7 @@ trans.zh_CN = apps/ministreaming/locale/messages_zh.po
|
||||
[I2P.manpages]
|
||||
;;
|
||||
;; after adding languages here, add to debian/*.manpages also
|
||||
;; You must run installer/resources/poupdate-man.sh first.
|
||||
;;
|
||||
type = PO
|
||||
source_file = installer/resources/locale-man/man.pot
|
||||
@@ -460,6 +575,7 @@ trans.nl = installer/resources/locale-man/man_nl.po
|
||||
trans.pl = installer/resources/locale-man/man_pl.po
|
||||
trans.pt = installer/resources/locale-man/man_pt.po
|
||||
trans.pt_BR = installer/resources/locale-man/man_pt_BR.po
|
||||
trans.ro = installer/resources/locale-man/man_ro.po
|
||||
trans.ru_RU = installer/resources/locale-man/man_ru.po
|
||||
trans.sv_SE = installer/resources/locale-man/man_sv.po
|
||||
trans.tr_TR = installer/resources/locale-man/man_tr.po
|
||||
@@ -467,26 +583,30 @@ trans.zh_CN = installer/resources/locale-man/man_zh.po
|
||||
|
||||
[I2P.eepsite]
|
||||
;;
|
||||
;; For any new translations, add links in index.html,
|
||||
;; For any new translations, add links in installer/resources/eepsite/docroot/help/index.html
|
||||
;; and copy new flags in build.xml copyflags-unlesspkg target,
|
||||
;; and add to debian/i2p-router.links and debian-alt/*/i2p-router.links
|
||||
;;
|
||||
type = HTML
|
||||
source_file = installer/resources/eepsite/docroot/help/index.html
|
||||
source_lang = en
|
||||
trans.ar = installer/resources/eepsite/docroot/help/index_ar.html
|
||||
;; File contains local changes to fix RTL issues.
|
||||
;; Merge locally or make changes on TX side before re-enabling
|
||||
;;trans.ar = installer/resources/eepsite/docroot/help/index_ar.html
|
||||
trans.az = installer/resources/eepsite/docroot/help/index_az.html
|
||||
trans.de = installer/resources/eepsite/docroot/help/index_de.html
|
||||
;; not yet translated on TX, use old page
|
||||
;;trans.es = installer/resources/eepsite/docroot/help/index_es.html
|
||||
trans.fr = installer/resources/eepsite/docroot/help/index_fr.html
|
||||
trans.hu = installer/resources/eepsite/docroot/help/index_hu.html
|
||||
;; Java converts id to in
|
||||
trans.id = installer/resources/eepsite/docroot/help/index_in.html
|
||||
trans.it = installer/resources/eepsite/docroot/help/index_it.html
|
||||
;; not yet translated on TX, use old page
|
||||
;;trans.nl = installer/resources/eepsite/docroot/help/index_nl.html
|
||||
trans.pl = installer/resources/eepsite/docroot/help/index_nl.html
|
||||
trans.pt = installer/resources/eepsite/docroot/help/index_nl.html
|
||||
trans.pl = installer/resources/eepsite/docroot/help/index_pl.html
|
||||
trans.pt = installer/resources/eepsite/docroot/help/index_pt.html
|
||||
trans.ro = installer/resources/eepsite/docroot/help/index_ro.html
|
||||
trans.ru_RU = installer/resources/eepsite/docroot/help/index_ru.html
|
||||
;; not yet translated on TX, use old page
|
||||
;;trans.sv_SE = installer/resources/eepsite/docroot/help/index_sv.html
|
||||
@@ -499,18 +619,21 @@ trans.tr_TR = installer/resources/eepsite/docroot/help/index_tr.html
|
||||
;; Text on /console
|
||||
;;
|
||||
type = HTML
|
||||
source_file = installer/resources/readme/readme.html
|
||||
source_file = apps/routerconsole/resources/docs/readme.html
|
||||
source_lang = en
|
||||
trans.ar = installer/resources/readme/readme_ar.html
|
||||
trans.de = installer/resources/readme/readme_de.html
|
||||
trans.ar = apps/routerconsole/resources/docs/readme_ar.html
|
||||
trans.de = apps/routerconsole/resources/docs/readme_de.html
|
||||
trans.fr = apps/routerconsole/resources/docs/readme_fr.html
|
||||
;; Java converts id to in
|
||||
trans.id = installer/resources/readme/readme_in.html
|
||||
trans.it = installer/resources/readme/readme_it.html
|
||||
trans.ja = installer/resources/readme/readme_ja.html
|
||||
trans.pl = installer/resources/readme/readme_pl.html
|
||||
trans.pt = installer/resources/readme/readme_pt.html
|
||||
trans.ru_RU = installer/resources/readme/readme_ru.html
|
||||
trans.tr_TR = installer/resources/readme/readme_tr.html
|
||||
trans.id = apps/routerconsole/resources/docs/readme_in.html
|
||||
trans.it = apps/routerconsole/resources/docs/readme_it.html
|
||||
trans.ja = apps/routerconsole/resources/docs/readme_ja.html
|
||||
trans.pl = apps/routerconsole/resources/docs/readme_pl.html
|
||||
trans.pt = apps/routerconsole/resources/docs/readme_pt.html
|
||||
trans.ro = apps/routerconsole/resources/docs/readme_ro.html
|
||||
trans.ru_RU = apps/routerconsole/resources/docs/readme_ru.html
|
||||
trans.tr_TR = apps/routerconsole/resources/docs/readme_tr.html
|
||||
trans.zh_CN = apps/routerconsole/resources/docs/readme_zh.html
|
||||
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export JAVA_HOME=/opt/jdk/jre
|
||||
|
||||
# Ensure user rights
|
||||
chown -R i2p:nobody /opt/i2p
|
||||
chmod -R u+rwx /opt/i2p
|
||||
|
||||
gosu i2p /opt/i2p/i2psvc /opt/i2p/wrapper.config wrapper.pidfile=/var/tmp/i2p.pid \
|
||||
wrapper.name=i2p \
|
||||
wrapper.displayname="I2P Service" \
|
||||
wrapper.statusfile=/var/tmp/i2p.status \
|
||||
wrapper.java.statusfile=/var/tmp/i2p.java.status \
|
||||
wrapper.logfile=/var/tmp/wrapper.log
|
||||
80
Dockerfile
80
Dockerfile
@@ -1,62 +1,40 @@
|
||||
FROM meeh/java8server:latest
|
||||
# Docker image based on Alpine with Java.
|
||||
# Use a multi-stage build to reduce the size of the resulting image
|
||||
# We need alpine >v3 in order to install an apache-ant > 1.9
|
||||
FROM debian:buster-slim as builder
|
||||
|
||||
# We use Oracle Java to run I2P, but uses the openjdk to build it.
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Build installer
|
||||
RUN apt-get update \
|
||||
# Workaround for installing openjdk-11-jre-headless
|
||||
&& mkdir -p /usr/share/man/man1 \
|
||||
&& apt-get -qqqy install debhelper ant debconf gettext libgmp-dev po-debconf fakeroot \
|
||||
build-essential quilt dh-apparmor dh-systemd libservice-wrapper-java libjson-simple-java \
|
||||
devscripts libjetty9-java libtomcat9-java libtaglibs-standard-jstlel-java libgetopt-java \
|
||||
bash-completion
|
||||
|
||||
MAINTAINER Mikal Villa <mikal@sigterm.no>
|
||||
WORKDIR /tmp/build
|
||||
COPY . ./
|
||||
|
||||
ENV GIT_BRANCH="master"
|
||||
ENV I2P_PREFIX="/opt/i2p"
|
||||
ENV PATH=${I2P_PREFIX}/bin:$PATH
|
||||
ENV JAVA_HOME=/usr/lib/jvm/default-jvm
|
||||
RUN ant debian
|
||||
|
||||
ENV GOSU_VERSION=1.7
|
||||
ENV GOSU_SHASUM="34049cfc713e8b74b90d6de49690fa601dc040021980812b2f1f691534be8a50 /usr/local/bin/gosu"
|
||||
|
||||
RUN mkdir /user && adduser -S -h /user i2p && chown -R i2p:nobody /user
|
||||
|
||||
# Adding files first, since Docker.expt is required for installation
|
||||
ADD Docker.expt /tmp/Docker.expt
|
||||
ADD Docker.entrypoint.sh /entrypoint.sh
|
||||
|
||||
# Required for wget https
|
||||
RUN apk add --no-cache openssl
|
||||
# Gosu is a replacement for su/sudo in docker and not a backdoor :) See https://github.com/tianon/gosu
|
||||
RUN wget -O /usr/local/bin/gosu https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-amd64 \
|
||||
&& echo "${GOSU_SHASUM}" | sha256sum -c && chmod +x /usr/local/bin/gosu
|
||||
|
||||
#
|
||||
# Each RUN is a layer, adding the dependencies and building i2pd in one layer takes around 8-900Mb, so to keep the
|
||||
# image under 200mb we need to remove all the build dependencies in the same "RUN" / layer.
|
||||
#
|
||||
|
||||
# The main layer
|
||||
RUN apk --no-cache add build-base git gettext tar bzip2 apache-ant openjdk8 expect \
|
||||
&& mkdir -p /usr/src/build \
|
||||
&& cd /usr/src/build \
|
||||
&& git clone -b ${GIT_BRANCH} https://github.com/i2p/i2p.i2p.git \
|
||||
&& cd /usr/src/build/i2p.i2p \
|
||||
&& echo "noExe=true" >> build.properties \
|
||||
&& ant installer-linux \
|
||||
&& cp i2pinstall*.jar /tmp/i2pinstall.jar \
|
||||
&& mkdir -p /opt \
|
||||
&& chown i2p:root /opt \
|
||||
&& chmod u+rw /opt \
|
||||
&& gosu i2p expect -f /tmp/Docker.expt \
|
||||
&& cd ${I2P_PREFIX} \
|
||||
&& rm -fr man docs *.bat *.command *.app /tmp/i2pinstall.jar /tmp/Docker.expt \
|
||||
&& rm -fr /usr/src/build \
|
||||
&& apk --purge del build-base apache-ant expect tcl expat git openjdk8 openjdk8-jre openjdk8-jre-base openjdk8-jre-lib bzip2 tar \
|
||||
binutils-libs binutils pkgconfig libcurl libc-dev musl-dev g++ make fortify-headers pkgconf giflib libssh2 libxdmcp libxcb \
|
||||
libx11 pcre alsa-lib libxi libxrender libxml2 readline bash openssl \
|
||||
&& rm -fr /usr/lib/jvm/default-jre \
|
||||
&& ln -sf /opt/jdk/jre /usr/lib/jvm/default-jre \
|
||||
&& chmod a+x /entrypoint.sh
|
||||
# Second stage only using the installer from the last stage
|
||||
# ---------------------------------------------------------
|
||||
# We can't use alpine here as the java service wrapper is built with glibc
|
||||
# alpine uses musl
|
||||
FROM openjdk:11.0-jre-slim
|
||||
|
||||
# "install" i2p by copying over installed files
|
||||
COPY --from=builder /tmp/*.deb /tmp/
|
||||
|
||||
# Install and configure
|
||||
RUN apt-get update -qqq \
|
||||
&& apt-get -qqqy install geoip-database famfamfam-flag-png \
|
||||
&& dpkb -i /tmp/*
|
||||
|
||||
EXPOSE 7654 7656 7657 7658 4444 6668 8998 7659 7660 4445 15000-20000
|
||||
|
||||
ENTRYPOINT [ "/entrypoint.sh" ]
|
||||
USER i2psvc
|
||||
ENTRYPOINT [ "/usr/bin/i2prouter" ]
|
||||
CMD start
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ If you're having trouble, check the
|
||||
website at https://geti2p.net/, 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
|
||||
~/.i2p/ on Linux and %LOCALAPPDATA%\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
|
||||
@@ -40,7 +40,7 @@ To uninstall I2P:
|
||||
rm -rf $I2PInstallDir ~/.i2p
|
||||
|
||||
Supported JVMs:
|
||||
All platforms: Java 1.7 or higher required
|
||||
All platforms: Java 1.8 or higher required
|
||||
Windows: OpenJDK or Oracle from http://java.com/download
|
||||
Linux: OpenJDK or Oracle from http://java.com/download
|
||||
FreeBSD: OpenJDK or Oracle from http://java.com/download
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
I2P source installation instructions
|
||||
|
||||
Prerequisites to build from source:
|
||||
Java SDK (preferably Oracle/Sun or OpenJDK) 1.7.0 or higher
|
||||
Java SDK (preferably Oracle or OpenJDK) 8 or higher
|
||||
Non-linux operating systems and JVMs: See https://trac.i2p2.de/wiki/java
|
||||
Certain subsystems for embedded (core, router, mstreaming, streaming, i2ptunnel) require only Java 1.6
|
||||
Apache Ant 1.7.0 or higher
|
||||
Apache Ant 1.9.8 or higher
|
||||
The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
Build environment must use a UTF-8 locale.
|
||||
|
||||
56
LICENSE.txt
56
LICENSE.txt
@@ -36,10 +36,6 @@ Public domain except as listed below:
|
||||
Copyright (c) 2003, TheCrypto
|
||||
See licenses/LICENSE-ElGamalDSA.txt
|
||||
|
||||
HMAC:
|
||||
Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle
|
||||
See licenses/LICENSE-SHA256.txt
|
||||
|
||||
ElGamal:
|
||||
Copyright (c) 2000 - 2013 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org)
|
||||
See licenses/LICENSE-SHA256.txt
|
||||
@@ -82,18 +78,28 @@ Public domain except as listed below:
|
||||
Copyright (c) 1998 by Aaron M. Renn (arenn@urbanophile.com)
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
|
||||
EdDSA-Java:
|
||||
See licenses/LICENSE-CC0-1.0-Universal.txt
|
||||
|
||||
HostnameVerifier:
|
||||
From Apache HttpClient 4.4.1 and HttpCore 4.4.1
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
||||
json-simple 1.1.1
|
||||
json-simple 2.3.0
|
||||
(not included in most distribution packages)
|
||||
Copyright 2016 Clifton Labs
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
||||
Noise library:
|
||||
Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
See licenses/LICENSE-Noise.txt
|
||||
|
||||
MiniDNS library 1.0.0
|
||||
This software may be used under the terms of (at your choice)
|
||||
- LGPL version 2 (or later) (see licenses/LICENSE-LGPL2.1.txt)
|
||||
- Apache Software licence (see licenses/LICENSE-Apache2.0.txt)
|
||||
- DWTFYWTPL
|
||||
|
||||
|
||||
Router (router.jar):
|
||||
Public domain except as listed below:
|
||||
@@ -118,6 +124,14 @@ Public domain except as listed below:
|
||||
Copyright (C) 2016 Southern Storm Software, Pty Ltd.
|
||||
See licenses/LICENSE-Noise.txt
|
||||
|
||||
SparseArray:
|
||||
Copyright (C) 2006 The Android Open Source Project
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
||||
SSU HMAC:
|
||||
Copyright (c) 2000 - 2004 The Legion Of The Bouncy Castle
|
||||
See licenses/LICENSE-SHA256.txt
|
||||
|
||||
|
||||
Installer:
|
||||
(not included in distribution packages)
|
||||
@@ -164,17 +178,18 @@ Installer:
|
||||
|
||||
GeoIP Data:
|
||||
(not included in most distribution packages)
|
||||
This product includes GeoLite2 data created by MaxMind, available from http://www.maxmind.com/
|
||||
See licenses/LICENSE-GeoIP.txt
|
||||
IP Geolocation by DB-IP https://db-ip.com/
|
||||
See https://creativecommons.org/licenses/by/4.0/
|
||||
|
||||
Launchers:
|
||||
(not included in distribution packages)
|
||||
Copyright (c) 2002-2018 EPFL, Lausanne / Lightbend, Inc. , unless otherwise specified.
|
||||
See licenses/LICENSE-Scala.md
|
||||
|
||||
Java Service Wrapper Community Edition 32-bit 3.5.34:
|
||||
Java Service Wrapper Community Edition 3.5.44:
|
||||
(Windows: 3.5.25)
|
||||
(not included in most distribution packages)
|
||||
Copyright (C) 1999-2017 Tanuki Software, Ltd. All Rights Reserved.
|
||||
Copyright (C) 1999-2020 Tanuki Software, Ltd. All Rights Reserved.
|
||||
See licenses/LICENSE-Wrapper.txt
|
||||
|
||||
|
||||
@@ -184,7 +199,7 @@ Jbigi Libraries (jbigi.jar):
|
||||
GMP 4.3.2 / 5.0.2:
|
||||
Copyright 1991, 1996, 1999, 2000, 2007 Free Software Foundation, Inc.
|
||||
See licenses/LICENSE-LGPLv3.txt
|
||||
GMP 6.0.0:
|
||||
GMP 6.0.0 / 6.1.2 / 6.2.0:
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
|
||||
@@ -246,23 +261,22 @@ Applications:
|
||||
Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
Copyright (c) 2008 Alexander von Gernler. All rights reserved.
|
||||
See licenses/LICENSE-BSD.txt
|
||||
Zxing 3.3.0:
|
||||
Zxing 3.4.1:
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
|
||||
Jetty 9.2.25.v20180606 (jetty-*.jar, org.mortbay.*.jar):
|
||||
Jetty 9.3.29.v20201019 (jetty-*.jar, org.mortbay.*.jar):
|
||||
(not included in most distribution packages, except for jetty-i2p.jar)
|
||||
See licenses/ABOUT-Jetty.html
|
||||
See licenses/NOTICE-Jetty.html
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/LICENSE-ECLIPSE-1.0.html
|
||||
|
||||
JRobin 1.6.0-1 (jrobin.jar):
|
||||
RRD4J 3.6 (jrobin.jar):
|
||||
Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
|
||||
Copyright (c) 2011 The OpenNMS Group, Inc.
|
||||
Copyright 2011 The RRD4J Authors.
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/LICENSE-LGPLv2.1.txt
|
||||
DeallocationHelper:
|
||||
Copyright (c) 2006-2016 Julien Gouesse
|
||||
See licenses/LICENSE-GPLv2.txt
|
||||
|
||||
Ministreaming Lib (mstreaming.jar):
|
||||
By mihi.
|
||||
@@ -286,6 +300,12 @@ Applications:
|
||||
FatCow icons: See licenses/LICENSE-FatCowIcons.txt
|
||||
Fugue Icons: See licenses/LICENSE-FugueIcons.txt
|
||||
Feather icons: Copyright (c) 2013-2017 Cole Bemis; see licenses/LICENSE-Feather.txt
|
||||
Fontawesome icons: Copyright (c) 2018 @fontawesome(company) see licenses/LICENSE-fontawesome.txt
|
||||
|
||||
Router Console unthemed, light, and dark theme logos:
|
||||
Copyright (c) 2019 The Invisible Internet Project. All rights reserved.
|
||||
Creative Commons Attribution-ShareAlike 4.0 International License
|
||||
See https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
Router Console and I2PSnark themes:
|
||||
Some images licensed under a Creative Commons 2.0 license.
|
||||
@@ -319,9 +339,9 @@ Applications:
|
||||
Systray (systray.jar):
|
||||
Public domain.
|
||||
|
||||
Tomcat 8.5.38 (jasper-runtime.jar):
|
||||
Tomcat 9.0.40 (jasper-runtime.jar):
|
||||
(not included in most distribution packages)
|
||||
Copyright 1999-2019 The Apache Software Foundation
|
||||
Copyright 1999-2020 The Apache Software Foundation
|
||||
See licenses/LICENSE-Apache2.0.txt
|
||||
See licenses/NOTICE-Tomcat.txt
|
||||
|
||||
|
||||
30
README.md
30
README.md
@@ -2,19 +2,19 @@
|
||||
|
||||
This is the source code for the reference Java implementation of I2P.
|
||||
|
||||
Latest release: https://geti2p.net/download
|
||||
Latest release: [https://geti2p.net/download](https://geti2p.net/download)
|
||||
|
||||
## Installing
|
||||
|
||||
See INSTALL.txt or https://geti2p.net/download for installation instructions.
|
||||
See [INSTALL.txt](INSTALL.txt) or [https://geti2p.net/download](https://geti2p.net/download) for installation instructions.
|
||||
|
||||
## Documentation
|
||||
|
||||
https://geti2p.net/how
|
||||
[https://geti2p.net/how](https://geti2p.net/how)
|
||||
|
||||
FAQ: https://geti2p.net/faq
|
||||
FAQ: [https://geti2p.net/faq](https://geti2p.net/faq)
|
||||
|
||||
API: http://docs.i2p-projekt.de/javadoc/
|
||||
API: [http://docs.i2p-projekt.de/javadoc/](http://docs.i2p-projekt.de/javadoc/)
|
||||
or run 'ant javadoc' then start at build/javadoc/index.html
|
||||
|
||||
## How to contribute / Hack on I2P
|
||||
@@ -23,17 +23,17 @@ Please check out [HACKING.md](docs/HACKING.md) and other documents in the docs d
|
||||
|
||||
## Building packages from source
|
||||
|
||||
To get development branch from source control: https://geti2p.net/newdevelopers
|
||||
To get development branch from source control: [https://geti2p.net/newdevelopers](https://geti2p.net/newdevelopers)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Java SDK (preferably Oracle/Sun or OpenJDK) 1.7.0 or higher
|
||||
- Non-linux operating systems and JVMs: See https://trac.i2p2.de/wiki/java
|
||||
- Java SDK (preferably Oracle or OpenJDK) 8 or higher
|
||||
- Non-linux operating systems and JVMs: See [https://trac.i2p2.de/wiki/java](https://trac.i2p2.de/wiki/java)
|
||||
- Certain subsystems for embedded (core, router, mstreaming, streaming, i2ptunnel)
|
||||
require only Java 1.6
|
||||
- Apache Ant 1.7.0 or higher
|
||||
require only Java 6
|
||||
- Apache Ant 1.9.8 or higher
|
||||
- The xgettext, msgfmt, and msgmerge tools installed from the GNU gettext package
|
||||
http://www.gnu.org/software/gettext/
|
||||
[http://www.gnu.org/software/gettext/](http://www.gnu.org/software/gettext/)
|
||||
- Build environment must use a UTF-8 locale.
|
||||
|
||||
### Ant build process
|
||||
@@ -68,13 +68,13 @@ your `~/.gradle/gradle.properties`:
|
||||
|
||||
Need help? See the IRC channel #i2p on irc.freenode.net
|
||||
|
||||
Bug reports: https://trac.i2p2.de/report/1
|
||||
Bug reports: [https://trac.i2p2.de/report/1](https://trac.i2p2.de/report/1)
|
||||
|
||||
Contact information, security issues, press inquiries: https://geti2p.net/en/contact
|
||||
Contact information, security issues, press inquiries: [https://geti2p.net/en/contact](https://geti2p.net/en/contact)
|
||||
|
||||
Twitter: @i2p, @geti2p
|
||||
Twitter: [@i2p](https://twitter.com/i2p), [@geti2p](https://twitter.com/GetI2P)
|
||||
|
||||
## Licenses
|
||||
|
||||
See LICENSE.txt
|
||||
See [LICENSE.txt](LICENSE.txt)
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
Prerequisites to build from source:
|
||||
Java SDK (preferably Oracle/Sun or OpenJDK) 1.7.0 or higher
|
||||
Java SDK (preferably Oracle or OpenJDK) 8 or higher
|
||||
Non-linux operating systems and JVMs: See https://trac.i2p2.de/wiki/java
|
||||
Certain subsystems for embedded (core, router, mstreaming, streaming, i2ptunnel) require only Java 1.6
|
||||
Apache Ant 1.7.0 or higher
|
||||
Certain subsystems for embedded (core, router, mstreaming, streaming, i2ptunnel) require only Java 6
|
||||
Apache Ant 1.9.8 or higher
|
||||
The xgettext, msgfmt, and msgmerge tools installed
|
||||
from the GNU gettext package http://www.gnu.org/software/gettext/
|
||||
Build environment must use a UTF-8 locale.
|
||||
|
||||
@@ -39,8 +39,9 @@ is divided into following sections:
|
||||
<property file="${user.properties.file}"/>
|
||||
<!-- The two properties below are usually overridden -->
|
||||
<!-- by the active platform. Just a fallback. -->
|
||||
<property name="default.javac.source" value="1.4"/>
|
||||
<property name="default.javac.target" value="1.4"/>
|
||||
<property name="default.javac.source" value="1.8"/>
|
||||
<property name="default.javac.target" value="1.8"/>
|
||||
<property name="javac.release" value="8"/>
|
||||
</target>
|
||||
<target depends="-pre-init,-init-private,-init-user" name="-init-project">
|
||||
<property file="nbproject/configs/${config}.properties"/>
|
||||
@@ -155,7 +156,7 @@ is divided into following sections:
|
||||
<attribute default="/does/not/exist" name="sourcepath"/>
|
||||
<element name="customize" optional="true"/>
|
||||
<sequential>
|
||||
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}">
|
||||
<javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" release="${javac.release}">
|
||||
<classpath>
|
||||
<path path="@{classpath}"/>
|
||||
</classpath>
|
||||
|
||||
@@ -29,28 +29,19 @@ endorsed.classpath=
|
||||
excludes=**/*.html,**/*.txt
|
||||
file.reference.build-javadoc=../../i2p.i2p/build/javadoc
|
||||
file.reference.i2p.jar=../../core/java/build/i2p.jar
|
||||
file.reference.i2ptunnel.jar=../i2ptunnel/java/build/i2ptunnel.jar
|
||||
file.reference.jbigi.jar=../../build/jbigi.jar
|
||||
file.reference.mstreaming.jar=../ministreaming/java/build/mstreaming.jar
|
||||
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/all/wrapper.jar
|
||||
includes=**
|
||||
jar.compress=true
|
||||
javac.classpath=\
|
||||
${file.reference.router.jar}:\
|
||||
${file.reference.i2ptunnel.jar}:\
|
||||
${file.reference.mstreaming.jar}:\
|
||||
${file.reference.streaming.jar}:\
|
||||
${file.reference.wrapper.jar}:\
|
||||
${file.reference.i2p.jar}:\
|
||||
${file.reference.router.jar}
|
||||
${file.reference.i2p.jar}
|
||||
# Space-separated list of extra javac options
|
||||
javac.compilerargs=
|
||||
javac.deprecation=false
|
||||
javac.version=1.7
|
||||
javac.version=1.8
|
||||
javac.source=${javac.version}
|
||||
javac.target=${javac.version}
|
||||
javac.release=8
|
||||
javac.test.classpath=\
|
||||
${javac.classpath}:\
|
||||
${build.classes.dir}:\
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<configuration>
|
||||
<data xmlns="http://www.netbeans.org/ns/j2se-project/3">
|
||||
<name>BOB</name>
|
||||
<minimum-ant-version>1.6.5</minimum-ant-version>
|
||||
<minimum-ant-version>1.9.8</minimum-ant-version>
|
||||
<source-roots>
|
||||
<root id="src.dir"/>
|
||||
</source-roots>
|
||||
|
||||
@@ -38,6 +38,7 @@ import net.i2p.I2PAppContext;
|
||||
import net.i2p.app.*;
|
||||
import net.i2p.client.I2PClient;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.PortMapper;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
@@ -111,7 +112,9 @@ import net.i2p.util.SimpleTimer2;
|
||||
* BOB, main command socket listener, launches the command parser engine.
|
||||
*
|
||||
* @author sponge
|
||||
* @deprecated Please port applications to SAMv3
|
||||
*/
|
||||
@Deprecated
|
||||
public class BOB implements Runnable, ClientApp {
|
||||
|
||||
public final static String PROP_CONFIG_LOCATION = "BOB.config";
|
||||
@@ -140,6 +143,7 @@ public class BOB implements Runnable, ClientApp {
|
||||
|
||||
private volatile ServerSocket listener;
|
||||
private volatile Thread _runner;
|
||||
private volatile boolean _warned;
|
||||
|
||||
/**
|
||||
* Stop BOB gracefully
|
||||
@@ -342,6 +346,12 @@ public class BOB implements Runnable, ClientApp {
|
||||
}
|
||||
|
||||
if (g) {
|
||||
if (!_warned) {
|
||||
_warned = true;
|
||||
String s = "BOB is deprecated. Please port applications to SAMv3.";
|
||||
_context.logManager().getLog(BOB.class).logAlways(Log.WARN, s);
|
||||
_log.warn(s);
|
||||
}
|
||||
DoCMDS conn_c = new DoCMDS(spin, lock, server, props, database, _log);
|
||||
Thread t = new I2PAppThread(conn_c);
|
||||
t.setName("BOB.DoCMDS " + i);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>BOB, the Basic Open Bridge, allows TCP applications to talk over I2P.</p>
|
||||
<p>BOB, the Basic Open Bridge, allows TCP applications to talk over I2P - DEPRECATED - Please port applications to SAMv3.</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
addressbook v2.0.2 - A simple name resolution mechanism for I2P
|
||||
|
||||
addressbook is a simple implementation of subscribable address books for I2P.
|
||||
Addresses are stored in userhosts.txt and a second copy of the address book is
|
||||
placed on your eepsite as hosts.txt.
|
||||
|
||||
subscriptions.txt contains a list of urls to check for new addresses.
|
||||
Since the urls are checked in order, and conflicting addresses are not added,
|
||||
addressbook.subscriptions can be considered to be ranked in order of trust.
|
||||
|
||||
The system created by addressbook is similar to the early days of DNS,
|
||||
when everyone ran a local name server. The major difference is the lack of
|
||||
authority. Name cannot be guaranteed to be globally unique, but in practise
|
||||
they probably will be, for a variety of social reasons.
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
i2p with a running http proxy
|
||||
|
||||
Installation and Usage
|
||||
**********************
|
||||
|
||||
1. Unzip addressbook-%ver.zip into your i2p directory.
|
||||
2. Restart your router.
|
||||
|
||||
The addressbook daemon will automatically run while the router is up.
|
||||
|
||||
Aside from the daemon itself, the other elements of the addressbook interface
|
||||
are the config.txt, myhosts.txt, and subscriptions.txt files found in the addressbook
|
||||
directory.
|
||||
|
||||
config.txt is the configuration file for addressbook.
|
||||
|
||||
myhosts.txt is the addressbook master address book. Addresses placed in this file
|
||||
take precidence over those in the router address book and in remote address books.
|
||||
If changes are made to this file, they will be reflected in the router address book
|
||||
and published address book after the next update. Do not make changes directly to the
|
||||
router address book, as they could be lost during an update.
|
||||
|
||||
subscriptions.txt is the subscription list for addressbook. Each entry is an absolute
|
||||
url to a file in hosts.txt format. Since the list is checked in order, url's should be
|
||||
listed in order of trust.
|
||||
@@ -7,7 +7,8 @@
|
||||
<property name="jar" value="addressbook.jar"/>
|
||||
<property name="war" value="addressbook.war"/>
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.7" />
|
||||
<property name="javac.version" value="1.8" />
|
||||
<property name="javac.release" value="8" />
|
||||
|
||||
<target name="all" depends="jar, emptyWar"/>
|
||||
|
||||
@@ -40,7 +41,9 @@
|
||||
|
||||
<target name="compile" depends="init, depend, warUpToDate">
|
||||
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
release="${javac.release}"
|
||||
includeAntRuntime="false"
|
||||
encoding="UTF-8"
|
||||
srcdir="${src}" destdir="${build}">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
<classpath>
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# This is the configuration file for addressbook.
|
||||
#
|
||||
# Options
|
||||
# *******
|
||||
# All paths are realitive to i2p/addressbook. Default value for
|
||||
# each option is given in parentheses.
|
||||
#
|
||||
# proxy_host The hostname of your I2P http proxy.
|
||||
# (localhost)
|
||||
#
|
||||
# proxy_port The port of your I2P http proxy. (4444)
|
||||
#
|
||||
# master_addressbook The path to your master address book, used for local
|
||||
# changes only. (myhosts.txt)
|
||||
#
|
||||
# router_addressbook The path to the address book used by the router.
|
||||
# Contains the addresses from your master address book
|
||||
# and your subscribed address books. (../userhosts.txt)
|
||||
#
|
||||
# private_addressbook The path to the private address book used by the router.
|
||||
# This is used only by the router and SusiDNS.
|
||||
# It is not published by addressbook. (../privatehosts.txt)
|
||||
#
|
||||
# published_addressbook The path to the copy of your address book made
|
||||
# available on i2p. (../eepsite/docroot/hosts.txt)
|
||||
#
|
||||
# log The path to your addressbook log. (log.txt)
|
||||
#
|
||||
# subscriptions The path to your subscription file. (subscriptions.txt)
|
||||
#
|
||||
# etags The path to the etags header storage file. (etags)
|
||||
#
|
||||
# last_modified The path to the last-modified header storage file.
|
||||
# (last_modified)
|
||||
#
|
||||
# update_delay The time (in hours) between each update. (1)
|
||||
|
||||
proxy_host=localhost
|
||||
proxy_port=4444
|
||||
master_addressbook=myhosts.txt
|
||||
router_addressbook=../userhosts.txt
|
||||
private_addressbook=../privatehosts.txt
|
||||
published_addressbook=../eepsite/docroot/hosts.txt
|
||||
log=log.txt
|
||||
subscriptions=subscriptions.txt
|
||||
etags=etags
|
||||
last_modified=last_modified
|
||||
update_delay=1
|
||||
@@ -166,6 +166,10 @@ class ConfigParser {
|
||||
Map<String, String> result;
|
||||
try {
|
||||
result = parse(file);
|
||||
// migrate
|
||||
String local = result.remove("master_addressbook");
|
||||
if (local != null)
|
||||
result.put("local_addressbook", local);
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
if (!result.containsKey(entry.getKey()))
|
||||
result.put(entry.getKey(), entry.getValue());
|
||||
|
||||
@@ -67,8 +67,8 @@ class Daemon {
|
||||
* Update the router and published address books using remote data from the
|
||||
* subscribed address books listed in subscriptions.
|
||||
*
|
||||
* @param master
|
||||
* The master AddressBook. This address book is never
|
||||
* @param local
|
||||
* The local AddressBook. This address book is never
|
||||
* overwritten, so it is safe for the user to write to.
|
||||
* It is only merged to the published addressbook.
|
||||
* May be null.
|
||||
@@ -77,7 +77,7 @@ class Daemon {
|
||||
* client applications.
|
||||
* @param published
|
||||
* The published AddressBook. This address book is published on
|
||||
* the user's eepsite so that others may subscribe to it.
|
||||
* the user's I2P Site so that others may subscribe to it.
|
||||
* May be null.
|
||||
* If non-null, overwrite with the new addressbook.
|
||||
* @param subscriptions
|
||||
@@ -87,7 +87,7 @@ class Daemon {
|
||||
* The log to write changes and conflicts to.
|
||||
* May be null.
|
||||
*/
|
||||
public static void update(AddressBook master, AddressBook router,
|
||||
public static void update(AddressBook local, AddressBook router,
|
||||
File published, SubscriptionList subscriptions, Log log) {
|
||||
for (AddressBook book : subscriptions) {
|
||||
// yes, the EepGet fetch() is done in next()
|
||||
@@ -95,8 +95,8 @@ class Daemon {
|
||||
}
|
||||
router.write();
|
||||
if (published != null) {
|
||||
if (master != null)
|
||||
router.merge(master, true, null);
|
||||
if (local != null)
|
||||
router.merge(local, true, null);
|
||||
router.write(published);
|
||||
}
|
||||
subscriptions.write();
|
||||
@@ -105,13 +105,13 @@ class Daemon {
|
||||
/**
|
||||
* Update the router and published address books using remote data from the
|
||||
* subscribed address books listed in subscriptions.
|
||||
* Merging of the "master" addressbook is NOT supported.
|
||||
* Merging of the "local" addressbook is NOT supported.
|
||||
*
|
||||
* @param router
|
||||
* The NamingService to update, generally the root NamingService from the context.
|
||||
* @param published
|
||||
* The published AddressBook. This address book is published on
|
||||
* the user's eepsite so that others may subscribe to it.
|
||||
* the user's I2P Site so that others may subscribe to it.
|
||||
* May be null.
|
||||
* If non-null, overwrite with the new addressbook.
|
||||
* @param subscriptions
|
||||
@@ -751,17 +751,17 @@ class Daemon {
|
||||
if (Boolean.parseBoolean(settings.get("update_direct"))) {
|
||||
// Direct hosts.txt access
|
||||
File routerFile = new File(home, settings.get("router_addressbook"));
|
||||
AddressBook master;
|
||||
AddressBook local;
|
||||
if (should_publish) {
|
||||
File masterFile = new File(home, settings.get("master_addressbook"));
|
||||
master = new AddressBook(masterFile);
|
||||
File localFile = new File(home, settings.get("local_addressbook"));
|
||||
local = new AddressBook(localFile);
|
||||
} else {
|
||||
master = null;
|
||||
local = null;
|
||||
}
|
||||
AddressBook router = new AddressBook(routerFile);
|
||||
update(master, router, published, subscriptions, log);
|
||||
update(local, router, published, subscriptions, log);
|
||||
} else {
|
||||
// Naming service - no merging of master to router and published is supported.
|
||||
// Naming service - no merging of local to router and published is supported.
|
||||
update(getNamingService(settings.get("naming_service")), published, subscriptions, log);
|
||||
}
|
||||
}
|
||||
@@ -841,7 +841,7 @@ class Daemon {
|
||||
Map<String, String> defaultSettings = new HashMap<String, String>();
|
||||
defaultSettings.put("proxy_host", "127.0.0.1");
|
||||
defaultSettings.put("proxy_port", "4444");
|
||||
defaultSettings.put("master_addressbook", "../userhosts.txt");
|
||||
defaultSettings.put("local_addressbook", "../userhosts.txt");
|
||||
defaultSettings.put("router_addressbook", "../hosts.txt");
|
||||
defaultSettings.put("published_addressbook", "../eepsite/docroot/hosts.txt");
|
||||
defaultSettings.put("should_publish", "false");
|
||||
@@ -856,10 +856,10 @@ class Daemon {
|
||||
|
||||
if (!homeFile.exists()) {
|
||||
boolean created = homeFile.mkdirs();
|
||||
if (created)
|
||||
System.out.println("INFO: Addressbook directory " + homeFile.getName() + " created");
|
||||
else
|
||||
System.out.println("ERROR: Addressbook directory " + homeFile.getName() + " could not be created");
|
||||
if (!created)
|
||||
System.out.println("ERROR: Addressbook directory " + homeFile.getAbsolutePath() + " could not be created");
|
||||
//else
|
||||
// System.out.println("INFO: Addressbook directory " + homeFile.getAbsolutePath() + " created");
|
||||
}
|
||||
|
||||
File settingsFile = new File(homeFile, settingsLocation);
|
||||
@@ -868,7 +868,7 @@ class Daemon {
|
||||
// wait
|
||||
try {
|
||||
Thread.sleep(5*60*1000 + I2PAppContext.getGlobalContext().random().nextLong(5*60*1000));
|
||||
// Static method, and redundent Thread.currentThread().sleep(5*60*1000);
|
||||
// Static method, and redundant Thread.currentThread().sleep(5*60*1000);
|
||||
} catch (InterruptedException ie) {}
|
||||
|
||||
while (_running) {
|
||||
|
||||
@@ -138,9 +138,11 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
private static final String VERSION = "4";
|
||||
|
||||
private static final String PROP_ADDED = "a";
|
||||
private static final String PROP_MODDED = "m";
|
||||
// See susidns
|
||||
//private static final String PROP_MODDED = "m";
|
||||
private static final String PROP_SOURCE = "s";
|
||||
private static final String PROP_VALIDATED = "v";
|
||||
// See susidns
|
||||
//private static final String PROP_VALIDATED = "v";
|
||||
|
||||
private static final String DUMMY = "";
|
||||
private static final int NEGATIVE_CACHE_SIZE = 32;
|
||||
@@ -1395,6 +1397,11 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
p = de.propsList.get(i);
|
||||
d = de.destList.get(i);
|
||||
}
|
||||
out.write("# ");
|
||||
out.write(key);
|
||||
out.write(": ");
|
||||
out.write(d.toBase32());
|
||||
out.write(nl);
|
||||
out.write(key);
|
||||
out.write('=');
|
||||
out.write(d.toBase64());
|
||||
@@ -2062,9 +2069,8 @@ public class BlockfileNamingService extends DummyNamingService {
|
||||
}
|
||||
if (baos.size() > 65535)
|
||||
throw new DataFormatException("Properties too big (65535 max): " + baos.size());
|
||||
byte propBytes[] = baos.toByteArray();
|
||||
DataHelper.writeLong(rawStream, 2, propBytes.length);
|
||||
rawStream.write(propBytes);
|
||||
DataHelper.writeLong(rawStream, 2, baos.size());
|
||||
baos.writeTo(rawStream);
|
||||
} else {
|
||||
DataHelper.writeLong(rawStream, 2, 0);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ the API may be subject to change.
|
||||
Contact I2P developers if you are considering use in another application.
|
||||
Following is the original documentation copied from metanotion website.
|
||||
</p>
|
||||
<h1>Metanotion BlockFile Database</h1>
|
||||
<h2>Metanotion BlockFile Database</h2>
|
||||
<p>A 100% Java 1.3, BSD Licensed, embeddable single file database engine in 32KB. This database was designed for PDA based and J2ME applications.</p>
|
||||
|
||||
<h2>Table of Contents</h2>
|
||||
@@ -32,18 +32,18 @@ Following is the original documentation copied from metanotion website.
|
||||
<li><a href="#download">Download</a></li>
|
||||
</ul>
|
||||
|
||||
<a name="features"><h2>Features</h2></a>
|
||||
<h2 id="features">Features</h2>
|
||||
<ul>
|
||||
<li>100% Java 1.3. No JNI.</li>
|
||||
<li>Will work with any "file" as long as you can approximate something like <a href="http://java.sun.com/j2se/1.3/docs/api/java/io/RandomAccessFile.html">java.io.RandomAccessFile</a>, you can use this.</li>
|
||||
<li>BSD Licensed. Yes, this means you can use it for free in a commercial project. However, if you base some really cool mobile technology startup on this code we'll gladly accept stock options...</p>
|
||||
<li>BSD Licensed. Yes, this means you can use it for free in a commercial project. However, if you base some really cool mobile technology startup on this code we'll gladly accept stock options...</li>
|
||||
<li>No dependence on file API's(useful for mobile apps)</li>
|
||||
<li>Small. 32KB in a JAR file. <2000 lines of code.</li>
|
||||
<li>Reasonably fast. This is used in an app running on a sub 200MHz StrongARM PocketPC, and quite handily deals with 70,000 records. The load time is a little slow, but its been tested with a <a href="http://java.sun.com/javame/reference/apis.jsp">CDC 1.0/Personal Profile</a> device.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<a name="unfeatures"><h2>Unfeatures</h2></a>
|
||||
<h2 id="unfeatures">Unfeatures</h2>
|
||||
<p>A good, ACID database is a nice thing to work with. Unfortunately, in the goal to make this small, fast, and work with minimal dependencies, something had to give. So I list things which this database will likely never have. Of course, since it is BSD Licensed, patches welcome...</p>
|
||||
|
||||
<ul>
|
||||
@@ -53,11 +53,11 @@ Following is the original documentation copied from metanotion website.
|
||||
<li>No use of reflection or automagical serialization tricks.</li>
|
||||
</ul>
|
||||
|
||||
<a name="future"><h2>Future Plans</h2></a>
|
||||
<h2 id="future">Future Plans</h2>
|
||||
<p>There are still bugs(none known...). The app that this was written for is still in testing, but we should most of the issues sorted by the time we deploy it in a few weeks(early November, 2006). Some loading speed issues on large record sets, and memory usage could still be improved. All this and feedback from other uses will direct this products evolution.</p>
|
||||
<p>What is currently up here is not "1.0" code, but we will release a labeled "1.0" version once we feel happy with the state of the codebase.</p>
|
||||
|
||||
<a name="design"><h2>What KIND of database is this?</h2></a>
|
||||
<h2 id="design">What KIND of database is this?</h2>
|
||||
<p>You probably store at least part of your application data in memory in a class from the <a href="http://java.sun.com/j2se/1.4.2/docs/guide/collections/">Java Collections Framework</a>. The BlockFile database stores data in a <a href="http://en.wikipedia.org/wiki/Skip_list">Skip</a> <a href="http://eternallyconfuzzled.com/tuts/skip.html">List</a> that almost implements <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/util/SortedMap.html">java.util.SortedMap</a>. You can create and store as many named(with a string) SkipList in the database as you want.</p>
|
||||
<p>To serialize your data, you have to either extend our SerialStreams class or implement our Serializer interface. We could have done something cool and fancy with reflection(and other cool stuff with Java 1.5), but that would probably not do the Right Thing™ most of the time. As you can see, there's not a lot to it anyway:</p>
|
||||
<h3>net.metanotion.io.SerialStreams</h3>
|
||||
@@ -91,9 +91,8 @@ public class SkipList {
|
||||
public ListIterator find(Comparable key) ...
|
||||
}
|
||||
</pre>
|
||||
</p>
|
||||
|
||||
<a name="examples"><h2>Examples</h2></a>
|
||||
<h2 id="examples">Examples</h2>
|
||||
<p>Better documentation is forthcoming, but there really isn't much to know. The entire public interface to the library is on this page. Where possible, it sticks to idiomatic Java and standard interfaces.</p>
|
||||
<ul>
|
||||
<li>Open a database:
|
||||
@@ -146,8 +145,8 @@ public class BlockFile implements Closeable {
|
||||
|
||||
<p>So, in other words, if you can provide an implementation of this interface, you can use the BlockFile database. This frees it from dependence on the RandomAccessFile class. If you don't see why this is useful and you're going to be using "files" on PDA's and phone's, well, you'll understand soon enough...</p>
|
||||
|
||||
<a name="download"><h2>Download</h2></a>
|
||||
<h3>Bugfix and cleanup Release 10/6/2006</h2>
|
||||
<h2 id="download">Download</h2>
|
||||
<h3>Bugfix and cleanup Release 10/6/2006</h3>
|
||||
<p>An unnecessary class was removed, some junk methods removed, and a couple of JDK compatability issues were fixed. The StringBytes class was switched to ASCII(from UTF-8) for better compatibility.</p>
|
||||
<ul>
|
||||
<li><a href="http://www.metanotion.net/software/sandbox/BlockFile.2006.10.06.jar">BlockFile binary JAR, version 0.1.1</a></li>
|
||||
@@ -160,7 +159,7 @@ public class BlockFile implements Closeable {
|
||||
<li><a href="http://www.metanotion.net/software/sandbox/BlockFile.src.2006.09.28.zip">BlockFile source code</a></li>
|
||||
</ul>
|
||||
|
||||
<hr />
|
||||
<center>© 2006 <a href="http://www.metanotion.net/">Metanotion Software</a></center>
|
||||
<hr>
|
||||
<p>© 2006 <a href="http://www.metanotion.net/">Metanotion Software</a></p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# addressbook master address book. Addresses placed in this file take precidence
|
||||
# over those in the router address book and in remote address books. If changes
|
||||
# are made to this file, they will be reflected in the router address book and
|
||||
# published address book after the next update.
|
||||
#
|
||||
# Do not make changes directly to the router address book, as they could be lost
|
||||
# during an update.
|
||||
#
|
||||
# This file takes addresses in the hosts.txt format, i.e.
|
||||
# example.i2p=somereallylongbase64thingAAAA
|
||||
@@ -1,7 +0,0 @@
|
||||
# Subscription list for addressbook
|
||||
#
|
||||
# Each entry is an absolute url to a file in hosts.txt format.
|
||||
# Since the list is checked in order, url's should be listed in order of trust.
|
||||
#
|
||||
http://dev.i2p/i2p/hosts.txt
|
||||
http://duck.i2p/hosts.txt
|
||||
@@ -1,99 +0,0 @@
|
||||
#Last Modified: Sun Dec 06 12:30:32 2015
|
||||
# vim:syntax=apparmor et ts=8 sw=4
|
||||
|
||||
#include <tunables/global>
|
||||
|
||||
$INSTALL_PATH/{i2prouter,runplain.sh} flags=(complain) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/fonts>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/ssl_certs>
|
||||
|
||||
capability sys_ptrace,
|
||||
network inet stream,
|
||||
network inet6 stream,
|
||||
|
||||
$INSTALL_PATH/ r,
|
||||
$INSTALL_PATH/{i2psvc,wrapper} rmix,
|
||||
owner $INSTALL_PATH/** rwkm,
|
||||
|
||||
# Needed for Java
|
||||
owner @{PROC} r,
|
||||
owner @{PROC}/[0-9]*/ r,
|
||||
owner @{PROC}/[0-9]*/status r,
|
||||
owner @{PROC}/[0-9]*/stat r,
|
||||
owner @{PROC}/[0-9]*/cmdline r,
|
||||
@{PROC}/uptime r,
|
||||
@{PROC}/sys/kernel/pid_max r,
|
||||
/sys/devices/system/cpu/ r,
|
||||
/sys/devices/system/cpu/** r,
|
||||
|
||||
/dev/random r,
|
||||
/dev/urandom r,
|
||||
|
||||
@{PROC}/1/comm r,
|
||||
|
||||
/etc/ssl/certs/java/** r,
|
||||
/etc/timezone r,
|
||||
/usr/share/javazi/** r,
|
||||
|
||||
# Debian
|
||||
/etc/java-{6,7,8}-openjdk/** r,
|
||||
/usr/lib/jvm/default-java/jre/bin/java rix,
|
||||
|
||||
# Debian, Ubuntu, openSUSE
|
||||
/usr/lib{,32,64}/jvm/java-*-openjdk-*/jre/bin/java rix,
|
||||
/usr/lib{,32,64}/jvm/java-*-openjdk-*/jre/bin/keytool rix,
|
||||
|
||||
# Raspbian
|
||||
/usr/lib/jvm/jdk-*-oracle-*/jre/bin/java rix,
|
||||
/usr/lib/jvm/jdk-*-oracle-*/jre/bin/keytool rix,
|
||||
|
||||
|
||||
# Fonts are needed for I2P's graphs
|
||||
/usr/share/java/java-atk-wrapper.jar r,
|
||||
|
||||
# Used by some plugins
|
||||
/usr/share/java/eclipse-ecj-*.jar r,
|
||||
|
||||
/{,var/}tmp/ rwm,
|
||||
owner /{,var/}tmp/** rwkm,
|
||||
|
||||
/{,usr/}bin/{,b,d}ash rix,
|
||||
/{,usr/}bin/cat rix,
|
||||
/{,usr/}bin/cut rix,
|
||||
/{,usr/}bin/dirname rix,
|
||||
/{,usr/}bin/expr rix,
|
||||
/{,usr/}bin/{,g,m}awk rix,
|
||||
/{,usr/}bin/grep rix,
|
||||
/{,usr/}bin/id rix,
|
||||
/{,usr/}bin/ldd rix,
|
||||
/{,usr/}bin/ls rix,
|
||||
/{,usr/}bin/mkdir rix,
|
||||
/{,usr/}bin/nohup rix,
|
||||
/{,usr/}bin/ps rix,
|
||||
/{,usr/}bin/rm rix,
|
||||
/{,usr/}bin/sed rix,
|
||||
/{,usr/}bin/sleep rix,
|
||||
/{,usr/}bin/tail rix,
|
||||
/{,usr/}bin/tr rix,
|
||||
/{,usr/}bin/uname rix,
|
||||
/{,usr/}bin/which rix,
|
||||
|
||||
@{HOME}/.java/fonts/** r,
|
||||
owner @{HOME}/.i2p/ rw,
|
||||
owner @{HOME}/.i2p/** rwk,
|
||||
|
||||
# Prevent spamming the logs
|
||||
deny owner @{HOME}/.java/ wk,
|
||||
deny @{HOME}/.fontconfig/ wk,
|
||||
deny @{HOME}/.java/fonts/** w,
|
||||
deny /dev/tty rw,
|
||||
deny /dev/pts/[0-9]* rw,
|
||||
deny @{PROC}/[0-9]*/fd/ r,
|
||||
deny /usr/local/share/fonts/ r,
|
||||
deny /var/cache/fontconfig/ wk,
|
||||
# Used by some versions of the Tanuki wrapper but never used by I2P
|
||||
deny /usr/share/java/hamcrest*.jar r,
|
||||
deny /usr/share/java/junit*.jar r,
|
||||
}
|
||||
@@ -2,6 +2,7 @@ sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'src'
|
||||
srcDir 'build/messages-src'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,3 +13,14 @@ dependencies {
|
||||
compile project(':installer')
|
||||
compile project(':apps:systray')
|
||||
}
|
||||
|
||||
// Create the java files from the po files. The jar task will compile them.
|
||||
// This requires gettext 0.19 or higher.
|
||||
// We don't support the "slow way"
|
||||
task bundle {
|
||||
doLast {
|
||||
if (!(new File("$buildDir/classes/java/main/net/i2p/desktopgui/messages_de.class")).exists())
|
||||
println "apps/desktopgui/bundle-messages.sh".execute().text
|
||||
}
|
||||
}
|
||||
jar.dependsOn bundle
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
<property name="jar" value="desktopgui.jar"/>
|
||||
<property name="javadoc" value="javadoc"/>
|
||||
<property name="javac.compilerargs" value=""/>
|
||||
<property name="javac.version" value="1.7" />
|
||||
<property name="javac.version" value="1.8" />
|
||||
<property name="javac.release" value="8" />
|
||||
<property name="require.gettext" value="true" />
|
||||
|
||||
<condition property="no.bundle">
|
||||
@@ -27,7 +28,9 @@
|
||||
|
||||
<target name="compile" depends="init">
|
||||
<javac debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
release="${javac.release}"
|
||||
includeAntRuntime="false"
|
||||
encoding="UTF-8"
|
||||
srcdir="${src}" destdir="${build}">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
<classpath>
|
||||
@@ -51,7 +54,9 @@
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<javac source="${javac.version}" target="${javac.version}"
|
||||
release="${javac.release}"
|
||||
includeAntRuntime="false"
|
||||
encoding="UTF-8"
|
||||
srcdir="${build}/messages-src" destdir="${build}">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
@@ -75,12 +80,14 @@
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<!-- ideal for linux: 24x24, but transparency doesn't work -->
|
||||
<copy tofile="${build}/desktopgui/resources/images/logo.png" file="../../installer/resources/themes/console/images/itoopie_xsm.png" />
|
||||
<copy tofile="${build}/desktopgui/resources/images/logo.png" file="../../apps/routerconsole/jsp/themes/console/images/itoopie_xsm.png" />
|
||||
<copy todir="${build}/desktopgui/resources/images" file="images/itoopie_black_24.png" />
|
||||
<copy todir="${build}/desktopgui/resources/images" file="images/itoopie_white_24.png" />
|
||||
<jar basedir="${build}" excludes="messages-src/**" destfile="${dist}/${jar}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="net.i2p.desktopgui.Main"/>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
<attribute name="Built-By" value="${build.built-by}" />
|
||||
<attribute name="Build-Date" value="${build.timestamp}" />
|
||||
<attribute name="Base-Revision" value="${workspace.version}" />
|
||||
<attribute name="Workspace-Changes" value="${workspace.changes.tr}" />
|
||||
|
||||
7
apps/desktopgui/bundle-messages.sh
Normal file → Executable file
7
apps/desktopgui/bundle-messages.sh
Normal file → Executable file
@@ -11,6 +11,7 @@
|
||||
# zzz - public domain
|
||||
# Mathiasdm - modifications for desktopgui
|
||||
#
|
||||
cd `dirname $0`
|
||||
CLASS=net.i2p.desktopgui.messages
|
||||
TMPFILE=build/javafiles.txt
|
||||
export TZ=UTC
|
||||
@@ -105,12 +106,12 @@ do
|
||||
# only generate for non-source language
|
||||
echo "Generating ${CLASS}_$LG ResourceBundle..."
|
||||
|
||||
msgfmt -V | grep -q '0\.19'
|
||||
msgfmt -V | grep -q -E ' 0\.((19)|[2-9])'
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
# slow way
|
||||
# convert to class files in build
|
||||
msgfmt --java --statistics -r $CLASS -l $LG -d build $i
|
||||
msgfmt --java2 --statistics -r $CLASS -l $LG -d build $i
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "ERROR - msgfmt failed on ${i}, not updating translations"
|
||||
@@ -128,7 +129,7 @@ do
|
||||
TDY=$TD2/net/i2p/desktopgui
|
||||
rm -rf $TD
|
||||
mkdir -p $TD $TDY
|
||||
msgfmt --java --statistics --source -r $CLASS -l $LG -d $TD $i
|
||||
msgfmt --java2 --statistics --source -r $CLASS -l $LG -d $TD $i
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "ERROR - msgfmt failed on ${i}, not updating translations"
|
||||
|
||||
94
apps/desktopgui/locale/messages_es_AR.po
Normal file
94
apps/desktopgui/locale/messages_es_AR.po
Normal file
@@ -0,0 +1,94 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# kaze kaze <kaze@rlab.be>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-11-16 15:29+0000\n"
|
||||
"Last-Translator: kaze kaze <kaze@rlab.be>\n"
|
||||
"Language-Team: Spanish (Argentina) (http://www.transifex.com/otf/I2P/language/es_AR/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: es_AR\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Iniciando I2P..."
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P esta iniciando!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "Iniciando"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Lanzar el Navegador I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Configurar la Bandeja de Sistema de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Deshabilitar"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Riniciar I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Detener I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr " Reiniciar I2P inmediatamente "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr " Detener I2P inmediatamente "
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Cancelar el Apagado de I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Apagar en {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Apagado inminente"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Red"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P Clic derecho para el menú"
|
||||
@@ -6,19 +6,20 @@
|
||||
# Translators:
|
||||
# Amir H. Firouzian, 2017
|
||||
# NoProfile, 2016
|
||||
# Reza Ghasemi, 2019
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2018-01-05 02:54+0000\n"
|
||||
"Last-Translator: Amir H. Firouzian\n"
|
||||
"PO-Revision-Date: 2019-07-02 14:46+0000\n"
|
||||
"Last-Translator: Reza Ghasemi\n"
|
||||
"Language-Team: Persian (http://www.transifex.com/otf/I2P/language/fa/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: fa\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
@@ -53,7 +54,7 @@ msgstr "غیرفعال کن"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr ""
|
||||
msgstr "راه اندازی مجدد I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
@@ -63,17 +64,17 @@ msgstr "توقف I2P"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr ""
|
||||
msgstr "راه اندازی مجدد I2P بلافاصله"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr ""
|
||||
msgstr "توقف I2P بلافاصله"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr ""
|
||||
msgstr "لغو خاموش کردن I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
@@ -87,7 +88,7 @@ msgstr ""
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr ""
|
||||
msgstr "شبکه"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# AO <ao@localizationlab.org>, 2019
|
||||
# blabla <blabla@trash-mail.com>, 2011
|
||||
# Boxoa590, 2013
|
||||
# ducki2p <ducki2p@gmail.com>, 2011
|
||||
# foo <foo@bar>, 2009
|
||||
# French language coordinator <french.coordinator@rbox.me>, 2017
|
||||
# French language coordinator <french.coordinator@rbox.me>, 2017
|
||||
# AO <ao@localizationlab.org>, 2017
|
||||
# AO <ao@localizationlab.org>, 2017
|
||||
# Boxoa590, 2013
|
||||
# Towinet, 2016
|
||||
msgid ""
|
||||
@@ -17,8 +18,8 @@ msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-10-25 17:51+0000\n"
|
||||
"Last-Translator: French language coordinator <french.coordinator@rbox.me>\n"
|
||||
"PO-Revision-Date: 2019-12-03 16:10+0000\n"
|
||||
"Last-Translator: AO <ao@localizationlab.org>\n"
|
||||
"Language-Team: French (http://www.transifex.com/otf/I2P/language/fr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -34,7 +35,7 @@ msgstr "Démarrer I2P"
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P démarre !"
|
||||
msgstr "I2P démarre !"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
@@ -98,4 +99,4 @@ msgstr "Réseau"
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P : clic droit pour obtenir le menu"
|
||||
msgstr "I2P : clic droit pour obtenir le menu"
|
||||
|
||||
94
apps/desktopgui/locale/messages_ku.po
Normal file
94
apps/desktopgui/locale/messages_ku.po
Normal file
@@ -0,0 +1,94 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Zagros <zagros21@cmail.nu>, 2020
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2020-09-23 21:02+0000\n"
|
||||
"Last-Translator: Zagros <zagros21@cmail.nu>\n"
|
||||
"Language-Team: Kurdish (http://www.transifex.com/otf/I2P/language/ku/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ku\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "I2P بەکاربخە"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "وا I2P دەستپێدەکات!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "دەستپێکردن"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "وێبگەڕی I2P بکەوە"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr ""
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "ناچالاکبکە"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P بەکاربخەوە"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P بوەستێنە"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "دەستبەجێ I2P بەکاربخەوە"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "دەستبەجێ I2P بوەستێنە"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "کووژاندنەوە I2P هەڵبوەشێنەوە"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "دەکووژێتەوە لە {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "دەستبەجێ کووژانەوە"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "ڕایەڵە"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: کرتەی ڕاست بکە بۆ لیستەکان"
|
||||
@@ -10,8 +10,8 @@ msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: zzzi2p\n"
|
||||
"PO-Revision-Date: 2019-05-01 07:33+0000\n"
|
||||
"Last-Translator: Giovanni Pellerano <giovanni.pellerano@evilaliv3.org>\n"
|
||||
"Language-Team: Malagasy (http://www.transifex.com/otf/I2P/language/mg/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -47,7 +47,7 @@ msgstr ""
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr ""
|
||||
msgstr "Désactiver"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
|
||||
94
apps/desktopgui/locale/messages_sr.po
Normal file
94
apps/desktopgui/locale/messages_sr.po
Normal file
@@ -0,0 +1,94 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Slobodan Simić <slsimic@gmail.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2019-07-11 00:36+0000\n"
|
||||
"Last-Translator: Aleksa Ristić\n"
|
||||
"Language-Team: Serbian (http://www.transifex.com/otf/I2P/language/sr/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: sr\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "Покрени И2П"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "И2П се покреће!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "Покрећем"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "Покрени И2П прегледач"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "Подеси И2П системску касету"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Искључи"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "Поново покрени И2П"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "Заустави И2П"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "Рестартуј И2П одмах"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Заустави И2П одмах"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "Откажи И2П гашење"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "Гашење за {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Гашење неизбежно"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Мрежа"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "И2П: десни клик за мени"
|
||||
94
apps/desktopgui/locale/messages_tk.po
Normal file
94
apps/desktopgui/locale/messages_tk.po
Normal file
@@ -0,0 +1,94 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# Alperen Yavuz <mingyu@yaani.com>, 2020
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2020-08-26 20:48+0000\n"
|
||||
"Last-Translator: Alperen Yavuz <mingyu@yaani.com>\n"
|
||||
"Language-Team: Turkmen (http://www.transifex.com/otf/I2P/language/tk/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: tk\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "I2P başlaň"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P başlaýar!"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "Başlamak"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "I2P brauzerini işe giriziň"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "I2P ulgam lýubkasyny sazlaň"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "Öçüriň"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "I2P-i täzeden açyň"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "I2P bes et"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "I2P derrew täzeden açyň"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "Derrew I2P duruzyň"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "I2P ýapmagy ýatyryň"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "{0} in ýapmak"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "Öçürmek ýakyn"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "Tor"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P: Menýu üçin sag basyň"
|
||||
@@ -6,14 +6,14 @@
|
||||
# Translators:
|
||||
# ducki2p <ducki2p@gmail.com>, 2011
|
||||
# walking <walking@i2pmail.org>, 2011
|
||||
# YF <yfdyh000@gmail.com>, 2016
|
||||
# YFdyh000 <yfdyh000@gmail.com>, 2016
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2017-06-30 21:32+0000\n"
|
||||
"Last-Translator: YF <yfdyh000@gmail.com>\n"
|
||||
"PO-Revision-Date: 2019-06-20 03:18+0000\n"
|
||||
"Last-Translator: Beta Ba <linsui555@gmail.com>\n"
|
||||
"Language-Team: Chinese (China) (http://www.transifex.com/otf/I2P/language/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -39,7 +39,7 @@ msgstr "正在启动"
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "正在启动I2P浏览器"
|
||||
msgstr "启动 I2P 浏览器"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
|
||||
94
apps/desktopgui/locale/messages_zh_TW.po
Normal file
94
apps/desktopgui/locale/messages_zh_TW.po
Normal file
@@ -0,0 +1,94 @@
|
||||
# I2P
|
||||
# Copyright (C) 2009 The I2P Project
|
||||
# This file is distributed under the same license as the desktopgui package.
|
||||
# To contribute translations, see http://www.i2p2.de/newdevelopers
|
||||
#
|
||||
# Translators:
|
||||
# 黃彥儒 <r1235613@gmail.com>, 2017
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: I2P\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2016-05-25 12:29+0000\n"
|
||||
"PO-Revision-Date: 2018-10-04 00:43+0000\n"
|
||||
"Last-Translator: erinm\n"
|
||||
"Language-Team: Chinese (Taiwan) (http://www.transifex.com/otf/I2P/language/zh_TW/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: zh_TW\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:31
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:59
|
||||
msgid "Start I2P"
|
||||
msgstr "啟動I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "I2P is starting!"
|
||||
msgstr "I2P已啟動"
|
||||
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:44
|
||||
#: src/net/i2p/desktopgui/ExternalTrayManager.java:72
|
||||
msgid "Starting"
|
||||
msgstr "啟動中"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:55
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:207
|
||||
msgid "Launch I2P Browser"
|
||||
msgstr "開啟I2P瀏覽器"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:76
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:228
|
||||
msgid "Configure I2P System Tray"
|
||||
msgstr "設定I2P系統文件夾"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:77
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:229
|
||||
msgid "Disable"
|
||||
msgstr "停用"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:93
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:245
|
||||
msgid "Restart I2P"
|
||||
msgstr "重啟I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:110
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:262
|
||||
msgid "Stop I2P"
|
||||
msgstr "停止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:126
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:278
|
||||
msgid "Restart I2P Immediately"
|
||||
msgstr "強制重啟I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:143
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:295
|
||||
msgid "Stop I2P Immediately"
|
||||
msgstr "強制終止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:157
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:309
|
||||
msgid "Cancel I2P Shutdown"
|
||||
msgstr "取消停止I2P"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:363
|
||||
#, java-format
|
||||
msgid "Shutdown in {0}"
|
||||
msgstr "關閉於 {0}"
|
||||
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:365
|
||||
msgid "Shutdown imminent"
|
||||
msgstr "強制關閉"
|
||||
|
||||
#. status translations are in the console bundle
|
||||
#: src/net/i2p/desktopgui/InternalTrayManager.java:370
|
||||
msgid "Network"
|
||||
msgstr "網路"
|
||||
|
||||
#. Windows typically has tooltips; Linux (at least Ubuntu) doesn't
|
||||
#: src/net/i2p/desktopgui/TrayManager.java:63
|
||||
msgid "I2P: Right-click for menu"
|
||||
msgstr "I2P:右鍵開啟選單"
|
||||
22
apps/i2pcontrol/build.gradle
Normal file
22
apps/i2pcontrol/build.gradle
Normal file
@@ -0,0 +1,22 @@
|
||||
plugins {
|
||||
id 'war'
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'java'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
providedCompile project(':router')
|
||||
providedCompile project(':apps:jetty')
|
||||
providedCompile files('../../installer/lib/wrapper/all/wrapper.jar')
|
||||
}
|
||||
|
||||
war {
|
||||
archiveName 'jsonrpc.war'
|
||||
webXml = file('web.xml')
|
||||
}
|
||||
@@ -50,7 +50,8 @@
|
||||
</target>
|
||||
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.7" />
|
||||
<property name="javac.version" value="1.8" />
|
||||
<property name="javac.release" value="8" />
|
||||
|
||||
<target name="compile" depends="builddep" >
|
||||
<mkdir dir="./build" />
|
||||
@@ -58,7 +59,9 @@
|
||||
<javac
|
||||
srcdir="./java"
|
||||
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
release="${javac.release}"
|
||||
includeAntRuntime="false"
|
||||
encoding="UTF-8"
|
||||
destdir="./build/obj"
|
||||
classpath="${cp}">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
@@ -76,7 +79,9 @@
|
||||
sourcepath=""
|
||||
srcdir="./java"
|
||||
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
release="${javac.release}"
|
||||
includeAntRuntime="false"
|
||||
encoding="UTF-8"
|
||||
destdir="./build/obj"
|
||||
classpath="${cpSocket}">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
@@ -88,6 +93,8 @@
|
||||
</target>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar destfile="build/i2pcontrol.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
<manifest>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
@@ -102,6 +109,8 @@
|
||||
</target>
|
||||
|
||||
<target name="socketJar" depends="compileSocketJar">
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<jar destfile="build/i2pcontrol.jar" basedir="./build/obj" includes="**/*.class" >
|
||||
<manifest>
|
||||
<attribute name="Implementation-Version" value="${full.version}" />
|
||||
@@ -116,6 +125,8 @@
|
||||
</target>
|
||||
|
||||
<target name="war" depends="compile" >
|
||||
<!-- set if unset -->
|
||||
<property name="workspace.changes.tr" value="" />
|
||||
<war destfile="build/jsonrpc.war" webxml="web.xml" >
|
||||
<classes dir="./build/obj" excludes="net/i2p/i2pcontrol/I2PControlController.class net/i2p/i2pcontrol/HostCheckHandler.class net/i2p/i2pcontrol/SocketController*.class" />
|
||||
<manifest>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.thetransactioncompany.jsonrpc2;
|
||||
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JsonObject;
|
||||
|
||||
|
||||
/**
|
||||
@@ -220,7 +220,7 @@ public class JSONRPC2Error extends Exception {
|
||||
* @see #toJSONObject
|
||||
*/
|
||||
@Deprecated
|
||||
public JSONObject toJSON() {
|
||||
public JsonObject toJSON() {
|
||||
|
||||
return toJSONObject();
|
||||
}
|
||||
@@ -231,9 +231,9 @@ public class JSONRPC2Error extends Exception {
|
||||
*
|
||||
* @return A JSON object representing this error object.
|
||||
*/
|
||||
public JSONObject toJSONObject() {
|
||||
public JsonObject toJSONObject() {
|
||||
|
||||
JSONObject out = new JSONObject();
|
||||
JsonObject out = new JsonObject();
|
||||
|
||||
out.put("code", code);
|
||||
out.put("message", super.getMessage());
|
||||
|
||||
@@ -5,8 +5,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.simple.JSONAware;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JsonObject;
|
||||
|
||||
|
||||
/**
|
||||
@@ -54,7 +53,7 @@ import org.json.simple.JSONObject;
|
||||
*
|
||||
* @author Vladimir Dzhuvinov
|
||||
*/
|
||||
public abstract class JSONRPC2Message implements JSONAware {
|
||||
public abstract class JSONRPC2Message {
|
||||
|
||||
|
||||
/**
|
||||
@@ -220,7 +219,7 @@ public abstract class JSONRPC2Message implements JSONAware {
|
||||
*
|
||||
* @return The JSON object.
|
||||
*/
|
||||
public abstract JSONObject toJSONObject();
|
||||
public abstract JsonObject toJSONObject();
|
||||
|
||||
|
||||
/**
|
||||
@@ -246,6 +245,6 @@ public abstract class JSONRPC2Message implements JSONAware {
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
return toJSONObject().toString();
|
||||
return toJSONObject().toJson();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ package com.thetransactioncompany.jsonrpc2;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JsonObject;
|
||||
|
||||
|
||||
/**
|
||||
@@ -414,9 +414,9 @@ public class JSONRPC2Notification extends JSONRPC2Message {
|
||||
|
||||
|
||||
@Override
|
||||
public JSONObject toJSONObject() {
|
||||
public JsonObject toJSONObject() {
|
||||
|
||||
JSONObject notf = new JSONObject();
|
||||
JsonObject notf = new JsonObject();
|
||||
|
||||
notf.put("method", method);
|
||||
|
||||
|
||||
@@ -4,9 +4,8 @@ package com.thetransactioncompany.jsonrpc2;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.simple.parser.ContainerFactory;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.json.simple.Jsoner;
|
||||
import org.json.simple.DeserializationException;
|
||||
|
||||
|
||||
/**
|
||||
@@ -56,12 +55,6 @@ import org.json.simple.parser.ParseException;
|
||||
public class JSONRPC2Parser {
|
||||
|
||||
|
||||
/**
|
||||
* Reusable JSON parser. Not thread-safe!
|
||||
*/
|
||||
private final JSONParser parser;
|
||||
|
||||
|
||||
/**
|
||||
* If {@code true} the order of the parsed JSON object members must be
|
||||
* preserved.
|
||||
@@ -153,10 +146,7 @@ public class JSONRPC2Parser {
|
||||
public JSONRPC2Parser(final boolean preserveOrder,
|
||||
final boolean ignoreVersion,
|
||||
final boolean parseNonStdAttributes) {
|
||||
|
||||
// Numbers parsed as long/double, requires JSON Smart 1.0.9+
|
||||
parser = new JSONParser();
|
||||
|
||||
|
||||
this.preserveOrder = preserveOrder;
|
||||
this.ignoreVersion = ignoreVersion;
|
||||
this.parseNonStdAttributes = parseNonStdAttributes;
|
||||
@@ -189,13 +179,9 @@ public class JSONRPC2Parser {
|
||||
|
||||
// Parse the JSON string
|
||||
try {
|
||||
//if (preserveOrder)
|
||||
// json = parser.parse(jsonString, ContainerFactory.FACTORY_ORDERED);
|
||||
|
||||
//else
|
||||
json = parser.parse(jsonString);
|
||||
json = Jsoner.deserialize(jsonString);
|
||||
|
||||
} catch (ParseException e) {
|
||||
} catch (DeserializationException e) {
|
||||
|
||||
// Terse message, do not include full parse exception message
|
||||
throw new JSONRPC2ParseException("Invalid JSON",
|
||||
|
||||
@@ -4,7 +4,7 @@ package com.thetransactioncompany.jsonrpc2;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JsonObject;
|
||||
|
||||
|
||||
/**
|
||||
@@ -472,9 +472,9 @@ public class JSONRPC2Request extends JSONRPC2Message {
|
||||
|
||||
|
||||
@Override
|
||||
public JSONObject toJSONObject() {
|
||||
public JsonObject toJSONObject() {
|
||||
|
||||
JSONObject req = new JSONObject();
|
||||
JsonObject req = new JsonObject();
|
||||
|
||||
req.put("method", method);
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package com.thetransactioncompany.jsonrpc2;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.JsonObject;
|
||||
|
||||
|
||||
/**
|
||||
@@ -384,9 +384,9 @@ public class JSONRPC2Response extends JSONRPC2Message {
|
||||
|
||||
|
||||
@Override
|
||||
public JSONObject toJSONObject() {
|
||||
public JsonObject toJSONObject() {
|
||||
|
||||
JSONObject out = new JSONObject();
|
||||
JsonObject out = new JsonObject();
|
||||
|
||||
// Result and error are mutually exclusive
|
||||
if (error != null) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* exception of <i>batching / multicall</i>. This feature is deliberately left
|
||||
* out as it tends to confuse users (judging by posts in the JSON-RPC forum).
|
||||
*
|
||||
* <p>See the <a href="http://www.jsonrpc.org/specification"></a>JSON-RPC 2.0
|
||||
* <p>See the <a href="http://www.jsonrpc.org/specification">JSON-RPC 2.0
|
||||
* specification</a> for more information or write to the
|
||||
* <a href="https://groups.google.com/forum/#!forum/json-rpc">user group</a> if
|
||||
* you have questions.
|
||||
|
||||
@@ -55,7 +55,7 @@ import java.util.StringTokenizer;
|
||||
* This handles the starting and stopping of Jetty
|
||||
* from a single static class so it can be called via clients.config.
|
||||
*
|
||||
* This makes installation of a new eepsite a turnkey operation.
|
||||
* This makes installation of a new I2P Site a turnkey operation.
|
||||
*
|
||||
* Usage: I2PControlController -d $PLUGIN [start|stop]
|
||||
*
|
||||
|
||||
@@ -37,8 +37,8 @@ import net.i2p.util.I2PSSLSocketFactory;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.PortMapper;
|
||||
|
||||
import org.json.simple.parser.JSONParser;
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.json.simple.Jsoner;
|
||||
import org.json.simple.DeserializationException;
|
||||
|
||||
import net.i2p.i2pcontrol.security.KeyStoreProvider;
|
||||
import net.i2p.i2pcontrol.security.SecurityManager;
|
||||
@@ -194,13 +194,12 @@ public class SocketController implements RouterApp {
|
||||
public void run() {
|
||||
try {
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
|
||||
final JSONParser parser = new JSONParser();
|
||||
while (true) {
|
||||
Object o = parser.parse(reader);
|
||||
Object o = Jsoner.deserialize(reader);
|
||||
// TODO
|
||||
System.out.println("i2pcontrol got: " + o);
|
||||
}
|
||||
} catch (ParseException pe) {
|
||||
} catch (DeserializationException pe) {
|
||||
_log.error("i2pcontrol handler", pe);
|
||||
return;
|
||||
} catch (IOException ioe) {
|
||||
|
||||
@@ -186,17 +186,18 @@ public class KeyStoreProvider {
|
||||
if (_keystore == null) {
|
||||
File keyStoreFile = new File(getKeyStoreLocation());
|
||||
|
||||
InputStream is = null;
|
||||
try {
|
||||
_keystore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
if (keyStoreFile.exists()) {
|
||||
InputStream is = new FileInputStream(keyStoreFile);
|
||||
is = new FileInputStream(keyStoreFile);
|
||||
_keystore.load(is, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
|
||||
return _keystore;
|
||||
}
|
||||
|
||||
initialize();
|
||||
if (keyStoreFile.exists()) {
|
||||
InputStream is = new FileInputStream(keyStoreFile);
|
||||
is = new FileInputStream(keyStoreFile);
|
||||
_keystore.load(is, DEFAULT_KEYSTORE_PASSWORD.toCharArray());
|
||||
return _keystore;
|
||||
} else {
|
||||
@@ -204,6 +205,8 @@ public class KeyStoreProvider {
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore. Not an issue. Let's just create a new keystore instead.
|
||||
} finally {
|
||||
if (is != null) try { is.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
|
||||
@@ -145,8 +145,9 @@ public class JSONRPC2Servlet extends HttpServlet {
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException {
|
||||
httpServletResponse.setContentType("text/html");
|
||||
setHeaders(httpServletResponse);
|
||||
PrintWriter out = httpServletResponse.getWriter();
|
||||
out.println("<html><head></head><body>");
|
||||
out.println("<p>I2PControl RPC Service version " + I2PControlVersion.VERSION + " : Running");
|
||||
if ("/password".equals(httpServletRequest.getServletPath())) {
|
||||
out.println("<form method=\"POST\" action=\"password\">");
|
||||
@@ -160,16 +161,19 @@ public class JSONRPC2Servlet extends HttpServlet {
|
||||
"<input name=\"save\" type=\"submit\" value=\"Change API Password\">" +
|
||||
"<p>If you forget the API password, stop i2pcontrol, delete the file <tt>" + _conf.getConfFile() +
|
||||
"</tt>, and restart i2pcontrol.");
|
||||
out.println("</form>");
|
||||
} else {
|
||||
out.println("<p><a href=\"password\">Change API Password</a>");
|
||||
}
|
||||
out.println("</body></html>");
|
||||
out.close();
|
||||
}
|
||||
|
||||
/** @since 0.12 */
|
||||
private void doPasswordChange(HttpServletRequest req, HttpServletResponse httpServletResponse) throws ServletException, IOException {
|
||||
httpServletResponse.setContentType("text/html");
|
||||
setHeaders(httpServletResponse);
|
||||
PrintWriter out = httpServletResponse.getWriter();
|
||||
out.println("<html><head></head><body>");
|
||||
String pw = req.getParameter("password");
|
||||
if (pw == null)
|
||||
pw = _secMan.DEFAULT_AUTH_PASSWORD;
|
||||
@@ -194,6 +198,21 @@ public class JSONRPC2Servlet extends HttpServlet {
|
||||
}
|
||||
}
|
||||
out.println("<p><a href=\"password\">Change API Password</a>");
|
||||
out.println("</body></html>");
|
||||
out.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.48
|
||||
*/
|
||||
private static void setHeaders(HttpServletResponse resp) {
|
||||
resp.setContentType("text/html");
|
||||
resp.setHeader("X-Frame-Options", "SAMEORIGIN");
|
||||
resp.setHeader("Content-Security-Policy", "default-src 'self'; style-src 'self'; script-src 'self'; form-action 'self'; frame-ancestors 'self'; object-src 'none'; media-src 'none'");
|
||||
resp.setHeader("X-XSS-Protection", "1; mode=block");
|
||||
resp.setHeader("X-Content-Type-Options", "nosniff");
|
||||
resp.setHeader("Pragma", "no-cache");
|
||||
resp.setHeader("Cache-Control","no-cache");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -86,7 +86,7 @@ public class AuthenticateHandler implements RequestHandler {
|
||||
|
||||
Integer apiVersion;
|
||||
try {
|
||||
apiVersion = ((Long) api).intValue();
|
||||
apiVersion = ((Number) api).intValue();
|
||||
} catch (ClassCastException e) {
|
||||
e.printStackTrace();
|
||||
return JSONRPC2ExtendedError.UNSPECIFIED_API_VERSION;
|
||||
|
||||
@@ -56,12 +56,10 @@ public class GetRateHandler implements RequestHandler {
|
||||
if (input == null) {
|
||||
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
|
||||
}
|
||||
long period;
|
||||
try {
|
||||
period = (Long) inParams.get("Period");
|
||||
} catch (NumberFormatException e) {
|
||||
Number p = (Number) inParams.get("Period");
|
||||
if (p == null)
|
||||
return new JSONRPC2Response(JSONRPC2Error.INVALID_PARAMS, req.getID());
|
||||
}
|
||||
long period = p.longValue();
|
||||
|
||||
RateStat rateStat = I2PAppContext.getGlobalContext().statManager().getRate(input);
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package net.i2p.i2pcontrol.servlets.jsonrpc2handlers;
|
||||
|
||||
import com.thetransactioncompany.jsonrpc2.JSONRPC2Error;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
/*
|
||||
* Copyright 2011 hottuna (dev@robertfoss.se)
|
||||
|
||||
@@ -32,25 +32,25 @@ import java.security.SecureRandom;
|
||||
* call the hashpw method with a random salt, like this:
|
||||
* <p>
|
||||
* <code>
|
||||
* String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt()); <br />
|
||||
* String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt());
|
||||
* </code>
|
||||
* <p>
|
||||
* To check whether a plaintext password matches one that has been
|
||||
* hashed previously, use the checkpw method:
|
||||
* <p>
|
||||
* <code>
|
||||
* if (BCrypt.checkpw(candidate_password, stored_hash))<br />
|
||||
* System.out.println("It matches");<br />
|
||||
* else<br />
|
||||
* System.out.println("It does not match");<br />
|
||||
* if (BCrypt.checkpw(candidate_password, stored_hash))
|
||||
* System.out.println("It matches");
|
||||
* else
|
||||
* System.out.println("It does not match");
|
||||
* </code>
|
||||
* <p>
|
||||
* The gensalt() method takes an optional parameter (log_rounds)
|
||||
* that determines the computational complexity of the hashing:
|
||||
* <p>
|
||||
* <code>
|
||||
* String strong_salt = BCrypt.gensalt(10)<br />
|
||||
* String stronger_salt = BCrypt.gensalt(12)<br />
|
||||
* String strong_salt = BCrypt.gensalt(10)
|
||||
* String stronger_salt = BCrypt.gensalt(12)
|
||||
* </code>
|
||||
* <p>
|
||||
* The amount of work increases exponentially (2**log_rounds), so
|
||||
|
||||
@@ -6,13 +6,14 @@ sourceSets {
|
||||
main {
|
||||
java {
|
||||
srcDir 'java/src'
|
||||
srcDir 'java/build/messages-src'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':core')
|
||||
compile project(':apps:systray')
|
||||
providedCompile project(':apps:systray')
|
||||
compile 'gnu.getopt:java-getopt:1.0.13'
|
||||
providedCompile project(':apps:ministreaming')
|
||||
providedCompile project(':apps:jetty')
|
||||
@@ -34,10 +35,26 @@ artifacts {
|
||||
archives i2psnarkJar
|
||||
}
|
||||
|
||||
war {
|
||||
into '.icons', {
|
||||
from 'icons'
|
||||
// Create the java files from the po files. The jar task will compile them.
|
||||
// This requires gettext 0.19 or higher.
|
||||
// We don't support the "slow way"
|
||||
task bundle {
|
||||
doLast {
|
||||
if (!(new File("$buildDir/classes/java/main/org/klomp/snark/web/messages_de.class")).exists())
|
||||
println "apps/i2psnark/java/bundle-messages.sh".execute().text
|
||||
}
|
||||
}
|
||||
war.dependsOn bundle
|
||||
|
||||
war {
|
||||
rootSpec.exclude('/org/klomp/snark/*.class')
|
||||
rootSpec.exclude('/org/klomp/snark/bencode/**')
|
||||
rootSpec.exclude('/org/klomp/snark/comments/**')
|
||||
rootSpec.exclude('/org/klomp/snark/dht/**')
|
||||
rootSpec.exclude('/org/klomp/snark/standalone/**')
|
||||
from ('resources', {
|
||||
into ".resources"
|
||||
})
|
||||
webInf {
|
||||
into 'classes/org/klomp/snark/web'
|
||||
from 'mime.properties'
|
||||
|
||||
@@ -1,7 +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), %APPDATA%\I2P (Windows),
|
||||
# files in ~/.i2p (Linux), %LOCALAPPDATA%\I2P (Windows),
|
||||
# or /Users/(user)/Library/Application Support/i2p (Mac), be sure to
|
||||
# edit the file in the configuration directory, NOT the install directory.
|
||||
# When running as a Linux daemon, the configuration directory is /var/lib/i2p
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
<!-- only used if not set by a higher build.xml -->
|
||||
<property name="javac.compilerargs" value="" />
|
||||
<property name="javac.version" value="1.7" />
|
||||
<property name="javac.version" value="1.8" />
|
||||
<property name="javac.release" value="8" />
|
||||
<property name="require.gettext" value="true" />
|
||||
<property name="manifest.classpath.name" value="Class-Path" />
|
||||
|
||||
@@ -41,7 +42,9 @@
|
||||
<javac
|
||||
srcdir="./src"
|
||||
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||
release="${javac.release}"
|
||||
destdir="./build/obj"
|
||||
encoding="UTF-8"
|
||||
includeAntRuntime="false" >
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
<classpath>
|
||||
@@ -163,7 +166,9 @@
|
||||
<arg value="./bundle-messages.sh" />
|
||||
</exec>
|
||||
<javac source="${javac.version}" target="${javac.version}"
|
||||
release="${javac.release}"
|
||||
includeAntRuntime="false"
|
||||
encoding="UTF-8"
|
||||
srcdir="build/messages-src" destdir="build/obj">
|
||||
<compilerarg line="${javac.compilerargs}" />
|
||||
</javac>
|
||||
@@ -245,53 +250,51 @@
|
||||
|
||||
<!-- add css, image, and js files for standalone snark to the war -->
|
||||
<target name="standalone_war" depends="war">
|
||||
<mkdir dir="build/standalone-resources/.resources/themes/snark" />
|
||||
<copy todir="build/standalone-resources/.resources/themes/snark" >
|
||||
<fileset dir="../../../installer/resources/themes/snark/" />
|
||||
<mkdir dir="build/standalone-resources/.resources/themes/" />
|
||||
<copy todir="build/standalone-resources/.resources/themes/" >
|
||||
<fileset dir="../resources/themes/" />
|
||||
</copy>
|
||||
|
||||
<replace dir="build/standalone-resources/.resources/themes/snark"
|
||||
<replace dir="build/standalone-resources/.resources/themes"
|
||||
summary="true"
|
||||
token="url(/themes/console/dark/images/"
|
||||
value="url(/i2psnark/.resources/themes/snark/dark/images/" >
|
||||
value="url(/i2psnark/.resources/themes/dark/images/" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
<replace dir="build/standalone-resources/.resources/themes/snark"
|
||||
<replace dir="build/standalone-resources/.resources/themes"
|
||||
summary="true"
|
||||
token="url(../../console/light/images/"
|
||||
value="url(/i2psnark/.resources/themes/snark/light/images/" >
|
||||
value="url(/i2psnark/.resources/themes/light/images/" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
<replace dir="build/standalone-resources/.resources/themes/snark"
|
||||
<replace dir="build/standalone-resources/.resources/themes"
|
||||
summary="true"
|
||||
token="url(/themes/console/light/images/"
|
||||
value="url(/i2psnark/.resources/themes/snark/light/images/" >
|
||||
value="url(/i2psnark/.resources/themes/light/images/" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
<replace dir="build/standalone-resources/.resources/themes/snark"
|
||||
<replace dir="build/standalone-resources/.resources/themes"
|
||||
summary="true"
|
||||
token="url(/themes/console/images/transparent.gif"
|
||||
value="url(/i2psnark/.resources/themes/snark/ubergine/images/transparent.gif" >
|
||||
value="url(/i2psnark/.resources/themes/ubergine/images/transparent.gif" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
<replace dir="build/standalone-resources/.resources/themes/snark"
|
||||
<replace dir="build/standalone-resources/.resources/themes"
|
||||
summary="true"
|
||||
token="url(/themes/console/images/info/"
|
||||
value="url(/i2psnark/.resources/themes/snark/ubergine/images/" >
|
||||
value="url(/i2psnark/.resources/themes/ubergine/images/" >
|
||||
<include name="**/*.css" />
|
||||
</replace>
|
||||
|
||||
<!-- Rather than pulling in all the console theme images, let's just specify the ones we need -->
|
||||
<copy file="../../../installer/resources/themes/console/images/transparent.gif"
|
||||
todir="build/standalone-resources/.resources/themes/snark/ubergine/images" />
|
||||
<copy file="../../../installer/resources/themes/console/dark/images/header.png"
|
||||
todir="build/standalone-resources/.resources/themes/snark/dark/images" />
|
||||
<copy file="../../../installer/resources/themes/console/light/images/header.png"
|
||||
todir="build/standalone-resources/.resources/themes/snark/light/images" />
|
||||
<copy file="../../../installer/resources/themes/console/dark/images/camotile2.png"
|
||||
todir="build/standalone-resources/.resources/themes/snark/dark/images" />
|
||||
<copy file="../../../installer/resources/themes/console/images/info/errortriangle.png"
|
||||
todir="build/standalone-resources/.resources/themes/snark/ubergine/images" />
|
||||
<copy file="../../routerconsole/jsp/themes/console/images/transparent.gif"
|
||||
todir="build/standalone-resources/.resources/themes/ubergine/images" />
|
||||
<copy file="../../routerconsole/jsp/themes/console/dark/images/header.png"
|
||||
todir="build/standalone-resources/.resources/themes/dark/images" />
|
||||
<copy file="../../routerconsole/jsp/themes/console/light/images/header.png"
|
||||
todir="build/standalone-resources/.resources/themes/light/images" />
|
||||
<copy file="../../routerconsole/jsp/themes/console/images/info/errortriangle.png"
|
||||
todir="build/standalone-resources/.resources/themes/ubergine/images" />
|
||||
|
||||
<mkdir dir="build/standalone-resources/.resources/js" />
|
||||
<copy file="../../routerconsole/jsp/js/ajax.js" todir="build/standalone-resources/.resources/js" />
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#
|
||||
# zzz - public domain
|
||||
#
|
||||
cd `dirname $0`
|
||||
CLASS=org.klomp.snark.web.messages
|
||||
TMPFILE=build/javafiles.txt
|
||||
export TZ=UTC
|
||||
@@ -96,12 +97,12 @@ do
|
||||
# only generate for non-source language
|
||||
echo "Generating ${CLASS}_$LG ResourceBundle..."
|
||||
|
||||
msgfmt -V | grep -q '0\.19'
|
||||
msgfmt -V | grep -q -E ' 0\.((19)|[2-9])'
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
# slow way
|
||||
# convert to class files in build/obj
|
||||
msgfmt --java --statistics -r $CLASS -l $LG -d build/obj $i
|
||||
msgfmt --java2 --statistics -r $CLASS -l $LG -d build/obj $i
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "ERROR - msgfmt failed on ${i}, not updating translations"
|
||||
@@ -119,7 +120,7 @@ do
|
||||
TDY=$TD2/org/klomp/snark/web
|
||||
rm -rf $TD
|
||||
mkdir -p $TD $TDY
|
||||
msgfmt --java --statistics --source -r $CLASS -l $LG -d $TD $i
|
||||
msgfmt --java2 --statistics --source -r $CLASS -l $LG -d $TD $i
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
echo "ERROR - msgfmt failed on ${i}, not updating translations"
|
||||
|
||||
@@ -78,4 +78,9 @@ public interface CompleteListener {
|
||||
* @since 0.9.31
|
||||
*/
|
||||
public void locked_saveComments(Snark snark, CommentSet comments);
|
||||
|
||||
/**
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public boolean shouldAutoStart();
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@ interface CoordinatorListener
|
||||
public boolean overUploadLimit(int uploaders);
|
||||
|
||||
/**
|
||||
* Are we currently over the upstream bandwidth limit?
|
||||
* Is i2psnark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit();
|
||||
|
||||
/**
|
||||
* Is the total (in Bps) over the upstream bandwidth limit?
|
||||
* Is a particular peer who has this recent download rate (in Bps) over our upstream bandwidth limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total);
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ abstract class ExtensionHandler {
|
||||
handshake.put("m", m);
|
||||
handshake.put("p", Integer.valueOf(TrackerClient.PORT));
|
||||
handshake.put("v", "I2PSnark");
|
||||
handshake.put("reqq", Integer.valueOf(5));
|
||||
handshake.put("reqq", Integer.valueOf(PeerState.MAX_PIPELINE));
|
||||
// BEP 21
|
||||
if (uploadOnly)
|
||||
handshake.put("upload_only", Integer.valueOf(1));
|
||||
|
||||
@@ -5,8 +5,10 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
@@ -57,7 +59,6 @@ public class I2PSnarkUtil {
|
||||
private int _i2cpPort;
|
||||
private final Map<String, String> _opts;
|
||||
private volatile I2PSocketManager _manager;
|
||||
private boolean _configured;
|
||||
private volatile boolean _connecting;
|
||||
private final Set<Hash> _banlist;
|
||||
private int _maxUploaders;
|
||||
@@ -84,6 +85,10 @@ public class I2PSnarkUtil {
|
||||
public static final String PROP_MAX_BW = "i2cp.outboundBytesPerSecond";
|
||||
public static final boolean DEFAULT_USE_DHT = true;
|
||||
public static final String EEPGET_USER_AGENT = "I2PSnark";
|
||||
private static final List<String> HIDDEN_I2CP_OPTS = Arrays.asList(new String[] {
|
||||
PROP_MAX_BW, "inbound.length", "outbound.length", "inbound.quantity", "outbound.quantity"
|
||||
});
|
||||
|
||||
|
||||
public I2PSnarkUtil(I2PAppContext ctx) {
|
||||
this(ctx, "i2psnark");
|
||||
@@ -142,25 +147,34 @@ public class I2PSnarkUtil {
|
||||
/** @since 0.9.1 */
|
||||
public I2PAppContext getContext() { return _context; }
|
||||
|
||||
public boolean configured() { return _configured; }
|
||||
|
||||
/**
|
||||
* @param i2cpHost may be null for no change
|
||||
* @param i2cpPort may be 0 for no change
|
||||
* @param opts may be null for no change
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public void setI2CPConfig(String i2cpHost, int i2cpPort, Map opts) {
|
||||
if (i2cpHost != null)
|
||||
_i2cpHost = i2cpHost;
|
||||
if (i2cpPort > 0)
|
||||
_i2cpPort = i2cpPort;
|
||||
// can't remove any options this way...
|
||||
if (opts != null)
|
||||
_opts.putAll(opts);
|
||||
if (opts != null) {
|
||||
synchronized(_opts) {
|
||||
// removed options...
|
||||
for (Iterator<String> iter = _opts.keySet().iterator(); iter.hasNext(); ) {
|
||||
String k = iter.next();
|
||||
if (!HIDDEN_I2CP_OPTS.contains(k) && !opts.containsKey(k))
|
||||
iter.remove();
|
||||
}
|
||||
_opts.putAll(opts);
|
||||
}
|
||||
}
|
||||
// this updates the session options and tells the router
|
||||
setMaxUpBW(_maxUpBW);
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public void setMaxUploaders(int limit) {
|
||||
_maxUploaders = limit;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,13 +183,16 @@ public class I2PSnarkUtil {
|
||||
*/
|
||||
public void setMaxUpBW(int limit) {
|
||||
_maxUpBW = limit;
|
||||
_opts.put(PROP_MAX_BW, Integer.toString(limit * (1024 * 6 / 5))); // add a little for overhead
|
||||
_configured = true;
|
||||
synchronized(_opts) {
|
||||
_opts.put(PROP_MAX_BW, Integer.toString(limit * (1024 * 6 / 5))); // add a little for overhead
|
||||
}
|
||||
if (_manager != null) {
|
||||
I2PSession sess = _manager.getSession();
|
||||
if (sess != null) {
|
||||
Properties newProps = new Properties();
|
||||
newProps.putAll(_opts);
|
||||
synchronized(_opts) {
|
||||
newProps.putAll(_opts);
|
||||
}
|
||||
sess.updateOptions(newProps);
|
||||
}
|
||||
}
|
||||
@@ -183,17 +200,24 @@ public class I2PSnarkUtil {
|
||||
|
||||
public void setMaxConnections(int limit) {
|
||||
_maxConnections = limit;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public void setStartupDelay(int minutes) {
|
||||
_startupDelay = minutes;
|
||||
_configured = true;
|
||||
}
|
||||
|
||||
public String getI2CPHost() { return _i2cpHost; }
|
||||
public int getI2CPPort() { return _i2cpPort; }
|
||||
public Map<String, String> getI2CPOptions() { return _opts; }
|
||||
|
||||
/**
|
||||
* @return a copy
|
||||
*/
|
||||
public Map<String, String> getI2CPOptions() {
|
||||
synchronized(_opts) {
|
||||
return new HashMap<String, String>(_opts);
|
||||
}
|
||||
}
|
||||
|
||||
public String getEepProxyHost() { return _proxyHost; }
|
||||
public int getEepProxyPort() { return _proxyPort; }
|
||||
public boolean getEepProxySet() { return _shouldProxy; }
|
||||
@@ -225,10 +249,37 @@ public class I2PSnarkUtil {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Connecting to I2P", new Exception("I did it"));
|
||||
Properties opts = _context.getProperties();
|
||||
if (_opts != null) {
|
||||
for (Map.Entry<String, String> entry : _opts.entrySet() )
|
||||
opts.setProperty(entry.getKey(), entry.getValue());
|
||||
synchronized(_opts) {
|
||||
opts.putAll(_opts);
|
||||
}
|
||||
// override preference and start with two tunnels. IdleChecker will ramp up/down as necessary
|
||||
String sin = opts.getProperty("inbound.quantity");
|
||||
if (sin != null) {
|
||||
int in;
|
||||
try {
|
||||
in = Integer.parseInt(sin);
|
||||
} catch (NumberFormatException nfe) {
|
||||
in = 3;
|
||||
}
|
||||
if (in > 2)
|
||||
opts.setProperty("inbound.quantity", "2");
|
||||
}
|
||||
String sout = opts.getProperty("outbound.quantity");
|
||||
if (sout != null) {
|
||||
int out;
|
||||
try {
|
||||
out = Integer.parseInt(sout);
|
||||
} catch (NumberFormatException nfe) {
|
||||
out = 3;
|
||||
}
|
||||
if (out > 2)
|
||||
opts.setProperty("outbound.quantity", "2");
|
||||
}
|
||||
if (opts.containsKey("inbound.backupQuantity"))
|
||||
opts.setProperty("inbound.backupQuantity", "0");
|
||||
if (opts.containsKey("outbound.backupQuantity"))
|
||||
opts.setProperty("outbound.backupQuantity", "0");
|
||||
|
||||
if (opts.getProperty("inbound.nickname") == null)
|
||||
opts.setProperty("inbound.nickname", _baseName.replace("i2psnark", "I2PSnark"));
|
||||
if (opts.getProperty("outbound.nickname") == null)
|
||||
@@ -267,6 +318,11 @@ public class I2PSnarkUtil {
|
||||
opts.setProperty("i2p.streaming.answerPings", "false");
|
||||
if (opts.getProperty(I2PClient.PROP_SIGTYPE) == null)
|
||||
opts.setProperty(I2PClient.PROP_SIGTYPE, "EdDSA_SHA512_Ed25519");
|
||||
if (opts.getProperty("i2cp.leaseSetEncType") == null)
|
||||
opts.setProperty("i2cp.leaseSetEncType", "4,0");
|
||||
// assume compressed content
|
||||
if (opts.getProperty(I2PClient.PROP_GZIP) == null)
|
||||
opts.setProperty(I2PClient.PROP_GZIP, "false");
|
||||
_manager = I2PSocketManagerFactory.createManager(_i2cpHost, _i2cpPort, opts);
|
||||
if (_manager != null)
|
||||
_startedTime = _context.clock().now();
|
||||
|
||||
@@ -29,13 +29,14 @@ class IdleChecker extends SimpleTimer2.TimedEvent {
|
||||
private int _consec;
|
||||
private int _consecNotRunning;
|
||||
private boolean _isIdle;
|
||||
private String _lastIn = "3";
|
||||
private String _lastOut = "3";
|
||||
private String _lastIn = DEFAULT_QTY;
|
||||
private String _lastOut = DEFAULT_QTY;
|
||||
private final Object _lock = new Object();
|
||||
|
||||
private static final long CHECK_TIME = 63*1000;
|
||||
private static final int MAX_CONSEC_IDLE = 4;
|
||||
private static final int MAX_CONSEC_NOT_RUNNING = 20;
|
||||
private static final String DEFAULT_QTY = "2";
|
||||
|
||||
/**
|
||||
* Caller must schedule
|
||||
@@ -93,8 +94,8 @@ class IdleChecker extends SimpleTimer2.TimedEvent {
|
||||
_isIdle = false;
|
||||
_consec = 0;
|
||||
_consecNotRunning = 0;
|
||||
_lastIn = "3";
|
||||
_lastOut = "3";
|
||||
_lastIn = DEFAULT_QTY;
|
||||
_lastOut = DEFAULT_QTY;
|
||||
}
|
||||
schedule(CHECK_TIME);
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ class MagnetState {
|
||||
infohash = iHash;
|
||||
if (meta != null) {
|
||||
metainfo = meta;
|
||||
initialize(meta.getInfoBytes().length);
|
||||
initialize(meta.getInfoBytesLength());
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,13 @@ public class MagnetURI {
|
||||
public static final String MAGNET_FULL = MAGNET + "?xt=urn:btih:";
|
||||
/** http://sponge.i2p/files/maggotspec.txt */
|
||||
public static final String MAGGOT = "maggot://";
|
||||
/**
|
||||
* https://blog.libtorrent.org/2020/09/bittorrent-v2/
|
||||
* TODO, dup param parsing, as a dual v1/v2 link
|
||||
* will contain two xt params
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public static final String MAGNET_FULL_V2 = MAGNET + "?xt=urn:btmh:";
|
||||
|
||||
/**
|
||||
* @param url non-null
|
||||
@@ -35,6 +42,7 @@ public class MagnetURI {
|
||||
if (url.startsWith(MAGNET)) {
|
||||
// magnet:?xt=urn:btih:0691e40aae02e552cfcb57af1dca56214680c0c5&tr=http://tracker2.postman.i2p/announce.php
|
||||
String xt = getParam("xt", url);
|
||||
// TODO btmh
|
||||
if (xt == null || !xt.startsWith("urn:btih:"))
|
||||
throw new IllegalArgumentException();
|
||||
ihash = xt.substring("urn:btih:".length());
|
||||
|
||||
@@ -49,6 +49,9 @@ class Message
|
||||
final static byte REJECT = 16; // Fast (BEP 6)
|
||||
final static byte ALLOWED_FAST = 17; // Fast (BEP 6)
|
||||
final static byte EXTENSION = 20; // BEP 10
|
||||
final static byte HASH_REQUEST = 21; // BEP 52
|
||||
final static byte HASHES = 22; // BEP 52
|
||||
final static byte HASH_REJECT = 23; // BEP 52
|
||||
|
||||
// Not all fields are used for every message.
|
||||
// KEEP_ALIVE doesn't have a real wire representation
|
||||
@@ -278,6 +281,13 @@ class Message
|
||||
return "REJECT(" + piece + ',' + begin + ',' + length + ')';
|
||||
case ALLOWED_FAST:
|
||||
return "ALLOWED_FAST(" + piece + ')';
|
||||
// BEP 52 below here
|
||||
case HASH_REQUEST:
|
||||
return "HASH_REQUEST";
|
||||
case HASHES:
|
||||
return "HASHES";
|
||||
case HASH_REJECT:
|
||||
return "HASH_REJECT";
|
||||
default:
|
||||
return "UNKNOWN (" + type + ')';
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import gnu.getopt.Getopt;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.SHA1;
|
||||
import net.i2p.data.DataHelper;
|
||||
@@ -56,6 +58,7 @@ public class MetaInfo
|
||||
private final String name_utf8;
|
||||
private final List<List<String>> files;
|
||||
private final List<List<String>> files_utf8;
|
||||
private final List<String> attributes;
|
||||
private final List<Long> lengths;
|
||||
private final int piece_length;
|
||||
private final byte[] piece_hashes;
|
||||
@@ -65,7 +68,9 @@ public class MetaInfo
|
||||
private final String comment;
|
||||
private final String created_by;
|
||||
private final long creation_date;
|
||||
private final List<String> url_list;
|
||||
private Map<String, BEValue> infoMap;
|
||||
private int infoBytesLength;
|
||||
|
||||
/**
|
||||
* Called by Storage when creating a new torrent from local data
|
||||
@@ -75,10 +80,12 @@ public class MetaInfo
|
||||
* @param lengths null for single-file torrent
|
||||
* @param announce_list may be null
|
||||
* @param created_by may be null
|
||||
* @param url_list may be null
|
||||
* @param comment may be null
|
||||
*/
|
||||
MetaInfo(String announce, String name, String name_utf8, List<List<String>> files, List<Long> lengths,
|
||||
int piece_length, byte[] piece_hashes, long length, boolean privateTorrent,
|
||||
List<List<String>> announce_list, String created_by)
|
||||
List<List<String>> announce_list, String created_by, List<String> url_list, String comment)
|
||||
{
|
||||
this.announce = announce;
|
||||
this.name = name;
|
||||
@@ -91,9 +98,13 @@ public class MetaInfo
|
||||
this.length = length;
|
||||
this.privateTorrent = privateTorrent;
|
||||
this.announce_list = announce_list;
|
||||
this.comment = null;
|
||||
this.comment = comment;
|
||||
this.created_by = created_by;
|
||||
this.creation_date = I2PAppContext.getGlobalContext().clock().now();
|
||||
this.url_list = url_list;
|
||||
|
||||
// TODO BEP 52 hybrid torrent with piece layers, meta version and file tree
|
||||
this.attributes = null;
|
||||
|
||||
// TODO if we add a parameter for other keys
|
||||
//if (other != null) {
|
||||
@@ -169,6 +180,18 @@ public class MetaInfo
|
||||
}
|
||||
}
|
||||
|
||||
// BEP 19
|
||||
val = m.get("url-list");
|
||||
if (val == null) {
|
||||
this.url_list = null;
|
||||
} else {
|
||||
List<BEValue> bl1 = val.getList();
|
||||
this.url_list = new ArrayList<String>(bl1.size());
|
||||
for (BEValue bev : bl1) {
|
||||
this.url_list.add(bev.getString());
|
||||
}
|
||||
}
|
||||
|
||||
// misc. optional top-level stuff
|
||||
val = m.get("comment");
|
||||
String st = null;
|
||||
@@ -236,8 +259,18 @@ public class MetaInfo
|
||||
piece_length = val.getInt();
|
||||
|
||||
val = info.get("pieces");
|
||||
if (val == null)
|
||||
if (val == null) {
|
||||
// BEP 52
|
||||
// We do the check here because a torrent file could be combined v1/v2,
|
||||
// so a version 2 value isn't by itself fatal
|
||||
val = info.get("meta version");
|
||||
if (val != null) {
|
||||
int version = val.getInt();
|
||||
if (version != 1)
|
||||
throw new InvalidBEncodingException("Version " + version + " torrent file not supported");
|
||||
}
|
||||
throw new InvalidBEncodingException("Missing piece bytes");
|
||||
}
|
||||
piece_hashes = val.getBytes();
|
||||
|
||||
val = info.get("length");
|
||||
@@ -248,6 +281,7 @@ public class MetaInfo
|
||||
files = null;
|
||||
files_utf8 = null;
|
||||
lengths = null;
|
||||
attributes = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,8 +297,9 @@ public class MetaInfo
|
||||
throw new InvalidBEncodingException("zero size files list");
|
||||
|
||||
List<List<String>> m_files = new ArrayList<List<String>>(size);
|
||||
List<List<String>> m_files_utf8 = new ArrayList<List<String>>(size);
|
||||
List<List<String>> m_files_utf8 = null;
|
||||
List<Long> m_lengths = new ArrayList<Long>(size);
|
||||
List<String> m_attributes = null;
|
||||
long l = 0;
|
||||
for (int i = 0; i < list.size(); i++)
|
||||
{
|
||||
@@ -310,6 +345,7 @@ public class MetaInfo
|
||||
|
||||
val = desc.get("path.utf-8");
|
||||
if (val != null) {
|
||||
m_files_utf8 = new ArrayList<List<String>>(size);
|
||||
path_list = val.getList();
|
||||
path_length = path_list.size();
|
||||
if (path_length > 0) {
|
||||
@@ -320,11 +356,28 @@ public class MetaInfo
|
||||
m_files_utf8.add(Collections.unmodifiableList(file));
|
||||
}
|
||||
}
|
||||
|
||||
// BEP 47
|
||||
val = desc.get("attr");
|
||||
if (val != null) {
|
||||
String s = val.getString();
|
||||
if (m_attributes == null) {
|
||||
m_attributes = new ArrayList<String>(size);
|
||||
for (int j = 0; j < i; j++) {
|
||||
m_attributes.add("");
|
||||
}
|
||||
m_attributes.add(s);
|
||||
}
|
||||
} else {
|
||||
if (m_attributes != null)
|
||||
m_attributes.add("");
|
||||
}
|
||||
}
|
||||
files = Collections.unmodifiableList(m_files);
|
||||
files_utf8 = Collections.unmodifiableList(m_files_utf8);
|
||||
files_utf8 = m_files_utf8 != null ? Collections.unmodifiableList(m_files_utf8) : null;
|
||||
lengths = Collections.unmodifiableList(m_lengths);
|
||||
length = l;
|
||||
attributes = m_attributes;
|
||||
}
|
||||
|
||||
info_hash = calculateInfoHash();
|
||||
@@ -370,6 +423,15 @@ public class MetaInfo
|
||||
return announce_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of urls or null.
|
||||
*
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public List<String> getWebSeedURLs() {
|
||||
return url_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original 20 byte SHA1 hash over the bencoded info map.
|
||||
*/
|
||||
@@ -415,6 +477,16 @@ public class MetaInfo
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this file a padding file?
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public boolean isPaddingFile(int filenum) {
|
||||
if (attributes == null)
|
||||
return false;
|
||||
return attributes.get(filenum).indexOf('p') >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of Longs indication the size of the individual
|
||||
* files, or null if it is a single file. It has the same size as
|
||||
@@ -550,6 +622,7 @@ public class MetaInfo
|
||||
|
||||
/**
|
||||
* Returns the total length of the torrent in bytes.
|
||||
* This includes any padding files.
|
||||
*/
|
||||
public long getTotalLength()
|
||||
{
|
||||
@@ -597,6 +670,8 @@ public class MetaInfo
|
||||
if (announce_list != null)
|
||||
m.put("announce-list", announce_list);
|
||||
// misc. optional top-level stuff
|
||||
if (url_list != null)
|
||||
m.put("url-list", url_list);
|
||||
if (comment != null)
|
||||
m.put("comment", comment);
|
||||
if (created_by != null)
|
||||
@@ -610,11 +685,27 @@ public class MetaInfo
|
||||
return BEncoder.bencode(m);
|
||||
}
|
||||
|
||||
/** @since 0.8.4 */
|
||||
/**
|
||||
* Side effect: Caches infoBytesLength.
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public synchronized byte[] getInfoBytes() {
|
||||
if (infoMap == null)
|
||||
createInfoMap();
|
||||
return BEncoder.bencode(infoMap);
|
||||
byte[] rv = BEncoder.bencode(infoMap);
|
||||
infoBytesLength = rv.length;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* The size of getInfoBytes().
|
||||
* Cached.
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public synchronized int getInfoBytesLength() {
|
||||
if (infoBytesLength > 0)
|
||||
return infoBytesLength;
|
||||
return getInfoBytes().length;
|
||||
}
|
||||
|
||||
/** @return an unmodifiable view of the Map */
|
||||
@@ -663,11 +754,19 @@ public class MetaInfo
|
||||
file.put("path.utf-8", new BEValue(beufiles));
|
||||
}
|
||||
file.put("length", new BEValue(lengths.get(i)));
|
||||
String attr = null;
|
||||
if (attributes != null) {
|
||||
attr = attributes.get(i);
|
||||
if (attr.length() > 0)
|
||||
file.put("attr", new BEValue(DataHelper.getASCII(attr)));
|
||||
}
|
||||
l.add(new BEValue(file));
|
||||
}
|
||||
info.put("files", new BEValue(l));
|
||||
}
|
||||
|
||||
// TODO BEP 52 meta version and file tree
|
||||
|
||||
// TODO if we add the ability for other keys in the first constructor
|
||||
//if (otherInfo != null)
|
||||
// info.putAll(otherInfo);
|
||||
@@ -701,20 +800,92 @@ public class MetaInfo
|
||||
|
||||
/** @since 0.8.5 */
|
||||
public static void main(String[] args) {
|
||||
if (args.length <= 0) {
|
||||
System.err.println("Usage: MetaInfo files...");
|
||||
return;
|
||||
boolean error = false;
|
||||
String created_by = null;
|
||||
String announce = null;
|
||||
List<String> url_list = null;
|
||||
String comment = null;
|
||||
Getopt g = new Getopt("Storage", args, "a:c:m:w:");
|
||||
try {
|
||||
int c;
|
||||
while ((c = g.getopt()) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
announce = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
created_by = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
comment = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (url_list == null)
|
||||
url_list = new ArrayList<String>();
|
||||
url_list.add(g.getOptarg());
|
||||
break;
|
||||
|
||||
case '?':
|
||||
case ':':
|
||||
default:
|
||||
error = true;
|
||||
break;
|
||||
} // switch
|
||||
} // while
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
error = true;
|
||||
}
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (error || args.length - g.getOptind() <= 0) {
|
||||
System.err.println("Usage: MetaInfo [-a announceURL] [-c created-by] [-m comment] [-w webseed-url]* file.torrent [file2.torrent...]");
|
||||
System.exit(1);
|
||||
}
|
||||
for (int i = g.getOptind(); i < args.length; i++) {
|
||||
InputStream in = null;
|
||||
java.io.OutputStream out = null;
|
||||
try {
|
||||
in = new FileInputStream(args[i]);
|
||||
MetaInfo meta = new MetaInfo(in);
|
||||
System.out.println(args[i] + " InfoHash: " + I2PSnarkUtil.toHex(meta.getInfoHash()));
|
||||
System.out.println(args[i] +
|
||||
"\nInfoHash: " + I2PSnarkUtil.toHex(meta.getInfoHash()) +
|
||||
"\nAnnounce: " + meta.getAnnounce() +
|
||||
"\nWebSeed URLs: " + meta.getWebSeedURLs() +
|
||||
"\nCreated By: " + meta.getCreatedBy() +
|
||||
"\nComment: " + meta.getComment());
|
||||
if (created_by != null || announce != null || url_list != null || comment != null) {
|
||||
String cb = created_by != null ? created_by : meta.getCreatedBy();
|
||||
String an = announce != null ? announce : meta.getAnnounce();
|
||||
String cm = comment != null ? comment : meta.getComment();
|
||||
List<String> urls = url_list != null ? url_list : meta.getWebSeedURLs();
|
||||
// changes/adds creation date
|
||||
MetaInfo meta2 = new MetaInfo(an, meta.getName(), null, meta.getFiles(), meta.getLengths(),
|
||||
meta.getPieceLength(0), meta.getPieceHashes(), meta.getTotalLength(), meta.isPrivate(),
|
||||
meta.getAnnounceList(), cb, urls, cm);
|
||||
java.io.File from = new java.io.File(args[i]);
|
||||
java.io.File to = new java.io.File(args[i] + ".bak");
|
||||
if (net.i2p.util.FileUtil.copy(from, to, true, false)) {
|
||||
out = new java.io.FileOutputStream(from);
|
||||
out.write(meta2.getTorrentData());
|
||||
out.close();
|
||||
System.out.println("Modified " + from + " and backed up old file to " + to);
|
||||
System.out.println(args[i] +
|
||||
"\nInfoHash: " + I2PSnarkUtil.toHex(meta2.getInfoHash()) +
|
||||
"\nAnnounce: " + meta2.getAnnounce() +
|
||||
"\nWebSeed URLs: " + meta2.getWebSeedURLs() +
|
||||
"\nCreated By: " + meta2.getCreatedBy() +
|
||||
"\nComment: " + meta2.getComment());
|
||||
} else {
|
||||
System.out.println("Failed backup of " + from + " to " + to);
|
||||
}
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
System.err.println("Error in file " + args[i] + ": " + ioe);
|
||||
} finally {
|
||||
try { if (in != null) in.close(); } catch (IOException ioe) {}
|
||||
try { if (out != null) out.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,17 +38,18 @@ import net.i2p.data.Destination;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
import org.klomp.snark.bencode.InvalidBEncodingException;
|
||||
|
||||
public class Peer implements Comparable<Peer>
|
||||
{
|
||||
private final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(Peer.class);
|
||||
protected final Log _log = I2PAppContext.getGlobalContext().logManager().getLog(getClass());
|
||||
// Identifying property, the peer id of the other side.
|
||||
private final PeerID peerID;
|
||||
|
||||
private final byte[] my_id;
|
||||
private final byte[] infohash;
|
||||
/** will start out null in magnet mode */
|
||||
private MetaInfo metainfo;
|
||||
protected MetaInfo metainfo;
|
||||
private Map<String, BEValue> handshakeMap;
|
||||
|
||||
// The data in/output streams set during the handshake and used by
|
||||
@@ -60,8 +61,11 @@ public class Peer implements Comparable<Peer>
|
||||
private final AtomicLong downloaded = new AtomicLong();
|
||||
private final AtomicLong uploaded = new AtomicLong();
|
||||
|
||||
// Keeps state for in/out connections. Non-null when the handshake
|
||||
// was successful, the connection setup and runs
|
||||
/** `
|
||||
* Keeps state for in/out connections. Non-null when the handshake
|
||||
* was successful, the connection setup and runs.
|
||||
* Do not access directly. All actions should be through Peer methods.
|
||||
*/
|
||||
volatile PeerState state;
|
||||
|
||||
/** shared across all peers on this torrent */
|
||||
@@ -76,22 +80,22 @@ public class Peer implements Comparable<Peer>
|
||||
|
||||
final static long CHECK_PERIOD = PeerCoordinator.CHECK_PERIOD; // 40 seconds
|
||||
final static int RATE_DEPTH = PeerCoordinator.RATE_DEPTH; // make following arrays RATE_DEPTH long
|
||||
private long uploaded_old[] = {-1,-1,-1};
|
||||
private long downloaded_old[] = {-1,-1,-1};
|
||||
private final long uploaded_old[] = {-1,-1,-1};
|
||||
private final long downloaded_old[] = {-1,-1,-1};
|
||||
|
||||
private static final byte[] HANDSHAKE = DataHelper.getASCII("BitTorrent protocol");
|
||||
// See BEP 4 for definitions
|
||||
// bytes per bt spec: 0011223344556677
|
||||
private static final long OPTION_EXTENSION = 0x0000000000100000l;
|
||||
private static final long OPTION_FAST = 0x0000000000000004l;
|
||||
//private static final long OPTION_DHT = 0x0000000000000001l;
|
||||
/** we use a different bit since the compact format is different */
|
||||
/* no, let's use an extension message
|
||||
static final long OPTION_I2P_DHT = 0x0000000040000000l;
|
||||
*/
|
||||
//private static final long OPTION_AZMP = 0x1000000000000000l;
|
||||
// hybrid support TODO
|
||||
private static final long OPTION_V2 = 0x0000000000000010L;
|
||||
private long options;
|
||||
private final boolean _isIncoming;
|
||||
private int _totalCommentsSent;
|
||||
private int _maxPipeline = PeerState.MIN_PIPELINE;
|
||||
|
||||
/**
|
||||
* Outgoing connection.
|
||||
@@ -289,7 +293,7 @@ public class Peer implements Comparable<Peer>
|
||||
if ((options & OPTION_EXTENSION) != 0) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Peer supports extensions, sending reply message");
|
||||
int metasize = metainfo != null ? metainfo.getInfoBytes().length : -1;
|
||||
int metasize = metainfo != null ? metainfo.getInfoBytesLength() : -1;
|
||||
boolean pexAndMetadata = metainfo == null || !metainfo.isPrivate();
|
||||
boolean dht = util.getDHT() != null;
|
||||
boolean comment = util.utCommentsEnabled();
|
||||
@@ -340,7 +344,6 @@ public class Peer implements Comparable<Peer>
|
||||
private byte[] handshake(InputStream in, OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
din = new DataInputStream(in);
|
||||
dout = new DataOutputStream(out);
|
||||
|
||||
// Handshake write - header
|
||||
@@ -365,6 +368,7 @@ public class Peer implements Comparable<Peer>
|
||||
_log.debug("Wrote my shared hash and ID to " + toString());
|
||||
|
||||
// Handshake read - header
|
||||
din = new DataInputStream(in);
|
||||
byte b = din.readByte();
|
||||
if (b != HANDSHAKE.length)
|
||||
throw new IOException("Handshake failure, expected 19, got "
|
||||
@@ -428,9 +432,30 @@ public class Peer implements Comparable<Peer>
|
||||
return handshakeMap;
|
||||
}
|
||||
|
||||
/** @since 0.8.4 */
|
||||
/**
|
||||
* @param map non-null
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void setHandshakeMap(Map<String, BEValue> map) {
|
||||
handshakeMap = map;
|
||||
BEValue bev = map.get("reqq");
|
||||
if (bev != null) {
|
||||
try {
|
||||
int reqq = bev.getInt();
|
||||
_maxPipeline = Math.min(PeerState.MAX_PIPELINE, Math.max(PeerState.MIN_PIPELINE, reqq));
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
} else {
|
||||
// BEP 10 "The default in libtorrent is 250"
|
||||
_maxPipeline = PeerState.MAX_PIPELINE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return min of PeerState.MIN_PIPELINE, max of PeerState.MAX_PIPELINE
|
||||
* @since 0.9.47
|
||||
*/
|
||||
public int getMaxPipeline() {
|
||||
return _maxPipeline;
|
||||
}
|
||||
|
||||
/** @since 0.8.4 */
|
||||
@@ -644,7 +669,8 @@ public class Peer implements Comparable<Peer>
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that have been downloaded.
|
||||
* Can be reset to zero with <code>resetCounters()</code>/
|
||||
* Can be reset to zero with <code>resetCounters()</code>
|
||||
* which is called every CHECK_PERIOD by PeerCheckerTask.
|
||||
*/
|
||||
public long getDownloaded()
|
||||
{
|
||||
@@ -653,7 +679,8 @@ public class Peer implements Comparable<Peer>
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that have been uploaded.
|
||||
* Can be reset to zero with <code>resetCounters()</code>/
|
||||
* Can be reset to zero with <code>resetCounters()</code>
|
||||
* which is called every CHECK_PERIOD by PeerCheckerTask.
|
||||
*/
|
||||
public long getUploaded()
|
||||
{
|
||||
@@ -713,6 +740,7 @@ public class Peer implements Comparable<Peer>
|
||||
|
||||
/**
|
||||
* Return how much the peer has
|
||||
* @return number of completed pieces (not bytes)
|
||||
*/
|
||||
public int completed()
|
||||
{
|
||||
@@ -764,4 +792,12 @@ public class Peer implements Comparable<Peer>
|
||||
void setTotalCommentsSent(int count) {
|
||||
_totalCommentsSent = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public boolean isWebPeer() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,9 @@ class PeerCheckerTask implements Runnable
|
||||
// Put it at the back of the list
|
||||
removed.add(peer);
|
||||
}
|
||||
else if (!peer.isInteresting() && !coordinator.completed())
|
||||
else if (!peer.isInteresting() && !coordinator.completed() &&
|
||||
// give new peers a better chance to get their first two pieces
|
||||
(peer.completed() >= 2 || random.nextInt(4) == 0))
|
||||
{
|
||||
// If they aren't interesting make someone else a downloader
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -221,7 +223,9 @@ class PeerCheckerTask implements Runnable
|
||||
worstdownload = download;
|
||||
worstDownloader = peer;
|
||||
}
|
||||
else if (upload < worstdownload && coordinator.completed())
|
||||
else if (upload < worstdownload && coordinator.completed() &&
|
||||
// give new peers a better chance to get their first four pieces
|
||||
(peer.completed() >= 4 || random.nextInt(8) == 0))
|
||||
{
|
||||
// Make sure upload is good if we are seeding
|
||||
worstdownload = upload;
|
||||
|
||||
@@ -26,11 +26,11 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
@@ -43,6 +43,7 @@ import net.i2p.data.Destination;
|
||||
import net.i2p.util.ConcurrentHashSet;
|
||||
import net.i2p.util.I2PAppThread;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.RandomSource;
|
||||
import net.i2p.util.SimpleTimer2;
|
||||
|
||||
import org.klomp.snark.bencode.BEValue;
|
||||
@@ -145,7 +146,17 @@ class PeerCoordinator implements PeerListener
|
||||
private final MagnetState magnetState;
|
||||
private final CoordinatorListener listener;
|
||||
private final I2PSnarkUtil _util;
|
||||
private final Random _random;
|
||||
private final RandomSource _random;
|
||||
|
||||
private final AtomicLong _commentsLastRequested = new AtomicLong();
|
||||
private final AtomicInteger _commentsNotRequested = new AtomicInteger();
|
||||
private static final long COMMENT_REQ_INTERVAL = 12*60*60*1000L;
|
||||
private static final long COMMENT_REQ_DELAY = 60*60*1000L;
|
||||
private static final int MAX_COMMENT_NOT_REQ = 10;
|
||||
|
||||
/** hostname to expire time, sync on this */
|
||||
private Map<String, Long> _webPeerBans;
|
||||
private static final long WEBPEER_BAN_TIME = 30*60*1000L;
|
||||
|
||||
/**
|
||||
* @param metainfo null if in magnet mode
|
||||
@@ -176,6 +187,9 @@ class PeerCoordinator implements PeerListener
|
||||
// this will help the behavior with global limits
|
||||
timer = new CheckEvent(_util.getContext(), new PeerCheckerTask(_util, this));
|
||||
timer.schedule((CHECK_PERIOD / 2) + _random.nextInt((int) CHECK_PERIOD));
|
||||
|
||||
// we don't store the last-requested time, so just delay a random amount
|
||||
_commentsLastRequested.set(util.getContext().clock().now() - (COMMENT_REQ_INTERVAL - _random.nextLong(COMMENT_REQ_DELAY)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -329,7 +343,8 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4-minute-average rate in Bps
|
||||
* Returns the average rate in Bps
|
||||
* over last RATE_DEPTH * CHECK_PERIOD seconds
|
||||
*/
|
||||
public long getDownloadRate()
|
||||
{
|
||||
@@ -338,6 +353,10 @@ class PeerCoordinator implements PeerListener
|
||||
return getRate(downloaded_old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the average rate in Bps
|
||||
* over last RATE_DEPTH * CHECK_PERIOD seconds
|
||||
*/
|
||||
public long getUploadRate()
|
||||
{
|
||||
if (halted)
|
||||
@@ -345,6 +364,10 @@ class PeerCoordinator implements PeerListener
|
||||
return getRate(uploaded_old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rate in Bps
|
||||
* over last complete CHECK_PERIOD seconds
|
||||
*/
|
||||
public long getCurrentUploadRate()
|
||||
{
|
||||
if (halted)
|
||||
@@ -404,7 +427,12 @@ class PeerCoordinator implements PeerListener
|
||||
public boolean needOutboundPeers() {
|
||||
//return wantedBytes != 0 && needPeers();
|
||||
// minus two to make it a little easier for new peers to get in on large swarms
|
||||
return wantedBytes != 0 &&
|
||||
return (wantedBytes != 0 ||
|
||||
(_util.utCommentsEnabled() &&
|
||||
// we should also check SnarkManager.getSavedCommentsEnabled() for this torrent,
|
||||
// but that reads in the config file, there's no caching.
|
||||
// TODO
|
||||
_commentsLastRequested.get() < _util.getContext().clock().now() - COMMENT_REQ_INTERVAL)) &&
|
||||
!halted &&
|
||||
peers.size() < getMaxConnections() - 2 &&
|
||||
(storage == null || !storage.isChecking());
|
||||
@@ -617,6 +645,8 @@ class PeerCoordinator implements PeerListener
|
||||
bitfield = storage.getBitField();
|
||||
else
|
||||
bitfield = null;
|
||||
if (!peer.isIncoming() && wantedBytes == 0 && _log.shouldInfo())
|
||||
_log.info("Outbound connection as seed to get comments for " + snark.getBaseName() + " to " + peer);
|
||||
// if we aren't a seed but we don't want any more
|
||||
final boolean partialComplete = wantedBytes == 0 && bitfield != null && !bitfield.complete();
|
||||
Runnable r = new Runnable()
|
||||
@@ -645,6 +675,9 @@ class PeerCoordinator implements PeerListener
|
||||
*/
|
||||
void unchokePeer()
|
||||
{
|
||||
if (storage == null || storage.getBitField().size() == 0)
|
||||
return;
|
||||
|
||||
// linked list will contain all interested peers that we choke.
|
||||
// At the start are the peers that have us unchoked at the end the
|
||||
// other peer that are interested, but are choking us.
|
||||
@@ -888,6 +921,7 @@ class PeerCoordinator implements PeerListener
|
||||
// As connections are already up, new Pieces will
|
||||
// not have their PeerID list populated, so do that.
|
||||
for (Peer p : peers) {
|
||||
// TODO don't access state directly
|
||||
PeerState s = p.state;
|
||||
if (s != null) {
|
||||
BitField bf = s.bitfield;
|
||||
@@ -1034,7 +1068,8 @@ class PeerCoordinator implements PeerListener
|
||||
// just in case
|
||||
removePartialPiece(piece);
|
||||
// Oops. We didn't actually download this then... :(
|
||||
downloaded.addAndGet(0 - metainfo.getPieceLength(piece));
|
||||
// Reports of counter going negative?
|
||||
//downloaded.addAndGet(0 - metainfo.getPieceLength(piece));
|
||||
// Mark this peer as not having the piece. PeerState will update its bitfield.
|
||||
for (Piece pc : wantedPieces) {
|
||||
if (pc.getId() == piece) {
|
||||
@@ -1114,6 +1149,10 @@ class PeerCoordinator implements PeerListener
|
||||
{
|
||||
if (interest)
|
||||
{
|
||||
if (storage == null || storage.getBitField().size() == 0) {
|
||||
// XD bug #80
|
||||
return;
|
||||
}
|
||||
if (uploaders.get() < allowedUploaders())
|
||||
{
|
||||
if(peer.isChoking())
|
||||
@@ -1212,12 +1251,12 @@ class PeerCoordinator implements PeerListener
|
||||
}
|
||||
int max = getMaxConnections();
|
||||
if (partialPieces.size() > max) {
|
||||
// sorts by remaining bytes, least first
|
||||
// sorts by preference, highest first
|
||||
Collections.sort(partialPieces);
|
||||
PartialPiece gone = partialPieces.remove(max);
|
||||
PartialPiece gone = partialPieces.remove(partialPieces.size() - 1);
|
||||
gone.release();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Discarding orphaned partial piece (list full)" + gone);
|
||||
_log.info("Discarding orphaned partial piece (list full) " + gone);
|
||||
}
|
||||
} else {
|
||||
// drop the empty partial piece
|
||||
@@ -1244,7 +1283,7 @@ class PeerCoordinator implements PeerListener
|
||||
if (storage != null && storage.isChecking())
|
||||
return null;
|
||||
synchronized(wantedPieces) {
|
||||
// sorts by remaining bytes, least first
|
||||
// sorts by preference, highest first
|
||||
Collections.sort(partialPieces);
|
||||
for (Iterator<PartialPiece> iter = partialPieces.iterator(); iter.hasNext(); ) {
|
||||
PartialPiece pp = iter.next();
|
||||
@@ -1252,6 +1291,7 @@ class PeerCoordinator implements PeerListener
|
||||
if (havePieces.get(savedPiece)) {
|
||||
// this is just a double-check, it should be in there
|
||||
boolean skipped = false;
|
||||
outer:
|
||||
for(Piece piece : wantedPieces) {
|
||||
if (piece.getId() == savedPiece) {
|
||||
if (peer.isCompleted() && piece.getPeerCount() > 1 &&
|
||||
@@ -1260,20 +1300,25 @@ class PeerCoordinator implements PeerListener
|
||||
// by not requesting a partial piece that at least two non-seeders also have
|
||||
// from a seeder
|
||||
int nonSeeds = 0;
|
||||
int seeds = 0;
|
||||
for (Peer pr : peers) {
|
||||
PeerState state = pr.state;
|
||||
if (state == null) continue;
|
||||
BitField bf = state.bitfield;
|
||||
if (bf == null) continue;
|
||||
if (bf.get(savedPiece) && !pr.isCompleted()) {
|
||||
if (++nonSeeds > 1)
|
||||
if (pr.isCompleted()) {
|
||||
if (++seeds >= 4)
|
||||
break;
|
||||
} else {
|
||||
// TODO don't access state directly
|
||||
PeerState state = pr.state;
|
||||
if (state == null) continue;
|
||||
BitField bf = state.bitfield;
|
||||
if (bf == null) continue;
|
||||
if (bf.get(savedPiece)) {
|
||||
if (++nonSeeds > 1) {
|
||||
skipped = true;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nonSeeds > 1) {
|
||||
skipped = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter.remove();
|
||||
piece.setRequested(peer, true);
|
||||
@@ -1299,6 +1344,7 @@ class PeerCoordinator implements PeerListener
|
||||
// Temporary? So PeerState never calls wantPiece() directly for now...
|
||||
Piece piece = wantPiece(peer, havePieces, true);
|
||||
if (piece != null) {
|
||||
// TODO padding
|
||||
return new PartialPiece(piece, metainfo.getPieceLength(piece.getId()), _util.getTempDir());
|
||||
}
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
@@ -1415,6 +1461,10 @@ class PeerCoordinator implements PeerListener
|
||||
if (bev.getMap().get(ExtensionHandler.TYPE_PEX) != null) {
|
||||
List<Peer> pList = peerList();
|
||||
pList.remove(peer);
|
||||
for (Iterator<Peer> iter = pList.iterator(); iter.hasNext(); ) {
|
||||
if (iter.next().isWebPeer())
|
||||
iter.remove();
|
||||
}
|
||||
if (!pList.isEmpty())
|
||||
ExtensionHandler.sendPEX(peer, pList);
|
||||
}
|
||||
@@ -1447,11 +1497,17 @@ class PeerCoordinator implements PeerListener
|
||||
*/
|
||||
void sendCommentReq(Peer peer) {
|
||||
Map<String, BEValue> handshake = peer.getHandshakeMap();
|
||||
if (handshake == null)
|
||||
if (handshake == null) {
|
||||
if (wantedBytes == 0 && _commentsNotRequested.incrementAndGet() >= MAX_COMMENT_NOT_REQ)
|
||||
_commentsLastRequested.set(_util.getContext().clock().now());
|
||||
return;
|
||||
}
|
||||
BEValue bev = handshake.get("m");
|
||||
if (bev == null)
|
||||
if (bev == null) {
|
||||
if (wantedBytes == 0 && _commentsNotRequested.incrementAndGet() >= MAX_COMMENT_NOT_REQ)
|
||||
_commentsLastRequested.set(_util.getContext().clock().now());
|
||||
return;
|
||||
}
|
||||
// TODO if peer hasn't been connected very long, don't bother
|
||||
// unless forced at handshake time (see above)
|
||||
try {
|
||||
@@ -1463,9 +1519,16 @@ class PeerCoordinator implements PeerListener
|
||||
sz = comments.size();
|
||||
}
|
||||
}
|
||||
_commentsNotRequested.set(0);
|
||||
_commentsLastRequested.set(_util.getContext().clock().now());
|
||||
if (sz >= CommentSet.MAX_SIZE)
|
||||
return;
|
||||
ExtensionHandler.sendCommentReq(peer, CommentSet.MAX_SIZE - sz);
|
||||
} else {
|
||||
// failsafe to prevent seed excessively connecting out to a swarm for comments
|
||||
// when nobody in the swarm supports comments
|
||||
if (wantedBytes == 0 && _commentsNotRequested.incrementAndGet() >= MAX_COMMENT_NOT_REQ)
|
||||
_commentsLastRequested.set(_util.getContext().clock().now());
|
||||
}
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
}
|
||||
@@ -1671,6 +1734,9 @@ class PeerCoordinator implements PeerListener
|
||||
interestedAndChoking.addAndGet(toAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is snark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit()
|
||||
{
|
||||
if (listener != null)
|
||||
@@ -1678,6 +1744,10 @@ class PeerCoordinator implements PeerListener
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a particular peer who has downloaded this many bytes from us
|
||||
* in the last CHECK_PERIOD over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total)
|
||||
{
|
||||
if (listener != null)
|
||||
@@ -1692,5 +1762,43 @@ class PeerCoordinator implements PeerListener
|
||||
public I2PSnarkUtil getUtil() {
|
||||
return _util;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ban a web peer for this torrent, for while or permanently.
|
||||
* @param host the host name
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public synchronized void banWebPeer(String host, boolean isPermanent) {
|
||||
if (_webPeerBans == null)
|
||||
_webPeerBans = new HashMap<String, Long>(4);
|
||||
Long time;
|
||||
if (isPermanent) {
|
||||
time = Long.valueOf(Long.MAX_VALUE);
|
||||
} else {
|
||||
long now = _util.getContext().clock().now();
|
||||
time = Long.valueOf(now + WEBPEER_BAN_TIME);
|
||||
}
|
||||
Long old = _webPeerBans.put(host, time);
|
||||
if (old != null && old.longValue() > time)
|
||||
_webPeerBans.put(host, old);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a web peer banned?
|
||||
* @param host the host name
|
||||
* @since 0.9.49
|
||||
*/
|
||||
public synchronized boolean isWebPeerBanned(String host) {
|
||||
if (_webPeerBans == null)
|
||||
return false;
|
||||
Long time = _webPeerBans.get(host);
|
||||
if (time == null)
|
||||
return false;
|
||||
long now = _util.getContext().clock().now();
|
||||
boolean rv = time.longValue() > now;
|
||||
if (!rv)
|
||||
_webPeerBans.remove(host);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -227,6 +227,10 @@ public class PeerID implements Comparable<PeerID>
|
||||
{
|
||||
if (_toStringCache != null)
|
||||
return _toStringCache;
|
||||
if (id != null && DataHelper.eq(id, 0, WebPeer.IDBytes, 0, WebPeer.IDBytes.length)) {
|
||||
_toStringCache = "WebSeed@" + Base32.encode(destHash) + ".b32.i2p";
|
||||
return _toStringCache;
|
||||
}
|
||||
if (id == null || address == null)
|
||||
return "unkn@" + Base64.encode(destHash).substring(0, 6);
|
||||
int nonZero = 0;
|
||||
|
||||
@@ -69,9 +69,12 @@ class PeerState implements DataLoader
|
||||
private Request lastRequest = null;
|
||||
|
||||
// FIXME if piece size < PARTSIZE, pipeline could be bigger
|
||||
private final static int MAX_PIPELINE = 5; // this is for outbound requests
|
||||
private final static int MAX_PIPELINE_BYTES = 128*1024; // this is for inbound requests
|
||||
/** @since 0.9.47 */
|
||||
public static final int MIN_PIPELINE = 5; // this is for outbound requests
|
||||
/** @since public since 0.9.47 */
|
||||
public static final int MAX_PIPELINE = 8; // this is for outbound requests
|
||||
public final static int PARTSIZE = 16*1024; // outbound request
|
||||
private final static int MAX_PIPELINE_BYTES = (MAX_PIPELINE + 2) * PARTSIZE; // this is for inbound requests
|
||||
private final static int MAX_PARTSIZE = 64*1024; // Don't let anybody request more than this
|
||||
private static final Integer PIECE_ALL = Integer.valueOf(-1);
|
||||
|
||||
@@ -259,9 +262,9 @@ class PeerState implements DataLoader
|
||||
if (bev != null) {
|
||||
try {
|
||||
if (bev.getMap().get(ExtensionHandler.TYPE_COMMENT) != null) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Allowing seed that connects to seeds for comments: " + peer);
|
||||
setInteresting(interest);
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Allowing seed that connects to seeds for comments: " + peer);
|
||||
setInteresting(false);
|
||||
return;
|
||||
}
|
||||
} catch (InvalidBEncodingException ibee) {}
|
||||
@@ -880,7 +883,7 @@ class PeerState implements DataLoader
|
||||
boolean more_pieces = true;
|
||||
while (more_pieces)
|
||||
{
|
||||
more_pieces = outstandingRequests.size() < MAX_PIPELINE;
|
||||
more_pieces = outstandingRequests.size() < peer.getMaxPipeline();
|
||||
// We want something and we don't have outstanding requests?
|
||||
if (more_pieces && lastRequest == null) {
|
||||
// we have nothing in the queue right now
|
||||
|
||||
@@ -304,6 +304,7 @@ public class Snark
|
||||
* Will not start itself. Caller must call startTorrent() if desired.
|
||||
*
|
||||
* @throws RuntimeException via fatal()
|
||||
* @throws RouterException via fatalRouter()
|
||||
*/
|
||||
public Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
|
||||
StorageListener slistener, CoordinatorListener clistener,
|
||||
@@ -321,6 +322,7 @@ public class Snark
|
||||
*
|
||||
* @param baseFile if null, use rootDir/torrentName; if non-null, use it instead
|
||||
* @throws RuntimeException via fatal()
|
||||
* @throws RouterException via fatalRouter()
|
||||
* @since 0.9.11
|
||||
*/
|
||||
public Snark(I2PSnarkUtil util, String torrent, String ip, int user_port,
|
||||
@@ -399,7 +401,7 @@ public class Snark
|
||||
fatal("'" + torrent + "' exists,"
|
||||
+ " but is not a valid torrent metainfo file."
|
||||
+ System.getProperty("line.separator"), ioe);
|
||||
else
|
||||
else
|
||||
fatal("I2PSnark does not support creating and tracking a torrent at the moment");
|
||||
/*
|
||||
{
|
||||
@@ -424,7 +426,7 @@ public class Snark
|
||||
else
|
||||
fatal("Cannot open '" + torrent + "'", ioe);
|
||||
} catch (OutOfMemoryError oom) {
|
||||
fatal("ERROR - Out of memory, cannot create torrent " + torrent + ": " + oom.getMessage());
|
||||
fatalRouter("ERROR - Out of memory, cannot create torrent " + torrent + ": " + oom.getMessage(), oom);
|
||||
} finally {
|
||||
if (in != null)
|
||||
try { in.close(); } catch (IOException ioe) {}
|
||||
@@ -467,7 +469,7 @@ public class Snark
|
||||
try { storage.close(); } catch (IOException ioee) {
|
||||
ioee.printStackTrace();
|
||||
}
|
||||
fatal("Could not check or create storage", ioe);
|
||||
fatal("Could not check or create files for " + getBaseInfo(), ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -489,6 +491,22 @@ public class Snark
|
||||
_comments = completeListener.getSavedComments(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* multitorrent, magnet, Used by snark-rpc plugin
|
||||
*
|
||||
* Will not start itself. Caller must call startTorrent() if desired.
|
||||
*
|
||||
* @param ignored used to be autostart
|
||||
* @throws RuntimeException via fatal()
|
||||
* @throws RouterException via fatalRouter()
|
||||
* @since 0.8.4, removed in 0.9.36, restored in 0.9.45 with boolean param now ignored
|
||||
*/
|
||||
protected Snark(I2PSnarkUtil util, String torrent, byte[] ih, String trackerURL,
|
||||
CompleteListener complistener, PeerCoordinatorSet peerCoordinatorSet,
|
||||
ConnectionAcceptor connectionAcceptor, boolean ignored, String rootDir) {
|
||||
this(util, torrent, ih, trackerURL, complistener, peerCoordinatorSet, connectionAcceptor, rootDir);
|
||||
}
|
||||
|
||||
/**
|
||||
* multitorrent, magnet
|
||||
*
|
||||
@@ -498,6 +516,7 @@ public class Snark
|
||||
* @param ih 20-byte info hash
|
||||
* @param trackerURL may be null
|
||||
* @throws RuntimeException via fatal()
|
||||
* @throws RouterException via fatalRouter()
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public Snark(I2PSnarkUtil util, String torrent, byte[] ih, String trackerURL,
|
||||
@@ -541,7 +560,12 @@ public class Snark
|
||||
rv[9] = snark;
|
||||
rv[10] = snark;
|
||||
rv[11] = snark;
|
||||
I2PAppContext.getGlobalContext().random().nextBytes(rv, 12, 8);
|
||||
try {
|
||||
I2PAppContext.getGlobalContext().random().nextBytes(rv, 12, 8);
|
||||
} catch (IllegalStateException ise) {
|
||||
// random is shut down
|
||||
throw new RouterException("Router shutdown", ise);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -550,8 +574,11 @@ public class Snark
|
||||
* Blocks if tunnel is not yet open.
|
||||
*
|
||||
* @throws RuntimeException via fatal()
|
||||
* @throws RouterException via fatalRouter()
|
||||
*/
|
||||
public synchronized void startTorrent() {
|
||||
if (!stopped)
|
||||
return;
|
||||
starting = true;
|
||||
try {
|
||||
x_startTorrent();
|
||||
@@ -563,11 +590,12 @@ public class Snark
|
||||
|
||||
private void x_startTorrent() {
|
||||
boolean ok = _util.connect();
|
||||
if (!ok) fatal("Unable to connect to I2P");
|
||||
if (!ok)
|
||||
fatalRouter("Unable to connect to I2P", null);
|
||||
if (coordinator == null) {
|
||||
I2PServerSocket serversocket = _util.getServerSocket();
|
||||
if (serversocket == null)
|
||||
fatal("Unable to listen for I2P connections");
|
||||
fatalRouter("Unable to listen for I2P connections", null);
|
||||
else {
|
||||
Destination d = serversocket.getManager().getSession().getMyDestination();
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
@@ -609,7 +637,7 @@ public class Snark
|
||||
try { storage.close(); } catch (IOException ioee) {
|
||||
ioee.printStackTrace();
|
||||
}
|
||||
fatal("Could not reopen storage", ioe);
|
||||
fatal("Could not open file for " + getBaseInfo(), ioe);
|
||||
}
|
||||
}
|
||||
trackerclient.start();
|
||||
@@ -648,18 +676,22 @@ public class Snark
|
||||
// TODO: Cache the config-in-mem to compare vs config-on-disk
|
||||
// (needed for auto-save to not double-save in some cases)
|
||||
long nowUploaded = getUploaded();
|
||||
boolean changed = storage.isChanged() || nowUploaded != savedUploaded;
|
||||
// If autoStart is enabled, always save the config, so we know
|
||||
// whether to start it up next time
|
||||
boolean changed = storage.isChanged() || nowUploaded != savedUploaded ||
|
||||
(completeListener != null && completeListener.shouldAutoStart());
|
||||
try {
|
||||
storage.close();
|
||||
} catch (IOException ioe) {
|
||||
System.out.println("Error closing " + torrent);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Error closing " + torrent);
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
savedUploaded = nowUploaded;
|
||||
if (changed && completeListener != null)
|
||||
completeListener.updateStatus(this);
|
||||
// TODO should save comments at shutdown even if never started...
|
||||
// SnarkManager.stopAllTorrents() will save comments at shutdown even if never started...
|
||||
if (completeListener != null) {
|
||||
if (changed)
|
||||
completeListener.updateStatus(this);
|
||||
synchronized(_commentLock) {
|
||||
if (_comments != null) {
|
||||
synchronized(_comments) {
|
||||
@@ -706,6 +738,19 @@ public class Snark
|
||||
return torrent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return base name for torrent [filtered version of getMetaInfo.getName()],
|
||||
* or a fake name if in magnet mode, followed by path info and error message,
|
||||
* for error logging only
|
||||
* @since 0.9.44
|
||||
*/
|
||||
private String getBaseInfo() {
|
||||
if (storage != null)
|
||||
return storage.getBaseName() + " at " +
|
||||
storage.getBase() + " - check that device is present and writable";
|
||||
return torrent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return always will be valid even in magnet mode
|
||||
* @since 0.8.4
|
||||
@@ -1183,21 +1228,18 @@ public class Snark
|
||||
|
||||
/**
|
||||
* Aborts program abnormally.
|
||||
* @throws RuntimeException always
|
||||
*/
|
||||
private void fatal(String s)
|
||||
{
|
||||
private void fatal(String s) throws RuntimeException {
|
||||
fatal(s, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts program abnormally.
|
||||
* @throws RuntimeException always
|
||||
*/
|
||||
private void fatal(String s, Throwable t)
|
||||
{
|
||||
private void fatal(String s, Throwable t) throws RuntimeException {
|
||||
_log.error(s, t);
|
||||
//System.err.println("snark: " + s + ((t == null) ? "" : (": " + t)));
|
||||
//if (debug >= INFO && t != null)
|
||||
// t.printStackTrace();
|
||||
stopTorrent();
|
||||
if (t != null)
|
||||
s += ": " + t;
|
||||
@@ -1206,6 +1248,29 @@ public class Snark
|
||||
throw new RuntimeException(s, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a unique exception class to blame the router that can be caught by SnarkManager
|
||||
* @throws RouterException always
|
||||
* @since 0.9.46
|
||||
*/
|
||||
private void fatalRouter(String s, Throwable t) throws RouterException {
|
||||
_log.error(s, t);
|
||||
stopTorrent();
|
||||
if (completeListener != null)
|
||||
completeListener.fatal(this, s);
|
||||
throw new RouterException(s, t);
|
||||
}
|
||||
|
||||
/**
|
||||
* A unique exception class to blame the router that can be caught by SnarkManager
|
||||
* @since 0.9.46
|
||||
*/
|
||||
static class RouterException extends RuntimeException {
|
||||
public RouterException(String s) { super(s); }
|
||||
public RouterException(String s, Throwable t) { super(s, t); }
|
||||
}
|
||||
|
||||
|
||||
/** CoordinatorListener - this does nothing */
|
||||
public void peerChange(PeerCoordinator coordinator, Peer peer)
|
||||
{
|
||||
@@ -1229,6 +1294,8 @@ public class Snark
|
||||
baseFile = new File(rootDataDir, base);
|
||||
else
|
||||
baseFile = new SecureFile(rootDataDir, base);
|
||||
if (baseFile.exists())
|
||||
throw new IOException("Data location already exists: " + baseFile);
|
||||
// The following two may throw IOE...
|
||||
storage = new Storage(_util, baseFile, metainfo, this, false);
|
||||
storage.check();
|
||||
@@ -1250,7 +1317,7 @@ public class Snark
|
||||
}
|
||||
// TODO we're still in an inconsistent state, won't work if restarted
|
||||
// (PeerState "disconnecting seed that connects to seeds"
|
||||
fatal("Could not create data files", ioe);
|
||||
fatal("Could not create file for " + getBaseInfo(), ioe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1385,6 +1452,9 @@ public class Snark
|
||||
return totalUploaders > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is i2psnark as a whole over its limit?
|
||||
*/
|
||||
public boolean overUpBWLimit() {
|
||||
if (_peerCoordinatorSet == null)
|
||||
return false;
|
||||
@@ -1399,6 +1469,9 @@ public class Snark
|
||||
return total > limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a particular peer who has this recent download rate (in Bps) over our upstream bandwidth limit?
|
||||
*/
|
||||
public boolean overUpBWLimit(long total) {
|
||||
long limit = 1024l * _util.getMaxUpBW();
|
||||
return total > limit;
|
||||
|
||||
@@ -8,6 +8,7 @@ import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.text.Collator;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -64,6 +65,10 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
* all adds, deletes, and the DirMonitor should sync on it.
|
||||
*/
|
||||
private final Map<String, Snark> _snarks;
|
||||
// sync on _snarks
|
||||
private final Map<SHA1Hash, Snark> _infoHashToSnark;
|
||||
// sync on _snarks
|
||||
private final Map<String, Snark> _filteredBaseNameToSnark;
|
||||
/** used to prevent DirMonitor from deleting torrents that don't have a torrent file yet */
|
||||
private final Set<String> _magnets;
|
||||
private final Object _addSnarkLock;
|
||||
@@ -116,6 +121,8 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
private static final String PROP_META_MAGNET_PREFIX = "i2psnark.magnet.";
|
||||
/** @since 0.9.31 */
|
||||
private static final String PROP_META_COMMENTS = "comments";
|
||||
/** @since 0.9.42 */
|
||||
private static final String PROP_META_ACTIVITY = "activity";
|
||||
|
||||
private static final String CONFIG_FILE_SUFFIX = ".config";
|
||||
private static final String CONFIG_FILE = "i2psnark" + CONFIG_FILE_SUFFIX;
|
||||
@@ -155,7 +162,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
public static final int MIN_UP_BW = 10;
|
||||
public static final int DEFAULT_MAX_UP_BW = 25;
|
||||
public static final int DEFAULT_STARTUP_DELAY = 3;
|
||||
public static final int DEFAULT_REFRESH_DELAY_SECS = 60;
|
||||
public static final int DEFAULT_REFRESH_DELAY_SECS = 15;
|
||||
private static final int DEFAULT_PAGE_SIZE = 50;
|
||||
public static final int DEFAULT_TUNNEL_QUANTITY = 3;
|
||||
public static final String CONFIG_DIR_SUFFIX = ".d";
|
||||
@@ -182,22 +189,26 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
// , "Galen", "http://5jpwQMI5FT303YwKa5Rd38PYSX04pbIKgTaKQsWbqoWjIfoancFdWCShXHLI5G5ofOb0Xu11vl2VEMyPsg1jUFYSVnu4-VfMe3y4TKTR6DTpetWrnmEK6m2UXh91J5DZJAKlgmO7UdsFlBkQfR2rY853-DfbJtQIFl91tbsmjcA5CGQi4VxMFyIkBzv-pCsuLQiZqOwWasTlnzey8GcDAPG1LDcvfflGV~6F5no9mnuisZPteZKlrv~~TDoXTj74QjByWc4EOYlwqK8sbU9aOvz~s31XzErbPTfwiawiaZ0RUI-IDrKgyvmj0neuFTWgjRGVTH8bz7cBZIc3viy6ioD-eMQOrXaQL0TCWZUelRwHRvgdPiQrxdYQs7ixkajeHzxi-Pq0EMm5Vbh3j3Q9kfUFW3JjFDA-MLB4g6XnjCbM5J1rC0oOBDCIEfhQkszru5cyLjHiZ5yeA0VThgu~c7xKHybv~OMXION7V8pBKOgET7ZgAkw1xgYe3Kkyq5syAAAA.i2p/tr/announce.php=http://galen.i2p/tr/"
|
||||
"Postman", "http://tracker2.postman.i2p/announce.php=http://tracker2.postman.i2p/"
|
||||
// ,"Welterde", "http://tracker.welterde.i2p/a=http://tracker.welterde.i2p/stats?mode=top5"
|
||||
,"Diftracker", "http://diftracker.i2p/announce.php=http://diftracker.i2p/"
|
||||
//last up Aug. 18 2019
|
||||
// ,"Diftracker", "http://diftracker.i2p/announce.php=http://diftracker.i2p/"
|
||||
// , "CRSTRACK", "http://b4G9sCdtfvccMAXh~SaZrPqVQNyGQbhbYMbw6supq2XGzbjU4NcOmjFI0vxQ8w1L05twmkOvg5QERcX6Mi8NQrWnR0stLExu2LucUXg1aYjnggxIR8TIOGygZVIMV3STKH4UQXD--wz0BUrqaLxPhrm2Eh9Hwc8TdB6Na4ShQUq5Xm8D4elzNUVdpM~RtChEyJWuQvoGAHY3ppX-EJJLkiSr1t77neS4Lc-KofMVmgI9a2tSSpNAagBiNI6Ak9L1T0F9uxeDfEG9bBSQPNMOSUbAoEcNxtt7xOW~cNOAyMyGydwPMnrQ5kIYPY8Pd3XudEko970vE0D6gO19yoBMJpKx6Dh50DGgybLQ9CpRaynh2zPULTHxm8rneOGRcQo8D3mE7FQ92m54~SvfjXjD2TwAVGI~ae~n9HDxt8uxOecAAvjjJ3TD4XM63Q9TmB38RmGNzNLDBQMEmJFpqQU8YeuhnS54IVdUoVQFqui5SfDeLXlSkh4vYoMU66pvBfWbAAAA.i2p/tracker/announce.php=http://crstrack.i2p/tracker/"
|
||||
// ,"Exotrack", "http://blbgywsjubw3d2zih2giokakhe3o2cko7jtte4risb3hohbcoyva.b32.i2p/announce.php=http://exotrack.i2p/"
|
||||
,"DgTrack", "http://w7tpbzncbcocrqtwwm3nezhnnsw4ozadvi2hmvzdhrqzfxfum7wa.b32.i2p/a=http://opentracker.dg2.i2p/"
|
||||
// The following is ECDSA_SHA256_P256
|
||||
,"TheBland", "http://s5ikrdyjwbcgxmqetxb3nyheizftms7euacuub2hic7defkh3xhq.b32.i2p/a=http://tracker.thebland.i2p/tracker/index.jsp"
|
||||
,"psi's open tracker", "http://uajd4nctepxpac4c4bdyrdw7qvja2a5u3x25otfhkptcjgd53ioq.b32.i2p/announce=http://uajd4nctepxpac4c4bdyrdw7qvja2a5u3x25otfhkptcjgd53ioq.b32.i2p/"
|
||||
,"C.Tracker", "http://ri5a27ioqd4vkik72fawbcryglkmwyy4726uu5j3eg6zqh2jswfq.b32.i2p/announce=http://tracker.crypthost.i2p/tracker/index.jsp",
|
||||
//last up Sep. 19 2020
|
||||
//,"TheBland", "http://s5ikrdyjwbcgxmqetxb3nyheizftms7euacuub2hic7defkh3xhq.b32.i2p/a=http://tracker.thebland.i2p/tracker/index.jsp"
|
||||
//down for good
|
||||
//,"psi's open tracker", "http://uajd4nctepxpac4c4bdyrdw7qvja2a5u3x25otfhkptcjgd53ioq.b32.i2p/announce=http://uajd4nctepxpac4c4bdyrdw7qvja2a5u3x25otfhkptcjgd53ioq.b32.i2p/"
|
||||
//last up May 21 2019
|
||||
// ,"C.Tracker", "http://ri5a27ioqd4vkik72fawbcryglkmwyy4726uu5j3eg6zqh2jswfq.b32.i2p/announce=http://tracker.crypthost.i2p/tracker/index.jsp",
|
||||
};
|
||||
|
||||
/** URL. This is our equivalent to router.utorrent.com for bootstrap */
|
||||
public static final String DEFAULT_BACKUP_TRACKER = "http://opentracker.dg2.i2p/a";
|
||||
|
||||
/** URLs, comma-separated. Used for "announce to open trackers also" */
|
||||
private static final String DEFAULT_OPENTRACKERS = DEFAULT_BACKUP_TRACKER +
|
||||
(SigType.ECDSA_SHA256_P256.isAvailable() ? ",http://tracker.thebland.i2p/a" : "");
|
||||
private static final String DEFAULT_OPENTRACKERS = DEFAULT_BACKUP_TRACKER; // +
|
||||
//(SigType.ECDSA_SHA256_P256.isAvailable() ? ",http://tracker.thebland.i2p/a" : "");
|
||||
|
||||
public static final Set<String> DEFAULT_TRACKER_ANNOUNCES;
|
||||
|
||||
@@ -246,6 +257,8 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
*/
|
||||
public SnarkManager(I2PAppContext ctx, String ctxPath, String ctxName) {
|
||||
_snarks = new ConcurrentHashMap<String, Snark>();
|
||||
_infoHashToSnark = new HashMap<SHA1Hash, Snark>();
|
||||
_filteredBaseNameToSnark = new HashMap<String, Snark>();
|
||||
_magnets = new ConcurrentHashSet<String>();
|
||||
_addSnarkLock = new Object();
|
||||
_context = ctx;
|
||||
@@ -870,6 +883,31 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
}
|
||||
return theme;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the preferred embedded icons for toImg, "solid/" for
|
||||
* dark and light, "" for everything else.
|
||||
*
|
||||
* If you add a theme with a new icon set, then you need to add a
|
||||
* corresponding condition here.
|
||||
*
|
||||
* @return String "solid/" or ""
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public String getThemeIconSet() {
|
||||
String iconset;
|
||||
String theme = getTheme();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Theme was: " + theme);
|
||||
if (theme.equals("dark") || theme.equals("light")) {
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("Using solid iconset.");
|
||||
iconset = "solid/";
|
||||
} else {
|
||||
iconset = "";
|
||||
}
|
||||
return iconset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all themes
|
||||
@@ -1440,17 +1478,16 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
|
||||
/**
|
||||
* Grab the torrent given the base name of the storage
|
||||
*
|
||||
* @param filename must be the filtered name, which may be different than
|
||||
* the metainfo's name
|
||||
* @return Snark or null
|
||||
* @since 0.7.14
|
||||
*/
|
||||
public Snark getTorrentByBaseName(String filename) {
|
||||
synchronized (_snarks) {
|
||||
for (Snark s : _snarks.values()) {
|
||||
if (s.getBaseName().equals(filename))
|
||||
return s;
|
||||
}
|
||||
return _filteredBaseNameToSnark.get(filename);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1460,23 +1497,68 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
*/
|
||||
public Snark getTorrentByInfoHash(byte[] infohash) {
|
||||
synchronized (_snarks) {
|
||||
for (Snark s : _snarks.values()) {
|
||||
if (DataHelper.eq(infohash, s.getInfoHash()))
|
||||
return s;
|
||||
}
|
||||
return _infoHashToSnark.get(new SHA1Hash(infohash));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caller must verify this torrent is not already added.
|
||||
*
|
||||
* @param filename the absolute path to save the metainfo to, generally ending in ".torrent"
|
||||
* @param baseFile may be null, if so look in dataDir
|
||||
* @throws RuntimeException via Snark.fatal()
|
||||
* Add the snark.
|
||||
* Caller must sync on _snarks
|
||||
* @since 0.9.42
|
||||
*/
|
||||
private void addTorrent(String filename, File baseFile, boolean dontAutoStart) {
|
||||
addTorrent(filename, baseFile, dontAutoStart, null);
|
||||
private void putSnark(String torrentFile, Snark snark) {
|
||||
_snarks.put(torrentFile, snark);
|
||||
_infoHashToSnark.put(new SHA1Hash(snark.getInfoHash()), snark);
|
||||
Storage storage = snark.getStorage();
|
||||
if (storage != null)
|
||||
_filteredBaseNameToSnark.put(storage.getBaseName(), snark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the snark.
|
||||
* Caller must sync on _snarks
|
||||
* @since 0.9.42
|
||||
*/
|
||||
private void removeSnark(Snark snark) {
|
||||
_snarks.remove(snark.getName());
|
||||
_infoHashToSnark.remove(new SHA1Hash(snark.getInfoHash()));
|
||||
Storage storage = snark.getStorage();
|
||||
if (storage != null)
|
||||
_filteredBaseNameToSnark.remove(storage.getBaseName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the snark.
|
||||
* Caller must sync on _snarks
|
||||
* @return the removed Snark or null
|
||||
* @since 0.9.42
|
||||
*/
|
||||
private Snark removeSnark(String torrentFile) {
|
||||
Snark snark = _snarks.remove(torrentFile);
|
||||
if (snark != null) {
|
||||
_infoHashToSnark.remove(new SHA1Hash(snark.getInfoHash()));
|
||||
Storage storage = snark.getStorage();
|
||||
if (storage != null)
|
||||
_filteredBaseNameToSnark.remove(storage.getBaseName());
|
||||
}
|
||||
return snark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename the torrent file to add a .BAD suffix,
|
||||
* log messages
|
||||
* @since 0.9.42
|
||||
*/
|
||||
private void disableTorrentFile(String torrentFile) {
|
||||
File sfile = new File(torrentFile);
|
||||
File rename = new File(torrentFile + ".BAD");
|
||||
if (rename.exists()) {
|
||||
if (sfile.delete())
|
||||
addMessage(_t("Torrent file deleted: {0}", sfile.toString()));
|
||||
} else {
|
||||
if (FileUtil.rename(sfile, rename))
|
||||
addMessage(_t("Torrent file moved from {0} to {1}", sfile.toString(), rename.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1484,26 +1566,33 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
*
|
||||
* @param filename the absolute path to save the metainfo to, generally ending in ".torrent"
|
||||
* @param baseFile may be null, if so look in dataDir
|
||||
* @param dontAutoStart must be false, AND running=true or null in torrent config file, to start
|
||||
* @throws RuntimeException via Snark.fatal()
|
||||
* @return success
|
||||
*/
|
||||
private boolean addTorrent(String filename, File baseFile, boolean dontAutoStart) {
|
||||
return addTorrent(filename, baseFile, dontAutoStart, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Caller must verify this torrent is not already added.
|
||||
*
|
||||
* @param filename the absolute path to save the metainfo to, generally ending in ".torrent"
|
||||
* @param baseFile may be null, if so look in dataDir
|
||||
* @param dontAutoStart must be false, AND running=true or null in torrent config file, to start
|
||||
* @param dataDir must exist, or null to default to snark data directory
|
||||
* @throws RuntimeException via Snark.fatal()
|
||||
* @return success
|
||||
* @since 0.9.17
|
||||
*/
|
||||
private void addTorrent(String filename, File baseFile, boolean dontAutoStart, File dataDir) {
|
||||
if ((!dontAutoStart) && !_util.connected()) {
|
||||
addMessage(_t("Connecting to I2P"));
|
||||
boolean ok = _util.connect();
|
||||
if (!ok) {
|
||||
addMessage(_t("Error connecting to I2P - check your I2CP settings!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
private boolean addTorrent(String filename, File baseFile, boolean dontAutoStart, File dataDir) {
|
||||
File sfile = new File(filename);
|
||||
try {
|
||||
filename = sfile.getCanonicalPath();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Unable to add the torrent " + filename, ioe);
|
||||
addMessage(_t("Error: Could not add the torrent {0}", filename) + ": " + ioe);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (dataDir == null)
|
||||
dataDir = getDataDir();
|
||||
@@ -1516,8 +1605,10 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
synchronized (_addSnarkLock) {
|
||||
// double-check
|
||||
synchronized (_snarks) {
|
||||
if(_snarks.get(filename) != null)
|
||||
return;
|
||||
if(_snarks.get(filename) != null) {
|
||||
addMessage(_t("Torrent already running: {0}", filename));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
FileInputStream fis = null;
|
||||
@@ -1525,8 +1616,8 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
fis = new FileInputStream(sfile);
|
||||
} catch (IOException ioe) {
|
||||
// catch this here so we don't try do delete it below
|
||||
addMessage(_t("Cannot open \"{0}\"", sfile.getName()) + ": " + ioe.getMessage());
|
||||
return;
|
||||
addMessage(_t("Cannot open \"{0}\"", sfile.getName()) + ": " + ioe.getLocalizedMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -1539,13 +1630,19 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
fis = null;
|
||||
} catch (IOException e) {}
|
||||
|
||||
// This test may be a duplicate, but not if we were called
|
||||
// These tests may be duplicates, but not if we were called
|
||||
// from the DirMonitor, which only checks for dup torrent file names.
|
||||
Snark snark = getTorrentByInfoHash(info.getInfoHash());
|
||||
if (snark != null) {
|
||||
// TODO - if the existing one is a magnet, delete it and add the metainfo instead?
|
||||
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
String filtered = Storage.filterName(info.getName());
|
||||
snark = getTorrentByBaseName(filtered);
|
||||
if (snark != null) {
|
||||
addMessage(_t("Torrent with the same data location is already running: {0}", snark.getBaseName()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TrackerClient.isValidAnnounce(info.getAnnounce())) {
|
||||
@@ -1578,52 +1675,58 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
dataDir.getPath(), baseFile);
|
||||
loadSavedFilePriorities(torrent);
|
||||
synchronized (_snarks) {
|
||||
_snarks.put(filename, torrent);
|
||||
putSnark(filename, torrent);
|
||||
}
|
||||
if (shouldAutoStart())
|
||||
torrent.startTorrent();
|
||||
} catch (IOException ioe) {
|
||||
// close before rename/delete for windows
|
||||
if (fis != null) try { fis.close(); fis = null; } catch (IOException ioe2) {}
|
||||
String err = _t("Torrent in \"{0}\" is invalid", sfile.toString()) + ": " + ioe.getMessage();
|
||||
String err = _t("Torrent in \"{0}\" is invalid", sfile.toString()) + ": " + ioe.getLocalizedMessage();
|
||||
addMessage(err);
|
||||
_log.error(err, ioe);
|
||||
File rename = new File(filename + ".BAD");
|
||||
if (rename.exists()) {
|
||||
if (sfile.delete())
|
||||
addMessage(_t("Torrent file deleted: {0}", sfile.toString()));
|
||||
} else {
|
||||
if (FileUtil.rename(sfile, rename))
|
||||
addMessage(_t("Torrent file moved from {0} to {1}", sfile.toString(), rename.toString()));
|
||||
}
|
||||
return;
|
||||
disableTorrentFile(filename);
|
||||
return false;
|
||||
} catch (OutOfMemoryError oom) {
|
||||
addMessage(_t("ERROR - Out of memory, cannot create torrent from {0}", sfile.getName()) + ": " + oom.getMessage());
|
||||
return;
|
||||
String s = _t("ERROR - Out of memory, cannot create torrent from {0}", sfile.getName()) + ": " + oom.getLocalizedMessage();
|
||||
addMessage(s);
|
||||
throw new Snark.RouterException(s, oom);
|
||||
} finally {
|
||||
if (fis != null) try { fis.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
addMessage(_t("Torrent already running: {0}", filename));
|
||||
return false;
|
||||
}
|
||||
// ok, snark created, now lets start it up or configure it further
|
||||
Properties config = getConfig(torrent);
|
||||
boolean running;
|
||||
String prop = config.getProperty(PROP_META_RUNNING);
|
||||
if(prop == null || Boolean.parseBoolean(prop)) {
|
||||
running = true;
|
||||
} else {
|
||||
running = false;
|
||||
String prop = config.getProperty(PROP_META_RUNNING);
|
||||
boolean running = prop == null || Boolean.parseBoolean(prop);
|
||||
prop = config.getProperty(PROP_META_ACTIVITY);
|
||||
if (prop != null && torrent.getStorage() != null) {
|
||||
try {
|
||||
long activity = Long.parseLong(prop);
|
||||
torrent.getStorage().setActivity(activity);
|
||||
} catch (NumberFormatException nfe) {}
|
||||
}
|
||||
|
||||
// Were we running last time?
|
||||
String link = linkify(torrent);
|
||||
if (!dontAutoStart && shouldAutoStart() && running) {
|
||||
if (!_util.connected()) {
|
||||
addMessage(_t("Connecting to I2P"));
|
||||
boolean ok = _util.connect();
|
||||
if (!ok) {
|
||||
addMessage(_t("Error connecting to I2P - check your I2CP settings!"));
|
||||
// this would rename the torrent to .BAD
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
torrent.startTorrent();
|
||||
addMessageNoEscape(_t("Torrent added and started: {0}", link));
|
||||
} else {
|
||||
addMessageNoEscape(_t("Torrent added: {0}", link));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1694,7 +1797,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
_magnets.add(name);
|
||||
if (updateStatus)
|
||||
saveMagnetStatus(ih, dirPath, trackerURL, name);
|
||||
_snarks.put(name, torrent);
|
||||
putSnark(name, torrent);
|
||||
}
|
||||
if (autoStart) {
|
||||
startTorrent(ih);
|
||||
@@ -1722,7 +1825,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
*/
|
||||
public void deleteMagnet(Snark snark) {
|
||||
synchronized (_snarks) {
|
||||
_snarks.remove(snark.getName());
|
||||
removeSnark(snark);
|
||||
}
|
||||
snark.stopTorrent();
|
||||
_magnets.remove(snark.getName());
|
||||
@@ -1748,7 +1851,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
String name = torrent.getName();
|
||||
// Tell the dir monitor not to delete us
|
||||
_magnets.add(name);
|
||||
_snarks.put(name, torrent);
|
||||
putSnark(name, torrent);
|
||||
}
|
||||
torrent.startTorrent();
|
||||
}
|
||||
@@ -1778,12 +1881,19 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
if (snark != null) {
|
||||
addMessage(_t("Torrent with this info hash is already running: {0}", snark.getBaseName()));
|
||||
return false;
|
||||
} else if (bitfield != null) {
|
||||
saveTorrentStatus(metainfo, bitfield, null, false, baseFile, true, 0, true); // no file priorities
|
||||
}
|
||||
String filtered = Storage.filterName(metainfo.getName());
|
||||
snark = getTorrentByBaseName(filtered);
|
||||
if (snark != null) {
|
||||
addMessage(_t("Torrent with the same data location is already running: {0}", snark.getBaseName()));
|
||||
return false;
|
||||
}
|
||||
if (bitfield != null) {
|
||||
saveTorrentStatus(metainfo, bitfield, null, false, baseFile, true, 0, 0, true); // no file priorities
|
||||
}
|
||||
// so addTorrent won't recheck
|
||||
if (filename == null) {
|
||||
File f = new File(getDataDir(), Storage.filterName(metainfo.getName()) + ".torrent");
|
||||
File f = new File(getDataDir(), filtered + ".torrent");
|
||||
if (f.exists()) {
|
||||
addMessage(_t("Failed to copy torrent file to {0}", f.getAbsolutePath()));
|
||||
_log.error("Torrent file already exists: " + f);
|
||||
@@ -1793,14 +1903,13 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
try {
|
||||
locked_writeMetaInfo(metainfo, filename, areFilesPublic());
|
||||
// hold the lock for a long time
|
||||
addTorrent(filename, baseFile, dontAutoStart);
|
||||
return addTorrent(filename, baseFile, dontAutoStart);
|
||||
} catch (IOException ioe) {
|
||||
addMessage(_t("Failed to copy torrent file to {0}", filename));
|
||||
_log.error("Failed to write torrent file", ioe);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1814,21 +1923,22 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
* Must be a filesystem-safe name.
|
||||
* @param dataDir must exist, or null to default to snark data directory
|
||||
* @throws RuntimeException via Snark.fatal()
|
||||
* @return success
|
||||
* @since 0.8.4
|
||||
*/
|
||||
public void copyAndAddTorrent(File fromfile, String filename, File dataDir) throws IOException {
|
||||
public boolean copyAndAddTorrent(File fromfile, String filename, File dataDir) throws IOException {
|
||||
// prevent interference by DirMonitor
|
||||
synchronized (_snarks) {
|
||||
boolean success = FileUtil.copy(fromfile.getAbsolutePath(), filename, false);
|
||||
if (!success) {
|
||||
addMessage(_t("Failed to copy torrent file to {0}", filename));
|
||||
_log.error("Failed to write torrent file to " + filename);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!areFilesPublic())
|
||||
SecureFileOutputStream.setPerms(new File(filename));
|
||||
// hold the lock for a long time
|
||||
addTorrent(filename, null, false, dataDir);
|
||||
return addTorrent(filename, null, false, dataDir);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2041,7 +2151,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
return;
|
||||
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(), storage.getInOrder(),
|
||||
storage.getBase(), storage.getPreserveFileNames(),
|
||||
snark.getUploaded(), snark.isStopped(), comments);
|
||||
snark.getUploaded(), storage.getActivity(), snark.isStopped(), comments);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2057,8 +2167,8 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
* @param base may be null
|
||||
*/
|
||||
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities, boolean inOrder,
|
||||
File base, boolean preserveNames, long uploaded, boolean stopped) {
|
||||
saveTorrentStatus(metainfo, bitfield, priorities, inOrder, base, preserveNames, uploaded, stopped, null);
|
||||
File base, boolean preserveNames, long uploaded, long activity, boolean stopped) {
|
||||
saveTorrentStatus(metainfo, bitfield, priorities, inOrder, base, preserveNames, uploaded, activity, stopped, null);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2066,15 +2176,15 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
* @since 0.9.31
|
||||
*/
|
||||
private void saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities, boolean inOrder,
|
||||
File base, boolean preserveNames, long uploaded, boolean stopped,
|
||||
File base, boolean preserveNames, long uploaded, long activity, boolean stopped,
|
||||
Boolean comments) {
|
||||
synchronized (_configLock) {
|
||||
locked_saveTorrentStatus(metainfo, bitfield, priorities, inOrder, base, preserveNames, uploaded, stopped, comments);
|
||||
locked_saveTorrentStatus(metainfo, bitfield, priorities, inOrder, base, preserveNames, uploaded, activity, stopped, comments);
|
||||
}
|
||||
}
|
||||
|
||||
private void locked_saveTorrentStatus(MetaInfo metainfo, BitField bitfield, int[] priorities, boolean inOrder,
|
||||
File base, boolean preserveNames, long uploaded, boolean stopped,
|
||||
File base, boolean preserveNames, long uploaded, long activity, boolean stopped,
|
||||
Boolean comments) {
|
||||
byte[] ih = metainfo.getInfoHash();
|
||||
Properties config = getConfig(ih);
|
||||
@@ -2104,6 +2214,8 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
config.setProperty(PROP_META_BASE, base.getAbsolutePath());
|
||||
if (comments != null)
|
||||
config.setProperty(PROP_META_COMMENTS, comments.toString());
|
||||
if (activity > 0)
|
||||
config.setProperty(PROP_META_ACTIVITY, Long.toString(activity));
|
||||
|
||||
// now the file priorities
|
||||
if (priorities != null) {
|
||||
@@ -2147,13 +2259,17 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
*/
|
||||
private void locked_saveTorrentStatus(byte[] ih, Properties config) {
|
||||
File conf = configFile(_configDir, ih);
|
||||
if (shouldAutoStart() && !conf.exists()) {
|
||||
// force on for new torrents
|
||||
config.setProperty(PROP_META_RUNNING, "true");
|
||||
}
|
||||
File subdir = conf.getParentFile();
|
||||
if (!subdir.exists())
|
||||
subdir.mkdirs();
|
||||
try {
|
||||
DataHelper.storeProps(config, conf);
|
||||
if (_log.shouldInfo())
|
||||
_log.info("Saved config to " + conf);
|
||||
_log.info("Saved config to " + conf /* , new Exception() */ );
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Unable to save the config to " + conf);
|
||||
}
|
||||
@@ -2306,12 +2422,13 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
} else if (info.getTotalLength() <= 0) {
|
||||
return _t("Torrent \"{0}\" has no data!", info.getName());
|
||||
} else if (info.getTotalLength() > Storage.MAX_TOTAL_SIZE) {
|
||||
/*
|
||||
System.out.println("torrent info: " + info.toString());
|
||||
List<Long> lengths = info.getLengths();
|
||||
if (lengths != null)
|
||||
for (int i = 0; i < lengths.size(); i++)
|
||||
System.out.println("File " + i + " is " + lengths.get(i) + " long.");
|
||||
|
||||
*/
|
||||
return _t("Torrents larger than {0}B are not supported yet \"{1}\"!", Storage.MAX_TOTAL_SIZE, info.getName());
|
||||
} else {
|
||||
// ok
|
||||
@@ -2329,14 +2446,14 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
filename = sfile.getCanonicalPath();
|
||||
} catch (IOException ioe) {
|
||||
_log.error("Unable to remove the torrent " + filename, ioe);
|
||||
addMessage(_t("Error: Could not remove the torrent {0}", filename) + ": " + ioe.getMessage());
|
||||
addMessage(_t("Error: Could not remove the torrent {0}", filename) + ": " + ioe.getLocalizedMessage());
|
||||
return null;
|
||||
}
|
||||
int remaining = 0;
|
||||
Snark torrent = null;
|
||||
synchronized (_snarks) {
|
||||
if (shouldRemove)
|
||||
torrent = _snarks.remove(filename);
|
||||
torrent = removeSnark(filename);
|
||||
else
|
||||
torrent = _snarks.get(filename);
|
||||
remaining = _snarks.size();
|
||||
@@ -2365,7 +2482,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
public void stopTorrent(Snark torrent, boolean shouldRemove) {
|
||||
if (shouldRemove) {
|
||||
synchronized (_snarks) {
|
||||
_snarks.remove(torrent.getName());
|
||||
removeSnark(torrent);
|
||||
}
|
||||
}
|
||||
boolean wasStopped = torrent.isStopped();
|
||||
@@ -2469,7 +2586,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
Storage storage = snark.getStorage();
|
||||
if (meta != null && storage != null)
|
||||
saveTorrentStatus(meta, storage.getBitField(), storage.getFilePriorities(), storage.getInOrder(),
|
||||
storage.getBase(), storage.getPreserveFileNames(), snark.getUploaded(),
|
||||
storage.getBase(), storage.getPreserveFileNames(), snark.getUploaded(), storage.getActivity(),
|
||||
snark.isStopped());
|
||||
}
|
||||
|
||||
@@ -2493,7 +2610,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
return null;
|
||||
}
|
||||
saveTorrentStatus(meta, storage.getBitField(), null, false,
|
||||
storage.getBase(), storage.getPreserveFileNames(), 0,
|
||||
storage.getBase(), storage.getPreserveFileNames(), 0, 0,
|
||||
snark.isStopped());
|
||||
// temp for addMessage() in case canonical throws
|
||||
String name = storage.getBaseName();
|
||||
@@ -2507,8 +2624,8 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
synchronized (_snarks) {
|
||||
locked_writeMetaInfo(meta, name, areFilesPublic());
|
||||
// put it in the list under the new name
|
||||
_snarks.remove(snark.getName());
|
||||
_snarks.put(name, snark);
|
||||
removeSnark(snark);
|
||||
putSnark(name, snark);
|
||||
}
|
||||
_magnets.remove(snark.getName());
|
||||
removeMagnetStatus(snark.getInfoHash());
|
||||
@@ -2619,25 +2736,40 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
_log.error("Error resolving '" + files[i] + "' in '" + dir, ioe);
|
||||
}
|
||||
}
|
||||
// sort so the initial startup goes in natural order, more or less
|
||||
Collections.sort(foundNames, Collator.getInstance());
|
||||
}
|
||||
|
||||
Set<String> existingNames = listTorrentFiles();
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug("DirMon found: " + DataHelper.toString(foundNames) + " existing: " + DataHelper.toString(existingNames));
|
||||
//if (_log.shouldLog(Log.DEBUG))
|
||||
// _log.debug("DirMon found: " + DataHelper.toString(foundNames) + " existing: " + DataHelper.toString(existingNames));
|
||||
// lets find new ones first...
|
||||
boolean shouldStart = shouldAutoStart();
|
||||
for (String name : foundNames) {
|
||||
if (existingNames.contains(name)) {
|
||||
// already known. noop
|
||||
} else {
|
||||
if (shouldAutoStart() && !_util.connect())
|
||||
addMessage(_t("Unable to connect to I2P!"));
|
||||
// Will call connect() in addTorrent() if enabled
|
||||
//if (shouldStart && !_util.connect())
|
||||
// addMessage(_t("Unable to connect to I2P!"));
|
||||
try {
|
||||
// Snark.fatal() throws a RuntimeException
|
||||
// don't let one bad torrent kill the whole loop
|
||||
addTorrent(name, null, !shouldAutoStart());
|
||||
boolean ok = addTorrent(name, null, !shouldStart);
|
||||
if (!ok) {
|
||||
addMessage(_t("Error: Could not add the torrent {0}", name));
|
||||
_log.error("Unable to add the torrent " + name);
|
||||
disableTorrentFile(name);
|
||||
rv = false;
|
||||
}
|
||||
} catch (Snark.RouterException e) {
|
||||
addMessage(_t("Error: Could not add the torrent {0}", name) + ": " + e);
|
||||
_log.error("Unable to add the torrent " + name, e);
|
||||
return false;
|
||||
} catch (RuntimeException e) {
|
||||
addMessage(_t("Error: Could not add the torrent {0}", name) + ": " + e);
|
||||
_log.error("Unable to add the torrent " + name, e);
|
||||
disableTorrentFile(name);
|
||||
rv = false;
|
||||
}
|
||||
}
|
||||
@@ -2793,7 +2925,7 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
*/
|
||||
public void startTorrent(Snark snark) {
|
||||
if (snark.isStarting() || !snark.isStopped()) {
|
||||
addMessage("Torrent already started");
|
||||
addMessageNoEscape(_t("Torrent already running: {0}", linkify(snark)));
|
||||
return;
|
||||
}
|
||||
boolean connected = _util.connected();
|
||||
@@ -2990,14 +3122,15 @@ public class SnarkManager implements CompleteListener, ClientApp {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ignore case, current locale
|
||||
* @since 0.9
|
||||
*/
|
||||
private static class IgnoreCaseComparator implements Comparator<Tracker>, Serializable {
|
||||
private final Collator coll = Collator.getInstance();
|
||||
public int compare(Tracker l, Tracker r) {
|
||||
return l.name.toLowerCase().compareTo(r.name.toLowerCase());
|
||||
return coll.compare(l.name, r.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,14 @@ import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import gnu.getopt.Getopt;
|
||||
|
||||
@@ -78,11 +80,12 @@ public class Storage implements Closeable
|
||||
private boolean _inOrder;
|
||||
private final AtomicInteger _allocateCount = new AtomicInteger();
|
||||
private final AtomicInteger _checkProgress = new AtomicInteger();
|
||||
private final AtomicLong _activity = new AtomicLong();
|
||||
|
||||
/** The default piece size. */
|
||||
private static final int DEFAULT_PIECE_SIZE = 256*1024;
|
||||
/** bigger than this will be rejected */
|
||||
public static final int MAX_PIECE_SIZE = 16*1024*1024;
|
||||
public static final int MAX_PIECE_SIZE = 32*1024*1024;
|
||||
/** The maximum number of pieces in a torrent. */
|
||||
public static final int MAX_PIECES = 32*1024;
|
||||
public static final long MAX_TOTAL_SIZE = MAX_PIECE_SIZE * (long) MAX_PIECES;
|
||||
@@ -141,6 +144,30 @@ public class Storage implements Closeable
|
||||
String created_by,
|
||||
boolean privateTorrent, StorageListener listener)
|
||||
throws IOException
|
||||
{
|
||||
this(util, baseFile, announce, announce_list, created_by, privateTorrent, null, null, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a storage from the existing file or directory.
|
||||
* Creates an in-memory metainfo but does not save it to
|
||||
* a file, caller must do that.
|
||||
*
|
||||
* Creates the metainfo, this may take a LONG time. BLOCKING.
|
||||
*
|
||||
* @param announce may be null
|
||||
* @param listener may be null
|
||||
* @param created_by may be null
|
||||
* @param url_list may be null
|
||||
* @param comment may be null
|
||||
* @throws IOException when creating and/or checking files fails.
|
||||
* @since 0.9.48
|
||||
*/
|
||||
public Storage(I2PSnarkUtil util, File baseFile, String announce,
|
||||
List<List<String>> announce_list,
|
||||
String created_by,
|
||||
boolean privateTorrent, List<String> url_list, String comment, StorageListener listener)
|
||||
throws IOException
|
||||
{
|
||||
_util = util;
|
||||
_base = baseFile;
|
||||
@@ -207,7 +234,7 @@ public class Storage implements Closeable
|
||||
byte[] piece_hashes = fast_digestCreate();
|
||||
metainfo = new MetaInfo(announce, baseFile.getName(), null, files,
|
||||
lengthsList, piece_size, piece_hashes, total, privateTorrent,
|
||||
announce_list, created_by);
|
||||
announce_list, created_by, url_list, comment);
|
||||
|
||||
}
|
||||
|
||||
@@ -319,6 +346,28 @@ public class Storage implements Closeable
|
||||
changed = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public long getActivity() {
|
||||
return _activity.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.42
|
||||
*/
|
||||
private void setActivity() {
|
||||
setActivity(I2PAppContext.getGlobalContext().clock().now());
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.42
|
||||
*/
|
||||
public void setActivity(long time) {
|
||||
_activity.set(time);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* File checking in progress.
|
||||
* @since 0.9.3
|
||||
@@ -408,9 +457,22 @@ public class Storage implements Closeable
|
||||
* @since 0.9.23
|
||||
*/
|
||||
public long[] remaining() {
|
||||
return remaining2()[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* For efficiency, calculate remaining bytes for all files at once.
|
||||
* Remaining bytes is rv[0]. Preview bytes is rv[1].
|
||||
*
|
||||
* @return number of bytes remaining and number of bytes available for a preview for each file, use indexOf() to get index for a file
|
||||
* @since 0.9.45
|
||||
*/
|
||||
public long[][] remaining2() {
|
||||
long[] rv = new long[_torrentFiles.size()];
|
||||
long[] pv = new long[_torrentFiles.size()];
|
||||
long[][] rva = new long[][] { rv, pv };
|
||||
if (complete())
|
||||
return rv;
|
||||
return rva;
|
||||
long bytes = 0;
|
||||
for (int i = 0; i < _torrentFiles.size(); i++) {
|
||||
TorrentFile tf = _torrentFiles.get(i);
|
||||
@@ -418,10 +480,23 @@ public class Storage implements Closeable
|
||||
long end = start + tf.length;
|
||||
int pc = (int) (bytes / piece_size);
|
||||
long rvi = 0;
|
||||
if (!bitfield.get(pc))
|
||||
rvi = Math.min(piece_size - (start % piece_size), tf.length);
|
||||
long pvi = 0;
|
||||
long first = Math.min(piece_size - (start % piece_size), tf.length);
|
||||
if (bitfield.get(pc))
|
||||
pvi = first;
|
||||
else
|
||||
rvi = first;
|
||||
boolean preview = true;
|
||||
for (int j = pc + 1; (((long)j) * piece_size) < end && j < pieces; j++) {
|
||||
if (!bitfield.get(j)) {
|
||||
if (bitfield.get(j)) {
|
||||
if (preview) {
|
||||
if (((long)(j+1))*piece_size < end)
|
||||
pvi += piece_size;
|
||||
else
|
||||
pvi += end - (((long)j) * piece_size);
|
||||
}
|
||||
} else {
|
||||
preview = false;
|
||||
if (((long)(j+1))*piece_size < end)
|
||||
rvi += piece_size;
|
||||
else
|
||||
@@ -429,9 +504,10 @@ public class Storage implements Closeable
|
||||
}
|
||||
}
|
||||
rv[i] = rvi;
|
||||
pv[i] = pvi;
|
||||
bytes += tf.length;
|
||||
}
|
||||
return rv;
|
||||
return rva;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -827,6 +903,13 @@ public class Storage implements Closeable
|
||||
0x2028, 0x2029
|
||||
};
|
||||
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file
|
||||
private static final String[] WIN_ILLEGAL = new String[] {
|
||||
"con", "prn", "aux", "nul",
|
||||
"com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
|
||||
"lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9"
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter the name, but only if configured to do so.
|
||||
* We will do so on torrents received from others, but not
|
||||
@@ -859,8 +942,18 @@ public class Storage implements Closeable
|
||||
rv = "_";
|
||||
} else {
|
||||
rv = name;
|
||||
if (rv.startsWith("."))
|
||||
if (rv.startsWith(".")) {
|
||||
rv = '_' + rv.substring(1);
|
||||
} else if (SystemVersion.isWindows()) {
|
||||
// https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file
|
||||
String iname = name.toLowerCase(Locale.US);
|
||||
for (int i = 0; i < WIN_ILLEGAL.length; i++) {
|
||||
String w = WIN_ILLEGAL[i];
|
||||
if (iname.equals(w) ||
|
||||
(iname.startsWith(w + '.') && w.indexOf('.', w.length() + 1) < 0))
|
||||
rv = '_' + rv;
|
||||
}
|
||||
}
|
||||
if (rv.endsWith(".") || rv.endsWith(" "))
|
||||
rv = rv.substring(0, rv.length() - 1) + '_';
|
||||
for (int i = 0; i < ILLEGAL.length; i++) {
|
||||
@@ -1227,6 +1320,7 @@ public class Storage implements Closeable
|
||||
}
|
||||
bs = rv.getData();
|
||||
getUncheckedPiece(piece, bs, off, len);
|
||||
setActivity();
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -1294,6 +1388,7 @@ public class Storage implements Closeable
|
||||
//rafs[i].write(bs, off + written, len);
|
||||
pp.write(raf, written, len);
|
||||
} catch (IOException ioe) {
|
||||
try { tf.closeRAF(); } catch (IOException ioe2) {}
|
||||
// get the file name in the logs
|
||||
IOException ioe2 = new IOException("Error writing " + tf.RAFfile.getAbsolutePath());
|
||||
ioe2.initCause(ioe);
|
||||
@@ -1311,7 +1406,7 @@ public class Storage implements Closeable
|
||||
pp.release();
|
||||
}
|
||||
|
||||
changed = true;
|
||||
setActivity();
|
||||
|
||||
// do this after the write, so we know it succeeded, and we don't set the
|
||||
// needed count to zero, which would cause checkRAF() to open the file readonly.
|
||||
@@ -1400,6 +1495,7 @@ public class Storage implements Closeable
|
||||
raf.seek(start);
|
||||
raf.readFully(bs, read, len);
|
||||
} catch (IOException ioe) {
|
||||
try { tf.closeRAF(); } catch (IOException ioe2) {}
|
||||
// get the file name in the logs
|
||||
IOException ioe2 = new IOException("Error reading " + tf.RAFfile.getAbsolutePath());
|
||||
ioe2.initCause(ioe);
|
||||
@@ -1567,8 +1663,7 @@ public class Storage implements Closeable
|
||||
* Caller must synchronize and call checkRAF() or openRAF().
|
||||
* @since 0.9.1
|
||||
*/
|
||||
public synchronized void balloonFile() throws IOException
|
||||
{
|
||||
private synchronized void balloonFile() throws IOException {
|
||||
long remaining = length;
|
||||
final int ZEROBLOCKSIZE = (int) Math.min(remaining, 32*1024);
|
||||
byte[] zeros = new byte[ZEROBLOCKSIZE];
|
||||
@@ -1616,7 +1711,9 @@ public class Storage implements Closeable
|
||||
boolean error = false;
|
||||
String created_by = null;
|
||||
String announce = null;
|
||||
Getopt g = new Getopt("Storage", args, "a:c:");
|
||||
List<String> url_list = null;
|
||||
String comment = null;
|
||||
Getopt g = new Getopt("Storage", args, "a:c:m:w:");
|
||||
try {
|
||||
int c;
|
||||
while ((c = g.getopt()) != -1) {
|
||||
@@ -1629,6 +1726,16 @@ public class Storage implements Closeable
|
||||
created_by = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
comment = g.getOptarg();
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (url_list == null)
|
||||
url_list = new ArrayList<String>();
|
||||
url_list.add(g.getOptarg());
|
||||
break;
|
||||
|
||||
case '?':
|
||||
case ':':
|
||||
default:
|
||||
@@ -1641,7 +1748,7 @@ public class Storage implements Closeable
|
||||
error = true;
|
||||
}
|
||||
if (error || args.length - g.getOptind() != 1) {
|
||||
System.err.println("Usage: Storage [-a announceURL] [-c created-by] file-or-dir");
|
||||
System.err.println("Usage: Storage [-a announceURL] [-c created-by] [-m comment] [-w webseed-url]* file-or-dir");
|
||||
System.exit(1);
|
||||
}
|
||||
File base = new File(args[g.getOptind()]);
|
||||
@@ -1650,7 +1757,7 @@ public class Storage implements Closeable
|
||||
File file = null;
|
||||
FileOutputStream out = null;
|
||||
try {
|
||||
Storage storage = new Storage(util, base, announce, null, created_by, false, null);
|
||||
Storage storage = new Storage(util, base, announce, null, created_by, false, url_list, comment, null);
|
||||
MetaInfo meta = storage.getMetaInfo();
|
||||
file = new File(storage.getBaseName() + ".torrent");
|
||||
out = new FileOutputStream(file);
|
||||
|
||||
@@ -134,8 +134,8 @@ public class TrackerClient implements Runnable {
|
||||
{
|
||||
super();
|
||||
// Set unique name.
|
||||
String id = urlencode(snark.getID());
|
||||
_threadName = "TrackerClient " + id.substring(id.length() - 12);
|
||||
byte[] hash = snark.getInfoHash();
|
||||
_threadName = "TrackerClient " + I2PSnarkUtil.toHex(hash);
|
||||
_util = util;
|
||||
_log = util.getContext().logManager().getLog(TrackerClient.class);
|
||||
this.meta = meta;
|
||||
@@ -144,7 +144,7 @@ public class TrackerClient implements Runnable {
|
||||
this.snark = snark;
|
||||
|
||||
this.port = PORT; //(port == -1) ? 9 : port;
|
||||
this.infoHash = urlencode(snark.getInfoHash());
|
||||
this.infoHash = urlencode(hash);
|
||||
this.peerID = urlencode(snark.getID());
|
||||
this.trackers = new ArrayList<TCTracker>(2);
|
||||
this.backupTrackers = new ArrayList<TCTracker>(2);
|
||||
@@ -292,7 +292,7 @@ public class TrackerClient implements Runnable {
|
||||
_log.debug("Announce: [" + primary + "] infoHash: " + infoHash);
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Skipping invalid or non-i2p announce: " + primary);
|
||||
_log.warn("Skipping invalid or non-i2p announce: " + primary + " for torrent " + snark.getBaseName());
|
||||
}
|
||||
} else {
|
||||
_log.warn("No primary announce");
|
||||
@@ -366,7 +366,7 @@ public class TrackerClient implements Runnable {
|
||||
Hash h = getHostHash(ann);
|
||||
if (h == null) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Bad announce URL: [" + ann + ']');
|
||||
_log.warn("Bad announce URL: [" + ann + "] for torrent " + snark.getBaseName());
|
||||
return false;
|
||||
}
|
||||
// comment this out if tracker.welterde.i2p upgrades
|
||||
@@ -374,19 +374,19 @@ public class TrackerClient implements Runnable {
|
||||
Destination dest = _util.getMyDestination();
|
||||
if (dest != null && dest.getSigType() != SigType.DSA_SHA1) {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Skipping incompatible tracker: " + ann);
|
||||
_log.warn("Skipping incompatible tracker: " + ann + " for torrent " + snark.getBaseName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (existing.size() >= MAX_TRACKERS) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Not using announce URL, we have enough: [" + ann + ']');
|
||||
_log.info("Not using announce URL, we have enough: [" + ann + "] for torrent " + snark.getBaseName());
|
||||
return false;
|
||||
}
|
||||
boolean rv = existing.add(h);
|
||||
if (!rv) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Dup announce URL: [" + ann + ']');
|
||||
_log.info("Dup announce URL: [" + ann + "] for torrent " + snark.getBaseName());
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -407,6 +407,8 @@ public class TrackerClient implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
int webPeers = getWebPeers();
|
||||
|
||||
// Local DHT tracker announce
|
||||
DHT dht = _util.getDHT();
|
||||
if (dht != null && (meta == null || !meta.isPrivate()))
|
||||
@@ -438,7 +440,7 @@ public class TrackerClient implements Runnable {
|
||||
}
|
||||
|
||||
// we could try and total the unique peers but that's too hard for now
|
||||
snark.setTrackerSeenPeers(maxSeenPeers);
|
||||
snark.setTrackerSeenPeers(maxSeenPeers + webPeers);
|
||||
|
||||
if (stop)
|
||||
return;
|
||||
@@ -605,7 +607,7 @@ public class TrackerClient implements Runnable {
|
||||
tplc.startsWith(ERROR_GOT_HTML) || // fake msg from doRequest()
|
||||
(!tr.isPrimary && tr.registerFails > MAX_REGISTER_FAILS / 2))
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Not longer announcing to " + tr.announce + " : " +
|
||||
_log.warn("No longer announcing to " + tr.announce + " : " +
|
||||
tr.trackerProblems + " after " + tr.registerFails + " failures");
|
||||
tr.stop = true;
|
||||
//
|
||||
@@ -720,6 +722,62 @@ public class TrackerClient implements Runnable {
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return valid web peers from metainfo
|
||||
* @since 0.9.49
|
||||
*/
|
||||
private int getWebPeers() {
|
||||
if (meta == null)
|
||||
return 0;
|
||||
// prevent connecting out to a webseed for comments only
|
||||
if (coordinator.getNeededLength() <= 0)
|
||||
return 0;
|
||||
List<String> urls = meta.getWebSeedURLs();
|
||||
if (urls == null || urls.isEmpty())
|
||||
return 0;
|
||||
// Uncomment to skip multifile torrents
|
||||
//if (meta.getLengths() != null)
|
||||
// return 0;
|
||||
List<Peer> peers = new ArrayList<Peer>(urls.size());
|
||||
for (String url : urls) {
|
||||
Hash h = getHostHash(url);
|
||||
if (h == null)
|
||||
continue;
|
||||
try {
|
||||
PeerID pID = new PeerID(h.getData(), _util);
|
||||
byte[] id = new byte[20];
|
||||
System.arraycopy(WebPeer.IDBytes, 0, id, 0, 12);
|
||||
System.arraycopy(h.getData(), 0, id, 12, 8);
|
||||
pID.setID(id);
|
||||
URI uri = new URI(url);
|
||||
String host = uri.getHost();
|
||||
if (host == null)
|
||||
continue;
|
||||
if (coordinator.isWebPeerBanned(host)) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Skipping banned webseed " + url);
|
||||
continue;
|
||||
}
|
||||
peers.add(new WebPeer(coordinator, uri, pID, snark.getMetaInfo()));
|
||||
} catch (InvalidBEncodingException ibe) {
|
||||
} catch (URISyntaxException use) {
|
||||
}
|
||||
}
|
||||
if (peers.isEmpty())
|
||||
return 0;
|
||||
Random r = _util.getContext().random();
|
||||
if (peers.size() > 1)
|
||||
Collections.shuffle(peers, r);
|
||||
Iterator<Peer> it = peers.iterator();
|
||||
while ((!stop) && it.hasNext() && coordinator.needOutboundPeers()) {
|
||||
Peer cur = it.next();
|
||||
if (coordinator.addPeer(cur) && it.hasNext()) {
|
||||
int delay = r.nextInt(DELAY_RAND) + DELAY_MIN;
|
||||
try { Thread.sleep(delay); } catch (InterruptedException ie) {}
|
||||
}
|
||||
}
|
||||
return peers.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a thread for each tracker in parallel if tunnel is still open
|
||||
@@ -917,8 +975,21 @@ public class TrackerClient implements Runnable {
|
||||
if (!"http".equals(url.getScheme()))
|
||||
return null;
|
||||
String host = url.getHost();
|
||||
if (host == null)
|
||||
if (host == null) {
|
||||
// URI can't handle b64dest or b64dest.i2p if it contains '~'
|
||||
// but it doesn't throw an exception, just returns a null host
|
||||
if (ann.startsWith("http://") && ann.length() >= 7 + 516 && ann.contains("~")) {
|
||||
ann = ann.substring(7);
|
||||
int slash = ann.indexOf('/');
|
||||
if (slash >= 516) {
|
||||
ann = ann.substring(0, slash);
|
||||
if (ann.endsWith(".i2p"))
|
||||
ann = ann.substring(0, ann.length() - 4);
|
||||
return ConvertToHash.getHash(ann);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (host.endsWith(".i2p")) {
|
||||
String path = url.getPath();
|
||||
if (path == null || !path.startsWith("/"))
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.klomp.snark.web;
|
||||
package org.klomp.snark;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
@@ -35,9 +35,9 @@ import net.i2p.data.DataHelper;
|
||||
* see UrlEncoded
|
||||
*
|
||||
* I2P modded from Jetty 8.1.15
|
||||
* @since 0.9.15
|
||||
* @since 0.9.15, moved from web in 0.9.49
|
||||
*/
|
||||
class URIUtil
|
||||
public class URIUtil
|
||||
{
|
||||
|
||||
/** Encode a URI path.
|
||||
@@ -87,6 +87,9 @@ class URIUtil
|
||||
case ':':
|
||||
case '[':
|
||||
case ']':
|
||||
case '&':
|
||||
case '|':
|
||||
case '\\':
|
||||
buf=new StringBuilder(path.length()*2);
|
||||
break loop;
|
||||
default:
|
||||
@@ -151,6 +154,17 @@ class URIUtil
|
||||
case ']':
|
||||
buf.append("%5D");
|
||||
continue;
|
||||
// not strictly required but this is probably HTML output
|
||||
case '&':
|
||||
buf.append("%26");
|
||||
continue;
|
||||
case '|':
|
||||
buf.append("%7C");
|
||||
continue;
|
||||
// browsers convert this to /
|
||||
case '\\':
|
||||
buf.append("%5C");
|
||||
continue;
|
||||
default:
|
||||
if (c <= 0x1f) // includes negative
|
||||
toHex(c,buf);
|
||||
@@ -204,6 +218,15 @@ class URIUtil
|
||||
case ']':
|
||||
buf.append("%5D");
|
||||
continue;
|
||||
case '&':
|
||||
buf.append("%26");
|
||||
continue;
|
||||
case '|':
|
||||
buf.append("%7C");
|
||||
continue;
|
||||
case '\\':
|
||||
buf.append("%5C");
|
||||
continue;
|
||||
default:
|
||||
if (c <= 0x1f || (c >= 0x7f && c <= 0x9f) || Character.isSpaceChar(c))
|
||||
toHex(c,buf);
|
||||
@@ -33,9 +33,9 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
private URI _currentURI;
|
||||
private Snark _snark;
|
||||
|
||||
private static final long MAX_LENGTH = 30*1024*1024;
|
||||
private static final long METAINFO_TIMEOUT = 30*60*1000;
|
||||
private static final long COMPLETE_TIMEOUT = 3*60*60*1000;
|
||||
private static final long MAX_LENGTH = 128*1024*1024;
|
||||
private static final long METAINFO_TIMEOUT = 60*60*1000;
|
||||
private static final long COMPLETE_TIMEOUT = 12*60*60*1000;
|
||||
private static final long CHECK_INTERVAL = 3*60*1000;
|
||||
|
||||
public UpdateRunner(I2PAppContext ctx, UpdateManager umgr, SnarkManager smgr,
|
||||
@@ -314,6 +314,11 @@ class UpdateRunner implements UpdateTask, CompleteListener {
|
||||
_smgr.locked_saveComments(snark, comments);
|
||||
}
|
||||
|
||||
/** @since 0.9.42 */
|
||||
public boolean shouldAutoStart() {
|
||||
return _smgr.shouldAutoStart();
|
||||
}
|
||||
|
||||
//////// end CompleteListener methods
|
||||
|
||||
private static String linkify(String url) {
|
||||
|
||||
667
apps/i2psnark/java/src/org/klomp/snark/WebPeer.java
Normal file
667
apps/i2psnark/java/src/org/klomp/snark/WebPeer.java
Normal file
@@ -0,0 +1,667 @@
|
||||
package org.klomp.snark;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.client.streaming.I2PSocket;
|
||||
import net.i2p.client.streaming.I2PSocketEepGet;
|
||||
import net.i2p.client.streaming.I2PSocketManager;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.data.Destination;
|
||||
import net.i2p.util.EepGet;
|
||||
import net.i2p.util.Log;
|
||||
|
||||
/**
|
||||
* BEP 19.
|
||||
* Does not have an associated PeerState.
|
||||
* All request tracking is done here.
|
||||
* @since 0.9.49
|
||||
*/
|
||||
class WebPeer extends Peer implements EepGet.StatusListener {
|
||||
|
||||
private final PeerCoordinator _coordinator;
|
||||
private final URI _uri;
|
||||
// as received from coordinator
|
||||
private final List<Request> outstandingRequests = new ArrayList<Request>();
|
||||
private final boolean isMultiFile;
|
||||
// needed?
|
||||
private Request lastRequest;
|
||||
private PeerListener listener;
|
||||
private BitField bitfield;
|
||||
private Thread thread;
|
||||
private boolean connected;
|
||||
private long lastRcvd;
|
||||
private int maxRequests;
|
||||
|
||||
// to be recognized by the UI
|
||||
public static final byte[] IDBytes = DataHelper.getASCII("WebSeedBEP19");
|
||||
private static final long HEADER_TIMEOUT = 60*1000;
|
||||
private static final long TOTAL_TIMEOUT = 10*60*1000;
|
||||
private static final long INACTIVITY_TIMEOUT = 2*60*1000;
|
||||
private static final long TARGET_FETCH_TIME = 2*60*1000;
|
||||
// 128 KB
|
||||
private static final int ABSOLUTE_MIN_REQUESTS = 8;
|
||||
// 2 MB
|
||||
private static final int ABSOLUTE_MAX_REQUESTS = 128;
|
||||
private final int MIN_REQUESTS;
|
||||
private final int MAX_REQUESTS;
|
||||
|
||||
/**
|
||||
* Outgoing connection.
|
||||
* Creates a disconnected peer given a PeerID, your own id and the
|
||||
* relevant MetaInfo.
|
||||
* @param uri must be http with .i2p host
|
||||
* @param metainfo non-null
|
||||
*/
|
||||
public WebPeer(PeerCoordinator coord, URI uri, PeerID peerID, MetaInfo metainfo) {
|
||||
super(peerID, null, null, metainfo);
|
||||
// no use asking for more than the number of chunks in a piece
|
||||
MAX_REQUESTS = Math.max(1, Math.min(ABSOLUTE_MAX_REQUESTS, metainfo.getPieceLength(0) / PeerState.PARTSIZE));
|
||||
MIN_REQUESTS = Math.min(ABSOLUTE_MIN_REQUESTS, MAX_REQUESTS);
|
||||
maxRequests = MIN_REQUESTS;
|
||||
isMultiFile = metainfo.getLengths() != null;
|
||||
_coordinator = coord;
|
||||
// We'll assume the base path is already encoded, because
|
||||
// it would have failed the checks in TrackerClient.getHostHash()
|
||||
_uri = uri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WebSeed " + _uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return socket debug string (for debug printing)
|
||||
*/
|
||||
@Override
|
||||
public synchronized String getSocket() {
|
||||
return toString() + ' ' + outstandingRequests.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The hash code of a Peer is the hash code of the peerID.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Two Peers are equal when they have the same PeerID.
|
||||
* All other properties are ignored.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof WebPeer) {
|
||||
WebPeer p = (WebPeer)o;
|
||||
// TODO
|
||||
return getPeerID().equals(p.getPeerID());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the connection to the other peer. This method does not
|
||||
* return until the connection is terminated.
|
||||
*
|
||||
* @param ignore our bitfield, ignore
|
||||
* @param uploadOnly if we are complete with skipped files, i.e. a partial seed
|
||||
*/
|
||||
@Override
|
||||
public void runConnection(I2PSnarkUtil util, PeerListener listener, BitField ignore,
|
||||
MagnetState mState, boolean uploadOnly) {
|
||||
if (uploadOnly)
|
||||
return;
|
||||
int fails = 0;
|
||||
int successes = 0;
|
||||
long dl = 0;
|
||||
boolean notify = true;
|
||||
ByteArrayOutputStream out = null;
|
||||
// current requests per-loop
|
||||
List<Request> requests = new ArrayList<Request>(8);
|
||||
try {
|
||||
if (!util.connected()) {
|
||||
boolean ok = util.connect();
|
||||
if (!ok)
|
||||
return;
|
||||
}
|
||||
|
||||
// This breaks out of the loop after any failure. TrackerClient will requeue eventually.
|
||||
loop:
|
||||
while (true) {
|
||||
I2PSocketManager mgr = util.getSocketManager();
|
||||
if (mgr == null)
|
||||
return;
|
||||
if (notify) {
|
||||
synchronized(this) {
|
||||
this.listener = listener;
|
||||
bitfield = new BitField(metainfo.getPieces());
|
||||
bitfield.setAll();
|
||||
thread = Thread.currentThread();
|
||||
connected = true;
|
||||
}
|
||||
listener.connected(this);
|
||||
boolean want = listener.gotBitField(this, bitfield);
|
||||
if (!want)
|
||||
return;
|
||||
listener.gotChoke(this, false);
|
||||
notify = false;
|
||||
}
|
||||
|
||||
synchronized(this) {
|
||||
// clear out previous requests
|
||||
if (!requests.isEmpty()) {
|
||||
outstandingRequests.removeAll(requests);
|
||||
requests.clear();
|
||||
}
|
||||
addRequest();
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Requests: " + outstandingRequests);
|
||||
while (outstandingRequests.isEmpty()) {
|
||||
if (_coordinator.getNeededLength() <= 0) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Complete: " + this);
|
||||
break loop;
|
||||
}
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("No requests, sleeping: " + this);
|
||||
connected = false;
|
||||
out = null;
|
||||
try {
|
||||
this.wait();
|
||||
} catch (InterruptedException ie) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Interrupted: " + this, ie);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
connected = true;
|
||||
// Add current requests from outstandingRequests list and add to requests list.
|
||||
// Do not remove from outstandingRequests until success.
|
||||
lastRequest = outstandingRequests.get(0);
|
||||
requests.add(lastRequest);
|
||||
int piece = lastRequest.getPiece();
|
||||
|
||||
// Glue together additional requests if consecutive for a single piece.
|
||||
// This will never glue together requests from different pieces,
|
||||
// and the coordinator generally won't give us consecutive pieces anyway.
|
||||
// Servers generally won't support multiple byte ranges anymore.
|
||||
for (int i = 1; i < outstandingRequests.size(); i++) {
|
||||
if (i >= maxRequests)
|
||||
break;
|
||||
Request r = outstandingRequests.get(i);
|
||||
if (r.getPiece() == piece &&
|
||||
lastRequest.off + lastRequest.len == r.off) {
|
||||
requests.add(r);
|
||||
lastRequest = r;
|
||||
} else {
|
||||
// all requests for a piece should be together, but not in practice
|
||||
// as orphaned requests can get in-between
|
||||
//break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// total values
|
||||
Request first = requests.get(0);
|
||||
Request last = requests.get(requests.size() - 1);
|
||||
int piece = first.getPiece();
|
||||
int off = first.off;
|
||||
long toff = (((long) piece) * metainfo.getPieceLength(0)) + off;
|
||||
int tlen = (last.off - first.off) + last.len;
|
||||
long start = System.currentTimeMillis();
|
||||
///// TODO direct to file, not in-memory
|
||||
if (out == null)
|
||||
out = new ByteArrayOutputStream(tlen);
|
||||
else
|
||||
out.reset();
|
||||
int filenum = -1;
|
||||
|
||||
// Loop for each file if multifile and crosses file boundaries.
|
||||
// Once only for single file.
|
||||
while (out.size() < tlen) {
|
||||
|
||||
// need these three things:
|
||||
// url to fetch
|
||||
String url;
|
||||
// offset in fetched file
|
||||
long foff;
|
||||
// length to fetch, will be adjusted if crossing a file boundary
|
||||
int flen = tlen - out.size();
|
||||
|
||||
if (isMultiFile) {
|
||||
// multifile
|
||||
List<Long> lengths = metainfo.getLengths();
|
||||
long limit = 0;
|
||||
if (filenum < 0) {
|
||||
// find the first file number and limit
|
||||
// inclusive
|
||||
long fstart = 0;
|
||||
// exclusive
|
||||
long fend = 0;
|
||||
foff = 0; // keep compiler happy, will always be re-set
|
||||
for (int f = 0; f < lengths.size(); f++) {
|
||||
long filelen = lengths.get(f).longValue();
|
||||
fend = fstart + filelen;
|
||||
if (toff < fend) {
|
||||
filenum = f;
|
||||
foff = toff - fstart;
|
||||
limit = fend - toff;
|
||||
break;
|
||||
}
|
||||
fstart += filelen;
|
||||
}
|
||||
if (filenum < 0)
|
||||
throw new IllegalStateException(lastRequest.toString());
|
||||
} else {
|
||||
// next file
|
||||
filenum++;
|
||||
foff = 0;
|
||||
limit = lengths.get(filenum).longValue();
|
||||
}
|
||||
|
||||
if (limit > 0 && flen > limit)
|
||||
flen = (int) limit;
|
||||
|
||||
if (metainfo.isPaddingFile(filenum)) {
|
||||
for (int i = 0; i < flen; i++) {
|
||||
out.write((byte) 0);
|
||||
}
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Skipped padding file " + filenum);
|
||||
continue;
|
||||
}
|
||||
|
||||
// build url
|
||||
String uri = _uri.toString();
|
||||
StringBuilder buf = new StringBuilder(uri.length() + 128);
|
||||
buf.append(uri);
|
||||
if (!uri.endsWith("/"))
|
||||
buf.append('/');
|
||||
// See BEP 19 rules
|
||||
URIUtil.encodePath(buf, metainfo.getName());
|
||||
List<String> path = metainfo.getFiles().get(filenum);
|
||||
for (int i = 0; i < path.size(); i++) {
|
||||
buf.append('/');
|
||||
URIUtil.encodePath(buf, path.get(i));
|
||||
}
|
||||
url = buf.toString();
|
||||
} else {
|
||||
// single file
|
||||
// See BEP 19 rules
|
||||
String uri = _uri.toString();
|
||||
if (uri.endsWith("/"))
|
||||
url = uri + URIUtil.encodePath(metainfo.getName());
|
||||
else
|
||||
url = uri;
|
||||
foff = toff;
|
||||
flen = tlen;
|
||||
}
|
||||
|
||||
// do the fetch
|
||||
EepGet get = new I2PSocketEepGet(util.getContext(), mgr, 0, flen, flen, null, out, url);
|
||||
get.addHeader("User-Agent", I2PSnarkUtil.EEPGET_USER_AGENT);
|
||||
get.addHeader("Range", "bytes=" + foff + '-' + (foff + flen - 1));
|
||||
get.addStatusListener(this);
|
||||
int osz = out.size();
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Fetching piece: " + piece + " offset: " + off + " file offset: " + foff + " len: " + flen + " from " + url);
|
||||
if (get.fetch(HEADER_TIMEOUT, TOTAL_TIMEOUT, INACTIVITY_TIMEOUT)) {
|
||||
int resp = get.getStatusCode();
|
||||
if (resp != 200 && resp != 206) {
|
||||
fail(url, resp);
|
||||
return;
|
||||
}
|
||||
int sz = out.size() - osz;
|
||||
if (sz != flen) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Fetch of " + url + " received: " + sz + " expected: " + flen);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (out.size() > 0) {
|
||||
// save any complete chunks received
|
||||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(out.toByteArray()));
|
||||
for (Iterator<Request> iter = requests.iterator(); iter.hasNext(); ) {
|
||||
Request req = iter.next();
|
||||
if (dis.available() < req.len)
|
||||
break;
|
||||
req.read(dis);
|
||||
iter.remove();
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Saved chunk " + req + " recvd before failure");
|
||||
}
|
||||
}
|
||||
int resp = get.getStatusCode();
|
||||
fail(url, resp);
|
||||
return;
|
||||
}
|
||||
|
||||
successes++;
|
||||
dl += flen;
|
||||
|
||||
if (!isMultiFile)
|
||||
break;
|
||||
} // for each file
|
||||
|
||||
// all data received successfully, now process it
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Fetch of piece: " + piece + " chunks: " + requests.size() + " offset: " + off + " torrent offset: " + toff + " len: " + tlen + " successful");
|
||||
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(out.toByteArray()));
|
||||
for (Request req : requests) {
|
||||
req.read(dis);
|
||||
}
|
||||
|
||||
PartialPiece pp = last.getPartialPiece();
|
||||
synchronized(pp) {
|
||||
// Last chunk needed for this piece?
|
||||
if (pp.getLength() == pp.getDownloaded()) {
|
||||
if (listener.gotPiece(this, pp)) {
|
||||
if (_log.shouldDebug())
|
||||
_log.debug("Got " + piece + ": " + this);
|
||||
} else {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Got BAD " + piece + " from " + this);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// piece not complete
|
||||
}
|
||||
}
|
||||
|
||||
long time = lastRcvd - start;
|
||||
if (time < TARGET_FETCH_TIME)
|
||||
maxRequests = Math.min(MAX_REQUESTS, 2 * maxRequests);
|
||||
else if (time > 2 * TARGET_FETCH_TIME)
|
||||
maxRequests = Math.max(MIN_REQUESTS, maxRequests / 2);
|
||||
} // request loop
|
||||
} catch(IOException eofe) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn(toString(), eofe);
|
||||
} finally {
|
||||
List<Request> pcs = returnPartialPieces();
|
||||
synchronized(this) {
|
||||
connected = false;
|
||||
outstandingRequests.clear();
|
||||
}
|
||||
requests.clear();
|
||||
if (!pcs.isEmpty())
|
||||
listener.savePartialPieces(this, pcs);
|
||||
listener.disconnected(this);
|
||||
disconnect();
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Completed, successful fetches: " + successes + " downloaded: " + dl + " for " + this);
|
||||
}
|
||||
}
|
||||
|
||||
private void fail(String url, int resp) {
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Fetch of " + url + " failed, rc: " + resp);
|
||||
if (resp == 301 || resp == 308 ||
|
||||
resp == 401 || resp == 403 || resp == 404 || resp == 410 || resp == 414 || resp == 416 || resp == 451) {
|
||||
// ban forever
|
||||
_coordinator.banWebPeer(_uri.getHost(), true);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Permanently banning the webseed " + url);
|
||||
} else if (resp == 429 || resp == 503) {
|
||||
// ban for a while
|
||||
_coordinator.banWebPeer(_uri.getHost(), false);
|
||||
if (_log.shouldWarn())
|
||||
_log.warn("Temporarily banning the webseed " + url);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxPipeline() {
|
||||
return maxRequests;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
synchronized(this) {
|
||||
return connected;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized void disconnect() {
|
||||
if (thread != null)
|
||||
thread.interrupt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void have(int piece) {}
|
||||
|
||||
@Override
|
||||
void cancel(int piece) {}
|
||||
|
||||
@Override
|
||||
void request() {
|
||||
addRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInterested() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public void setInteresting(boolean interest) {}
|
||||
|
||||
@Override
|
||||
public boolean isInteresting() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChoking(boolean choke) {}
|
||||
|
||||
@Override
|
||||
public boolean isChoking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChoked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getInactiveTime() {
|
||||
if (lastRcvd <= 0)
|
||||
return -1;
|
||||
long now = System.currentTimeMillis();
|
||||
return now - lastRcvd;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxInactiveTime() {
|
||||
return PeerCoordinator.MAX_INACTIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keepAlive() {}
|
||||
|
||||
@Override
|
||||
public void retransmitRequests() {}
|
||||
|
||||
@Override
|
||||
public int completed() {
|
||||
return metainfo.getPieces();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompleted() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true
|
||||
* @since 0.9.49
|
||||
*/
|
||||
@Override
|
||||
public boolean isWebPeer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// private methods below here implementing parts of PeerState
|
||||
|
||||
private synchronized void addRequest() {
|
||||
boolean more_pieces = true;
|
||||
while (more_pieces) {
|
||||
more_pieces = outstandingRequests.size() < getMaxPipeline();
|
||||
// We want something and we don't have outstanding requests?
|
||||
if (more_pieces && lastRequest == null) {
|
||||
// we have nothing in the queue right now
|
||||
more_pieces = requestNextPiece();
|
||||
} else if (more_pieces) {
|
||||
// We want something
|
||||
int pieceLength;
|
||||
boolean isLastChunk;
|
||||
pieceLength = metainfo.getPieceLength(lastRequest.getPiece());
|
||||
isLastChunk = lastRequest.off + lastRequest.len == pieceLength;
|
||||
|
||||
// Last part of a piece?
|
||||
if (isLastChunk) {
|
||||
more_pieces = requestNextPiece();
|
||||
} else {
|
||||
PartialPiece nextPiece = lastRequest.getPartialPiece();
|
||||
int nextBegin = lastRequest.off + PeerState.PARTSIZE;
|
||||
int maxLength = pieceLength - nextBegin;
|
||||
int nextLength = maxLength > PeerState.PARTSIZE ? PeerState.PARTSIZE
|
||||
: maxLength;
|
||||
Request req = new Request(nextPiece,nextBegin, nextLength);
|
||||
outstandingRequests.add(req);
|
||||
lastRequest = req;
|
||||
this.notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts requesting first chunk of next piece. Returns true if
|
||||
* something has been added to the requests, false otherwise.
|
||||
*/
|
||||
private synchronized boolean requestNextPiece() {
|
||||
// Check for adopting an orphaned partial piece
|
||||
PartialPiece pp = listener.getPartialPiece(this, bitfield);
|
||||
if (pp != null) {
|
||||
// Double-check that r not already in outstandingRequests
|
||||
if (!getRequestedPieces().contains(Integer.valueOf(pp.getPiece()))) {
|
||||
Request r = pp.getRequest();
|
||||
outstandingRequests.add(r);
|
||||
lastRequest = r;
|
||||
this.notifyAll();
|
||||
return true;
|
||||
} else {
|
||||
if (_log.shouldLog(Log.WARN))
|
||||
_log.warn("Got dup from coord: " + pp);
|
||||
pp.release();
|
||||
}
|
||||
}
|
||||
|
||||
// failsafe
|
||||
// However this is bad as it thrashes the peer when we change our mind
|
||||
// Ticket 691 cause here?
|
||||
if (outstandingRequests.isEmpty())
|
||||
lastRequest = null;
|
||||
|
||||
/*
|
||||
// If we are not in the end game, we may run out of things to request
|
||||
// because we are asking other peers. Set not-interesting now rather than
|
||||
// wait for those other requests to be satisfied via havePiece()
|
||||
if (interesting && lastRequest == null) {
|
||||
interesting = false;
|
||||
out.sendInterest(false);
|
||||
if (_log.shouldLog(Log.DEBUG))
|
||||
_log.debug(peer + " nothing more to request, now uninteresting");
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return all pieces we are currently requesting, or empty Set
|
||||
*/
|
||||
private synchronized Set<Integer> getRequestedPieces() {
|
||||
Set<Integer> rv = new HashSet<Integer>(outstandingRequests.size() + 1);
|
||||
for (Request req : outstandingRequests) {
|
||||
rv.add(Integer.valueOf(req.getPiece()));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return index in outstandingRequests or -1
|
||||
*/
|
||||
private synchronized int getFirstOutstandingRequest(int piece) {
|
||||
for (int i = 0; i < outstandingRequests.size(); i++) {
|
||||
if (outstandingRequests.get(i).getPiece() == piece)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private synchronized List<Request> returnPartialPieces() {
|
||||
Set<Integer> pcs = getRequestedPieces();
|
||||
List<Request> rv = new ArrayList<Request>(pcs.size());
|
||||
for (Integer p : pcs) {
|
||||
Request req = getLowestOutstandingRequest(p.intValue());
|
||||
if (req != null) {
|
||||
PartialPiece pp = req.getPartialPiece();
|
||||
synchronized(pp) {
|
||||
int dl = pp.getDownloaded();
|
||||
if (req.off != dl)
|
||||
req = new Request(pp, dl);
|
||||
}
|
||||
rv.add(req);
|
||||
}
|
||||
}
|
||||
outstandingRequests.clear();
|
||||
return rv;
|
||||
}
|
||||
|
||||
private synchronized Request getLowestOutstandingRequest(int piece) {
|
||||
Request rv = null;
|
||||
int lowest = Integer.MAX_VALUE;
|
||||
for (Request r : outstandingRequests) {
|
||||
if (r.getPiece() == piece && r.off < lowest) {
|
||||
lowest = r.off;
|
||||
rv = r;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
// EepGet status listeners to maintain the state for the web page
|
||||
|
||||
public void bytesTransferred(long alreadyTransferred, int currentWrite, long bytesTransferred, long bytesRemaining, String url) {
|
||||
lastRcvd = System.currentTimeMillis();
|
||||
downloaded(currentWrite);
|
||||
listener.downloaded(this, currentWrite);
|
||||
}
|
||||
|
||||
public void attemptFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt, int numRetries, Exception cause) {}
|
||||
public void transferComplete(long alreadyTransferred, long bytesTransferred, long bytesRemaining, String url, String outputFile, boolean notModified) {}
|
||||
public void transferFailed(String url, long bytesTransferred, long bytesRemaining, int currentAttempt) {}
|
||||
public void headerReceived(String url, int attemptNum, String key, String val) {}
|
||||
public void attempting(String url) {}
|
||||
|
||||
// End of EepGet status listeners
|
||||
}
|
||||
@@ -37,20 +37,6 @@ import net.i2p.data.DataHelper;
|
||||
public class BEncoder
|
||||
{
|
||||
|
||||
public static byte[] bencode(Object o) throws IllegalArgumentException
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bencode(o, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new InternalError(ioe.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void bencode(Object o, OutputStream out)
|
||||
throws IOException, IllegalArgumentException
|
||||
{
|
||||
@@ -72,40 +58,12 @@ public class BEncoder
|
||||
throw new IllegalArgumentException("Cannot bencode: " + o.getClass());
|
||||
}
|
||||
|
||||
public static byte[] bencode(String s)
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bencode(s, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new InternalError(ioe.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void bencode(String s, OutputStream out) throws IOException
|
||||
{
|
||||
byte[] bs = s.getBytes("UTF-8");
|
||||
bencode(bs, out);
|
||||
}
|
||||
|
||||
public static byte[] bencode(Number n)
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bencode(n, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new InternalError(ioe.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void bencode(Number n, OutputStream out) throws IOException
|
||||
{
|
||||
out.write('i');
|
||||
@@ -114,20 +72,6 @@ public class BEncoder
|
||||
out.write('e');
|
||||
}
|
||||
|
||||
public static byte[] bencode(List<?> l)
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bencode(l, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new InternalError(ioe.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void bencode(List<?> l, OutputStream out) throws IOException
|
||||
{
|
||||
out.write('l');
|
||||
@@ -137,20 +81,6 @@ public class BEncoder
|
||||
out.write('e');
|
||||
}
|
||||
|
||||
public static byte[] bencode(byte[] bs)
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
bencode(bs, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
throw new InternalError(ioe.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void bencode(byte[] bs, OutputStream out) throws IOException
|
||||
{
|
||||
String l = Integer.toString(bs.length);
|
||||
@@ -216,7 +146,8 @@ public class BEncoder
|
||||
if (l != null) {
|
||||
// Keys must be sorted. XXX - This is not the correct order.
|
||||
// Spec says to sort by bytes, not lexically
|
||||
Collections.sort(l);
|
||||
if (l.size() > 1)
|
||||
Collections.sort(l);
|
||||
for (String key : l) {
|
||||
bencode(key, out);
|
||||
bencode(m.get(key), out);
|
||||
@@ -224,7 +155,8 @@ public class BEncoder
|
||||
} else if (b != null) {
|
||||
// Works for arrays of equal lengths, otherwise is probably not
|
||||
// what the bittorrent spec intends.
|
||||
Collections.sort(b, new BAComparator());
|
||||
if (b.size() > 1)
|
||||
Collections.sort(b, new BAComparator());
|
||||
for (byte[] key : b) {
|
||||
bencode(key, out);
|
||||
bencode(m.get(key), out);
|
||||
|
||||
@@ -156,7 +156,8 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
/** stagger with other cleaners */
|
||||
private static final long CLEAN_TIME = 63*1000;
|
||||
private static final long EXPLORE_TIME = 877*1000;
|
||||
private static final long BLACKLIST_CLEAN_TIME = 17*60*1000;
|
||||
private static final long BLACKLIST_CLEAN_TIME = 67*60*1000;
|
||||
private static final int BLACKLIST_MAX_PEERS = 500;
|
||||
private static final long NODES_SAVE_TIME = 3*60*60*1000;
|
||||
public static final String DHT_FILE_SUFFIX = ".dht.dat";
|
||||
|
||||
@@ -1232,10 +1233,12 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Removed after consecutive timeouts: " + nInfo);
|
||||
}
|
||||
if (!_blacklist.contains(nid)) {
|
||||
// used as when-added time
|
||||
nid.setLastSeen();
|
||||
_blacklist.add(nid);
|
||||
// remove and add back with new date, may not be same object
|
||||
// used as when-added time
|
||||
nid.setLastSeen();
|
||||
boolean already = _blacklist.remove(nid);
|
||||
_blacklist.add(nid);
|
||||
if (!already) {
|
||||
if (_log.shouldLog(Log.INFO))
|
||||
_log.info("Blacklisted: " + nid);
|
||||
}
|
||||
@@ -1686,6 +1689,14 @@ public class KRPC implements I2PSessionMuxedListener, DHT {
|
||||
if (nid.lastSeen() < expire)
|
||||
iter.remove();
|
||||
}
|
||||
int sz = _blacklist.size();
|
||||
if (sz > BLACKLIST_MAX_PEERS) {
|
||||
// just remove random peers
|
||||
for (Iterator<NID> iter = _blacklist.iterator(); iter.hasNext() && sz > BLACKLIST_MAX_PEERS; sz--) {
|
||||
iter.next();
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
if (now - _nodesLastSaved > NODES_SAVE_TIME) {
|
||||
PersistDHT.saveDHT(_knownNodes, false, _dhtFile);
|
||||
_nodesLastSaved = now;
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ConfigUIHelper {
|
||||
* Country flag unused.
|
||||
*/
|
||||
private static final String langs[][] = {
|
||||
{ "ar", "lang_ar", "Arabic ﻉﺮﺒﻳﺓ", null },
|
||||
{ "ar", "lang_ar", "Arabic عربية", null },
|
||||
{ "az", "az", "Azerbaijani", null },
|
||||
{ "cs", "cz", "Čeština", null },
|
||||
{ "zh", "cn", "Chinese 中文", null },
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user