Compare commits

..

1168 Commits

Author SHA1 Message Date
d3cb0ab3f6 0.4.1
Checked in late, forgot to do so after actual release
2015-09-28 12:16:31 +00:00
e5fa4706db Fix loading of user guide and FAQ translations (#1641) 2015-09-12 15:40:16 +00:00
ecdd2ee426 Added new user guide translation 2015-09-12 14:30:22 +00:00
784a716f0a Updated translations 2015-09-12 14:29:53 +00:00
afdde691b4 CME fix 2015-09-02 01:33:49 +00:00
65d9439e03 Add owner to new ticket URL 2015-08-23 05:59:08 +00:00
8d19c4c78a Fixed CME 2015-08-21 02:22:35 +00:00
8731a72887 0.4 2015-08-21 02:20:25 +00:00
9e1b42134c Remove build numbers from version 2015-08-21 02:20:02 +00:00
17b4d035eb Update last checked time for manual checks too 2015-08-20 23:58:49 +00:00
d967d50c51 Fix email checking 2015-08-20 23:50:17 +00:00
42770cf01b Updated ignores 2015-08-20 11:53:10 +00:00
c910e17f6c Fix bug with sending anon emails 2015-08-20 11:52:09 +00:00
d408242173 Test OutboxProcessor.sendEmail(), proves existence of bug with anon emails 2015-08-20 11:26:34 +00:00
c52429f393 Add Mockito to unittest deps 2015-08-20 11:24:58 +00:00
aac9df446f 0.3 2015-08-15 23:33:58 +00:00
da40d97185 Temporarily disable IMAP due to class loader issues
Apache Commons Logging can't find the Log4J classes, because (I think) it is
not looking in the plugin's class loader (the classes are visible in I2P-Bote).
2015-08-15 23:23:51 +00:00
e661e4306c Updated ignores 2015-08-15 02:09:45 +00:00
18005cdfb3 Updated translations 2015-08-15 02:01:58 +00:00
1a7e8daf8e Fix app icon so it is bundled 2015-08-15 01:58:23 +00:00
771153c4d7 Add app icon 2015-08-15 01:55:14 +00:00
f1e750cef1 Change author to me (for feedback) 2015-08-15 01:54:54 +00:00
52e30278b5 Bump min I2P version to 0.9.18 (first to include my SU3 plugin cert) 2015-08-15 01:44:51 +00:00
4f1b81510f Add SU3 update URL 2015-08-15 01:32:26 +00:00
0c4d1dc5c3 Changed plugin signer and update URL 2015-08-15 01:28:38 +00:00
c1934b4576 Added missing image 2015-08-15 01:27:32 +00:00
0edd014c6b Deduplicate dependency verification 2015-08-15 01:26:47 +00:00
27e02ce527 Fix connection checking 2015-08-14 01:30:55 +00:00
9aa14a705e Only show "Check email" button for identities when connected 2015-08-14 00:56:50 +00:00
219de6e499 Adjust identities column widths on old themes 2015-08-14 00:56:19 +00:00
d07f790dbb Fix NPE in identity creation by properly saving identity config 2015-08-13 23:35:00 +00:00
8abfc8345b Deduplication 2015-08-13 12:39:37 +00:00
3cbcfaa331 Add config option for including local deps in update
Local deps are now moved out of update, because with the impending change of
plugin signer, all users will have all current JARs.
2015-08-13 12:00:06 +00:00
63b63a9f65 Bugfix 2015-08-13 11:29:42 +00:00
29f5db767d Extract common packing macro, delete .jar files from plugin (JIC) 2015-08-13 11:19:09 +00:00
90545b7046 Add config option for including remote deps in update
Remote deps are now moved out of update, because with the impending change of
plugin signer, all users will have all current JARs.
2015-08-13 11:00:06 +00:00
37b64f25c0 Fix hash verification 2015-08-12 12:10:49 +00:00
5f7bb2d7d1 Verify hashes of remote dependencies 2015-08-08 14:09:58 +00:00
69fc637bd7 Refactor remote dependency checking 2015-08-08 13:50:43 +00:00
cb0b0822a3 Upgrade to JavaMail 1.5.4, make it a remote dependency 2015-08-08 13:47:57 +00:00
f83f7cd085 Updated translations 2015-08-05 13:01:19 +00:00
bab92e082f Upgrade BouncyCastle to 1.52 2015-08-05 12:56:10 +00:00
d1e7eeb7bc Updated translation strings 2015-08-05 01:52:23 +00:00
a5409b0e43 Added new translations 2015-08-05 01:43:08 +00:00
742c697150 Updated translations 2015-08-05 01:42:37 +00:00
42c6269cda Improve recipient handling in email composition 2015-08-05 01:38:21 +00:00
03012e5323 Get IMAP STARTTLS working 2015-08-04 16:23:58 +00:00
97825a3d60 Upgrade to 20150627 snapshot of Apache James 2015-08-04 16:18:29 +00:00
dc5d066775 Get tests to pass 2015-08-03 13:21:57 +00:00
c2bc331b55 Add Email Date header tests 2015-08-03 13:19:17 +00:00
8f29c7d6fb Force loading of BouncyCastly so tests pass 2015-08-03 13:18:49 +00:00
6b530a364b Add direct link to creating tickets for I2P-Bote 2015-07-31 04:01:41 +00:00
3f60643c2e Updated history 2015-07-23 09:34:49 +00:00
3539b5a13b Don't move metadata file if we couldn't move email file (#1196) 2015-07-23 02:37:25 +00:00
e37f70506d Don't assume that email metadata file exists (#1196) 2015-07-23 02:27:09 +00:00
4196486799 Fix NPE (#937) 2015-07-22 21:16:18 +00:00
6dbecc0f6e Unused import 2015-07-22 12:30:51 +00:00
d209c9f94b Delete malformed packets from disk (#1287)
Incomplete email packets are unaffected because IncompleteEmailFolder overrides
the default behavior.
2015-07-22 11:44:49 +00:00
6e528dae6a Fix CME caused by no synchronization on kBuckets (#1586) 2015-07-21 10:09:32 +00:00
90f9de4861 Updated guide translations 2015-07-21 09:01:58 +00:00
f7b3499e93 Updated translations 2015-07-21 08:47:31 +00:00
5901565d74 Listen to identity updates too 2015-06-05 10:08:39 +00:00
f98990ad65 Added IdentitiesListener 2015-06-05 09:37:10 +00:00
d290665a17 New user guide translation for es 2015-03-20 09:31:16 +00:00
e2e2233b89 User guide fixes (thx strel!) 2015-03-20 09:25:31 +00:00
29190552d9 Updated translations 2015-03-20 09:24:29 +00:00
371ae89bc3 Preparation for moving StrongTls to i2p.jar:
- Removed last of pre-existing code
- Moved to net.i2p.util package
- Relicensed to public domain
- Improved interface
2015-03-19 19:49:55 +00:00
a34da62789 Overhauled StrongTls with 2015-era protocols and ciphers 2015-03-19 00:51:35 +00:00
8ff2c84cd4 Discovered that one of the old bootstrapping nodes is kytv, now resurrected 2015-03-16 10:12:19 +00:00
96140a49c5 New bootstrap peers (thanks str4d and The_Tin_Hat!) 2015-03-16 06:06:18 +00:00
b3f9ea8a0b Updated TODO 2015-03-12 21:45:10 +00:00
034660d4af Updated translations 2015-03-10 11:28:10 +00:00
bbda61316e Formatting changes by Transifex, and some string fixes 2015-03-10 11:22:45 +00:00
297a26cc63 Added user guide and FAQ to Transifex config 2015-03-10 11:22:26 +00:00
c9686adaef More formatting fixes for Transifex 2015-03-10 10:57:59 +00:00
82d31e4813 Formatting fixes for Transifex 2015-03-10 10:49:55 +00:00
63c17045b6 Multi-line Spanish translation 2015-03-10 10:40:06 +00:00
0566e42f21 New translation of FAQ into Spanish (thanks trolly!) 2015-03-10 04:16:22 +00:00
a21f67d429 Fixes 2015-02-15 10:52:36 +00:00
d7ae6d51e5 FAQ navigation 2015-02-15 10:23:13 +00:00
271eb004b2 Android themed wait.gif 2015-02-15 09:21:46 +00:00
c65e3f8f7e UI option for global identity check 2015-02-15 09:21:30 +00:00
dd7f4055a1 Prevent potential NPE 2015-02-15 09:20:52 +00:00
9b0836249d Bugfix 2015-02-15 07:13:17 +00:00
0585f211fb Implement checking individual identities 2015-02-15 03:25:40 +00:00
4df989d63a Don't disable default selection for new identities when only one exists 2015-02-14 22:33:59 +00:00
a76789cf30 Button layout fix 2015-02-14 22:33:34 +00:00
ae55336e06 Updated translations 2015-02-14 22:32:50 +00:00
437c5ddbac Backend implementation of per-identity relay settings, global check exclusion 2015-02-14 21:51:01 +00:00
63a574f578 Show which nav item is currently selected 2015-02-13 02:21:53 +00:00
42c3e0d369 Match nav drawer list item highlight to Material design spec 2015-02-13 02:01:13 +00:00
5d89032b90 Corrections from Material design spec 2015-02-13 01:55:57 +00:00
fc738142fa Moved getBooleanParameter() and getIntParameter() to Util 2015-02-07 19:51:39 +00:00
4e9b0e93cb Extract String constants 2015-02-06 10:00:05 +00:00
8912cfcf7d Include HTML files in WAR 2015-02-05 10:33:06 +00:00
73e22a3d34 Reference ticket numbers in TODO 2015-02-05 09:36:42 +00:00
dfa1dfbd74 Settings headings 2015-02-04 11:21:27 +00:00
eff95792ac Updated translations 2015-02-04 11:00:52 +00:00
bf53778367 String fix 2015-02-04 11:00:29 +00:00
74bde7aac6 HTML5 cleanups 2015-02-04 01:14:44 +00:00
848ec8cb14 Added not-yet-implemented features to TODO 2015-02-04 00:56:29 +00:00
a72bd3fb04 FAQ formatting 2015-02-03 14:22:22 +00:00
87ce7646f6 FAQ pagetitle 2015-02-03 14:19:29 +00:00
e2c003503a Reformatted FAQ 2015-02-03 14:16:46 +00:00
4f9d717725 List tweaks 2015-02-03 12:58:16 +00:00
f638d8e43a Limit user guide navigation width 2015-02-03 12:30:11 +00:00
2377acf15c Reorganized user guide sections 2015-02-03 12:29:19 +00:00
f11af022b2 User guide navigation 2015-02-03 12:25:31 +00:00
9ef5a15650 Removed unnecessary installation details, renumbered headings 2015-02-03 11:59:50 +00:00
02bb52dc67 Title fixes 2015-02-03 11:51:41 +00:00
bd9a0bd6b4 Consolidated credits 2015-02-03 11:32:04 +00:00
fe7516c24f Reworked user guide intro 2015-02-03 08:43:54 +00:00
97c567a105 User guide fixes 2015-02-03 04:55:16 +00:00
62308d053d Translation string fixes 2015-02-03 04:55:02 +00:00
f4ebc330a1 Translation fixes 2015-02-03 04:54:42 +00:00
93cabe4f44 Updated translation strings 2015-02-03 04:28:37 +00:00
5222861962 Proper theme names 2015-02-03 04:15:55 +00:00
9c09c739d2 Fixed bundle-messages.sh 2015-02-03 04:15:46 +00:00
8b3770f33d New translations 2015-02-03 03:52:46 +00:00
cd5d8b0ac2 Updated translations 2015-02-03 03:52:32 +00:00
596aa39d5d Updated Transifex config 2015-02-03 03:52:25 +00:00
212ca673b0 Updated TODO 2015-02-03 03:41:01 +00:00
9833590266 Move HTML files to subdir in preparation for Transifex 2015-02-03 03:40:50 +00:00
77242920bd Updated French translation of user guide 2015-02-03 03:33:22 +00:00
19a8c09a8d User guide tweaks 2015-02-03 03:33:00 +00:00
2634398ea4 Renamed user guide HTML 2015-02-02 22:41:19 +00:00
2fac3e9eae Tidied up user guide HTML 2015-02-02 22:40:04 +00:00
182bafb524 Enable HTML files to be themed 2015-02-02 22:32:52 +00:00
d7c673e4be Charts on network status page 2015-02-02 03:17:28 +00:00
33273675da Mark new relay peers instead of showing 0% reachability 2015-02-01 04:43:45 +00:00
7b405764fb NPE fix (ticket #1367) 2015-01-30 06:03:01 +00:00
750305fef1 Attachments icon 2015-01-30 05:38:57 +00:00
269f0d07e9 Improved info and error message displaying 2015-01-29 05:03:26 +00:00
7aae76ef4b Fixes after XSSFilter 2015-01-29 04:39:03 +00:00
302414a53d Enable different page title from browser title, more sidenav icons 2015-01-29 04:38:21 +00:00
22732d33c1 Missing bcprov changes 2015-01-28 23:54:55 +00:00
b113dd3e51 Font changes 2015-01-28 08:04:53 +00:00
ca0ac05614 Import identities 2015-01-28 06:47:47 +00:00
54ac8425b5 Export identities 2015-01-28 04:33:03 +00:00
67e36d834e Escape XML 2015-01-28 04:25:51 +00:00
48c2294517 HTML5 <time> 2015-01-27 02:48:12 +00:00
e3e694d0c9 Enable XSSFilter on all inputs except passwords 2015-01-27 01:43:12 +00:00
06fc60af43 Material tweak for new emails 2015-01-27 01:41:33 +00:00
9cd8bddf8a Bugfix 2015-01-27 01:30:29 +00:00
6c4ab4b1b3 NPE fix when attempting to change identity name to blank 2015-01-27 01:14:33 +00:00
3155308054 New theme based on the Material design of the Bote Android app 2015-01-26 10:32:42 +00:00
538a5b2e06 Change addressbook.gif to addressbook.png 2015-01-26 10:02:05 +00:00
dd126df6c7 Inputs to buttons 2015-01-26 07:41:43 +00:00
a1edb3173c Remove onclick from header, the inbox is easily accessed from the side nav 2015-01-26 04:56:34 +00:00
edc51acedb An article around email content 2015-01-26 04:24:07 +00:00
0394b591a7 Extra page title for use in new theme 2015-01-26 03:45:03 +00:00
9a5a161342 CSS tweak 2015-01-25 10:19:05 +00:00
ec3acae530 Replaced linebreak with margin 2015-01-25 09:32:05 +00:00
7fea66978b Remove "Public Address Directory" from side nav until it has a link 2015-01-25 09:21:16 +00:00
b7abb03b32 HTML5, preparations for new theme 2015-01-25 09:18:40 +00:00
958a072d9b HTML5 doctype and charset 2015-01-24 12:31:42 +00:00
e7042dc5a7 Detect file MIME types 2015-01-12 07:55:51 +00:00
bc6df473be Ask for plugin SU3 keystore password 2015-01-12 07:34:17 +00:00
04ac90d478 Prevent NPE on Android if the state gets weird (it has happened) 2015-01-11 12:25:45 +00:00
7e8421c63b Added ignores 2015-01-11 05:51:22 +00:00
3591d25f72 Migrate i2p.bote.crypto AES and EC to JCA; upgrade to BouncyCastle 1.51
This change was necessary to fix the crypto on Android, where SpongyCastly must
be used instead (because of classloader conflicts). The new ECUtils class
contains the remaining code that could not be made provider-agnostic. In
particular, the EmailDestination format for EC requires the use of BouncyCastle
point encoding.

The full BouncyCastle library is now bundled, because it must be added as a
Security Provider to use the JCA system, and this requires a valid signature.

JCA is used for AES operations instead of I2P's built-in AES engine because the
PKCS#7 padding class could not be accessed on its own in a provider-agnostic
manner. The resulting code is also cleaner.
2015-01-04 22:16:16 +00:00
1f1b328f70 Close InputStream in Util.getPartSize() 2015-01-04 05:00:08 +00:00
823491ae4d Pull out Util method for getting size of a Part 2014-12-28 11:42:23 +00:00
6856773636 Correct the Attachment interface 2014-12-28 11:42:02 +00:00
2cc3df7c1f Generalize attachments 2014-12-28 04:52:27 +00:00
852bad8d61 Moved JSPs to correct location
For i2pbote.war the location doesn't matter, because the JSPs are compiled. For
the Eclipse testnet, the JSPs are not compiled and cannot be located because
access to files in WEB-INF is restricted.
2014-12-23 10:47:11 +00:00
4f357db8ec Use I2PSocketManagerFactory.createDisconnectedManager() for better connectError 2014-12-17 23:54:31 +00:00
877b02cc04 Layout fix 2014-12-13 10:56:30 +00:00
8b5b7507c6 Helpers to get the name for an EmailDestination 2014-11-18 04:00:00 +00:00
5ff770bc31 Use assertArrayEquals 2014-11-17 22:39:04 +00:00
4107467c64 Mockery thread synchronization 2014-11-17 22:23:20 +00:00
05def741fb Fix BCC header removal bug 2014-11-17 21:41:57 +00:00
82ac0d59d8 Unused imports 2014-11-17 21:25:00 +00:00
10445e1082 junit.framework -> org.junit 2014-11-17 21:15:00 +00:00
a968f5c6f4 Updated history 2014-09-25 05:54:49 +00:00
d6564680a5 Update to techdoc by HungryHobo 2014-09-25 05:54:31 +00:00
ec41d7d82e Switch to Maven directory structure without losing history 2014-09-25 05:50:39 +00:00
8a29b9dd0d Mark locations of code incompatible with newer I2P Destinations 2014-09-21 05:32:43 +00:00
6c53344f51 A zero-length password is an uncached password
This brings PasswordCache in line with FileEncryptionUtil.
2014-09-21 05:31:08 +00:00
2768297be9 Add and remove interface for password listeners 2014-09-18 06:11:01 +00:00
740197e439 Added TODO 2014-08-26 11:55:12 +00:00
6e4c52b746 Remove spaces and newlines 2014-08-07 11:56:43 +00:00
cc59ed9adb Remove possible prefixes 2014-08-07 11:46:58 +00:00
3c0a431f09 Remove UpdateChecker
Plugins have been auto-updated by the router for a while now
2014-08-03 10:47:11 +00:00
392ba71037 Another Tomcat 7 fix, see rev. 5e9c9148 2014-08-03 10:42:32 +00:00
e39abcc145 Use SecureFile instead of Util.makePrivate()
* Replace Util.makePrivate() with SecureFile and SecureFileOutputStream
* Make derivparams a SecureFile
2014-08-02 16:46:17 +00:00
e030e9ed5f 0.2.10 2014-07-23 21:36:12 +00:00
1896fccf1f Fix NullPointerExceptions 2014-07-23 21:25:31 +00:00
ca19e9d9e0 Use a separate SessionKeyManager instead of the router's 2014-07-23 21:24:39 +00:00
729a4ac99f Upgrade to 20140722 snapshot of Apache James 2014-07-23 21:22:15 +00:00
729f59e729 Support I2CP connections over Unix domain sockets
Only supported on Android for now.
2014-07-16 04:05:35 +00:00
78b66b5509 Bugfix after net.i2p.data.Base64.decode() errors were cleaned up 2014-07-07 00:28:22 +00:00
5cdcae1416 Missing network status change 2014-07-06 14:26:47 +00:00
348262e7a2 NetworkStatusListener implementation 2014-07-06 13:05:39 +00:00
adb290658a Inform caller if importer found no identities 2014-07-06 02:55:44 +00:00
c04fc24445 Implement encrypted identities export 2014-07-06 02:28:40 +00:00
4762f8486e Implement identity appending on import 2014-07-05 23:50:02 +00:00
52a717d7e3 Import identities from FileDescriptor (no appending possible yet) 2014-07-05 04:23:19 +00:00
e9ffb4643b Export identities to file (no encryption possible yet) 2014-07-04 06:21:17 +00:00
382f75f4a4 Pulled out Identities <-> Properties conversion into separate methods 2014-07-04 00:23:14 +00:00
4a6fc262e7 Show number of incomplete emails 2014-07-02 09:23:58 +00:00
4cd24cd579 Expose number of incomplete emails 2014-07-02 06:38:02 +00:00
32ce92d7cb Updated license.txt 2014-06-23 01:47:07 +00:00
96bb3a0719 Enable saving picture for EmailIdentity 2014-06-16 05:41:11 +00:00
5cebc0b2ee Added EmailIdentity.setPictureBase64() 2014-06-16 04:57:32 +00:00
4e7d57d8e3 Implement vanity destinations 2014-06-11 21:11:11 +00:00
0ad03ce6d4 Fix for new Jetty/Tomcat 2014-06-11 06:13:13 +00:00
2082fd0856 Emails are not kept in-memory inside EmailFolder, so store \Recent in metadata 2014-06-10 12:17:35 +00:00
98c56de3a5 Added specific listener for newly-received emails 2014-06-09 04:51:20 +00:00
1801e308b2 Fixed bug in setFlags() 2014-06-08 06:46:56 +00:00
f318587209 Helper method 2014-06-08 04:59:13 +00:00
38d5833551 Improved FolderListener, emails added to a folder outside IMAP now get \Recent 2014-06-08 04:12:30 +00:00
6bbd015d38 Store other IMAP flags in-memory (like \Recent) 2014-06-08 02:59:39 +00:00
f20ae940a8 Add missing file 2014-06-03 06:01:55 +00:00
f7f185a68c Handle index packets that are bigger than a datagram (fixes "After merging, IndexPacket is too big..." errors) 2014-06-02 21:01:26 +00:00
a47100d14a Fix NullPointerException on fresh installs 2014-05-29 22:21:09 +00:00
32bd6e45a8 Fixes for Tomcat 7 which is more anal about the JSP spec than Jetty or Tomcat 6 2014-05-29 22:14:28 +00:00
ca19b0929e NPE fix for corrupt folder 2014-05-24 00:00:34 +00:00
3dede23a24 Reworked email status storage for UI flexibility 2014-05-23 01:18:18 +00:00
e190587330 Reverted bad log tweak 2014-05-17 04:37:23 +00:00
0d92ddb6e1 Set connectTask to null so getNetworkStatus() returns valid state 2014-05-17 04:36:42 +00:00
52f6405c74 Removed unused import 2014-05-17 04:33:28 +00:00
99fb8bf264 NPE fixes, log tweak 2014-05-17 04:27:59 +00:00
fa22d47252 Whitespace, don't create SSL key store on Android 2014-05-17 04:21:06 +00:00
2dfa656b06 JSSE requires keystore and key passwords to be identical 2014-05-13 05:07:05 +00:00
56aa3f3c1c Generate the SSL cert on-the-fly to prevent MITM 2014-05-13 02:23:09 +00:00
c2e75290fb Reverted mistaken checkin 2014-05-13 02:20:19 +00:00
3387cdd90c Enable STARTTLS for IMAP and SMTP using selfsigned certificate
Certificate domain is 127.0.0.1, clients will throw a warning if using localhost
(alongside the warning for selfsigned cert).
2014-05-12 13:49:13 +00:00
c3088c5931 Mark important comments 2014-05-12 13:23:28 +00:00
a149a0bdc0 Fixed NPE (ticket #1272) 2014-05-12 12:37:47 +00:00
7867198fe9 Override updateMessageID() on Android to prevent NetworkOnMainThreadException 2014-04-17 23:27:40 +00:00
38293ebcf9 Added elementUpdated() to FolderListener, made setNew() throws consistent 2014-04-16 13:07:17 +00:00
6f4a0615ff Update FolderListeners when Email is moved 2014-04-15 00:58:02 +00:00
22fa6105ac Updated FAQ and User's Guide 2014-04-14 02:30:00 +00:00
946fa8d6ec Insert addressbook/identity names, @bote, {UNK} into IMAP email headers 2014-04-14 02:29:37 +00:00
5a8d9c6f4f Remove @bote before validating sender and recipient addresses in SMTP 2014-04-13 05:05:41 +00:00
5c53c2071b Updated about.jsp 2014-04-13 02:45:57 +00:00
c84770036d Create BoteMailboxes once, and remove their FolderListeners when IMAP stops 2014-04-13 02:27:31 +00:00
d9756407b0 Refactor to handle recipient headers containing multiple recipients 2014-04-13 01:46:13 +00:00
fe9c6d9d47 Pack new mailapi.jar in update for 0.2.10 2014-04-11 22:42:07 +00:00
ee96addef6 Removed signature from scrypt jar (pack200 interferes) 2014-04-10 21:51:49 +00:00
1f9aa61d2f Upgraded to scrypt 1.4.0 2014-04-10 20:59:44 +00:00
zzz
5e559846db one more typo 2014-04-07 13:26:10 +00:00
bbd24eaaff fix another missing '/' 2014-04-07 12:20:12 +00:00
4db680f067 add missing / to paths 2014-04-07 12:14:44 +00:00
79595913f2 Previous fix wasn't quite right 2014-04-04 20:01:29 +00:00
b387b77bfb Fixed concurrency problem 2014-03-30 03:10:04 +00:00
dce43d11ae Fixed IMAP UID implementation to conform to RFC 3501 2014-03-30 02:14:56 +00:00
8fec6b28e8 Remove @bote properly from SMTP messages 2014-03-29 03:19:53 +00:00
17282cda4d Missing Bean method 2014-03-28 20:58:26 +00:00
1664253417 Fixed password "corruption" (ticket #1239) 2014-03-28 20:57:56 +00:00
654b136cb0 Somehow, file duplication has stopped 2014-03-18 20:04:50 +00:00
2b5de7958e Doc tweak 2014-03-18 10:56:28 +00:00
10b9b2e593 Updated identity file spec 2014-03-18 10:22:47 +00:00
3571adf2ec Another StatusListener 2014-03-09 23:05:22 +00:00
44027e80ca Save and load default key properly 2014-03-09 09:11:00 +00:00
9d821f66b9 Update default identity when changed (for writing to file) 2014-03-08 23:07:54 +00:00
bef847d270 Moved Servlet-dependent helper methods back to JSPHelper 2014-03-04 01:46:56 +00:00
967a523130 Missing javadoc @param 2014-03-04 01:36:11 +00:00
c35e9c9139 Enable listening to status of internal operations (for Android UI) 2014-03-02 10:32:23 +00:00
c0b62e25c1 Remove throw (handled in rev 78f6a5bcf158019aceb75a48aebd8d9c20b203ce) 2014-03-01 01:55:15 +00:00
936e1e7d50 Updated techdoc.txt for mailapi.jar 2014-02-28 22:08:34 +00:00
592793eaac Add a setting to enable/disable SMTP 2014-02-28 22:02:49 +00:00
f1c9ac9788 Updated to mailapi 1.5.1 2014-02-27 05:19:54 +00:00
bdd24d7e9d Apparently Jasper can't follow inheritance 2014-02-27 04:40:15 +00:00
de36d91909 Delete i2pbote.jar in clean 2014-02-27 03:28:18 +00:00
1a6ae22b99 Allow using result of folder.getName() in getMailFolder()
This is used for saving instance state in Android.
2014-02-27 03:00:03 +00:00
adde9736be Split JSPHelper so common utilities can be used by other UIs (Android) 2014-02-26 23:08:34 +00:00
173d08d798 Allow FolderListeners to be removed 2014-02-26 07:07:42 +00:00
acb1ace33a Don't add source files to i2pbote.jar (it duplicates .txt files) 2014-02-26 07:07:11 +00:00
ffa7450e77 Reordered list of folders 2014-02-26 03:28:18 +00:00
d9d9c47124 Add README.md for GitHub 2014-02-16 18:18:45 +00:00
d960308461 Update techdoc.txt 2014-02-16 13:41:27 +00:00
616df8de9f Update translations from Transifex 2014-02-16 13:40:34 +00:00
427e293bac 0.2.9 2014-02-16 13:39:32 +00:00
163f8d58c0 Make send button easier to find 2014-01-08 01:44:02 +00:00
43e34eb221 Added code to mapper for fetching recent messages
This functionally changes nothing, because BoteMessage.isRecent()
always returns false.
2014-01-01 21:30:02 +00:00
c2d1334c04 Unset flags correctly 2014-01-01 05:57:41 +00:00
a05890eaec Implemented deleting via IMAP
The \Deleted flag is stored in EmailMetadata, but is ignored by Bote and only
used for IMAP deletion.
2013-12-31 20:20:17 +00:00
2a744fb1cd RFC 2822: set From: header 2013-12-31 16:43:55 +00:00
ed60728edd Don't delete libs with "ant clean" 2013-12-31 07:29:26 +00:00
48e69d3cd5 Don't break folder list if an email can't be decrypted 2013-12-27 02:33:26 +00:00
df09332ead Added libs to .jar manifest (so IMAP setting works) 2013-12-26 09:54:01 +00:00
585413fa2b Fixed potential NPE 2013-12-25 23:30:02 +00:00
68c48cb332 Update to jMock 2.6.0 (v2.5.1 is not available from their website anymore) 2013-05-01 18:12:55 +00:00
ae87a801ea Fix classpath and typos 2013-05-01 17:52:44 +00:00
901b051546 Implement SMTP 2013-05-01 17:50:42 +00:00
6590e3122a Shorten known email destinations in the folder view 2013-04-29 19:18:02 +00:00
e601b5f46e Add a setting to enable/disable IMAP 2013-04-29 18:53:41 +00:00
641085ab24 don't try to zip up non-existent images directory (see rev. 1ae37d314f064cfb6c870727775f5b5ccc5ea69e) 2013-04-29 18:34:15 +00:00
5d371f983a IMAP interface, works with Thunderbird but not Evolution 2013-04-29 00:21:37 +00:00
8fc111fc86 Fix Content-Transfer-Encoding (8bit doesn't allow zeros, CR, or LF) 2013-04-26 23:15:13 +00:00
2dc809c025 Close streams when done reading 2013-04-26 23:06:15 +00:00
7b0149dc39 by request, adding my i2pbote node's public destination 2013-04-11 16:00:55 +00:00
24509df2b5 Delete commented out line 2013-04-02 21:47:28 +00:00
263b68550e Fix a compiler warning 2013-04-02 21:42:34 +00:00
ae3ac8b5be Attach file on selection when JS is enabled 2013-04-02 21:33:36 +00:00
7c22899f32 try supressing/fixing a few warnings 2013-04-01 21:01:18 +00:00
3970d6d015 build fix (don't try to zip up non-existent images directory) 2013-04-01 20:40:12 +00:00
4464301119 Remove unused images 2013-04-01 18:08:37 +00:00
f0622d202b Move style attributes to CSS 2013-04-01 17:57:59 +00:00
63e260f932 Show anonymous sender in italics 2013-03-31 22:36:24 +00:00
87ad8db92a Display of signatures:
* Combine signature column and replied column
 * Don't show signature warning for anonymous emails
2013-03-31 22:23:00 +00:00
cc7e0209ec Simplification 2013-03-30 23:01:32 +00:00
1a4c25a32f Add a null check 2013-03-30 22:58:14 +00:00
79339a0208 Fix a comment 2013-03-30 22:57:26 +00:00
249389a4d3 Replace ReentrantLock with synchronized 2013-03-30 08:55:16 +00:00
92a5a998d6 Show a wait page when the password is changed 2013-03-29 17:09:10 +00:00
e1a49cf440 Add a JSP that allows users to check encrypted files 2013-03-24 12:32:31 +00:00
e30cb79c5f 0.2.8 2013-03-08 21:51:26 +00:00
49268b21ea Increase #words to 8 and #zero bits to 10 2013-03-07 21:38:57 +00:00
74384e0517 Fix: unneccessary lookup when confirm=true 2013-03-07 21:25:44 +00:00
9bfde0ac33 Fix formatting on editIdentity.jsp 2013-03-07 21:22:36 +00:00
55d5ea6084 Fix NullPointerException when no word list is available for the current language 2013-03-05 23:01:49 +00:00
0e36c3dcc3 Fix: Escape characters handled incorrectly when saving and loading 2013-03-05 22:40:08 +00:00
0155e5f57f Implement mark() and reset() 2013-03-05 22:14:02 +00:00
a2b3833602 Store fingerprint with email identity and show it on editIdentity.jsp 2013-03-05 19:29:43 +00:00
200d9ceb3d Switch address book to a properties-style format; show imported picture and text on editContact.jsp 2013-03-03 12:48:36 +00:00
69fd2431c8 Switch identities file to a properties-style format; show published picture and text on editIdentity.jsp 2013-02-26 21:48:06 +00:00
66020b2fc7 Add 0.2.7 release notes 2013-02-14 15:35:32 +00:00
34e76ce627 Add a missing test 2013-02-12 13:30:15 +00:00
79393f0ea8 Fix ContactTest when run from Ant 2013-02-12 13:29:41 +00:00
c4cdbb98cc trim() name before publishing or doing a lookup 2013-02-11 21:24:28 +00:00
eda69d1e7e Fix @bote.i2p suffix 2013-02-11 21:23:00 +00:00
1f2c528b9b Sign Contact packets:
* sign on publish
 * verify on import
 * ignore invalid Contact packets in lookups
2013-02-11 21:18:01 +00:00
6a99b034b7 Implement fingerprints for directory entries 2013-02-11 12:03:15 +00:00
17db81eee1 Use native scrypt if available 2013-02-04 22:13:33 +00:00
d50c843145 Change DEFAULT_PASSWORD_CACHE_DURATION back to 10 (I accidentally changed it to 1 in rev f957174cc94b1ed2a836e94cb71850ed612f2622) 2013-02-04 21:51:02 +00:00
7cbf364407 Rename DirectoryEntryTest to ContactTest 2013-02-04 21:47:57 +00:00
bd8674950e Add null check 2013-02-02 12:18:11 +00:00
0a0418f83f Make sure test files and directories are cleaned up 2013-02-02 12:17:11 +00:00
a5832cd1e4 Add comment 2013-02-02 12:15:29 +00:00
ccbc2c3e01 Check for existing name before publishing 2013-02-02 12:09:26 +00:00
d5c6c2d046 Ignore requests to replace existing Contacts 2013-02-02 00:04:12 +00:00
d8a606946e Don't skip sleep() on exceptions; lower log level 2013-01-27 22:30:58 +00:00
dbaa00d5b1 Print number of running threads 2013-01-27 22:30:17 +00:00
844bfcb842 Implement basic address directory 2013-01-27 22:29:01 +00:00
882a6d207a merge of '8d66ebeab68f6165dbd977cb2b5a5d52d09eab03'
and 'd27fa448d59dd46241e032896b0788e9057da5e1'
2013-01-27 21:59:38 +00:00
730aff2a50 Updated Norwegian Bokmål translation updates from transifex.
(100% translation)
2013-01-26 19:17:27 +00:00
de6d2d60a9 Lower max packet size to 10 kBytes 2013-01-24 20:57:57 +00:00
a724a521cd Add an option to change the ping interval 2013-01-24 20:39:49 +00:00
eaaf3c90e4 Remove Util.get(Collection, int) and use toArray() instead 2013-01-24 20:37:39 +00:00
a0febacdfd Fix: addresses and identities still available after password cache expires 2013-01-23 21:42:24 +00:00
2f0cb066ab Fix forward URL when context path is something other than /i2pbote 2013-01-23 21:08:46 +00:00
fc89896246 Don't attempt to show number of new emails when a password needs to be entered first (metadata is password protected as of recently) 2013-01-22 22:05:27 +00:00
e9c262c8b7 Add package.html files 2013-01-22 20:49:32 +00:00
093e439e04 Fix JavaDoc warnings 2013-01-22 20:31:17 +00:00
bf07f9c664 merge of '90e5bcb2bddcd45813c9eb3b354026f37152c66e'
and 'a6a21a22bbe0d4a61750abff96d5aaaa23b8df54'
2013-01-21 22:27:35 +00:00
bba9ac405a Add a command line program for testing datagram reliability 2013-01-21 22:26:19 +00:00
a0457273b7 switch javadocs from bob.i2p to i2p-javadocs.i2p
(sponge no longer hosts them)
2013-01-21 01:56:14 +00:00
e6a330944d update oracle package-list URLs 2013-01-21 01:44:10 +00:00
20940f209b Lower log level 2013-01-20 21:23:06 +00:00
bbc71ad13c Some refactoring 2013-01-20 21:21:53 +00:00
64917757a4 Make delivery checking turn-offable 2013-01-20 21:21:36 +00:00
b966ebbcfd address.tag: replace hover with click-to-expand; share code with editIdentity.jsp 2013-01-20 19:49:23 +00:00
ca7f4124c4 Update en and de strings 2013-01-20 16:13:42 +00:00
b24fe46661 Fix ambiguous i18n source string "Sent" 2013-01-20 16:11:32 +00:00
1db3aee096 merge of '05f071f4da46716c5566db81c177ec3e3ec04852'
and 'de9594e3f85d2d2401af64407c0c54c4e6a61d33'
2013-01-20 03:02:17 +00:00
db5a566e15 Language nb is more precise than no. 2013-01-20 02:53:01 +00:00
f485c68472 DeliveryChecker.java:
* Don't save metadata unless it changed
 * Logging
 * Code formatting
2013-01-20 02:28:41 +00:00
78013d6725 Wait until connected to DHT 2013-01-20 02:20:51 +00:00
261d05a1d6 Prevent "${param.path}" from showing up as a translation string 2013-01-20 02:15:17 +00:00
4a79a28d28 Handle tags that have an attribute but the message key is in the body 2013-01-20 02:02:51 +00:00
844a7a24fe Add help text to editIdentities.jsp 2013-01-20 01:28:23 +00:00
9937ec73f9 Remove more mockup elements 2013-01-19 23:32:30 +00:00
54629d8d05 Appearance changes to sendEmail.jsp 2013-01-19 23:28:19 +00:00
15dcd78936 Show whether an email has been replied to 2013-01-19 23:21:00 +00:00
087a4a68be Remove an extra '<' 2013-01-17 23:10:03 +00:00
7829c44d0d Add a delete button after replying to an email 2013-01-17 22:57:15 +00:00
476d06a588 German, French, Italian, Polish, Portuguese, and Russian translation updates from transifex 2013-01-17 12:43:25 +00:00
53223be28d Display an error if no public name entered 2013-01-16 22:27:27 +00:00
691b8ade1c Bump version to 0.2.7; migrate metadata files 2013-01-16 22:14:08 +00:00
7ac255ec94 Encrypt metadata files (as of rev 24af3e..., they contain email destinations and packet keys) 2013-01-16 22:05:35 +00:00
cf84a6aeee Don't receive packets as streams 2013-01-15 21:18:50 +00:00
15c45ad820 Remove unused import 2013-01-15 20:53:49 +00:00
10100b8177 Synchronize a method I missed in rev 7db2932b3db6bbf32d4ae937c93eb37e06e9f099 2013-01-15 20:51:51 +00:00
6adef679ac Synchronize CryptoFactory (Ticket #610) 2013-01-14 20:16:04 +00:00
00411877ad Change log level 2013-01-14 20:10:33 +00:00
7dc9f6caa0 Change log level to DEBUG (same as the other background threads) 2013-01-14 20:09:57 +00:00
dcb2b0f945 Translate page titles 2013-01-14 20:00:06 +00:00
f396729698 Disable "default" checkbox when there are less than two identities 2013-01-13 21:15:07 +00:00
0aff058acd Add a note about automatic email checking when a password is set 2013-01-13 21:00:12 +00:00
55f363aa73 Add @Overrides 2013-01-13 20:48:27 +00:00
6fec35ce85 Remove unused methods 2013-01-13 20:45:13 +00:00
42001079b5 Don't show private key link when creating a new identity 2013-01-13 20:42:35 +00:00
ab3d23a3af Fix variable name 2013-01-13 20:38:29 +00:00
3b0c9774e5 Remove mockup elements 2013-01-13 20:35:39 +00:00
8b44166b90 Simplify stringification 2013-01-13 20:12:55 +00:00
46ca0add8a Shorten thread name so it doesn't get truncated in the logs 2013-01-13 20:09:58 +00:00
6e967b2365 Fix: Version number not correctly written to file 2013-01-13 20:05:15 +00:00
bc72ebb865 Implement delivery status feature 2013-01-13 17:25:01 +00:00
e204d01fa2 Remove a System.out.println() 2013-01-12 02:51:39 +00:00
4a05868f11 Catch a more specific exception 2013-01-12 02:44:11 +00:00
6400913229 Move remaining third-party code (flexiprovider, lzma, and scrypt) into .jars 2013-01-12 02:42:00 +00:00
d7d3f2f01c Update to NTRU 1.2; move NTRU into a .jar 2013-01-12 02:08:08 +00:00
f9014d7b7b Fix unit test 2013-01-07 15:02:32 +00:00
a64ece90c2 Sort relay peers 2013-01-07 15:02:16 +00:00
e8f16cc83c Remove an unused method 2013-01-07 15:01:36 +00:00
d7b7355dd1 Fix warnings 2013-01-07 15:01:15 +00:00
816cf49b8c Get rid of the I2PBoteThread mechanism and handle thread interruptions correctly 2013-01-05 22:07:38 +00:00
bf2e2224c9 More detailed log message 2013-01-03 13:45:06 +00:00
2824c9a773 Minor comment change 2013-01-02 23:35:04 +00:00
1dbbcd8b78 Fix: themes not found because directory names were localized 2013-01-02 23:34:35 +00:00
d7d6257a36 Add an import for JavaDoc 2013-01-02 21:28:57 +00:00
020ef33b95 Log exceptions 2013-01-02 21:28:21 +00:00
8cfe4c5660 Only send up to 20 peers in a PeerList 2013-01-02 21:27:27 +00:00
e04deb28a1 Add info on how to set up Eclipse 2013-01-02 21:23:56 +00:00
fc0837ede4 Fix identities file name; change some wording 2013-01-02 21:20:22 +00:00
zzz
3ade199175 Specify source=1.6 target=1.6 so we can build with Java 7.
Suppress ant warning.
2013-01-02 12:53:28 +00:00
zzz
7bffe19e9e merge of '9030eb5d24f9d9f0c546f54c8a078749941e28df'
and 'ec0ec8bca6aa7c8d6b314688662891ed0c80aa34'


Merge broken rev from asaf.
Mtn 1.0 can't handle dates with trailing time zone indicators,
such as 'Z'. asaf's checkin was done with guitone which
adds the 'Z'. Hopefully this will make mtn 1.0 happy again.
2013-01-02 12:38:22 +00:00
3ffcf9d8d3 Update German translation from Transifex 2012-12-30 15:52:52 +00:00
111b3d8dbb Add a heading and a brief explanation 2012-12-02 14:27:31 +00:00
e177cd4567 Comments 2012-11-27 17:43:19 +00:00
a0ce9017a9 Include file size in log 2012-11-27 17:39:08 +00:00
bc1848ddcf Add a few more classes from the upstream bouncycastle jar due to recent changes in I2P.
Fixes the error found at http://pastethis.i2p/show/fnVXfo6eWaq4uaQNUjhO/
2012-09-25 23:02:14 +00:00
1f595fc079 Change "New" button text to "Compose" 2012-08-14 18:27:29 +00:00
22c0b789c4 Display last mail check time 2012-08-14 18:23:47 +00:00
967286aed0 New Arabic translation from Transifex
100% complete
2012-08-09 14:00:31 +00:00
ef357a5f2a Updated German and Spanish translations from tx. Pushing en source files to tx. 2012-07-29 10:03:47 +00:00
9fb05ba42e Remove a wrong comment 2012-07-20 12:00:29 +00:00
f13743d7b9 Make the "error" status text a link that shows a stack trace 2012-07-20 11:58:32 +00:00
549c39681d Lower log level 2012-07-20 10:56:09 +00:00
a3e8f657dd Show connect button if connecting failed 2012-07-20 10:54:35 +00:00
9cb3409a1a Add KYTV, change HH's role to Main Dev 2012-07-20 10:53:08 +00:00
5e87d6fa2d Lower log level 2012-07-19 15:16:35 +00:00
902db81fa7 Disable streaming 2012-07-19 15:15:17 +00:00
3cd0f09a41 More detailed log message 2012-07-19 15:13:27 +00:00
d0204effa2 Scroll down to the plugin section 2012-07-19 15:12:48 +00:00
ec619dd830 Fix: some threads not terminating on interrupt() 2012-07-19 15:08:52 +00:00
10e3df428c Spanish translation update from tx 2012-06-06 10:11:49 +00:00
e11f41d7f2 merge of '6f90a7d3635c3fece552972c32e378fc5177dd0b'
and '754beaa17f082deb32703c671277a2c0a5ef9ae5'
2012-06-03 21:37:14 +00:00
f7aae2de4e Add Hungarian translation from TX, thanks AdminLMH! 2012-06-03 13:57:06 +00:00
d1e4d1a715 Apply layout fixes from rev. e3deccd7238bb85c8b21b564b52979e3b3441142 to network.jsp 2012-06-03 09:38:15 +00:00
9435b23ab2 Internationalize a string 2012-06-03 09:23:05 +00:00
bdffd2b8c4 Apply layout fixes from rev. e3deccd7238bb85c8b21b564b52979e3b3441142 to the vanilla theme 2012-06-03 09:19:50 +00:00
590b9a9e05 Handle individual files 2012-06-03 07:20:36 +00:00
86ec61db22 Fix layout issues in recent versions of Firefox and Chromium 2012-05-24 18:33:04 +00:00
45f60e9242 Add translators 2012-04-20 00:11:08 +00:00
56be74a167 Dutch updates from Transifex 2012-04-19 23:31:06 +00:00
14376afddb Translation updates from TX (cs, de, es, pl, & sv) 2012-02-23 12:17:55 +00:00
d2adcd64a7 Fixed bug with "Check mail" button.
Better presentation for "Compose" button.
Some advantages in russian translation
2012-01-01 00:00:00 +00:00
13c19addff copy theme folder 2011-12-17 00:37:29 +00:00
dad6a579c1 Escape & entities 2011-12-17 00:37:15 +00:00
83d585f651 s/wordwrap/word-wrap/ 2011-12-17 00:36:56 +00:00
90ceef4583 Add the ability for users to add their own UI themes 2011-12-15 06:51:16 +00:00
0bf899e291 Update translation 2011-12-14 02:48:25 +00:00
bbdfc5745b * Add theming support
* Add 'vanilla' theme
* Remove unused icon files
2011-12-14 02:44:22 +00:00
c3e6a437c9 HTML/CSS:
* Move CSS out of JSPs
 * Replace layout tables with CSS
 * Make pages variable width
2011-12-10 05:08:12 +00:00
dbe4400409 Internationalize strings 2011-11-27 06:26:59 +00:00
bb5d075a54 Replace no-argument JSP functions with bean properties 2011-11-27 06:01:53 +00:00
5d87d5ec00 Put close() in a finally{ } 2011-11-26 05:06:39 +00:00
d24eea365c Add comment 2011-11-26 04:57:35 +00:00
abd4a55956 Move the two toByteArray methods into the superclass 2011-11-26 04:55:00 +00:00
732b14115b Fix error message 2011-11-26 04:39:13 +00:00
4455fbb172 * Move symmetric encryption to AbstractCryptoImplementation
* Don't use deprecated methods AESEngine.safeEncrypt() and AESEngine.safeDecrypt()
2011-11-26 04:31:35 +00:00
673d43cd86 Use the global context, don't create a new one 2011-11-24 05:23:02 +00:00
b45a162826 Updated (ant poupdate) and pushed to tx 2011-09-23 19:23:44 +00:00
b06d07b5d1 Add Vietnamese language from Transifex 2011-09-23 19:23:16 +00:00
52ac133ffa Add Italian and Ukrainian from transifex 2011-09-23 19:17:23 +00:00
4a240fbb5b Ran ant poupdate for ar and fr. These have been pushed to transifex. 2011-09-23 19:16:52 +00:00
252a7f0dad merge of '6e3866d554a0bce90773691091c5e037aa69cadc'
and '95a0846bd260b60d641a584dceb6ced27aa2e3ce'
2011-09-23 19:01:36 +00:00
1cd51c811d display tooltips in routerconsole 2011-07-20 04:15:26 +00:00
dda1f5b585 corrected version in manual to current release 2011-07-20 03:46:22 +00:00
fb5e1fc4c2 upd i2p-bote messages_fr.po 2011-07-08 14:39:57 +00:00
0e6a32a0a0 Update Arabic po from source and finished translation 100% 2011-06-11 09:23:59 +00:00
d9bc25e1aa translate French strings into Arabic 2011-06-09 13:57:26 +00:00
b124a1046d update .po's 2011-06-02 18:47:29 +00:00
cd21435b60 correction to history.txt 2011-05-02 16:29:02 +00:00
44130323ad typo es 2011-05-02 16:28:38 +00:00
ef339c29d0 Fix: Existing derivparams file not found 2011-04-30 22:28:56 +00:00
8ea8e86d99 Correction to translators 2011-04-30 18:45:46 +00:00
0edf2cfbe3 Replace b32 url with i2pbote.i2p 2011-04-30 18:25:15 +00:00
a4b284a71c 0.2.6 2011-04-25 23:36:22 +00:00
e1b9eb5bbc When replying to an email sent by a local identity, send to the recipient of the original email by default 2011-04-25 00:22:33 +00:00
f45a185502 Update techdoc.txt; remove To Do / Ideas section 2011-04-24 15:06:40 +00:00
be545c0836 Don't run migration if already migrated to the latest version 2011-04-24 15:06:39 +00:00
6c10b8ac64 Fix: signature flag (Email.SIGNATURE_VALID_HEADER) not set on emails in the "sent" folder 2011-04-23 23:35:23 +00:00
92ff6b58f0 Add FileInfo tool 2011-04-23 22:16:26 +00:00
1f54ed9ba8 Change order of parameters in the derivparams file so it matches encrypted files 2011-04-23 21:36:47 +00:00
19452867b4 Fix error messages in log: "Request contains a parameter named recipient0, but no parameter named recipientType0." 2011-04-23 08:35:22 +00:00
1fe6c4fc36 Move illegal <description> tags out of i2pbote.tld 2011-04-23 07:15:44 +00:00
57ead77d39 Capitalize static variable 2011-04-23 06:29:46 +00:00
dd3ed14174 Remove empty directories (see rev. 65aabb15c2a5df2959bdd8987b6ef8959fe3a537) 2011-04-23 06:23:43 +00:00
efc2363ade Translate page title 2011-04-23 06:01:24 +00:00
19a586b170 Integrate FAQ and user guide 2011-04-23 05:59:54 +00:00
3851faff3f Fix a few things in the German translation, and make it more German 2011-04-22 21:29:08 +00:00
a583a1fcc3 Add/fix comments 2011-04-22 20:58:41 +00:00
0464c76884 Wrap (fold) long signatures 2011-04-22 08:28:14 +00:00
2bc05d4d46 Use identities from TestUtil 2011-04-22 07:18:25 +00:00
19970b1d53 Fix: "Check Mail" button brings up an error page if a password is required 2011-04-22 05:54:48 +00:00
035cd346a4 Fix: "constant string too long" when compiling tests with Ant (javac) 2011-04-21 04:56:04 +00:00
cb1d5bbf67 Set encoding to ISO-8859-1 when compiling flexiprovider sources 2011-04-21 04:50:54 +00:00
058d09d262 Pare down flexiprovider some more 2011-04-21 04:48:05 +00:00
14c728c588 merge of '110cd0892a45b8d875bce780895a137da24510d8'
and 'df7b1ac4e3f00852ae445bab6259fb76bd56c5b6'
2011-04-20 03:08:49 +00:00
7823b38d24 Update russian translation 2011-04-19 17:44:33 +00:00
cb76489c0f Use SHA-512 for ECDSA-521 2011-04-18 05:57:28 +00:00
fb0352cd7e Don't create zero-length packet files 2011-04-17 19:22:46 +00:00
b7fcbb5829 Fix plugin target 2011-04-16 22:03:16 +00:00
80a04a70cb Fix IdentitiesTest 2011-04-16 04:58:40 +00:00
b48534b5f7 * Fix: endless JSP forwarding loop when two emails in the same folder have been encrypted with different passwords
* Make PasswordException a checked exception
* Remove unused method AddressBook.iterator()
2011-04-16 04:57:53 +00:00
a1085909e1 ego inflation 2011-04-07 21:50:23 +00:00
dc7777be7f fix about identity creation 2011-04-07 08:20:48 +00:00
0ed58252d9 fix about identity creation 2011-04-07 07:31:13 +00:00
660b77c112 fix about identity creation 2011-04-07 07:15:44 +00:00
1c2fe9a481 typos 2011-04-06 19:37:47 +00:00
dc2d8397ab ug_fr.html saved as manual_fr.odt 2011-04-06 13:20:04 +00:00
926a06e53c end (0.2.6) 2011-04-06 13:03:08 +00:00
7de621dc82 end? 2011-04-06 08:55:16 +00:00
35bf2b930a still wip 2011-04-06 07:24:31 +00:00
307e4e8863 fix Guide 2011-04-05 23:33:57 +00:00
04569977d5 still wip 2011-04-05 18:40:39 +00:00
b11bd7b53b small fixes 2011-04-05 18:16:59 +00:00
4f42050cf2 wip 2011-04-05 17:13:49 +00:00
4b95f34430 wip 2011-04-05 12:22:12 +00:00
e10933cc0e typos 2011-04-05 11:03:54 +00:00
db4c3f23cd wip 2011-04-05 11:03:10 +00:00
3ff443fcc8 upd 2011-04-05 10:28:29 +00:00
3c302441ea upd 2011-04-05 08:32:19 +00:00
250f12a69f upd 2011-04-05 07:50:20 +00:00
cc15bff91b add 2011-04-05 07:24:31 +00:00
9b8828109c testers 2011-04-03 21:43:58 +00:00
72e033e2ef merge of '8bc35fe3851864fad1642e80e73229d6c14d1ba7'
and 'e2e8fcdb307d607cd9d22db33030468d94ec1883'
2011-04-03 20:17:22 +00:00
08f96661fa endend 2011-04-03 19:10:25 +00:00
7bfffe413c Update to BouncyCastle 1.46 which fixes a bug in ECDSA 2011-04-03 06:51:59 +00:00
1425a641ae merge of '4fc6f4c8c7963990ab7f079b86d96b7b8aeb761d'
and 'fd7b2809cdc6fa75aacb97c2ed09a2df4101f41f'
2011-04-03 04:41:16 +00:00
8ed88d1331 ECDH_ECDSA.java:
* Remove exceptions that are declared but never thrown
 * Remove safeEncrypt() TODO, not worth breaking compatibility
2011-04-03 04:40:05 +00:00
a99c08d0e7 typos 2011-04-03 02:17:32 +00:00
c1191d803c translation tweaks es, pt 2011-04-03 00:30:14 +00:00
844f1d3741 translation tweaks es & pt 2011-04-03 00:20:57 +00:00
612753b39e Fix: message not showing when an identity is deleted 2011-04-03 00:11:41 +00:00
cecccddc2e translation tweak es 2011-04-03 00:08:56 +00:00
17073ed8cd translation tweak es 2011-04-03 00:01:19 +00:00
efe14faae4 Move "delete identity" link to editIdentity.jsp and replace the trash can icon with a "delete" button to make it harder to accidentally delete an identity 2011-04-02 23:14:22 +00:00
08aa68d257 Suppress echoing of .bat commands during JRE installation, show a wait message instead 2011-04-02 23:03:12 +00:00
2b9b19030f Undo rev. fcd151e70c681bd38f2677cf4e9be334c7ca4cbe which broke win32installer 2011-04-02 22:27:39 +00:00
87b70ff7bc merge of 'e1744d66f44b6c2f5d1b7d6c2d337c5f2db49687'
and 'fcd151e70c681bd38f2677cf4e9be334c7ca4cbe'
2011-04-02 17:16:21 +00:00
6776b87040 update Swedish translation; thx to hottuna and jaywalk 2011-04-02 12:39:44 +00:00
210ad7f767 Dutch translation updated 2011-04-02 11:34:48 +00:00
3960e41534 Transifex config 2011-04-02 11:26:06 +00:00
32fc56754a Add support for Transifex, fixing po errors. 2011-04-02 11:24:30 +00:00
082f553be4 Create i2pbote.jar in ant_build/lib instead of WebContent/WEB-INF/lib 2011-04-02 02:44:20 +00:00
bcb31dca0a merge of 'a887eef6899db3400a21fb2319e61208d91cbb29'
and 'b156a7cf0018eebcf3ca07c4273a7918ef260ce7'
2011-04-01 19:55:53 +00:00
a508fa1a0f update translations from web-based translations for sv and zh 2011-04-01 19:55:22 +00:00
dbf769a8cb end2 2011-04-01 14:30:28 +00:00
f3825f3890 end 2011-04-01 12:48:58 +00:00
4125ada488 typo 2011-03-31 19:28:24 +00:00
6a425d1880 merge of 'a11d73c48aa593549c58e0caf94c3effd46ad971'
and 'a7d2d9270b5d91a90992345375b12bd392697635'
2011-03-31 01:28:44 +00:00
173c89306f go on and go2bed 2011-03-31 01:23:06 +00:00
8c6e3bedfb go on 2011-03-31 00:47:01 +00:00
db9a13d58d go on. Please user have a look...I PM my 2 questions 2011-03-30 23:38:51 +00:00
fa37238e00 update translation es and pt 2011-03-30 21:07:40 +00:00
2f10c2bb29 update FAQ and Manual 2011-03-30 20:16:16 +00:00
437686b1e6 redo 2011-03-30 19:41:45 +00:00
53508009b9 upd 2011-03-30 17:01:08 +00:00
49ff872b88 go on FAQ_fr 2011-03-30 11:24:38 +00:00
115688de03 begin 2011-03-30 09:17:51 +00:00
346d0cd822 Fix remaining file deletion issues on Windows (see rev. 10d16759d75f1ee7ddcbe3bbf16a826d21345619) 2011-03-28 07:56:28 +00:00
e51c29565e Don't report an error if there is no metadata file 2011-03-28 07:43:49 +00:00
15f209844d Internationalize string 2011-03-28 07:38:11 +00:00
86a50c7986 Update win32installer to work with latest router install.xml, add flexi-gmss-1.7p1.jar 2011-03-27 06:50:46 +00:00
5d44198fef Update German translation 2011-03-27 06:49:38 +00:00
3ab31b8b16 Don't log stack trace when plugin.config not found 2011-03-27 06:48:53 +00:00
4bbab19d14 If no good relay peers are known, query for peers more often 2011-03-25 00:34:24 +00:00
d532c6117d Replace NtruSign with GMSS which uses smaller public keys and inspires more confidence security-wise 2011-03-24 04:38:21 +00:00
63dc3ea208 Fix: Identities and address book still available after the Clear Password icon is clicked 2011-03-16 22:10:00 +00:00
82cb40e9bf Check for null values from I2PSession.receiveMessage() 2011-03-16 19:11:27 +00:00
ec0b072fca Refactor / cleanup:
* Reduce visibility of classes and methods
* Remove unused methods and commented-out code
*
2011-03-16 19:09:57 +00:00
4718424d11 Fix: "Password cleared" message not showing 2011-03-16 17:05:26 +00:00
4300ce67e8 Fix NPE in clearPasswordCache.jsp when password is not in cache 2011-03-16 15:33:11 +00:00
c58a8bb562 Add null checks 2011-03-16 04:30:56 +00:00
55859d669b Remove unnecessary instance variables 2011-03-16 03:51:11 +00:00
e11e80832a Update German translation 2011-03-16 01:31:47 +00:00
e5f7e1e78f Show an icon when the password is in the cache, and uncache the password when the icon is clicked on 2011-03-16 01:25:02 +00:00
6893f5b487 Remove unused constructor UniqueId(InputStream) 2011-03-14 06:20:10 +00:00
d56ccaf436 If Seedless not available, continue trying 2011-03-14 06:18:26 +00:00
1110bbe386 add credits 2011-03-12 03:36:16 +00:00
65290098e6 Add an option to show the full email identity (public + private keys) 2011-03-08 05:33:53 +00:00
5fd314753b 2011-03-08 05:20:56 +00:00
8dd98f2733 Update russian translation 2011-03-07 19:34:05 +00:00
d33882848f Include encrypt.bat and decrypt.bat in the plugin install (I missed this in rev. 01eb620588f85f0d86184be1fb349a43a83fbcfb) 2011-03-06 22:56:56 +00:00
0e174f870c 2011-03-06 22:08:02 +00:00
6954e5c7a8 Change /passive option to /s 2011-03-06 22:04:39 +00:00
8de6a0ab07 Update JRE download link to 6u24 2011-03-06 22:04:00 +00:00
d7cf897072 Add launch scripts for the Encrypt and Decrypt tools 2011-03-06 21:05:09 +00:00
596d19d212 * Add command line programs Encrypt.java and Decrypt.java
* EncryptedInputStream: throw a PasswordException if AESEngine.safeDecrypt() returns null
2011-03-05 23:21:22 +00:00
4e44fc204e merge of '0c43ec8566a97f8ad57f17575db898b259932435'
and '662195feb3df61d6b5a84dea177727d94cedb8b6'
2011-03-03 21:23:00 +00:00
277a535be4 l8tion 2011-03-03 18:13:39 +00:00
1dbd6ebc4c Add Override annotations 2011-03-03 03:46:25 +00:00
bcf869586f Update comments 2011-03-03 03:41:33 +00:00
6b5bc59775 Update techdoc.txt 2011-03-03 03:38:55 +00:00
17feb49b0a Fix: Cached scrypt params and salt not correctly reused 2011-03-02 01:51:21 +00:00
9625566913 update zh translation
adapt gettext script to work under windows:
set $LG2 to update/build ONLY with the language you want.
2011-02-28 06:13:51 +00:00
b2a3308c2e Ignore blank lines 2011-02-28 05:30:55 +00:00
89e5a195f8 Remove extraneous character from destination key 2011-02-28 05:30:41 +00:00
e4c130f51f merge of 'c2a5904fdb10cc3d4cbfa195c557c06cf2f65b5e'
and 'e32e7d661f1c0e4ba49afe94f9b2d89acd40e0d5'
2011-02-28 04:59:29 +00:00
899c0f6796 add credits 2011-02-28 02:11:18 +00:00
fc1287a016 add 安全,分布式电子邮件 and بريد الكتروني الآمن و الغير متمركز 2011-02-28 01:49:40 +00:00
fd3ca21a0c 2011-02-27 23:58:52 +00:00
789f8ddc3f If the forwardUrl parameter is not present in an ib:requirePassword tag, go back to the originating page after password entry 2011-02-27 19:51:50 +00:00
bda40109ed Don't show the "known" and "signature" columns in the sent folder 2011-02-27 17:09:42 +00:00
8c44d3890d Replace PBKDF2 with scrypt 2011-02-27 06:15:53 +00:00
0e2b89dff1 Fix: Duplicate identity created if password was not entered beforehand 2011-02-27 06:07:46 +00:00
7c46127738 fix and update .po's, update de,es,pt,fr 2011-02-27 04:40:42 +00:00
d33b8da111 Fix: PasswordException never thrown when saving/deleting an identity 2011-02-19 20:56:02 +00:00
5d6c30f0bb merge of '4e3d88847518753370c65b8240f9f8a623bb3834'
and '9a74d7db99343b21d83e1fb4d89977feb4b541d2'
2011-02-19 19:37:05 +00:00
7008c26545 Show a wait page if an email identity will take long to generate 2011-02-19 19:36:25 +00:00
b8597014dd Fix anonymous sending of emails 2011-02-17 03:55:16 +00:00
0457bd307f Refactor:
* Rename package i2p.bote.io to i2p.bote.fileencryption
 * Move DHT packets to the DHT package
 * Move relay packets to their own package
 * Move ExpirationThread to i2p.bote.service
 * Rename RelayPacketTest to RelayRequestTest
2011-02-17 02:23:10 +00:00
eb446f8703 Add Arabic translation of the plugin 2011-02-16 19:25:19 +00:00
9df307365c Show attachment sizes 2011-02-14 03:12:05 +00:00
fcd4fb63ed New CryptoImplementation: NTRUEncrypt1087_NTRUSign349 2011-02-14 00:11:37 +00:00
27713fb7b6 Remove unused method 2011-02-13 19:23:58 +00:00
0db3ce5026 Make the default status translatable 2011-02-13 19:14:54 +00:00
0f04c2c51a Display an error if the attach button is clicked and no file is selected 2011-02-13 16:35:11 +00:00
206be17615 Show the first few characters of the email destination in the "From:" drop-down 2011-02-13 06:08:26 +00:00
2511c5b851 2011-02-13 04:34:23 +00:00
4db98b2c2b Fix RelayPacketTest 2011-02-13 04:31:05 +00:00
8d2d360180 Fix email deletion on Windows 2011-02-13 03:50:19 +00:00
7d7b509eb9 initial translation for chinese 2011-02-10 16:02:26 +00:00
124ca1ba62 Inform user when an update is available 2011-02-05 23:24:52 +00:00
e9cd4a9f6c * Send big packets as a stream
* Don't rely on InputStream.available() in Util.readBytes()
2011-02-05 16:10:41 +00:00
c627299a35 Fix: All input after first flush() is dropped 2011-02-05 15:53:56 +00:00
e0f183efa8 Comments 2011-02-02 19:30:09 +00:00
89395885ba Fix a NPE 2011-02-01 05:41:53 +00:00
a77309ab36 Change constant scope to private 2011-01-31 07:33:03 +00:00
efd04f322c Remove unused method getMaxFragmentSize 2011-01-31 07:09:42 +00:00
a12f90d432 merge of 'a0f3953b8929001edc2b9d59c3bf314040fc4c7b'
and 'fd9b359f0a1eb07fcc4c0c8ec5abe95a0bc073dd'
2011-01-11 19:29:29 +00:00
5919da4930 merge of '62dcd55b7726aedd5624b076d838cbd11787695a'
and 'cb7ee59eaf0eb93c0dcb91a8226591ca01e51342'
2011-01-11 19:22:47 +00:00
2d291f1ce2 added credits 2011-01-02 05:45:53 +00:00
e299d2e83d Quick fixes to Swedish translation. 2011-01-01 21:54:22 +00:00
76551e3d3f Added Swedish translation. 2011-01-01 21:47:34 +00:00
2f134bfbe4 add translation to Norwegian 2010-12-31 07:01:23 +00:00
c03c481b94 merge of '9a8a529946e94b430d154a127ca08010f15d66d5'
and 'cc0e869985b06631a79b60bf1060d86cc0e88afd'
2010-12-31 01:09:35 +00:00
7d1fed76da mods to pt 2010-12-29 15:51:57 +00:00
7148172e9c New unit test: PasswordCacheTest 2010-12-22 06:01:17 +00:00
5c102da3a0 * Reset expiration when a password is set
* Clear derived key when password is cleared
2010-12-22 05:49:18 +00:00
f3a1c618e5 merge of '243e68f714882dc1fe2f79958b31ac862053ba9f'
and 'f9ab92a43553dde223bb24940d32f19a60022b34'
2010-12-20 05:38:39 +00:00
5c221f31d9 Add missing copyright notices 2010-12-20 00:42:37 +00:00
7ac42c0e4e translation updates 2010-12-19 23:32:17 +00:00
4da3ee6aed New Ant task: win32installer 2010-12-19 23:00:50 +00:00
3aecc56933 Restore plugin.config after mismerge 2010-12-19 22:27:47 +00:00
5ea124b7d2 Jetty fix 2010-12-19 22:22:17 +00:00
7fb33a0d35 Fix return to folder.jsp after password entry 2010-12-19 22:21:04 +00:00
6d2878db5c * Add jMock .jars to JUnit classpath
* Offer to download JUnit and jMock if they're not found
2010-12-18 03:46:00 +00:00
9bee5057f1 merge of '0b216d7818b91cf69fdfb88048dfcbfbfce02833'
and 'de95731855e9e7f8a81b42642fd566ac6ee76c08'
2010-12-17 19:54:42 +00:00
bdce2ecad5 merge of '561ea16dc8eb82dc348dca962f30e579c8ed3d63'
and 'b1b87fc5a28b9aad267b6c3aeddc1c23377c5ab6'
2010-12-17 19:54:42 +00:00
d3ee66ff60 * Remove unused method toBase32
* Replace instanceof with getClass() in equals()
2010-12-17 03:43:44 +00:00
647efead3b Fix unit tests; jMock now required to run them 2010-12-17 03:41:57 +00:00
09f5d107c9 translation update de 2010-12-17 02:01:47 +00:00
d33bc11a31 Contributors update 2010-12-16 01:27:09 +00:00
2d6066ad58 Remove serialVersionUID from non-serializable class 2010-12-16 00:40:21 +00:00
0bdd216ef0 Remove an obsolete comment 2010-12-16 00:39:08 +00:00
75336e899d Fix an import 2010-12-16 00:28:22 +00:00
3870ca5335 plugin.config nl link translation 2010-12-13 18:46:26 +00:00
5aaae853af plugin.config translation 2010-12-13 16:39:01 +00:00
a64cdca34e merge of '0039d7fd449038234648a57ff05906383d0ce75d'
and '92c193a4f6709ce5205a43617bcd8a144ae598ca'
2010-12-13 11:52:48 +00:00
99f64adc05 merge of 'b85935006af43967ba763bb53ab75c6f0278c539'
and 'eff65f71bc633578ad72cbcb2d5301f1d1766c30'
2010-12-13 11:52:47 +00:00
05c24ab545 explicit merge of '93973b70de2d4a41180a7d2f201b684e5ea6d445'
and '451bb8a70baa411c0d401c329b5b60b7c14d09b3'
2010-12-13 11:44:04 +00:00
897d43ff51 Fix a typo 2010-12-13 11:42:56 +00:00
46b9e3a039 explicit merge of '7ca94be8ef990b10920f144f441a51d239d33c48'
and 'ef38ab9835eb8fec5dbd981f2951d12d5d0d5d0d'
2010-12-13 08:06:21 +00:00
018209bed5 Dutch translation by KwukDuck 2010-12-13 08:03:04 +00:00
fe14f97dfd explicit merge of '5c7fd9edde41ff7c26cd2fb28e1a46b96c1f8538'
and '9245efd7b168684236148a7102535f0a009e2c4f'
2010-12-13 01:39:10 +00:00
f2b1d3cc1c Portuguese translation 2010-12-13 01:13:25 +00:00
0600b6e595 merge of '08eff6bfa6a2b340f314f1de096c771337eb3a3b'
and '1dbb023c5b2674f49708ad83060aed35cdb3a7a1'
2010-12-12 20:10:11 +00:00
aab0b139d3 * Don't encrypt meta files
* Don't attempt to convert a non-existing directory
2010-12-12 20:06:18 +00:00
872c386929 Focus the "old password" field 2010-12-12 20:03:19 +00:00
23f57da28e * Cache file encryption key, reuse salt for performance
* EncryptedOutputStream: Cache key, not password; keep a copy of the key until close() is called so the key is not lost when the original is erased by PasswordCache
* Prevent password expiration during password change (which can take some time)
2010-12-12 20:01:09 +00:00
7fbd29b75d File encryption 2010-12-10 20:10:49 +00:00
b8fd5b5c1d Add TO-DO note for HH to do an important fix. 2010-12-07 00:36:20 +00:00
c81f2cb46c merge of '43b11afe7287401107616e5cff0c1d4773c0e1d3'
and '92344efb7a96786e8ef1e256f754ea8e9666c765'
2010-12-07 00:23:23 +00:00
6c859388c5 changes to Spanish translation 2010-12-04 10:56:38 +00:00
087b8ddc42 changes to the manual 2010-12-04 10:52:54 +00:00
0eba059a8c merge of '28760fe7e19dd265a2ede35a51f73e5c07b1a2aa'
and 'db84face38fdd977157aaf02c444b894c7049d84'
2010-11-28 06:45:44 +00:00
7136ab215c Refactor out Deprecated destFromName calls, fixup nb files 2010-11-28 06:45:22 +00:00
3f867d8041 plugin.config: add russian translation 2010-11-20 19:29:23 +00:00
a8bb3652fe added string to plugin.config and a minor correction 2010-11-16 22:34:07 +00:00
1672d95ae6 merge of '2e376f13320c297b93e734b3f39e113752891578'
and 'f2d47e61537a5a2f2077eae200af07ef12114b2e'
2010-11-11 21:01:03 +00:00
c3c832649c update manual 2010-11-11 21:00:10 +00:00
c115278016 merge of '6b7cd0a43c55b9a2ae53778a25e6940cfe4fba1f'
and '9245efd7b168684236148a7102535f0a009e2c4f'
2010-11-11 17:32:29 +00:00
a65653b30b Spanish translation for Bote; fixes sent in by Redzara to French translation 2010-11-11 17:31:18 +00:00
d92f66720a merge of '37af2db09b85c46e860280cdb70d92bf07810401'
and 'df5454597876a5df6f61e5adb97d30fb57b63d48'
2010-11-04 06:57:33 +00:00
0954398245 minor corrections 2010-11-03 18:10:46 +00:00
50da5ccc80 Fix a NPE 2010-11-03 06:09:00 +00:00
2b71438c82 French translation by albat and mixxy 2010-10-29 20:19:23 +00:00
1b5356e845 Fix a comment 2010-10-26 20:24:52 +00:00
9c951dc2f1 Fix a NPE 2010-10-26 18:27:11 +00:00
117c35cc5a * Sign email before saving to sent folder
* Don't hide signature column in folder.jsp. It was a kludge, signing before saving is the right way to do it.
2010-10-14 19:02:11 +00:00
dbd46e2b4f Comments 2010-10-03 22:06:20 +00:00
a2c55a78fc 0.2.5 2010-10-03 22:05:54 +00:00
c423b7331e Implement KBucketTest 2010-10-03 21:59:48 +00:00
a031f4da28 Decrease text field width on the "new email" page 2010-10-03 19:19:15 +00:00
7573eed929 Minor things 2010-10-03 19:13:53 +00:00
1e78638692 Refresh folder list when new mail arrives so the inbox message count is updated 2010-10-03 08:07:48 +00:00
19ea512d79 Fix: Two new recipient fields appear when the "plus" button is clicked after entering text in the existing recipient field 2010-10-03 07:25:07 +00:00
b9155254d0 Use base64 for RelayPacketFolder filenames, which is what all other folders do 2010-10-03 00:19:14 +00:00
0ebe7e68c7 Update techdoc.txt 2010-10-02 22:50:02 +00:00
48340cb790 Update manual 2010-10-02 20:14:24 +00:00
02b803fda7 Fix duplicate "Unknown" in the date/time column in folder.jsp 2010-10-02 19:49:41 +00:00
4d306d5f85 Translation update 2010-10-02 19:47:05 +00:00
388843a439 Implement reading from ByteBuffer and writing to OutputStream 2010-10-02 18:34:56 +00:00
e03521821a Make the outbox check interval a config setting 2010-10-02 06:23:40 +00:00
ac77853485 Fix display of date/time in showEmail.jsp 2010-10-02 04:57:30 +00:00
ce664ebf8b * Use a non-deprecated variant of ElGamalAESEngine.encrypt()
* Do ElGamal/AES in the new methods Util.encrypt() and Util.decrypt()
* Use a min padding size of zero when calling ElGamalAESEngine.encrypt()
2010-10-02 03:51:59 +00:00
93041cb1d4 Simplifications:
* Get rid of RelayDataPackets, put everything in RelayRequests
 * Put a packet ID in all Communication Packets (most of them had it already)
 * Combine MalformedCommunicationPacketException and MalformedDataPacketException into MalformedPacketException
2010-10-02 03:00:53 +00:00
d68fd5429e Log deletion of relay packets 2010-09-30 05:50:03 +00:00
a7b4b9acc6 Pad relay packets 2010-09-30 05:11:42 +00:00
20841b7a4a Remove the unused and confusing Email Address field from the Edit Identity page 2010-09-27 05:54:08 +00:00
e7f186b7f3 * Write to metadata the time an email is created
* Add a "create time" column to the outbox
* Make "create time" the default sort column in the outbox
2010-09-27 05:37:27 +00:00
2a2adc6645 Change a few more logging statements I missed in rev. 6c3cec9cf9ac70dadd403a2f2bc10a5be18f1fbd to print peers in base32 2010-09-26 19:52:11 +00:00
9989940693 * Fix NegativeArraySizeException when a two-byte length field in a packet contains a value greater than Short.MAX_VALUE
* Keep packet size below I2PBotePacket.MAX_DATAGRAM_SIZE, take into account relay packet overhead
2010-09-26 18:51:49 +00:00
f71f0e1470 Show a message after saving settings 2010-09-25 07:32:00 +00:00
3c7bd9acf6 Simplify folderLink.tag by using folder.jsp for the outbox; see rev. 7790618d3eba2f460983f87db7ddc1fe1b94053c 2010-09-25 07:11:58 +00:00
1439358221 Take the user back to outbox.jsp after an outbox email is deleted 2010-09-25 06:48:31 +00:00
0895c3c976 Sort by name and destination, not just name, so different destinations/identities can have the same name 2010-09-25 06:45:53 +00:00
8a6c6c2627 Fix non-ASCII characters in the New Identity / Edit Identity form by changing it to POST (should be POST anyway) 2010-09-24 06:50:08 +00:00
c3883bb069 Make the "unknown" column a "known" column, show a check mark when an email dest is known 2010-09-23 05:52:06 +00:00
4e5104ff52 Show status for outbox emails 2010-09-23 05:29:22 +00:00
ecf093119a Reduce default delay to 5..40 minutes per hop 2010-09-23 05:04:26 +00:00
cbd7a8dffb Don't show signature column in "sent" folder 2010-09-23 04:57:37 +00:00
08cd5406f4 Sort address book and identities by name 2010-09-23 04:06:10 +00:00
af2f63565f Update technical documentation 2010-09-22 17:38:34 +00:00
1b481dcf24 Add user manual by mixxy, delete userdoc.txt 2010-09-22 17:38:15 +00:00
6ee5005944 Align Sent Time 2010-09-22 07:18:27 +00:00
b4b94ad38a Log peer destinations in base32 2010-09-22 06:21:57 +00:00
aa4551fc14 Show local destination and peer destinations in base32 2010-09-20 05:18:46 +00:00
9d77f57123 Add a note about attachment sizes 2010-09-20 03:31:11 +00:00
3115faedb2 Fix comments, remove unnecessary braces 2010-09-20 02:37:46 +00:00
4e7b0c115e Keep trying to send an email if there is an error 2010-09-20 02:27:33 +00:00
c28c99060b Replication:
* Replicate onto the closest nodes to the packet's DHT key instead of the local destination hash
 * When a packet has been re-stored since the last replication, assume it has been stored on all closest nodes and don't replicate it to any peer
 * When a delete request is received for a replicated packet, stop replicating that packet and replicate the delete request instead
2010-09-19 08:31:36 +00:00
d3a072c54b * Don't replicate packets that were recently replicated
* Log number of replicated packets
2010-09-16 05:06:44 +00:00
174a94f492 Fix: ReplicateThread.packetStored() not called when storing in a DeletionAwareDhtFolder 2010-09-16 05:02:12 +00:00
9f6806a738 Verify hashes of received email packets against the DHT key 2010-09-15 06:50:52 +00:00
809dc90bc8 Fix non-ascii characters (switching from Commons FileUpload to JavaMail-based multipart parsing broke them) 2010-09-09 06:04:40 +00:00
c14faf5fc4 Lower the LZMA dictionary size, 2^24 causes heap space errors when running as a .war in the router 2010-09-07 07:40:03 +00:00
d9034fee31 Change a few log levels 2010-09-06 22:56:27 +00:00
c30180fcbf Remove newlines from the end of files (just a personal preference) 2010-09-06 22:46:58 +00:00
110a4bd484 Fix LZMA dictionary size 2010-09-06 19:46:47 +00:00
06106c0b57 Use isProtocolVersionOk() for version checking, see rev. c848aa079ff8d62fac18c1c7782d48befc13b98d 2010-09-06 19:44:32 +00:00
a006e3b688 Use different texts for the two test emails 2010-09-06 07:53:18 +00:00
d37911e5b1 Add a new field containing a Return Chain to the Relay Request format. Only empty return chains are supported for now. 2010-09-06 07:10:35 +00:00
b128693296 * Talk to peers that use protocol version 4 or higher
* Do the version check in one place (I2PBotePacket.isProtocolVersionOk()), not two
2010-09-06 06:32:37 +00:00
85d958a0cc Add Russian translation by suhr 2010-09-05 19:59:11 +00:00
ca1d5e6d8c Update RelayPacketTest to use the new file format introduced in revision bfde50fb7c22410d7859a6914990798c68127bc5 2010-08-25 02:28:48 +00:00
245e50aaa9 Count emails with no metadata as new to match the behavior of the EmailMetaData class 2010-08-22 20:49:33 +00:00
4d0d5d245c Minor things 2010-08-18 20:58:51 +00:00
f1d8554ab3 Put a space between name and angle bracket 2010-08-18 20:56:42 +00:00
c76a33fa69 Fix: Extra blank char after the name when clicking "add to address book" in an email 2010-08-18 20:48:21 +00:00
5a3e49c4dd Replace Thread.sleep() with awaitShutdownRequest() 2010-08-18 04:33:57 +00:00
2ad8d2ac8e Fix: Folder view only shows the recipient if it is a local identity 2010-08-18 04:32:38 +00:00
d0c4fd7ca8 * Only use the last 20 peer list requests / responses to calculate reachability
* Increase RelayPeerManager.UPDATE_INTERVAL to 60 minutes
2010-08-18 03:05:28 +00:00
6b38f0d520 Comments and other minor things 2010-08-17 17:52:33 +00:00
0105bb360a Cleanup 2010-08-17 17:47:54 +00:00
35d22a9638 * Fix: EmailPacketFolder.storeAndCreateDeleteRequest() does not correctly handle multiple deletion records in the same DEL_ file
* Fix: Delete verification hash contains the same data as the delete auth key. Apply SHA256 so the delete verification hash actually is the hash of the auth key.
2010-08-17 17:41:25 +00:00
2cce8c9a7a Remove option to set the UI language, always use the router console setting. The language option was changing the router console language, so it was kind of pointless. 2010-08-16 19:44:13 +00:00
a525c3d920 * Rewrite of MultipartFilter: Use javax.mail.internet.MimeMultipart for multipart parsing, get rid of commons-io and commons-fileupload.
* Move attachment adding code in SendEmailTag.java to Email.java
* Encode attachments in 8bit rather than base64 because base64 negates compression
2010-08-16 08:41:37 +00:00
8f090fd3e3 Clean up test folder when finished 2010-08-12 06:10:49 +00:00
c36b24bad6 * Comments, Formatting
* Move ProxyRequest.java into the seedless package because it is only used there
2010-08-12 06:08:31 +00:00
9b8fd8e6fc * Store metadata files along with email files
* Move the new/old flag to metadata (no more N_ and O_ filename prefixes)
* Write the received time to metadata when an email is received
* Use the received time as the sort criteria when an email has no sent time
2010-08-12 05:46:56 +00:00
078f0952ef Fix an NPE when trying to connect before Seedless is initialized 2010-08-01 06:21:11 +00:00
834331903e * Don't set the Date header if it is already there
* Slight code simplification
2010-08-01 06:18:55 +00:00
b112ad89f3 * Remove KademliaDHTTest (would have been to complicated to implement)
* Add KBucketTest (does nothing yet)
2010-08-01 01:26:12 +00:00
73f8295c9c A few little things 2010-08-01 01:23:25 +00:00
c2da679543 * Make getFilenames() protected
* Remove individualPackets() override in DeletionAwareDhtFolder which does nothing
2010-08-01 01:21:27 +00:00
ac46459a0d Send a specific delay time in relay packets, not a min/max range 2010-08-01 01:16:37 +00:00
c663415ebc Add includeSendTime parameter so Email.updateHeaders() doesn't have to call I2PBote.getInstance(). It also has the small benefit of the "include send time" setting being determined at the time the user clicks Send rather than the time the email is sent from the outbox (which doesn't always happen instantly, for example when there is no network connection yet or several emails are queued in the outbox). 2010-08-01 01:08:38 +00:00
68f9360f40 Folder.iterator(): Don't return null if an invalid/unreadable file is encountered, skip it instead 2010-08-01 00:43:45 +00:00
e0436d1e43 * Do not exit background threads on unchecked exceptions
* I2PBote.java: put all background threads in a Collection like sponge suggested
* Do automatic and user-initiated email checking in one class (EmailChecker)
* New interface NetworkStatusSource, used by OutboxProcessor and EmailChecker
* Several other changes
2010-08-01 00:20:52 +00:00
a488294bb3 Convert tabs to spaces 2010-07-29 00:29:50 +00:00
175345dfe4 Shut down EmailPacketTask threads when the tasks are finished 2010-07-25 05:09:12 +00:00
78bb4f7366 Fix member field name in comment 2010-07-24 07:50:08 +00:00
29f485f4e2 Fix: Reachability of relay peers changes to 100% after startup 2010-07-24 07:47:58 +00:00
b794aaf0e0 Remove unused methods 2010-07-24 02:17:22 +00:00
465d509bcc * Autorefresh "inbox" and "sent" folders
* Autorefresh outbox if it is not empty
2010-07-19 05:39:51 +00:00
a4b25f0ae8 Stop refreshing when the CONNECTED or ERROR status is reached 2010-07-19 01:26:26 +00:00
7feba2f15e * Don't disable the "new email" button
* Refresh the frame until the Check Mail button becomes ungreyed
2010-07-19 01:22:20 +00:00
2e72fb7f36 Don't send email if no recipient, show error message instead 2010-07-18 05:48:17 +00:00
a225fa20b1 Fix NPE when sending before connected 2010-07-18 05:47:22 +00:00
f87fe26811 javadoc Ant target, javadoc formatting, documentation 2010-07-17 22:52:24 +00:00
d2b38a3f33 merge of '34a49b587bbb0c309e60a1df7a9a792654e48fd2'
and 'bf83f8762c1d6cfaa71871d32bdc9a3e089058c1'
2010-07-16 15:41:45 +00:00
ef8a143eb0 Ant build file:
* Use I2P libs from $I2P/lib instead of the mtn working directory
 * More help text
 * Check for presence of the I2P env variable
 * Add "src" to the "all" target
2010-07-16 07:07:48 +00:00
e33d186ed0 When writing a file or creating a directory, set permissions to readable / writable only by owner 2010-07-15 05:20:57 +00:00
0527c1f246 Fix counting of #lines read 2010-07-14 18:46:20 +00:00
7ee570e375 * Translate the string for the outbox status "Queued"
* Remove an unused method
2010-07-14 07:09:14 +00:00
c7182a27cf Remember the selected sender identity when leaving the "new email" page (via the address book button) and returning. 2010-07-14 07:05:57 +00:00
f972c9e2e6 Fix: MultipartFilter drops request parameters that are added via jsp:param in a jsp:forward 2010-07-13 07:52:44 +00:00
29df785ab6 merge of '9c9772d22e302d48a4c849c18c8ff3bcb3ff8404'
and 'e09e454db05d06c660ba0e8e2ff5021aa52ec787'
2010-07-12 06:14:06 +00:00
e3448c9b17 Added needed jar files to project.xml for NB 6.5 2010-07-12 04:29:16 +00:00
a3a8c77963 merge of '3e369acec144cfce4278be9456f6b81de0455791'
and 'dc2bcd3d2bdc8b5c7462377da7462d3f5108b3ee'
2010-07-12 03:48:39 +00:00
67dab8aaf7 merge of '3e369acec144cfce4278be9456f6b81de0455791'
and 'dc2bcd3d2bdc8b5c7462377da7462d3f5108b3ee'
2010-07-12 02:14:52 +00:00
7c2fc47933 Refactor of Seedless:
* Move the doSeedless* methods out of I2PBote.java into the Seedless* classes
 * Move the other Seedless stuff into SeedlessParameters.java
 * Don't inject peers into DHT, call a getter on SeedlessScrapePeers instead
 * Many little things
2010-07-11 23:17:33 +00:00
0a3a2bedf8 Add commons-fileupload-1.2.1.jar and commons-io-1.4.jar to build file 2010-07-11 22:56:17 +00:00
38ab0630af Change announce to 60 minutes to deal with new inter-server transfer specs.
Announces should be done once within 1/5th of it's TTL 72 minutes for bote.
2010-07-11 11:23:41 +00:00
d6be15ca4d * Fix for a bug in the multipart code that broke sending of emails on Jetty
* Ditto for non-ASCII chars not being encoded properly
2010-07-11 00:49:43 +00:00
77ec925d45 Post-merge cleanup. This revision diffs cleanly against 14ada4dcae2f555f4b5539305e32f96bafec675e (the last rev before Seedless). 2010-07-07 05:14:08 +00:00
2bd6eac5af merge of '15679f7110fe5f55407d2d04c63bc18e1d460113'
and '289456e0b294a38c3d0e75d69873d614170f9e58'
2010-07-04 07:42:56 +00:00
50673b6358 Comments 2010-07-04 07:28:05 +00:00
ee578e7b06 Use a SHA256 hash rather than random data for the base32 part of the filename to avoid creating a new copy if a packet is received more than once. 2010-07-04 07:26:14 +00:00
4025734680 * When a relay packet is received, acknowledge receipt to the sender
* Resend relay packets until acknowledgement is received
2010-07-04 07:22:14 +00:00
2bbba38007 * Attachment support
* Lower the priority of some background tasks
2010-07-03 21:59:14 +00:00
479b28f35f Fix: Corrupt padding error with ECDH when the input size is a multiple of 16 2010-06-30 18:36:06 +00:00
07a3340ffa Depend on Seedless _first_, then fallback to built-in, as per HH. 2010-06-28 21:10:51 +00:00
69f289b0d9 Fix annoying NPE 2010-06-25 14:57:59 +00:00
308330c8a0 Success!
We now turn off Seedless peer searches and scrapes when network is connected.
Announce to random ordered Seedless servers.
Thanks to ALL our testers, especially superuser and darrob. 
Thier feedback was very valuable!
2010-06-25 14:50:50 +00:00
aac785dda8 Specify PROTO_DATAGRAM, PORT_UNSPECIFIED, and PORT_UNSPECIFIED when sending.
The default uses PROTO_UNSPECIFIED, which isn't what we wanted.
2010-06-25 13:45:31 +00:00
6bd4cab290 Muxed depends on gzip == true? 2010-06-25 06:49:04 +00:00
816eb59c94 Compress emails before encrypting them 2010-06-25 02:36:15 +00:00
889a28063d * Add sponge as a contributor
* Replace HungryHobo email address with email destination
2010-06-25 02:18:43 +00:00
a783a0ddb8 Salt relay peers like bote does 2010-06-24 22:41:17 +00:00
617122dfe1 Fix NPE. 2010-06-24 20:19:31 +00:00
e471ddd57a Added injection to relay peers as well. This possibly isn't the correct intent. 2010-06-24 20:06:28 +00:00
1999eb2432 merge of '7561cf99368e4a244f4b67c350c0c92f7a1afc08'
and 'a74daea914c9a98d3953dbe4e2507b4ad032ae66'
2010-06-24 17:56:14 +00:00
a22eea0f66 - 2010-06-24 17:55:44 +00:00
62a1a85a8f zap comment 2010-06-24 09:41:21 +00:00
dev
00fbabded2 merge of '5ee8d2f16550b6e4181d9123c069dd8e800059de'
and 'f9c92102d1893e1d6e2597ce50dd617256a4aee3'
2010-06-24 07:46:04 +00:00
dev
53a052382f . 2010-06-24 07:26:58 +00:00
66b970d22b disapproval of revision '0c7dc27eead74ddbe0d89793014d5c1cf2e35b2f' 2010-06-24 06:58:57 +00:00
2b5ce8cf27 And now we hope it is set correctly.
disapproval of revision 'f9c92102d1893e1d6e2597ce50dd617256a4aee3'
2010-06-24 06:26:03 +00:00
408f63bdf9 Hopeful fix to the commits that mtn seems to have goofed up on.
There is nothing in this patch.
2010-06-24 06:24:25 +00:00
1ce75177e9 Change for log debugging. 2010-06-24 06:18:55 +00:00
0df770bc68 Temp fix. See comment KademliaDHT.java ~line 364 2010-06-24 06:12:06 +00:00
120de4af9e Fix stupid bug *embarrassment* 2010-06-24 03:03:50 +00:00
b557973e79 Should work with passworded routerconsole,
Don't know if the injector works right. Needs testing, etc.
That's the part HH needs to finish if it is incorrect.
2010-06-24 03:00:52 +00:00
6b833622cf Seedless:
Can scrape servers
  Can scrape peers
  Can announce
  Can't work with a passworded router console yet.
2010-06-22 18:13:51 +00:00
99baa56af3 Apply patch by zzz to abort the build if <exec> returns non-zero. 2010-06-20 05:20:21 +00:00
95ac52b7ea Increase expiration times in testCheckExpiration() to fix test failures reported by one user. 2010-06-20 05:16:58 +00:00
e4696b2bad Add Netbeans 6.5 Project file 2010-06-18 13:17:50 +00:00
00226dfe4d Remove some unnecessary files from the src target 2010-06-14 08:09:20 +00:00
c0ad846a3d 2010-06-14 07:07:13 +00:00
9a0226674f 0.2.4 2010-06-14 07:06:28 +00:00
5d5a4bc50f Fix "Gateway disabled" error with non-gateway emails 2010-06-14 07:06:06 +00:00
2976f10d92 Don't unnecessarily send a IndexPacketDeleteRequest if there is nothing to delete 2010-06-14 07:00:36 +00:00
9ac0fd128d * Set the X-I2PBote-Sig-Valid header when an email is received
* Use the X-I2PBote-Sig-Valid header flag to determine if an email has a valid signature; only verify the signature if no X-I2PBote-Sig-Valid header
2010-06-14 06:58:45 +00:00
4062cfa97c Restore contents of built-in-peers.txt which I accidentally changed when I moved it to a different package 2010-06-13 07:35:09 +00:00
ff0d6e2ff2 * Change console link name
* Use a b32 update URL
2010-06-13 07:27:34 +00:00
9461bc1edb * Don't use protocol v2 peers as relay peers, put them on the ban list
* Fix: BucketManager doesn't ban unknown peers if they use the wrong protocol
2010-06-13 07:25:15 +00:00
f06e936e10 Update translations and fix a few strings 2010-06-13 07:19:30 +00:00
f90f6059c3 Minor things 2010-06-12 07:40:21 +00:00
f529cd3db0 Gateway (in/outproxy) support 2010-06-12 07:39:37 +00:00
a9a0a5202e Fix sending and displaying of anonymous emails 2010-06-11 20:11:19 +00:00
67a871814e Start peers out at 0 reachability 2010-06-11 20:01:57 +00:00
24d2f2fd9a Suppress two warnings in the ant "compile" target 2010-06-11 07:15:41 +00:00
c3a3a19751 * Include bcprov-ecc-jdk16-145.jar
* Fix path to built-in-peers.txt which has moved
* Don't add jstl.jar and standard jar to the war
2010-06-11 07:12:59 +00:00
37643b15b7 Use 'outbox', not 'outbox/local' for the outbox dir 2010-06-11 02:42:53 +00:00
defbb68445 Make packet type codes compatible to the older packet version so no exceptions are thrown when v0.2.3 peers and v0.2.4 peers try to talk to each other 2010-06-11 02:28:07 +00:00
744c1c1b61 Fix: Existing IndexPackets get lost when adding a new one to the IndexPacketFolder 2010-06-11 02:18:03 +00:00
88e0f5c081 More tests 2010-06-10 18:30:24 +00:00
01eb01dc24 Minor 2010-06-10 08:32:40 +00:00
03dac6db84 Shut down replicateThread when Kademlia shuts down 2010-06-10 08:25:45 +00:00
535dd76c8e * Start / stop the RelayPeerManager service on app startup / shutdown
* Move RelayPeerManager to i2p.bote.service
* Keep reachability statistics on relay peers
2010-06-10 08:24:53 +00:00
e211b1040c Cleanup 2010-06-09 23:22:08 +00:00
8533790aa3 Logging tweak 2010-06-09 20:37:32 +00:00
09a271ba12 Fix NPE when sending email before DHT is done bootstrapping 2010-06-09 20:21:24 +00:00
09337fa259 Minor things 2010-06-09 20:19:40 +00:00
97a93db976 * Fix: Relaying does not work with more than one relay peer
* Add remaining relay-related files
2010-06-09 20:13:49 +00:00
9c9b4b5404 Fix: sentSignal and sentTime were not initialized in one of the CommunicationPacket constructors 2010-06-09 03:11:17 +00:00
9212075b08 Call removePacketListener() even if an exception occurs 2010-06-09 03:08:38 +00:00
0c95890d77 Minor things 2010-06-09 02:48:02 +00:00
135190058a Implement sending of emails through relays 2010-06-09 02:12:13 +00:00
ff87fa0a78 Remove an unused class 2010-06-09 01:34:42 +00:00
ed1b2bcdd2 Start OutboxProcessor and ReplicateThread when Kademlia is finished bootstrapping 2010-06-05 04:51:44 +00:00
6b796c1715 Remove unused constant STALE_THRESHOLD 2010-06-04 06:29:16 +00:00
cdfbd98612 Cleanup 2010-06-04 06:25:58 +00:00
8e471d84a1 Add a paragraph about encryption algorithms to noIdentities.jsp 2010-06-04 06:25:19 +00:00
db72661f57 Implement ECC-256 2010-06-04 06:24:10 +00:00
5524b4b563 Periodically replicate email packets and index packet entries onto other nodes 2010-06-04 06:15:17 +00:00
6488aeac56 Preliminary work for packet replication: Keep a record of (locally) deleted email packets, like it is already the case for index packet entries. Use one common format (the new packet type DeletionInfoPacket) for both packet types so Delete Authorization Keys don't unnecessarily take up space in Index Packets. 2010-05-29 10:05:11 +00:00
91e6daa303 Some minor stuff 2010-05-28 07:12:20 +00:00
f56c3ca1bf Read the Delete Authorization Key from an UnencryptedEmailPacket, not from a received Index Packet (because it's always zeroes) 2010-05-28 07:10:29 +00:00
8c5b402edf * Zero out Delete Authorizations before sending a response to an Index Packet retrieve request
* When an Index Packet Delete Request is received, compare the hash of the Delete Authorization against the local Delete Verification Hash, not the local Delete Authorization (which is always zeros)
2010-05-28 07:04:35 +00:00
50eb754d19 Add license.txt 2010-05-27 03:04:11 +00:00
ae41a90478 Use the AES implementation that comes with I2P instead of a JCE provider because the Sun JRE makes it a PITA to enable "unlimited strength encryption" in an end user friendly manner. Fortunately, only AES is affected by the crypto restrictions.
Another problem with the Sun JRE is that it makes it near impossible to ship only a subset of the 1.7 meg BouncyCastle .jar. The .jar has to be signed with a key certified by Sun, which is a lengthy process that involves giving Sun a DNA sample and sacrificing an animal in front of their headquarters. So the ECC code now uses the BouncyCastle API instead of JCE.
2010-05-27 02:11:58 +00:00
892a795c68 Remove an unused method 2010-05-25 20:50:07 +00:00
d2634bd130 Fix a potential lockup 2010-05-25 20:49:35 +00:00
6a482911b3 Minor stuff 2010-05-25 20:46:18 +00:00
35f1320ef1 Delete email packets and index packet entries that are more than 100 days old 2010-05-25 20:42:48 +00:00
6a9729f898 * Add BouncyCastle ECC library (a subset of bcprov-jdk16-145.jar that only contains the ECDH/ECDSA provider)
* Add BouncyCastle license
2010-05-25 20:14:30 +00:00
a064857ff5 Minor things 2010-05-22 01:48:13 +00:00
3fab712da7 Add null checks 2010-05-22 01:45:47 +00:00
d4542b8449 Add some missing license headers 2010-05-22 01:32:05 +00:00
366fa10ce8 Several changes to the packet format:
* Add time stamps in preparation for packet expiration
 * Change a few packet type codes
 * Support addt'l crypto algorithms, implement elliptic curve encryption
 * Fix two design flaws in the packet format:
    1) anybody can delete index packet entries of others
    2) malicious storage nodes can delete all copies of an email packet before
       the recipient receives the packet
2010-05-22 00:35:46 +00:00
050a6dbbbc 0.2.3 2010-05-10 07:12:57 +00:00
8bb3313f38 Make the INFO log level more useful 2010-05-09 23:24:03 +00:00
e7575018bc Synchronize on packetListeners when iterating 2010-05-09 23:22:21 +00:00
863b58913a Name the "sent" folder something different than the "sent" time column because they translate to different German words. 2010-05-09 09:57:46 +00:00
6d581f37a9 editIdentity.jsp:
* Remove garbage characters at the top of the page
  * Fix the cancel button
2010-05-09 07:58:39 +00:00
8c152f27d8 Delete index packet entries (email packet keys) from the DHT even if all requests for the email packet come back negative. This deals with the problem of index packet entries not going away when the email packet does not exist. 2010-05-09 07:25:44 +00:00
07fdac2312 Some comments 2010-05-09 05:54:25 +00:00
e467e6232a Fix constant s-bucket refreshes when there are very few peers. 2010-05-09 05:46:05 +00:00
6e2a14af39 Override toString() for logging 2010-05-07 07:28:19 +00:00
f23db925ad Move the logStatus() call so it doesn't report alpha-1 parallel requests when there are alpha. 2010-05-07 07:24:52 +00:00
93bf69d0aa Increase alpha to 10 2010-05-07 06:54:34 +00:00
cd74c6aac2 Fix a NPE 2010-05-07 06:35:53 +00:00
240a8c12eb Fix a bug that hides some text if the "ellipsis" CSS class is used.
The fix is to get rid of ellipsis, which was a hack anyway, but it
means no more fade effect when text is cut off.
2010-05-07 06:34:57 +00:00
4888f0dd54 Javascript fix 2010-05-06 18:06:15 +00:00
7c5aa40d26 Increase Kademlia lookup timeout to 5 minutes 2010-05-06 08:16:15 +00:00
d9fb751b7b 2010-05-06 08:14:02 +00:00
a23983f686 Eliminate duplicate message IDs, they cause msgmerge to fail 2010-05-06 08:11:29 +00:00
561b4244d6 Rename activeSince to firstSeen 2010-05-06 05:04:07 +00:00
331f72ef67 2010-05-05 22:49:54 +00:00
bea47a0c5d Remove some dead code 2010-05-05 13:28:12 +00:00
232e6f72e7 Remove the localDestination parameter from the KademliaDHT constructor, read localDestination from the I2PSendQueue instead. 2010-05-05 13:26:55 +00:00
1557694beb * Handle requests to the local destination directly, not through the network
* Fix/add some comments
* Rename CheckEmailTask.findEmailPacketKeys() to CheckEmailTask.getEmailPacketKeys(), rename the parameter to dhtPackets
* Add some debug output
2010-05-05 12:56:12 +00:00
1824e0ddcc 2010-05-05 12:42:55 +00:00
d6d0756a6b Use a bean property for displaying the local destination hash, no need for a tag. 2010-05-05 12:20:38 +00:00
c08eff08db Remove an unused method 2010-05-04 22:31:22 +00:00
7664dcbd5b 2010-05-04 17:30:00 +00:00
1e666ca7de Refresh folder list every 20 seconds when sending, otherwise every 2 minutes 2010-05-04 02:10:48 +00:00
56baffba77 BootstrapTask: unlock bootstrap node before adding to bucket 2010-05-03 21:35:49 +00:00
529b39efe9 Cache message IDs of emails that have been received, and ignore email packets whose message ID is in the cache. 2010-05-03 05:39:54 +00:00
a826750254 When new email arrives, don't do a page refresh, but go to the inbox URL 2010-05-02 03:19:49 +00:00
cff2752b8f Insert a random number into the request string so others can't see contacts or identities using the CSS history hack 2010-05-01 23:11:33 +00:00
3daa866b10 Strip local address book names before sending an email 2010-05-01 21:46:53 +00:00
e1e1a7a8e4 Don't throw a NPE in the call to log.error() 2010-05-01 21:23:03 +00:00
b76288e944 One more trash folder related commit in addition to rev. ec310a306f43f2b5e51f77640f415bca08e5971d 2010-05-01 21:19:20 +00:00
905f9aa974 * Implement the trash folder
* Move emails to trash instead of deleting them; do delete emails from the trash folder
2010-04-30 06:18:21 +00:00
57a2d2b891 * Implement the "Sent" folder
* After an email has been sent, move it to the "Sent" folder
2010-04-29 10:04:05 +00:00
7d060c495a Make the folders box an iframe, auto-refresh if outbox contains emails. 2010-04-29 09:58:24 +00:00
e2c83d58da Add a file I missed in rev. 82ebf22a7ebcec38ddaff619afe27a8e19dc9fcc 2010-04-28 06:33:25 +00:00
f5a73349fb Instead of a random DHT key, use a SHA-256 hash so receivers can verify the integrity of email packets. 2010-04-28 03:26:32 +00:00
f02148e159 Show any recipient, not a local recipient, in the "To" column in the outbox (usually there are no local recipients in an outgoing email). 2010-04-27 05:22:35 +00:00
e03a6640fb Make the "To:" column sortable 2010-04-27 05:04:26 +00:00
a4c37841ec When sorting a folder by address, sort by displayed address, not by header value. 2010-04-27 03:45:42 +00:00
b44f67011f Fix duplicate "identity created" message when creating a new identity 2010-04-26 05:39:06 +00:00
a5765a5920 Remove the "new" parameter which does nothing 2010-04-26 05:34:33 +00:00
ae7c0947cf Fix page title 2010-04-26 05:33:32 +00:00
af9e46c983 Focus the destination field if it is empty; if it is not, focus the name field 2010-04-26 05:01:01 +00:00
eb39dfdb90 Always put a blank recipient field at the end 2010-04-26 04:44:28 +00:00
6b5ad92ea6 Rename Field to EmailAttribute 2010-04-26 04:23:02 +00:00
d60f26561a Escape HTML in the textarea 2010-04-25 23:47:28 +00:00
f36d0f2298 Implement the "remove recipient" button 2010-04-25 23:03:06 +00:00
c796311c55 Replace some JSP code in newEmail.jsp with Java code (it was getting too complex for JSP) 2010-04-25 21:40:03 +00:00
4ee42e9a1f Show the "add to address book" button only for the last address 2010-04-25 05:44:27 +00:00
33ce63db4e * newEmail.jsp: Implement the "add recipient" button
* Rename the JSP function getRecipients to getSortedRecipientParams
* newEmail.jsp: Remove redundant filtering of recipient* parameters which is already done in getSortedRecipientParams()
* sendEmail.jsp: Keep ordering of recipients the same as in the UI
2010-04-25 04:36:47 +00:00
340d6cd83b Handle single quotes and double quotes in text fields 2010-04-24 07:30:56 +00:00
560f6e4946 2010-04-23 06:00:26 +00:00
6445dd5d4c Handle whitespace in email destinations 2010-04-23 04:23:22 +00:00
86fe700d9f When displaying an email, show full Email Destinations only on mouse over 2010-04-22 07:21:59 +00:00
d2d4031f2e Update outbox status after every sendToOne call 2010-04-21 06:29:20 +00:00
e598b81600 Handle CC and BCC addresses 2010-04-21 06:27:38 +00:00
7f9f55fbac Fix title of the outbox page; remove reference to non-existant param.path parameter 2010-04-21 06:23:00 +00:00
a707f2830b After deleting an email, go to the containing folder instead of the inbox. 2010-04-20 20:49:27 +00:00
0f95825828 Save outgoing emails to the outbox and send them in the background 2010-04-20 20:48:29 +00:00
c764008170 More detailed debug output 2010-04-19 02:11:31 +00:00
dc43492537 * If an email destination in an email is known, always show the name from the address book or the identity
* Don't show an add button if sender is a local identity
* Several minor things
2010-04-19 01:48:33 +00:00
e87a4efe2f Default to descending sort order for dates, ascending for all other fields 2010-04-15 05:49:17 +00:00
95cfab5e71 Remove an unused constant 2010-04-15 05:45:27 +00:00
ab1ad92278 * New Email page: Add a button which adds a recipient to the address book
* Address book: In select mode, show a "return" button instead of the "add" button if the address book is empty.
* Rename the HTTP request parameter "search" to "select"
* Fix some JSP compile warnings caused by invalid XML in i2pbote.tld
2010-04-15 03:21:48 +00:00
f2afa866f9 Some comments 2010-04-15 02:25:19 +00:00
de53a1fbc9 Add missing license headers 2010-04-15 02:13:19 +00:00
97f078721b Say whether the unit tests passed or failed 2010-04-11 08:27:52 +00:00
52f295396c Show mail folders sorted; clickable column headers for sorting 2010-04-11 08:23:57 +00:00
ade9804ae6 Remove unnecessary call to getProperty() 2010-04-04 08:04:57 +00:00
7fb9cb8290 * JspStrings.java is the new jsp2po.sh
* Extract strings from <ib:message> tag bodies
* Add a few more missing translations
* Don't translate "value" parameters in <button> tags
* Finish the text in noIdentities.jsp
2010-04-04 08:03:33 +00:00
3d262db251 Fix high CPU usage bug introduced in rev. 54d0f214f9894b433925bc2d0979c5ea6eb924b6,
reported at http://forum.i2p/viewtopic.php?p=23465#23465 (Thanks to the reporter!)
2010-04-03 08:20:43 +00:00
d093f81e46 * Folder.jsp: Add "Unknown Sender" and "Signature" columns
* showEmail.jsp: Show whether the signature is valid
2010-04-01 06:49:25 +00:00
1c2af589fd Oops, forgot to add Locales.java in rev. 9b93a31813555d2157e6a815e907bb3f6b5c31fe 2010-03-31 07:57:26 +00:00
daa289bed1 Add EmailTest.java 2010-03-31 07:54:34 +00:00
40ad4cd488 Fix a NPE 2010-03-31 07:51:43 +00:00
d9931f519d * Sign outgoing emails, verify signatures of incoming emails
* Don't make a copy of the email for removing BCC headers, work on the original
* Remove unused methods from i2p.bote.Util
2010-03-31 07:47:31 +00:00
78a5d59ef3 * Fix: i2pbote-update.xpi2p too big when building the plugin target twice in a row
* Add missing files to the src target
2010-03-29 23:58:23 +00:00
c4be1543ce A few minor things 2010-03-29 05:31:05 +00:00
2652d75346 Don't query locked peers 2010-03-29 05:30:18 +00:00
72621a20c9 * Add a UI option to include / not include the "sent" time when sending an email
* Format the "active since" column on network.jsp according to the locale
2010-03-29 05:28:20 +00:00
960f480d3a Remove extra line in the <textarea> 2010-03-28 06:18:08 +00:00
d8f7d8bfb2 * Show "sent" date/time in showEmail.jsp
* Format date/time according to locale
2010-03-28 04:10:45 +00:00
4b0fdf6932 * Alternate colors in folder list
* Replace tabs with spaces in folder.jsp
2010-03-27 21:13:55 +00:00
739e517c3f Do not translate the directory name in a folder link, only the display name 2010-03-27 20:52:45 +00:00
0af131b043 * Make language user-configurable
* Optionally leave text that is auto-added to an email, such as "Re:", untranslated
2010-03-27 04:21:54 +00:00
b780f79e30 * Move setLastLookupTime() calls from KademliaDHT to BucketManager
* More logging changes
2010-03-25 03:47:31 +00:00
6fcaf3761c Synchronize on pendingRequests in packetReceived 2010-03-25 03:17:55 +00:00
9bf0f45ad0 2010-03-23 19:41:03 +00:00
d23ac867a4 Add/change log output, add some comments 2010-03-23 19:34:50 +00:00
3195fd1cb3 2010-03-23 19:00:56 +00:00
76fd98c346 0.2.2 2010-03-22 07:17:20 +00:00
f3bdebead6 Spelling of the plugin display name 2010-03-22 07:16:32 +00:00
d735db129a Increase max. lock time for unresponsive peers 2010-03-22 04:16:31 +00:00
903c58d7ce Use a solid background for displaying emails 2010-03-21 17:38:18 +00:00
96d51bbc4d Fix: Bootstrap nodes are shown as active since 1970 2010-03-21 17:12:03 +00:00
35050ae5c9 Don't create a N_ file if an O_ file exists for the same message ID. 2010-03-21 16:21:31 +00:00
2fa58dc2c2 * Rename I2PBoteThread.awaitShutdown() to awaitShutdownRequest(), keep DHT.awaitShutdown()
* Write peers to file on shutdown
2010-03-21 08:00:21 +00:00
f307561705 Abort lookup on shutdown request 2010-03-21 07:41:09 +00:00
d313cd89e6 Use BufferedWriter.newline() instead of System.getProperty(line.separator) 2010-03-21 07:36:22 +00:00
13174f7164 Cleanup 2010-03-21 01:27:06 +00:00
668c7c4896 Implement IndexPacketTest 2010-03-21 01:26:17 +00:00
8724648d53 Don't exit until send queue is empty (or the thread is killed) 2010-03-19 23:07:49 +00:00
707aaf0bd0 Shut down ExecutorService when done so threads exit 2010-03-19 20:43:05 +00:00
bb055ce55c Adjust text field widths, now that the CSS doesn't make them all 100% wide 2010-03-19 20:04:54 +00:00
5bf930102c * Make auto mail checking configurable
* Configuration.java:
  - Wrap Properties instead of extending it
  - Replace tabs with spaces
2010-03-19 19:55:18 +00:00
554b0e251d Add some missing translations 2010-03-15 07:07:55 +00:00
9a84bb2ae1 Put a space after Re: 2010-03-15 06:38:37 +00:00
ce6bcecff9 Increase stack size to 256 kB for mail check threads 2010-03-15 06:30:41 +00:00
d6fd4e971e PacketQueue:
* Now based on an ArrayList instead of LinkedList
 * Any synchronization issues should be gone
2010-03-15 05:28:36 +00:00
f399f8d691 Rename REFRESH_TIMEOUT to BUCKET_REFRESH_INTERVAL 2010-03-14 21:04:44 +00:00
5acebd19fe Fix a ConcurrentModificationException 2010-03-14 20:57:26 +00:00
80db993ca7 Make saveToFile() parameterless and rename to save() 2010-03-14 20:56:10 +00:00
9d59cd074c Remove some unused stuff 2010-03-14 18:42:15 +00:00
e86ef43058 German translation 2010-03-14 18:40:31 +00:00
b928c41d22 * Multi-language support
* Delete PrintAppVersionTag, replace with a JSPHelper property
2010-03-14 17:41:35 +00:00
1cc96558d5 Second bootstrap node 2010-03-05 16:28:11 +00:00
7371f835de Fix a NPE 2010-03-05 16:18:46 +00:00
e9010555a1 Fix: refilling the s-bucket broke BucketManagerTest 2010-03-04 07:05:16 +00:00
ee2f9f7471 Fix a potential IndexOutOfBoundsException 2010-03-04 07:02:11 +00:00
8c1e166007 * Use locked + unlocked peers for refilling the s-bucket
* Fix: refillSiblings() generates duplicate peers
2010-03-04 07:00:27 +00:00
030ec907f4 * add missing "}"
* replace tabs with spaces
2010-03-04 06:22:41 +00:00
e9bd3ed60e 2010-03-03 18:06:04 +00:00
e156962b24 0.2.1 2010-03-03 18:05:03 +00:00
aa6b5489f7 2010-03-03 18:00:15 +00:00
1adec9c83b Shutdown:
* Fix: NPE when stopping plugin before the application has started connecting
  * Shut down all threads so the app exits without having to kill the JVM
2010-03-03 17:59:34 +00:00
e21db2b740 store(): Include local node if not enough peers found, or if local node is closer than one of the peers found 2010-03-01 08:05:01 +00:00
5ff0f41988 * Always query the closest unqueried peer, instead of picking one randomly
* Have a list of all (not just S) peers ready at the beginning of the lookup. This fixes the "No storages found" bug (which I think would have gone away in the next release due to the higher S value).
2010-03-01 08:02:56 +00:00
302db49850 2010-03-01 06:26:52 +00:00
b11459eeba Fix: An IndexPacketDeleteRequest for an already deleted entry causes a NPE 2010-03-01 06:04:37 +00:00
1ae332a85d Partial undo of rev. 30c74967ae81dff73f62ecca085cd72a85424ffe: Don't move unresponsive siblings to a k-bucket. I don't know what I was thinking, there is no reason to do that. 2010-03-01 03:21:32 +00:00
653a162643 Layout fix 2010-03-01 02:27:06 +00:00
cf3d58920a Re-bootstrap when there are no more active peers 2010-02-28 22:44:07 +00:00
1431272618 Run pack200 on plugin jars 2010-02-28 20:52:07 +00:00
3c0fb794d9 Code simplification 2010-02-28 06:34:35 +00:00
5135d07fa4 Ant plugin target: get the app version in a platform-independent way
Ant src target: get the app version from the source like the plugin target does
2010-02-28 02:42:12 +00:00
c1aa31bdfb 2010-02-28 02:35:24 +00:00
79b2197dc0 Option to compile I2P-Bote as an I2P plugin 2010-02-26 23:32:43 +00:00
ec7e057b6d * Fix: ClosestNodesLookupTask returned too early in some cases
* Periodical s-bucket refresh
* Exponential backoff for unresponsive peers
* Lots of minor stuff
2010-02-25 02:02:00 +00:00
d6a69e237e * when a sibling times out, move it to a k-bucket and refill the s-bucket
* don't use unresponsive peers for lookups, but keep them unless there is a replacement peer
* remove some unused or redundant code
2010-02-19 05:43:44 +00:00
cc48d56682 * Bucket refresh (periodically refresh a bucket if there hasn't been a DHT lookup for a key within the bucket's range)
* New method KBucket.toString() for logging purposes
* Fix: bucket prefix was calculated wrong
2010-02-17 04:10:07 +00:00
831d263449 2010-02-16 04:47:25 +00:00
7ae9575ed2 Use fn:escapeXml for displaying email data 2010-02-16 04:46:17 +00:00
215a9ab160 Fix junit Ant task 2010-02-16 04:02:29 +00:00
5fac243e70 Ant can use web.xml directly, no need for web-template.xml 2010-02-16 03:51:54 +00:00
6b3c11322e Some cleaning up and other minor stuff 2010-02-15 06:39:58 +00:00
422eacd53d 2010-02-15 06:38:18 +00:00
947ad0014c Set character encoding in requests to UTF-8 unless the browser sets an encoding 2010-02-15 06:37:46 +00:00
b91f08fa01 Implement the Address Book feature 2010-02-15 06:31:38 +00:00
2227955eee Implement the "default identity" feature. 2010-02-12 05:30:17 +00:00
fddefc9275 Fix: Trying to edit an existing identity creates a new one 2010-02-11 05:06:23 +00:00
352df69d51 Fix NPE when navigating to network.jsp right after the 3-minute initial wait 2010-02-11 03:03:41 +00:00
82917aaaab When replying, don't add a Re: if there is one already 2010-02-10 23:13:16 +00:00
75fbcbaecf 2010-02-10 23:11:51 +00:00
45c0fff636 Display Kademlia-specific information on network.jsp while still keeping the DHT interface implementation-agnostic 2010-02-10 21:06:59 +00:00
cc846c3abe * Rename KademliaException to DhtException; in DHT, throw DhtException instead of Exception
* Drop Comparable from I2PSendQueue.ScheduledPacket
* Remove an unneccessary "throws"
* Fix some minor issues found by FindBugs:
  - Don't ignore return values of File.mkdir, File.renameTo, etc.
  - Close open files even if an exception happens
  - Use Integer.valueOf instead of the Integer constructor
  - Make some inner classes static
  - Remove an unused method from UniqueId
  - Make two fields volatile
2010-02-10 04:59:44 +00:00
a131fa6600 90k chars can't fit into 3 email packets anymore due to email encoding, so lower it to 80k chars. 2010-02-09 19:36:17 +00:00
40bd121a77 * Fix: test failed because peers[199] was the same destination as localDestination
* Comments
2010-02-09 19:13:39 +00:00
e4d317c76d Change K and S to real world values. B is still 1 for now. 2010-02-09 19:10:04 +00:00
22a0ef14b6 Return K peers in a Kademlia lookup, not S 2010-02-09 19:05:18 +00:00
f26c8116e8 Remove an incorrect log message 2010-02-09 19:01:07 +00:00
0a03d90696 New unit test BucketManagerTest 2010-02-09 04:39:36 +00:00
3d7788632e * Several Kademlia bugs fixed (bucket splitting was severely broken)
* Use all positive numbers for representing a Hash as a BigInteger
* Some refactoring of the Kademlia code, mainly in order to keep buckets sorted by last reception time without having to explicitly store a "last seen" time for each peer.
2010-02-09 04:38:55 +00:00
6df3e8b845 remove unused variable 2010-02-09 04:29:17 +00:00
39fed9ec83 remove unused import 2010-02-09 04:28:09 +00:00
e2cc37c3e3 Catch all exceptions in messageAvailable() and log them before they get caught in I2PSessionImpl which doesn\'t print a stack trace 2010-02-09 04:21:12 +00:00
b17bcbaa07 More detailed log output 2010-02-09 04:17:35 +00:00
8bdb64c39b * Remove Email.getUniqueID() and Email.setUniqueID(), only use getMessageID()/setMessageID()
* call super method in Email.updateHeaders()
* Explicitly encode subject line from UTF-8
2010-02-06 06:38:31 +00:00
ff880b25ef * Use UTF-8 in HTTP requests
* Instead of an HTTP param, use an EL variable for passing the page title to header.jsp so non-US characters don't get messed up
* Fix title on network.jsp
2010-02-06 06:27:22 +00:00
c341d47b27 2010-02-05 06:21:28 +00:00
8212edca98 * Use JavaMail
* Get rid of the FolderElement interface
2010-02-05 06:20:04 +00:00
bdabe0e19a Add some missing unit tests to AllTests.java 2010-02-04 06:18:10 +00:00
37cbc5cfd9 * Get rid of MessageId, use UniqueId instead
* Don't use the "Message-Id" header at all. The message Id is already in the
  file name (for .mail files) or in the MSID field (for packetized emails).
2010-02-04 06:16:29 +00:00
015af37a59 * Pass the whole Ant classpath to Ant tasks because JSPC seems to need a java compiler for tag files
* Partial fix for the junit task (tests still fail, but they compile now)
* Print SHA256 sum for the war file
* Delete src.zip in the "clean" task
2010-02-03 07:36:53 +00:00
38ad423353 Rename test/.../kademlia package to test/.../dht for consistency 2010-02-02 03:48:37 +00:00
b64614ea45 Version 0.2 2010-02-01 16:09:38 +00:00
c7277b944a Remove the cancel button, disable the save button 2010-02-01 16:05:04 +00:00
27e8723753 Put a tag back in that got accidentally deleted in rev. d6d2a84b2ce55918029c8362a8526ed21e254fe6 2010-02-01 07:01:56 +00:00
bdce1fc8a3 2010-02-01 06:17:36 +00:00
cf6a89a731 Prevent network.jsp from throwing an error when the app has not started connecting yet 2010-02-01 03:44:26 +00:00
e929c8fb18 Show "to" addresses in the inbox and when displaying an email 2010-02-01 03:03:07 +00:00
4e051a8111 Remove unused file 2010-02-01 02:56:51 +00:00
e5385f4017 Reverse sort order, was oldest to newest 2010-02-01 02:56:12 +00:00
146bb6f876 Auto-check for new mail periodically 2010-02-01 01:31:21 +00:00
3698843c0f Fix the delete button 2010-02-01 01:23:07 +00:00
24fb21ea2c * N_ or O_ prefix in the filename indicates if an email is new (read) or old (unread)
* Show new emails in bold, read ones in normal font
* Set an email to "old" when the user displays it
2010-01-31 21:37:41 +00:00
44d09a1b37 2010-01-31 21:37:01 +00:00
64fe831e0c * Move some code out of getElements() into the new method getFilenames()
* Add method getNumElements()
2010-01-31 01:59:12 +00:00
0bc9825a46 2010-01-31 01:45:57 +00:00
4c7f3bd029 remove redundant interface declaration 2010-01-31 01:36:54 +00:00
be58442eed Fix: wrong field name in the javascript that focuses the "public name" field on page load 2010-01-31 01:14:01 +00:00
aafcce644e IncomingPacketHandler:
* Ignore response packets whose id doesn't match the request
 * Rename addPeers to updatePeers
2010-01-30 19:44:07 +00:00
24c76dd897 * Handle invalid packets better
* Ban peers that use a protocol version other than 2
2010-01-30 10:48:29 +00:00
38171179df Remove some unnecessary code 2010-01-30 10:38:33 +00:00
808b895951 * Print local dest hash on the network status page
* List active peers and banned peers separately on the network status page
2010-01-30 10:24:49 +00:00
540b0990eb 2010-01-30 09:49:24 +00:00
f5e3b128f3 Remove unused class 2010-01-30 09:39:23 +00:00
0d12ee1240 2010-01-29 04:55:20 +00:00
d26032595e * AbstractBucket/KBucket: Replace ConcurrentSkipListSet with ConcurrentHashSet for the peer list and the replacement cache
* drop a peer after 3 consecutive non-responses
* several minor changes
2010-01-29 04:54:47 +00:00
80c66d7c23 Oops, two more files should have gone into revision 6b0ba3c712564df1061979948a109779470024f8 2010-01-27 20:13:15 +00:00
5785c5836b . 2010-01-27 07:14:00 +00:00
1c52df1713 Fix the stale counter 2010-01-27 07:13:33 +00:00
591c3bff98 . 2010-01-27 06:32:00 +00:00
28f09ac7d4 Implement reply button 2010-01-27 04:20:59 +00:00
6a059521f0 Remove debug message 2010-01-27 04:16:20 +00:00
7164b7f428 Fix: Public Name and Description headings were in the wrong order 2010-01-25 01:09:38 +00:00
471e8f4b25 Fix: left angle bracket disappears when inserting line break in the sender field 2010-01-25 01:08:09 +00:00
84eb1ded73 Make textarea one row bigger because some email destinations have more line breaks than others 2010-01-25 01:04:44 +00:00
db3429d0e0 * Include sender's Public Name in the "sender" header field
* Use a proportional font for the "new email" text box
2010-01-25 00:17:39 +00:00
ed4439ef4d Don't try to read peers.txt if it does not exist. 2010-01-24 18:24:06 +00:00
63b8bf29e8 Preserve line breaks in emails when sending and convert them to HTML for displaying emails. 2010-01-24 06:36:34 +00:00
7a09d652d1 Fix incorrect logger names 2010-01-24 02:09:04 +00:00
2ebb389900 Use POST for the "New Email" form 2010-01-23 06:07:35 +00:00
2e50916897 Add license notices 2010-01-23 05:11:16 +00:00
b40e327508 Fix unnecessary timeouts when doing DHT retrievals 2010-01-23 04:46:41 +00:00
b9534b2a2a PacketQueue: Insert packets with an earliestSendTime>0 in the right place 2010-01-23 01:05:25 +00:00
c022088190 Always send a response to retrieve requests, even if nothing found. 2010-01-23 00:52:00 +00:00
f5db9e18b5 Don't report a peer timeout if the packet hasn't been sent to the peer yet 2010-01-22 19:04:24 +00:00
87cc21dcf1 * Show peer info on the network page
* Remove some dead code
* Major refactoring of the Kademlia code:
 - Interface DhtPeer replaces the PeerInfo class
 - KademliaPeer extends Destination
 - Get rid of BanList, store ban info in KademliaPeer instead
 - Use separate classes for k-buckets and s-buckets, both extend AbstractBucket
2010-01-22 01:59:25 +00:00
d0af45125e Show peer info on network.jsp 2010-01-19 01:59:21 +00:00
39b66e85ce Put peers on the ban list if they use a wrong protocol version (has no effect yet) 2010-01-18 06:54:40 +00:00
b4072d4813 * Implement deletion of email packets from the DHT and deletion of index packet entries
* Version 2 of the network protocol
2010-01-18 06:51:27 +00:00
525cd894f5 Log dest hash, not dest key in packetReceived 2010-01-08 21:00:01 +00:00
b8dfe7f96d * Allow the X-Priority header field
* Set the "From" field when setting the "Sender" field
2010-01-08 20:43:47 +00:00
289c78108d . 2010-01-08 20:41:50 +00:00
fb9fb7844e Throw an exception if no peers were found for storing a packet 2009-12-20 04:28:19 +00:00
10e32012f9 . 2009-12-20 04:25:48 +00:00
1218c1545c Ver. 0.1.5 2009-12-20 00:08:27 +00:00
a3be21648b 0.1.5 2009-12-20 00:00:03 +00:00
7694ea3e58 Fix: redirect to noIdentities.jsp was broken 2009-12-19 23:56:10 +00:00
c6a12fc336 support deletion of emails 2009-12-19 23:24:32 +00:00
f50b0a9da1 Fix: DHT packets only got stored on one node because the StoreRequests all had the same packet Id. 2009-12-19 23:23:56 +00:00
e9554c7924 Doing a findOne for index packets didn't seem such a good idea after all because
it might return an incomplete version of the index packet when there is a more
complete version stored on another peer. So I'm reverting back to findAll.
2009-12-19 23:22:20 +00:00
424e0dfb35 support deletion of emails 2009-12-19 23:19:24 +00:00
fec9052413 new 2009-12-19 23:15:57 +00:00
cc85ef3d0b . 2009-12-19 20:41:08 +00:00
35fbaa377c Add disabled button style 2009-12-19 19:27:02 +00:00
ee941ea7a1 Move some app status related code to getStatus.jsp so it can be shared with other JSPs 2009-12-19 19:26:24 +00:00
2005a2db4d Disable the Network Status link until the I2P session is ready 2009-12-19 19:21:51 +00:00
31cd0b9bd1 Disable two buttons and one link until I2P session is ready 2009-12-19 19:20:36 +00:00
e8fc716b21 new file 2009-12-19 17:26:36 +00:00
bb33c8dcd9 remove all unimplemented HTML links 2009-12-19 08:26:51 +00:00
ff88ec13ba don't say "connected" until done bootstrapping 2009-12-19 08:21:55 +00:00
62f1850144 Remove some dead code;
in the find method, return the local result immediately if only one result was asked for
2009-12-19 07:34:38 +00:00
0e4a732c76 . 2009-12-19 07:30:39 +00:00
7d4b9d051f Just use the first index packet received, don't wait for all peers to respond 2009-12-19 07:30:21 +00:00
b3d883f7fa fix: distance can't be negative; add JavaDoc 2009-12-19 06:07:13 +00:00
7c51fd6848 Set max bucket size to k for k-buckets, and s for the s-bucket 2009-12-19 04:24:30 +00:00
02e28eb59f . 2009-12-19 03:50:39 +00:00
737237c836 synchronize the list of responses received; more log output; log dest hash, not the full dest key; use the correct key type when removing a mapping from pendingRequests 2009-12-19 03:49:56 +00:00
3d343e7949 Fix: toByteArray wrote all 387 bytes of an I2P destination instead of just the two public keys 2009-12-19 03:30:13 +00:00
278f612aa4 rename FindCloseNodesPacketTest to FindClosePeersPacketTest; add PeerListTest 2009-12-19 03:27:12 +00:00
b858cccb59 . 2009-12-19 03:24:42 +00:00
6d535e6699 New file PeerListTest.java 2009-12-19 03:24:06 +00:00
af193ec09b rename FindCloseNodesPacketTest to FindClosePeersPacketTest 2009-12-19 03:23:19 +00:00
e5d84be0db Implement equals and hashCode 2009-12-18 18:06:55 +00:00
e330c4bf22 log destination hash, not the complete dest key 2009-12-18 18:04:57 +00:00
b5191bc663 add the src target which makes a src.zip file 2009-12-17 18:38:54 +00:00
9dc72d2c70 . 2009-12-17 18:13:58 +00:00
19758eab8e add createRandomHash() 2009-12-17 18:13:20 +00:00
fb2726b0b0 Move all network and threading code out of BucketManager into KademliaDHT;
don't add self to buckets;
use a peer for bootstrapping if it initiated communication;
fix the refresh(KBucket) method which didn't do a closest nodes lookup;
other, minor changes
2009-12-17 18:12:33 +00:00
11438e3649 Move all network and threading code out of BucketManager into KademliaDHT; don't add self to buckets; make BucketManager iterable; other, minor changes 2009-12-17 17:56:50 +00:00
b03534c339 Only log the dest hash, not the multi-line output of Destination.toString(); get rid of an unnecessary if 2009-12-17 17:44:44 +00:00
f6ac9b910a Check for expired packets once a day, not every time when checking for new packets 2009-12-17 17:33:27 +00:00
ed765834fe 0.1.4 2009-12-13 07:41:58 +00:00
459075ca7f Release 0.1.4; Do the 3-minute wait in the background and support skipping the wait time. 2009-12-13 07:41:28 +00:00
47da9495fe New tag "connect"; new JSP function getNetworkStatus 2009-12-13 07:28:06 +00:00
b51733ff2f New JSP function getNetworkStatus() 2009-12-13 07:26:50 +00:00
df463fd6d0 New method isConnected() 2009-12-13 07:25:51 +00:00
d50d9a5318 Modify statusbox class for revised statusFrame.jsp 2009-12-13 07:24:11 +00:00
3b7b748e71 Fix jstllib path; don't add JSPs to war (thanks zzz) 2009-12-13 07:20:05 +00:00
d77b61e939 Link to network.jsp 2009-12-13 07:17:35 +00:00
fbba5d461b Add JSTL for displaying local I2P destination, commented out for now. 2009-12-13 07:17:03 +00:00
0fc434b6d7 Remove unused welcome-file entries 2009-12-13 07:14:46 +00:00
57be687166 New file 2009-12-13 07:12:07 +00:00
9880a54337 0.1.3 2009-12-12 07:45:52 +00:00
08629cb759 Remove unused code; other minor changes 2009-12-12 07:23:58 +00:00
4fe2c5c08d Fix: high cpu usage when sending or receiving; use sendQueue.send instead of sendQueue.sendAndWait so requests can be sent in parallel. 2009-12-12 07:08:07 +00:00
f9ee3ae653 Set DHT key in the merge constructor (fixes a NPE) 2009-12-12 07:02:50 +00:00
ab26312aa0 2009-12-12 07:00:30 +00:00
a1687cb50d bump to ver. 0.1.3; wait 3 minutes before connecting after startup; set tunnel names to "I2P-Bote"; minor changes like renaming of variables 2009-12-12 06:59:55 +00:00
76d6008daa Fix: inboxFlag was never set, which caused the "Check Mail" button not to show new emails. See also buttonFrame.jsp, rev. 1c93f3214bbc0b5ee1ef772caccf576644fe3cbd vs ed79eab91430b185d5b710b0fe8ef3afc8567cb0 2009-12-12 06:55:00 +00:00
05e93e53dd Fix: "Check Mail" button didn't show new emails, user had to reload inbox 2009-12-12 06:49:21 +00:00
1509a65bee checkMail.jsp no longer needed since buttonFrame.jsp does all the mail checking 2009-12-12 06:47:38 +00:00
ab6a498fb7 add failonerror="true" to javac tasks; change all /opt/... paths to ../i2p/... 2009-12-12 06:42:00 +00:00
bf50d5049d 2009-12-07 06:13:58 +00:00
503 changed files with 93161 additions and 8546 deletions

69
.mtn-ignore Normal file
View File

@ -0,0 +1,69 @@
# Just to try and prevent some noob disasters.
# Use mtn add --no-respect-ignore foo.jar to ignore this ignore list
# Temporary/build files
i2pbote.jar
i2pbote.xpi2p
i2pbote-update.xpi2p
~$
# Temporary/build dirs
^ant_build
^plugin/plugin.tmp
# Build property overrides
override.properties
# Downloaded JavaMail libraries
mailapi-.*.jar
# Downloaded BouncyCastle Provider libraries
bcprov-jdk15on-.*.jar
# Downloaded IMAP libraries
apache-james-imap-api-0.4-.*.jar
apache-james-imap-message-0.4-.*.jar
apache-james-imap-processor-0.4-.*.jar
apache-james-mailbox-api-0.6-.*.jar
apache-james-mailbox-store-0.6-.*.jar
apache-mime4j-core-.*.jar
apache-mime4j-dom-.*.jar
commons-codec-.*.jar
commons-collections-.*.jar
commons-configuration-.*.jar
commons-io-.*.jar
commons-lang-.*.jar
james-server-filesystem-api-3.0.0-beta5-SNAPSHOT.jar
james-server-lifecycle-api-3.0.0-beta5-SNAPSHOT.jar
james-server-protocols-imap4-3.0.0-beta5-SNAPSHOT.jar
james-server-protocols-library-3.0.0-beta5-SNAPSHOT.jar
james-server-util-3.0.0-beta5-SNAPSHOT.jar
jutf7-1.0.0.jar
log4j-1.2.17.jar
netty-3.3.1.Final.jar
protocols-api-1.6.4-.*.jar
protocols-imap-1.6.4-.*.jar
protocols-netty-1.6.4-.*.jar
slf4j-api-.*.jar
slf4j-log4j12-.*.jar
# Downloaded SMTP libraries
subethasmtp-3.1.7.jar
# Downloaded JUnit libraries
junit-4.8.1.jar
# Downloaded Mockito libraries
mockito-core-2.0.31-beta.jar
# Downloaded jMock libraries
cglib-nodep-2.2.3.jar
hamcrest-core-1.3.jar
hamcrest-library-1.3.jar
hamcrest-unit-test-1.3.jar
jmock-2.6.0.jar
jmock-junit3-2.6.0.jar
jmock-junit4-2.6.0.jar
jmock-legacy-2.6.0.jar
jmock-script-2.6.0.jar
objenesis-1.0.jar

21
.tx/config Normal file
View File

@ -0,0 +1,21 @@
[main]
host = https://www.transifex.com
lang_map = ru_RU: ru, sv_SE: sv, tr_TR: tr, uk_UA: uk, zh_CN: zh
[I2P.plugin_i2pbote]
file_filter = locale/messages_<lang>.po
source_file = locale/messages_en.po
source_lang = en
minimum_perc = 40
[I2P.plugin_i2pbote_userguide]
file_filter = src/main/webapp/html/userGuide_<lang>.html
source_file = src/main/webapp/html/userGuide.html
source_lang = en
minimum_perc = 50
[I2P.plugin_i2pbote_faq]
file_filter = src/main/webapp/html/FAQ_<lang>.html
source_file = src/main/webapp/html/FAQ.html
source_lang = en
minimum_perc = 50

28
README.md Normal file
View File

@ -0,0 +1,28 @@
# I2P-Bote
I2P-Bote is a plugin for I2P that allows users to send and receive emails while preserving privacy. It does not need a mail server because emails are stored in a distributed hash table. They are automatically encrypted and digitally signed, which ensures no one but the intended recipient can read the email, and third parties cannot forge them.
**Features:**
* Themeable webmail interface
* User interface translated in many languages
* One-click creation of email accounts (called email identities)
* Emails can be sent under a sender identity, or anonymously
* ElGamal, Elliptic Curve, and NTRU Encryption
* Encryption and signing is transparent, without the need to know about PGP
* Delivery confirmation
* Basic support for short recipient names
* IMAP / SMTP
**Planned Features:**
* Custom folders
* Sending and receiving via relays, similar to Mixmaster
* Lots of small improvements
**More information**
The links below only work within I2P, i.e., make sure you are running I2P and your browser is using the proxy at localhost:4444.
* http://i2pbote.i2p I2P-Bote homepage
* http://forum.i2p/viewforum.php?f=35 I2P-Bote forum

28
TODO Normal file
View File

@ -0,0 +1,28 @@
User guide
- Howto for IMAP/SMTP
Email composition
- "Include sent time" as an option, pre-filled with settings default
Identities
- Generate dests in background rather than needing a dedicated tab open
IMAP/SMTP
- "Force SSL" option
- When disabled, users can connect with "insecure" or "STARTTLS"
- When enabled, users can connect with "SSL"
- Separate password cache (IMAP auth should not unlock webui)
Not-yet-implemented
- Drafts folder
- User-defined folders
- Automatically disable timestamps when using mail routes
- Random offset for fetch interval (#1360)
- Per-identity settings (#1359)
- Fetch interval
- Mail route per-hop settings
- Delay (#1361)
- Fixed forward time
- Traffic correlation countermeasures at relays
- Mixing anonymity (minimum threshold on relay packets to send)
- Constant traffic (test and dummy messages)
- Balanced incoming/outgoing ratio
- Packet padding
- Retrieving email via relays

View File

@ -1,2 +0,0 @@
<%@ attribute name="index" required="true" description="0-based index of the email identity" %>
test

View File

@ -1,17 +0,0 @@
<%@ attribute name="text" required="true" description="The text to display" %>
<%@ attribute name="width" required="false" description="The maximum number of characters in each line" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<c:if test="${empty width}">
<c:set var="width" value="64"/>
</c:if>
<c:set var="length" value="${fn:length(text)}"/>
<c:forEach var="i" begin="0" end="${length}" step="${width}">
<c:if test="${i > 0}">
<br/>
</c:if>
${fn:substring(text, i, i+64)}
</c:forEach>

View File

@ -1,127 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-jsptaglibrary_2_0.xsd">
<tlib-version>1.0</tlib-version>
<short-name>i2pbote</short-name>
<uri>I2pBoteTags</uri>
<tag>
<name>sendEmail</name>
<tag-class>i2p.bote.web.SendEmailTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>sender</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
<attribute>
<name>recipient</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
<attribute>
<name>subject</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
<attribute>
<name>message</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
</tag>
<tag>
<name>checkForMail</name>
<tag-class>i2p.bote.web.CheckMailTag</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>numDhtPeers</name>
<tag-class>i2p.bote.web.PrintNumDhtPeersTag</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>numRelayPeers</name>
<tag-class>i2p.bote.web.PrintNumRelayPeersTag</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>printVersion</name>
<tag-class>i2p.bote.web.PrintAppVersionTag</tag-class>
<body-content>empty</body-content>
</tag>
<function>
<name>getIdentities</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.email.Identities getIdentities()
</function-signature>
</function>
<function>
<name>getLocalDestination</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.String getLocalDestination()
</function-signature>
</function>
<function>
<name>saveIdentity</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
boolean saveIdentity(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
</function-signature>
</function>
<function>
<name>deleteIdentity</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
boolean deleteIdentity(java.lang.String)
</function-signature>
</function>
<function>
<name>isCheckingForMail</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
boolean isCheckingForMail()
</function-signature>
</function>
<function>
<name>newMailReceived</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
boolean newMailReceived()
</function-signature>
</function>
<function>
<name>getMailFolder</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.EmailFolder getMailFolder(java.lang.String)
</function-signature>
</function>
<function>
<name>getEmail</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.email.Email getEmail(java.lang.String, java.lang.String)
</function-signature>
</function>
<tag-file>
<name>printWithLineBreaks</name>
<path>/WEB-INF/tags/printWithLineBreaks.tag</path>
</tag-file>
</taglib>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>i2pbote</display-name>
<!-- precompiled servlets -->
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>i2p.bote.web.ServiceInitializer</listener-class>
</listener>
</web-app>

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>i2pbote</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>i2p.bote.web.ServiceInitializer</listener-class>
</listener>
</web-app>

View File

@ -1,75 +0,0 @@
<%--
Copyright (C) 2009 HungryHobo@mail.i2p
The GPG fingerprint for HungryHobo@mail.i2p is:
6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
This file is part of I2P-Bote.
I2P-Bote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
I2P-Bote is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="ib" uri="I2pBoteTags" %>
<c:if test="${ib:isCheckingForMail()}">
<c:set var="checkingForMail" value="true"/>
</c:if>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="i2pbote.css" />
<c:if test="${checkingForMail}">
<meta http-equiv="refresh" content="20" />
</c:if>
</head>
<body style="background-color: transparent; margin: 0px;">
<table><tr>
<td>
<c:if test="${checkingForMail}">
<div class="checkmail">
<img src="images/wait.gif"/>Checking for mail...
</div>
</c:if>
<c:if test="${!checkingForMail}">
<div class="checkmail">
<form action="checkMail.jsp" target="_top" method="GET">
<input type="hidden" name="path" value="Inbox"/>
<button type="submit" value="Check Mail">Check Mail</button>
</form>
</div>
<c:if test="${ib:newMailReceived()}">
<script language="Javascript">
// If inbox is being displayed, reload so the new email(s) show
if (document.getElementById("inboxFlag"))
window.location.reload();
</script>
</c:if>
</c:if>
</td>
<td>
<form action="newEmail.jsp" target="_top" method="GET">
<button type="submit" value="New">New</button>
</form>
</td>
</tr></table>
</body>
</html>

View File

@ -1,99 +0,0 @@
<%--
Copyright (C) 2009 HungryHobo@mail.i2p
The GPG fingerprint for HungryHobo@mail.i2p is:
6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
This file is part of I2P-Bote.
I2P-Bote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
I2P-Bote is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="ib" uri="I2pBoteTags" %>
<c:choose>
<c:when test="${param.new}">
<c:set var="title" value="New Email Identity"/>
<c:set var="commitAction" value="Create"/>
</c:when>
<c:otherwise>
<c:set var="title" value="Edit Email Identity"/>
<c:set var="commitAction" value="Save"/>
</c:otherwise>
</c:choose>
<jsp:include page="header.jsp">
<jsp:param name="title" value="${title}"/>
</jsp:include>
<div class="errorMessage">
${param.errorMessage}
</div>
<div class="main">
<form name="form" action="saveIdentity.jsp">
<table>
<tr>
<td>
<div style="font-weight: bold;">Public Name:</div>
<div style="font-size: 0.8em;">(required field, shown to recipients)</div>
</td>
<td>
<input type="text" size="25" name="publicName" value="${param.publicName}"/>
</td>
</tr>
<tr>
<td>
<div style="font-weight: bold;">Description:</div>
<div style="font-size: 0.8em;">(optional, kept private)</div>
</td>
<td>
<input type="text" size="25" name="description" value="${param.description}"/>
</td>
</tr>
<tr>
<td>
<div style="font-weight: bold;">Email Address:</div>
<div style="font-size: 0.8em;">(optional)</div>
</td>
<td>
<input type="text" size="50" name="emailAddress" value="${param.emailAddress}"/>
</td>
</tr>
<c:if test="${!empty param.key}">
<tr>
<td style="font-weight: bold; vertical-align: top;">
Email Destination:
</td>
<td>
<textarea cols="64" rows="8" readonly="yes" wrap="soft" style="background-color: transparent; border: none;">${param.key}</textarea>
</td>
</tr>
</c:if>
</table>
<input type="submit" name="action" value="${commitAction}"/>
<input type="submit" name="action" value="Cancel"/>
</form>
<script type="text/javascript" language="JavaScript">
document.forms['form'].elements['name'].focus();
</script>
</div>
<jsp:include page="footer.jsp"/>

View File

@ -1,81 +0,0 @@
<%--
Copyright (C) 2009 HungryHobo@mail.i2p
The GPG fingerprint for HungryHobo@mail.i2p is:
6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
This file is part of I2P-Bote.
I2P-Bote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
I2P-Bote is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="ib" uri="I2pBoteTags" %>
<jsp:include page="header.jsp">
<jsp:param name="title" value="${param.path}"/>
</jsp:include>
<c:if test="${folderName == 'Inbox'}">
<div id="inboxFlag"></div>
</c:if>
[DEBUG MSG: This is the <b>${param.path}</b> folder.]
<div class="main">
<div class="folder">
<table>
<tr>
<th style="width: 100px;">Sender</th>
<th style="width: 150px;">Subject</th>
<th style="width: 100px;">Date</th>
<th style="width: 20px;"></th>
</tr>
<c:set var="folderName" value="Inbox"/>
<c:forEach items="${ib:getMailFolder(folderName).elements}" var="email">
<tr>
<c:set var="sender" value="${email.sender}"/>
<c:if test="${empty sender}">
<c:set var="sender" value="Anonymous"/>
</c:if>
<c:set var="date" value="${email.date}"/>
<c:if test="${empty date}">
<c:set var="date" value="${email.dateString}"/>
</c:if>
<c:if test="${empty date}">
<c:set var="date" value="Unknown"/>
</c:if>
<c:set var="subject" value="${email.subject}"/>
<c:if test="${empty subject}">
<c:set var="subject" value="(No subject)"/>
</c:if>
<c:set var="mailUrl" value="showEmail.jsp?folder=${folderName}&messageID=${email.messageID}"/>
<td><div class="ellipsis"><a href="${mailUrl}">${sender}</a></div></td>
<td><div class="ellipsis"><a href="${mailUrl}">${subject}</a></div></td>
<td><a href="${mailUrl}">${date}</a></td>
<td><a href="deleteEmail.jsp?folder=${folderName}&messageID=${email.messageID}"><img src="images/delete.png" alt="Delete" title="Delete this email"/></a></td>
</tr>
</c:forEach>
</table>
</div>
</div>
<jsp:include page="footer.jsp"/>

View File

@ -1,85 +0,0 @@
<%--
Copyright (C) 2009 HungryHobo@mail.i2p
The GPG fingerprint for HungryHobo@mail.i2p is:
6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
This file is part of I2P-Bote.
I2P-Bote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
I2P-Bote is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="ib" uri="I2pBoteTags" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="i2pbote.css" />
<link rel="icon" type="image/png" href="images/favicon.png" />
<title>${param.title} - I2P-Bote</title>
</head>
<body>
<div class="titlebar" style="cursor:pointer" onclick="document.location='.'">
<div class="title">I2P-Bote</div>
<br/>
<div class="subtitle">Secure Distributed Email</div>
</div>
<div class="menubox">
<iframe src="buttonFrame.jsp" width="100%" height="40px" scrolling="no" frameborder="0" allowtransparency="true"></iframe>
</div>
<div class="menubox">
<h2>Folders</h2>
<a href="folder.jsp?path=Inbox"><img src="images/folder.png"/>Inbox</a><br/>
<a href="folder.jsp?path=Outbox"><img src="images/folder.png"/>Outbox</a><br/>
<a href="folder.jsp?path=Sent"><img src="images/folder.png"/>Sent</a><br/>
<a href="folder.jsp?path=Drafts"><img src="images/folder.png"/>Drafts</a><br/>
<a href="folder.jsp?path=Trash"><img src="images/folder.png"/>Trash</a><br/>
<hr/>
<a href="folder.jsp?path=User_created_Folder_1"><img src="images/folder.png"/>User_created_Folder_1</a><br/>
<a href="folder.jsp?path=User_created_Folder_2"><img src="images/folder.png"/>User_created_Folder_2</a><br/>
<a href="folder.jsp?path=User_created_Folder_3"><img src="images/folder.png"/>User_created_Folder_3</a><br/>
<hr/>
<a href=.>Manage Folders</a>
</div>
<div class="menubox">
<h2>Addresses</h2>
<a href="identities.jsp">Identities</a><br/>
<a href=.>Private Address Book</a><br/>
<a href=.>Public Address Directory</a><br/>
</div>
<div class="menubox">
<h2>Configuration</h2>
<a href=.>Settings</a><br/>
</div>
<div class="menubox">
<h2>Network Status</h2>
<iframe src="statusFrame.jsp" width="100%" height="40px" scrolling="no" frameborder="0" allowtransparency="true"></iframe>
</div>
<div class="menubox">
<h2>Help</h2>
<a href=.>User Guide</a><br/>
<a href="about.jsp">About</a><br/>
</div>

View File

@ -1,336 +0,0 @@
/* Based on the router console css */
body {
margin: 15px 0 0 10px;
padding: 0em;
text-align: center;
background: #eef;
color: #000;
font: 9pt/130% "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
}
.titlebar {
width: 800px;
margin: 0px 20px 20px 240px;
background-color: #fff;
color: #310;
padding: 0 15px 15px 25px;
-moz-border-radius: 4px;
-khtml-border-radius: 4px;
border-radius: 4px;
border: 1px solid #001;
text-align: center;
-moz-box-shadow: inset 0px 0px 1px 0px #002;
white-space: normal;
background: #ddf url('images/lightbluetile.png');
opacity: 1.0;
}
.title {
font: normal bold 20pt/120% 'Lucida Sans Unicode', 'Bitstream Vera Sans', Verdana, Tahoma, Helvetica, sans-serif;
font-weight: bold;
letter-spacing: 0.15em;
text-shadow: 0px 0px 1px rgba(0, 0, 148, 0.9);
}
.subtitle {
font-size: 8pt;
color: #cf0606;
letter-spacing: 5pt;
text-shadow: 0px 0px 1px rgba(148, 0, 0, 0.9);
}
.checkmail {
font: bold 8pt "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
color: #555;
}
.menubox {
float: left;
width: 175px;
margin: 0px 0px 10px 10px;
padding: 10px;
text-align: left;
border: 1px solid #000033;
background: #ddf url('images/lightbluetile.png');
color: #000;
font-size: 8pt;
clear: left;
-moz-border-radius: 4px;
-khtml-border-radius: 4px;
border-radius: 4px;
-moz-box-shadow: inset 0px 0px 1px 0px #002;
}
.menubox a:link, .menubox a:visited {
text-shadow: 0px 0px 1px rgba(0, 0, 32, 0.5);
}
.menubox a:hover {
text-shadow: 0px 0px 0.5px rgba(255, 255, 255, 0.7);
color: #f60;
}
.menubox h2 {
font-size: 12pt;
color: #001;
letter-spacing: 0.05em;
text-shadow: 0px 0px 1px rgba(0, 0, 64, 0.5);
wordwrap: none;
}
.statusbox table {
width: 100%;
}
.statusbox td {
text-align: left;
color: #000;
font-size: 8pt;
vertical-align: top;
padding: 0px 30px 0px 0px;
width: 100%;
}
.main {
width: 800px;
margin: 0px 20px 20px 240px;
padding: 0 15px 15px 25px;
background: #eef;
font: 9pt/130% "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
text-align: left;
color: #001;
border: 1px solid #000033;
background: #ddf url('images/lightbluetile.png');
-moz-border-radius: 4px;
-khtml-border-radius: 4px;
border-radius: 4px;
-moz-box-shadow: inset 0px 0px 1px 0px #002;
}
.infoMessage {
margin: 0px 20px 5px 240px;
text-align: left;
color: green;
}
.errorMessage {
margin: 0px 20px 5px 240px;
text-align: left;
color: red;
}
img {
border: none;
}
a:active {
color: #900;
}
a:link {
color: #007;
text-decoration: none;
font-weight: bold;
word-wrap: break-word;
}
a:visited {
color: #606;
text-decoration: none;
font-weight: bold;
}
a:hover {
color: #f60;
text-decoration: underline;
font-weight: bold;
}
a:active {
color: #f93;
text-decoration: underline;
font-weight: bold;
}
button, button:visited {
font: bold 8pt "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
border: 1px outset #999;
padding: 1px 3px;
background: #ddf !important;
text-decoration: none;
border-radius: 4px;
-moz-border-radius: 4px;
-khtml-border-radius: 4px;
margin: 0 1px;
text-align: center;
min-width: 80px;
-moz-box-shadow: inset 0px 2px 8px 0px #fff;
color: #006;
}
button:hover {
border: 1px solid #f60;
background: #f60 !important;
color: #fff;
-moz-box-shadow: inset 0px 0px 0px 1px #fff;
}
button:active {
border: 1px solid #f60;
background: #001 !important;
color: #f60;
-moz-box-shadow: inset 0px 0px 0px 1px #f60;
}
.underline {
border-bottom: 1px solid #000022;
padding: 5px 0px 5px 0px;
margin: 0px 0px 10px 0px;
}
input {
background: #eef;
color: #001;
margin: 5px 10px 5px 10px;
padding: 4px 2px;
font: bold 8pt "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
border: 1px solid #001;
text-decoration: none;
min-width: 110px;
}
input, input:visited {
border: 1px outset #999;
background: #ddf;
color: #001;
margin: 5px;
font: bold 8pt "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
padding: 1px 2px;
text-decoration: none;
min-width: 110px;
border-radius: 4px;
-moz-border-radius: 4px;
-khtml-border-radius: 4px;
-moz-box-shadow: inset 0px 2px 8px 0px #fff;
color: #006;
opacity: 0.9;
}
input:hover {
background: #f60;
color: #fff;
border: 1px solid #f60;
opacity: 1.0;
-moz-box-shadow: inset 0px 0px 0px 1px #fff;
}
input:active {
background: #002;
color: #f60;
border: 1px solid #f60;
opacity: 1.0;
-moz-box-shadow: inset 0px 0px 0px 1px #f60;
}
input[type=text] {
width: 100%;
background: #eef;
color: #001;
margin: 5px;
padding: 5px;
font: bold 8pt "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
border: 1px solid #001;
text-decoration: none;
}
input checkbox {
border: 0 !important;
}
textarea {
width: 100%;
padding: 5px;
margin: 5px;
background: #eef;
color: #003;
border-radius: 4px;
-moz-border-radius: 4px;
-khtml-border-radius: 4px;
font: 8pt "Lucida Console", "DejaVu Sans Mono", Courier, mono;
min-height: 100px;
border: 1px solid #001;
}
submit {
background: #f00;
color: #eef;
margin: 10px 2px 10px 0;
padding: 2px;
font-family: "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
font-weight: bold;
border: 1px solid #001;
text-decoration: none;
}
select {
background: #eef;
color: #003;
padding: 2px;
margin: 5px;
border: 1px solid #001;
font: 9pt "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
border-radius: 4px;
-moz-border-radius: 4px;
-khtml-border-radius: 4px;
text-align: left !important;
}
.folder table {
table-layout: fixed;
width: 800px;
}
.identities table {
table-layout: fixed;
width: 800px;
}
.identities td, .identities th {
vertical-align: top;
padding: 0px 30px 0px 0px;
white-space: nowrap;
overflow-x: hidden;
}
.ellipsis
{
line-height: 1.2em;
height: 1.2em;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
-o-text-overflow: ellipsis;
-moz-binding: url(moz_fix2.xml#ellipsis);
}
.moz-ellipsis > DIV:first-child
{
float: left;
margin-right: -26px;
}
.moz-ellipsis > DIV + DIV
{
float: right;
margin-top: -1.2em;
background: url('images/lightbluefade.png');
padding-left: 26px;
}
.moz-ellipsis > DIV + DIV::after
{
background: url('images/lightbluetile.png');
content: '...';
}

View File

@ -1,93 +0,0 @@
<%--
Copyright (C) 2009 HungryHobo@mail.i2p
The GPG fingerprint for HungryHobo@mail.i2p is:
6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
This file is part of I2P-Bote.
I2P-Bote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
I2P-Bote is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="ib" uri="I2pBoteTags" %>
<jsp:include page="header.jsp">
<jsp:param name="title" value="Identities"/>
</jsp:include>
<div class="infoMessage">
${param.infoMessage}
</div>
<div class="main">
<h2>
Email Identities
</h2>
<c:if test="${empty ib:getIdentities().all}">
No email identities are defined.
</c:if>
<div class="identities">
<table>
<tr>
<th>Description</th>
<th>Public Name</th>
<th>Email Address</th>
<th>Key</th>
<th style="width: 20px; padding: 0px"></th>
</tr>
<c:forEach items="${ib:getIdentities().all}" var="identity">
<tr>
<td style="width: 100px;">
<div class="ellipsis">
<a href="editIdentity.jsp?new=false&key=${identity.key}&publicName=${identity.publicName}&description=${identity.description}&emailAddress=${identity.emailAddress}">
${identity.publicName}
</a>
</div>
</td>
<td style="width: 150px;">
<div class="ellipsis">
${identity.description}
</div>
</td>
<td style="width: 150px;">
<div class="ellipsis">
${identity.emailAddress}
</div>
</td>
<td style="width: 100px;">
<div class="ellipsis">
${identity.key}
</div>
</td>
<td>
<a href="deleteIdentity.jsp?key=${identity.key}"><img src="images/delete.png" alt="Delete" title="Delete this identity"/></a>
</td>
</tr>
</c:forEach>
</table>
</div>
<p/>
<form action="editIdentity.jsp?new=true" method="POST">
<button type="submit" value="New">New Identity</button>
</form>
</div>
<jsp:include page="footer.jsp"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,22 +0,0 @@
<?xml version="1.0"?>
<bindings xmlns="http://www.mozilla.org/xbl" xmlns:html="http://www.w3.org/1999/xhtml">
<binding id="ellipsis" applyauthorstyles="false">
<implementation>
<constructor><![CDATA[
(function(block){
setTimeout(function(){
block.style.mozBinding = '';
var t = document.createElement('DIV');
block.appendChild(t);
block.appendChild(document.createElement('DIV'));
while (block.firstChild != t)
t.appendChild(block.firstChild);
block.className = block.className + ' moz-ellipsis';
}, 0);
})(this);
]]></constructor>
</implementation>
</binding>
</bindings>

View File

@ -1,84 +0,0 @@
<%--
Copyright (C) 2009 HungryHobo@mail.i2p
The GPG fingerprint for HungryHobo@mail.i2p is:
6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
This file is part of I2P-Bote.
I2P-Bote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
I2P-Bote is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="ib" uri="I2pBoteTags" %>
<jsp:include page="header.jsp">
<jsp:param name="title" value="New Email"/>
</jsp:include>
<div class="main">
<form action="sendEmail.jsp">
<table>
<tr>
<td>
From:
</td>
<td>
<select name="sender">
<option value="anonymous">Anonymous</option>
<c:forEach items="${ib:getIdentities().all}" var="identity">
<option value="${identity.key}">
${identity.publicName}
<c:if test="${!empty identity.description}"> - ${identity.description}</c:if>
</option>
</c:forEach>
</select>
</td>
</tr>
<tr>
<td>
<select name="recipientType0">
<option value="to">To:</option>
<option value="cc">CC:</option>
<option value="bcc">BCC:</option>
<option value="reply_to">Reply To:</option>
</select>
</td>
<td>
<input type="text" size="80" name="recipient0"/>
</td>
</tr>
<tr>
<td valign="top"><br/>Subject:</td>
<td><input type="text" size="80" name="subject"/></td>
</tr>
<tr>
<td valign="top"><br/>Message:</td>
<td><textarea rows="30" cols="80" name="message"></textarea></td>
</tr>
<tr>
<td colspan=2 align="center">
<input type="submit" value="Send"/>
<input type="submit" value="Cancel"/>
<input type="submit" value="Save"/>
</td>
</tr>
</table>
</form>
</div>
<jsp:include page="footer.jsp"/>

View File

@ -1,64 +0,0 @@
<%--
Copyright (C) 2009 HungryHobo@mail.i2p
The GPG fingerprint for HungryHobo@mail.i2p is:
6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
This file is part of I2P-Bote.
I2P-Bote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
I2P-Bote is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<jsp:include page="header.jsp">
<jsp:param name="title" value="No Identity"/>
</jsp:include>
<div class="main">
<h2>No Email Identity Defined</h2>
<p>
In order to receive email from other people, you need to create an email identity
first.
</p><p>
This is similar to traditional email where you first have to set up an email account
with an email provider. The difference is that in I2P-Bote, there is no provider that
can read all your email because I2P-Bote stores all emails encrypted on the network.
</p><p>
I2P-Bote automatically decrypts emails sent to you, using the email identity you
created.
</p><p>
An email identity has a secret key, and a public key. Anybody who has the secret key
can download and decrypt your emails, so you should never give it to anybody. The
public key, on the other hand, allows people to send email to you. Think of it as
the equivalent of a traditional email address. Give it to everybody you want to be
able to contact you, or make it public.
</p><p>
[TODO paragraph about spam, HashCash].
</p><p>
You will find that email identities are long combinations of numbers and letters,
and that they are impossible to memorize. I2P-Bote lets you assign an email address
to an email identity to make it easier for you and your contacts to remember.
</p><p>
[TODO name attribute, address attribute].
The public addressbook should not be 100% trusted. Only destination keys are secure.
</p><p>
[TODO private address book, address directory].
<form action="editIdentity.jsp?new=true" method="POST">
<button type="submit" value="New">Create a New Email Identity</button>
</form>
</div>
<jsp:include page="footer.jsp"/>

View File

@ -1,60 +0,0 @@
<%--
Copyright (C) 2009 HungryHobo@mail.i2p
The GPG fingerprint for HungryHobo@mail.i2p is:
6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
This file is part of I2P-Bote.
I2P-Bote is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
I2P-Bote is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="ib" uri="I2pBoteTags" %>
<c:set var="email" value="${ib:getEmail(param.folder, param.messageID)}"/>
<jsp:include page="header.jsp">
<jsp:param name="title" value="${email.subject}"/>
</jsp:include>
<div class="main">
<table>
<tr>
<td valign="top"><strong>From:</strong></td>
<td>
<c:forEach var="i" begin="0" end="${fn:length(email.sender)}" step="64">
<c:if test="${i > 0}">
<br/>
</c:if>
${fn:substring(email.sender, i, i+64)}
</c:forEach>
</td>
</tr>
<tr>
<td valign="top"><strong>Subject:</strong></td>
<td>${email.subject}</td>
</tr>
<tr>
<td valign="top"><strong>Message:</strong></td>
<td>${email.bodyText}</td>
</tr>
</table>
</div>
<jsp:include page="footer.jsp"/>

927
build.xml
View File

@ -1,35 +1,203 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="I2P-Bote">
<property name="i2plib" value="/opt/i2p/lib"/>
<property name="jstllib" value="WebContent/WEB-INF/lib"/>
<property name="jettylib" value="${i2plib}"/>
<property name="antlib" value="/opt/ant/lib"/>
<project basedir="." default="help" name="I2P-Bote" xmlns:if="ant:if" xmlns:unless="ant:unless">
<property environment="env"/>
<condition property="i2pbase" value="${env.I2P}">
<isset property="env.I2P"/>
</condition>
<property name="i2plib" value="${i2pbase}/lib"/>
<property name="jstllib" value="${i2pbase}/apps/susidns/src/WEB-INF/lib"/>
<property name="lib" value="lib"/>
<property name="makeplugin" value="../i2p.scripts/plugin/makeplugin.sh"/>
<property name="junit.filename" value="junit-4.8.1.jar"/>
<property name="junit.url" value="http://sourceforge.net/projects/junit/files/junit/4.8.1/junit-4.8.1.jar/download"/>
<property name="mockito.filename" value="mockito-core-2.0.31-beta.jar"/>
<property name="mockito.url" value="https://bintray.com/artifact/download/szczepiq/maven/org/mockito/mockito-core/2.0.31-beta/mockito-core-2.0.31-beta.jar"/>
<!-- Just the main jMock .jar, the .zip contains this and dependencies -->
<property name="jmock.filename" value="jmock-2.6.0.jar"/>
<property name="jmock.archive" value="jmock-2.6.0-jars.zip"/>
<property name="jmockcp" value="${lib}/jmock-2.6.0.jar:${lib}/hamcrest-core-1.3.jar:${lib}/hamcrest-library-1.3.jar:${lib}/jmock-legacy-2.6.0.jar:${lib}/cglib-nodep-2.2.3.jar:${lib}/objenesis-1.0.jar"/>
<property name="jmock.url" value="http://jmock.org/downloads/${jmock.archive}"/>
<!-- Dependencies -->
<!-- Local -->
<property name="ntruenc.filename" value="ntruenc-1.2.jar"/>
<property name="ntruenc.includeinupdate" value="false"/>
<property name="scrypt.filename" value="scrypt-1.4.0.jar"/>
<property name="scrypt.includeinupdate" value="false"/>
<property name="lzma.filename" value="lzma-9.20.jar"/>
<property name="lzma.includeinupdate" value="false"/>
<property name="gmss.filename" value="flexi-gmss-1.7p1.jar"/>
<property name="gmss.includeinupdate" value="false"/>
<property name="jcommon.filename" value="jcommon-1.0.23.jar"/>
<property name="jcommon.includeinupdate" value="false"/>
<property name="jfreechart.filename" value="jfreechart-1.0.19.jar"/>
<property name="jfreechart.includeinupdate" value="false"/>
<!-- JavaMail -->
<property name="mailapi.name" value="JavaMail"/>
<property name="mailapi.filename" value="mailapi-1.5.4.jar"/>
<property name="mailapi.hash" value="6786437244ec10d05601c52ee418b33e31f7ce5ed2cad8c8893139b28cb18ac3"/>
<property name="mailapi.url" value="https://maven.java.net/content/repositories/releases/com/sun/mail/mailapi/1.5.4/mailapi-1.5.4.jar"/>
<property name="mailapi.includeinupdate" value="false"/>
<!-- BouncyCastle Provider -->
<property name="bcprov.name" value="BouncyCastle Provider"/>
<property name="bcprov.filename" value="bcprov-jdk15on-152.jar"/>
<property name="bcprov.hash" value="0dc4d181e4d347893c2ddbd2e6cd5d7287fc651c03648fa64b2341c7366b1773"/>
<property name="bcprov.url" value="http://downloads.bouncycastle.org/java/bcprov-jdk15on-152.jar"/>
<property name="bcprov.includeinupdate" value="false"/>
<!-- Apache James IMAP server -->
<!-- Just one of the James .jars for checking presence of James, the .zip contains this and dependencies -->
<property name="james.filename" value="apache-james-mailbox-api-0.6-20150508.040939-710.jar"/>
<property name="james.archive" value="james-server-app-3.0.0-beta5-20150627.102412-1076-app.zip"/>
<!--
James snapshots are only kept for a few days. The URL below points to a copy of the 6/27/2015 snapshot.
To be replaced with a repository.apache.org URL once beta5 is out.
-->
<property name="james.url" value="http://download.i2p2.de/mirror/lib/james-server-app-3.0.0-beta5-20150627.102412-1076-app.zip"/>
<property name="james.includeinupdate" value="false"/>
<!-- SubEtha SMTP -->
<property name="subetha.name" value="SubEtha SMTP"/>
<property name="subetha.filename" value="subethasmtp-3.1.7.jar"/>
<property name="subetha.hash" value="95cf031f1bc1b1a69b08554fbf8970bad994b32db32388d482c6afb482f1db76"/>
<property name="subetha.archive" value="subethasmtp-3.1.7.zip"/>
<property name="subetha.url" value="http://subethasmtp.googlecode.com/files/subethasmtp-3.1.7.zip"/>
<property name="subetha.includeinupdate" value="false"/>
<!-- the following are only used by win32installer -->
<property name="i2p.mtn" value="../i2p.mtn"/>
<property name="win32launcherurl" value="http://dist.codehaus.org/izpack/native-launcher/izpack-launcher-1.3.zip"/>
<property name="win32jreurl" value="http://javadl.sun.com/webapps/download/AutoDL?BundleId=47363"/>
<fileset dir="${lib}" id="imaplibs">
<include name="apache-james-mailbox-api-0.6-20150508.040939-710.jar"/>
<include name="apache-james-mailbox-store-0.6-20150508.041003-704.jar"/>
<include name="apache-mime4j-core-0.8.0-20150617.024907-738.jar"/>
<include name="apache-mime4j-dom-0.8.0-20150617.024927-735.jar"/>
<include name="commons-codec-1.7.jar"/>
<include name="commons-collections-3.2.1.jar"/>
<include name="commons-configuration-1.9.jar"/>
<include name="commons-io-2.4.jar"/>
<include name="commons-lang-2.6.jar"/>
<include name="james-server-filesystem-api-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="james-server-lifecycle-api-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="james-server-protocols-imap4-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="james-server-protocols-library-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="james-server-util-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="jutf7-1.0.0.jar"/>
<include name="log4j-1.2.17.jar"/>
<include name="netty-3.3.1.Final.jar"/>
<include name="protocols-api-1.6.4-20150617.121129-1080.jar"/>
<include name="protocols-imap-1.6.4-20150617.121245-927.jar"/>
<include name="protocols-netty-1.6.4-20150617.121137-1044.jar"/>
<include name="slf4j-api-1.7.2.jar"/>
<include name="slf4j-log4j12-1.7.2.jar"/>
</fileset>
<path id="cp">
<pathelement path="${classpath}" />
<pathelement path="${java.class.path}" />
<pathelement location="${i2plib}/i2p.jar" />
<pathelement location="${jstllib}/jstl.jar" />
<pathelement location="${jstllib}/standard.jar" />
<pathelement location="${jettylib}/org.mortbay.jetty.jar"/>
<pathelement location="${jettylib}/jasper-compiler.jar" />
<pathelement location="${jettylib}/jasper-runtime.jar" />
<pathelement location="${jettylib}/javax.servlet.jar" />
<pathelement location="${jettylib}/commons-logging.jar" />
<pathelement location="${jettylib}/commons-el.jar" />
<pathelement location="${antlib}/ant.jar" />
<pathelement location="${i2plib}/mstreaming.jar" />
<pathelement location="${i2plib}/streaming.jar" />
<pathelement location="${i2plib}/router.jar" />
<pathelement location="${i2plib}/org.mortbay.jetty.jar"/>
<pathelement location="${i2plib}/jasper-compiler.jar" />
<pathelement location="${i2plib}/jasper-runtime.jar" />
<pathelement location="${i2plib}/javax.servlet.jar" />
<pathelement location="${i2plib}/commons-logging.jar" />
<pathelement location="${i2plib}/commons-el.jar" />
<pathelement location="${i2plib}/jstl.jar" />
<pathelement location="${i2plib}/standard.jar" />
<pathelement location="${lib}/${mailapi.filename}" />
<pathelement location="${lib}/${bcprov.filename}" />
<pathelement location="${lib}/${ntruenc.filename}" />
<pathelement location="${lib}/${scrypt.filename}" />
<pathelement location="${lib}/${lzma.filename}" />
<pathelement location="${lib}/${gmss.filename}" />
<pathelement location="${lib}/${subetha.filename}" />
<pathelement location="${lib}/${jcommon.filename}" />
<pathelement location="${lib}/${jfreechart.filename}" />
<pathelement location="src/main/webapp/WEB-INF/classes" />
<fileset refid="imaplibs"/>
</path>
<target name="all" depends="clean, war" />
<pathconvert property="manifest.classpath" pathsep=" ">
<path refid="cp" />
<mapper>
<flattenmapper />
</mapper>
</pathconvert>
<target name="compile">
<target name="help">
<echo message="Useful targets:" />
<echo message=" war: Makes a .war file" />
<echo message=" plugin: Makes a I2P plugin. Only runs on Linux." />
<echo message=" Requires the i2p.scripts branch to be checked out" />
<echo message=" alongside this directory (for makeplugin.sh)." />
<echo message=" all: src + war + plugin" />
<echo message=" win32installer: Makes a Windows-only installer that installs" />
<echo message=" I2P, I2P-Bote, and optionally a JRE. Needs 7z and" />
<echo message=" mtn on the path, and a mtn DB containing i2p.i2p." />
<echo message=" Requires Ant 1.8.0 or higher." />
<echo message=" poupdate: Updates the messages_*.po files from the source code," />
<echo message=" adding any untranslated strings. Depends on additional" />
<echo message=" software, see bundle-messages.sh." />
<echo message=" This task only runs on Linux at the moment." />
<echo message=" src: Zips up the source code" />
<echo message=" junit: Runs all unit tests" />
<echo message=" javadoc: Generates code documentation in the javadoc dir" />
<echo message=" clean: Removes all generated files and directories" />
<echo message=" distclean: Removes all generated files and directories, and all downloaded libraries" />
</target>
<target name="all" depends="clean, src, war, plugin" />
<target name="checki2pbase">
<fail unless="i2pbase" message="The I2P environment variable is not set.${line.separator}It must point to an I2P installation. It is usually a path of the form ${line.separator}/xxx/yyy/i2p."/>
</target>
<macrodef name="checkdep">
<attribute name="dep"/>
<sequential>
<local name="hashValid"/>
<checksum file="${lib}/${@{dep}.filename}" algorithm="SHA-256" property="${@{dep}.hash}" verifyProperty="hashValid"/>
<fail message="The ${@{dep}.name} library has an invalid hash.">
<condition>
<isfalse value="${hashValid}"/>
</condition>
</fail>
</sequential>
</macrodef>
<target name="checkdependencies">
<available property="mailapiexists" file="${lib}/${mailapi.filename}" type="file"/>
<available property="bcprovexists" file="${lib}/${bcprov.filename}" type="file"/>
<available property="jamesexists" file="${lib}/${james.filename}" type="file"/>
<available property="subethaexists" file="${lib}/${subetha.filename}" type="file"/>
<ant target="downloadmailapi"/>
<ant target="downloadbcprov"/>
<ant target="downloadjames"/>
<ant target="downloadsubetha"/>
<checkdep dep="mailapi"/>
<checkdep dep="bcprov"/>
<checkdep dep="subetha"/>
</target>
<!-- compiles everything under src/main/java, but not src/test/ or src/build/ -->
<target name="compile" depends="checki2pbase, checkdependencies">
<mkdir dir="./ant_build" />
<mkdir dir="./ant_build/classes" />
<javac
srcdir="./src"
debug="true" deprecation="on" source="1.5" target="1.5"
srcdir="./src/main/java"
debug="true"
deprecation="on"
source="1.6" target="1.6"
includeAntRuntime="false"
destdir="./ant_build/classes"
classpathref="cp" >
<compilerarg line="" />
</javac>
classpathref="cp"
failonerror="true" />
</target>
<target name="precompilejsp">
@ -48,51 +216,720 @@
<arg value="-webinc" />
<arg value="ant_build/web-fragment.xml" />
<arg value="-webapp" />
<arg value="WebContent" />
<arg value="src/main/webapp" />
</java>
<javac debug="true" deprecation="on" source="1.5" target="1.5"
destdir="ant_build/classes" srcdir="./ant_build/jspjava"
includes="**/*.java" classpathref="jspcp">
<compilerarg line="" />
</javac>
<copy file="WebContent/WEB-INF/web-template.xml" tofile="ant_build/web.xml" />
<javac
debug="true"
deprecation="on"
source="1.6" target="1.6"
includeAntRuntime="false"
destdir="ant_build/classes"
srcdir="./ant_build/jspjava"
includes="**/*.java"
classpathref="jspcp"
failonerror="true" />
<copy file="src/main/webapp/WEB-INF/web.xml" tofile="ant_build/web.xml" />
<loadfile property="jspc.web.fragment" srcfile="ant_build/web-fragment.xml" />
<replace file="ant_build/web.xml">
<replacefilter token="&lt;!-- precompiled servlets --&gt;" value="${jspc.web.fragment}" />
</replace>
</target>
<target name="war" depends="compile,precompilejsp">
<target name="war" depends="jar">
<mkdir dir="ant_build" />
<war destfile="i2pbote.war" webxml="ant_build/web.xml">
<classes dir="ant_build/classes" includes="**/*.class" />
<classes dir="src" includes="i2p/bote/network/kademlia/built-in-peers.txt" />
<fileset dir="WebContent" includes="*.jsp"/>
<fileset dir="WebContent" includes="*.css"/>
<fileset dir="WebContent/" includes="*.xml"/>
<webinf dir="WebContent/WEB-INF/tlds" includes="*.tld"/>
<lib file="${jstllib}/jstl.jar"/>
<lib file="${jstllib}/standard.jar"/>
<zipfileset dir="WebContent/images" prefix="images"/>
<classes dir="ant_build/classes" includes="i2p/bote/web/** i2p/bote/jsp/** org/apache/jsp/**" />
<fileset dir="src/main/webapp" includes="*.html"/>
<fileset dir="src/main/webapp/" includes="*.xml"/>
<webinf dir="src/main/webapp/WEB-INF/tlds" includes="*.tld"/>
<lib file="${lib}/i2pbote.jar"/>
<lib file="${lib}/${mailapi.filename}"/>
<lib file="${lib}/${bcprov.filename}"/>
<lib file="${lib}/${ntruenc.filename}"/>
<lib file="${lib}/${scrypt.filename}"/>
<lib file="${lib}/${lzma.filename"/>
<lib file="${lib}/${gmss.filename}"/>
<lib file="${lib}/${jcommon.filename}" />
<lib file="${lib}/${jfreechart.filename}" />
<zipfileset dir="src/main/webapp/html" prefix="html"/>
<zipfileset dir="src/main/webapp/themes" prefix="themes"/>
</war>
<echo message="SHA256 sum:"/>
<exec executable="sha256sum">
<arg value="i2pbote.war"/>
</exec>
</target>
<target name="jar" depends="compile,precompilejsp,bundle">
<mkdir dir="ant_build" />
<jar destfile="${lib}/i2pbote.jar">
<fileset dir="ant_build/classes" excludes="i2p/bote/web/** i2p/bote/jsp/** org/apache/jsp/** codec/** **/*Test.class"/>
<fileset dir="src/main/java" includes="i2p/bote/network/built-in-peers.txt"/>
<fileset dir="src/main/java" includes="i2p/bote/crypto/wordlist/"/>
<manifest>
<attribute name="Class-Path" value="${manifest.classpath}" />
</manifest>
<metainf file="src/main/webapp/META-INF/mime.types"/>
</jar>
</target>
<macrodef name="packdep">
<attribute name="dep"/>
<element name="exec-args" optional="yes" implicit="yes"/>
<sequential>
<exec executable="pack200" failonerror="true">
<arg value="--no-gzip"/>
<arg value="--effort=9"/>
<arg value="--modification-time=latest"/>
<exec-args/>
<arg value="plugin/plugin.tmp/lib/${@{dep}.filename}.pack"/>
<arg value="${lib}/${@{dep}.filename}"/>
</exec>
</sequential>
</macrodef>
<macrodef name="removepack">
<attribute name="dep"/>
<sequential>
<delete file="plugin/plugin.tmp/lib/${@{dep}.filename}"/>
<delete file="plugin/plugin.tmp/lib/${@{dep}.filename}.pack"/>
</sequential>
</macrodef>
<!--
- Make two plugins, one for initial installs and one for updates.
- Neither includes jstl.jar or standard.jar, as any i2p version that has
- plugin support has these two jars pulled out of susidns.war and put in
- $I2P/lib. We set the classpath in webapps.config to find them.
-->
<target name="plugin" depends="pluginwar,getversion">
<mkdir dir="plugin/plugin.tmp/lib" />
<mkdir dir="plugin/plugin.tmp/console/webapps" />
<copy file="plugin/webapps.config" todir="plugin/plugin.tmp/console/" />
<!-- run all .jars and i2pbote-plugin.war through pack200 -->
<move file="i2pbote-plugin.war" tofile="plugin/plugin.tmp/console/webapps/i2pbote.jar" />
<exec executable="pack200" failonerror="true">
<arg value="--no-gzip"/>
<arg value="--effort=9"/>
<arg value="--modification-time=latest"/>
<arg value="plugin/plugin.tmp/console/webapps/i2pbote.war.pack"/>
<arg value="plugin/plugin.tmp/console/webapps/i2pbote.jar"/>
</exec>
<delete file="plugin/plugin.tmp/console/webapps/i2pbote.jar" />
<exec executable="pack200" failonerror="true">
<arg value="--no-gzip"/>
<arg value="--effort=9"/>
<arg value="--modification-time=latest"/>
<arg value="plugin/plugin.tmp/lib/i2pbote.jar.pack"/>
<arg value="${lib}/i2pbote.jar"/>
</exec>
<!-- pack local dependencies in updater -->
<includedep updater="true" dep="ntruenc"/>
<includedep updater="true" dep="scrypt"/>
<includedep updater="true" dep="lzma"/>
<includedep updater="true" dep="gmss"/>
<includedep updater="true" dep="jcommon"/>
<includedep updater="true" dep="jfreechart"/>
<!-- pack remote dependencies in updater -->
<includedep updater="true" dep="mailapi"/>
<includedep updater="true" dep="bcprov"/>
<includedep updater="true" dep="james"/>
<includedep updater="true" dep="subetha"/>
<copy file="src/main/scripts/encrypt.sh" todir="plugin/plugin.tmp/lib"/>
<copy file="src/main/scripts/decrypt.sh" todir="plugin/plugin.tmp/lib"/>
<copy file="src/main/scripts/fileinfo.sh" todir="plugin/plugin.tmp/lib"/>
<copy file="src/main/scripts/encrypt.bat" todir="plugin/plugin.tmp/lib"/>
<copy file="src/main/scripts/decrypt.bat" todir="plugin/plugin.tmp/lib"/>
<copy file="src/main/scripts/fileinfo.bat" todir="plugin/plugin.tmp/lib"/>
<!-- get build number -->
<buildnumber file="plugin/build.number" />
<!-- make the update xpi2p -->
<copy file="plugin/plugin.config" todir="plugin/plugin.tmp" overwrite="true" />
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.tmp/plugin.config" append="true">
<arg value="version=${version}" />
</exec>
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.tmp/plugin.config" append="true">
<arg value="update-only=true" />
</exec>
<input message="Enter key password for plugin-su3-keystore.ks:" addproperty="release.password.su3" />
<fail message="You must enter a password." >
<condition>
<equals arg1="${release.password.su3}" arg2=""/>
</condition>
</fail>
<exec executable="${makeplugin}" inputstring="${release.password.su3}" failonerror="true" >
<arg value="plugin/plugin.tmp" />
</exec>
<move file="i2pbote.xpi2p" tofile="i2pbote-update.xpi2p" />
<move file="i2pbote.su3" tofile="i2pbote-update.su3" />
<!-- pack local dependencies in installer -->
<includedep dep="ntruenc"/>
<includedep dep="scrypt"/>
<includedep dep="lzma"/>
<includedep dep="gmss"/>
<includedep dep="jcommon"/>
<includedep dep="jfreechart"/>
<!-- pack remote dependencies in installer -->
<includedep dep="mailapi"/>
<includedep dep="bcprov"/>
<includedep dep="james"/>
<includedep dep="subetha"/>
<!-- make the install xpi2p -->
<copy file="plugin/plugin.config" todir="plugin/plugin.tmp" overwrite="true" />
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.tmp/plugin.config" append="true">
<arg value="version=${version}" />
</exec>
<exec executable="${makeplugin}" inputstring="${release.password.su3}" failonerror="true" >
<arg value="plugin/plugin.tmp" />
</exec>
</target>
<!-- same as war but without the library jars -->
<target name="pluginwar" depends="compile,jar,precompilejsp,bundle">
<mkdir dir="ant_build" />
<war destfile="i2pbote-plugin.war" webxml="ant_build/web.xml">
<classes dir="ant_build/classes" includes="i2p/bote/web/** i2p/bote/jsp/** org/apache/jsp/**" />
<fileset dir="src/main/webapp" includes="*.html"/>
<fileset dir="src/main/webapp/" includes="*.xml"/>
<webinf dir="src/main/webapp/WEB-INF/tlds" includes="*.tld"/>
<zipfileset dir="src/main/webapp/html" prefix="html"/>
<zipfileset dir="src/main/webapp/themes" prefix="themes"/>
</war>
</target>
<macrodef name="includedep">
<attribute name="updater" default="false"/>
<attribute name="dep"/>
<sequential>
<local name="packDep"/>
<local name="removePack"/>
<condition property="packDep" else="false">
<or>
<and>
<istrue value="@{updater}"/>
<istrue value="${@{dep}.includeinupdate}"/>
</and>
<and>
<isfalse value="@{updater}"/>
<isfalse value="${@{dep}.includeinupdate}"/>
</and>
</or>
</condition>
<condition property="removePack" else="false">
<and>
<istrue value="@{updater}"/>
<isfalse value="${@{dep}.includeinupdate}"/>
</and>
</condition>
<ant target="packdep.@{dep}" if:true="${packDep}"/>
<ant target="removepack.@{dep}" if:true="${removePack}"/>
</sequential>
</macrodef>
<target name="packdep.ntruenc">
<packdep dep="ntruenc"/>
</target>
<target name="removepack.ntruenc">
<removepack dep="ntruenc"/>
</target>
<target name="packdep.scrypt">
<packdep dep="scrypt"/>
</target>
<target name="removepack.scrypt">
<removepack dep="scrypt"/>
</target>
<target name="packdep.lzma">
<packdep dep="lzma"/>
</target>
<target name="removepack.lzma">
<removepack dep="lzma"/>
</target>
<target name="packdep.gmss">
<packdep dep="gmss"/>
</target>
<target name="removepack.gmss">
<removepack dep="gmss"/>
</target>
<target name="packdep.jcommon">
<packdep dep="jcommon"/>
</target>
<target name="removepack.jcommon">
<removepack dep="jcommon"/>
</target>
<target name="packdep.jfreechart">
<packdep dep="jfreechart"/>
</target>
<target name="removepack.jfreechart">
<removepack dep="jfreechart"/>
</target>
<target name="packdep.mailapi">
<packdep dep="mailapi"/>
</target>
<target name="removepack.mailapi">
<removepack dep="mailapi"/>
</target>
<target name="packdep.bcprov">
<packdep dep="bcprov">
<arg value="--segment-limit=-1"/>
</packdep>
</target>
<target name="removepack.bcprov">
<removepack dep="bcprov"/>
</target>
<target name="packdep.james">
<apply executable="pack200" failonerror="true" parallel="false" dest="plugin/plugin.tmp/lib/">
<arg value="--no-gzip"/>
<arg value="--effort=9"/>
<arg value="--modification-time=latest"/>
<targetfile/>
<srcfile/>
<fileset refid="imaplibs"/>
<mapper type="glob" from="*.jar" to="*.jar.pack"/>
</apply>
</target>
<target name="removepack.james">
<apply executable="rm" dest="plugin/plugin.tmp/lib/" addsourcefile="false">
<targetfile/>
<fileset refid="imaplibs"/>
<flattenmapper/>
</apply>
<apply executable="rm" dest="plugin/plugin.tmp/lib/" addsourcefile="false">
<targetfile suffix=".pack"/>
<fileset refid="imaplibs"/>
<flattenmapper/>
</apply>
</target>
<target name="packdep.subetha">
<packdep dep="subetha"/>
</target>
<target name="removepack.subetha">
<removepack dep="subetha"/>
</target>
<target name="bundle" depends="compile">
<!-- Update the messages_*.po files.
We need to supply the bat file for windows, and then change the fail property to true -->
<exec executable="sh" osfamily="unix" failifexecutionfails="false" >
<arg value="src/build/scripts/bundle-messages.sh" />
</exec>
<exec executable="sh" osfamily="mac" failifexecutionfails="false" >
<arg value="src/build/scripts/bundle-messages.sh" />
</exec>
<exec executable="sh" osfamily="windows" failifexecutionfails="false" >
<arg value="src/build/scripts/bundle-messages.sh" />
</exec>
</target>
<!-- depends on compileantclasses for SearchAndInsert.class -->
<target name="win32installer" depends="pluginwar, compileantclasses">
<property name="installerdir" value="ant_build/win32installer"/>
<property name="installerresources" value="${installerdir}/resources"/>
<property name="i2pinstallerdir" value="${installerdir}/i2p.i2p/installer"/>
<property name="i2pinstallerplugindir" value="${installerdir}/i2p.i2p/plugins/i2pbote"/>
<mkdir dir="${installerdir}"/>
<!-- get 7z_extra.7z and extract 7zS.sfx -->
<get src="http://sourceforge.net/projects/sevenzip/files/7-Zip/9.19/7z919_extra.7z/download" dest="${installerdir}/7z_extra.7z" skipexisting="true"/>
<exec executable="7z" dir="${installerdir}">
<arg value="e"/>
<arg value="-y"/>
<arg value="7z_extra.7z"/>
<arg value="7zS.sfx"/>
</exec>
<!-- check out i2p.i2p from mtn, add i2pbote, and build install.jar -->
<delete dir="${installerdir}/i2p.i2p" />
<exec executable="mtn" dir="${installerdir}" failonerror="true">
<arg value="--db" />
<arg value="../../${i2p.mtn}" />
<arg value="--branch" />
<arg value="i2p.i2p" />
<arg value="co" />
</exec>
<!-- add I2P-Bote to install.xml -->
<java classname="i2p.bote.ant.SearchAndInsert" classpathref="cp" classpath="./ant_build/classes" failonerror="true">
<arg value="-before"/>
<arg value="${i2pinstallerdir}/install.xml"/>
<arg value="${i2pinstallerdir}/install.xml.new"/>
<arg value="&lt;/packs&gt;"/>
<arg value="win32installer/i2pbote_pack.txt"/>
</java>
<move file="${i2pinstallerdir}/install.xml.new" tofile="${i2pinstallerdir}/install.xml"/>
<!-- make the plugins dir -->
<mkdir dir="${i2pinstallerplugindir}/console/webapps"/>
<mkdir dir="${i2pinstallerplugindir}/lib"/>
<copy file="plugin/plugin.config" todir="${i2pinstallerplugindir}"/>
<copy file="i2pbote-plugin.war" tofile="${i2pinstallerplugindir}/console/webapps/i2pbote.war"/>
<copy file="plugin/webapps.config" todir="${i2pinstallerplugindir}/console"/>
<copy file="${lib}/i2pbote.jar" todir="${i2pinstallerplugindir}/lib"/>
<copy file="${lib}/${mailapi.filename}" todir="${i2pinstallerplugindir}/lib"/>
<copy file="${lib}/${bcprov.filename}" todir="${i2pinstallerplugindir}/lib"/>
<copy file="${lib}/ntruenc-1.2.jar" todir="${i2pinstallerplugindir}/lib"/>
<copy file="${lib}/scrypt-1.4.0.jar" todir="${i2pinstallerplugindir}/lib"/>
<copy file="${lib}/lzma-9.20.jar" todir="${i2pinstallerplugindir}/lib"/>
<copy file="${lib}/flexi-gmss-1.7p1.jar" todir="${i2pinstallerplugindir}/lib"/>
<copy file="${lib}/jcommon-1.0.23.jar" todir="${i2pinstallerplugindir}/lib"/>
<copy file="${lib}/jfreechart-1.0.19.jar" todir="${i2pinstallerplugindir}/lib"/>
<!-- build the I2P + I2P-Bote install.jar -->
<ant antfile="${installerdir}/i2p.i2p/build.xml" target="installer" inheritAll="false"/>
<copy file="${installerdir}/i2p.i2p/install.jar" todir="${installerresources}"/>
<!-- download Windows JRE -->
<get src="${win32jreurl}" verbose="true" dest="${installerresources}/jre.exe" skipexisting="true"/>
<copy file="win32installer/jreinstall.bat" todir="${installerresources}"/>
<copy file="win32installer/launcher.ini" todir="${installerresources}"/>
<copy file="win32installer/config.txt" todir="${installerdir}"/>
<!-- download the launcher .zip and unzip dist/* to resources/ -->
<get src="${win32launcherurl}" verbose="true" dest="${installerdir}/izpack-launcher.zip" skipexisting="true"/>
<unzip src="${installerdir}/izpack-launcher.zip" dest="${installerresources}">
<patternset>
<include name="*/dist/*"/>
</patternset>
<flattenmapper/>
</unzip>
<exec executable="7z" dir="${installerresources}" failonerror="true">
<arg value="a"/>
<arg value="../files.7z"/>
<arg value="*"/>
</exec>
<concat destfile="i2pinstall.exe" binary="true">
<fileset dir="${installerdir}" includes="7zS.sfx, config.txt, files.7z"/>
</concat>
</target>
<!-- depends on compileantclasses for JspStrings.class -->
<target name="poupdate" depends="compileantclasses">
<!-- Update the messages_*.po files. -->
<exec executable="sh" osfamily="unix" failonerror="true" >
<arg value="src/build/scripts/bundle-messages.sh" />
<arg value="-p" />
</exec>
<exec executable="sh" osfamily="mac" failonerror="true" >
<arg value="src/build/scripts/bundle-messages.sh" />
<arg value="-p" />
</exec>
<exec executable="sh" osfamily="windows" failifexecutionfails="true" >
<arg value="src/build/scripts/bundle-messages.sh" />
<arg value="-p" />
</exec>
</target>
<!-- compiles the Java code in the ant directory -->
<target name="compileantclasses" depends="compile">
<javac
srcdir="./src/build/java"
debug="true"
deprecation="on"
source="1.6" target="1.6"
includeAntRuntime="false"
destdir="./ant_build/classes"
classpathref="cp"
classpath="./ant_build/classes"
failonerror="true" />
</target>
<target name="junit" depends="compile">
<junit printsummary="yes">
<available property="junitexists" file="${lib}/${junit.filename}" type="file"/>
<ant target="downloadjunit"/>
<available property="mockitoexists" file="${lib}/${mockito.filename}" type="file"/>
<ant target="downloadmockito"/>
<available property="jmockexists" file="${lib}/${jmock.filename}" type="file"/>
<ant target="downloadjmock"/>
<path id="junitcp">
<pathelement location="${lib}/${junit.filename}"/>
<pathelement location="${lib}/${mockito.filename}"/>
<pathelement path="${jmockcp}"/>
<pathelement location="./ant_build/classes"/>
<path refid="cp"/>
</path>
<javac
srcdir="./src/test/java"
debug="true"
deprecation="on"
source="1.6" target="1.6"
includeAntRuntime="false"
destdir="./ant_build/classes"
classpathref="junitcp"
failonerror="true" />
<copy file="src/test/java/i2p/bote/packet/dht/Struwwelpeter.jpg" tofile="ant_build/classes/i2p/bote/packet/dht/Struwwelpeter.jpg"/>
<copy file="src/main/java/i2p/bote/crypto/wordlist/words_de.txt" tofile="ant_build/classes/i2p/bote/crypto/wordlist/words_de.txt"/>
<copy file="src/main/java/i2p/bote/crypto/wordlist/words_en.txt" tofile="ant_build/classes/i2p/bote/crypto/wordlist/words_en.txt"/>
<echo message="Running JUnit tests..."/>
<junit printsummary="off" failureproperty="failed">
<classpath>
<path refid="classpath"/>
<path refid="application"/>
<path refid="junitcp"/>
</classpath>
<batchtest fork="yes">
<fileset dir="${src.dir}" includes="*Test.java"/>
<batchtest fork="true" todir="./ant_build">
<fileset dir="./ant_build/classes" includes="**/*Test.class"/>
<formatter type="plain"/>
</batchtest>
</junit>
<condition property="result"
value="At least one unit test failed."
else="All unit tests were successful.">
<isset property="failed"/>
</condition>
<echo message="${result}"/>
<echo message="For details, see ant_build/TEST*"/>
</target>
<target name="downloadjunit" unless="junitexists">
<input message="JUnit not found, download now?" validargs="y,n" addproperty="userinput.junit"/>
<fail message="OK, aborting build.">
<condition>
<equals arg1="${userinput.junit}" arg2="n"/>
</condition>
</fail>
<get src="${junit.url}" verbose="true" dest="${lib}/${junit.filename}"/>
</target>
<target name="downloadmockito" unless="mockitoexists">
<input message="Mockito not found, download now?" validargs="y,n" addproperty="userinput.mockito"/>
<fail message="OK, aborting build." >
<condition>
<equals arg1="${userinput.mockito}" arg2="n"/>
</condition>
</fail>
<get src="${mockito.url}" verbose="true" dest="${lib}/${mockito.filename}"/>
</target>
<target name="downloadjmock" unless="jmockexists">
<input message="jMock not found, download now?" validargs="y,n" addproperty="userinput.jmock"/>
<fail message="OK, aborting build." >
<condition>
<equals arg1="${userinput.jmock}" arg2="n"/>
</condition>
</fail>
<get src="${jmock.url}" verbose="true" dest="${lib}/${jmock.archive}"/>
<unzip src="${lib}/${jmock.archive}" dest="${lib}">
<patternset includes="**/*.jar"/>
<mapper>
<flattenmapper/>
</mapper>
</unzip>
<delete file="${lib}/${jmock.archive}"/>
</target>
<target name="downloadmailapi" unless="mailapiexists">
<input message="JavaMail not found, download now?" validargs="y,n" addproperty="userinput.mailapi"/>
<fail message="OK, aborting build.">
<condition>
<equals arg1="${userinput.mailapi}" arg2="n"/>
</condition>
</fail>
<get src="${mailapi.url}" verbose="true" dest="${lib}/${mailapi.filename}"/>
</target>
<target name="downloadbcprov" unless="bcprovexists">
<input message="BouncyCastle Provider not found, download now?" validargs="y,n" addproperty="userinput.bcprov"/>
<fail message="OK, aborting build.">
<condition>
<equals arg1="${userinput.bcprov}" arg2="n"/>
</condition>
</fail>
<get src="${bcprov.url}" verbose="true" dest="${lib}/${bcprov.filename}"/>
</target>
<target name="downloadjames" unless="jamesexists">
<input message="Apache James not found, download now?" validargs="y,n" addproperty="userinput.junit"/>
<fail message="OK, aborting build.">
<condition>
<equals arg1="${userinput.junit}" arg2="n"/>
</condition>
</fail>
<get src="${james.url}" verbose="true" dest="${lib}/${james.archive}"/>
<unzip src="${lib}/${james.archive}" dest="${lib}">
<patternset>
<include name="**/apache-james-mailbox-api-0.6-20150508.040939-710.jar"/>
<include name="**/apache-james-mailbox-store-0.6-20150508.041003-704.jar"/>
<include name="**/apache-mime4j-core-0.8.0-20150617.024907-738.jar"/>
<include name="**/apache-mime4j-dom-0.8.0-20150617.024927-735.jar"/>
<include name="**/commons-codec-1.7.jar"/>
<include name="**/commons-collections-3.2.1.jar"/>
<include name="**/commons-configuration-1.9.jar"/>
<include name="**/commons-io-2.4.jar"/>
<include name="**/commons-lang-2.6.jar"/>
<include name="**/james-server-filesystem-api-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="**/james-server-lifecycle-api-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="**/james-server-protocols-imap4-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="**/james-server-protocols-library-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="**/james-server-util-3.0.0-beta5-SNAPSHOT.jar"/>
<include name="**/jutf7-1.0.0.jar"/>
<include name="**/log4j-1.2.17.jar"/>
<include name="**/netty-3.3.1.Final.jar"/>
<include name="**/protocols-api-1.6.4-20150617.121129-1080.jar"/>
<include name="**/protocols-imap-1.6.4-20150617.121245-927.jar"/>
<include name="**/protocols-netty-1.6.4-20150617.121137-1044.jar"/>
<include name="**/slf4j-api-1.7.2.jar"/>
<include name="**/slf4j-log4j12-1.7.2.jar"/>
</patternset>
<mapper>
<flattenmapper/>
</mapper>
</unzip>
<delete file="${lib}/${james.archive}"/>
</target>
<target name="downloadsubetha" unless="subethaexists">
<input message="SubEtha SMTP not found, download now?" validargs="y,n" addproperty="userinput.junit"/>
<fail message="OK, aborting build.">
<condition>
<equals arg1="${userinput.junit}" arg2="n"/>
</condition>
</fail>
<get src="${subetha.url}" verbose="true" dest="${lib}/${subetha.archive}"/>
<unzip src="${lib}/${subetha.archive}" dest="${lib}">
<patternset includes="**/${subetha.filename}"/>
<mapper>
<flattenmapper/>
</mapper>
</unzip>
<delete file="${lib}/${subetha.archive}"/>
</target>
<!-- Write the app version into ${version} -->
<!-- Depends on compile b/c it gets the app version from I2PBote.class -->
<target name="getversion" depends="compile">
<javac
srcdir="./src/build/java"
debug="true"
deprecation="on"
source="1.6" target="1.6"
includeAntRuntime="false"
destdir="./ant_build/classes"
classpathref="cp"
classpath="./ant_build/classes"
failonerror="true" />
<java
classname="i2p.bote.ant.PrintAppVersion"
classpathref="cp"
classpath="./ant_build/classes"
outputproperty="version"
failonerror="true"/>
<delete dir="./ant_build/classes/i2p/bote/ant" />
<echo message="I2P-Bote version is ${version}"/>
</target>
<target name="src" depends="getversion">
<property name="subdir" value="i2pbote-${version}-src"/>
<zip destfile="src.zip">
<zipfileset dir="src" prefix="${subdir}/src" followsymlinks="false"/>
<zipfileset dir="doc" prefix="${subdir}/doc"/>
<zipfileset dir="plugin" prefix="${subdir}/plugin">
<exclude name="plugin.tmp/**"/>
</zipfileset>
<zipfileset file="build.xml" prefix="${subdir}"/>
<zipfileset file="locale/messages_de.po" prefix="${subdir}/locale"/>
<zipfileset file="src/build/scripts/bundle-messages.sh" prefix="${subdir}"/>
<zipfileset file="history.txt" prefix="${subdir}"/>
<zipfileset file="license.txt" prefix="${subdir}"/>
</zip>
<echo message="SHA256 sum:"/>
<exec executable="sha256sum">
<arg value="src.zip"/>
</exec>
</target>
<target name="javadoc" depends="getversion">
<!--
Instead of eepgetting the package list, it would be easier to just let Ant
do it through the eeproxy:
<javadoc ...>
<link href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/"/>
But Ant falls back to no proxy if a proxied download fails, so eepget is preferable.
-->
<mkdir dir="ant_build" />
<property name="pkglistdir" value="ant_build/package_lists"/>
<mkdir dir="${pkglistdir}" />
<echo message="Downloading package lists"/>
<mkdir dir="${pkglistdir}/jdk"/>
<java classname="net.i2p.util.EepGet" classpath="${i2plib}/i2p.jar">
<arg value="-o"/>
<arg value="${pkglistdir}/jdk/package-list"/>
<arg value="http://docs.oracle.com/javase/6/docs/api/package-list"/>
</java>
<mkdir dir="${pkglistdir}/servlet"/>
<java classname="net.i2p.util.EepGet" classpath="${i2plib}/i2p.jar">
<arg value="-o"/>
<arg value="${pkglistdir}/servlet/package-list"/>
<arg value="http://docs.oracle.com/javaee/1.4/api/package-list"/>
</java>
<mkdir dir="${pkglistdir}/javamail"/>
<java classname="net.i2p.util.EepGet" classpath="${i2plib}/i2p.jar">
<arg value="-o"/>
<arg value="${pkglistdir}/javamail/package-list"/>
<arg value="http://java.sun.com/products/javamail/javadocs/package-list"/>
</java>
<mkdir dir="${pkglistdir}/bouncycastle"/>
<java classname="net.i2p.util.EepGet" classpath="${i2plib}/i2p.jar">
<arg value="-o"/>
<arg value="${pkglistdir}/bouncycastle/package-list"/>
<arg value="http://bouncycastle.org/docs/docs1.6/package-list"/>
</java>
<javadoc
sourcepath="src"
destdir="javadoc"
classpathref="cp"
windowtitle="I2P-Bote"
doctitle="I2P-Bote ${version} Javadoc"
use="true"
linksource="yes">
<arg value="-J-Dhttp.proxyHost=localhost"/>
<arg value="-J-Dhttp.proxyPort=4444"/>
<link href="http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/" offline="true" packagelistloc="${pkglistdir}/jdk"/>
<link href="http://download.oracle.com/docs/cd/E17477_01/javaee/1.4/api/" offline="true" packagelistloc="${pkglistdir}/servlet"/>
<link href="http://java.sun.com/products/javamail/javadocs/" offline="true" packagelistloc="${pkglistdir}/javamail"/>
<link href="http://bouncycastle.org/docs/docs1.6/" offline="true" packagelistloc="${pkglistdir}/bouncycastle"/>
<link href="http://i2p-javadocs.i2p/"/>
</javadoc>
</target>
<target name="clean">
<delete dir="ant_build" />
<delete file="${lib}/i2pbote.jar" />
<delete file="i2pbote.war" />
<delete file="i2pbote-plugin.war" />
<delete dir="plugin/plugin.tmp" />
<delete file="i2pbote.xpi2p" />
<delete file="i2pbote-update.xpi2p" />
<delete file="src.zip" />
<delete file="i2pinstall.exe" />
<delete dir="javadoc" />
</target>
<target name="distclean" depends="clean">
<delete>
<fileset refid="imaplibs"/>
</delete>
<delete file="${lib}/${subetha.filename}" />
</target>
</project>

BIN
doc/manual.odt Normal file

Binary file not shown.

BIN
doc/manual_fr.odt Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +0,0 @@
I2P-Bote
--------
This file explains how to use I2P-Bote. For technical documentation, see techdoc.txt.
1. To install the app, [TODO]
2. Set up an email address [TODO]
3. Send a test email to yourself [TODO]
4. Checking for email
When you view your inbox through the web interface or click the "Get Mail" button on your email
client, two things happen: New downloaded emails are shown, if there are any, and the I2P-Bote
network is contacted to see if more emails are waiting to be downloaded.
5. The Configuration File

177
history.txt Normal file
View File

@ -0,0 +1,177 @@
I2P-Bote Version History
------------------------
0.4.1 (Released on Sep 12, 2015)
* Fixed bugs:
o ConcurrentModificationException errors in logs
o User guide and FAQ not loading translations
0.4 (Released on Aug 21, 2015)
* Fixed bugs:
o Email checking would get stuck if no new mail was found
o "Last checked" time was inconsistent for manual checks
o Anonymous emails would never send
* Removed build number from version
* Skipped 0.3.* series
o 0.3.1 is less than 0.3-b195; would need to go to 0.3.196
0.3 (Released on Aug 15, 2015)
* New default theme based on Material design
* New features:
o Exclude individual identities from global email checking
o Manual per-identity email checking
o Import and export identities
* Strip prefixes, spaces and newlines from email destinations (to better
handle destinations pasted from different sources). Supported prefixes:
o mailto:
o bote:
o i2pbote:
* Translations for user guide and FAQ
* Use I2P XSSFilter on inputs
* Bundle BouncyCastle 1.51 crypto provider
* In-app update notification removed
* IMAP temporarily disabled due to bug
* Bug fixes
0.2.10 (Released on Jul 23, 2014)
* Vanity destinations
* Security fix related to ElGamal email destinations
* IMAP fixes
* "After merging, IndexPacket is too big..." error fixed
* Numerous fixes and enhancements by str4d
0.2.9 (Released on Feb 7, 2014)
* Experimental SMTP and IMAP support
* UI and IMAP improvements by str4d
* Misc. UI improvements
0.2.8 (Released on Mar 8, 2013)
* Fixes and enhancements to the address directory
0.2.7 (Released on Feb 13, 2013)
* Delivery confirmations
* Basic distributed address directory
* Datagram-only communication, streams no longer used;
smaller datagrams for better reliability
* More translations
* UI Themes
* Misc. UI improvements
* Bug fixes
0.2.6 (Released on Apr 26, 2011)
* Password encryption of mail folders, identities, and contacts
* New translations (in chronological order):
o French by albat, redzara and magma
o Spanish by mixxy
o Dutch by KwukDuck
o Portuguese by mixxy
o Norwegian by nej
o Swedish by hottuna
o Chinese by walking
o Arabic by hamada
* In-app user guide and FAQ in English (by mixxy) and its French translation (by magma)
* Availability of updates now displayed in I2P-Bote itself
* NTRU encryption / GMSS signatures
* Big packets are now sent as streams (see http://trac.i2p2.de/ticket/346)
* Fix: Email files not deleted on Windows
* Fix: Emails in sent folder and outbox not signed
* Fix: Seedless not used if I2P-Bote is ready before Seedless
* Minor fixes and enhancements
0.2.5 (Released on Oct 04, 2010)
* Email attachments
* Seedless peer exchange
* Russian translation by suhr
* All generated files are now read/writable by the owner only
* I2P-Bote always uses the router console language (if translation available)
* The network page now shows peers in b32 for I2P compatibility
* Address book and identities are now sorted alphabetically
* The "unknown" column has been inverted to a "known" column
* Signatures for sent emails are not shown because signatures are not saved
* Emails, including attachments, are compressed before sending
* Protocol version 4
* Improvements and fixes to relaying
* Fix for a bug that sometimes made emails to ECC destinations disappear
* Many more bugfixes and improvements. Thanks to mixxy and others for testing!
0.2.4 (Released on Jun 14, 2010)
* Elliptic curve encryption
* Email can be sent via relays for added anonymity
* Experimental gateway (in/outproxy) support
* Protocol version 3, fixes two weaknesses
* Kademlia replication
* Fix: Error when trying to send anonymously
0.2.3 (Released on May 10, 2010)
* Email signatures
* Multiple recipients / CC / BCC implemented
* A button on the "new email" page for adding a recipient to the address book
* Local names for Email Destinations are displayed automatically and
take priority over names chosen by senders
* Local names for Email Destinations are removed from emails before sending
* Sorted mail folders
* Outbox functionality; emails are now sent in the background
* Sent folder, Trash folder
* No more getting the same email over and over again
* New options on the Settings page:
o Enable/disable sending of date/time
o Enable/disable localization of text that recipients see, such as "Re:"
o UI language
* Misc UI enhancements
* Fix for a bug that caused excessive CPU usage
* Fix for a bug that hid the first row in a table (identities, inbox, etc.)
0.2.2 (Released on Mar 22, 2010)
* German translation
* Automatic mail checking is now user-configurable
* Save peers.txt on exit
* Several minor changes
* Several bug fixes
0.2.1 (Released on Mar 05, 2010)
* I2P-Bote can now be run as an I2P plugin (I2P 0.7.12 or newer required)
* Option to set a default Email Identity
* Address book
* Umlaute and other non-ASCII characters are now supported
* Increase k-bucket size to 20
* Several bug fixes
0.2 (Released on Feb 01, 2010)
* Sending and retrieving now much faster
* Email packets are now deleted from storage nodes after retrieval
* Reply button
* Drop dead peers
* Automatically check for new email
* Inbox shows new emails in bold, number of new emails is shown
* "To" addresses are shown in the inbox and when displaying an email
* Network protocol changed to version 2, peers that use the old protocol are ignored
* "Network" page now shows peer info
* Several bug fixes and minor enhancements
0.1.5 (Released on Dec 19, 2009)
* Fixes a number of bugs in the Kademlia code
* Removed unimplemented HTML links
* Network-related UI elements are now disabled until tunnel is ready
* Emails can now be deleted from a folder
* "No Identity Defined" page didn't come up, fixed
0.1.4
* Do the 3-minute wait in the background
* Added a "Connect now" button to skip the wait
* Network Status panel now gives more useful information
0.1.3
* After startup, wait 3 minutes before connecting
* Change the paths in the build file from /opt/... to ../i2p/...
* Fix: "Check Mail" button doesn't show new emails, user has to reload inbox
* Fix: high cpu usage when sending or receiving
* Set tunnel names to "I2P-Bote"
0.1.2
Mostly a bug fix release. It adds two .jar files that were missing.
0.1.1
Fix: Clicking on an email in the inbox causes an error.
0.1 (Released on Dec 06, 2009)
First version. Lets a user create email identities and send/receive plain-text emails

BIN
lib/flexi-gmss-1.7p1.jar Normal file

Binary file not shown.

BIN
lib/jcommon-1.0.23.jar Normal file

Binary file not shown.

BIN
lib/jfreechart-1.0.19.jar Normal file

Binary file not shown.

BIN
lib/lzma-9.20.jar Normal file

Binary file not shown.

BIN
lib/ntruenc-1.2.jar Normal file

Binary file not shown.

BIN
lib/scrypt-1.4.0.jar Normal file

Binary file not shown.

View File

@ -1,674 +1,10 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
LICENSES
--------
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This software is licensed under the GPL version 3 (see licenses/GPLv3.txt),
except for:
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
- bcprov-jdk15on-152.jar which is licensed under the Bouncy Castle License
(see licenses/BouncyCastle.txt).
- nl.jteam.tls.StrongTls which is licensed under the Apache License, Version
2.0 (see licenses/LICENSE-Apache2.0.txt).

22
licenses/BouncyCastle.txt Normal file
View File

@ -0,0 +1,22 @@
License
Copyright (c) 2000 - 2009 The Legion Of The Bouncy Castle
(http://www.bouncycastle.org)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

674
licenses/GPLv3.txt Normal file
View File

@ -0,0 +1,674 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

1326
locale/messages_ar.po Normal file

File diff suppressed because it is too large Load Diff

1332
locale/messages_cs.po Normal file

File diff suppressed because it is too large Load Diff

1373
locale/messages_de.po Normal file

File diff suppressed because it is too large Load Diff

1356
locale/messages_en.po Normal file

File diff suppressed because it is too large Load Diff

1392
locale/messages_es.po Normal file

File diff suppressed because it is too large Load Diff

1317
locale/messages_fi.po Normal file

File diff suppressed because it is too large Load Diff

1378
locale/messages_fr.po Normal file

File diff suppressed because it is too large Load Diff

1332
locale/messages_hu.po Normal file

File diff suppressed because it is too large Load Diff

1352
locale/messages_id.po Normal file

File diff suppressed because it is too large Load Diff

1369
locale/messages_it.po Normal file

File diff suppressed because it is too large Load Diff

1343
locale/messages_ja.po Normal file

File diff suppressed because it is too large Load Diff

1347
locale/messages_nb.po Normal file

File diff suppressed because it is too large Load Diff

1366
locale/messages_nl.po Normal file

File diff suppressed because it is too large Load Diff

1363
locale/messages_pl.po Normal file

File diff suppressed because it is too large Load Diff

1366
locale/messages_pt.po Normal file

File diff suppressed because it is too large Load Diff

1339
locale/messages_pt_BR.po Normal file

File diff suppressed because it is too large Load Diff

1356
locale/messages_ro.po Normal file

File diff suppressed because it is too large Load Diff

1367
locale/messages_ru.po Normal file

File diff suppressed because it is too large Load Diff

1353
locale/messages_sk.po Normal file

File diff suppressed because it is too large Load Diff

1357
locale/messages_sv.po Normal file

File diff suppressed because it is too large Load Diff

1326
locale/messages_uk.po Normal file

File diff suppressed because it is too large Load Diff

1325
locale/messages_vi.po Normal file

File diff suppressed because it is too large Load Diff

1335
locale/messages_zh.po Normal file

File diff suppressed because it is too large Load Diff

113
nbproject/project.xml Normal file
View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://www.netbeans.org/ns/project/1">
<type>org.netbeans.modules.ant.freeform</type>
<configuration>
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
<name>I2P-Bote</name>
</general-data>
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/2">
<!-- Do not use Project Properties customizer when editing this file manually. -->
<name>I2P-Bote</name>
<properties/>
<folders>
<source-folder>
<label>I2P-Bote</label>
<location>.</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
<label>WebContent</label>
<type>doc_root</type>
<location>WebContent</location>
</source-folder>
<source-folder>
<label>WEB-INF</label>
<type>web_inf</type>
<location>WebContent/WEB-INF</location>
</source-folder>
<source-folder>
<label>test</label>
<type>java</type>
<location>test</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
<label>src</label>
<type>java</type>
<location>src</location>
<encoding>UTF-8</encoding>
</source-folder>
</folders>
<ide-actions>
<action name="build">
<target>all</target>
</action>
<action name="clean">
<target>clean</target>
</action>
<action name="test">
<target>junit</target>
</action>
<action name="rebuild">
<target>clean</target>
<target>all</target>
</action>
</ide-actions>
<export>
<type>folder</type>
<location>ant_build/classes</location>
<build-target>all</build-target>
</export>
<view>
<items>
<source-folder style="tree">
<label>Web Pages</label>
<location>WebContent</location>
</source-folder>
<source-folder style="tree">
<label>WEB-INF Content</label>
<location>WebContent/WEB-INF</location>
</source-folder>
<source-folder style="packages">
<label>test</label>
<location>test</location>
</source-folder>
<source-folder style="packages">
<label>src</label>
<location>src</location>
</source-folder>
<source-file>
<location>build.xml</location>
</source-file>
</items>
<context-menu>
<ide-action name="build"/>
<ide-action name="rebuild"/>
<ide-action name="clean"/>
<ide-action name="test"/>
</context-menu>
</view>
<subprojects/>
</general-data>
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/1">
<compilation-unit>
<package-root>test</package-root>
<classpath mode="compile">../i2p/core/java/build/i2p.jar:../i2p/apps/jetty/jettylib/org.mortbay.jetty.jar:../i2p/apps/jetty/jettylib/jasper-compiler.jar:../i2p/apps/jetty/jettylib/jasper-runtime.jar:../i2p/apps/jetty/jettylib/javax.servlet.jar:../i2p/apps/jetty/jettylib/commons-logging.jar:../i2p/apps/jetty/jettylib/commons-el.jar:../i2p/apps/susidns/src/WEB-INF/lib/jstl.jar:../i2p/apps/susidns/src/WEB-INF/lib/standard.jar:WebContent/WEB-INF/lib/mailapi.jar:WebContent/WEB-INF/lib/bcprov-jdk15on-152.jar:ant_build/classes:/usr/local/netbeans-6.5/platform9/modules/ext/junit-4.5.jar:../i2p/router/java/build/router.jar:WebContent/WEB-INF/lib/commons-fileupload-1.2.1.jar:WebContent/WEB-INF/lib/commons-io-1.4.jar</classpath>
<source-level>1.5</source-level>
</compilation-unit>
<compilation-unit>
<package-root>src</package-root>
<classpath mode="compile">../i2p/core/java/build/i2p.jar:../i2p/apps/jetty/jettylib/org.mortbay.jetty.jar:../i2p/apps/jetty/jettylib/jasper-compiler.jar:../i2p/apps/jetty/jettylib/jasper-runtime.jar:../i2p/apps/jetty/jettylib/javax.servlet.jar:../i2p/apps/jetty/jettylib/commons-logging.jar:../i2p/apps/jetty/jettylib/commons-el.jar:../i2p/apps/susidns/src/WEB-INF/lib/jstl.jar:../i2p/apps/susidns/src/WEB-INF/lib/standard.jar:WebContent/WEB-INF/lib/mailapi.jar:WebContent/WEB-INF/lib/bcprov-jdk15on-152.jar:ant_build/classes:../i2p/apps/streaming/java/build/streaming.jar:../i2p/apps/ministreaming/java/build/mstreaming.jar:../i2p/apps/routerconsole/java/build/routerconsole.jar:../i2p/router/java/build/router.jar:WebContent/WEB-INF/lib/commons-fileupload-1.2.1.jar:WebContent/WEB-INF/lib/commons-io-1.4.jar</classpath>
<built-to>ant_build/classes</built-to>
<source-level>1.5</source-level>
</compilation-unit>
</java-data>
<web-data xmlns="http://www.netbeans.org/ns/freeform-project-web/1">
<web-module>
<doc-root>WebContent</doc-root>
<classpath/>
<j2ee-spec-level>1.5</j2ee-spec-level>
</web-module>
</web-data>
</configuration>
</project>

44
plugin/plugin.config Normal file
View File

@ -0,0 +1,44 @@
name=i2pbote
signer=str4d@mail.i2p
consoleLinkName=SecureMail
consoleLinkName_de=Sichere.Mail
consoleLinkName_nl=Beveiligde Mail
consoleLinkName_fr=CourrierSécurisé
consoleLinkName_es=CorreoSeguro
consoleLinkName_pt=CorreioSeguro
consoleLinkName_ru=Безопасная почта
consoleLinkName_no=SecureMail #SikkerPost
consoleLinkName_sv=SäkerPost
consoleLinkName_zh=安全电邮
consoleLinkName_ar=بريد الكتروني الآمن
consoleLinkTooltip=Decentralized secure email
consoleLinkTooltip_de=Dezentrale, sichere Mailanwendung
consoleLinkTooltip_nl=Gedecentraliseerde beveiligde email
consoleLinkTooltip_fr=Courrier sécurisé et décentralisé
consoleLinkTooltip_es=Correo electrónico seguro y descentralizado
consoleLinkTooltip_pt=Correio eletrônico seguro e descentralizado
consoleLinkTooltip_ru=Безопасная распределённая почта
consoleLinkTooltip_no=Desentralisert sikker epost
consoleLinkTooltip_sv=Decentraliserad säker e-post
consoleLinkTooltip_zh=安全分布式电子邮件
consoleLinkTooltip_ar=بريد الكتروني الآمن و الغير متمركز
consoleLinkURL=/i2pbote/index.jsp
console-icon=/themes/material/icon.png
websiteURL=http://bote.i2p/
updateURL=http://bote.i2p/i2pbote-update.xpi2p
updateURL.su3=http://bote.i2p/i2pbote-update.su3
description=Decentralized secure email
description_de=Dezentrale, sichere Mailanwendung
description_nl=Gedecentraliseerde beveiligde email
description_fr=Courrier sécurisé et décentralisé
description_es=Correo electrónico seguro y descentralizado
description_pt=Correio eletrônico seguro e descentralizado
description_ru=Безопасная распределённая почта
description_no=Desentralisert sikker epost
description_sv=Decentraliserad säker e-post
description_zh=安全分布式电子邮件
description_ar=بريد الكتروني الآمن و الغير متمركز
license=GPL V3
min-java-version=1.6
min-i2p-version=0.9.18
author=str4d@mail.i2p

1
plugin/webapps.config Normal file
View File

@ -0,0 +1 @@
webapps.i2pbote.classpath=$I2P/lib/jstl.jar,$I2P/lib/standard.jar,$PLUGIN/lib/i2pbote.jar,$PLUGIN/lib/mailapi-1.5.4.jar,$PLUGIN/lib/bcprov-jdk15on-152.jar,$PLUGIN/lib/flexi-gmss-1.7p1.jar,$PLUGIN/lib/ntruenc-1.2.jar,$PLUGIN/lib/scrypt-1.4.0.jar,$PLUGIN/lib/lzma-9.20.jar,$PLUGIN/lib/apache-james-mailbox-api-0.6-20150508.040939-710.jar,$PLUGIN/lib/apache-james-mailbox-store-0.6-20150508.041003-704.jar,$PLUGIN/lib/apache-mime4j-core-0.8.0-20150617.024907-738.jar,$PLUGIN/lib/commons-codec-1.7.jar,$PLUGIN/lib/commons-collections-3.2.1.jar,$PLUGIN/lib/commons-configuration-1.9.jar,$PLUGIN/lib/commons-io-2.4.jar,$PLUGIN/lib/commons-lang-2.6.jar,$PLUGIN/lib/james-server-filesystem-api-3.0.0-beta5-SNAPSHOT.jar,$PLUGIN/lib/james-server-lifecycle-api-3.0.0-beta5-SNAPSHOT.jar,$PLUGIN/lib/james-server-protocols-imap4-3.0.0-beta5-SNAPSHOT.jar,$PLUGIN/lib/james-server-protocols-library-3.0.0-beta5-SNAPSHOT.jar,$PLUGIN/lib/james-server-util-3.0.0-beta5-SNAPSHOT.jar,$PLUGIN/lib/jcommon-1.0.23.jar,$PLUGIN/lib/jfreechart-1.0.19.jar,$PLUGIN/lib/jutf7-1.0.0.jar,$PLUGIN/lib/log4j-1.2.17.jar,$PLUGIN/lib/netty-3.3.1.Final.jar,$PLUGIN/lib/protocols-api-1.6.4-20150617.121129-1080.jar,$PLUGIN/lib/protocols-imap-1.6.4-20150617.121245-927.jar,$PLUGIN/lib/protocols-netty-1.6.4-20150617.121137-1044.jar,$PLUGIN/lib/slf4j-api-1.7.2.jar,$PLUGIN/lib/slf4j-log4j12-1.7.2.jar,$PLUGIN/lib/subethasmtp-3.1.7.jar

View File

@ -0,0 +1,207 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.ant;
import i2p.bote.Util;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
/**
* A command line program that extracts strings from <ib:message> tags and prints them
* to stdout in .po format (the .po header is not printed).
*/
public class JspStrings {
public static void main(String[] args) throws IOException {
if (args.length < 1) {
System.out.println("Syntax: JspStrings <Directory>");
System.out.println();
System.out.println("Prints .po entries for the <ib:message> keys in all .jsp");
System.out.println("and .tag files in <Directory> and its subdirectories.");
System.exit(1);
}
List<PoEntry> poEntries = processDirectory(new File(args[0]));
removeDuplicates(poEntries);
for (PoEntry poEntry: poEntries)
print(poEntry);
}
static void removeDuplicates(List<PoEntry> poEntries) {
for (int i=poEntries.size()-1; i>=0; i--)
for (int j=poEntries.size()-1; j>i; j--) {
PoEntry entry1 = poEntries.get(i);
PoEntry entry2 = poEntries.get(j);
if (entry1!=entry2 && entry1.msgKey.equals(entry2.msgKey))
poEntries.remove(entry2);
}
}
static void print(PoEntry poEntry) {
System.out.println("#: " + poEntry.comment);
System.out.println("msgid \"" + poEntry.msgKey + "\"");
System.out.println("msgstr \"\"");
System.out.println();
}
static List<PoEntry> processDirectory(File dir) throws IOException {
List<PoEntry> results = new ArrayList<PoEntry>();
// extract strings from all files in the directory
File[] files = dir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toLowerCase().endsWith(".jsp") || name.toLowerCase().endsWith(".tag");
}
});
for (File file: files)
results.addAll(processFile(file));
// recurse into subdirectories
File[] subdirs = dir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory();
}
});
for (File subdir: subdirs)
results.addAll(processDirectory(subdir));
return results;
}
static List<PoEntry> processFile(File file) throws IOException {
FileInputStream inputStream = new FileInputStream(file);
BufferedReader inputReader = new BufferedReader(new InputStreamReader(inputStream));
// Read the file into a string
StringBuilder strBuilder = new StringBuilder();
while (true) {
String line = inputReader.readLine();
if (line == null)
break;
if (strBuilder.length() > 0)
strBuilder = strBuilder.append(System.getProperty("line.separator"));
strBuilder = strBuilder.append(line);
}
inputStream.close();
String fileContents = strBuilder.toString();
String[] tags = fileContents.split("<ib:message");
List<String> msgKeys = new ArrayList<String>();
for (int i=1; i<tags.length; i++) {
String tag = tags[i];
if (!shouldSkip(tag)) {
String key = extract(tag);
if (key != null)
msgKeys.add(key);
}
}
List<PoEntry> entries = new ArrayList<PoEntry>();
entries.addAll(PoEntry.create(msgKeys, file));
return entries;
}
/**
* Extracts a message key from a ib:message tag
* @param tag a ib:message tag minus the &lt;ib:message part at the beginning
* @return
*/
static String extract(String tag) {
if (tag.contains(" key=")) // format is <ib:message key="foobar" .../> ...
return extractFromKeyAttribute(tag);
else // format is <ib:message ...>foobar</ib:message> ...
return extractFromTagBody(tag);
}
/**
* Extracts the text between <ib:message> and </ib:message>
* @param tag a ib:message tag minus the &lt;ib:message part at the beginning
*/
static String extractFromTagBody(String tag) {
int gtIndex = tag.indexOf(">");
tag = tag.substring(gtIndex + 1);
int endIdx = tag.indexOf("</ib:message");
if (endIdx < 0) {
System.err.println("No \"</ib:message\" end tag in string: <" + tag + ">");
return null;
}
String str = tag.substring(0, endIdx);
// convert multiple whitespaces in a row to a single space, remove leading and trailing whitespace
str = Util.removeExtraWhitespace(str);
return str;
}
/** Extracts the values of the "key" attribute */
static String extractFromKeyAttribute(String string) {
String keyAttrSQ = "key='";
String keyAttrDQ = "key=\"";
int keyAttrLen = keyAttrDQ.length();
int startIdxSQ = string.indexOf(keyAttrSQ);
int endIdxSQ = string.indexOf("'", startIdxSQ+keyAttrLen);
int startIdxDQ = string.indexOf(keyAttrDQ);
int endIdxDQ = string.indexOf("\"", startIdxDQ+keyAttrLen);
if (startIdxSQ>=0 && (startIdxSQ<startIdxDQ || startIdxDQ<0) && endIdxSQ>=0)
return string.substring(startIdxSQ+keyAttrLen, endIdxSQ);
else if (startIdxDQ>=0 && (startIdxDQ<startIdxSQ || startIdxSQ<0) && endIdxDQ>=0)
return string.substring(startIdxDQ+keyAttrLen, endIdxDQ);
else {
System.err.println("Expected a string containing key=\"...\" or key='...', got " + string);
return null;
}
}
/** Returns <code>true</code> if a ib:message tag has the noextract attribute set to <code>true</code>. */
static boolean shouldSkip(String tag) {
tag = tag.replaceAll("\\s+", "");
return tag.contains("noextract=\"true\"") || tag.contains("noextract='true'");
}
static class PoEntry {
String msgKey;
String comment;
static List<PoEntry> create(List<String> msgKeys, File file) {
List<PoEntry> poEntries = new ArrayList<PoEntry>();
for (String msgKey: msgKeys) {
PoEntry entry = new PoEntry();
entry.msgKey = msgKey;
entry.comment = file.toString();
poEntries.add(entry);
}
return poEntries;
}
}
}

View File

@ -0,0 +1,31 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.ant;
import i2p.bote.I2PBote;
public class PrintAppVersion {
public static void main(String[] args) {
System.out.println(I2PBote.getAppVersion());
}
}

View File

@ -0,0 +1,107 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.ant;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/**
* Searches a text file for a string and adds text before
* or after the first occurrence of the search string.
*/
public class SearchAndInsert {
enum Position {BEFORE, AFTER};
public static void main(String[] args) throws IOException {
if (args.length < 4) {
System.out.println("Syntax: SearchAndInsert [-after|-before] <inputFile> <outputFile> <key> <newTextFile>");
System.out.println();
System.out.println("Searches a text file for a string and adds text before or after");
System.out.println("the first occurrence of the search string. The new text is read");
System.out.println("from a file.");
System.out.println("The default is to insert after the search string.");
System.exit(1);
}
int argIndex = 0;
Position position = Position.AFTER;
if ("-before".equals(args[0]) || "-after".equals(args[0])) {
argIndex++;
if ("-before".equals(args[0]))
position = Position.BEFORE;
}
BufferedReader reader = null;
BufferedWriter writer = null;
try {
reader = new BufferedReader(new FileReader(args[argIndex++]));
writer = new BufferedWriter(new FileWriter(args[argIndex++]));
String searchString = args[argIndex++];
String newTextFile = args[argIndex];
while (true) {
String line = reader.readLine();
if (line == null)
break;
boolean match = line.contains(searchString);
if (match && position==Position.BEFORE) {
write(writer, newTextFile);
writer.newLine();
}
writer.write(line);
writer.newLine();
if (match && position==Position.AFTER) {
write(writer, newTextFile);
writer.newLine();
}
}
}
finally {
if (reader != null)
reader.close();
if (writer != null)
writer.close();
}
}
private static void write(BufferedWriter writer, String filename) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(filename));
while (true) {
String line = reader.readLine();
if (line == null)
break;
writer.write(line);
writer.newLine();
}
}
finally {
if (reader != null)
reader.close();
}
}
}

View File

@ -0,0 +1,120 @@
#!/bin/sh
#
# Update messages_xx.po and messages_xx.class files,
# from both java and jsp sources.
# Requires installed programs xgettext, msgfmt, msgmerge, msguniq, find,
# and the Java class i2p.bote.ant.JspStrings.
# On Linux, the programs xgettext and msg* can be found in the gettext package.
#
# usage:
# bundle-messages.sh (generates the resource bundle from the .po file)
# bundle-messages.sh -p (updates the .po file from the source tags, then generates the resource bundle)
#
# zzz - public domain
#
JAVA=java
CLASS=i2p.bote.locale.Messages
TMPFILE=ant_build/javafiles.txt
export TZ=UTC
if [ "$1" = "-p" ]
then
POUPDATE=1
fi
# on windows, one must specify the path of commnad find
# since windows has its own retarded version of find.
if which find|grep -q -i windows ; then
export PATH=.:/bin:/usr/local/bin:$PATH
fi
# Fast mode - update ondemond
echo setting the environment variable LG2={LangCode}
echo will limit .po file update to the language specified by {LangCode}.
# add ../java/ so the refs will work in the po file
JPATHS="src/main/java"
JSPPATHS="src/main/webapp"
for i in locale/messages_*.po
do
# get language
LG=${i#locale/messages_}
LG=${LG%.po}
# skip, if specified
if [ $LG2 ]; then
[ $LG != $LG2 ] && continue || echo INFO: Language update is set to [$LG2] only.
fi
if [ "$POUPDATE" = "1" ]
then
# make list of java files newer than the .po file
find $JPATHS -name *.java -newer $i > $TMPFILE
find $JSPPATHS -name *.java -newer $i >> $TMPFILE
fi
if [ -s ant_build/classes/i2p/bote/locale/messages_$LG.class -a \
ant_build/classes/i2p/bote/locale/messages_$LG.class -nt $i -a \
! -s $TMPFILE ]
then
continue
fi
if [ "$POUPDATE" = "1" ]
then
echo "Updating the $i file from the tags..."
# extract strings from java and jsp files, and update messages.po files
# translate calls must be one of the forms:
# _("foo")
# _x("foo")
# To start a new translation, copy the header from an old translation to the new .po file,
# then ant distclean poupdate.
find $JPATHS -name *.java > $TMPFILE
xgettext -f $TMPFILE -F -L java --from-code=UTF-8 \
--keyword=_ --keyword=_x \
-o ${i}t
if [ $? -ne 0 ]
then
echo 'Warning - xgettext failed, not updating translations'
rm -f ${i}t
break
fi
# extract strings from jsp files
$JAVA -cp ant_build/classes:$I2P/lib/i2p.jar i2p.bote.ant.JspStrings $JSPPATHS >> ${i}t
if [ $? -ne 0 ]
then
echo 'Warning - JspStrings failed, not updating translations'
rm -f ${i}t
break
fi
msguniq -o ${i}t ${i}t
msgmerge -U --backup=none $i ${i}t
if [ $? -ne 0 ]
then
echo 'Warning - msgmerge failed, not updating translations'
rm -f ${i}t
break
fi
rm -f ${i}t
# so we don't do this again
touch $i
fi
if [ "$LG" != "en" ]
then
# only generate for non-source language
echo "Generating ${CLASS}_$LG ResourceBundle..."
# convert to class files in ant_build/classes
msgfmt --java --statistics -r $CLASS -l $LG -d ant_build/classes $i
if [ $? -ne 0 ]
then
echo 'Warning - msgfmt failed, not updating translations'
break
fi
fi
done
rm -f $TMPFILE
# todo: return failure
exit 0

View File

@ -1,223 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
public class Configuration extends Properties {
private static final long serialVersionUID = -6318245413106186095L;
private static final String I2P_BOTE_SUBDIR = "i2pbote"; // relative to the I2P app dir
private static final String CONFIG_FILE_NAME = "i2pbote.config";
private static final String DEST_KEY_FILE_NAME = "local_dest.key";
private static final String PEER_FILE_NAME = "peers.txt";
private static final String IDENTITIES_FILE_NAME = "identities.txt";
private static final String OUTBOX_DIR = "outbox"; // relative to I2P_BOTE_SUBDIR
private static final String OUTBOX_SUBDIR_LOCAL = "local"; // relative to OUTBOX_DIR
private static final String OUTBOX_SUBDIR_RELAY = "relay"; // relative to OUTBOX_DIR
private static final String INCOMPLETE_SUBDIR = "incomplete"; // relative to I2P_BOTE_SUBDIR
private static final String EMAIL_DHT_SUBDIR = "dht_email_pkt"; // relative to I2P_BOTE_SUBDIR
private static final String INDEX_PACKET_DHT_SUBDIR = "dht_index_pkt"; // relative to I2P_BOTE_SUBDIR
private static final String INBOX_SUBDIR = "inbox"; // relative to I2P_BOTE_SUBDIR
// Parameter names in the config file
private static final String PARAMETER_REDUNDANCY = "redundancy";
private static final String PARAMETER_STORAGE_SPACE_INBOX = "storageSpaceInbox";
private static final String PARAMETER_STORAGE_SPACE_RELAY = "storageSpaceRelay";
private static final String PARAMETER_STORAGE_TIME = "storageTime";
private static final String PARAMETER_MAX_FRAGMENT_SIZE = "maxFragmentSize";
private static final String PARAMETER_HASHCASH_STRENGTH = "hashCashStrength";
private static final String PARAMETER_SMTP_PORT = "smtpPort";
private static final String PARAMETER_POP3_PORT = "pop3Port";
private static final String PARAMETER_MAX_CONCURRENT_IDENTITIES_CHECK_MAIL = "maxConcurIdCheckMail";
// Defaults for each parameter
private static final int DEFAULT_REDUNDANCY = 2;
private static final int DEFAULT_STORAGE_SPACE_INBOX = 1024 * 1024 * 1024;
private static final int DEFAULT_STORAGE_SPACE_RELAY = 100 * 1024 * 1024;
private static final int DEFAULT_STORAGE_TIME = 31; // in days
private static final int DEFAULT_MAX_FRAGMENT_SIZE = 10 * 1024 * 1024; // the maximum size one email fragment can be, in bytes
private static final int DEFAULT_HASHCASH_STRENGTH = 10;
private static final int DEFAULT_SMTP_PORT = 7661;
private static final int DEFAULT_POP3_PORT = 7662;
private static final int DEFAULT_MAX_CONCURRENT_IDENTITIES_CHECK_MAIL = 10;
private Log log = new Log(Configuration.class);
private File i2pBoteDir;
/**
* Reads configuration settings from the <code>I2P_BOTE_SUBDIR</code> subdirectory under
* the I2P application directory. The I2P application directory can be changed via the
* <code>i2p.dir.app</code> system property.
*
* Logging is done through the I2P logger. I2P reads the log configuration from the
* <code>logger.config</code> file whose location is determined by the
* <code>i2p.dir.config</code> system property.
* @return
*/
public Configuration() {
// get the I2PBote directory and make sure it exists
i2pBoteDir = getI2PBoteDirectory();
if (!i2pBoteDir.exists())
i2pBoteDir.mkdirs();
// read the configuration file
File configFile = new File(i2pBoteDir, CONFIG_FILE_NAME);
boolean configurationLoaded = false;
if (configFile.exists()) {
log.debug("Loading config file <" + configFile.getAbsolutePath() + ">");
try {
DataHelper.loadProps(this, configFile);
configurationLoaded = true;
} catch (IOException e) {
log.error("Error loading configuration file <" + configFile.getAbsolutePath() + ">", e);
}
}
if (!configurationLoaded)
log.info("Can't read configuration file <" + configFile.getAbsolutePath() + ">, using default settings.");
}
public File getDestinationKeyFile() {
return new File(i2pBoteDir, DEST_KEY_FILE_NAME);
}
public File getPeerFile() {
return new File(i2pBoteDir, PEER_FILE_NAME);
}
public File getIdentitiesFile() {
return new File(i2pBoteDir, IDENTITIES_FILE_NAME);
}
public File getLocalOutboxDir() {
return new File(getOutboxBaseDir(), OUTBOX_SUBDIR_LOCAL);
}
public File getRelayOutboxDir() {
return new File(getOutboxBaseDir(), OUTBOX_SUBDIR_RELAY);
}
private File getOutboxBaseDir() {
return new File(i2pBoteDir, OUTBOX_DIR);
}
public File getInboxDir() {
return new File(i2pBoteDir, INBOX_SUBDIR);
}
public File getIncompleteDir() {
return new File(i2pBoteDir, INCOMPLETE_SUBDIR);
}
public File getEmailDhtStorageDir() {
return new File(i2pBoteDir, EMAIL_DHT_SUBDIR);
}
public File getIndexPacketDhtStorageDir() {
return new File(i2pBoteDir, INDEX_PACKET_DHT_SUBDIR);
}
private static File getI2PBoteDirectory() {
// the parent directory of the I2PBote directory ($HOME or the value of the i2p.dir.app property)
File i2pAppDir = I2PAppContext.getGlobalContext().getAppDir();
return new File(i2pAppDir, I2P_BOTE_SUBDIR);
}
/**
* Save the configuration
* @param configFile
* @throws IOException
*/
public void saveToFile(File configFile) throws IOException {
log.debug("Saving config file <" + configFile.getAbsolutePath() + ">");
DataHelper.storeProps(this, configFile);
}
/**
* Returns the number of relays to use for sending and receiving email. Zero is a legal value.
* @return
*/
public int getRedundancy() {
return getIntParameter(PARAMETER_REDUNDANCY, DEFAULT_REDUNDANCY);
}
/**
* Returns the maximum size (in bytes) the inbox can take up.
* @return
*/
public int getStorageSpaceInbox() {
return getIntParameter(PARAMETER_STORAGE_SPACE_INBOX, DEFAULT_STORAGE_SPACE_INBOX);
}
/**
* Returns the maximum size (in bytes) all messages stored for relaying can take up.
* @return
*/
public int getStorageSpaceRelay() {
return getIntParameter(PARAMETER_STORAGE_SPACE_RELAY, DEFAULT_STORAGE_SPACE_RELAY);
}
/**
* Returns the time (in milliseconds) after which an email is deleted from the outbox if it cannot be sent / relayed.
* @return
*/
public long getStorageTime() {
return 24L * 3600 * 1000 * getIntParameter(PARAMETER_STORAGE_TIME, DEFAULT_STORAGE_TIME);
}
public int getMaxFragmentSize() {
return getIntParameter(PARAMETER_MAX_FRAGMENT_SIZE, DEFAULT_MAX_FRAGMENT_SIZE);
}
public int getHashCashStrength() {
return getIntParameter(PARAMETER_HASHCASH_STRENGTH, DEFAULT_HASHCASH_STRENGTH);
}
/**
* Returns the maximum number of email identities to retrieve new emails for at a time.
* @return
*/
public int getMaxConcurIdCheckMail() {
return getIntParameter(PARAMETER_MAX_CONCURRENT_IDENTITIES_CHECK_MAIL, DEFAULT_MAX_CONCURRENT_IDENTITIES_CHECK_MAIL);
}
private int getIntParameter(String parameterName, int defaultValue) {
String stringValue = getProperty(parameterName);
if (stringValue == null)
return defaultValue;
else
try {
return new Integer(getProperty(parameterName));
}
catch (NumberFormatException e) {
log.warn("Can't convert value <" + stringValue + "> for parameter <" + parameterName + "> to int, using default.");
return defaultValue;
}
}
}

View File

@ -1,358 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote;
import i2p.bote.email.Email;
import i2p.bote.email.EmailDestination;
import i2p.bote.email.EmailIdentity;
import i2p.bote.email.Identities;
import i2p.bote.folder.DhtPacketFolder;
import i2p.bote.folder.EmailFolder;
import i2p.bote.folder.IncompleteEmailFolder;
import i2p.bote.folder.IndexPacketFolder;
import i2p.bote.folder.Outbox;
import i2p.bote.folder.PacketFolder;
import i2p.bote.network.CheckEmailTask;
import i2p.bote.network.DHT;
import i2p.bote.network.I2PPacketDispatcher;
import i2p.bote.network.I2PSendQueue;
import i2p.bote.network.PeerManager;
import i2p.bote.network.kademlia.KademliaDHT;
import i2p.bote.packet.DataPacket;
import i2p.bote.packet.EncryptedEmailPacket;
import i2p.bote.packet.IndexPacket;
import i2p.bote.packet.RelayPacket;
import i2p.bote.packet.UnencryptedEmailPacket;
import i2p.bote.service.OutboxProcessor;
import i2p.bote.service.POP3Service;
import i2p.bote.service.RelayPacketSender;
import i2p.bote.service.SMTPService;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import net.i2p.I2PAppContext;
import net.i2p.I2PException;
import net.i2p.client.I2PClient;
import net.i2p.client.I2PClientFactory;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.util.Log;
/**
* This is the core class of the application. Is is implemented as a singleton.
*/
public class I2PBote {
private static final String VERSION = "0.1.2";
private static I2PBote instance;
private Log log = new Log(I2PBote.class);
private I2PAppContext appContext;
private I2PClient i2pClient;
private I2PSession i2pSession;
private Configuration configuration;
private Identities identities;
private I2PSendQueue sendQueue;
private Outbox outbox; // stores outgoing emails for all local users
private EmailFolder inbox; // stores incoming emails for all local users
private PacketFolder<RelayPacket> relayPacketFolder; // stores email packets we're forwarding for other machines
private IncompleteEmailFolder incompleteEmailFolder; // stores email packets addressed to a local user
private DhtPacketFolder<? extends DataPacket> emailDhtStorageFolder; // stores email packets and index packets for other peers
private IndexPacketFolder indexPacketDhtStorageFolder; // stores index packets
//TODO private PacketFolder<> addressDhtStorageFolder; // stores email address-destination mappings
private SMTPService smtpService;
private POP3Service pop3Service;
private OutboxProcessor outboxProcessor; // reads emails stored in the outbox and sends them
private RelayPacketSender relayPacketSender; // reads packets stored in the relayPacketFolder and sends them
private DHT dht;
private PeerManager peerManager;
private ThreadFactory mailCheckThreadFactory;
private ExecutorService mailCheckExecutor;
private Collection<Future<Boolean>> mailCheckResults;
private I2PBote() {
Thread.currentThread().setName("I2PBoteMain");
initializeLogging();
appContext = new I2PAppContext();
i2pClient = I2PClientFactory.createClient();
configuration = new Configuration();
mailCheckThreadFactory = Util.createThreadFactory("ChkMailTask", CheckEmailTask.THREAD_STACK_SIZE);
mailCheckExecutor = Executors.newFixedThreadPool(configuration.getMaxConcurIdCheckMail(), mailCheckThreadFactory);
identities = new Identities(configuration.getIdentitiesFile());
initializeSession();
initializeFolderAccess();
initializeServices();
startAllServices();
}
private void initializeLogging() {
}
/**
* Initializes objects for accessing emails and packet files on the filesystem.
*/
private void initializeFolderAccess() {
inbox = new EmailFolder(configuration.getInboxDir());
outbox = new Outbox(configuration.getLocalOutboxDir());
relayPacketFolder = new PacketFolder<RelayPacket>(configuration.getRelayOutboxDir());
incompleteEmailFolder = new IncompleteEmailFolder(configuration.getIncompleteDir(), inbox);
emailDhtStorageFolder = new DhtPacketFolder<EncryptedEmailPacket>(configuration.getEmailDhtStorageDir());
indexPacketDhtStorageFolder = new IndexPacketFolder(configuration.getIndexPacketDhtStorageDir());
}
/**
* Sets up a {@link I2PSession}, using the I2P destination stored on disk or creating a new I2P
* destination if no key file exists.
*/
private void initializeSession() {
Properties sessionProperties = new Properties();
sessionProperties.setProperty("i2cp.gzip", String.valueOf(false)); // most of the data we send is encrypted and therefore uncompressible
// read the local destination key from the key file if it exists
File destinationKeyFile = configuration.getDestinationKeyFile();
try {
FileReader fileReader = new FileReader(destinationKeyFile);
char[] destKeyBuffer = new char[(int)destinationKeyFile.length()];
fileReader.read(destKeyBuffer);
byte[] localDestinationKey = Base64.decode(new String(destKeyBuffer));
ByteArrayInputStream inputStream = new ByteArrayInputStream(localDestinationKey);
i2pSession = i2pClient.createSession(inputStream, sessionProperties);
i2pSession.connect();
}
catch (IOException e) {
log.debug("Destination key file doesn't exist or isn't readable: " + e);
} catch (I2PSessionException e) {
log.warn("Error creating I2PSession", e);
}
// if the local destination key can't be read or is invalid, create a new one
if (i2pSession == null) {
log.debug("Creating new local destination key");
try {
ByteArrayOutputStream arrayStream = new ByteArrayOutputStream();
i2pClient.createDestination(arrayStream);
byte[] localDestinationArray = arrayStream.toByteArray();
i2pSession = i2pClient.createSession(new ByteArrayInputStream(localDestinationArray), sessionProperties);
i2pSession.connect();
saveLocalDestinationKeys(destinationKeyFile, localDestinationArray);
} catch (I2PException e) {
log.error("Error creating local destination key or I2PSession.", e);
} catch (IOException e) {
log.error("Error writing local destination key to file.", e);
}
}
Destination localDestination = i2pSession.getMyDestination();
log.debug("Local destination key = " + localDestination.toBase64());
log.debug("Local destination hash = " + localDestination.calculateHash().toBase64());
}
/**
* Initializes daemon threads, doesn't start them yet.
*/
private void initializeServices() {
I2PPacketDispatcher dispatcher = new I2PPacketDispatcher();
i2pSession.addSessionListener(dispatcher, I2PSession.PROTO_ANY, I2PSession.PORT_ANY);
smtpService = new SMTPService();
pop3Service = new POP3Service();
relayPacketSender = new RelayPacketSender(sendQueue, relayPacketFolder, appContext);
sendQueue = new I2PSendQueue(i2pSession, dispatcher);
dht = new KademliaDHT(i2pSession.getMyDestination(), sendQueue, dispatcher, configuration.getPeerFile());
dht.setStorageHandler(EncryptedEmailPacket.class, emailDhtStorageFolder);
dht.setStorageHandler(IndexPacket.class, indexPacketDhtStorageFolder);
//TODO dht.setStorageHandler(AddressPacket.class, );
peerManager = new PeerManager();
outboxProcessor = new OutboxProcessor(dht, outbox, configuration, peerManager, appContext);
}
/**
* Writes private + public keys for the local destination out to a file.
* @param keyFile
* @param localDestinationArray
* @throws DataFormatException
* @throws IOException
*/
private void saveLocalDestinationKeys(File keyFile, byte[] localDestinationArray) throws DataFormatException, IOException {
if (keyFile.exists()) {
File oldKeyFile = new File(keyFile.getPath() + "_backup");
keyFile.renameTo(oldKeyFile);
}
else
keyFile.createNewFile();
FileWriter fileWriter = new FileWriter(keyFile);
fileWriter.write(Base64.encode(localDestinationArray));
fileWriter.close();
}
public static void startUp() {
getInstance();
}
public static void shutDown() {
if (instance != null)
instance.stopAllServices();
}
public static I2PBote getInstance() {
if (instance == null)
instance = new I2PBote();
return instance;
}
public String getVersion() {
return VERSION;
}
public Identities getIdentities() {
return identities;
}
public String getLocalDestination() {
return i2pSession.getMyDestination().toBase64();
}
public void sendEmail(Email email) throws Exception {
/*XXX*/
email.updateHeaders();
String recipient = email.getAllRecipients().iterator().next();
if (recipient.indexOf('@')>=0)
recipient = recipient.substring(0, recipient.indexOf('@'));
EmailDestination emailDestination = new EmailDestination(recipient);
Collection<UnencryptedEmailPacket> emailPackets = email.createEmailPackets(recipient);
Collection<EncryptedEmailPacket> encryptedPackets = EncryptedEmailPacket.encrypt(emailPackets, emailDestination, appContext);
for (EncryptedEmailPacket packet: encryptedPackets)
dht.store(packet);
dht.store(new IndexPacket(encryptedPackets, emailDestination));
// TODO uncomment for next milestone, move code above into OutboxProcessor
/* outbox.add(email);
outboxProcessor.checkForEmail();*/
}
public synchronized void checkForMail() {
if (!isCheckingForMail())
mailCheckResults = Collections.synchronizedCollection(new ArrayList<Future<Boolean>>());
for (EmailIdentity identity: getIdentities()) {
Callable<Boolean> checkMailTask = new CheckEmailTask(identity, dht, peerManager, incompleteEmailFolder, appContext);
Future<Boolean> result = mailCheckExecutor.submit(checkMailTask);
mailCheckResults.add(result);
}
}
public synchronized boolean isCheckingForMail() {
if (mailCheckResults == null)
return false;
for (Future<Boolean> result: mailCheckResults)
if (!result.isDone())
return true;
return false;
}
/**
* Returns <code>true</code> if the last call to {@link checkForMail} has completed
* and added new mail to the inbox.
* If this method returns <code>true</code>, subsequent calls will always return
* <code>false</code> until {@link checkForMail} is executed again.
* @return
*/
public synchronized boolean newMailReceived() {
if (mailCheckResults == null)
return false;
if (isCheckingForMail())
return false;
try {
for (Future<Boolean> result: mailCheckResults)
if (result.get(1, TimeUnit.MILLISECONDS)) {
mailCheckResults = null;
return true;
}
}
catch (Exception e) {
log.error("Error while checking whether new mail has arrived.", e);
}
mailCheckResults = null;
return false;
}
public EmailFolder getInbox() {
return inbox;
}
public int getNumDhtPeers() {
return dht.getNumPeers();
}
public int getNumRelayPeers() {
return peerManager.getNumPeers();
}
private void startAllServices() {
dht.start();
outboxProcessor.start();
relayPacketSender.start();
smtpService.start();
pop3Service.start();
sendQueue.start();
}
private void stopAllServices() {
dht.shutDown();
outboxProcessor.shutDown();
relayPacketSender.requestShutdown();
smtpService.shutDown();
pop3Service.shutDown();
sendQueue.requestShutdown();
mailCheckExecutor.shutdownNow();
}
}

View File

@ -1,85 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ThreadFactory;
import net.i2p.client.I2PSession;
import net.i2p.data.DataFormatException;
public class Util {
private static final int BUFFER_SIZE = 32 * 1024;
private Util() { }
public static void copyBytes(InputStream inputStream, OutputStream outputStream) throws IOException {
byte[] buffer = new byte[BUFFER_SIZE];
boolean done = false;
while (!done) {
int bytesRead = inputStream.read(buffer);
outputStream.write(buffer);
if (bytesRead < 0)
done = true;
}
}
public static void writeKeyStream(I2PSession i2pSession, OutputStream outputStream) throws DataFormatException, IOException {
i2pSession.getMyDestination().writeBytes(outputStream);
i2pSession.getDecryptionKey().writeBytes(outputStream);
i2pSession.getPrivateKey().writeBytes(outputStream);
}
public static InputStream createKeyStream(I2PSession i2pSession) throws DataFormatException, IOException {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
writeKeyStream(i2pSession, outputStream);
return new ByteArrayInputStream(outputStream.toByteArray());
}
public static byte[] readInputStream(InputStream inputStream) throws IOException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
byte[] buffer = new byte[32*1024];
while (true) {
int bytesToRead = Math.min(inputStream.available(), buffer.length);
if (bytesToRead <= 0)
break;
else {
int bytesRead = inputStream.read(buffer, 0, bytesToRead);
byteStream.write(buffer, 0, bytesRead);
}
}
return byteStream.toByteArray();
}
public static ThreadFactory createThreadFactory(final String threadName, final int stackSize) {
return new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
return new Thread(null, runnable, threadName, stackSize);
}
};
}
}

View File

@ -1,408 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.email;
import i2p.bote.UniqueId;
import i2p.bote.Util;
import i2p.bote.folder.FolderElement;
import i2p.bote.packet.UnencryptedEmailPacket;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TimeZone;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
import com.nettgryppa.security.HashCash;
// TODO move one package up
public class Email implements FolderElement {
private static final int MAX_BYTES_PER_PACKET = 30 * 1024;
private static final char[] NEW_LINE = new char[] {13, 10}; // separates header section from mail body; same for all platforms per RFC 5322
private static final Set<String> HEADER_WHITELIST = createHeaderWhitelist();
private static Log log = new Log(Email.class);
private File file;
private List<Header> headers;
private byte[] content; // save memory by using bytes rather than chars
private MessageId messageId;
public Email() {
headers = Collections.synchronizedList(new ArrayList<Header>());
content = new byte[0];
messageId = new MessageId();
}
/**
* Creates an Email object from an InputStream containing a MIME email.
*
* @param inputStream
* @throws IOException
*/
public Email(InputStream inputStream) throws IOException {
this(Util.readInputStream(inputStream));
}
/**
* Creates an Email object from a byte array containing a MIME email.
*
* @param bytes
*/
public Email(byte[] bytes) {
BufferedReader reader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes)));
headers = Collections.synchronizedList(new ArrayList<Header>());
ByteArrayOutputStream contentStream = new ByteArrayOutputStream();
boolean allHeadersRead = false;
try {
// read mail headers
while (true) {
String line = reader.readLine();
if (line == null) // EOF
break;
if ("".equals(line)) { // empty line separates header from mail body
allHeadersRead = true;
continue;
}
if (!allHeadersRead) {
String[] splitString = line.split(":\\s*", 2);
if (splitString.length > 1) {
String name = splitString[0];
String value = splitString[1];
if (HEADER_WHITELIST.contains(name))
headers.add(new Header(name, value));
}
else
allHeadersRead = true;
}
if (allHeadersRead)
contentStream.write(line.getBytes());
}
}
catch (IOException e) {
log.error("Can't read from ByteArrayInputStream.", e);
}
content = contentStream.toByteArray();
String messageIdString = getHeader("Message-Id");
if (messageIdString != null)
messageId = new MessageId(messageIdString);
}
private static Set<String> createHeaderWhitelist() {
String[] headerArray = new String[] {
"From", "Sender", "To", "CC", "BCC", "Reply-To", "Subject", "Date", "MIME-Version", "Content-Type",
"Content-Transfer-Encoding", "Message-Id", "In-Reply-To", "X-HashCash"
};
ConcurrentHashSet<String> headerSet = new ConcurrentHashSet<String>();
headerSet.addAll(Arrays.asList(headerArray));
return headerSet;
}
public void setHashCash(HashCash hashCash) {
setHeader("X-HashCash", hashCash.toString());
}
public void setHeader(String name, String value) {
for (Header header: headers)
if (name.equals(header.name))
headers.remove(header);
addHeader(name, value);
}
public void addHeader(String name, String value) {
if (HEADER_WHITELIST.contains(name))
headers.add(new Header(name, value));
else
log.debug("Ignoring non-whitelisted header: " + name);
}
public void setSender(String sender) {
setHeader("Sender", sender);
}
/**
* Returns the value of the RFC 5322 "From" header field. If the "From" header
* field is absent, the value of the "Sender" field is returned. If both
* fields are absent, <code>null</code> is returned.
* @return
*/
public String getSender() {
String sender = getHeader("From");
if (sender != null)
return sender;
sender = getHeader("Sender");
return sender;
}
public void setSubject(String subject) {
setHeader("Subject", subject);
}
public String getSubject() {
return getHeader("Subject");
}
public Collection<String> getAllRecipients() {
List<String> recipients = new ArrayList<String>();
for (Header header: headers)
if (isRecipient(header.name))
recipients.add(header.value);
return recipients;
}
private boolean isRecipient(String headerName) {
return RecipientType.TO.equalsString(headerName) || RecipientType.CC.equalsString(headerName) || RecipientType.BCC.equalsString(headerName);
}
public void addRecipient(RecipientType type, String address) {
addHeader(type.toString(), address);
}
/**
* Initializes some basic header fields.
*/
public void updateHeaders() {
setHeader("Content-Type", "text/plain");
setHeader("Content-Transfer-Encoding", "7bit");
setHeader("Message-Id", messageId.getEmailMessageId());
// Set the "Date" field, using english for the locale.
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT+0"));
DateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss +0000", Locale.ENGLISH); // always use UTC for outgoing mail
setHeader("Date", formatter.format(calendar.getTime()));
}
/**
* Returns the value of the "Date" header field.
* @return
*/
public String getDateString() {
return getHeader("Date");
}
/**
* Parses the value of the "Date" header field into a {@link Date}.
* If the field cannot be parsed, <code>null</code> is returned.
* @return
*/
public Date getDate() {
try {
return parseDate(getDateString());
}
catch (ParseException e) {
return null;
}
}
/**
* Example for a valid date string: Sat, 19 Aug 2006 20:05:41 +0100
* @param dateString
* @return
* @throws ParseException
*/
private Date parseDate(String dateString) throws ParseException {
// remove day of week if present
String[] tokens = dateString.split(",\\s+", 2);
if (tokens.length > 1)
dateString = tokens[1];
DateFormat parser = new SimpleDateFormat("dd MMM yyyy kk:mm:ss Z", Locale.ENGLISH);
return parser.parse(dateString);
}
public void setContent(String content) {
this.content = content.getBytes();
}
public void setContent(byte[] content) {
this.content = content;
}
public byte[] getContent() {
return content;
}
public String getBodyText() {
return new String(content);
}
public MessageId getMessageID() {
return messageId;
}
/**
* Converts the email into one or more email packets.
*
* @param bccToKeep All BCC fields in the header section of the email are removed, except this field. If this parameter is <code>null</code>, all BCC fields are written.
* @return
* @throws IOException
*/
public Collection<UnencryptedEmailPacket> createEmailPackets(String bccToKeep) {
ArrayList<UnencryptedEmailPacket> packets = new ArrayList<UnencryptedEmailPacket>();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
writeTo(outputStream, bccToKeep);
byte[] emailArray = outputStream.toByteArray();
// calculate fragment count
int numFragments = (emailArray.length+MAX_BYTES_PER_PACKET-1) / MAX_BYTES_PER_PACKET;
int fragmentIndex = 0;
int blockStart = 0; // the array index where the next block of data starts
while (true) {
int blockSize = Math.min(emailArray.length-blockStart, MAX_BYTES_PER_PACKET);
if (blockSize <= 0)
break;
else {
// make a new array with the right length
byte[] block = new byte[blockSize];
System.arraycopy(emailArray, blockStart, block, 0, blockSize);
UniqueId deletionKeyPlain = new UniqueId();
UniqueId deletionKeyEncrypted = deletionKeyPlain.clone(); // encryption happens in the constructor call below
UnencryptedEmailPacket packet = new UnencryptedEmailPacket(deletionKeyPlain, deletionKeyEncrypted, messageId, fragmentIndex, numFragments, block);
packets.add(packet);
fragmentIndex++;
blockStart += blockSize;
}
}
return packets;
}
/**
* Removes all "BCC" headers except the one for <code>recipient<code>.
* The mail body is not copied (which means the new email shares its body with the original).
* @String recipient
* @return
*/
public Email removeBCCs(String recipient) {
List<Header> newHeaders = Collections.synchronizedList(new ArrayList<Header>());
for (Header header: headers)
if (!"BCC".equals(header.name) || !recipient.equals(header.value))
newHeaders.add(header);
Email newEmail = new Email();
newEmail.headers = newHeaders;
newEmail.content = content;
newEmail.messageId = messageId;
return newEmail;
}
/**
* Returns the value of the first header field for a header field name,
* or <code>null</code> if no field by that name exists.
* @param name
* @return
*/
private String getHeader(String name) {
for (Header header: headers)
if (name.equals(header.name))
return header.value;
return null;
}
// FolderElement implementation
@Override
public File getFile() {
return file;
}
// FolderElement implementation
@Override
public void setFile(File file) {
this.file = file;
}
/**
* Writes the email as an RFC 5322 stream.
* @see <a href="http://tools.ietf.org/html/rfc5322">http://tools.ietf.org/html/rfc5322</a>
*/
@Override
public void writeTo(OutputStream outputStream) throws IOException {
writeTo(outputStream, null);
}
/**
* Writes the email as an RFC 5322 stream.
* @see <a href="http://tools.ietf.org/html/rfc5322">http://tools.ietf.org/html/rfc5322</a>
* @param outputStream
* @param bccToKeep All BCC fields in the header section of the email are removed, except this field. If this parameter is <code>null</code>, all BCC fields are written.
* @throws IOException
*/
public void writeTo(OutputStream outputStream, String bccToKeep) {
PrintWriter writer = new PrintWriter(outputStream);
writeHeaders(writer, bccToKeep);
writer.print(NEW_LINE);
writer.print(new String(content));
writer.print(NEW_LINE);
writer.close();
}
private void writeHeaders(PrintWriter writer, String bccToKeep) {
for (Header header: headers)
if (bccToKeep==null || !"BCC".equals(header.name) || bccToKeep.equals(header.value))
writer.println(header.toString());
}
private class Header {
String name;
String value;
Header(String name, String value) {
this.name = name;
this.value = value;
}
@Override
public String toString() {
return name + ": " + value;
}
}
}

View File

@ -1,173 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.email;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import net.i2p.client.I2PClient;
import net.i2p.client.I2PClientFactory;
import net.i2p.client.I2PSession;
import net.i2p.crypto.SHA256Generator;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.data.PublicKey;
import net.i2p.data.SigningPublicKey;
import net.i2p.util.Log;
/**
* Uniquely identifies an email recipient. This implementation uses I2P keypairs.
*/
public class EmailDestination {
private Log log = new Log(EmailDestination.class);
private PublicKey publicEncryptionKey;
private SigningPublicKey publicSigningKey;
/**
* Creates a fresh <code>EmailDestination</code>.
*/
public EmailDestination() {
try {
I2PClient i2pClient = I2PClientFactory.createClient();
ByteArrayOutputStream arrayStream = new ByteArrayOutputStream();
i2pClient.createDestination(arrayStream);
byte[] destinationArray = arrayStream.toByteArray();
I2PSession i2pSession = i2pClient.createSession(new ByteArrayInputStream(destinationArray), null);
initKeys(i2pSession);
}
catch (Exception e) {
log.error("Can't generate EmailDestination.", e);
}
}
/**
* Creates a <code>EmailDestination</code> using data read from a {@link ByteBuffer}.
* @param buffer
*/
public EmailDestination(ByteBuffer buffer) {
byte[] encryptionKeyArray = new byte[PublicKey.KEYSIZE_BYTES];
buffer.get(encryptionKeyArray);
publicEncryptionKey = new PublicKey(encryptionKeyArray);
byte[] signingKeyArray = new byte[SigningPublicKey.KEYSIZE_BYTES];
buffer.get(signingKeyArray);
publicSigningKey = new SigningPublicKey(signingKeyArray);
}
public EmailDestination(String base64Data) {
try {
base64Data += "AAAA"; // add a null certificate
Destination i2pDestination = new Destination(base64Data);
publicEncryptionKey = i2pDestination.getPublicKey();
publicSigningKey = i2pDestination.getSigningPublicKey();
} catch (DataFormatException e) {
log.error("Can't generate EmailDestination.", e);
}
}
/* public EmailDestination(byte[] data) {
try {
byte[] destinationPlusCert = addNullCertificate(data);
ByteArrayInputStream byteStream = new ByteArrayInputStream(destinationPlusCert);
I2PSession i2pSession = I2PClientFactory.createClient().createSession(byteStream, null);
initKeys(i2pSession);
}
catch (I2PSessionException e) {
log.error("Can't generate EmailDestination.", e);
}
}*/
/* private byte[] addNullCertificate(byte[] data) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
outputStream.write(data);
outputStream.write(new Certificate().toByteArray());
// Add an extra zero byte so I2PSessionImpl.readDestination doesn't fall on its face. I believe this is a bug.
outputStream.write(0);
}
catch (IOException e) {
log.error("Can't write to ByteArrayOutputStream.", e);
}
return outputStream.toByteArray();
}*/
protected void initKeys(I2PSession i2pSession) {
publicEncryptionKey = i2pSession.getMyDestination().getPublicKey();
publicSigningKey = i2pSession.getMyDestination().getSigningPublicKey();
}
public PublicKey getPublicEncryptionKey() {
return publicEncryptionKey;
}
public SigningPublicKey getPublicSigningKey() {
return publicSigningKey;
}
private byte[] getKeysAsArray() {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try {
writeTo(byteStream);
}
catch (IOException e) {
log.error("Can't write to ByteArrayOutputStream.", e);
}
return byteStream.toByteArray();
}
private void writeTo(OutputStream outputStream) throws IOException {
try {
publicEncryptionKey.writeBytes(outputStream);
publicSigningKey.writeBytes(outputStream);
}
catch (DataFormatException e) {
log.error("Invalid encryption key or signing key.", e);
}
}
public Hash getHash() {
// TODO cache the hash value?
return SHA256Generator.getInstance().calculateHash(getKeysAsArray());
}
/**
* Returns the two public keys in Base64 representation.
*/
public String getKey() {
return Base64.encode(getKeysAsArray());
}
public String toBase64() {
return getKey();
}
@Override
public String toString() {
return getKey();
}
}

View File

@ -1,144 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.email;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import net.i2p.client.I2PClient;
import net.i2p.client.I2PClientFactory;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.data.Base64;
import net.i2p.data.PrivateKey;
import net.i2p.data.SigningPrivateKey;
import net.i2p.util.Log;
public class EmailIdentity extends EmailDestination {
private Log log = new Log(EmailIdentity.class);
private PrivateKey privateEncryptionKey;
private SigningPrivateKey privateSigningKey;
private String publicName;
private String description; // optional
private String emailAddress; // optional
/**
* Creates a random <code>EmailIdentity</code>.
*/
public EmailIdentity() {
// key initialization happens in the super constructor, which calls initKeys
}
/**
* Creates a <code>EmailIdentity</code> from a Base64-encoded string. The format is the same as
* for Base64-encoded local I2P destinations, except there is no null certificate.
* @param key
*/
public EmailIdentity(String key) {
try {
key = key.substring(0, 512) + "AAAA" + key.substring(512); // insert a null certificate for I2PClient.createSession()
ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64.decode(key));
I2PClient i2pClient = I2PClientFactory.createClient();
I2PSession i2pSession = i2pClient.createSession(inputStream, null);
initKeys(i2pSession);
}
catch (I2PSessionException e) {
log.error("Can't generate EmailIdentity.", e);
}
}
public PrivateKey getPrivateEncryptionKey() {
return privateEncryptionKey;
}
public SigningPrivateKey getPrivateSigningKey() {
return privateSigningKey;
}
public void setPublicName(String publicName) {
this.publicName = publicName;
}
public String getPublicName() {
return publicName;
}
public void setDescription(String name) {
this.description = name;
}
public String getDescription() {
return description;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getEmailAddress() {
return emailAddress;
}
protected void initKeys(I2PSession i2pSession) {
super.initKeys(i2pSession);
privateEncryptionKey = i2pSession.getDecryptionKey();
privateSigningKey = i2pSession.getPrivateKey();
}
private byte[] getKeysAsArray() {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try {
byteStream.write(getPublicEncryptionKey().getData());
byteStream.write(getPublicSigningKey().getData());
byteStream.write(getPrivateEncryptionKey().getData());
byteStream.write(getPrivateSigningKey().getData());
}
catch (IOException e) {
log.error("Can't write to ByteArrayOutputStream.", e);
}
return byteStream.toByteArray();
}
/**
* Returns the two key pairs (public + private) as one Base64-encoded string.
* @return
*/
public String getFullKey() {
return Base64.encode(getKeysAsArray());
}
@Override
public String toString() {
return getKey() + " address=<" + getEmailAddress() + "> identity name=<" + getDescription() + "> visible name=<" + getPublicName() + ">";
}
/* @Override
public boolean equals(Object anotherObject) {
if (anotherObject instanceof EmailIdentity) {
EmailIdentity otherIdentity = (EmailIdentity)anotherObject;
return Arrays.equals(getKeysAsArray(), otherIdentity.getKeysAsArray());
}
return false;
}*/
}

View File

@ -1,193 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.email;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.regex.PatternSyntaxException;
import net.i2p.data.Hash;
import net.i2p.util.Log;
/**
* Represents a set of <code>EmailIdentities</code>.
*/
public class Identities implements Iterable<EmailIdentity> {
private Log log = new Log(Identities.class);
private File identitiesFile;
private List<EmailIdentity> identities;
public Identities(File identitiesFile) {
this.identitiesFile = identitiesFile;
identities = Collections.synchronizedList(new ArrayList<EmailIdentity>());
if (!identitiesFile.exists()) {
log.debug("Identities file does not exist: <" + identitiesFile.getAbsolutePath() + ">");
return;
}
log.debug("Reading identities file: <" + identitiesFile.getAbsolutePath() + ">");
BufferedReader input = null;
try {
input = new BufferedReader(new FileReader(identitiesFile));
while (true) {
String line = input.readLine();
if (line == null) // EOF
break;
EmailIdentity identity = parse(line);
if (identity != null)
identities.add(identity);
}
} catch (IOException e) {
log.error("Can't read identities file.", e);
}
finally {
if (input != null)
try {
input.close();
}
catch (IOException e) {
log.error("Error closing input stream.", e);
}
}
}
private EmailIdentity parse(String emailIdentityString) {
try {
String[] fields = emailIdentityString.split("\\t", 4);
if (fields.length < 2) {
log.debug("Unparseable email identity: <" + emailIdentityString + ">");
return null;
}
EmailIdentity identity = new EmailIdentity(fields[0]);
if (fields.length > 1)
identity.setPublicName(fields[1]);
if (fields.length > 2)
identity.setDescription(fields[2]);
if (fields.length > 3)
identity.setEmailAddress(fields[3]);
return identity;
}
catch (PatternSyntaxException e) {
log.debug("Unparseable email identity: <" + emailIdentityString + ">");
return null;
}
}
/**
* This is the counterpart of the <code>parse</code> method. It encodes a {@link EmailIdentity} into
* an entry for the identities file.
* @param identity
* @return
*/
private String toFileFormat(EmailIdentity identity) {
StringBuilder string = new StringBuilder();
string = string.append(identity.getFullKey());
string = string.append("\t");
string = string.append(identity.getPublicName());
string = string.append("\t");
if (identity.getDescription() != null)
string = string.append(identity.getDescription());
string = string.append("\t");
if (identity.getEmailAddress() != null)
string = string.append(identity.getEmailAddress());
return string.toString();
}
public void save() throws IOException {
String newLine = System.getProperty("line.separator");
try {
Writer writer = new BufferedWriter(new FileWriter(identitiesFile));
for (EmailIdentity identity: identities)
writer.write(toFileFormat(identity) + newLine);
writer.close();
}
catch (IOException e) {
log.error("Can't save email identities to file <" + identitiesFile.getAbsolutePath() + ">.", e);
throw e;
}
}
public void add(EmailIdentity identity) {
identities.add(identity);
}
public void remove(String key) {
EmailIdentity identity = get(key);
if (identity != null)
identities.remove(identity);
}
public EmailIdentity get(int i) {
return identities.get(i);
}
/**
* Looks up an {@link EmailIdentity} by its Base64 key. If none is found,
* <code>null</code> is returned.
* @param key
* @return
*/
public EmailIdentity get(String key) {
if (key==null || key.isEmpty())
return null;
for (EmailIdentity identity: identities)
if (key.equals(identity.getKey()))
return identity;
return null;
}
public Collection<EmailIdentity> getAll() {
return identities;
}
public EmailIdentity[] getArray() {
return identities.toArray(new EmailIdentity[0]);
}
public int size() {
return identities.size();
}
public boolean contains(Hash emailDestination) {
// TODO
return true;
}
@Override
public Iterator<EmailIdentity> iterator() {
return identities.iterator();
}
}

View File

@ -1,20 +0,0 @@
package i2p.bote.email;
public enum RecipientType {
TO("To"), CC("CC"), BCC("BCC");
private String value;
private RecipientType(String value) {
this.value = value;
}
@Override
public String toString() {
return value;
}
public boolean equalsString(String string) {
return value.equalsIgnoreCase(string);
}
}

View File

@ -1,98 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.folder;
import i2p.bote.email.Email;
import i2p.bote.email.MessageId;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import net.i2p.util.Log;
/**
* Stores emails in a directory on the file system. Each email is stored in one file.
* The filename is the message Id plus an extension.
*/
public class EmailFolder extends Folder<Email> {
protected static final String EMAIL_FILE_EXTENSION = ".mail";
private Log log = new Log(EmailFolder.class);
public EmailFolder(File storageDir) {
super(storageDir, EMAIL_FILE_EXTENSION);
}
// store an email file
public void add(Email email) throws IOException {
// write out the email file
File emailFile = getEmailFile(email);
log.info("Storing email in outbox: '" + emailFile.getAbsolutePath() + "'");
OutputStream emailOutputStream = new FileOutputStream(emailFile);
email.writeTo(emailOutputStream);
emailOutputStream.close();
}
/**
* Finds an <code>Email</code> by message id. If the <code>Email</code> is
* not found, <code>null</code> is returned.
* The <code>messageId</code> parameter must be a 44-character base64-encoded
* message id. If the message id contains an ampersand, the ampersand and
* everything after it is ignored.
* @param messageId
* @return
*/
public Email getEmail(String messageIdString) {
MessageId messageId = new MessageId(messageIdString);
File file = getEmailFile(messageId);
try {
return createFolderElement(file);
}
catch (Exception e) {
log.error("Can't read email from file: <" + file.getAbsolutePath() + ">", e);
return null;
}
}
private File getEmailFile(Email email) {
return getEmailFile(email.getMessageID());
}
private File getEmailFile(MessageId messageId) {
return new File(storageDir, messageId.toBase64() + EMAIL_FILE_EXTENSION);
}
public void delete(Email email) {
if (!getEmailFile(email).delete())
log.error("Cannot delete file: '" + getEmailFile(email) + "'");
}
@Override
protected Email createFolderElement(File file) throws Exception {
FileInputStream inputStream = new FileInputStream(file);
return new Email(inputStream);
}
}

View File

@ -1,118 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.folder;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import net.i2p.util.Log;
/**
*
* @param <T> The type of objects the folder can store.
*/
public abstract class Folder<T extends FolderElement> implements Iterable<T> {
private Log log = new Log(Folder.class);
protected File storageDir;
protected String fileExtension;
protected Folder(File storageDir, String fileExtension) {
this.storageDir = storageDir;
this.fileExtension = fileExtension;
if (!storageDir.exists() && !storageDir.mkdirs())
log.error("Can't create directory: '" + storageDir + "'");
}
public File getStorageDirectory() {
return storageDir;
}
public Collection<T> getElements() {
Collection<T> elements = new ArrayList<T>();
Iterator<T> iterator = iterator();
while (iterator.hasNext())
elements.add(iterator.next());
return elements;
}
// An {@link Iterator} implementation that loads one file into memory at a time.
@Override
public final Iterator<T> iterator() {
final File[] files = storageDir.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.toUpperCase().endsWith(fileExtension.toUpperCase());
}
});
if (files == null)
log.error("Cannot list files in directory <" + storageDir + ">");
else
log.debug(files.length + " files with the extension '" + fileExtension + "' found in '" + storageDir + "'.");
// sort files by date, newest first
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(File f1, File f2) {
return (int)Math.signum(f1.lastModified() - f2.lastModified());
}
});
return new Iterator<T>() {
int nextIndex = 0;
@Override
public boolean hasNext() {
return nextIndex < files.length;
}
@Override
public T next() {
File file = files[nextIndex];
String filePath = file.getAbsolutePath();
log.info("Reading file: '" + filePath + "'");
try {
T nextElement = createFolderElement(file);
nextElement.setFile(file);
nextIndex++;
return nextElement;
}
catch (Exception e) {
log.error("Can't create a FolderElement from file: " + filePath, e);
return null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Use the Folder instance to delete a folder element.");
}
};
}
protected abstract T createFolderElement(File file) throws Exception;
}

View File

@ -1,61 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.folder;
import i2p.bote.packet.I2PBotePacket;
import i2p.bote.packet.IndexPacket;
import i2p.bote.packet.dht.DhtStorablePacket;
import java.io.File;
import net.i2p.util.Log;
/**
* This class differs from {@link DhtPacketFolder} in that it doesn't overwrite an existing
* packet when a new packet is stored under the same key, but merges the packets.
*/
public class IndexPacketFolder extends DhtPacketFolder<IndexPacket> {
private final Log log = new Log(I2PBotePacket.class);
public IndexPacketFolder(File storageDir) {
super(storageDir);
}
@Override
public void store(DhtStorablePacket packetToStore) {
if (!(packetToStore instanceof IndexPacket))
throw new IllegalArgumentException("This class only stores packets of type " + IndexPacket.class.getSimpleName() + ".");
IndexPacket indexPacketToStore = (IndexPacket)packetToStore;
DhtStorablePacket existingPacket = retrieve(packetToStore.getDhtKey());
// If an index packet with the same key exists in the folder, merge the two packets.
if (existingPacket instanceof IndexPacket) {
packetToStore = new IndexPacket(indexPacketToStore, (IndexPacket)existingPacket);
if (packetToStore.isTooBig())
// TODO make two new index packets, put half the email packet keys in each one, store the two index packets on the DHT, and put the two index packet keys into the local index file (only keep those two).
log.error("After merging, IndexPacket is too big for a datagram: size=" + packetToStore.getSize());
}
super.store(packetToStore);
}
}

View File

@ -1,88 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.folder;
import i2p.bote.email.Email;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import net.i2p.util.Log;
/**
* Stores emails in a directory on the filesystem. For each email, two files are created; the actual
* email and a status file.
* Status files and email files have the same name, except for the extension.
* Even emails that need to be fragmented are stored as a whole.
* Message IDs are used for filenames.
*
* Status files contain a status for each recipient address.
*/
public class Outbox extends EmailFolder implements Iterable<Email> {
private static final String STATUS_FILE_EXTENSION = ".status";
// private static final String PARAM_QUEUE_DATE = "X-QueueDate";
private static final Log log = new Log(Outbox.class);
public Outbox(File storageDir) {
super(storageDir);
}
// store one email file + one status file.
@Override
public void add(Email email) throws IOException {
// write out the email file
super.add(email);
// collect info for status file
String queueDate = String.valueOf(System.currentTimeMillis());
// write out the status file
File statusFile = getStatusFile(email);
FileWriter statusFileWriter = new FileWriter(statusFile);
statusFileWriter.write(queueDate);
statusFileWriter.close();
}
private File getStatusFile(Email email) {
return new File(storageDir, email.getMessageID() + STATUS_FILE_EXTENSION);
}
// delete an email file + the status file
@Override
public void delete(Email email) {
super.delete(email);
if (!getStatusFile(email).delete())
log.error("Cannot delete file: '" + getStatusFile(email) + "'");
}
/**
*
* @param email
* @param relayInfo A 0-length array means no relays were used, i.e. the email was sent directly to the recipient.
* @param statusMessage
*/
public void updateStatus(Email email, int[] relayInfo, String statusMessage) {
// TODO write out a new status file. filename is the msg id, statusMessage goes into the file.
}
}

View File

@ -1,86 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.folder;
import i2p.bote.UniqueId;
import i2p.bote.packet.DataPacket;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import net.i2p.util.Log;
/**
* This class stores new files under a random file name with the .pkt extension.
*
* @param <PacketType> The type of data stored in this folder
*/
public class PacketFolder<PacketType extends DataPacket> extends Folder<PacketType> {
protected static final String PACKET_FILE_EXTENSION = ".pkt";
private Log log = new Log(PacketFolder.class);
public PacketFolder(File storageDir) {
super(storageDir, PACKET_FILE_EXTENSION);
}
public <T extends PacketType> void add(T packetToStore) {
String filename = new UniqueId().toBase64() + PACKET_FILE_EXTENSION;
add(packetToStore, filename);
}
/**
*
* @param packetToStore
* @param filename A filename relative to this folder's storage directory.
*/
protected void add(DataPacket packetToStore, String filename) {
FileOutputStream outputStream = null;
try {
File file = new File(storageDir, filename);
outputStream = new FileOutputStream(file);
packetToStore.writeTo(outputStream);
} catch (Exception e) {
log.error("Can't save packet to file: <" + filename + ">", e);
}
finally {
if (outputStream != null)
try {
outputStream.close();
}
catch (IOException e) {
log.error("Can't close file: <" + filename + ">", e);
}
}
}
public void delete(UniqueId packetId) {
// TODO
}
@Override
@SuppressWarnings("unchecked")
protected PacketType createFolderElement(File file) throws Exception {
return (PacketType)DataPacket.createPacket(file);
}
}

View File

@ -1,172 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.network;
import i2p.bote.UniqueId;
import i2p.bote.Util;
import i2p.bote.email.EmailIdentity;
import i2p.bote.folder.IncompleteEmailFolder;
import i2p.bote.packet.EncryptedEmailPacket;
import i2p.bote.packet.IndexPacket;
import i2p.bote.packet.UnencryptedEmailPacket;
import i2p.bote.packet.dht.DhtStorablePacket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import net.i2p.I2PAppContext;
import net.i2p.data.DataFormatException;
import net.i2p.data.Hash;
import net.i2p.util.Log;
/**
* Gets email packets from the DHT for one email identity. A separate thread is used for
* each packet in order to speed things up, and because the packets are in different places
* on the network.
*/
public class CheckEmailTask implements Callable<Boolean> {
public static final int THREAD_STACK_SIZE = 64 * 1024; // TODO find a safe low value (default in 64-bit Java 1.6 = 1MByte)
private static final int MAX_THREADS = 50;
private static final ThreadFactory EMAIL_PACKET_TASK_THREAD_FACTORY = Util.createThreadFactory("EmailPktTask", THREAD_STACK_SIZE);
private Log log = new Log(CheckEmailTask.class);
private EmailIdentity identity;
private DHT dht;
private PeerManager peerManager;
private IncompleteEmailFolder incompleteEmailFolder;
private I2PAppContext appContext;
private ExecutorService executor;
public CheckEmailTask(EmailIdentity identity, DHT dht, PeerManager peerManager, IncompleteEmailFolder incompleteEmailFolder, I2PAppContext appContext) {
this.identity = identity;
this.dht = dht;
this.peerManager = peerManager;
this.incompleteEmailFolder = incompleteEmailFolder;
this.appContext = appContext;
executor = Executors.newFixedThreadPool(MAX_THREADS, EMAIL_PACKET_TASK_THREAD_FACTORY);
}
/**
* Returns <code>true</code> if a new email was created in the inbox as a result
* of receiving an email packet.
*/
@Override
public Boolean call() {
Collection<Hash> emailPacketKeys = findEmailPacketKeys();
Collection<Future<Boolean>> results = new ArrayList<Future<Boolean>>();
for (Hash dhtKey: emailPacketKeys) {
Future<Boolean> result = executor.submit(new EmailPacketTask(dhtKey));
results.add(result);
}
boolean newEmail = false;
for (Future<Boolean> result: results)
try {
if (result.get())
newEmail = true;
} catch (ExecutionException e) {
log.error("Can't retrieve email packet.", e);
} catch (InterruptedException e) {
log.error("Interrupted while checking for mail.", e);
}
return newEmail;
}
/**
* Queries the DHT for new index packets and returns the DHT keys contained in them.
* @return A <code>Collection</code> containing zero or more elements
*/
private Collection<Hash> findEmailPacketKeys() {
log.debug("Querying the DHT for index packets with key " + identity.getHash());
Collection<DhtStorablePacket> packets = dht.findAll(identity.getHash(), IndexPacket.class);
// build an Collection of index packets
Collection<IndexPacket> indexPackets = new ArrayList<IndexPacket>();
for (DhtStorablePacket packet: packets)
if (packet instanceof IndexPacket)
indexPackets.add((IndexPacket)packet);
else
log.error("DHT returned packet of class " + packet.getClass().getSimpleName() + ", expected IndexPacket.");
IndexPacket mergedPacket = new IndexPacket(indexPackets);
log.debug("Found " + mergedPacket.getDhtKeys().size() + " Email Packet keys.");
return mergedPacket.getDhtKeys();
}
/**
* Queries the DHT for an email packet, adds the packet to the {@link IncompleteEmailFolder},
* and deletes the packet from the DHT.
*/
private class EmailPacketTask implements Callable<Boolean> {
private Hash dhtKey;
/**
*
* @param dhtKey The DHT key of the email packet to retrieve
*/
public EmailPacketTask(Hash dhtKey) {
this.dhtKey = dhtKey;
}
/**
* Returns <code>true</code> if a new email was created in the inbox as a result
* of receiving an email packet.
*/
@Override
public Boolean call() {
boolean emailCompleted = false;
DhtStorablePacket packet = dht.findOne(dhtKey, EncryptedEmailPacket.class);
if (packet instanceof EncryptedEmailPacket) {
EncryptedEmailPacket emailPacket = (EncryptedEmailPacket)packet;
try {
UnencryptedEmailPacket decryptedPacket = emailPacket.decrypt(identity, appContext);
emailCompleted = incompleteEmailFolder.addEmailPacket(decryptedPacket);
sendDeleteRequest(dhtKey, decryptedPacket.getVerificationDeletionKey());
}
catch (DataFormatException e) {
log.error("Can't decrypt email packet: " + emailPacket, e);
// TODO propagate error message to UI
}
}
else
if (packet != null)
log.error("DHT returned packet of class " + packet.getClass().getSimpleName() + ", expected EmailPacket.");
return emailCompleted;
}
/**
* Sends a delete request to the DHT.
* @param dhtKey The DHT key of the email packet that is to be deleted
* @param deletionKey The deletion key for the email packet
*/
private void sendDeleteRequest(Hash dhtKey, UniqueId deletionKey) {
// TODO
}
}
}

View File

@ -1,422 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.network;
import i2p.bote.UniqueId;
import i2p.bote.packet.CommunicationPacket;
import i2p.bote.packet.DataPacket;
import i2p.bote.packet.RelayPacket;
import i2p.bote.packet.RelayRequest;
import i2p.bote.packet.ResponsePacket;
import i2p.bote.packet.StatusCode;
import i2p.bote.service.I2PBoteThread;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import net.i2p.client.I2PSession;
import net.i2p.client.I2PSessionException;
import net.i2p.client.datagram.I2PDatagramMaker;
import net.i2p.data.Destination;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
import com.nettgryppa.security.HashCash;
/**
* All outgoing I2P traffic goes through this class.
* Packets are sent at a rate no greater than specified by the
* <CODE>maxBandwidth</CODE> property.
*
* The packet queue is FIFO with the exception of delayed packets.
* The packet with the highest index in the queue is always the next
* to be sent.
*/
public class I2PSendQueue extends I2PBoteThread implements PacketListener {
private Log log = new Log(I2PSendQueue.class);
private I2PSession i2pSession;
private PacketQueue packetQueue;
private Map<UniqueId, ScheduledPacket> outstandingRequests; // sent packets that haven't been responded to
private Set<PacketBatch> runningBatches;
private int maxBandwidth;
private Collection<SendQueuePacketListener> sendQueueListeners;
private Map<SendQueuePacketListener, Long> timeoutValues;
/**
* @param i2pSession
* @param i2pReceiver
*/
public I2PSendQueue(I2PSession i2pSession, I2PPacketDispatcher i2pReceiver) {
super("I2PSendQueue");
this.i2pSession = i2pSession;
i2pReceiver.addPacketListener(this);
packetQueue = new PacketQueue();
outstandingRequests = new ConcurrentHashMap<UniqueId, ScheduledPacket>();
runningBatches = new ConcurrentHashSet<PacketBatch>();
sendQueueListeners = Collections.synchronizedCollection(new ArrayList<SendQueuePacketListener>());
timeoutValues = new HashMap<SendQueuePacketListener, Long>();
}
/**
* Queues a packet behind the last undelayed packet.
* @param packet
* @param destination
*/
public void send(CommunicationPacket packet, Destination destination) {
send(packet, destination, 0);
}
/**
* Queues a packet behind the last undelayed packet and waits for up to
* <code>timeoutSeconds</code> for a response.
* @param packet
* @param destination
* @param timeoutMilliSeconds
* @return The response packet, or <code>null</code> if a timeout occurred.
* @throws InterruptedException
*/
public CommunicationPacket sendAndWait(CommunicationPacket packet, Destination destination, long timeoutMilliSeconds) throws InterruptedException {
ScheduledPacket scheduledPacket = new ScheduledPacket(packet, destination, 0);
long scheduleTime = System.currentTimeMillis();
packetQueue.add(scheduledPacket);
scheduledPacket.awaitSending();
outstandingRequests.put(packet.getPacketId(), scheduledPacket);
scheduledPacket.awaitResponse(timeoutMilliSeconds, TimeUnit.MILLISECONDS);
if (log.shouldLog(Log.DEBUG)) {
long responseTime = scheduledPacket.getResponseTime();
String responseInfo = responseTime<0?"timed out":"took " + (responseTime-scheduledPacket.getSentTime()) + "ms.";
log.debug("Packet with id " + packet.getPacketId() + " was queued for " + (scheduledPacket.getSentTime()-scheduleTime) + " ms, response " + responseInfo);
}
return scheduledPacket.getResponse();
}
/**
* Queues a packet for sending at or after a certain time.
* @param packet
* @param destination
* @param earliestSendTime
*/
public void send(CommunicationPacket packet, Destination destination, long earliestSendTime) {
packetQueue.add(new ScheduledPacket(packet, destination, earliestSendTime));
}
public void sendRelayRequest(RelayPacket relayPacket, HashCash hashCash, long earliestSendTime) {
RelayRequest relayRequest = new RelayRequest(hashCash, relayPacket);
ScheduledPacket scheduledPacket = new ScheduledPacket(relayRequest, relayPacket.getNextDestination(), earliestSendTime);
packetQueue.add(scheduledPacket);
}
/**
* Sends a Response Packet to a {@link Destination}, with the status code "OK".
* @param packet
* @param destination
* @param requestPacketId The packet id of the packet we're responding to
*/
public void sendResponse(DataPacket packet, Destination destination, UniqueId requestPacketId) {
sendResponse(packet, destination, StatusCode.OK, requestPacketId);
}
/**
* Sends a Response Packet to a {@link Destination}.
* @param packet
* @param destination
* @param statusCode
* @param requestPacketId The packet id of the packet we're responding to
*/
public void sendResponse(DataPacket packet, Destination destination, StatusCode statusCode, UniqueId requestPacketId) {
send(new ResponsePacket(packet, statusCode, requestPacketId), destination);
}
/**
* Sends a batch of packets, each to its own destination.
* Replies to the batch's packets are received until {@link remove(PacketBatch)} is called.
* @param batch
*/
public void send(PacketBatch batch) {
log.debug("Adding a batch containing " + batch.getPacketCount() + " packets.");
runningBatches.add(batch);
batch.initializeSentSignal();
for (PacketBatchItem batchItem: batch) {
ScheduledPacket scheduledPacket = new ScheduledPacket(batchItem.getPacket(), batchItem.getDestination(), 0, batch);
packetQueue.add(scheduledPacket);
}
}
public void remove(PacketBatch batch) {
runningBatches.remove(batch);
}
public int getQueueLength() {
return packetQueue.size();
}
/**
* Set the maximum outgoing bandwidth in kbits/s
* @param maxBandwidth
*/
public void setMaxBandwidth(int maxBandwidth) {
this.maxBandwidth = maxBandwidth;
}
/**
* Return the maximum outgoing bandwidth in kbits/s
* @return
*/
public int getMaxBandwidth() {
return maxBandwidth;
}
public void addSendQueueListener(SendQueuePacketListener listener) {
addSendQueueListener(listener, null);
}
/**
* Add a {@link SendQueuePacketListener} that is automatically removed after
* <code>timeout</code> milliseconds.
* @param listener
* @param timeout
*/
public void addSendQueueListener(SendQueuePacketListener listener, Long timeout) {
sendQueueListeners.add(listener);
timeoutValues.put(listener, timeout);
}
public void removeSendQueueListener(SendQueuePacketListener listener) {
sendQueueListeners.remove(listener);
timeoutValues.remove(listener);
}
private void firePacketListeners(CommunicationPacket packet) {
for (SendQueuePacketListener listener: sendQueueListeners)
listener.packetSent(packet);
}
// Implementation of PacketListener
@Override
public void packetReceived(CommunicationPacket packet, Destination sender, long receiveTime) {
if (packet instanceof ResponsePacket) {
log.debug("Response Packet received: Packet Id = " + packet.getPacketId() + " Sender = " + sender);
UniqueId packetId = packet.getPacketId();
for (PacketBatch batch: runningBatches)
if (batch.contains(packetId))
batch.addResponse(((ResponsePacket)packet).getPayload());
// Remove the original request if it is on the list, and notify objects waiting on a response
ScheduledPacket requestPacket = outstandingRequests.remove(packetId);
if (requestPacket != null) {
requestPacket.setResponse(packet);
requestPacket.decrementResponseLatch();
}
// If there is a packet file for the original packet, it can be deleted now.
// Use the cached filename if the packet was in the cache; otherwise, find the file by packet Id
/* ScheduledPacket cachedPacket = recentlySentCache.remove(packetId);
if (cachedPacket != null)
fileManager.removePacketFile(cachedPacket);
else
fileManager.removePacketFile(packetId);*/
}
}
@Override
public void run() {
I2PDatagramMaker datagramMaker = new I2PDatagramMaker(i2pSession);
while (true) {
ScheduledPacket scheduledPacket;
try {
scheduledPacket = packetQueue.take();
}
catch (InterruptedException e) {
log.warn("Interrupted while waiting for new packets.", e);
break;
}
CommunicationPacket i2pBotePacket = scheduledPacket.data;
// wait long enough so rate <= maxBandwidth;
if (maxBandwidth > 0) {
int packetSizeBits = i2pBotePacket.getSize() * 8;
int maxBWBitsPerSecond = maxBandwidth * 1024;
long waitTimeMsecs = 1000L * packetSizeBits / maxBWBitsPerSecond;
if (System.currentTimeMillis()+waitTimeMsecs < scheduledPacket.earliestSendTime)
waitTimeMsecs = scheduledPacket.earliestSendTime;
try {
TimeUnit.MILLISECONDS.sleep(waitTimeMsecs);
}
catch (InterruptedException e) {
log.warn("Interrupted while waiting to send packet.", e);
}
}
PacketBatch batch = scheduledPacket.batch;
boolean isBatchPacket = batch != null;
log.debug("Sending " + (isBatchPacket?"":"non-") + "batch packet: [" + i2pBotePacket + "] to peer: " + scheduledPacket.destination.toBase64());
byte[] replyableDatagram = datagramMaker.makeI2PDatagram(i2pBotePacket.toByteArray());
try {
i2pSession.sendMessage(scheduledPacket.destination, replyableDatagram);
// set sentTime; update queue+cache, update countdown latch, fire packet listeners
scheduledPacket.data.setSentTime(System.currentTimeMillis());
packetQueue.remove(scheduledPacket);
if (isBatchPacket)
batch.decrementSentLatch();
scheduledPacket.decrementSentLatch();
firePacketListeners(scheduledPacket.data);
log.debug("Packet sent. Send queue length is now " + packetQueue.size());
if (isBatchPacket)
log.debug(" Batch has " + batch.getPacketCount() + " packets total, " + batch.getUnsentPacketCount() + " waiting to be sent.");
}
catch (I2PSessionException sessExc) {
log.error("Can't send packet.", sessExc);
// pause to avoid CPU hogging if the error doesn't go away
try {
TimeUnit.SECONDS.sleep(1);
}
catch (InterruptedException intrExc) {
log.error("Interrupted while sleeping after a send error.", intrExc);
}
}
}
}
private class PacketQueue extends LinkedList<ScheduledPacket> {
public void add(ScheduledPacket packet, long earliestSendTime) {
int index = getInsertionIndex(packet, earliestSendTime);
add(index, packet);
}
private int getInsertionIndex(ScheduledPacket packet, long earliestSendTime) {
if (isEmpty())
return 0;
// do a linear search (binary search isn't a good fit for LinkedList)
// TODO using foreach would be more efficient
for (int i=0; i<size(); i++)
if (get(i).earliestSendTime <= earliestSendTime)
return i;
return size();
}
/**
* Not synchronized because there should only be one {@link I2PSendQueue}.
* @throws InterruptedException
* @return
*/
public ScheduledPacket take() throws InterruptedException {
while (isEmpty())
TimeUnit.SECONDS.sleep(1);
return pollLast();
}
}
private class ScheduledPacket implements Comparable<ScheduledPacket> {
CommunicationPacket data;
Destination destination;
long earliestSendTime;
PacketBatch batch; // the batch this packet belongs to, or null if not part of a batch
long sentTime;
long responseTime;
CountDownLatch sentSignal;
CountDownLatch responseSignal;
CommunicationPacket response;
public ScheduledPacket(CommunicationPacket packet, Destination destination, long earliestSendTime) {
this(packet, destination, earliestSendTime, null);
}
public ScheduledPacket(CommunicationPacket packet, Destination destination, long earliestSendTime, PacketBatch batch) {
this.data = packet;
this.destination = destination;
this.earliestSendTime = earliestSendTime;
this.batch = batch;
this.sentSignal = new CountDownLatch(1);
this.responseSignal = new CountDownLatch(1);
this.responseTime = -1;
}
@Override
public int compareTo(ScheduledPacket anotherPacket) {
return new Long(earliestSendTime).compareTo(anotherPacket.earliestSendTime);
}
public void decrementSentLatch() {
sentTime = System.currentTimeMillis();
sentSignal.countDown();
}
public void awaitSending() throws InterruptedException {
sentSignal.await();
}
public long getSentTime() {
return sentTime;
}
/**
* Returns the time at which a response packet was received, or -1 if no response.
* @return
*/
public long getResponseTime() {
return responseTime;
}
public void decrementResponseLatch() {
responseTime = System.currentTimeMillis();
responseSignal.countDown();
}
public void awaitResponse(long timeout, TimeUnit unit) throws InterruptedException {
responseSignal.await(timeout, unit);
}
public void setResponse(CommunicationPacket response) {
this.response = response;
}
/**
* If this packet was sent via <code>sendAndWait</code>, and a response packet has been
* received (i.e., a packet with the same packet id), this method returns the response packet.
* Otherwise, <code>null</code> is returned.
* @return
*/
public CommunicationPacket getResponse() {
return response;
}
}
}

View File

@ -1,344 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.network.kademlia;
import i2p.bote.network.I2PSendQueue;
import i2p.bote.network.PacketListener;
import i2p.bote.packet.CommunicationPacket;
import i2p.bote.service.I2PBoteThread;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
import net.i2p.util.RandomSource;
// TODO if a sibling times out, refill the sibling table
public class BucketManager extends I2PBoteThread implements PacketListener {
private static final int INTERVAL = 5 * 60 * 1000;
private static final int PING_TIMEOUT = 20 * 1000;
private Log log = new Log(BucketManager.class);
private I2PSendQueue sendQueue;
private List<KBucket> kBuckets;
private KBucket siblingBucket; // TODO [ordered furthest away to closest in terms of hash distance to local node]
private Hash localDestinationHash;
public BucketManager(I2PSendQueue sendQueue, Collection<KademliaPeer> initialPeers, Hash localDestinationHash) {
super("BucketMgr");
this.sendQueue = sendQueue;
this.localDestinationHash = localDestinationHash;
kBuckets = Collections.synchronizedList(new ArrayList<KBucket>());
kBuckets.add(new KBucket(KBucket.MIN_HASH_VALUE, KBucket.MAX_HASH_VALUE, 0, true)); // this is the root bucket, so depth=0
siblingBucket = new KBucket(KBucket.MIN_HASH_VALUE, KBucket.MAX_HASH_VALUE, 0, false);
addAll(initialPeers);
}
public void addAll(Collection<KademliaPeer> nodes) {
for (KademliaPeer node: nodes)
addOrUpdate(node);
}
/**
* Add a <code>{@link KademliaPeer}</code> to the sibling list or a bucket.
* @param peer
*/
public void addOrUpdate(KademliaPeer peer) {
Hash peerHash = peer.getDestinationHash();
log.debug("Adding/updating peer: Hash = " + peerHash);
peer.resetStaleCounter();
synchronized(this) {
if (!siblingBucket.isFull() || siblingBucket.contains(peer)) {
siblingBucket.addOrUpdate(peer);
getBucket(peerHash).remove(peer);
}
else if (isCloserSibling(peer)) {
KademliaPeer ejectedPeer = siblingBucket.getMostDistantPeer(localDestinationHash);
addToBucket(ejectedPeer);
siblingBucket.remove(ejectedPeer);
siblingBucket.addOrUpdate(peer);
getBucket(peerHash).remove(peer);
}
else
addToBucket(peer);
}
logBucketStats();
/* KademliaPeer ejectedPeer = addSibling(peer);
// if the peer was added as a sibling, it may need to be removed from a bucket
if (ejectedPeer != peer)
getBucket(peerHash).remove(peer);
// if the peer didn't get added as a sibling, try a bucket
else
addToBucket(peer);
// if adding the peer to the list of siblings replaced another sibling, add the old sibling to a bucket
if (ejectedPeer != null)
addToBucket(ejectedPeer);*/
/*TODO synchronized(siblings) {
if (siblings.isFull()) {
KBucket bucket = getBucket(nodeHash);
KademliaPeer mostDistantSibling = getMostDistantSibling();
if (getDistance(node.getDestinationHash()) < getDistance(mostDistantSibling)) {
bucket.addOrUpdate(mostDistantSibling);
siblings.remove(mostDistantSibling);
siblings.add(node);
}
else
bucket.addOrUpdate(node);
}
else {
siblings.add(node);
}*/
}
private void logBucketStats() {
int numBuckets = kBuckets.size();
int numPeers = getAllPeers().size();
log.debug("#buckets=" + numBuckets + "+sibBkt, #peers=" + numPeers);
}
/**
* Add a <code>{@link KademliaPeer}</code> to the appropriate bucket.
* @param peer
*/
private void addToBucket(KademliaPeer peer) {
Hash nodeHash = peer.getDestinationHash();
KBucket bucket = getBucket(nodeHash);
KBucket newBucket = bucket.addOrSplit(peer);
if (newBucket != null)
kBuckets.add(newBucket);
}
/**
* Return <code>true</code> if a given peer is closer to the local node than at
* least one sibling. In other words, test if <code>peer</code> should replace
* an existing sibling.
* @param peer
* @return
*/
private boolean isCloserSibling(KademliaPeer peer) {
BigInteger peerDistance = KademliaUtil.getDistance(peer, localDestinationHash);
for (KademliaPeer sibling: siblingBucket) {
BigInteger siblingDistance = KademliaUtil.getDistance(sibling.getDestinationHash(), localDestinationHash);
if (peerDistance.compareTo(siblingDistance) < 0)
return true;
}
return false;
}
/**
* Add a peer to the sibling list if the list is not full, or if there is a node that can be
* replaced.
*
* If <code>peer</code> replaced an existing sibling, that sibling is returned.
* If <code>peer</code> could not be added to the list, <code>peer</code> is returned.
* If the list was not full, <code>null</code> is returned.
* @param peer
* @return
*/
/* private KademliaPeer addSibling(KademliaPeer peer) {
// no need to handle a replacement cache because the sibling bucket has none.
KademliaPeer mostDistantSibling = siblingBucket.getMostDistantPeer(localDestinationHash);
if (!siblingBucket.isFull()) {
siblingBucket.add(peer);
return null;
}
else if (new PeerDistanceComparator(localDestinationHash).compare(peer, mostDistantSibling) < 0) {
siblingBucket.remove(mostDistantSibling);
siblingBucket.add(peer);
return mostDistantSibling;
}
else
return peer;
}*/
public void remove(KademliaPeer peer) {
Hash nodeHash = peer.getDestinationHash();
getBucket(nodeHash).remove(peer);
}
/**
* Do a binary search for the index of the bucket whose key range contains a given {@link Hash}.
* @param key
* @return
*/
private int getBucketIndex(Hash key) {
// initially, the search interval is 0..n-1
int lowEnd = 0;
int highEnd = kBuckets.size();
BigInteger keyValue = new BigInteger(key.getData());
while (lowEnd < highEnd) {
int centerIndex = (highEnd + lowEnd) / 2;
if (keyValue.compareTo(kBuckets.get(centerIndex).getStartId()) < 0)
highEnd = centerIndex;
else if (keyValue.compareTo(kBuckets.get(centerIndex).getEndId()) > 0)
lowEnd = centerIndex;
else
return centerIndex;
}
log.error("This should never happen! No k-bucket found for hash: " + key);
return -1;
}
/**
* Do a binary search for the bucket whose key range contains a given {@link Hash}.
* @param key
* @return
*/
private KBucket getBucket(Hash key) {
return kBuckets.get(getBucketIndex(key));
}
/**
* Return the <code>count</code> peers that are closest to a given key.
* Less than <code>count</code> peers may be returned if there aren't
* enough peers in the k-buckets.
* @param key
* @param count
* @return
*/
public Collection<KademliaPeer> getClosestPeers(Hash key, int count) {
Collection<KademliaPeer> closestPeers = new ConcurrentHashSet<KademliaPeer>();
// TODO don't put all peers in one huge list, only use two buckets at a time
KademliaPeer[] allPeers = getAllPeersSortedByDistance(key);
for (int i=0; i<count && i<allPeers.length; i++)
closestPeers.add(allPeers[i]);
return closestPeers;
}
private KademliaPeer[] getAllPeersSortedByDistance(Hash key) {
List<KademliaPeer> allPeers = getAllPeers();
KademliaPeer[] peerArray = getAllPeers().toArray(new KademliaPeer[allPeers.size()]);
Arrays.sort(peerArray, new PeerDistanceComparator(key));
return peerArray;
}
private List<KademliaPeer> getAllPeers() {
List<KademliaPeer> allPeers = new ArrayList<KademliaPeer>();
for (KBucket bucket: kBuckets)
allPeers.addAll(bucket.getNodes());
allPeers.addAll(siblingBucket.getNodes());
return allPeers;
}
/**
* Return all siblings of the local node (siblings are an S/Kademlia feature).
* @return
*/
public List<KademliaPeer> getSiblings() {
List<KademliaPeer> siblingDestinations = new ArrayList<KademliaPeer>();
for (KademliaPeer sibling: siblingBucket)
siblingDestinations.add(sibling);
return siblingDestinations;
}
/**
* Return the total number of known Kademlia peers.
* @return
*/
public int getPeerCount() {
int count = 0;
for (KBucket bucket: kBuckets)
count += bucket.size();
count += siblingBucket.size();
return count;
}
/**
* "refresh all k-buckets further away than the closest neighbor. This refresh is just a lookup of a random key that is within that k-bucket range."
*/
public void refreshAll() {
for (KBucket bucket: kBuckets)
refresh(bucket);
}
private void refresh(KBucket bucket) {
byte[] randomHash = new byte[Hash.HASH_LENGTH];
for (int i=0; i<Hash.HASH_LENGTH; i++)
randomHash[i] = (byte)RandomSource.getInstance().nextInt(256);
Hash key = new Hash(randomHash);
getClosestPeers(key, KademliaConstants.K);
}
/* private void updatePeerList() {
for (Destination peer: peers) {
if (ping(peer))
requestPeerList(peer);
}
}*/
@Override
public void run() {
while (!shutdownRequested()) {
try {
// TODO replicate();
// TODO updatePeerList(); refresh every bucket to which we haven't performed a node lookup in the past hour. Refreshing means picking a random ID in the bucket's range and performing a node search for that ID.
sleep(INTERVAL);
}
catch (InterruptedException e) {
log.debug("Thread '" + getName() + "' + interrupted", e);
}
}
}
// PacketListener implementation
@Override
public void packetReceived(CommunicationPacket packet, Destination sender, long receiveTime) {
// any type of incoming packet updates the peer's record in the bucket/sibling list, or adds the peer to the bucket/sibling list
addOrUpdate(new KademliaPeer(sender, receiveTime));
}
private class PeerDistanceComparator implements Comparator<KademliaPeer> {
private Hash reference;
PeerDistanceComparator(Hash reference) {
this.reference = reference;
}
@Override
public int compare(KademliaPeer peer1, KademliaPeer peer2) {
BigInteger distance1 = KademliaUtil.getDistance(peer1.getDestinationHash(), reference);
BigInteger distance2 = KademliaUtil.getDistance(peer2.getDestinationHash(), reference);
return distance1.compareTo(distance2);
}
}
}

View File

@ -1,219 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.network.kademlia;
import i2p.bote.UniqueId;
import i2p.bote.network.I2PPacketDispatcher;
import i2p.bote.network.I2PSendQueue;
import i2p.bote.network.PacketListener;
import i2p.bote.packet.CommunicationPacket;
import i2p.bote.packet.DataPacket;
import i2p.bote.packet.PeerList;
import i2p.bote.packet.ResponsePacket;
import i2p.bote.packet.dht.FindClosePeersPacket;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
public class ClosestNodesLookupTask implements Runnable {
private static final int REQUEST_TIMEOUT = 30 * 1000;
private static final int CLOSEST_NODES_LOOKUP_TIMEOUT = 2 * 60 * 1000; // the maximum amount of time a FIND_CLOSEST_NODES can take
private Log log = new Log(ClosestNodesLookupTask.class);
private Hash key;
private I2PPacketDispatcher i2pReceiver;
private BucketManager bucketManager;
private Random randomNumberGenerator;
private I2PSendQueue sendQueue;
private Set<Destination> responseReceived;
private Set<KademliaPeer> notQueriedYet;
private Set<FindClosePeersPacket> pendingRequests;
public ClosestNodesLookupTask(Hash key, I2PSendQueue sendQueue, I2PPacketDispatcher i2pReceiver, BucketManager bucketManager) {
this.key = key;
this.sendQueue = sendQueue;
this.i2pReceiver = i2pReceiver;
this.bucketManager = bucketManager;
randomNumberGenerator = new Random(getTime());
responseReceived = new TreeSet<Destination>(new HashDistanceComparator(key)); // nodes that have responded to a query; sorted by distance to the key
notQueriedYet = new ConcurrentHashSet<KademliaPeer>(); // peers we haven't contacted yet
pendingRequests = new ConcurrentHashSet<FindClosePeersPacket>(); // outstanding queries
}
@Override
public void run() {
log.debug("Looking up nodes closest to " + key);
PacketListener packetListener = new IncomingPacketHandler();
i2pReceiver.addPacketListener(packetListener);
// prepare a list of close nodes (might need more than alpha if they don't all respond)
notQueriedYet.addAll(bucketManager.getClosestPeers(key, KademliaConstants.S));
long startTime = getTime();
while (true) {
// send new requests if less than alpha are pending
while (pendingRequests.size()<KademliaConstants.ALPHA && !notQueriedYet.isEmpty()) {
KademliaPeer peer = selectRandom(notQueriedYet);
notQueriedYet.remove(peer);
FindClosePeersPacket packet = new FindClosePeersPacket(key);
pendingRequests.add(packet);
try {
CommunicationPacket response = sendQueue.sendAndWait(packet, peer.getDestination(), REQUEST_TIMEOUT);
if (response == null) // timeout occurred
peer.incrementStaleCounter();
else
peer.resetStaleCounter();
}
catch (InterruptedException e) {
log.warn("Interrupted while waiting on a lookup request.", e);
}
}
if (responseReceived.size() >= KademliaConstants.S)
break;
if (hasTimedOut(startTime, CLOSEST_NODES_LOOKUP_TIMEOUT)) {
log.error("Lookup for closest nodes timed out.");
break;
}
}
log.debug(responseReceived.size() + " nodes found.");
i2pReceiver.removePacketListener(packetListener);
}
private KademliaPeer selectRandom(Collection<KademliaPeer> collection) {
KademliaPeer[] array = new KademliaPeer[collection.size()];
int index = randomNumberGenerator.nextInt(array.length);
return collection.toArray(array)[index];
}
private long getTime() {
return System.currentTimeMillis();
}
private boolean hasTimedOut(long startTime, long timeout) {
return getTime() > startTime + timeout;
}
/**
* Return up to <code>s</code> peers.
* @return
*/
public List<Destination> getResults() {
List<Destination> resultsList = new ArrayList<Destination>();
for (Destination destination: responseReceived)
resultsList.add(destination);
Collections.sort(resultsList, new HashDistanceComparator(key));
// trim the list to the k closest nodes
if (resultsList.size() > KademliaConstants.S)
resultsList = resultsList.subList(0, KademliaConstants.S);
return resultsList;
}
/**
* Return <code>true</code> if a set of peers contains a given peer.
* @param peerSet
* @param peerToFind
* @return
*/
private boolean contains(Set<KademliaPeer> peerSet, KademliaPeer peerToFind) {
Hash peerHash = peerToFind.getDestinationHash();
for (KademliaPeer peer: peerSet)
if (peer.getDestinationHash().equals(peerHash))
return true;
return false;
}
// compares two Destinations in terms of closeness to <code>reference</code>
private class HashDistanceComparator implements Comparator<Destination> {
private Hash reference;
public HashDistanceComparator(Hash reference) {
this.reference = reference;
}
public int compare(Destination dest1, Destination dest2) {
BigInteger dest1Distance = KademliaUtil.getDistance(dest1.calculateHash(), reference);
BigInteger dest2Distance = KademliaUtil.getDistance(dest2.calculateHash(), reference);
return dest1Distance.compareTo(dest2Distance);
}
};
private class IncomingPacketHandler implements PacketListener {
@Override
public void packetReceived(CommunicationPacket packet, Destination sender, long receiveTime) {
if (packet instanceof ResponsePacket) {
ResponsePacket responsePacket = (ResponsePacket)packet;
DataPacket payload = responsePacket.getPayload();
if (payload instanceof PeerList)
addPeers(responsePacket, (PeerList)payload, sender, receiveTime);
}
}
private void addPeers(ResponsePacket responsePacket, PeerList peerListPacket, Destination sender, long receiveTime) {
log.debug("Peer List Packet received: #peers=" + peerListPacket.getPeers().size() + ", sender="+ sender);
// if the packet is in response to a pending request, update the three Sets
FindClosePeersPacket request = getPacketById(pendingRequests, responsePacket.getPacketId()); // find the request the node list is in response to
if (request != null) {
// TODO make responseReceived and pendingRequests a parameter in the constructor?
responseReceived.add(sender);
Collection<KademliaPeer> peersReceived = peerListPacket.getPeers();
for (KademliaPeer peer: peersReceived)
if (contains(notQueriedYet, peer))
notQueriedYet.add(peer);
pendingRequests.remove(request);
// TODO synchronize access to shortList and pendingRequests
}
else
log.debug("No Find Close Nodes packet found for Peer List: " + peerListPacket);
}
/**
* Returns a packet that matches a given {@link UniqueId} from a {@link Collection} of packets, or
* <code>null</code> if no match.
* @param packets
* @param packetId
* @return
*/
private FindClosePeersPacket getPacketById(Collection<FindClosePeersPacket> packets, UniqueId packetId) {
for (FindClosePeersPacket packet: packets)
if (packetId.equals(packet.getPacketId()))
return packet;
return null;
}
};
}

View File

@ -1,280 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.network.kademlia;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.Log;
/**
* Peers are sorted by the time of the most recent communication: Index 0 = least recent,
* index n-1 = most recent.
*
*/
class KBucket implements Iterable<KademliaPeer> {
static final BigInteger MIN_HASH_VALUE = BigInteger.ONE.negate().shiftLeft(Hash.HASH_LENGTH*8); // system-wide minimum hash value
static final BigInteger MAX_HASH_VALUE = BigInteger.ONE.shiftLeft(Hash.HASH_LENGTH*8).subtract(BigInteger.ONE); // system-wide maximum hash value
private static final int CAPACITY = KademliaConstants.K; // The maximum number of peers the bucket can hold
private Log log = new Log(KBucket.class);
private BigInteger startId;
private BigInteger endId;
private List<KademliaPeer> peers; // the list is always kept sorted by "last seen" time
private Set<KademliaPeer> replacementCache;
private int depth;
private boolean replacementCacheEnabled;
KBucket(BigInteger startId, BigInteger endId, int depth, boolean replacementCacheEnabled) {
this.startId = startId;
this.endId = endId;
Comparator<KademliaPeer> peerComparator = createLastReceptionComparator();
peers = new ArrayList<KademliaPeer>();
replacementCache = new ConcurrentSkipListSet<KademliaPeer>(peerComparator);
this.depth = depth;
this.replacementCacheEnabled = replacementCacheEnabled;
}
BigInteger getStartId() {
return startId;
}
BigInteger getEndId() {
return endId;
}
List<KademliaPeer> getNodes() {
// TODO only return peers that are not locked
return peers;
}
void add(KademliaPeer node) {
if (isFull())
log.error("Error: adding a node to a full k-bucket. Bucket needs to be split first. Size=" + size() + ", capacity=" + CAPACITY);
peers.add(node);
}
/**
* Adds a node to the bucket, splitting the bucket if necessary. If the bucket is split,
* the newly created bucket is returned. Otherwise, <code>null</code> is returned.
*
* If the bucket is full but cannot be split, the new node is added to the replacement
* cache and <code>null</code> is returned.
* @param peer
* @return
*/
synchronized KBucket addOrSplit(KademliaPeer peer) {
if (!rangeContains(peer))
log.error("Attempt to add a node whose hash is outside the bucket's range! Bucket start=" + startId + " Bucket end=" + endId + " peer hash=" + new BigInteger(peer.getDestinationHash().getData()));
if (isFull() && !contains(peer)) {
if (canSplit(peer)) {
KBucket newBucket = split(peer.getDestinationHash());
if (rangeContains(peer))
add(peer);
else if (newBucket.rangeContains(peer))
newBucket.add(peer);
else
log.error("After splitting a bucket, node is outside of both buckets' ranges.");
return newBucket;
}
else {
replacementCache.add(peer);
return null;
}
}
else {
addOrUpdate(peer);
return null;
}
}
/**
* Returns <code>true</code> if the bucket should be split in order to make room for a new peer.
* @return
*/
private boolean canSplit(KademliaPeer peer) {
return depth%KademliaConstants.B!=0 || rangeContains(peer);
}
/**
* Updates a known peer, or adds the peer if it isn't known.
* TODO If the bucket is full, the peer is added to the bucket's replacement cache.
* @param destination
* @return <code>true</code> if the peer was added (or replacement-cached),
* <code>false</code> if it was updated.
*/
boolean addOrUpdate(KademliaPeer peer) {
// TODO log an error if peer outside bucket's range
// TODO handle stale peers
// TODO manage replacement cache
KademliaPeer existingPeer = getPeer(peer.getDestination());
if (existingPeer == null) {
add(peer);
return true;
}
else {
existingPeer.setLastReception(peer.getLastReception());
// TODO move to end of list if lastReception is highest value, which it should be most of the time
return false;
}
}
/**
* Returns <code>true</code> if a peer exists in the bucket.
* @param peer
* @return
*/
boolean contains(KademliaPeer peer) {
return getPeer(peer.getDestination()) != null;
}
/**
* Returns <code>true</code> if the bucket's Id range contains the hash of a given
* peer, regardless if the bucket contains the peer; <code>false</code> if the hash
* is outside the range.
* @param peer
* @return
*/
private boolean rangeContains(KademliaPeer peer) {
BigInteger peerHash = new BigInteger(peer.getDestinationHash().getData());
return (startId.compareTo(peerHash)<=0 || endId.compareTo(peerHash)>0);
}
/**
* Returns a peer with a given I2P destination from the bucket, or <code>null</code> if the
* peer isn't in the bucket.
* @param destination
* @return
*/
KademliaPeer getPeer(Destination destination) {
for (KademliaPeer peer: peers)
if (peer.getDestination().equals(destination))
return peer;
return null;
}
KademliaPeer getClosestPeer(Hash key) {
KademliaPeer closestPeer = null;
BigInteger minDistance = MAX_HASH_VALUE;
for (KademliaPeer peer: peers) {
BigInteger distance = KademliaUtil.getDistance(key, peer.getDestination().calculateHash());
if (distance.compareTo(minDistance) < 0) {
closestPeer = peer;
minDistance = distance;
}
}
return closestPeer;
}
/* KademliaPeer getMostDistantPeer(KademliaPeer node) {
return getMostDistantPeer(node.getDestinationHash());
}*/
KademliaPeer getMostDistantPeer(Hash key) {
KademliaPeer mostDistantPeer = null;
BigInteger maxDistance = BigInteger.ZERO;
for (KademliaPeer peer: peers) {
BigInteger distance = KademliaUtil.getDistance(key, peer.getDestination().calculateHash());
if (distance.compareTo(maxDistance) > 0) {
mostDistantPeer = peer;
maxDistance = distance;
}
}
return mostDistantPeer;
}
@Override
public Iterator<KademliaPeer> iterator() {
return peers.iterator();
}
void remove(Destination destination) {
peers.remove(getPeer(destination));
}
/**
* Removes a peer from the bucket. If the peer doesn't exist in the bucket, nothing happens.
* @param node
*/
void remove(KademliaPeer node) {
peers.remove(node);
}
int size() {
return peers.size();
}
boolean isFull() {
return size() >= CAPACITY;
}
/**
* Moves half the nodes into a new bucket.
* @return The new bucket
*/
KBucket split() {
depth++;
KBucket newBucket = new KBucket(startId, endId, depth, replacementCacheEnabled);
for (int i=0; i<peers.size()/2; i++) {
KademliaPeer peer = peers.get(i);
newBucket.add(peer);
remove(peer);
}
return newBucket;
}
KBucket split(Hash hash) {
return split(new BigInteger(hash.toBase64()));
}
KBucket split(BigInteger pivot) {
depth++;
KBucket newBucket = new KBucket(startId, pivot.subtract(BigInteger.ONE), depth, replacementCacheEnabled);
startId = pivot;
for (KademliaPeer peer: peers) {
BigInteger nodeId = new BigInteger(peer.getDestination().calculateHash().getData());
if (nodeId.compareTo(pivot) >= 0) {
newBucket.add(peer);
remove(peer);
}
}
return newBucket;
}
private Comparator<KademliaPeer> createLastReceptionComparator() {
return new Comparator<KademliaPeer>() {
@Override
public int compare(KademliaPeer peer1, KademliaPeer peer2) {
return Long.valueOf(peer1.getLastReception()).compareTo(peer2.getLastReception());
}
};
}
}

View File

@ -1,416 +0,0 @@
/**
* Copyright (C) 2009 HungryHobo@mail.i2p
*
* The GPG fingerprint for HungryHobo@mail.i2p is:
* 6DD3 EAA2 9990 29BC 4AD2 7486 1E2C 7B61 76DC DC12
*
* This file is part of I2P-Bote.
* I2P-Bote is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* I2P-Bote is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with I2P-Bote. If not, see <http://www.gnu.org/licenses/>.
*/
package i2p.bote.network.kademlia;
import i2p.bote.network.DHT;
import i2p.bote.network.DhtStorageHandler;
import i2p.bote.network.I2PPacketDispatcher;
import i2p.bote.network.I2PSendQueue;
import i2p.bote.network.PacketBatch;
import i2p.bote.network.PacketListener;
import i2p.bote.packet.CommunicationPacket;
import i2p.bote.packet.I2PBotePacket;
import i2p.bote.packet.PeerList;
import i2p.bote.packet.ResponsePacket;
import i2p.bote.packet.StatusCode;
import i2p.bote.packet.dht.DhtStorablePacket;
import i2p.bote.packet.dht.FindClosePeersPacket;
import i2p.bote.packet.dht.RetrieveRequest;
import i2p.bote.packet.dht.StoreRequest;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.ConcurrentHashSet;
import net.i2p.util.Log;
import com.nettgryppa.security.HashCash;
/**
* The main class of the Kademlia implementation. All the high-level Kademlia logic
* is in here.
*
* Resources used:
* [1] http://pdos.csail.mit.edu/~petar/papers/maymounkov-kademlia-lncs.pdf
* [2] http://xlattice.sourceforge.net/components/protocol/kademlia/specs.html
* [3] http://en.wikipedia.org/wiki/Kademlia
* [4] http://www.barsoom.org/papers/infocom-2006-kad.pdf
* [5] http://doc.tm.uka.de/SKademlia_2007.pdf
* [6] OverSim (http://www.oversim.org/), which includes a S/Kademlia implementation
*
*/
public class KademliaDHT implements DHT, PacketListener {
private static final URL BUILT_IN_PEER_FILE = KademliaDHT.class.getResource("built-in-peers.txt");
private Log log = new Log(KademliaDHT.class);
private Hash localDestinationHash;
private I2PSendQueue sendQueue;
private I2PPacketDispatcher i2pReceiver;
private File peerFile;
private Collection<KademliaPeer> initialPeers;
private BucketManager bucketManager;
private Map<Class<? extends DhtStorablePacket>, DhtStorageHandler> storageHandlers;
public KademliaDHT(Destination localDestination, I2PSendQueue sendQueue, I2PPacketDispatcher i2pReceiver, File peerFile) {
localDestinationHash = localDestination.calculateHash();
this.sendQueue = sendQueue;
this.i2pReceiver = i2pReceiver;
this.peerFile = peerFile;
initialPeers = Collections.synchronizedList(new ArrayList<KademliaPeer>());
// Read the built-in peer file
readPeers(BUILT_IN_PEER_FILE);
// Read the updateable peer file
readPeers(peerFile);
bucketManager = new BucketManager(sendQueue, initialPeers, localDestination.calculateHash());
storageHandlers = new ConcurrentHashMap<Class<? extends DhtStorablePacket>, DhtStorageHandler>();
}
/**
* Returns the S nodes closest to a given key by querying peers.
* This method blocks. It returns after <code>CLOSEST_NODES_LOOKUP_TIMEOUT+1</code> seconds at
* the longest.
*
* The number of pending requests never exceeds ALPHA. According to [4], this is the most efficient.
*
* If there are less than <code>s</code> results after the kademlia lookup finishes, nodes from
* the sibling list are used.
*/
private Collection<Destination> getClosestNodes(Hash key) {
ClosestNodesLookupTask lookupTask = new ClosestNodesLookupTask(key, sendQueue, i2pReceiver, bucketManager);
lookupTask.run();
return lookupTask.getResults();
}
@Override
public DhtStorablePacket findOne(Hash key, Class<? extends DhtStorablePacket> dataType) {
Collection<DhtStorablePacket> results = find(key, dataType, false);
if (results.isEmpty())
return null;
else
return results.iterator().next();
}
@Override
public Collection<DhtStorablePacket> findAll(Hash key, Class<? extends DhtStorablePacket> dataType) {
return find(key, dataType, true);
}
@Override
public void setStorageHandler(Class<? extends DhtStorablePacket> packetType, DhtStorageHandler storageHandler) {
storageHandlers.put(packetType, storageHandler);
}
@Override
public int getNumPeers() {
return bucketManager.getPeerCount();
}
private Collection<DhtStorablePacket> find(Hash key, Class<? extends DhtStorablePacket> dataType, boolean exhaustive) {
final Collection<Destination> closeNodes = getClosestNodes(key);
log.debug("Querying " + closeNodes.size() + " nodes for data type " + dataType + ", Kademlia key " + key);
final Collection<I2PBotePacket> receivedPackets = new ConcurrentHashSet<I2PBotePacket>(); // avoid adding duplicate packets
/* PacketListener packetListener = new PacketListener() {
@Override
public void packetReceived(CommunicationPacket packet, Destination sender, long receiveTime) {
// add packet to list of received packets if the packet is in response to a RetrieveRequest
if (packet instanceof RetrieveRequest && closeNodes.contains(sender))
receivedPackets.add(packet);
}
};
i2pReceiver.addPacketListener(packetListener);*/
// Send the retrieve requests
PacketBatch batch = new PacketBatch();
for (Destination node: closeNodes)
batch.putPacket(new RetrieveRequest(key, dataType), node);
sendQueue.send(batch);
try {
batch.awaitSendCompletion();
}
catch (InterruptedException e) {
log.warn("Interrupted while waiting for Retrieve Requests to be sent.", e);
}
// wait for replies
try {
if (exhaustive)
TimeUnit.SECONDS.sleep(60); // TODO make a static field
else
batch.awaitFirstReply(60, TimeUnit.SECONDS); // TODO make a static field
}
catch (InterruptedException e) {
log.warn("Interrupted while waiting for responses to Retrieve Requests.", e);
}
log.debug(batch.getResponses().size() + " response packets received for hash " + key + " and data type " + dataType);
sendQueue.remove(batch);
// i2pReceiver.removePacketListener(packetListener);
ConcurrentHashSet<DhtStorablePacket> storablePackets = getStorablePackets(batch);
DhtStorablePacket localResult = findLocally(key, dataType);
if (localResult != null) {
log.debug("Locally stored packet found for hash " + key + " and data type " + dataType);
storablePackets.add(localResult);
}
return storablePackets;
}
private DhtStorablePacket findLocally(Hash key, Class<? extends DhtStorablePacket> dataType) {
DhtStorageHandler storageHandler = storageHandlers.get(dataType);
if (storageHandler != null)
return storageHandler.retrieve(key);
else
return null;
}
/**
* Returns all <code>DhtStorablePacket</code> packets that have been received as a response to a send batch.
* @param batch
* @return
*/
private ConcurrentHashSet<DhtStorablePacket> getStorablePackets(PacketBatch batch) {
ConcurrentHashSet<DhtStorablePacket> storablePackets = new ConcurrentHashSet<DhtStorablePacket>();
for (I2PBotePacket packet: batch.getResponses())
if (packet instanceof DhtStorablePacket)
storablePackets.add((DhtStorablePacket)packet);
return storablePackets;
}
@Override
public void store(DhtStorablePacket packet) throws NoSuchAlgorithmException {
Hash key = packet.getDhtKey();
Collection<Destination> closeNodes = getClosestNodes(key);
log.debug("Storing a " + packet.getClass().getSimpleName() + " with key " + key + " on " + closeNodes.size() + " nodes");
HashCash hashCash = HashCash.mintCash("", 1); // TODO
StoreRequest storeRequest = new StoreRequest(hashCash, packet);
PacketBatch batch = new PacketBatch();
for (Destination node: closeNodes)
batch.putPacket(storeRequest, node);
sendQueue.send(batch);
try {
batch.awaitSendCompletion();
// TODO awaitAllResponses, repeat if necessary
}
catch (InterruptedException e) {
log.warn("Interrupted while waiting for responses to Storage Requests to be sent.", e);
}
sendQueue.remove(batch);
}
@Override
public void start() {
i2pReceiver.addPacketListener(this);
bucketManager.start();
bootstrap();
}
@Override
public void shutDown() {
i2pReceiver.removePacketListener(this);
bucketManager.requestShutdown();
writePeersToFile(peerFile);
}
private void bootstrap() {
new BootstrapTask().start();
}
private class BootstrapTask extends Thread {
public BootstrapTask() {
setDaemon(true);
}
@Override
public void run() {
log.debug("Bootstrap start");
while (true) {
for (KademliaPeer bootstrapNode: initialPeers) {
bootstrapNode.setLastReception(-1);
bucketManager.addOrUpdate(bootstrapNode);
Collection<Destination> closestNodes = getClosestNodes(localDestinationHash);
// if last reception time is not set, the node didn't respond, so remove it
if (bootstrapNode.getLastReception() <= 0)
bucketManager.remove(bootstrapNode);
if (closestNodes.isEmpty()) {
log.debug("No response from bootstrap node " + bootstrapNode);
bucketManager.remove(bootstrapNode);
}
else {
bucketManager.refreshAll();
log.info("Bootstrapping finished. Number of peers = " + bucketManager.getPeerCount());
return;
}
}
log.warn("Can't bootstrap off any known peer, will retry shortly.");
try {
TimeUnit.MINUTES.sleep(1);
} catch (InterruptedException e) {
log.error("Interrupted while pausing after unsuccessful bootstrap attempt.", e);
}
}
}
}
/**
* Writes all peers to a file in descending order of "last seen" time.
* @param peerFile
*/
private void writePeersToFile(File peerFile) {
// TODO
}
private void readPeers(URL url) {
log.info("Reading peers from URL: '" + url + "'");
InputStream stream = null;
try {
stream = url.openStream();
readPeers(stream);
}
catch (IOException e) {
log.error("Error reading peers from URL.", e);
} finally {
if (stream != null)
try {
stream.close();
} catch (IOException e) {
log.error("Can't close input stream.", e);
}
}
}
private void readPeers(File peerFile) {
log.info("Reading peers from file: '" + peerFile.getAbsolutePath() + "'");
InputStream stream = null;
try {
stream = new FileInputStream(peerFile);
readPeers(stream);
} catch (IOException e) {
log.error("Error reading peers from file.", e);
} finally {
if (stream != null)
try {
stream.close();
} catch (IOException e) {
log.error("Can't close input stream.", e);
}
}
}
/**
* Reads peer destinations from an <code>InputStream</code> and writes them to <code>initialPeers</code>.
* @param inputStream
*/
private void readPeers(InputStream inputStream) throws IOException {
BufferedReader inputBuffer = new BufferedReader(new InputStreamReader(inputStream));
int numPeersBefore = initialPeers.size();
while (true) {
String line = null;
line = inputBuffer.readLine();
if (line == null)
break;
if (!line.startsWith("#"))
try {
Destination destination = new Destination(line);
KademliaPeer peer = new KademliaPeer(destination, 0);
// don't add the local destination as a peer
if (!peer.getDestinationHash().equals(localDestinationHash))
initialPeers.add(peer);
}
catch (DataFormatException e) {
log.error("Invalid destination key in line " + line, e);
}
}
log.debug(initialPeers.size()-numPeersBefore + " peers read.");
}
private void sendPeerList(FindClosePeersPacket packet, Destination destination) {
// TODO don't include the requesting peer
Collection<KademliaPeer> closestPeers = bucketManager.getClosestPeers(packet.getKey(), KademliaConstants.K);
PeerList peerList = new PeerList(closestPeers);
sendQueue.sendResponse(peerList, destination, packet.getPacketId());
}
// PacketListener implementation
@Override
public void packetReceived(CommunicationPacket packet, Destination sender, long receiveTime) {
if (packet instanceof FindClosePeersPacket)
sendPeerList((FindClosePeersPacket)packet, sender);
else if (packet instanceof StoreRequest) {
DhtStorablePacket packetToStore = ((StoreRequest)packet).getPacketToStore();
if (packetToStore != null) {
DhtStorageHandler storageHandler = storageHandlers.get(packetToStore.getClass());
if (storageHandler != null)
storageHandler.store(packetToStore);
else
log.warn("No storage handler found for type " + packetToStore.getClass().getSimpleName() + ".");
}
}
else if (packet instanceof RetrieveRequest) {
RetrieveRequest retrieveRequest = (RetrieveRequest)packet;
DhtStorageHandler storageHandler = storageHandlers.get(retrieveRequest.getDataType());
if (storageHandler != null) {
DhtStorablePacket storedPacket = storageHandler.retrieve(retrieveRequest.getKey());
// if requested packet found, send it to the requester
if (storedPacket != null) {
log.debug("Packet found for retrieve request: [" + retrieveRequest + "], replying to sender: [" + sender + "]");
ResponsePacket response = new ResponsePacket(storedPacket, StatusCode.OK, retrieveRequest.getPacketId());
sendQueue.send(response, sender);
}
else
log.debug("No matching packet found for retrieve request: [" + retrieveRequest + "]");
}
else
log.warn("No storage handler found for type " + packet.getClass().getSimpleName() + ".");
}
// bucketManager is not registered as a PacketListener, so notify it here
bucketManager.packetReceived(packet, sender, receiveTime);
}
}

Some files were not shown because too many files have changed in this diff Show More