Compare commits

...

826 Commits

Author SHA1 Message Date
str4d
d3cb0ab3f6 0.4.1
Checked in late, forgot to do so after actual release
2015-09-28 12:16:31 +00:00
str4d
e5fa4706db Fix loading of user guide and FAQ translations (#1641) 2015-09-12 15:40:16 +00:00
str4d
ecdd2ee426 Added new user guide translation 2015-09-12 14:30:22 +00:00
str4d
784a716f0a Updated translations 2015-09-12 14:29:53 +00:00
str4d
afdde691b4 CME fix 2015-09-02 01:33:49 +00:00
str4d
65d9439e03 Add owner to new ticket URL 2015-08-23 05:59:08 +00:00
str4d
8d19c4c78a Fixed CME 2015-08-21 02:22:35 +00:00
str4d
8731a72887 0.4 2015-08-21 02:20:25 +00:00
str4d
9e1b42134c Remove build numbers from version 2015-08-21 02:20:02 +00:00
str4d
17b4d035eb Update last checked time for manual checks too 2015-08-20 23:58:49 +00:00
str4d
d967d50c51 Fix email checking 2015-08-20 23:50:17 +00:00
str4d
42770cf01b Updated ignores 2015-08-20 11:53:10 +00:00
str4d
c910e17f6c Fix bug with sending anon emails 2015-08-20 11:52:09 +00:00
str4d
d408242173 Test OutboxProcessor.sendEmail(), proves existence of bug with anon emails 2015-08-20 11:26:34 +00:00
str4d
c52429f393 Add Mockito to unittest deps 2015-08-20 11:24:58 +00:00
str4d
aac9df446f 0.3 2015-08-15 23:33:58 +00:00
str4d
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
str4d
e661e4306c Updated ignores 2015-08-15 02:09:45 +00:00
str4d
18005cdfb3 Updated translations 2015-08-15 02:01:58 +00:00
str4d
1a7e8daf8e Fix app icon so it is bundled 2015-08-15 01:58:23 +00:00
str4d
771153c4d7 Add app icon 2015-08-15 01:55:14 +00:00
str4d
f1e750cef1 Change author to me (for feedback) 2015-08-15 01:54:54 +00:00
str4d
52e30278b5 Bump min I2P version to 0.9.18 (first to include my SU3 plugin cert) 2015-08-15 01:44:51 +00:00
str4d
4f1b81510f Add SU3 update URL 2015-08-15 01:32:26 +00:00
str4d
0c4d1dc5c3 Changed plugin signer and update URL 2015-08-15 01:28:38 +00:00
str4d
c1934b4576 Added missing image 2015-08-15 01:27:32 +00:00
str4d
0edd014c6b Deduplicate dependency verification 2015-08-15 01:26:47 +00:00
str4d
27e02ce527 Fix connection checking 2015-08-14 01:30:55 +00:00
str4d
9aa14a705e Only show "Check email" button for identities when connected 2015-08-14 00:56:50 +00:00
str4d
219de6e499 Adjust identities column widths on old themes 2015-08-14 00:56:19 +00:00
str4d
d07f790dbb Fix NPE in identity creation by properly saving identity config 2015-08-13 23:35:00 +00:00
str4d
8abfc8345b Deduplication 2015-08-13 12:39:37 +00:00
str4d
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
str4d
63b63a9f65 Bugfix 2015-08-13 11:29:42 +00:00
str4d
29f5db767d Extract common packing macro, delete .jar files from plugin (JIC) 2015-08-13 11:19:09 +00:00
str4d
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
str4d
37b64f25c0 Fix hash verification 2015-08-12 12:10:49 +00:00
str4d
5f7bb2d7d1 Verify hashes of remote dependencies 2015-08-08 14:09:58 +00:00
str4d
69fc637bd7 Refactor remote dependency checking 2015-08-08 13:50:43 +00:00
str4d
cb0b0822a3 Upgrade to JavaMail 1.5.4, make it a remote dependency 2015-08-08 13:47:57 +00:00
str4d
f83f7cd085 Updated translations 2015-08-05 13:01:19 +00:00
str4d
bab92e082f Upgrade BouncyCastle to 1.52 2015-08-05 12:56:10 +00:00
str4d
d1e7eeb7bc Updated translation strings 2015-08-05 01:52:23 +00:00
str4d
a5409b0e43 Added new translations 2015-08-05 01:43:08 +00:00
str4d
742c697150 Updated translations 2015-08-05 01:42:37 +00:00
str4d
42c6269cda Improve recipient handling in email composition 2015-08-05 01:38:21 +00:00
str4d
03012e5323 Get IMAP STARTTLS working 2015-08-04 16:23:58 +00:00
str4d
97825a3d60 Upgrade to 20150627 snapshot of Apache James 2015-08-04 16:18:29 +00:00
str4d
dc5d066775 Get tests to pass 2015-08-03 13:21:57 +00:00
str4d
c2bc331b55 Add Email Date header tests 2015-08-03 13:19:17 +00:00
str4d
8f29c7d6fb Force loading of BouncyCastly so tests pass 2015-08-03 13:18:49 +00:00
str4d
6b530a364b Add direct link to creating tickets for I2P-Bote 2015-07-31 04:01:41 +00:00
str4d
3f60643c2e Updated history 2015-07-23 09:34:49 +00:00
str4d
3539b5a13b Don't move metadata file if we couldn't move email file (#1196) 2015-07-23 02:37:25 +00:00
str4d
e37f70506d Don't assume that email metadata file exists (#1196) 2015-07-23 02:27:09 +00:00
str4d
4196486799 Fix NPE (#937) 2015-07-22 21:16:18 +00:00
str4d
6dbecc0f6e Unused import 2015-07-22 12:30:51 +00:00
str4d
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
str4d
6e528dae6a Fix CME caused by no synchronization on kBuckets (#1586) 2015-07-21 10:09:32 +00:00
str4d
90f9de4861 Updated guide translations 2015-07-21 09:01:58 +00:00
str4d
f7b3499e93 Updated translations 2015-07-21 08:47:31 +00:00
str4d
5901565d74 Listen to identity updates too 2015-06-05 10:08:39 +00:00
str4d
f98990ad65 Added IdentitiesListener 2015-06-05 09:37:10 +00:00
str4d
d290665a17 New user guide translation for es 2015-03-20 09:31:16 +00:00
str4d
e2e2233b89 User guide fixes (thx strel!) 2015-03-20 09:25:31 +00:00
str4d
29190552d9 Updated translations 2015-03-20 09:24:29 +00:00
str4d
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
str4d
a34da62789 Overhauled StrongTls with 2015-era protocols and ciphers 2015-03-19 00:51:35 +00:00
str4d
8ff2c84cd4 Discovered that one of the old bootstrapping nodes is kytv, now resurrected 2015-03-16 10:12:19 +00:00
str4d
96140a49c5 New bootstrap peers (thanks str4d and The_Tin_Hat!) 2015-03-16 06:06:18 +00:00
str4d
b3f9ea8a0b Updated TODO 2015-03-12 21:45:10 +00:00
str4d
034660d4af Updated translations 2015-03-10 11:28:10 +00:00
str4d
bbda61316e Formatting changes by Transifex, and some string fixes 2015-03-10 11:22:45 +00:00
str4d
297a26cc63 Added user guide and FAQ to Transifex config 2015-03-10 11:22:26 +00:00
str4d
c9686adaef More formatting fixes for Transifex 2015-03-10 10:57:59 +00:00
str4d
82d31e4813 Formatting fixes for Transifex 2015-03-10 10:49:55 +00:00
str4d
63c17045b6 Multi-line Spanish translation 2015-03-10 10:40:06 +00:00
str4d
0566e42f21 New translation of FAQ into Spanish (thanks trolly!) 2015-03-10 04:16:22 +00:00
str4d
a21f67d429 Fixes 2015-02-15 10:52:36 +00:00
str4d
d7ae6d51e5 FAQ navigation 2015-02-15 10:23:13 +00:00
str4d
271eb004b2 Android themed wait.gif 2015-02-15 09:21:46 +00:00
str4d
c65e3f8f7e UI option for global identity check 2015-02-15 09:21:30 +00:00
str4d
dd7f4055a1 Prevent potential NPE 2015-02-15 09:20:52 +00:00
str4d
9b0836249d Bugfix 2015-02-15 07:13:17 +00:00
str4d
0585f211fb Implement checking individual identities 2015-02-15 03:25:40 +00:00
str4d
4df989d63a Don't disable default selection for new identities when only one exists 2015-02-14 22:33:59 +00:00
str4d
a76789cf30 Button layout fix 2015-02-14 22:33:34 +00:00
str4d
ae55336e06 Updated translations 2015-02-14 22:32:50 +00:00
str4d
437c5ddbac Backend implementation of per-identity relay settings, global check exclusion 2015-02-14 21:51:01 +00:00
str4d
63a574f578 Show which nav item is currently selected 2015-02-13 02:21:53 +00:00
str4d
42c3e0d369 Match nav drawer list item highlight to Material design spec 2015-02-13 02:01:13 +00:00
str4d
5d89032b90 Corrections from Material design spec 2015-02-13 01:55:57 +00:00
str4d
fc738142fa Moved getBooleanParameter() and getIntParameter() to Util 2015-02-07 19:51:39 +00:00
str4d
4e9b0e93cb Extract String constants 2015-02-06 10:00:05 +00:00
str4d
8912cfcf7d Include HTML files in WAR 2015-02-05 10:33:06 +00:00
str4d
73e22a3d34 Reference ticket numbers in TODO 2015-02-05 09:36:42 +00:00
str4d
dfa1dfbd74 Settings headings 2015-02-04 11:21:27 +00:00
str4d
eff95792ac Updated translations 2015-02-04 11:00:52 +00:00
str4d
bf53778367 String fix 2015-02-04 11:00:29 +00:00
str4d
74bde7aac6 HTML5 cleanups 2015-02-04 01:14:44 +00:00
str4d
848ec8cb14 Added not-yet-implemented features to TODO 2015-02-04 00:56:29 +00:00
str4d
a72bd3fb04 FAQ formatting 2015-02-03 14:22:22 +00:00
str4d
87ce7646f6 FAQ pagetitle 2015-02-03 14:19:29 +00:00
str4d
e2c003503a Reformatted FAQ 2015-02-03 14:16:46 +00:00
str4d
4f9d717725 List tweaks 2015-02-03 12:58:16 +00:00
str4d
f638d8e43a Limit user guide navigation width 2015-02-03 12:30:11 +00:00
str4d
2377acf15c Reorganized user guide sections 2015-02-03 12:29:19 +00:00
str4d
f11af022b2 User guide navigation 2015-02-03 12:25:31 +00:00
str4d
9ef5a15650 Removed unnecessary installation details, renumbered headings 2015-02-03 11:59:50 +00:00
str4d
02bb52dc67 Title fixes 2015-02-03 11:51:41 +00:00
str4d
bd9a0bd6b4 Consolidated credits 2015-02-03 11:32:04 +00:00
str4d
fe7516c24f Reworked user guide intro 2015-02-03 08:43:54 +00:00
str4d
97c567a105 User guide fixes 2015-02-03 04:55:16 +00:00
str4d
62308d053d Translation string fixes 2015-02-03 04:55:02 +00:00
str4d
f4ebc330a1 Translation fixes 2015-02-03 04:54:42 +00:00
str4d
93cabe4f44 Updated translation strings 2015-02-03 04:28:37 +00:00
str4d
5222861962 Proper theme names 2015-02-03 04:15:55 +00:00
str4d
9c09c739d2 Fixed bundle-messages.sh 2015-02-03 04:15:46 +00:00
str4d
8b3770f33d New translations 2015-02-03 03:52:46 +00:00
str4d
cd5d8b0ac2 Updated translations 2015-02-03 03:52:32 +00:00
str4d
596aa39d5d Updated Transifex config 2015-02-03 03:52:25 +00:00
str4d
212ca673b0 Updated TODO 2015-02-03 03:41:01 +00:00
str4d
9833590266 Move HTML files to subdir in preparation for Transifex 2015-02-03 03:40:50 +00:00
str4d
77242920bd Updated French translation of user guide 2015-02-03 03:33:22 +00:00
str4d
19a8c09a8d User guide tweaks 2015-02-03 03:33:00 +00:00
str4d
2634398ea4 Renamed user guide HTML 2015-02-02 22:41:19 +00:00
str4d
2fac3e9eae Tidied up user guide HTML 2015-02-02 22:40:04 +00:00
str4d
182bafb524 Enable HTML files to be themed 2015-02-02 22:32:52 +00:00
str4d
d7c673e4be Charts on network status page 2015-02-02 03:17:28 +00:00
str4d
33273675da Mark new relay peers instead of showing 0% reachability 2015-02-01 04:43:45 +00:00
str4d
7b405764fb NPE fix (ticket #1367) 2015-01-30 06:03:01 +00:00
str4d
750305fef1 Attachments icon 2015-01-30 05:38:57 +00:00
str4d
269f0d07e9 Improved info and error message displaying 2015-01-29 05:03:26 +00:00
str4d
7aae76ef4b Fixes after XSSFilter 2015-01-29 04:39:03 +00:00
str4d
302414a53d Enable different page title from browser title, more sidenav icons 2015-01-29 04:38:21 +00:00
str4d
22732d33c1 Missing bcprov changes 2015-01-28 23:54:55 +00:00
str4d
b113dd3e51 Font changes 2015-01-28 08:04:53 +00:00
str4d
ca0ac05614 Import identities 2015-01-28 06:47:47 +00:00
str4d
54ac8425b5 Export identities 2015-01-28 04:33:03 +00:00
str4d
67e36d834e Escape XML 2015-01-28 04:25:51 +00:00
str4d
48c2294517 HTML5 <time> 2015-01-27 02:48:12 +00:00
str4d
e3e694d0c9 Enable XSSFilter on all inputs except passwords 2015-01-27 01:43:12 +00:00
str4d
06fc60af43 Material tweak for new emails 2015-01-27 01:41:33 +00:00
str4d
9cd8bddf8a Bugfix 2015-01-27 01:30:29 +00:00
str4d
6c4ab4b1b3 NPE fix when attempting to change identity name to blank 2015-01-27 01:14:33 +00:00
str4d
3155308054 New theme based on the Material design of the Bote Android app 2015-01-26 10:32:42 +00:00
str4d
538a5b2e06 Change addressbook.gif to addressbook.png 2015-01-26 10:02:05 +00:00
str4d
dd126df6c7 Inputs to buttons 2015-01-26 07:41:43 +00:00
str4d
a1edb3173c Remove onclick from header, the inbox is easily accessed from the side nav 2015-01-26 04:56:34 +00:00
str4d
edc51acedb An article around email content 2015-01-26 04:24:07 +00:00
str4d
0394b591a7 Extra page title for use in new theme 2015-01-26 03:45:03 +00:00
str4d
9a5a161342 CSS tweak 2015-01-25 10:19:05 +00:00
str4d
ec3acae530 Replaced linebreak with margin 2015-01-25 09:32:05 +00:00
str4d
7fea66978b Remove "Public Address Directory" from side nav until it has a link 2015-01-25 09:21:16 +00:00
str4d
b7abb03b32 HTML5, preparations for new theme 2015-01-25 09:18:40 +00:00
str4d
958a072d9b HTML5 doctype and charset 2015-01-24 12:31:42 +00:00
str4d
e7042dc5a7 Detect file MIME types 2015-01-12 07:55:51 +00:00
str4d
bc6df473be Ask for plugin SU3 keystore password 2015-01-12 07:34:17 +00:00
str4d
04ac90d478 Prevent NPE on Android if the state gets weird (it has happened) 2015-01-11 12:25:45 +00:00
str4d
7e8421c63b Added ignores 2015-01-11 05:51:22 +00:00
str4d
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
str4d
1f1b328f70 Close InputStream in Util.getPartSize() 2015-01-04 05:00:08 +00:00
str4d
823491ae4d Pull out Util method for getting size of a Part 2014-12-28 11:42:23 +00:00
str4d
6856773636 Correct the Attachment interface 2014-12-28 11:42:02 +00:00
str4d
2cc3df7c1f Generalize attachments 2014-12-28 04:52:27 +00:00
str4d
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
str4d
4f357db8ec Use I2PSocketManagerFactory.createDisconnectedManager() for better connectError 2014-12-17 23:54:31 +00:00
str4d
877b02cc04 Layout fix 2014-12-13 10:56:30 +00:00
str4d
8b5b7507c6 Helpers to get the name for an EmailDestination 2014-11-18 04:00:00 +00:00
str4d
5ff770bc31 Use assertArrayEquals 2014-11-17 22:39:04 +00:00
str4d
4107467c64 Mockery thread synchronization 2014-11-17 22:23:20 +00:00
str4d
05def741fb Fix BCC header removal bug 2014-11-17 21:41:57 +00:00
str4d
82ac0d59d8 Unused imports 2014-11-17 21:25:00 +00:00
str4d
10445e1082 junit.framework -> org.junit 2014-11-17 21:15:00 +00:00
str4d
a968f5c6f4 Updated history 2014-09-25 05:54:49 +00:00
str4d
d6564680a5 Update to techdoc by HungryHobo 2014-09-25 05:54:31 +00:00
str4d
ec41d7d82e Switch to Maven directory structure without losing history 2014-09-25 05:50:39 +00:00
str4d
8a29b9dd0d Mark locations of code incompatible with newer I2P Destinations 2014-09-21 05:32:43 +00:00
str4d
6c53344f51 A zero-length password is an uncached password
This brings PasswordCache in line with FileEncryptionUtil.
2014-09-21 05:31:08 +00:00
str4d
2768297be9 Add and remove interface for password listeners 2014-09-18 06:11:01 +00:00
str4d
740197e439 Added TODO 2014-08-26 11:55:12 +00:00
str4d
6e4c52b746 Remove spaces and newlines 2014-08-07 11:56:43 +00:00
str4d
cc59ed9adb Remove possible prefixes 2014-08-07 11:46:58 +00:00
HungryHobo
3c0a431f09 Remove UpdateChecker
Plugins have been auto-updated by the router for a while now
2014-08-03 10:47:11 +00:00
HungryHobo
392ba71037 Another Tomcat 7 fix, see rev. 5e9c9148 2014-08-03 10:42:32 +00:00
HungryHobo
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
HungryHobo
e030e9ed5f 0.2.10 2014-07-23 21:36:12 +00:00
HungryHobo
1896fccf1f Fix NullPointerExceptions 2014-07-23 21:25:31 +00:00
HungryHobo
ca19e9d9e0 Use a separate SessionKeyManager instead of the router's 2014-07-23 21:24:39 +00:00
HungryHobo
729a4ac99f Upgrade to 20140722 snapshot of Apache James 2014-07-23 21:22:15 +00:00
str4d
729f59e729 Support I2CP connections over Unix domain sockets
Only supported on Android for now.
2014-07-16 04:05:35 +00:00
str4d
78b66b5509 Bugfix after net.i2p.data.Base64.decode() errors were cleaned up 2014-07-07 00:28:22 +00:00
str4d
5cdcae1416 Missing network status change 2014-07-06 14:26:47 +00:00
str4d
348262e7a2 NetworkStatusListener implementation 2014-07-06 13:05:39 +00:00
str4d
adb290658a Inform caller if importer found no identities 2014-07-06 02:55:44 +00:00
str4d
c04fc24445 Implement encrypted identities export 2014-07-06 02:28:40 +00:00
str4d
4762f8486e Implement identity appending on import 2014-07-05 23:50:02 +00:00
str4d
52a717d7e3 Import identities from FileDescriptor (no appending possible yet) 2014-07-05 04:23:19 +00:00
str4d
e9ffb4643b Export identities to file (no encryption possible yet) 2014-07-04 06:21:17 +00:00
str4d
382f75f4a4 Pulled out Identities <-> Properties conversion into separate methods 2014-07-04 00:23:14 +00:00
str4d
4a6fc262e7 Show number of incomplete emails 2014-07-02 09:23:58 +00:00
str4d
4cd24cd579 Expose number of incomplete emails 2014-07-02 06:38:02 +00:00
str4d
32ce92d7cb Updated license.txt 2014-06-23 01:47:07 +00:00
str4d
96bb3a0719 Enable saving picture for EmailIdentity 2014-06-16 05:41:11 +00:00
str4d
5cebc0b2ee Added EmailIdentity.setPictureBase64() 2014-06-16 04:57:32 +00:00
HungryHobo
4e7d57d8e3 Implement vanity destinations 2014-06-11 21:11:11 +00:00
str4d
0ad03ce6d4 Fix for new Jetty/Tomcat 2014-06-11 06:13:13 +00:00
str4d
2082fd0856 Emails are not kept in-memory inside EmailFolder, so store \Recent in metadata 2014-06-10 12:17:35 +00:00
str4d
98c56de3a5 Added specific listener for newly-received emails 2014-06-09 04:51:20 +00:00
str4d
1801e308b2 Fixed bug in setFlags() 2014-06-08 06:46:56 +00:00
str4d
f318587209 Helper method 2014-06-08 04:59:13 +00:00
str4d
38d5833551 Improved FolderListener, emails added to a folder outside IMAP now get \Recent 2014-06-08 04:12:30 +00:00
str4d
6bbd015d38 Store other IMAP flags in-memory (like \Recent) 2014-06-08 02:59:39 +00:00
HungryHobo
f20ae940a8 Add missing file 2014-06-03 06:01:55 +00:00
HungryHobo
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
HungryHobo
a47100d14a Fix NullPointerException on fresh installs 2014-05-29 22:21:09 +00:00
HungryHobo
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
str4d
ca19b0929e NPE fix for corrupt folder 2014-05-24 00:00:34 +00:00
str4d
3dede23a24 Reworked email status storage for UI flexibility 2014-05-23 01:18:18 +00:00
str4d
e190587330 Reverted bad log tweak 2014-05-17 04:37:23 +00:00
str4d
0d92ddb6e1 Set connectTask to null so getNetworkStatus() returns valid state 2014-05-17 04:36:42 +00:00
str4d
52f6405c74 Removed unused import 2014-05-17 04:33:28 +00:00
str4d
99fb8bf264 NPE fixes, log tweak 2014-05-17 04:27:59 +00:00
str4d
fa22d47252 Whitespace, don't create SSL key store on Android 2014-05-17 04:21:06 +00:00
str4d
2dfa656b06 JSSE requires keystore and key passwords to be identical 2014-05-13 05:07:05 +00:00
str4d
56aa3f3c1c Generate the SSL cert on-the-fly to prevent MITM 2014-05-13 02:23:09 +00:00
str4d
c2e75290fb Reverted mistaken checkin 2014-05-13 02:20:19 +00:00
str4d
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
str4d
c3088c5931 Mark important comments 2014-05-12 13:23:28 +00:00
str4d
a149a0bdc0 Fixed NPE (ticket #1272) 2014-05-12 12:37:47 +00:00
str4d
7867198fe9 Override updateMessageID() on Android to prevent NetworkOnMainThreadException 2014-04-17 23:27:40 +00:00
str4d
38293ebcf9 Added elementUpdated() to FolderListener, made setNew() throws consistent 2014-04-16 13:07:17 +00:00
str4d
6f4a0615ff Update FolderListeners when Email is moved 2014-04-15 00:58:02 +00:00
str4d
22fa6105ac Updated FAQ and User's Guide 2014-04-14 02:30:00 +00:00
str4d
946fa8d6ec Insert addressbook/identity names, @bote, {UNK} into IMAP email headers 2014-04-14 02:29:37 +00:00
str4d
5a8d9c6f4f Remove @bote before validating sender and recipient addresses in SMTP 2014-04-13 05:05:41 +00:00
str4d
5c53c2071b Updated about.jsp 2014-04-13 02:45:57 +00:00
str4d
c84770036d Create BoteMailboxes once, and remove their FolderListeners when IMAP stops 2014-04-13 02:27:31 +00:00
str4d
d9756407b0 Refactor to handle recipient headers containing multiple recipients 2014-04-13 01:46:13 +00:00
str4d
fe9c6d9d47 Pack new mailapi.jar in update for 0.2.10 2014-04-11 22:42:07 +00:00
str4d
ee96addef6 Removed signature from scrypt jar (pack200 interferes) 2014-04-10 21:51:49 +00:00
str4d
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
kytv
bbd24eaaff fix another missing '/' 2014-04-07 12:20:12 +00:00
kytv
4db680f067 add missing / to paths 2014-04-07 12:14:44 +00:00
str4d
79595913f2 Previous fix wasn't quite right 2014-04-04 20:01:29 +00:00
str4d
b387b77bfb Fixed concurrency problem 2014-03-30 03:10:04 +00:00
str4d
dce43d11ae Fixed IMAP UID implementation to conform to RFC 3501 2014-03-30 02:14:56 +00:00
str4d
8fec6b28e8 Remove @bote properly from SMTP messages 2014-03-29 03:19:53 +00:00
str4d
17282cda4d Missing Bean method 2014-03-28 20:58:26 +00:00
str4d
1664253417 Fixed password "corruption" (ticket #1239) 2014-03-28 20:57:56 +00:00
str4d
654b136cb0 Somehow, file duplication has stopped 2014-03-18 20:04:50 +00:00
str4d
2b5de7958e Doc tweak 2014-03-18 10:56:28 +00:00
str4d
10b9b2e593 Updated identity file spec 2014-03-18 10:22:47 +00:00
str4d
3571adf2ec Another StatusListener 2014-03-09 23:05:22 +00:00
str4d
44027e80ca Save and load default key properly 2014-03-09 09:11:00 +00:00
str4d
9d821f66b9 Update default identity when changed (for writing to file) 2014-03-08 23:07:54 +00:00
str4d
bef847d270 Moved Servlet-dependent helper methods back to JSPHelper 2014-03-04 01:46:56 +00:00
str4d
967a523130 Missing javadoc @param 2014-03-04 01:36:11 +00:00
str4d
c35e9c9139 Enable listening to status of internal operations (for Android UI) 2014-03-02 10:32:23 +00:00
str4d
c0b62e25c1 Remove throw (handled in rev 78f6a5bcf158019aceb75a48aebd8d9c20b203ce) 2014-03-01 01:55:15 +00:00
str4d
936e1e7d50 Updated techdoc.txt for mailapi.jar 2014-02-28 22:08:34 +00:00
str4d
592793eaac Add a setting to enable/disable SMTP 2014-02-28 22:02:49 +00:00
str4d
f1c9ac9788 Updated to mailapi 1.5.1 2014-02-27 05:19:54 +00:00
str4d
bdd24d7e9d Apparently Jasper can't follow inheritance 2014-02-27 04:40:15 +00:00
str4d
de36d91909 Delete i2pbote.jar in clean 2014-02-27 03:28:18 +00:00
str4d
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
str4d
adde9736be Split JSPHelper so common utilities can be used by other UIs (Android) 2014-02-26 23:08:34 +00:00
str4d
173d08d798 Allow FolderListeners to be removed 2014-02-26 07:07:42 +00:00
str4d
acb1ace33a Don't add source files to i2pbote.jar (it duplicates .txt files) 2014-02-26 07:07:11 +00:00
str4d
ffa7450e77 Reordered list of folders 2014-02-26 03:28:18 +00:00
HungryHobo
d9d9c47124 Add README.md for GitHub 2014-02-16 18:18:45 +00:00
HungryHobo
d960308461 Update techdoc.txt 2014-02-16 13:41:27 +00:00
HungryHobo
616df8de9f Update translations from Transifex 2014-02-16 13:40:34 +00:00
HungryHobo
427e293bac 0.2.9 2014-02-16 13:39:32 +00:00
str4d
163f8d58c0 Make send button easier to find 2014-01-08 01:44:02 +00:00
str4d
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
str4d
c2d1334c04 Unset flags correctly 2014-01-01 05:57:41 +00:00
str4d
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
str4d
2a744fb1cd RFC 2822: set From: header 2013-12-31 16:43:55 +00:00
str4d
ed60728edd Don't delete libs with "ant clean" 2013-12-31 07:29:26 +00:00
str4d
48e69d3cd5 Don't break folder list if an email can't be decrypted 2013-12-27 02:33:26 +00:00
str4d
df09332ead Added libs to .jar manifest (so IMAP setting works) 2013-12-26 09:54:01 +00:00
str4d
585413fa2b Fixed potential NPE 2013-12-25 23:30:02 +00:00
HungryHobo
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
HungryHobo
ae87a801ea Fix classpath and typos 2013-05-01 17:52:44 +00:00
HungryHobo
901b051546 Implement SMTP 2013-05-01 17:50:42 +00:00
HungryHobo
6590e3122a Shorten known email destinations in the folder view 2013-04-29 19:18:02 +00:00
HungryHobo
e601b5f46e Add a setting to enable/disable IMAP 2013-04-29 18:53:41 +00:00
HungryHobo
641085ab24 don't try to zip up non-existent images directory (see rev. 1ae37d314f064cfb6c870727775f5b5ccc5ea69e) 2013-04-29 18:34:15 +00:00
HungryHobo
5d371f983a IMAP interface, works with Thunderbird but not Evolution 2013-04-29 00:21:37 +00:00
HungryHobo
8fc111fc86 Fix Content-Transfer-Encoding (8bit doesn't allow zeros, CR, or LF) 2013-04-26 23:15:13 +00:00
HungryHobo
2dc809c025 Close streams when done reading 2013-04-26 23:06:15 +00:00
kytv
7b0149dc39 by request, adding my i2pbote node's public destination 2013-04-11 16:00:55 +00:00
HungryHobo
24509df2b5 Delete commented out line 2013-04-02 21:47:28 +00:00
HungryHobo
263b68550e Fix a compiler warning 2013-04-02 21:42:34 +00:00
HungryHobo
ae3ac8b5be Attach file on selection when JS is enabled 2013-04-02 21:33:36 +00:00
kytv
7c22899f32 try supressing/fixing a few warnings 2013-04-01 21:01:18 +00:00
kytv
3970d6d015 build fix (don't try to zip up non-existent images directory) 2013-04-01 20:40:12 +00:00
HungryHobo
4464301119 Remove unused images 2013-04-01 18:08:37 +00:00
HungryHobo
f0622d202b Move style attributes to CSS 2013-04-01 17:57:59 +00:00
HungryHobo
63e260f932 Show anonymous sender in italics 2013-03-31 22:36:24 +00:00
HungryHobo
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
HungryHobo
cc7e0209ec Simplification 2013-03-30 23:01:32 +00:00
HungryHobo
1a4c25a32f Add a null check 2013-03-30 22:58:14 +00:00
HungryHobo
79339a0208 Fix a comment 2013-03-30 22:57:26 +00:00
HungryHobo
249389a4d3 Replace ReentrantLock with synchronized 2013-03-30 08:55:16 +00:00
HungryHobo
92a5a998d6 Show a wait page when the password is changed 2013-03-29 17:09:10 +00:00
HungryHobo
e1a49cf440 Add a JSP that allows users to check encrypted files 2013-03-24 12:32:31 +00:00
HungryHobo
e30cb79c5f 0.2.8 2013-03-08 21:51:26 +00:00
HungryHobo
49268b21ea Increase #words to 8 and #zero bits to 10 2013-03-07 21:38:57 +00:00
HungryHobo
74384e0517 Fix: unneccessary lookup when confirm=true 2013-03-07 21:25:44 +00:00
HungryHobo
9bfde0ac33 Fix formatting on editIdentity.jsp 2013-03-07 21:22:36 +00:00
HungryHobo
55d5ea6084 Fix NullPointerException when no word list is available for the current language 2013-03-05 23:01:49 +00:00
HungryHobo
0e36c3dcc3 Fix: Escape characters handled incorrectly when saving and loading 2013-03-05 22:40:08 +00:00
HungryHobo
0155e5f57f Implement mark() and reset() 2013-03-05 22:14:02 +00:00
HungryHobo
a2b3833602 Store fingerprint with email identity and show it on editIdentity.jsp 2013-03-05 19:29:43 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
66020b2fc7 Add 0.2.7 release notes 2013-02-14 15:35:32 +00:00
HungryHobo
34e76ce627 Add a missing test 2013-02-12 13:30:15 +00:00
HungryHobo
79393f0ea8 Fix ContactTest when run from Ant 2013-02-12 13:29:41 +00:00
HungryHobo
c4cdbb98cc trim() name before publishing or doing a lookup 2013-02-11 21:24:28 +00:00
HungryHobo
eda69d1e7e Fix @bote.i2p suffix 2013-02-11 21:23:00 +00:00
HungryHobo
1f2c528b9b Sign Contact packets:
* sign on publish
 * verify on import
 * ignore invalid Contact packets in lookups
2013-02-11 21:18:01 +00:00
HungryHobo
6a99b034b7 Implement fingerprints for directory entries 2013-02-11 12:03:15 +00:00
HungryHobo
17db81eee1 Use native scrypt if available 2013-02-04 22:13:33 +00:00
HungryHobo
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
HungryHobo
7cbf364407 Rename DirectoryEntryTest to ContactTest 2013-02-04 21:47:57 +00:00
HungryHobo
bd8674950e Add null check 2013-02-02 12:18:11 +00:00
HungryHobo
0a0418f83f Make sure test files and directories are cleaned up 2013-02-02 12:17:11 +00:00
HungryHobo
a5832cd1e4 Add comment 2013-02-02 12:15:29 +00:00
HungryHobo
ccbc2c3e01 Check for existing name before publishing 2013-02-02 12:09:26 +00:00
HungryHobo
d5c6c2d046 Ignore requests to replace existing Contacts 2013-02-02 00:04:12 +00:00
HungryHobo
d8a606946e Don't skip sleep() on exceptions; lower log level 2013-01-27 22:30:58 +00:00
HungryHobo
dbaa00d5b1 Print number of running threads 2013-01-27 22:30:17 +00:00
HungryHobo
844bfcb842 Implement basic address directory 2013-01-27 22:29:01 +00:00
HungryHobo
882a6d207a merge of '8d66ebeab68f6165dbd977cb2b5a5d52d09eab03'
and 'd27fa448d59dd46241e032896b0788e9057da5e1'
2013-01-27 21:59:38 +00:00
meeh
730aff2a50 Updated Norwegian Bokmål translation updates from transifex.
(100% translation)
2013-01-26 19:17:27 +00:00
HungryHobo
de6d2d60a9 Lower max packet size to 10 kBytes 2013-01-24 20:57:57 +00:00
HungryHobo
a724a521cd Add an option to change the ping interval 2013-01-24 20:39:49 +00:00
HungryHobo
eaaf3c90e4 Remove Util.get(Collection, int) and use toArray() instead 2013-01-24 20:37:39 +00:00
HungryHobo
a0febacdfd Fix: addresses and identities still available after password cache expires 2013-01-23 21:42:24 +00:00
HungryHobo
2f0cb066ab Fix forward URL when context path is something other than /i2pbote 2013-01-23 21:08:46 +00:00
HungryHobo
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
HungryHobo
e9c262c8b7 Add package.html files 2013-01-22 20:49:32 +00:00
HungryHobo
093e439e04 Fix JavaDoc warnings 2013-01-22 20:31:17 +00:00
HungryHobo
bf07f9c664 merge of '90e5bcb2bddcd45813c9eb3b354026f37152c66e'
and 'a6a21a22bbe0d4a61750abff96d5aaaa23b8df54'
2013-01-21 22:27:35 +00:00
HungryHobo
bba9ac405a Add a command line program for testing datagram reliability 2013-01-21 22:26:19 +00:00
kytv
a0457273b7 switch javadocs from bob.i2p to i2p-javadocs.i2p
(sponge no longer hosts them)
2013-01-21 01:56:14 +00:00
kytv
e6a330944d update oracle package-list URLs 2013-01-21 01:44:10 +00:00
HungryHobo
20940f209b Lower log level 2013-01-20 21:23:06 +00:00
HungryHobo
bbc71ad13c Some refactoring 2013-01-20 21:21:53 +00:00
HungryHobo
64917757a4 Make delivery checking turn-offable 2013-01-20 21:21:36 +00:00
HungryHobo
b966ebbcfd address.tag: replace hover with click-to-expand; share code with editIdentity.jsp 2013-01-20 19:49:23 +00:00
HungryHobo
ca7f4124c4 Update en and de strings 2013-01-20 16:13:42 +00:00
HungryHobo
b24fe46661 Fix ambiguous i18n source string "Sent" 2013-01-20 16:11:32 +00:00
kytv
1db3aee096 merge of '05f071f4da46716c5566db81c177ec3e3ec04852'
and 'de9594e3f85d2d2401af64407c0c54c4e6a61d33'
2013-01-20 03:02:17 +00:00
kytv
db5a566e15 Language nb is more precise than no. 2013-01-20 02:53:01 +00:00
HungryHobo
f485c68472 DeliveryChecker.java:
* Don't save metadata unless it changed
 * Logging
 * Code formatting
2013-01-20 02:28:41 +00:00
HungryHobo
78013d6725 Wait until connected to DHT 2013-01-20 02:20:51 +00:00
HungryHobo
261d05a1d6 Prevent "${param.path}" from showing up as a translation string 2013-01-20 02:15:17 +00:00
HungryHobo
4a79a28d28 Handle tags that have an attribute but the message key is in the body 2013-01-20 02:02:51 +00:00
HungryHobo
844a7a24fe Add help text to editIdentities.jsp 2013-01-20 01:28:23 +00:00
HungryHobo
9937ec73f9 Remove more mockup elements 2013-01-19 23:32:30 +00:00
HungryHobo
54629d8d05 Appearance changes to sendEmail.jsp 2013-01-19 23:28:19 +00:00
HungryHobo
15dcd78936 Show whether an email has been replied to 2013-01-19 23:21:00 +00:00
HungryHobo
087a4a68be Remove an extra '<' 2013-01-17 23:10:03 +00:00
HungryHobo
7829c44d0d Add a delete button after replying to an email 2013-01-17 22:57:15 +00:00
kytv
476d06a588 German, French, Italian, Polish, Portuguese, and Russian translation updates from transifex 2013-01-17 12:43:25 +00:00
HungryHobo
53223be28d Display an error if no public name entered 2013-01-16 22:27:27 +00:00
HungryHobo
691b8ade1c Bump version to 0.2.7; migrate metadata files 2013-01-16 22:14:08 +00:00
HungryHobo
7ac255ec94 Encrypt metadata files (as of rev 24af3e..., they contain email destinations and packet keys) 2013-01-16 22:05:35 +00:00
HungryHobo
cf84a6aeee Don't receive packets as streams 2013-01-15 21:18:50 +00:00
HungryHobo
15c45ad820 Remove unused import 2013-01-15 20:53:49 +00:00
HungryHobo
10100b8177 Synchronize a method I missed in rev 7db2932b3db6bbf32d4ae937c93eb37e06e9f099 2013-01-15 20:51:51 +00:00
HungryHobo
6adef679ac Synchronize CryptoFactory (Ticket #610) 2013-01-14 20:16:04 +00:00
HungryHobo
00411877ad Change log level 2013-01-14 20:10:33 +00:00
HungryHobo
7dc9f6caa0 Change log level to DEBUG (same as the other background threads) 2013-01-14 20:09:57 +00:00
HungryHobo
dcb2b0f945 Translate page titles 2013-01-14 20:00:06 +00:00
HungryHobo
f396729698 Disable "default" checkbox when there are less than two identities 2013-01-13 21:15:07 +00:00
HungryHobo
0aff058acd Add a note about automatic email checking when a password is set 2013-01-13 21:00:12 +00:00
HungryHobo
55f363aa73 Add @Overrides 2013-01-13 20:48:27 +00:00
HungryHobo
6fec35ce85 Remove unused methods 2013-01-13 20:45:13 +00:00
HungryHobo
42001079b5 Don't show private key link when creating a new identity 2013-01-13 20:42:35 +00:00
HungryHobo
ab3d23a3af Fix variable name 2013-01-13 20:38:29 +00:00
HungryHobo
3b0c9774e5 Remove mockup elements 2013-01-13 20:35:39 +00:00
HungryHobo
8b44166b90 Simplify stringification 2013-01-13 20:12:55 +00:00
HungryHobo
46ca0add8a Shorten thread name so it doesn't get truncated in the logs 2013-01-13 20:09:58 +00:00
HungryHobo
6e967b2365 Fix: Version number not correctly written to file 2013-01-13 20:05:15 +00:00
HungryHobo
bc72ebb865 Implement delivery status feature 2013-01-13 17:25:01 +00:00
HungryHobo
e204d01fa2 Remove a System.out.println() 2013-01-12 02:51:39 +00:00
HungryHobo
4a05868f11 Catch a more specific exception 2013-01-12 02:44:11 +00:00
HungryHobo
6400913229 Move remaining third-party code (flexiprovider, lzma, and scrypt) into .jars 2013-01-12 02:42:00 +00:00
HungryHobo
d7d3f2f01c Update to NTRU 1.2; move NTRU into a .jar 2013-01-12 02:08:08 +00:00
HungryHobo
f9014d7b7b Fix unit test 2013-01-07 15:02:32 +00:00
HungryHobo
a64ece90c2 Sort relay peers 2013-01-07 15:02:16 +00:00
HungryHobo
e8f16cc83c Remove an unused method 2013-01-07 15:01:36 +00:00
HungryHobo
d7b7355dd1 Fix warnings 2013-01-07 15:01:15 +00:00
HungryHobo
816cf49b8c Get rid of the I2PBoteThread mechanism and handle thread interruptions correctly 2013-01-05 22:07:38 +00:00
HungryHobo
bf2e2224c9 More detailed log message 2013-01-03 13:45:06 +00:00
HungryHobo
2824c9a773 Minor comment change 2013-01-02 23:35:04 +00:00
HungryHobo
1dbbcd8b78 Fix: themes not found because directory names were localized 2013-01-02 23:34:35 +00:00
HungryHobo
d7d6257a36 Add an import for JavaDoc 2013-01-02 21:28:57 +00:00
HungryHobo
020ef33b95 Log exceptions 2013-01-02 21:28:21 +00:00
HungryHobo
8cfe4c5660 Only send up to 20 peers in a PeerList 2013-01-02 21:27:27 +00:00
HungryHobo
e04deb28a1 Add info on how to set up Eclipse 2013-01-02 21:23:56 +00:00
HungryHobo
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
HungryHobo
3ffcf9d8d3 Update German translation from Transifex 2012-12-30 15:52:52 +00:00
HungryHobo
111b3d8dbb Add a heading and a brief explanation 2012-12-02 14:27:31 +00:00
HungryHobo
e177cd4567 Comments 2012-11-27 17:43:19 +00:00
HungryHobo
a0ce9017a9 Include file size in log 2012-11-27 17:39:08 +00:00
kytv
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
HungryHobo
1f595fc079 Change "New" button text to "Compose" 2012-08-14 18:27:29 +00:00
HungryHobo
22c0b789c4 Display last mail check time 2012-08-14 18:23:47 +00:00
kytv
967286aed0 New Arabic translation from Transifex
100% complete
2012-08-09 14:00:31 +00:00
kytv
ef357a5f2a Updated German and Spanish translations from tx. Pushing en source files to tx. 2012-07-29 10:03:47 +00:00
HungryHobo
9fb05ba42e Remove a wrong comment 2012-07-20 12:00:29 +00:00
HungryHobo
f13743d7b9 Make the "error" status text a link that shows a stack trace 2012-07-20 11:58:32 +00:00
HungryHobo
549c39681d Lower log level 2012-07-20 10:56:09 +00:00
HungryHobo
a3e8f657dd Show connect button if connecting failed 2012-07-20 10:54:35 +00:00
HungryHobo
9cb3409a1a Add KYTV, change HH's role to Main Dev 2012-07-20 10:53:08 +00:00
HungryHobo
5e87d6fa2d Lower log level 2012-07-19 15:16:35 +00:00
HungryHobo
902db81fa7 Disable streaming 2012-07-19 15:15:17 +00:00
HungryHobo
3cd0f09a41 More detailed log message 2012-07-19 15:13:27 +00:00
HungryHobo
d0204effa2 Scroll down to the plugin section 2012-07-19 15:12:48 +00:00
HungryHobo
ec619dd830 Fix: some threads not terminating on interrupt() 2012-07-19 15:08:52 +00:00
kytv
10e3df428c Spanish translation update from tx 2012-06-06 10:11:49 +00:00
HungryHobo
e11f41d7f2 merge of '6f90a7d3635c3fece552972c32e378fc5177dd0b'
and '754beaa17f082deb32703c671277a2c0a5ef9ae5'
2012-06-03 21:37:14 +00:00
kytv
f7aae2de4e Add Hungarian translation from TX, thanks AdminLMH! 2012-06-03 13:57:06 +00:00
HungryHobo
d1e4d1a715 Apply layout fixes from rev. e3deccd7238bb85c8b21b564b52979e3b3441142 to network.jsp 2012-06-03 09:38:15 +00:00
HungryHobo
9435b23ab2 Internationalize a string 2012-06-03 09:23:05 +00:00
HungryHobo
bdffd2b8c4 Apply layout fixes from rev. e3deccd7238bb85c8b21b564b52979e3b3441142 to the vanilla theme 2012-06-03 09:19:50 +00:00
HungryHobo
590b9a9e05 Handle individual files 2012-06-03 07:20:36 +00:00
HungryHobo
86ec61db22 Fix layout issues in recent versions of Firefox and Chromium 2012-05-24 18:33:04 +00:00
kytv
45f60e9242 Add translators 2012-04-20 00:11:08 +00:00
kytv
56be74a167 Dutch updates from Transifex 2012-04-19 23:31:06 +00:00
kytv
14376afddb Translation updates from TX (cs, de, es, pl, & sv) 2012-02-23 12:17:55 +00:00
7c54f9fbcb80e56dd9c1e144e255982ef6396df2
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
kytv
13c19addff copy theme folder 2011-12-17 00:37:29 +00:00
kytv
dad6a579c1 Escape & entities 2011-12-17 00:37:15 +00:00
kytv
83d585f651 s/wordwrap/word-wrap/ 2011-12-17 00:36:56 +00:00
HungryHobo
90ceef4583 Add the ability for users to add their own UI themes 2011-12-15 06:51:16 +00:00
HungryHobo
0bf899e291 Update translation 2011-12-14 02:48:25 +00:00
HungryHobo
bbdfc5745b * Add theming support
* Add 'vanilla' theme
* Remove unused icon files
2011-12-14 02:44:22 +00:00
HungryHobo
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
HungryHobo
dbe4400409 Internationalize strings 2011-11-27 06:26:59 +00:00
HungryHobo
bb5d075a54 Replace no-argument JSP functions with bean properties 2011-11-27 06:01:53 +00:00
HungryHobo
5d87d5ec00 Put close() in a finally{ } 2011-11-26 05:06:39 +00:00
HungryHobo
d24eea365c Add comment 2011-11-26 04:57:35 +00:00
HungryHobo
abd4a55956 Move the two toByteArray methods into the superclass 2011-11-26 04:55:00 +00:00
HungryHobo
732b14115b Fix error message 2011-11-26 04:39:13 +00:00
HungryHobo
4455fbb172 * Move symmetric encryption to AbstractCryptoImplementation
* Don't use deprecated methods AESEngine.safeEncrypt() and AESEngine.safeDecrypt()
2011-11-26 04:31:35 +00:00
HungryHobo
673d43cd86 Use the global context, don't create a new one 2011-11-24 05:23:02 +00:00
kytv
b45a162826 Updated (ant poupdate) and pushed to tx 2011-09-23 19:23:44 +00:00
kytv
b06d07b5d1 Add Vietnamese language from Transifex 2011-09-23 19:23:16 +00:00
kytv
52ac133ffa Add Italian and Ukrainian from transifex 2011-09-23 19:17:23 +00:00
kytv
4a240fbb5b Ran ant poupdate for ar and fr. These have been pushed to transifex. 2011-09-23 19:16:52 +00:00
kytv
252a7f0dad merge of '6e3866d554a0bce90773691091c5e037aa69cadc'
and '95a0846bd260b60d641a584dceb6ced27aa2e3ce'
2011-09-23 19:01:36 +00:00
m1xxy
1cd51c811d display tooltips in routerconsole 2011-07-20 04:15:26 +00:00
m1xxy
dda1f5b585 corrected version in manual to current release 2011-07-20 03:46:22 +00:00
magma
fb5e1fc4c2 upd i2p-bote messages_fr.po 2011-07-08 14:39:57 +00:00
hamada
0e6a32a0a0 Update Arabic po from source and finished translation 100% 2011-06-11 09:23:59 +00:00
hamada
d9bc25e1aa translate French strings into Arabic 2011-06-09 13:57:26 +00:00
m1xxy
b124a1046d update .po's 2011-06-02 18:47:29 +00:00
m1xxy
cd21435b60 correction to history.txt 2011-05-02 16:29:02 +00:00
m1xxy
44130323ad typo es 2011-05-02 16:28:38 +00:00
HungryHobo
ef339c29d0 Fix: Existing derivparams file not found 2011-04-30 22:28:56 +00:00
HungryHobo
8ea8e86d99 Correction to translators 2011-04-30 18:45:46 +00:00
HungryHobo
0edf2cfbe3 Replace b32 url with i2pbote.i2p 2011-04-30 18:25:15 +00:00
HungryHobo
a4b284a71c 0.2.6 2011-04-25 23:36:22 +00:00
HungryHobo
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
HungryHobo
f45a185502 Update techdoc.txt; remove To Do / Ideas section 2011-04-24 15:06:40 +00:00
HungryHobo
be545c0836 Don't run migration if already migrated to the latest version 2011-04-24 15:06:39 +00:00
HungryHobo
6c10b8ac64 Fix: signature flag (Email.SIGNATURE_VALID_HEADER) not set on emails in the "sent" folder 2011-04-23 23:35:23 +00:00
HungryHobo
92ff6b58f0 Add FileInfo tool 2011-04-23 22:16:26 +00:00
HungryHobo
1f54ed9ba8 Change order of parameters in the derivparams file so it matches encrypted files 2011-04-23 21:36:47 +00:00
HungryHobo
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
HungryHobo
1fe6c4fc36 Move illegal <description> tags out of i2pbote.tld 2011-04-23 07:15:44 +00:00
HungryHobo
57ead77d39 Capitalize static variable 2011-04-23 06:29:46 +00:00
HungryHobo
dd3ed14174 Remove empty directories (see rev. 65aabb15c2a5df2959bdd8987b6ef8959fe3a537) 2011-04-23 06:23:43 +00:00
HungryHobo
efc2363ade Translate page title 2011-04-23 06:01:24 +00:00
HungryHobo
19a586b170 Integrate FAQ and user guide 2011-04-23 05:59:54 +00:00
HungryHobo
3851faff3f Fix a few things in the German translation, and make it more German 2011-04-22 21:29:08 +00:00
HungryHobo
a583a1fcc3 Add/fix comments 2011-04-22 20:58:41 +00:00
HungryHobo
0464c76884 Wrap (fold) long signatures 2011-04-22 08:28:14 +00:00
HungryHobo
2bc05d4d46 Use identities from TestUtil 2011-04-22 07:18:25 +00:00
HungryHobo
19970b1d53 Fix: "Check Mail" button brings up an error page if a password is required 2011-04-22 05:54:48 +00:00
HungryHobo
035cd346a4 Fix: "constant string too long" when compiling tests with Ant (javac) 2011-04-21 04:56:04 +00:00
HungryHobo
cb1d5bbf67 Set encoding to ISO-8859-1 when compiling flexiprovider sources 2011-04-21 04:50:54 +00:00
HungryHobo
058d09d262 Pare down flexiprovider some more 2011-04-21 04:48:05 +00:00
HungryHobo
14c728c588 merge of '110cd0892a45b8d875bce780895a137da24510d8'
and 'df7b1ac4e3f00852ae445bab6259fb76bd56c5b6'
2011-04-20 03:08:49 +00:00
hiddenz
7823b38d24 Update russian translation 2011-04-19 17:44:33 +00:00
HungryHobo
cb76489c0f Use SHA-512 for ECDSA-521 2011-04-18 05:57:28 +00:00
HungryHobo
fb0352cd7e Don't create zero-length packet files 2011-04-17 19:22:46 +00:00
HungryHobo
b7fcbb5829 Fix plugin target 2011-04-16 22:03:16 +00:00
HungryHobo
80a04a70cb Fix IdentitiesTest 2011-04-16 04:58:40 +00:00
HungryHobo
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
magma
a1085909e1 ego inflation 2011-04-07 21:50:23 +00:00
magma
dc7777be7f fix about identity creation 2011-04-07 08:20:48 +00:00
magma
0ed58252d9 fix about identity creation 2011-04-07 07:31:13 +00:00
magma
660b77c112 fix about identity creation 2011-04-07 07:15:44 +00:00
magma
1c2fe9a481 typos 2011-04-06 19:37:47 +00:00
magma
dc2d8397ab ug_fr.html saved as manual_fr.odt 2011-04-06 13:20:04 +00:00
magma
926a06e53c end (0.2.6) 2011-04-06 13:03:08 +00:00
magma
7de621dc82 end? 2011-04-06 08:55:16 +00:00
magma
35bf2b930a still wip 2011-04-06 07:24:31 +00:00
m1xxy
307e4e8863 fix Guide 2011-04-05 23:33:57 +00:00
magma
04569977d5 still wip 2011-04-05 18:40:39 +00:00
magma
b11bd7b53b small fixes 2011-04-05 18:16:59 +00:00
magma
4f42050cf2 wip 2011-04-05 17:13:49 +00:00
magma
4b95f34430 wip 2011-04-05 12:22:12 +00:00
magma
e10933cc0e typos 2011-04-05 11:03:54 +00:00
magma
db4c3f23cd wip 2011-04-05 11:03:10 +00:00
magma
3ff443fcc8 upd 2011-04-05 10:28:29 +00:00
magma
3c302441ea upd 2011-04-05 08:32:19 +00:00
magma
250f12a69f upd 2011-04-05 07:50:20 +00:00
magma
cc15bff91b add 2011-04-05 07:24:31 +00:00
magma
9b8828109c testers 2011-04-03 21:43:58 +00:00
HungryHobo
72e033e2ef merge of '8bc35fe3851864fad1642e80e73229d6c14d1ba7'
and 'e2e8fcdb307d607cd9d22db33030468d94ec1883'
2011-04-03 20:17:22 +00:00
magma
08f96661fa endend 2011-04-03 19:10:25 +00:00
HungryHobo
7bfffe413c Update to BouncyCastle 1.46 which fixes a bug in ECDSA 2011-04-03 06:51:59 +00:00
HungryHobo
1425a641ae merge of '4fc6f4c8c7963990ab7f079b86d96b7b8aeb761d'
and 'fd7b2809cdc6fa75aacb97c2ed09a2df4101f41f'
2011-04-03 04:41:16 +00:00
HungryHobo
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
m1xxy
a99c08d0e7 typos 2011-04-03 02:17:32 +00:00
m1xxy
c1191d803c translation tweaks es, pt 2011-04-03 00:30:14 +00:00
m1xxy
844f1d3741 translation tweaks es & pt 2011-04-03 00:20:57 +00:00
HungryHobo
612753b39e Fix: message not showing when an identity is deleted 2011-04-03 00:11:41 +00:00
m1xxy
cecccddc2e translation tweak es 2011-04-03 00:08:56 +00:00
m1xxy
17073ed8cd translation tweak es 2011-04-03 00:01:19 +00:00
HungryHobo
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
HungryHobo
08aa68d257 Suppress echoing of .bat commands during JRE installation, show a wait message instead 2011-04-02 23:03:12 +00:00
HungryHobo
2b9b19030f Undo rev. fcd151e70c681bd38f2677cf4e9be334c7ca4cbe which broke win32installer 2011-04-02 22:27:39 +00:00
HungryHobo
87b70ff7bc merge of 'e1744d66f44b6c2f5d1b7d6c2d337c5f2db49687'
and 'fcd151e70c681bd38f2677cf4e9be334c7ca4cbe'
2011-04-02 17:16:21 +00:00
m1xxy
6776b87040 update Swedish translation; thx to hottuna and jaywalk 2011-04-02 12:39:44 +00:00
duck
210ad7f767 Dutch translation updated 2011-04-02 11:34:48 +00:00
duck
3960e41534 Transifex config 2011-04-02 11:26:06 +00:00
duck
32fc56754a Add support for Transifex, fixing po errors. 2011-04-02 11:24:30 +00:00
HungryHobo
082f553be4 Create i2pbote.jar in ant_build/lib instead of WebContent/WEB-INF/lib 2011-04-02 02:44:20 +00:00
m1xxy
bcb31dca0a merge of 'a887eef6899db3400a21fb2319e61208d91cbb29'
and 'b156a7cf0018eebcf3ca07c4273a7918ef260ce7'
2011-04-01 19:55:53 +00:00
m1xxy
a508fa1a0f update translations from web-based translations for sv and zh 2011-04-01 19:55:22 +00:00
magma
dbf769a8cb end2 2011-04-01 14:30:28 +00:00
magma
f3825f3890 end 2011-04-01 12:48:58 +00:00
m1xxy
4125ada488 typo 2011-03-31 19:28:24 +00:00
m1xxy
6a425d1880 merge of 'a11d73c48aa593549c58e0caf94c3effd46ad971'
and 'a7d2d9270b5d91a90992345375b12bd392697635'
2011-03-31 01:28:44 +00:00
magma
173c89306f go on and go2bed 2011-03-31 01:23:06 +00:00
magma
8c6e3bedfb go on 2011-03-31 00:47:01 +00:00
magma
db9a13d58d go on. Please user have a look...I PM my 2 questions 2011-03-30 23:38:51 +00:00
m1xxy
fa37238e00 update translation es and pt 2011-03-30 21:07:40 +00:00
m1xxy
2f10c2bb29 update FAQ and Manual 2011-03-30 20:16:16 +00:00
magma
437686b1e6 redo 2011-03-30 19:41:45 +00:00
magma
53508009b9 upd 2011-03-30 17:01:08 +00:00
magma
49ff872b88 go on FAQ_fr 2011-03-30 11:24:38 +00:00
magma
115688de03 begin 2011-03-30 09:17:51 +00:00
HungryHobo
346d0cd822 Fix remaining file deletion issues on Windows (see rev. 10d16759d75f1ee7ddcbe3bbf16a826d21345619) 2011-03-28 07:56:28 +00:00
HungryHobo
e51c29565e Don't report an error if there is no metadata file 2011-03-28 07:43:49 +00:00
HungryHobo
15f209844d Internationalize string 2011-03-28 07:38:11 +00:00
HungryHobo
86a50c7986 Update win32installer to work with latest router install.xml, add flexi-gmss-1.7p1.jar 2011-03-27 06:50:46 +00:00
HungryHobo
5d44198fef Update German translation 2011-03-27 06:49:38 +00:00
HungryHobo
3ab31b8b16 Don't log stack trace when plugin.config not found 2011-03-27 06:48:53 +00:00
HungryHobo
4bbab19d14 If no good relay peers are known, query for peers more often 2011-03-25 00:34:24 +00:00
HungryHobo
d532c6117d Replace NtruSign with GMSS which uses smaller public keys and inspires more confidence security-wise 2011-03-24 04:38:21 +00:00
HungryHobo
63dc3ea208 Fix: Identities and address book still available after the Clear Password icon is clicked 2011-03-16 22:10:00 +00:00
HungryHobo
82cb40e9bf Check for null values from I2PSession.receiveMessage() 2011-03-16 19:11:27 +00:00
HungryHobo
ec0b072fca Refactor / cleanup:
* Reduce visibility of classes and methods
* Remove unused methods and commented-out code
*
2011-03-16 19:09:57 +00:00
HungryHobo
4718424d11 Fix: "Password cleared" message not showing 2011-03-16 17:05:26 +00:00
HungryHobo
4300ce67e8 Fix NPE in clearPasswordCache.jsp when password is not in cache 2011-03-16 15:33:11 +00:00
HungryHobo
c58a8bb562 Add null checks 2011-03-16 04:30:56 +00:00
HungryHobo
55859d669b Remove unnecessary instance variables 2011-03-16 03:51:11 +00:00
HungryHobo
e11e80832a Update German translation 2011-03-16 01:31:47 +00:00
HungryHobo
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
HungryHobo
6893f5b487 Remove unused constructor UniqueId(InputStream) 2011-03-14 06:20:10 +00:00
HungryHobo
d56ccaf436 If Seedless not available, continue trying 2011-03-14 06:18:26 +00:00
m1xxy
1110bbe386 add credits 2011-03-12 03:36:16 +00:00
HungryHobo
65290098e6 Add an option to show the full email identity (public + private keys) 2011-03-08 05:33:53 +00:00
HungryHobo
5fd314753b 2011-03-08 05:20:56 +00:00
hiddenz
8dd98f2733 Update russian translation 2011-03-07 19:34:05 +00:00
HungryHobo
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
HungryHobo
0e174f870c 2011-03-06 22:08:02 +00:00
HungryHobo
6954e5c7a8 Change /passive option to /s 2011-03-06 22:04:39 +00:00
HungryHobo
8de6a0ab07 Update JRE download link to 6u24 2011-03-06 22:04:00 +00:00
HungryHobo
d7cf897072 Add launch scripts for the Encrypt and Decrypt tools 2011-03-06 21:05:09 +00:00
HungryHobo
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
HungryHobo
4e44fc204e merge of '0c43ec8566a97f8ad57f17575db898b259932435'
and '662195feb3df61d6b5a84dea177727d94cedb8b6'
2011-03-03 21:23:00 +00:00
m1xxy
277a535be4 l8tion 2011-03-03 18:13:39 +00:00
HungryHobo
1dbd6ebc4c Add Override annotations 2011-03-03 03:46:25 +00:00
HungryHobo
bcf869586f Update comments 2011-03-03 03:41:33 +00:00
HungryHobo
6b5bc59775 Update techdoc.txt 2011-03-03 03:38:55 +00:00
HungryHobo
17feb49b0a Fix: Cached scrypt params and salt not correctly reused 2011-03-02 01:51:21 +00:00
walking
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
HungryHobo
b2a3308c2e Ignore blank lines 2011-02-28 05:30:55 +00:00
HungryHobo
89e5a195f8 Remove extraneous character from destination key 2011-02-28 05:30:41 +00:00
HungryHobo
e4c130f51f merge of 'c2a5904fdb10cc3d4cbfa195c557c06cf2f65b5e'
and 'e32e7d661f1c0e4ba49afe94f9b2d89acd40e0d5'
2011-02-28 04:59:29 +00:00
m1xxy
899c0f6796 add credits 2011-02-28 02:11:18 +00:00
m1xxy
fc1287a016 add 安全,分布式电子邮件 and بريد الكتروني الآمن و الغير متمركز 2011-02-28 01:49:40 +00:00
m1xxy
fd3ca21a0c 2011-02-27 23:58:52 +00:00
HungryHobo
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
HungryHobo
bda40109ed Don't show the "known" and "signature" columns in the sent folder 2011-02-27 17:09:42 +00:00
HungryHobo
8c44d3890d Replace PBKDF2 with scrypt 2011-02-27 06:15:53 +00:00
HungryHobo
0e2b89dff1 Fix: Duplicate identity created if password was not entered beforehand 2011-02-27 06:07:46 +00:00
m1xxy
7c46127738 fix and update .po's, update de,es,pt,fr 2011-02-27 04:40:42 +00:00
HungryHobo
d33b8da111 Fix: PasswordException never thrown when saving/deleting an identity 2011-02-19 20:56:02 +00:00
HungryHobo
5d6c30f0bb merge of '4e3d88847518753370c65b8240f9f8a623bb3834'
and '9a74d7db99343b21d83e1fb4d89977feb4b541d2'
2011-02-19 19:37:05 +00:00
HungryHobo
7008c26545 Show a wait page if an email identity will take long to generate 2011-02-19 19:36:25 +00:00
HungryHobo
b8597014dd Fix anonymous sending of emails 2011-02-17 03:55:16 +00:00
HungryHobo
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
hamada
eb446f8703 Add Arabic translation of the plugin 2011-02-16 19:25:19 +00:00
HungryHobo
9df307365c Show attachment sizes 2011-02-14 03:12:05 +00:00
HungryHobo
fcd4fb63ed New CryptoImplementation: NTRUEncrypt1087_NTRUSign349 2011-02-14 00:11:37 +00:00
HungryHobo
27713fb7b6 Remove unused method 2011-02-13 19:23:58 +00:00
HungryHobo
0db3ce5026 Make the default status translatable 2011-02-13 19:14:54 +00:00
HungryHobo
0f04c2c51a Display an error if the attach button is clicked and no file is selected 2011-02-13 16:35:11 +00:00
HungryHobo
206be17615 Show the first few characters of the email destination in the "From:" drop-down 2011-02-13 06:08:26 +00:00
HungryHobo
2511c5b851 2011-02-13 04:34:23 +00:00
HungryHobo
4db98b2c2b Fix RelayPacketTest 2011-02-13 04:31:05 +00:00
HungryHobo
8d2d360180 Fix email deletion on Windows 2011-02-13 03:50:19 +00:00
walking
7d7b509eb9 initial translation for chinese 2011-02-10 16:02:26 +00:00
HungryHobo
124ca1ba62 Inform user when an update is available 2011-02-05 23:24:52 +00:00
HungryHobo
e9cd4a9f6c * Send big packets as a stream
* Don't rely on InputStream.available() in Util.readBytes()
2011-02-05 16:10:41 +00:00
HungryHobo
c627299a35 Fix: All input after first flush() is dropped 2011-02-05 15:53:56 +00:00
HungryHobo
e0f183efa8 Comments 2011-02-02 19:30:09 +00:00
HungryHobo
89395885ba Fix a NPE 2011-02-01 05:41:53 +00:00
HungryHobo
a77309ab36 Change constant scope to private 2011-01-31 07:33:03 +00:00
HungryHobo
efd04f322c Remove unused method getMaxFragmentSize 2011-01-31 07:09:42 +00:00
HungryHobo
a12f90d432 merge of 'a0f3953b8929001edc2b9d59c3bf314040fc4c7b'
and 'fd9b359f0a1eb07fcc4c0c8ec5abe95a0bc073dd'
2011-01-11 19:29:29 +00:00
HungryHobo
5919da4930 merge of '62dcd55b7726aedd5624b076d838cbd11787695a'
and 'cb7ee59eaf0eb93c0dcb91a8226591ca01e51342'
2011-01-11 19:22:47 +00:00
m1xxy
2d291f1ce2 added credits 2011-01-02 05:45:53 +00:00
dev-transport
e299d2e83d Quick fixes to Swedish translation. 2011-01-01 21:54:22 +00:00
dev-transport
76551e3d3f Added Swedish translation. 2011-01-01 21:47:34 +00:00
m1xxy
2f134bfbe4 add translation to Norwegian 2010-12-31 07:01:23 +00:00
m1xxy
c03c481b94 merge of '9a8a529946e94b430d154a127ca08010f15d66d5'
and 'cc0e869985b06631a79b60bf1060d86cc0e88afd'
2010-12-31 01:09:35 +00:00
m1xxy
7d1fed76da mods to pt 2010-12-29 15:51:57 +00:00
HungryHobo
7148172e9c New unit test: PasswordCacheTest 2010-12-22 06:01:17 +00:00
HungryHobo
5c102da3a0 * Reset expiration when a password is set
* Clear derived key when password is cleared
2010-12-22 05:49:18 +00:00
HungryHobo
f3a1c618e5 merge of '243e68f714882dc1fe2f79958b31ac862053ba9f'
and 'f9ab92a43553dde223bb24940d32f19a60022b34'
2010-12-20 05:38:39 +00:00
HungryHobo
5c221f31d9 Add missing copyright notices 2010-12-20 00:42:37 +00:00
m1xxy
7ac42c0e4e translation updates 2010-12-19 23:32:17 +00:00
HungryHobo
4da3ee6aed New Ant task: win32installer 2010-12-19 23:00:50 +00:00
HungryHobo
3aecc56933 Restore plugin.config after mismerge 2010-12-19 22:27:47 +00:00
HungryHobo
5ea124b7d2 Jetty fix 2010-12-19 22:22:17 +00:00
HungryHobo
7fb33a0d35 Fix return to folder.jsp after password entry 2010-12-19 22:21:04 +00:00
HungryHobo
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
HungryHobo
9bee5057f1 merge of '0b216d7818b91cf69fdfb88048dfcbfbfce02833'
and 'de95731855e9e7f8a81b42642fd566ac6ee76c08'
2010-12-17 19:54:42 +00:00
HungryHobo
bdce2ecad5 merge of '561ea16dc8eb82dc348dca962f30e579c8ed3d63'
and 'b1b87fc5a28b9aad267b6c3aeddc1c23377c5ab6'
2010-12-17 19:54:42 +00:00
HungryHobo
d3ee66ff60 * Remove unused method toBase32
* Replace instanceof with getClass() in equals()
2010-12-17 03:43:44 +00:00
HungryHobo
647efead3b Fix unit tests; jMock now required to run them 2010-12-17 03:41:57 +00:00
m1xxy
09f5d107c9 translation update de 2010-12-17 02:01:47 +00:00
HungryHobo
d33bc11a31 Contributors update 2010-12-16 01:27:09 +00:00
HungryHobo
2d6066ad58 Remove serialVersionUID from non-serializable class 2010-12-16 00:40:21 +00:00
HungryHobo
0bdd216ef0 Remove an obsolete comment 2010-12-16 00:39:08 +00:00
HungryHobo
75336e899d Fix an import 2010-12-16 00:28:22 +00:00
m1xxy
3870ca5335 plugin.config nl link translation 2010-12-13 18:46:26 +00:00
m1xxy
5aaae853af plugin.config translation 2010-12-13 16:39:01 +00:00
m1xxy
a64cdca34e merge of '0039d7fd449038234648a57ff05906383d0ce75d'
and '92c193a4f6709ce5205a43617bcd8a144ae598ca'
2010-12-13 11:52:48 +00:00
m1xxy
99f64adc05 merge of 'b85935006af43967ba763bb53ab75c6f0278c539'
and 'eff65f71bc633578ad72cbcb2d5301f1d1766c30'
2010-12-13 11:52:47 +00:00
m1xxy
05c24ab545 explicit merge of '93973b70de2d4a41180a7d2f201b684e5ea6d445'
and '451bb8a70baa411c0d401c329b5b60b7c14d09b3'
2010-12-13 11:44:04 +00:00
m1xxy
897d43ff51 Fix a typo 2010-12-13 11:42:56 +00:00
m1xxy
46b9e3a039 explicit merge of '7ca94be8ef990b10920f144f441a51d239d33c48'
and 'ef38ab9835eb8fec5dbd981f2951d12d5d0d5d0d'
2010-12-13 08:06:21 +00:00
m1xxy
018209bed5 Dutch translation by KwukDuck 2010-12-13 08:03:04 +00:00
m1xxy
fe14f97dfd explicit merge of '5c7fd9edde41ff7c26cd2fb28e1a46b96c1f8538'
and '9245efd7b168684236148a7102535f0a009e2c4f'
2010-12-13 01:39:10 +00:00
m1xxy
f2b1d3cc1c Portuguese translation 2010-12-13 01:13:25 +00:00
HungryHobo
0600b6e595 merge of '08eff6bfa6a2b340f314f1de096c771337eb3a3b'
and '1dbb023c5b2674f49708ad83060aed35cdb3a7a1'
2010-12-12 20:10:11 +00:00
HungryHobo
aab0b139d3 * Don't encrypt meta files
* Don't attempt to convert a non-existing directory
2010-12-12 20:06:18 +00:00
HungryHobo
872c386929 Focus the "old password" field 2010-12-12 20:03:19 +00:00
HungryHobo
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
HungryHobo
7fbd29b75d File encryption 2010-12-10 20:10:49 +00:00
sponge
b8fd5b5c1d Add TO-DO note for HH to do an important fix. 2010-12-07 00:36:20 +00:00
sponge
c81f2cb46c merge of '43b11afe7287401107616e5cff0c1d4773c0e1d3'
and '92344efb7a96786e8ef1e256f754ea8e9666c765'
2010-12-07 00:23:23 +00:00
m1xxy
6c859388c5 changes to Spanish translation 2010-12-04 10:56:38 +00:00
m1xxy
087b8ddc42 changes to the manual 2010-12-04 10:52:54 +00:00
sponge
0eba059a8c merge of '28760fe7e19dd265a2ede35a51f73e5c07b1a2aa'
and 'db84face38fdd977157aaf02c444b894c7049d84'
2010-11-28 06:45:44 +00:00
sponge
7136ab215c Refactor out Deprecated destFromName calls, fixup nb files 2010-11-28 06:45:22 +00:00
hiddenz
3f867d8041 plugin.config: add russian translation 2010-11-20 19:29:23 +00:00
m1xxy
a8bb3652fe added string to plugin.config and a minor correction 2010-11-16 22:34:07 +00:00
m1xxy
1672d95ae6 merge of '2e376f13320c297b93e734b3f39e113752891578'
and 'f2d47e61537a5a2f2077eae200af07ef12114b2e'
2010-11-11 21:01:03 +00:00
m1xxy
c3c832649c update manual 2010-11-11 21:00:10 +00:00
m1xxy
c115278016 merge of '6b7cd0a43c55b9a2ae53778a25e6940cfe4fba1f'
and '9245efd7b168684236148a7102535f0a009e2c4f'
2010-11-11 17:32:29 +00:00
m1xxy
a65653b30b Spanish translation for Bote; fixes sent in by Redzara to French translation 2010-11-11 17:31:18 +00:00
HungryHobo
d92f66720a merge of '37af2db09b85c46e860280cdb70d92bf07810401'
and 'df5454597876a5df6f61e5adb97d30fb57b63d48'
2010-11-04 06:57:33 +00:00
m1xxy
0954398245 minor corrections 2010-11-03 18:10:46 +00:00
HungryHobo
50da5ccc80 Fix a NPE 2010-11-03 06:09:00 +00:00
m1xxy
2b71438c82 French translation by albat and mixxy 2010-10-29 20:19:23 +00:00
HungryHobo
1b5356e845 Fix a comment 2010-10-26 20:24:52 +00:00
HungryHobo
9c951dc2f1 Fix a NPE 2010-10-26 18:27:11 +00:00
HungryHobo
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
HungryHobo
dbd46e2b4f Comments 2010-10-03 22:06:20 +00:00
HungryHobo
a2c55a78fc 0.2.5 2010-10-03 22:05:54 +00:00
HungryHobo
c423b7331e Implement KBucketTest 2010-10-03 21:59:48 +00:00
HungryHobo
a031f4da28 Decrease text field width on the "new email" page 2010-10-03 19:19:15 +00:00
HungryHobo
7573eed929 Minor things 2010-10-03 19:13:53 +00:00
HungryHobo
1e78638692 Refresh folder list when new mail arrives so the inbox message count is updated 2010-10-03 08:07:48 +00:00
HungryHobo
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
HungryHobo
b9155254d0 Use base64 for RelayPacketFolder filenames, which is what all other folders do 2010-10-03 00:19:14 +00:00
HungryHobo
0ebe7e68c7 Update techdoc.txt 2010-10-02 22:50:02 +00:00
HungryHobo
48340cb790 Update manual 2010-10-02 20:14:24 +00:00
HungryHobo
02b803fda7 Fix duplicate "Unknown" in the date/time column in folder.jsp 2010-10-02 19:49:41 +00:00
HungryHobo
4d306d5f85 Translation update 2010-10-02 19:47:05 +00:00
HungryHobo
388843a439 Implement reading from ByteBuffer and writing to OutputStream 2010-10-02 18:34:56 +00:00
HungryHobo
e03521821a Make the outbox check interval a config setting 2010-10-02 06:23:40 +00:00
HungryHobo
ac77853485 Fix display of date/time in showEmail.jsp 2010-10-02 04:57:30 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
d68fd5429e Log deletion of relay packets 2010-09-30 05:50:03 +00:00
HungryHobo
a7b4b9acc6 Pad relay packets 2010-09-30 05:11:42 +00:00
HungryHobo
20841b7a4a Remove the unused and confusing Email Address field from the Edit Identity page 2010-09-27 05:54:08 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
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
HungryHobo
f71f0e1470 Show a message after saving settings 2010-09-25 07:32:00 +00:00
HungryHobo
3c7bd9acf6 Simplify folderLink.tag by using folder.jsp for the outbox; see rev. 7790618d3eba2f460983f87db7ddc1fe1b94053c 2010-09-25 07:11:58 +00:00
HungryHobo
1439358221 Take the user back to outbox.jsp after an outbox email is deleted 2010-09-25 06:48:31 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
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
HungryHobo
4e5104ff52 Show status for outbox emails 2010-09-23 05:29:22 +00:00
HungryHobo
ecf093119a Reduce default delay to 5..40 minutes per hop 2010-09-23 05:04:26 +00:00
HungryHobo
cbd7a8dffb Don't show signature column in "sent" folder 2010-09-23 04:57:37 +00:00
HungryHobo
08cd5406f4 Sort address book and identities by name 2010-09-23 04:06:10 +00:00
HungryHobo
af2f63565f Update technical documentation 2010-09-22 17:38:34 +00:00
HungryHobo
1b481dcf24 Add user manual by mixxy, delete userdoc.txt 2010-09-22 17:38:15 +00:00
HungryHobo
6ee5005944 Align Sent Time 2010-09-22 07:18:27 +00:00
HungryHobo
b4b94ad38a Log peer destinations in base32 2010-09-22 06:21:57 +00:00
HungryHobo
aa4551fc14 Show local destination and peer destinations in base32 2010-09-20 05:18:46 +00:00
HungryHobo
9d77f57123 Add a note about attachment sizes 2010-09-20 03:31:11 +00:00
HungryHobo
3115faedb2 Fix comments, remove unnecessary braces 2010-09-20 02:37:46 +00:00
HungryHobo
4e7b0c115e Keep trying to send an email if there is an error 2010-09-20 02:27:33 +00:00
HungryHobo
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
HungryHobo
d3a072c54b * Don't replicate packets that were recently replicated
* Log number of replicated packets
2010-09-16 05:06:44 +00:00
HungryHobo
174a94f492 Fix: ReplicateThread.packetStored() not called when storing in a DeletionAwareDhtFolder 2010-09-16 05:02:12 +00:00
HungryHobo
9f6806a738 Verify hashes of received email packets against the DHT key 2010-09-15 06:50:52 +00:00
HungryHobo
809dc90bc8 Fix non-ascii characters (switching from Commons FileUpload to JavaMail-based multipart parsing broke them) 2010-09-09 06:04:40 +00:00
HungryHobo
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
HungryHobo
d9034fee31 Change a few log levels 2010-09-06 22:56:27 +00:00
HungryHobo
c30180fcbf Remove newlines from the end of files (just a personal preference) 2010-09-06 22:46:58 +00:00
HungryHobo
110a4bd484 Fix LZMA dictionary size 2010-09-06 19:46:47 +00:00
HungryHobo
06106c0b57 Use isProtocolVersionOk() for version checking, see rev. c848aa079ff8d62fac18c1c7782d48befc13b98d 2010-09-06 19:44:32 +00:00
HungryHobo
a006e3b688 Use different texts for the two test emails 2010-09-06 07:53:18 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
85d958a0cc Add Russian translation by suhr 2010-09-05 19:59:11 +00:00
HungryHobo
ca1d5e6d8c Update RelayPacketTest to use the new file format introduced in revision bfde50fb7c22410d7859a6914990798c68127bc5 2010-08-25 02:28:48 +00:00
HungryHobo
245e50aaa9 Count emails with no metadata as new to match the behavior of the EmailMetaData class 2010-08-22 20:49:33 +00:00
HungryHobo
4d0d5d245c Minor things 2010-08-18 20:58:51 +00:00
HungryHobo
f1d8554ab3 Put a space between name and angle bracket 2010-08-18 20:56:42 +00:00
HungryHobo
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
HungryHobo
5a3e49c4dd Replace Thread.sleep() with awaitShutdownRequest() 2010-08-18 04:33:57 +00:00
HungryHobo
2ad8d2ac8e Fix: Folder view only shows the recipient if it is a local identity 2010-08-18 04:32:38 +00:00
HungryHobo
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
HungryHobo
6b38f0d520 Comments and other minor things 2010-08-17 17:52:33 +00:00
HungryHobo
0105bb360a Cleanup 2010-08-17 17:47:54 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
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
HungryHobo
8f090fd3e3 Clean up test folder when finished 2010-08-12 06:10:49 +00:00
HungryHobo
c36b24bad6 * Comments, Formatting
* Move ProxyRequest.java into the seedless package because it is only used there
2010-08-12 06:08:31 +00:00
HungryHobo
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
HungryHobo
078f0952ef Fix an NPE when trying to connect before Seedless is initialized 2010-08-01 06:21:11 +00:00
HungryHobo
834331903e * Don't set the Date header if it is already there
* Slight code simplification
2010-08-01 06:18:55 +00:00
HungryHobo
b112ad89f3 * Remove KademliaDHTTest (would have been to complicated to implement)
* Add KBucketTest (does nothing yet)
2010-08-01 01:26:12 +00:00
HungryHobo
73f8295c9c A few little things 2010-08-01 01:23:25 +00:00
HungryHobo
c2da679543 * Make getFilenames() protected
* Remove individualPackets() override in DeletionAwareDhtFolder which does nothing
2010-08-01 01:21:27 +00:00
HungryHobo
ac46459a0d Send a specific delay time in relay packets, not a min/max range 2010-08-01 01:16:37 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
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
HungryHobo
a488294bb3 Convert tabs to spaces 2010-07-29 00:29:50 +00:00
HungryHobo
175345dfe4 Shut down EmailPacketTask threads when the tasks are finished 2010-07-25 05:09:12 +00:00
HungryHobo
78bb4f7366 Fix member field name in comment 2010-07-24 07:50:08 +00:00
HungryHobo
29f485f4e2 Fix: Reachability of relay peers changes to 100% after startup 2010-07-24 07:47:58 +00:00
HungryHobo
b794aaf0e0 Remove unused methods 2010-07-24 02:17:22 +00:00
HungryHobo
465d509bcc * Autorefresh "inbox" and "sent" folders
* Autorefresh outbox if it is not empty
2010-07-19 05:39:51 +00:00
HungryHobo
a4b25f0ae8 Stop refreshing when the CONNECTED or ERROR status is reached 2010-07-19 01:26:26 +00:00
HungryHobo
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
HungryHobo
2e72fb7f36 Don't send email if no recipient, show error message instead 2010-07-18 05:48:17 +00:00
HungryHobo
a225fa20b1 Fix NPE when sending before connected 2010-07-18 05:47:22 +00:00
HungryHobo
f87fe26811 javadoc Ant target, javadoc formatting, documentation 2010-07-17 22:52:24 +00:00
HungryHobo
d2b38a3f33 merge of '34a49b587bbb0c309e60a1df7a9a792654e48fd2'
and 'bf83f8762c1d6cfaa71871d32bdc9a3e089058c1'
2010-07-16 15:41:45 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
0527c1f246 Fix counting of #lines read 2010-07-14 18:46:20 +00:00
HungryHobo
7ee570e375 * Translate the string for the outbox status "Queued"
* Remove an unused method
2010-07-14 07:09:14 +00:00
HungryHobo
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
HungryHobo
f972c9e2e6 Fix: MultipartFilter drops request parameters that are added via jsp:param in a jsp:forward 2010-07-13 07:52:44 +00:00
sponge
29df785ab6 merge of '9c9772d22e302d48a4c849c18c8ff3bcb3ff8404'
and 'e09e454db05d06c660ba0e8e2ff5021aa52ec787'
2010-07-12 06:14:06 +00:00
sponge
e3448c9b17 Added needed jar files to project.xml for NB 6.5 2010-07-12 04:29:16 +00:00
sponge
a3a8c77963 merge of '3e369acec144cfce4278be9456f6b81de0455791'
and 'dc2bcd3d2bdc8b5c7462377da7462d3f5108b3ee'
2010-07-12 03:48:39 +00:00
HungryHobo
67dab8aaf7 merge of '3e369acec144cfce4278be9456f6b81de0455791'
and 'dc2bcd3d2bdc8b5c7462377da7462d3f5108b3ee'
2010-07-12 02:14:52 +00:00
HungryHobo
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
HungryHobo
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
sponge
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
HungryHobo
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
HungryHobo
77ec925d45 Post-merge cleanup. This revision diffs cleanly against 14ada4dcae2f555f4b5539305e32f96bafec675e (the last rev before Seedless). 2010-07-07 05:14:08 +00:00
HungryHobo
2bd6eac5af merge of '15679f7110fe5f55407d2d04c63bc18e1d460113'
and '289456e0b294a38c3d0e75d69873d614170f9e58'
2010-07-04 07:42:56 +00:00
HungryHobo
50673b6358 Comments 2010-07-04 07:28:05 +00:00
HungryHobo
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
HungryHobo
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
HungryHobo
2bbba38007 * Attachment support
* Lower the priority of some background tasks
2010-07-03 21:59:14 +00:00
HungryHobo
479b28f35f Fix: Corrupt padding error with ECDH when the input size is a multiple of 16 2010-06-30 18:36:06 +00:00
sponge
07a3340ffa Depend on Seedless _first_, then fallback to built-in, as per HH. 2010-06-28 21:10:51 +00:00
sponge
69f289b0d9 Fix annoying NPE 2010-06-25 14:57:59 +00:00
sponge
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
sponge
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
sponge
6bd4cab290 Muxed depends on gzip == true? 2010-06-25 06:49:04 +00:00
HungryHobo
816eb59c94 Compress emails before encrypting them 2010-06-25 02:36:15 +00:00
HungryHobo
889a28063d * Add sponge as a contributor
* Replace HungryHobo email address with email destination
2010-06-25 02:18:43 +00:00
sponge
a783a0ddb8 Salt relay peers like bote does 2010-06-24 22:41:17 +00:00
sponge
617122dfe1 Fix NPE. 2010-06-24 20:19:31 +00:00
sponge
e471ddd57a Added injection to relay peers as well. This possibly isn't the correct intent. 2010-06-24 20:06:28 +00:00
sponge
1999eb2432 merge of '7561cf99368e4a244f4b67c350c0c92f7a1afc08'
and 'a74daea914c9a98d3953dbe4e2507b4ad032ae66'
2010-06-24 17:56:14 +00:00
sponge
a22eea0f66 - 2010-06-24 17:55:44 +00:00
sponge
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
sponge
66b970d22b disapproval of revision '0c7dc27eead74ddbe0d89793014d5c1cf2e35b2f' 2010-06-24 06:58:57 +00:00
sponge-transport
2b5ce8cf27 And now we hope it is set correctly.
disapproval of revision 'f9c92102d1893e1d6e2597ce50dd617256a4aee3'
2010-06-24 06:26:03 +00:00
sponge
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
sponge-transport
1ce75177e9 Change for log debugging. 2010-06-24 06:18:55 +00:00
sponge-transport
0df770bc68 Temp fix. See comment KademliaDHT.java ~line 364 2010-06-24 06:12:06 +00:00
sponge-transport
120de4af9e Fix stupid bug *embarrassment* 2010-06-24 03:03:50 +00:00
sponge-transport
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
sponge
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
HungryHobo
99baa56af3 Apply patch by zzz to abort the build if <exec> returns non-zero. 2010-06-20 05:20:21 +00:00
HungryHobo
95ac52b7ea Increase expiration times in testCheckExpiration() to fix test failures reported by one user. 2010-06-20 05:16:58 +00:00
sponge
e4696b2bad Add Netbeans 6.5 Project file 2010-06-18 13:17:50 +00:00
496 changed files with 82728 additions and 10505 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

Binary file not shown.

View File

@@ -1,45 +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/>.
--%>
<%@ attribute name="dirName" required="true" description="The directory used by the folder" %>
<%@ attribute name="displayName" required="true" description="The display name for the folder" %>
<%@ 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="numEmails" value="${ib:getMailFolder(dirName).numElements}"/>
<c:set var="numNew" value="${ib:getMailFolder(dirName).numNewEmails}"/>
<c:choose>
<c:when test="${dirName eq 'Outbox'}">
<a href="outbox.jsp" target="_parent" title="${numEmails} emails total, ${numNew} new">
<img src="images/folder.png"/>${displayName}
</a>
</c:when>
<c:otherwise>
<a href="folder.jsp?path=${dirName}" target="_parent" title="${numEmails} emails total, ${numNew} new">
<img src="images/folder.png"/>${displayName}
</a>
</c:otherwise>
</c:choose>
<c:if test="${numNew>0}">(${numNew})</c:if>

View File

@@ -1,459 +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>JSP</body-content>
<attribute>
<name>sender</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>recipient</name>
<info>
Adds an email recipient. Must be inside an ib:sendEmail tag.
</info>
<tag-class>i2p.bote.web.RecipientTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>type</name>
<description>
Can be any of the javax.mail.Message.RecipientType values
(TO, CC, or BCC).
</description>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
<attribute>
<name>address</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>formatPlainText</name>
<tag-class>i2p.bote.web.FormatPlainTextTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>text</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
</tag>
<tag>
<name>setEmailRead</name>
<tag-class>i2p.bote.web.SetEmailReadTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>folder</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
<attribute>
<name>messageId</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
<attribute>
<name>read</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
</tag>
<tag>
<name>quote</name>
<tag-class>i2p.bote.web.QuoteTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>text</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
</tag>
<tag>
<name>connect</name>
<tag-class>i2p.bote.web.ConnectTag</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>peerInfo</name>
<tag-class>i2p.bote.web.PeerInfoTag</tag-class>
<body-content>empty</body-content>
</tag>
<tag>
<name>localizedLanguageName</name>
<tag-class>i2p.bote.web.LocalizedLanguageNameTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>locale</name>
<rtexprvalue>true</rtexprvalue>
<required>true</required>
</attribute>
</tag>
<tag>
<name>message</name>
<info>
Same as fmt:message, except that message keys in
the "en" locale translate to the message key itself.
</info>
<tag-class>i2p.bote.web.MessageTag</tag-class>
<body-content>JSP</body-content>
<attribute>
<name>key</name>
<rtexprvalue>true</rtexprvalue>
<required>false</required>
</attribute>
<attribute>
<name>bundle</name>
<rtexprvalue>true</rtexprvalue>
<required>false</required>
</attribute>
<attribute>
<name>var</name>
<rtexprvalue>true</rtexprvalue>
<required>false</required>
</attribute>
<attribute>
<name>scope</name>
<rtexprvalue>true</rtexprvalue>
<required>false</required>
</attribute>
<attribute>
<name>hide</name>
<description>
If this parameter is set to true, and the user has chosen to hide
the UI language from email recipients, the message is not translated.
</description>
<rtexprvalue>true</rtexprvalue>
<required>false</required>
</attribute>
</tag>
<tag>
<name>param</name>
<info>
Same as fmt:param. Must be inside an ib:message tag.
</info>
<tag-class>i2p.bote.web.ParamTag</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>value</name>
<rtexprvalue>true</rtexprvalue>
<required>false</required>
</attribute>
</tag>
<tag>
<name>saveConfiguration</name>
<info>
Saves the configuration to the config file.
</info>
<tag-class>i2p.bote.web.SaveConfigurationTag</tag-class>
<body-content>empty</body-content>
</tag>
<function>
<name>getNetworkStatus</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.network.NetworkStatus getNetworkStatus()
</function-signature>
</function>
<function>
<name>getIdentities</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.email.Identities getIdentities()
</function-signature>
</function>
<function>
<name>saveIdentity</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
boolean saveIdentity(boolean, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, boolean)
</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>getIdentity</name>
<description>
Looks up an EmailIdentity by destination key.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.email.EmailIdentity getIdentity(java.lang.String)
</function-signature>
</function>
<function>
<name>getCryptoImplementation</name>
<description>
Looks up a CryptoImplementation by ID number.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.crypto.CryptoImplementation getCryptoImplementation(int)
</function-signature>
</function>
<function>
<name>getAddressBook</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.addressbook.AddressBook getAddressBook()
</function-signature>
</function>
<function>
<name>saveContact</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
boolean saveContact(java.lang.String, java.lang.String)
</function-signature>
</function>
<function>
<name>deleteContact</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
boolean deleteContact(java.lang.String)
</function-signature>
</function>
<function>
<name>getContactName</name>
<description>
Looks up a name for an Email Destination in the address book.
If the Email Destination does not exist in the address book,
an empty string is returned.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.String getContactName(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>
<function>
<name>getEmails</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.util.List getEmails(i2p.bote.folder.EmailFolder, i2p.bote.email.EmailAttribute, boolean)
</function-signature>
</function>
<function>
<name>getShortSenderName</name>
<description>
Returns up to maxLength characters of a "sender" header field.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.String getShortSenderName(java.lang.String, int)
</function-signature>
</function>
<function>
<name>getOneLocalRecipient</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.String getOneLocalRecipient(i2p.bote.email.Email)
</function-signature>
</function>
<function>
<name>getEmailStatus</name>
<description>
Returns the status of an email in the outbox. See OutboxProcessor.java.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.String getEmailStatus(i2p.bote.email.Email)
</function-signature>
</function>
<function>
<name>deleteEmail</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.boolean deleteEmail(java.lang.String, java.lang.String)
</function-signature>
</function>
<function>
<name>getNameAndDestination</name>
<description>
Returns a string containing the locally known name of the Email Destination
in the String argument, and the Base64-encoded Email Destination.
If the Email Destination is not locally known (if it doesn't exist in the
address book or any of the identities), the address is returned unaltered.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.String getNameAndDestination(java.lang.String)
</function-signature>
</function>
<function>
<name>extractName</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.String extractName(java.lang.String)
</function-signature>
</function>
<function>
<name>extractEmailDestination</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
i2p.bote.email.EmailDestination extractEmailDestination(java.lang.String)
</function-signature>
</function>
<function>
<name>getSortedRecipientParams</name>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.util.Map getSortedRecipientParams(java.util.Map)
</function-signature>
</function>
<function>
<name>mergeRecipientFields</name>
<description>
This method is used by newEmail.jsp. It adds the values of all
selectedContact keys as recipient addresses, and returns a List
containing the old recipient addresses as well as the new ones.
If the "action" parameter is set to "addRecipientField", a blank
recipient address is added additionally.
If the action is "removeRecipient" followed by a number, the
recipient field with that index is removed.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.util.List mergeRecipientFields(javax.servlet.ServletRequest)
</function-signature>
</function>
<function>
<name>isKnown</name>
<description>
Returns true if a string contains a Base64-encoded Email Destination that
is either in the address book or among the Email Identities.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
boolean isKnown(java.lang.String)
</function-signature>
</function>
<function>
<name>escapeQuotes</name>
<description>
Converts all double and single quotes in a string to HTML entities,
which makes the string safe to use in hidden form fields.
</description>
<function-class>i2p.bote.web.JSPHelper</function-class>
<function-signature>
java.lang.String escapeQuotes(java.lang.String)
</function-signature>
</function>
<tag-file>
<name>printWithLineBreaks</name>
<path>/WEB-INF/tags/printWithLineBreaks.tag</path>
</tag-file>
<tag-file>
<name>folderLink</name>
<path>/WEB-INF/tags/folderLink.tag</path>
</tag-file>
<tag-file>
<name>address</name>
<path>/WEB-INF/tags/address.tag</path>
</tag-file>
<tag-file>
<name>emailDate</name>
<path>/WEB-INF/tags/emailDate.tag</path>
</tag-file>
<tag-file>
<name>copyParams</name>
<path>/WEB-INF/tags/copyParams.tag</path>
</tag-file>
</taglib>

View File

@@ -1,29 +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.jsp</welcome-file>
</welcome-file-list>
<listener>
<listener-class>i2p.bote.web.ServiceInitializer</listener-class>
</listener>
<filter>
<filter-name>CharsetFilter</filter-name>
<filter-class>i2p.bote.web.CharsetFilter</filter-class>
<init-param>
<param-name>requestEncoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharsetFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>

View File

@@ -1,97 +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="getStatus.jsp"/>
<c:if test="${param.checkMail == 1}">
<ib:checkForMail/>
</c:if>
<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;url=buttonFrame.jsp" />
</c:if>
</head>
<body style="background-color: transparent; margin: 0px;">
<c:set var="disable" value=""/>
<c:if test="${connStatus == DELAY}">
<c:set var="disable" value="disabled=&quot;disabled&quot;"/>
</c:if>
<table><tr>
<td>
<c:if test="${checkingForMail}">
<div class="checkmail">
<img src="images/wait.gif"/><ib:message key="Checking for mail..."/>
</div>
</c:if>
<c:if test="${!checkingForMail}">
<div class="checkmail">
<c:choose>
<c:when test="${empty ib:getIdentities().all}">
<c:set var="url" value="noIdentities.jsp"/>
<c:set var="frame" value="target=&quot;_parent&quot;"/>
</c:when>
<c:otherwise>
<c:set var="link" value="buttonFrame.jsp"/>
<c:set var="frame" value=""/>
</c:otherwise>
</c:choose>
<form action="${url}" ${frame} method="GET">
<input type="hidden" name="checkMail" value="1"/>
<button type="submit" value="Check Mail/>" ${disable}><ib:message key="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 (parent.document.getElementById('inboxFlag'))
parent.location.href = 'folder.jsp?path=Inbox';
</script>
</c:if>
</c:if>
</td>
<td>
<form action="newEmail.jsp" target="_top" method="GET">
<button type="submit" value="New" ${disable}><ib:message key="New"/></button>
</form>
</td>
</tr></table>
</body>
</html>

View File

@@ -1,150 +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}">
<ib:message key="New Email Identity" var="title" scope="request"/>
<ib:message key="Create" var="commitAction"/>
<c:set var="publicName" value="${param.publicName}"/>
<c:set var="description" value="${param.description}"/>
</c:when>
<c:otherwise>
<ib:message key="Edit Email Identity" var="title" scope="request"/>
<ib:message key="Save" var="commitAction"/>
<c:set var="key" value="${param.key}"/>
<c:set var="identity" value="${ib:getIdentity(key)}"/>
<c:set var="publicName" value="${ib:escapeQuotes(identity.publicName)}"/>
<c:set var="description" value="${ib:escapeQuotes(identity.description)}"/>
</c:otherwise>
</c:choose>
<jsp:include page="header.jsp"/>
<div class="errorMessage">
${fn:escapeXml(param.errorMessage)}
</div>
<div class="main">
<form name="form" action="saveIdentity.jsp">
<table>
<tr>
<td>
<div style="font-weight: bold;"><ib:message key="Public Name:"/></div>
<div style="font-size: 0.8em;"><ib:message key="(required field, shown to recipients)"/></div>
</td>
<td>
<input type="text" size="40" name="publicName" value="${publicName}"/>
</td>
</tr>
<tr>
<td>
<div style="font-weight: bold;"><ib:message key="Description:"/></div>
<div style="font-size: 0.8em;"><ib:message key="(optional, kept private)"/></div>
</td>
<td>
<input type="text" size="40" name="description" value="${description}"/>
</td>
</tr>
<tr>
<td>
<div style="font-weight: bold;"><ib:message key="Email Address:"/></div>
<div style="font-size: 0.8em;"><ib:message key="(optional)"/></div>
</td>
<td>
<input type="text" size="40" name="emailAddress" value="${param.emailAddress}"/>
</td>
</tr>
<tr>
<td>
<div style="font-weight: bold;"><ib:message key="Encryption:"/></div>
<c:if test="${param.new}">
<div style="font-size: 0.8em;"><ib:message key="(If unsure, leave the default)"/></div>
</c:if>
</td>
<c:if test="${param.new}">
<td>
<c:set var="selectedCryptoImplId" value="${param.cryptoImpl}"/>
<c:if test="${empty param.cryptoImpl}">
<c:set var="selectedCryptoImplId" value="2"/>
</c:if>
<select name="cryptoImpl">
<jsp:useBean id="jspHelperBean" class="i2p.bote.web.JSPHelper"/>
<c:forEach items="${jspHelperBean.cryptoImplementations}" var="cryptoImpl">
<c:set var="selected" value=""/>
<c:if test="${selectedCryptoImplId eq cryptoImpl.id}">
<c:set var="selected" value=" selected"/>
</c:if>
<option value="${cryptoImpl.id}"${selected}>
${cryptoImpl.name}
</option>
</c:forEach>
</select>
</td>
</c:if>
<c:if test="${not param.new}">
<td>
<c:set var="cryptoImpl" value="${ib:getCryptoImplementation(identity.cryptoImpl.id)}"/>
${cryptoImpl.name}
</td>
</c:if>
</tr>
<c:if test="${!param.new}">
<tr>
<td style="font-weight: bold; vertical-align: top;">
<ib:message key="Email Destination:"/>
</td>
<td>
<textarea cols="64" rows="9" readonly="yes" wrap="soft" class="destinationtextarea">${param.key}</textarea>
</td>
</tr>
<tr>
<td style="font-weight: bold; vertical-align: top;">
<ib:message key="Default Identity:"/>
</td>
<td>
<c:if test="${param.isDefault}">
<c:set var="checked" value="checked"/>
</c:if>
<input type="checkbox" name="isDefault" ${checked}/>
</td>
</tr>
</c:if>
</table>
<input type="hidden" name="new" value="${param.new}"/>
<input type="hidden" name="key" value="${param.key}"/>
<button name="action" value="${commitAction}">${commitAction}</button>
<button name="action" value="cancel"/><ib:message key="Cancel"/></button>
</form>
<script type="text/javascript" language="JavaScript">
document.forms['form'].elements['publicName'].focus();
</script>
</div>
<jsp:include page="footer.jsp"/>

View File

@@ -1,174 +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" %>
<%
pageContext.setAttribute("FROM", i2p.bote.email.EmailAttribute.FROM, PageContext.PAGE_SCOPE);
pageContext.setAttribute("TO", i2p.bote.email.EmailAttribute.TO, PageContext.PAGE_SCOPE);
pageContext.setAttribute("SUBJECT", i2p.bote.email.EmailAttribute.SUBJECT, PageContext.PAGE_SCOPE);
pageContext.setAttribute("DATE", i2p.bote.email.EmailAttribute.DATE, PageContext.PAGE_SCOPE);
%>
<c:set var="title" value="${param.path}" scope="request"/>
<jsp:include page="header.jsp"/>
<c:set var="folderName" value="${param.path}"/>
<c:if test="${empty folderName}">
<c:set var="folderName" value="Inbox"/>
</c:if>
<c:if test="${folderName == 'Inbox'}">
<div id="inboxFlag"></div>
</c:if>
<c:set var="sortcolumn" value="${DATE}"/>
<c:if test="${!empty param.sortcolumn}">
<c:set var="sortcolumn" value="${param.sortcolumn}"/>
</c:if>
<c:choose>
<c:when test="${empty param.descending}">
<%-- Use the default sort direction: descending for date, ascending for everything else --%>
<c:if test="${sortcolumn eq DATE}">
<c:set var="descending" value="true"/>
</c:if>
<c:if test="${sortcolumn ne DATE}">
<c:set var="descending" value="false"/>
</c:if>
</c:when>
<c:otherwise>
<%-- Set the sort direction depending on param.descending --%>
<c:set var="descending" value="false"/>
<c:if test="${param.descending}">
<c:set var="descending" value="true"/>
</c:if>
</c:otherwise>
</c:choose>
<c:if test="${!descending}">
<c:set var="sortIndicator" value="&#x25b4;"/>
<c:set var="reverseSortOrder" value="&descending=true"/>
</c:if>
<c:if test="${descending}">
<c:set var="sortIndicator" value="&#x25be;"/>
<c:set var="reverseSortOrder" value="&descending=false"/>
</c:if>
<div class="main">
<div class="folder">
<table class="table">
<c:set var="folder" value="${ib:getMailFolder(folderName)}"/>
<tr>
<th style="width: 100px;">
<c:set var="sortLink" value="folder.jsp?path=${param.path}&sortcolumn=${FROM}"/>
<c:if test="${sortcolumn eq FROM}">
<c:set var="sortLink" value="${sortLink}${reverseSortOrder}"/>
<c:set var="fromColumnIndicator" value=" ${sortIndicator}"/>
</c:if>
<a href="${sortLink}"><ib:message key="From"/>${fromColumnIndicator}</a>
</th>
<th style="width: 30px; text-align: center;"><ib:message key="Unkn."/></th>
<th style="width: 20px; text-align: center;"><ib:message key="Sig"/></th>
<th style="width: 100px;">
<c:set var="sortLink" value="folder.jsp?path=${param.path}&sortcolumn=${TO}"/>
<c:if test="${sortcolumn eq TO}">
<c:set var="sortLink" value="${sortLink}${reverseSortOrder}"/>
<c:set var="toColumnIndicator" value=" ${sortIndicator}"/>
</c:if>
<a href="${sortLink}"><ib:message key="To"/>${toColumnIndicator}</a>
</th>
<th style="width: 150px;">
<c:set var="sortLink" value="folder.jsp?path=${param.path}&sortcolumn=${SUBJECT}"/>
<c:if test="${sortcolumn eq SUBJECT}">
<c:set var="sortLink" value="${sortLink}${reverseSortOrder}"/>
<c:set var="subjectColumnIndicator" value=" ${sortIndicator}"/>
</c:if>
<a href="${sortLink}"><ib:message key="Subject"/>${subjectColumnIndicator}</a>
</th>
<th style="width: 100px;">
<c:set var="sortLink" value="folder.jsp?path=${param.path}&sortcolumn=${DATE}"/>
<c:if test="${sortcolumn eq DATE}">
<c:set var="sortLink" value="${sortLink}${reverseSortOrder}"/>
<c:set var="dateColumnIndicator" value=" ${sortIndicator}"/>
</c:if>
<a href="${sortLink}"><ib:message key="Sent"/>${dateColumnIndicator}</a>
</th>
<th style="width: 20px;"></th>
</tr>
<c:forEach items="${ib:getEmails(folder, sortcolumn, descending)}" var="email" varStatus="status">
<c:set var="sender" value="${ib:getNameAndDestination(email.sender)}"/>
<c:if test="${empty sender}">
<ib:message key="Anonymous" var="sender"/>
</c:if>
<c:if test="${email.signatureValid}">
<c:set var="signature" value="<div style='color: green;'>&#10004;</div>"/>
</c:if>
<c:if test="${!email.signatureValid}">
<c:set var="signature" value="<div style='color: red;'>&#10008;</div>"/>
</c:if>
<c:set var="recipient" value="${ib:getNameAndDestination(ib:getOneLocalRecipient(email))}"/>
<c:set var="subject" value="${email.subject}"/>
<c:if test="${empty subject}">
<ib:message key="(No subject)" var="subject"/>
</c:if>
<c:set var="mailUrl" value="showEmail.jsp?folder=${folderName}&messageID=${email.messageID}"/>
<c:choose>
<c:when test="${email.new}"><c:set var="fontWeight" value="bold"/></c:when>
<c:otherwise><c:set var="fontWeight" value="normal"/></c:otherwise>
</c:choose>
<c:set var="class" value=""/>
<c:if test="${status.index%2 != 0}">
<c:set var="class" value=" class=\"alttablecell\""/>
</c:if>
<tr>
<td><div${class}><a href="${mailUrl}" style="font-weight: ${fontWeight}">${fn:escapeXml(sender)}</a></div></td>
<td><div${class} style="text-align: center;">${!ib:isKnown(email.sender) ? '&#10007' : '&nbsp;'}</div></td>
<td><div${class} style="text-align: center;"><c:out value="${signature}" escapeXml="false"/></div></td>
<td><div${class}><a href="${mailUrl}" style="font-weight: ${fontWeight}">${fn:escapeXml(recipient)}</a></div></td>
<td><div${class}><a href="${mailUrl}" style="font-weight: ${fontWeight}">${fn:escapeXml(subject)}</a></div></td>
<td><div${class}><a href="${mailUrl}" style="font-weight: ${fontWeight}"><ib:emailDate email="${email}" timeStyle="short"/></a></div></td>
<td>
<div${class}>
<a href="deleteEmail.jsp?folder=${folderName}&messageID=${email.messageID}">
<img src="images/delete.png" alt="<ib:message key='Delete'/>" title="<ib:message key='Delete this email'/>"/></a>
</div>
</td>
</tr>
</c:forEach>
</table>
</div>
</div>
<jsp:include page="footer.jsp"/>

View File

@@ -1,92 +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="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="ib" uri="I2pBoteTags" %>
<fmt:requestEncoding value="UTF-8"/>
<jsp:useBean id="jspHelperBean" class="i2p.bote.web.JSPHelper"/>
<c:set var="configuration" value="${jspHelperBean.configuration}"/>
<fmt:setLocale value="${configuration.language}" scope="request"/>
<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" />
<c:if test="${!empty title}">
<title>${title} <ib:message key="- I2P-Bote"/></title>
</c:if>
</head>
<body>
<div class="titlebar" style="cursor:pointer" onclick="document.location='.'">
<div class="title"><ib:message key="I2P-Bote"/></div>
<br/>
<div class="subtitle"><ib:message key="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">
<iframe src="folders.jsp" width="100%" height="250px" scrolling="no" frameborder="0" allowtransparency="true"></iframe>
</div>
<div class="menubox">
<h2><ib:message key="Addresses"/></h2>
<a href="identities.jsp"><ib:message key="Identities"/></a><br/>
<a href="addressBook.jsp"><ib:message key="Address Book"/></a><br/>
Public Address Directory<br/>
</div>
<div class="menubox">
<h2><ib:message key="Configuration"/></h2>
<a href="settings.jsp"><ib:message key="Settings"/></a><br/>
</div>
<div class="menubox">
<h2><a href="network.jsp"><ib:message key="Network Status"/></a></h2>
<iframe src="statusFrame.jsp" width="100%" height="40px" scrolling="no" frameborder="0" allowtransparency="true"></iframe>
</div>
<div class="menubox">
<h2><ib:message key="Help"/></h2>
<ib:message key="User Guide"/><br/>
<a href="about.jsp"><ib:message key="About"/></a><br/>
</div>
<div class="infoMessage">
${fn:escapeXml(param.infoMessage)}
</div>
<div class="errorMessage">
${fn:escapeXml(param.errorMessage)}
</div>

View File

@@ -1,365 +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 {
font-size: 8pt;
font-weight: bold;
text-align: left;
}
.folderbox {
font-size: 8pt;
font-weight: bold;
text-align: left;
}
.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;
}
.emailtext {
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: #cce2ff;
-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;
}
button[disabled] {
border: 1px outset #999;
background: #ddf !important;
color: #666;
-moz-box-shadow: inset 0px 0px 0px 1px #999;
}
.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] {
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;
}
.widetextfield {
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: 9pt/130% "Lucida Sans Unicode", "Bitstream Vera Sans", Verdana, Tahoma, Helvetica, sans-serif;
min-height: 100px;
border: 1px solid #001;
}
.destinationtextarea {
width: 100%;
background: #eef;
background-color: transparent;
color: #003;
border: none;
font: 8pt "Lucida Console", "DejaVu Sans Mono", Courier, mono;
min-height: 100px;
}
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;
}
.table {
table-layout: fixed;
width: 800px;
}
.table td, th {
padding-left: 10px;
background: url('images/lightbluetile.png');
white-space: nowrap;
overflow-x: hidden;
}
.table td:first-child, th:first-child {
padding-left: 0px;
background: url('images/lightbluetile.png');
white-space: nowrap;
overflow-x: hidden;
}
.alttablecell
{
background: url('images/lightbluetile-alt.png');
white-space: nowrap;
overflow-x: hidden;
}
#address form span {
display: none;
}
#address form:hover span {
display: block;
padding: 3px;
}
wbr:after { content: "\00200B" } /* For Opera */

View File

@@ -1,104 +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:set var="title" value="Identities" scope="request"/>
<jsp:include page="header.jsp"/>
<div class="main">
<h2>
<ib:message key="Email Identities"/>
</h2>
<c:set var="identities" value="${ib:getIdentities().all}"/>
<c:if test="${empty identities}">
<ib:message key="No email identities are defined."/>
</c:if>
<table class="table">
<c:if test="${!empty identities}">
<tr>
<th style="width: 20px;"><ib:message key="Def."/></th>
<th><ib:message key="Public Name"/></th>
<th><ib:message key="Description"/></th>
<th><ib:message key="Email Address"/></th>
<th><ib:message key="Email Destination"/></th>
<th style="width: 20px"></th>
</tr>
</c:if>
<c:forEach items="${identities}" var="identity" varStatus="loopStatus">
<c:set var="class" value=""/>
<c:if test="${loopStatus.index%2 != 0}">
<c:set var="class" value=" class=\"alttablecell\""/>
</c:if>
<tr>
<td style="width: 20px; text-align: right;">
<div${class}>
<c:if test="${identity.default}">
<img src="images/asterisk.png"/>
</c:if>
</div>
</td>
<td style="width: 100px;">
<div${class}>
<jsp:useBean id="jspHelperBean" class="i2p.bote.web.JSPHelper"/>
<%-- Insert a random number into the request string so others can't see contacts or identities using the CSS history hack --%>
<a href="editIdentity.jsp?rnd=${jspHelperBean.randomNumber}&new=false&key=${identity.key}&cryptoImpl=${identity.cryptoImpl}&publicName=${ib:escapeQuotes(identity.publicName)}&description=${ib:escapeQuotes(identity.description)}&emailAddress=${ib:escapeQuotes(identity.emailAddress)}&isDefault=${identity.default}">
${identity.publicName}
</a>
</div>
</td>
<td style="width: 150px;">
<div${class}>
${identity.description}
</div>
</td>
<td style="width: 150px;">
<div${class}>
${identity.emailAddress}
</div>
</td>
<td style="width: 100px;">
<div${class}>
${identity.key}
</div>
</td>
<td>
<a href="deleteIdentity.jsp?key=${identity.key}"><img src="images/delete.png" alt="<ib:message key='Delete'/>" title="<ib:message key='Delete this identity'/>"/></a>
</td>
</tr>
</c:forEach>
</table>
<p/>
<form action="editIdentity.jsp?new=true" method="POST">
<button type="submit" value="New"><ib:message key="New Identity"/></button>
</form>
</div>
<jsp:include page="footer.jsp"/>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

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: 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,159 +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" %>
<%--
Valid actions:
<default> - show the "new email" form
send - send an email using the request data
addToAddrBook - add a recipient to the address book and return here
lookup - add one or more address book entries as recipients and return here
addRecipientField - add a recipient field
removeRecipient<i> - remove the recipient field with index i
Other parameters:
new - true for new contact, false for existing contact
--%>
<c:choose>
<c:when test="${param.action eq 'send'}">
<jsp:forward page="sendEmail.jsp"/>
</c:when>
<c:when test="${param.action eq 'addToAddrBook'}">
<c:set var="destparam" value="${param.destparamname}"/>
<jsp:forward page="editContact.jsp">
<jsp:param name="new" value="true"/>
<jsp:param name="destination" value="${ib:escapeQuotes(param[destparam])}"/>
<jsp:param name="forwardUrl" value="newEmail.jsp"/>
<jsp:param name="backUrl" value="newEmail.jsp"/>
<jsp:param name="paramsToCopy" value="recipient*,to*,cc*,bcc*,replyto*,subject,message,forwardUrl,backUrl,paramsToCopy"/>
</jsp:forward>
</c:when>
<c:when test="${param.action eq 'lookup'}">
<jsp:forward page="addressBook.jsp">
<jsp:param name="select" value="true"/>
<jsp:param name="forwardUrl" value="newEmail.jsp"/>
<jsp:param name="paramsToCopy" value="recipient*,to*,cc*,bcc*,replyto*,subject,message,forwardUrl"/>
</jsp:forward>
</c:when>
</c:choose>
<ib:message key="New Email" var="title"scope="request"/>
<jsp:include page="header.jsp"/>
<div class="main">
<form action="newEmail.jsp" method="post">
<table>
<tr>
<td>
<ib:message key="From:"/>
</td>
<td>
<select name="sender">
<option value="anonymous"><ib:message key="Anonymous"/></option>
<c:forEach items="${ib:getIdentities().all}" var="identity">
<c:set var="selected" value=""/>
<c:if test="${fn:contains(param.sender, identity.key)}">
<c:set var="selected" value=" selected"/>
</c:if>
<c:if test="${empty param.sender && identity.default}">
<c:set var="selected" value=" selected"/>
</c:if>
<option value="${identity.publicName} &lt;${identity.key}&gt;"${selected}>
${identity.publicName}
<c:if test="${!empty identity.description}"> - ${identity.description}</c:if>
</option>
</c:forEach>
</select>
</td>
</tr>
<%-- Add an address line for each recipient --%>
<c:set var="recipients" value="${ib:mergeRecipientFields(pageContext.request)}"/>
<c:forEach var="recipient" items="${recipients}" varStatus="status">
<c:set var="recipientField" value="recipient${status.index}"/>
<tr><td>
<c:set var="recipientTypeField" value="recipientType${status.index}"/>
<c:set var="recipientType" value="${param[recipientTypeField]}"/>
<select name="recipientType${status.index}">
<c:set var="toSelected" value="${recipientType eq 'to' ? ' selected' : ''}"/>
<c:set var="ccSelected" value="${recipientType eq 'cc' ? ' selected' : ''}"/>
<c:set var="bccSelected" value="${recipientType eq 'bcc' ? ' selected' : ''}"/>
<c:set var="replytoSelected" value="${recipientType eq 'replyto' ? ' selected' : ''}"/>
<option value="to"${toSelected}><ib:message key="To:"/></option>
<option value="cc"${ccSelected}><ib:message key="CC:"/></option>
<option value="bcc"${bccSelected}><ib:message key="BCC:"/></option>
<option value="replyto"${replytoSelected}><ib:message key="Reply To:"/></option>
</select>
</td><td>
<input type="text" size="80" name="${recipientField}" value="${ib:escapeQuotes(recipient.address)}"/>
<c:choose>
<c:when test="${status.last}">
<input type="hidden" name="destparamname" value="${recipientField}"/>
<button type="submit" name="action" value="addToAddrBook">&#x2794;<img src="images/addressbook.gif"/></button>
</c:when>
<c:otherwise>
<button type="submit" name="action" value="removeRecipient${status.index}">-</button>
</c:otherwise>
</c:choose>
</td></tr>
</c:forEach>
<tr>
<td/>
<td style="text-align: right;">
<button type="submit" name="action" value="addRecipientField">+</button>
<button type="submit" name="action" value="lookup"><ib:message key="Addr. Book..."/></button>
</td>
</tr>
<tr>
<td valign="top"><br/><ib:message key="Subject:"/></td>
<td><input class="widetextfield" type="text" size="80" name="subject" value="${ib:escapeQuotes(param.subject)}"/></td>
</tr>
<tr>
<td valign="top"><br/><ib:message key="Message:"/></td>
<td>
<textarea rows="30" cols="80" name="message"><c:if test="${!empty param.quoteMsgId}">
<%-- The following lines are not indented because the indentation would show up as blank chars on the textarea --%>
<c:set var="origEmail" value="${ib:getEmail(param.quoteMsgFolder, param.quoteMsgId)}"/>
<ib:message key="{0} wrote:" hide="true">
<ib:param value="${ib:getShortSenderName(origEmail.sender, 50)}"></ib:param>
</ib:message><ib:quote text="${fn:escapeXml(origEmail.text)}"/></c:if><c:if test="${empty param.quoteMsgId}">${fn:escapeXml(param.message)}</c:if></textarea>
</td>
</tr>
<tr>
<td colspan=3 align="center">
<button type="submit" name="action" value="send"><ib:message key="Send"/></button>
<button type="submit" name="action" disabled="disabled"><ib:message key="Save"/></button>
</td>
</tr>
</table>
</form>
</div>
<jsp:include page="footer.jsp"/>

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" %>
<c:set var="title" value="No Identity" scope="request"/>
<jsp:include page="header.jsp"/>
<div class="main">
<h2><ib:message key="No Email Identity Defined"/></h2>
<p>
<ib:message>
In order to receive email from other people, you need to create an email identity
first.
</ib:message>
</p><p>
<ib:message>
Every email identity is associated with an email destination. Anybody can send email
to the email destination, but only the identity holder can read it.
</ib:message>
<br/>
<ib:message>
In a sense, email identities are the equivalent to traditional email accounts -
except that there is no provider that can read all your email because I2P-Bote
stores all emails encrypted on the network.
</ib:message>
</p><p>
<ib:message>
I2P-Bote automatically decrypts emails sent to you, using the email identity you
created. Email identities are stored in a file named identities.txt; never give
this file to anyone or they will be able to read all your emails.
</ib:message>
<br/>
<ib:message>
Do give out the email destination so others can contact you.
</ib:message>
</p><p>
<ib:message>
It is easy to create multiple identities for different purposes, or different
contacts.
</ib:message>
</p><p>
<ib:message>
When you create a new email identity, you can choose the type of encryption that
will be used by the email identity. While all encryption algorithms offered by
I2P-Bote provide a high level of privacy, the length of an email destination
depends on the encryption used. The higher the number of bits, the longer the
email destination.
</ib:message>
<br/>
<ib:message>
Note that the same is not true for encryption strength. 256-bit elliptic curve
encryption is equivalent in strength to 3072-bit ElGamal. 521-bit elliptic curve
is equivalent to 15360-bit ElGamal.
</ib:message>
<form action="editIdentity.jsp?new=true" method="POST">
<button type="submit" value="New"><ib:message key="Create a New Email Identity"/></button>
</form>
</div>
<jsp:include page="footer.jsp"/>

View File

@@ -1,128 +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)}"/>
<c:if test="${fn:toLowerCase(param.folder) ne 'outbox'}">
<ib:setEmailRead folder="${ib:getMailFolder(param.folder)}" messageId="${param.messageID}" read="true"/>
</c:if>
<c:set var="title" value="${email.subject}" scope="request"/>
<jsp:include page="header.jsp"/>
<div class="emailtext">
<table>
<tr>
<td valign="top"><strong><ib:message key="From:"/></strong></td>
<td>
<c:if test="${email.anonymous}">
<ib:message key="Anonymous"/>
</c:if>
<c:if test="${!email.anonymous}">
<ib:address address="${email.sender}"/>
</c:if>
</td>
</tr>
<tr>
<td valign="top"><strong><ib:message key="Signature:"/></strong></td>
<td>
<c:if test="${email.signatureValid}"><ib:message key="Valid"/></c:if>
<c:if test="${!email.signatureValid}"><div style="color: red;"><ib:message key="Invalid or missing"/></div></c:if>
</td>
</tr>
<c:forEach var="replyToAddress" varStatus="status" items="${email.replyToAddresses}">
<tr>
<td valign="top"><strong><ib:message key="Reply To:"/></strong></td>
<td><ib:address address="${replyToAddress}"/></td>
</tr>
</c:forEach>
<c:forEach var="toAddress" varStatus="status" items="${email.toAddresses}">
<tr>
<td valign="top"><strong><ib:message key="To:"/></strong></td>
<td><ib:address address="${toAddress}"/></td>
</tr>
</c:forEach>
<c:forEach var="ccAddress" varStatus="status" items="${email.CCAddresses}">
<tr>
<td valign="top"><strong><ib:message key="CC:"/></strong></td>
<td><ib:address address="${ccAddress}"/></td>
</tr>
</c:forEach>
<c:forEach var="bccAddress" varStatus="status" items="${email.BCCAddresses}">
<tr>
<td valign="top"><strong><ib:message key="BCC:"/></strong></td>
<td><ib:address address="${bccAddress}"/></td>
</tr>
</c:forEach>
<tr>
<td valign="top"><strong><ib:message key="Sent:"/></strong></td>
<td><ib:emailDate email="${email}" timeStyle="full"/></td>
</tr>
<tr>
<td valign="top"><strong><ib:message key="Subject:"/></strong></td>
<td>${fn:escapeXml(email.subject)}</td>
</tr>
<tr>
<td valign="top"><strong><ib:message key="Message:"/></strong></td>
<td><ib:formatPlainText text="${fn:escapeXml(email.text)}"/></td>
</tr>
<tr>
<td colspan="2">
<table><tr>
<td>
<form action="newEmail.jsp" method="post">
<c:set var="replyDisabled" value="${email.anonymous ? 'disabled=&quot;disabled&quot;' : ''}"/>
<button type="submit"${replyDisabled}><ib:message key="Reply"/></button>
<input type="hidden" name="sender" value="${ib:escapeQuotes(ib:getOneLocalRecipient(email))}"/>
<input type="hidden" name="recipient0" value="${ib:escapeQuotes(email.sender)}"/>
<ib:message key="Re:" var="responsePrefix" hide="true"/>
<c:set var="responsePrefix" value="${responsePrefix} "/>
<c:if test="${fn:startsWith(email.subject, responsePrefix)}">
<c:set var="responsePrefix" value=""/>
</c:if>
<input type="hidden" name="subject" value="${responsePrefix}${ib:escapeQuotes(email.subject)}"/>
<input type="hidden" name="quoteMsgFolder" value="${param.folder}"/>
<input type="hidden" name="quoteMsgId" value="${param.messageID}"/>
</form>
</td><td>
<form action="deleteEmail.jsp" method="post">
<button type="submit"><ib:message key="Delete"/></button>
<input type="hidden" name="folder" value="${param.folder}"/>
<input type="hidden" name="messageID" value="${email.messageID}"/>
</form>
</td>
</tr></table>
</td>
</tr>
</table>
</div>
<jsp:include page="footer.jsp"/>

View File

@@ -1,59 +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="getStatus.jsp"/>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="i2pbote.css" />
<meta http-equiv="refresh" content="20" />
</head>
<body style="background-color: transparent; margin: 0px;">
<div class="statusbox">
<c:choose>
<c:when test="${connStatus == NOT_STARTED}"><img src="images/redsquare.png"/> <ib:message key="Not Started"/></c:when>
<c:when test="${connStatus == DELAY}"><img src="images/yellowsquare.png"/> <ib:message key="Waiting 3 Minutes..."/><br/>
<div style="text-align: center">
<%-- When the connect button is clicked, refresh the entire page so the buttons in buttonFrame.jsp are enabled --%>
<form action="connect.jsp" target="_top" method="GET">
<button type="submit"><ib:message key="Connect Now"/></button>
</form>
</div>
</c:when>
<c:when test="${connStatus == CONNECTING}"><img src="images/yellowsquare.png"/> <ib:message key="Connecting..."/></c:when>
<c:when test="${connStatus == CONNECTED}"><img src="images/greensquare.png"/> <ib:message key="Connected"/></c:when>
<c:when test="${connStatus == ERROR}"><img src="images/redsquare.png"/> <ib:message key="Error"/></c:when>
<c:otherwise> <ib:message key="Unknown Status"/></c:otherwise>
</c:choose>
</div>
</body>
</html>

813
build.xml
View File

@@ -1,46 +1,200 @@
<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="help" name="I2P-Bote">
<property name="i2pbase" value="../i2p"/>
<property name="i2plib" value="${i2pbase}/core/java/build"/>
<property name="jettylib" value="${i2pbase}/apps/jetty/jettylib"/>
<property name="antlib" value="${jettylib}"/>
<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="WebContent/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="${java.class.path}" />
<pathelement location="${i2plib}/i2p.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="${jstllib}/jstl.jar" />
<pathelement location="${jstllib}/standard.jar" />
<pathelement location="${lib}/mailapi.jar" />
<pathelement location="${lib}/bcprov-ecc-jdk16-145.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>
<pathconvert property="manifest.classpath" pathsep=" ">
<path refid="cp" />
<mapper>
<flattenmapper />
</mapper>
</pathconvert>
<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=" $I2P must point to an I2P installation." />
<echo message=" all: war + plugin" />
<echo message=" src: Zips up the source code" />
<echo message=" junit: Runs all unit tests" />
<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, war, plugin" />
<target name="all" depends="clean, src, war, plugin" />
<target name="compile">
<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"
srcdir="./src/main/java"
debug="true"
deprecation="on"
source="1.6" target="1.6"
includeAntRuntime="false"
destdir="./ant_build/classes"
classpathref="cp"
failonerror="true" />
@@ -62,36 +216,44 @@
<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.6" target="1.6"
includeAntRuntime="false"
destdir="ant_build/classes"
srcdir="./ant_build/jspjava"
includes="**/*.java"
classpathref="jspcp"
failonerror="true" />
<copy file="WebContent/WEB-INF/web.xml" tofile="ant_build/web.xml" />
<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,bundle">
<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/built-in-peers.txt" />
<fileset dir="WebContent" includes="index.html"/>
<fileset dir="WebContent" includes="*.css"/>
<fileset dir="WebContent/" includes="*.xml"/>
<webinf dir="WebContent/WEB-INF/tlds" includes="*.tld"/>
<lib file="${lib}/mailapi.jar"/>
<lib file="${lib}/bcprov-ecc-jdk16-145.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:"/>
@@ -100,9 +262,43 @@
</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.
- Only the initial install includes mailapi.jar.
- 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.
@@ -112,9 +308,9 @@
<mkdir dir="plugin/plugin.tmp/console/webapps" />
<copy file="plugin/webapps.config" todir="plugin/plugin.tmp/console/" />
<!-- run i2pbote-plugin.war through pack200 -->
<!-- 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" failifexecutionfails="true">
<exec executable="pack200" failonerror="true">
<arg value="--no-gzip"/>
<arg value="--effort=9"/>
<arg value="--modification-time=latest"/>
@@ -122,103 +318,331 @@
<arg value="plugin/plugin.tmp/console/webapps/i2pbote.jar"/>
</exec>
<delete file="plugin/plugin.tmp/console/webapps/i2pbote.jar" />
<!-- run bcprov-ecc-jdk16-145.jar through pack200 -->
<exec executable="pack200" failifexecutionfails="true">
<exec executable="pack200" failonerror="true">
<arg value="--no-gzip"/>
<arg value="--effort=9"/>
<arg value="--modification-time=latest"/>
<arg value="plugin/plugin.tmp/lib/bcprov-ecc-jdk16-145.jar.pack"/>
<arg value="${lib}/bcprov-ecc-jdk16-145.jar"/>
<arg value="plugin/plugin.tmp/lib/i2pbote.jar.pack"/>
<arg value="${lib}/i2pbote.jar"/>
</exec>
<delete file="plugin/plugin.tmp/lib/mailapi.jar" />
<delete file="plugin/plugin.tmp/lib/mailapi.jar.pack" />
<!-- 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" failifexecutionfails="true" output="plugin/plugin.tmp/plugin.config" append="true">
<arg value="version=${version}-b${build.number}" />
<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" failifexecutionfails="true" output="plugin/plugin.tmp/plugin.config" append="true">
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.tmp/plugin.config" append="true">
<arg value="update-only=true" />
</exec>
<exec executable="${makeplugin}" failifexecutionfails="true" >
<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 -->
<exec executable="pack200" failifexecutionfails="true">
<arg value="--no-gzip"/>
<arg value="--effort=9"/>
<arg value="--modification-time=latest"/>
<arg value="plugin/plugin.tmp/lib/mailapi.jar.pack"/>
<arg value="${lib}/mailapi.jar"/>
</exec>
<copy file="plugin/plugin.config" todir="plugin/plugin.tmp" overwrite="true" />
<exec executable="echo" osfamily="unix" failifexecutionfails="true" output="plugin/plugin.tmp/plugin.config" append="true">
<arg value="version=${version}-b${build.number}" />
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.tmp/plugin.config" append="true">
<arg value="version=${version}" />
</exec>
<exec executable="${makeplugin}" >
<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,precompilejsp,bundle">
<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="**/*.class" />
<classes dir="src" includes="i2p/bote/network/built-in-peers.txt" />
<fileset dir="WebContent" includes="index.html"/>
<fileset dir="WebContent" includes="*.css"/>
<fileset dir="WebContent/" includes="*.xml"/>
<webinf dir="WebContent/WEB-INF/tlds" includes="*.tld"/>
<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"/>
<zipfileset dir="src/main/webapp/html" prefix="html"/>
<zipfileset dir="src/main/webapp/themes" prefix="themes"/>
</war>
</target>
<target name="bundle">
<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 fai
l property to true -->
We need to supply the bat file for windows, and then change the fail property to true -->
<exec executable="sh" osfamily="unix" failifexecutionfails="false" >
<arg value="./bundle-messages.sh" />
<arg value="src/build/scripts/bundle-messages.sh" />
</exec>
<exec executable="sh" osfamily="mac" failifexecutionfails="false" >
<arg value="./bundle-messages.sh" />
<arg value="src/build/scripts/bundle-messages.sh" />
</exec>
<exec executable="cmd" osfamily="windows" failifexecutionfails="false" >
<arg value="/c" />
<arg value="bundle-messages.bat" />
<exec executable="sh" osfamily="windows" failifexecutionfails="false" >
<arg value="src/build/scripts/bundle-messages.sh" />
</exec>
</target>
<target name="poupdate" depends="compilejspstrings">
<!-- 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" failifexecutionfails="true" >
<arg value="./bundle-messages.sh" />
<exec executable="sh" osfamily="unix" failonerror="true" >
<arg value="src/build/scripts/bundle-messages.sh" />
<arg value="-p" />
</exec>
<exec executable="sh" osfamily="mac" failifexecutionfails="true" >
<arg value="./bundle-messages.sh" />
<exec executable="sh" osfamily="mac" failonerror="true" >
<arg value="src/build/scripts/bundle-messages.sh" />
<arg value="-p" />
</exec>
<exec executable="cmd" osfamily="windows" failifexecutionfails="true" >
<arg value="/c" />
<arg value="bundle-messages.bat" />
<exec executable="sh" osfamily="windows" failifexecutionfails="true" >
<arg value="src/build/scripts/bundle-messages.sh" />
<arg value="-p" />
</exec>
</target>
<target name="compilejspstrings" depends="compile">
<!-- compiles the Java code in the ant directory -->
<target name="compileantclasses" depends="compile">
<javac
srcdir="./ant"
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"
@@ -226,20 +650,35 @@ l property to true -->
</target>
<target name="junit" depends="compile">
<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.jar"/>
<pathelement location="${lib}/${junit.filename}"/>
<pathelement location="${lib}/${mockito.filename}"/>
<pathelement path="${jmockcp}"/>
<pathelement location="./ant_build/classes"/>
<path refid="cp"/>
</path>
<javac
srcdir="./test"
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="junitcp"/>
@@ -258,12 +697,129 @@ l property to true -->
<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="./ant"
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"
@@ -278,22 +834,17 @@ l property to true -->
<echo message="I2P-Bote version is ${version}"/>
</target>
<!-- depends on compile b/c it gets the app version from I2PBote.class -->
<target name="src" depends="getversion">
<property name="subdir" value="i2pbote-${version}-src"/>
<zip destfile="src.zip">
<zipfileset dir="src" prefix="${subdir}/src"/>
<zipfileset dir="WebContent" prefix="${subdir}/WebContent" followsymlinks="false"/>
<zipfileset dir="test" prefix="${subdir}/test"/>
<zipfileset dir="ant" prefix="${subdir}/ant"/>
<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="bundle-messages.sh" prefix="${subdir}"/>
<zipfileset file="jsp2po.sh" prefix="${subdir}"/>
<zipfileset file="src/build/scripts/bundle-messages.sh" prefix="${subdir}"/>
<zipfileset file="history.txt" prefix="${subdir}"/>
<zipfileset file="license.txt" prefix="${subdir}"/>
</zip>
@@ -304,13 +855,81 @@ l property to true -->
</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

View File

@@ -1,6 +1,99 @@
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

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

@@ -2,5 +2,9 @@ LICENSES
--------
This software is licensed under the GPL version 3 (see licenses/GPLv3.txt),
except for bcprov-ecc-jdk16-145.jar which is licensed under the
Bouncy Castle License (see licenses/BouncyCastle.txt).
except for:
- 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).

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

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>

View File

@@ -1,12 +1,44 @@
name=i2pbote
signer=HungryHobo@mail.i2p
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
websiteURL=http://tjgidoycrw6s3guetge3kvrvynppqjmvqsosmtbmgqasa6vmsf6a.b32.i2p/
updateURL=http://tjgidoycrw6s3guetge3kvrvynppqjmvqsosmtbmgqasa6vmsf6a.b32.i2p/i2pbote-update.xpi2p
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
author=HungryHobo@mail.i2p
min-i2p-version=0.9.18
author=str4d@mail.i2p

View File

@@ -1 +1 @@
webapps.i2pbote.classpath=$I2P/lib/jstl.jar,$I2P/lib/standard.jar,$PLUGIN/lib/mailapi.jar,$PLUGIN/lib/bcprov-ecc-jdk16-145.jar
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

@@ -34,7 +34,7 @@ import java.util.ArrayList;
import java.util.List;
/**
* Extracts strings from <ib:message> tags and prints them
* 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 {
@@ -51,8 +51,8 @@ public class JspStrings {
List<PoEntry> poEntries = processDirectory(new File(args[0]));
removeDuplicates(poEntries);
for (PoEntry poEntry: poEntries)
print(poEntry);
for (PoEntry poEntry: poEntries)
print(poEntry);
}
static void removeDuplicates(List<PoEntry> poEntries) {
@@ -114,64 +114,79 @@ public class JspStrings {
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>();
// Process all tags of the format <ib:message>foobar</ib:message>
String[] noAttributeTags = fileContents.split("<ib:message>");
List<String> msgKeys = (extractFromTagBody(noAttributeTags));
entries.addAll(PoEntry.create(msgKeys, file));
// Process all tags of the format <ib:message key="foobar".../>, as well as
// <ib:message key="foo {0}"><ib:param value="bar"/></ib:message>
String[] attributeTags = fileContents.split("<ib:message ");
msgKeys = extractFromKeyAttribute(attributeTags);
entries.addAll(PoEntry.create(msgKeys, file));
return entries;
}
/** Extracts the text between each pair of <ib:message> and </ib:message> tags */
static List<String> extractFromTagBody(String[] strings) {
List<String> keys = new ArrayList<String>();
for (int i=1; i<strings.length; i++) {
String element = strings[i];
int endIdx = element.indexOf("</ib:message");
if (endIdx < 0) {
System.err.println("No \"</ib:message\" end tag in string: <" + element + ">");
continue;
}
String str = element.substring(0, endIdx);
// convert multiple whitespaces in a row to a single space, remove leading and trailing whitespace
str = Util.removeExtraWhitespace(str);
keys.add(str);
}
return keys;
/**
* 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 values of all "key" attributes */
static List<String> extractFromKeyAttribute(String[] strings) {
/**
* 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();
List<String> keys = new ArrayList<String>();
for (int i=1; i<strings.length; i++) {
String element = strings[i];
int startIdxSQ = element.indexOf(keyAttrSQ);
int endIdxSQ = element.indexOf("'", startIdxSQ+keyAttrLen);
int startIdxDQ = element.indexOf(keyAttrDQ);
int endIdxDQ = element.indexOf("\"", startIdxDQ+keyAttrLen);
String message;
if (startIdxSQ>=0 && (startIdxSQ<startIdxDQ || startIdxDQ<0) && endIdxSQ>=0)
message = element.substring(startIdxSQ+keyAttrLen, endIdxSQ);
else if (startIdxDQ>=0 && (startIdxDQ<startIdxSQ || startIdxSQ<0) && endIdxDQ>=0)
message = element.substring(startIdxDQ+keyAttrLen, endIdxDQ);
else {
System.err.println("Expected a string containing key=\"...\" or key='...', got " + element);
continue;
}
keys.add(message);
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;
}
return keys;
}
/** 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 {

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

@@ -1,3 +1,4 @@
#!/bin/sh
#
# Update messages_xx.po and messages_xx.class files,
# from both java and jsp sources.
@@ -21,15 +22,29 @@ 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"
JSPPATHS="WebContent"
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
@@ -65,7 +80,7 @@ do
fi
# extract strings from jsp files
$JAVA -cp ant_build/classes i2p.bote.ant.JspStrings WebContent >> ${i}t
$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'
@@ -86,15 +101,19 @@ do
touch $i
fi
echo "Generating ${CLASS}_$LG ResourceBundle..."
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
# 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

View File

@@ -1,453 +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.Locale;
import java.util.Properties;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
import net.i2p.util.Translate;
public class Configuration {
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 DHT_PEER_FILE_NAME = "dht_peers.txt";
private static final String RELAY_PEER_FILE_NAME = "relay_peers.txt";
private static final String IDENTITIES_FILE_NAME = "identities.txt";
private static final String ADDRESS_BOOK_FILE_NAME = "addressBook.txt";
private static final String MESSAGE_ID_CACHE_FILE = "msgidcache.txt";
private static final String OUTBOX_DIR = "outbox"; // relative to I2P_BOTE_SUBDIR
private static final String RELAY_PKT_SUBDIR = "relay_pkt"; // relative to I2P_BOTE_SUBDIR
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
private static final String SENT_FOLDER_DIR = "sent"; // relative to I2P_BOTE_SUBDIR
private static final String TRASH_FOLDER_DIR = "trash"; // 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";
private static final String PARAMETER_AUTO_MAIL_CHECK = "autoMailCheckEnabled";
private static final String PARAMETER_MAIL_CHECK_INTERVAL = "mailCheckInterval";
private static final String PARAMETER_LANGUAGE = "locale";
private static final String PARAMETER_HIDE_LOCALE = "hideLocale";
private static final String PARAMETER_INCLUDE_SENT_TIME = "includeSentTime";
private static final String PARAMETER_MESSAGE_ID_CACHE_SIZE = "messageIdCacheSize";
private static final String PARAMETER_RELAY_REDUNDANCY = "relayRedundancy";
private static final String PARAMETER_RELAY_MIN_DELAY = "relayMinDelay";
private static final String PARAMETER_RELAY_MAX_DELAY = "relayMaxDelay";
private static final String PARAMETER_NUM_STORE_HOPS = "numSendHops";
private static final String PARAMETER_GATEWAY_DESTINATION = "gatewayDestination";
private static final String PARAMETER_GATEWAY_ENABLED = "gatewayEnabled";
// 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 static final boolean DEFAULT_AUTO_MAIL_CHECK = true;
private static final int DEFAULT_MAIL_CHECK_INTERVAL = 30; // in minutes
private static final String DEFAULT_LANGUAGE = Locale.getDefault().getLanguage();
private static final boolean DEFAULT_HIDE_LOCALE = true;
private static final boolean DEFAULT_INCLUDE_SENT_TIME = true;
private static final int DEFAULT_MESSAGE_ID_CACHE_SIZE = 1000; // the maximum number of message IDs to cache
private static final int DEFAULT_RELAY_REDUNDANCY = 5; // lower than the DHT redundancy because only the highest-uptime peers are used for relaying
private static final int DEFAULT_RELAY_MIN_DELAY = 120; // in minutes
private static final int DEFAULT_RELAY_MAX_DELAY = 600; // in minutes
private static final int DEFAULT_NUM_STORE_HOPS = 0;
private static final String DEFAULT_GATEWAY_DESTINATION = "";
private static final boolean DEFAULT_GATEWAY_ENABLED = true;
private Log log = new Log(Configuration.class);
private Properties properties;
private File i2pBoteDir;
private File configFile;
/**
* 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() {
properties = new Properties();
// get the I2PBote directory and make sure it exists
i2pBoteDir = getI2PBoteDirectory();
if (!i2pBoteDir.exists() && !i2pBoteDir.mkdirs())
log.error("Cannot create directory: <" + i2pBoteDir.getAbsolutePath() + ">");
// read the configuration file
configFile = new File(i2pBoteDir, CONFIG_FILE_NAME);
boolean configurationLoaded = false;
if (configFile.exists()) {
log.info("Loading config file <" + configFile.getAbsolutePath() + ">");
try {
DataHelper.loadProps(properties, 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.");
// Apply the language setting if there is one in the config file
setLanguage(getLanguage());
}
public File getDestinationKeyFile() {
return new File(i2pBoteDir, DEST_KEY_FILE_NAME);
}
public File getDhtPeerFile() {
return new File(i2pBoteDir, DHT_PEER_FILE_NAME);
}
public File getRelayPeerFile() {
return new File(i2pBoteDir, RELAY_PEER_FILE_NAME);
}
public File getIdentitiesFile() {
return new File(i2pBoteDir, IDENTITIES_FILE_NAME);
}
public File getAddressBookFile() {
return new File(i2pBoteDir, ADDRESS_BOOK_FILE_NAME);
}
public File getMessageIdCacheFile() {
return new File(i2pBoteDir, MESSAGE_ID_CACHE_FILE);
}
public File getOutboxDir() {
return new File(i2pBoteDir, OUTBOX_DIR);
}
public File getRelayPacketDir() {
return new File(i2pBoteDir, RELAY_PKT_SUBDIR);
}
public File getSentFolderDir() {
return new File(i2pBoteDir, SENT_FOLDER_DIR);
}
public File getTrashFolderDir() {
return new File(i2pBoteDir, TRASH_FOLDER_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
*/
public void save() {
log.debug("Saving config file <" + configFile.getAbsolutePath() + ">");
try {
DataHelper.storeProps(properties, configFile);
} catch (IOException e) {
log.error("Cannot save configuration to file <" + configFile.getAbsolutePath() + ">", e);
}
}
/**
* 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);
}
public void setAutoMailCheckEnabled(boolean enabled) {
properties.setProperty(PARAMETER_AUTO_MAIL_CHECK, new Boolean(enabled).toString());
}
public boolean isAutoMailCheckEnabled() {
return getBooleanParameter(PARAMETER_AUTO_MAIL_CHECK, DEFAULT_AUTO_MAIL_CHECK);
}
public void setMailCheckInterval(int minutes) {
properties.setProperty(PARAMETER_MAIL_CHECK_INTERVAL, Integer.valueOf(minutes).toString());
}
/**
* Returns the number of minutes the application should wait before automatically
* checking for mail.
* @return
*/
public int getMailCheckInterval() {
return getIntParameter(PARAMETER_MAIL_CHECK_INTERVAL, DEFAULT_MAIL_CHECK_INTERVAL);
}
/**
* Sets the UI language.
* @param languageCode A two-letter language code such as "en" or "de", or null for the system default.
*/
public void setLanguage(String languageCode) {
if (languageCode == null) {
properties.remove(PARAMETER_LANGUAGE);
System.clearProperty(Translate.PROP_LANG);
}
else {
properties.setProperty(PARAMETER_LANGUAGE, languageCode);
// Set the language used by i2p.bote.Util._().
// This may interfere with other I2P apps.
// Unfortunately, there is no setProperty() in I2PAppContext.
System.setProperty(Translate.PROP_LANG, languageCode);
}
}
/**
* Returns the two-letter language code for the current locale.
* @return
*/
public String getLanguage() {
return properties.getProperty(PARAMETER_LANGUAGE, DEFAULT_LANGUAGE);
}
/**
* Returns the current locale.
* @return
*/
public Locale getLocale() {
return new Locale(getLanguage());
}
/**
* Returns all locales for which a translation exists.
* @return
*/
public Locale[] getAllLocales() {
return I2PBote.getInstance().getAllLocales();
}
/**
* Controls whether strings that are added to outgoing email, like "Re:" or "Fwd:",
* are translated or not.
* If <code>hideLocale</code> is <code>false</code>, the UI language is used.
* If <code>hideLocale</code> is <code>true</code>, the strings are left untranslated
* (which means they are in English).
* @param hideLocale
*/
public void setHideLocale(boolean hideLocale) {
properties.setProperty(PARAMETER_HIDE_LOCALE, Boolean.valueOf(hideLocale).toString());
}
public boolean getHideLocale() {
return getBooleanParameter(PARAMETER_HIDE_LOCALE, DEFAULT_HIDE_LOCALE);
}
/**
* Controls whether the send time is included in outgoing emails.
* @param includeSentTime
*/
public void setIncludeSentTime(boolean includeSentTime) {
properties.setProperty(PARAMETER_INCLUDE_SENT_TIME, Boolean.valueOf(includeSentTime).toString());
}
public boolean getIncludeSentTime() {
return getBooleanParameter(PARAMETER_INCLUDE_SENT_TIME, DEFAULT_INCLUDE_SENT_TIME);
}
public int getMessageIdCacheSize() {
return getIntParameter(PARAMETER_MESSAGE_ID_CACHE_SIZE, DEFAULT_MESSAGE_ID_CACHE_SIZE);
}
/**
* Returns the number of relay chains that should be used per Relay Request.
* @return
*/
public int getRelayRedundancy() {
return getIntParameter(PARAMETER_RELAY_REDUNDANCY, DEFAULT_RELAY_REDUNDANCY);
}
/**
* Sets the minimum amount of time that a Relay Request is delayed.
* @param minDelay The minimum delay in minutes
*/
public void setRelayMinDelay(int minDelay) {
properties.setProperty(PARAMETER_RELAY_MIN_DELAY, Integer.valueOf(minDelay).toString());
}
public int getRelayMinDelay() {
return getIntParameter(PARAMETER_RELAY_MIN_DELAY, DEFAULT_RELAY_MIN_DELAY);
}
/**
* Sets the maximum amount of time that a Relay Request is delayed.
* @param minDelay The minimum delay in minutes
*/
public void setRelayMaxDelay(int maxDelay) {
properties.setProperty(PARAMETER_RELAY_MAX_DELAY, Integer.valueOf(maxDelay).toString());
}
/**
* Returns the maximum amount of time in minutes that a Relay Request is delayed.
* @return
*/
public int getRelayMaxDelay() {
return getIntParameter(PARAMETER_RELAY_MAX_DELAY, DEFAULT_RELAY_MAX_DELAY);
}
/**
* Returns the number of relays that should be used when sending a DHT store request.
* @return
*/
public void setNumStoreHops(int numHops) {
properties.setProperty(PARAMETER_NUM_STORE_HOPS, Integer.valueOf(numHops).toString());
}
public int getNumStoreHops() {
return getIntParameter(PARAMETER_NUM_STORE_HOPS, DEFAULT_NUM_STORE_HOPS);
}
public void setGatewayDestination(String destination) {
properties.setProperty(PARAMETER_GATEWAY_DESTINATION, destination);
}
public String getGatewayDestination() {
return properties.getProperty(PARAMETER_GATEWAY_DESTINATION, DEFAULT_GATEWAY_DESTINATION);
}
public void setGatewayEnabled(boolean enable) {
properties.setProperty(PARAMETER_GATEWAY_ENABLED, Boolean.valueOf(enable).toString());
}
public boolean isGatewayEnabled() {
return getBooleanParameter(PARAMETER_GATEWAY_ENABLED, DEFAULT_GATEWAY_ENABLED);
}
private boolean getBooleanParameter(String parameterName, boolean defaultValue) {
String stringValue = properties.getProperty(parameterName);
if ("true".equalsIgnoreCase(stringValue) || "yes".equalsIgnoreCase(stringValue) || "on".equalsIgnoreCase(stringValue) || "1".equals(stringValue))
return true;
else if ("false".equalsIgnoreCase(stringValue) || "no".equalsIgnoreCase(stringValue) || "off".equalsIgnoreCase(stringValue) || "0".equals(stringValue))
return false;
else if (stringValue == null)
return defaultValue;
else {
log.warn("<" + stringValue + "> is not a legal value for the boolean parameter <" + parameterName + ">");
return defaultValue;
}
}
private int getIntParameter(String parameterName, int defaultValue) {
String stringValue = properties.getProperty(parameterName);
if (stringValue == null)
return defaultValue;
else
try {
return new Integer(stringValue);
}
catch (NumberFormatException e) {
log.warn("Can't convert value <" + stringValue + "> for parameter <" + parameterName + "> to int, using default.");
return defaultValue;
}
}
}

View File

@@ -1,585 +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.addressbook.AddressBook;
import i2p.bote.email.Email;
import i2p.bote.email.EmailIdentity;
import i2p.bote.email.Identities;
import i2p.bote.folder.EmailFolder;
import i2p.bote.folder.EmailPacketFolder;
import i2p.bote.folder.IncompleteEmailFolder;
import i2p.bote.folder.IndexPacketFolder;
import i2p.bote.folder.MessageIdCache;
import i2p.bote.folder.Outbox;
import i2p.bote.folder.RelayPacketFolder;
import i2p.bote.folder.TrashFolder;
import i2p.bote.locale.Locales;
import i2p.bote.network.BanList;
import i2p.bote.network.BannedPeer;
import i2p.bote.network.CheckEmailTask;
import i2p.bote.network.DHT;
import i2p.bote.network.DhtPeerStats;
import i2p.bote.network.I2PPacketDispatcher;
import i2p.bote.network.I2PSendQueue;
import i2p.bote.network.NetworkStatus;
import i2p.bote.network.RelayPacketHandler;
import i2p.bote.network.RelayPeer;
import i2p.bote.network.kademlia.KademliaDHT;
import i2p.bote.packet.EncryptedEmailPacket;
import i2p.bote.packet.IndexPacket;
import i2p.bote.service.AutoMailCheckTask;
import i2p.bote.service.I2PBoteThread;
import i2p.bote.service.OutboxListener;
import i2p.bote.service.OutboxProcessor;
import i2p.bote.service.POP3Service;
import i2p.bote.service.RelayPacketSender;
import i2p.bote.service.RelayPeerManager;
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.Locale;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
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. It is implemented as a singleton.
*/
public class I2PBote {
public static final int PROTOCOL_VERSION = 3;
private static final String APP_VERSION = "0.2.4";
private static final int STARTUP_DELAY = 3; // the number of minutes to wait before connecting to I2P (this gives the router time to get ready)
private static volatile I2PBote instance;
private Log log = new Log(I2PBote.class);
private I2PClient i2pClient;
private I2PSession i2pSession;
private Configuration configuration;
private Identities identities;
private AddressBook addressBook;
private I2PSendQueue sendQueue;
private Outbox outbox; // stores outgoing emails for all local users
private EmailFolder inbox; // stores incoming emails for all local users
private EmailFolder sentFolder;
private TrashFolder trashFolder;
private RelayPacketFolder relayPacketFolder; // stores email packets we're forwarding for other machines
private IncompleteEmailFolder incompleteEmailFolder; // stores email packets addressed to a local user
private EmailPacketFolder emailDhtStorageFolder; // stores email 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 AutoMailCheckTask autoMailCheckTask;
private ExpirationThread expirationThread;
private RelayPacketSender relayPacketSender; // reads packets stored in the relayPacketFolder and sends them
private DHT dht;
private RelayPeerManager peerManager;
private ThreadFactory mailCheckThreadFactory;
private ExecutorService mailCheckExecutor;
private Collection<Future<Boolean>> pendingMailCheckTasks;
private long lastMailCheckTime;
private ConnectTask connectTask;
private I2PBote() {
Thread.currentThread().setName("I2PBoteMain");
I2PAppContext appContext = new I2PAppContext();
appContext.addShutdownTask(new Runnable() {
@Override
public void run() {
shutDown();
}
});
i2pClient = I2PClientFactory.createClient();
configuration = new Configuration();
mailCheckThreadFactory = Util.createThreadFactory("ChkMailTask", CheckEmailTask.THREAD_STACK_SIZE);
identities = new Identities(configuration.getIdentitiesFile());
addressBook = new AddressBook(configuration.getAddressBookFile());
initializeFolderAccess();
// The rest of the initialization happens in ConnectTask because it needs an I2PSession.
// It is done in the background so we don't block the webapp thread.
connectTask = new ConnectTask();
connectTask.start();
}
/**
* Initializes objects for accessing emails and packet files on the filesystem.
*/
private void initializeFolderAccess() {
inbox = new EmailFolder(configuration.getInboxDir());
outbox = new Outbox(configuration.getOutboxDir());
sentFolder = new EmailFolder(configuration.getSentFolderDir());
trashFolder = new TrashFolder(configuration.getTrashFolderDir());
relayPacketFolder = new RelayPacketFolder(configuration.getRelayPacketDir());
MessageIdCache messageIdCache = new MessageIdCache(configuration.getMessageIdCacheFile(), configuration.getMessageIdCacheSize());
incompleteEmailFolder = new IncompleteEmailFolder(configuration.getIncompleteDir(), messageIdCache, inbox);
emailDhtStorageFolder = new EmailPacketFolder(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("inbound.nickname", "I2P-Bote");
sessionProperties.setProperty("outbound.nickname", "I2P-Bote");
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();
FileReader fileReader = null;
try {
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);
}
finally {
if (fileReader != null)
try {
fileReader.close();
}
catch (IOException e) {
log.debug("Error closing file: <" + destinationKeyFile.getAbsolutePath() + ">" + 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.info("Local destination key = " + localDestination.toBase64());
log.info("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();
sendQueue = new I2PSendQueue(i2pSession, dispatcher);
relayPacketSender = new RelayPacketSender(sendQueue, relayPacketFolder);
dht = new KademliaDHT(sendQueue, dispatcher, configuration.getDhtPeerFile());
dht.setStorageHandler(EncryptedEmailPacket.class, emailDhtStorageFolder);
dht.setStorageHandler(IndexPacket.class, indexPacketDhtStorageFolder);
//TODO dht.setStorageHandler(AddressPacket.class, );
peerManager = new RelayPeerManager(sendQueue, getLocalDestination(), configuration.getRelayPeerFile());
dispatcher.addPacketListener(emailDhtStorageFolder);
dispatcher.addPacketListener(indexPacketDhtStorageFolder);
dispatcher.addPacketListener(new RelayPacketHandler(relayPacketFolder, dht, i2pSession));
dispatcher.addPacketListener(peerManager);
expirationThread = new ExpirationThread();
expirationThread.addExpirationListener(emailDhtStorageFolder);
expirationThread.addExpirationListener(indexPacketDhtStorageFolder);
expirationThread.addExpirationListener(relayPacketSender);
outboxProcessor = new OutboxProcessor(dht, outbox, peerManager, relayPacketFolder, configuration);
outboxProcessor.addOutboxListener(new OutboxListener() {
/** Moves sent emails to the "sent" folder */
@Override
public void emailSent(Email email) {
try {
outbox.setNew(email, false); // this prevents OutboxProcessor from sending the email again if it can't be moved for some reason
log.debug("Moving email [" + email + "] to the \"sent\" folder.");
outbox.move(email, sentFolder);
}
catch (Exception e) {
log.error("Cannot move email from outbox to sent folder: " + email, e);
}
}
});
autoMailCheckTask = new AutoMailCheckTask(configuration.getMailCheckInterval());
}
/**
* 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");
if (!keyFile.renameTo(oldKeyFile))
log.error("Cannot rename destination key file <" + keyFile.getAbsolutePath() + "> to <" + oldKeyFile.getAbsolutePath() + ">");
}
else
if (!keyFile.createNewFile())
log.error("Cannot create destination key file: <" + keyFile.getAbsolutePath() + ">");
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 Configuration getConfiguration() {
return configuration;
}
public static String getAppVersion() {
return APP_VERSION;
}
public Locale[] getAllLocales() {
return Locales.ALL_LOCALES;
}
public Identities getIdentities() {
return identities;
}
public AddressBook getAddressBook() {
return addressBook;
}
public Destination getLocalDestination() {
return i2pSession.getMyDestination();
}
public void sendEmail(Email email) throws Exception {
email.checkAddresses();
outbox.add(email);
outboxProcessor.checkForEmail();
}
public synchronized void checkForMail() {
if (!isCheckingForMail()) {
if (identities.size() <= 0)
log.info("Not checking for mail because no identities are defined.");
else
log.info("Checking mail for " + identities.size() + " Email Identities...");
lastMailCheckTime = System.currentTimeMillis();
pendingMailCheckTasks = Collections.synchronizedCollection(new ArrayList<Future<Boolean>>());
mailCheckExecutor = Executors.newFixedThreadPool(configuration.getMaxConcurIdCheckMail(), mailCheckThreadFactory);
for (EmailIdentity identity: identities) {
Callable<Boolean> checkMailTask = new CheckEmailTask(identity, dht, peerManager, sendQueue, incompleteEmailFolder, emailDhtStorageFolder, indexPacketDhtStorageFolder);
Future<Boolean> task = mailCheckExecutor.submit(checkMailTask);
pendingMailCheckTasks.add(task);
}
mailCheckExecutor.shutdown(); // finish all tasks, then shut down
}
else
log.info("Not checking for mail because the last mail check hasn't finished.");
}
public synchronized long getLastMailCheckTime() {
return lastMailCheckTime;
}
public synchronized boolean isCheckingForMail() {
if (mailCheckExecutor == null)
return false;
return !mailCheckExecutor.isTerminated();
}
/**
* 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 (pendingMailCheckTasks == null)
return false;
if (isCheckingForMail())
return false;
try {
for (Future<Boolean> result: pendingMailCheckTasks)
if (result.get(1, TimeUnit.MILLISECONDS)) {
pendingMailCheckTasks = null;
return true;
}
}
catch (Exception e) {
log.error("Error while checking whether new mail has arrived.", e);
}
pendingMailCheckTasks = null;
return false;
}
public EmailFolder getInbox() {
return inbox;
}
public Outbox getOutbox() {
return outbox;
}
public EmailFolder getSentFolder() {
return sentFolder;
}
public EmailFolder getTrashFolder() {
return trashFolder;
}
public boolean moveToTrash(EmailFolder sourceFolder, String messageId) {
return sourceFolder.move(messageId, trashFolder);
}
public int getNumDhtPeers() {
if (dht == null)
return 0;
else
return dht.getNumPeers();
}
public DhtPeerStats getDhtStats() {
if (dht == null)
return null;
else
return dht.getPeerStats();
}
public Set<RelayPeer> getRelayPeers() {
return peerManager.getAllPeers();
}
public Collection<BannedPeer> getBannedPeers() {
return BanList.getInstance().getAll();
}
private void startAllServices() {
peerManager.start();
outboxProcessor.start();
dht.start();
relayPacketSender.start();
// smtpService.start();
// pop3Service.start();
sendQueue.start();
autoMailCheckTask.start();
expirationThread.start();
}
private void stopAllServices() {
if (connectTask != null)
connectTask.requestShutdown();
if (dht != null) dht.requestShutdown();
if (outboxProcessor != null) outboxProcessor.requestShutdown();
if (relayPacketSender != null) relayPacketSender.requestShutdown();
if (smtpService != null) smtpService.requestShutdown();
if (pop3Service != null) pop3Service.requestShutdown();
if (sendQueue != null) sendQueue.requestShutdown();
if (mailCheckExecutor != null) mailCheckExecutor.shutdown();
if (pendingMailCheckTasks != null)
for (Future<Boolean> mailCheckTask: pendingMailCheckTasks)
mailCheckTask.cancel(false);
if (autoMailCheckTask != null) autoMailCheckTask.requestShutdown();
if (expirationThread != null) expirationThread.requestShutdown();
if (peerManager != null) peerManager.requestShutdown();
long deadline = System.currentTimeMillis() + 1000 * 60; // the time at which any background threads that are still running are killed
if (dht != null)
try {
dht.awaitShutdown(deadline - System.currentTimeMillis());
}
catch(InterruptedException e) {
log.error("Interrupted while waiting for DHT shutdown.", e);
}
join(outboxProcessor, deadline);
join(relayPacketSender, deadline);
join(smtpService, deadline);
join(pop3Service, deadline);
join(sendQueue, deadline);
if (mailCheckExecutor != null) mailCheckExecutor.shutdownNow();
join(autoMailCheckTask, deadline);
long currentTime = System.currentTimeMillis();
if (mailCheckExecutor!=null && currentTime<deadline)
try {
mailCheckExecutor.awaitTermination(deadline-currentTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
log.error("Interrupted while waiting for mailCheckExecutor to exit", e);
}
try {
if (i2pSession != null)
i2pSession.destroySession();
} catch (I2PSessionException e) {
log.error("Can't destroy I2P session.", e);
}
}
private void join(Thread thread, long until) {
if (thread == null)
return;
long timeout = System.currentTimeMillis() - until;
if (timeout > 0)
try {
thread.join(timeout);
} catch (InterruptedException e) {
log.error("Interrupted while waiting for thread <" + thread.getName() + "> to exit", e);
}
}
/**
* Connects to the network, skipping the connect delay.
* If the delay time has already passed, calling this method has no effect.
*/
public void connectNow() {
connectTask.startSignal.countDown();
}
public NetworkStatus getNetworkStatus() {
if (!connectTask.isDone())
return connectTask.getNetworkStatus();
else if (dht != null)
return dht.isReady()?NetworkStatus.CONNECTED:NetworkStatus.CONNECTING;
else
return NetworkStatus.ERROR;
}
/**
* Waits <code>STARTUP_DELAY</code> milliseconds or until <code>startSignal</code>
* is triggered from outside this class, then sets up an I2P session and everything
* that depends on it.
*/
private class ConnectTask extends I2PBoteThread {
volatile NetworkStatus status = NetworkStatus.NOT_STARTED;
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(1);
protected ConnectTask() {
super("ConnectTask");
setDaemon(true);
}
public NetworkStatus getNetworkStatus() {
return status;
}
public boolean isDone() {
try {
return doneSignal.await(0, TimeUnit.SECONDS);
} catch (InterruptedException e) {
return false;
}
}
@Override
public void requestShutdown() {
super.requestShutdown();
startSignal.countDown();
}
@Override
public void run() {
status = NetworkStatus.DELAY;
try {
startSignal.await(STARTUP_DELAY, TimeUnit.MINUTES);
status = NetworkStatus.CONNECTING;
initializeSession();
initializeServices();
startAllServices();
doneSignal.countDown();
} catch (Exception e) {
status = NetworkStatus.ERROR;
log.error("Can't initialize the application.", e);
}
}
}
}

View File

@@ -1,260 +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.BufferedReader;
import java.io.ByteArrayOutputStream;
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.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ThreadFactory;
import net.i2p.I2PAppContext;
import net.i2p.data.Base32;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.Hash;
import net.i2p.util.Log;
import net.i2p.util.Translate;
public class Util {
private static final String BUNDLE_NAME = "i2p.bote.locale.Messages";
private Util() { }
public static byte[] readBytes(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();
}
/**
* Opens a <code>URL</code> and reads one line at a time.
* Returns the lines as a <code>List</code> of <code>String</code>s,
* or an empty <code>List</code> if an error occurred.
* @param url
* @return
* @see readLines(File)
*/
public static List<String> readLines(URL url) {
Log log = new Log(Util.class);
log.info("Reading URL: <" + url + ">");
InputStream stream = null;
try {
stream = url.openStream();
return readLines(stream);
}
catch (IOException e) {
log.error("Error reading URL.", e);
return Collections.emptyList();
} finally {
if (stream != null)
try {
stream.close();
} catch (IOException e) {
log.error("Can't close input stream.", e);
}
}
}
/**
* Opens a <code>File</code> and reads one line at a time.
* Returns the lines as a <code>List</code> of <code>String</code>s,
* or an empty <code>List</code> if an error occurred.
* @param file
* @return
* @see readLines(URL)
*/
public static List<String> readLines(File file) {
Log log = new Log(Util.class);
log.info("Reading file: <" + file.getAbsolutePath() + ">");
InputStream stream = null;
try {
stream = new FileInputStream(file);
return readLines(stream);
} catch (IOException e) {
log.error("Error reading file.", e);
return Collections.emptyList();
} finally {
if (stream != null)
try {
stream.close();
} catch (IOException e) {
log.error("Can't close input stream.", e);
}
}
}
/**
* Opens an <code>InputStream</code> and reads one line at a time.
* Returns the lines as a <code>List</code> of <code>String</code>s.
* or an empty <code>List</code> if an error occurred.
* @param url
* @return
* @see readLines(URL)
*/
private static List<String> readLines(InputStream inputStream) throws IOException {
Log log = new Log(Util.class);
BufferedReader inputBuffer = new BufferedReader(new InputStreamReader(inputStream));
List<String> lines = new ArrayList<String>();
int linesRead = 0;
while (true) {
String line = null;
line = inputBuffer.readLine();
if (line == null)
break;
lines.add(line);
}
log.info(linesRead + " lines read.");
return lines;
}
/**
* Creates an I2P destination with a null certificate from 384 bytes that
* are read from a <code>ByteBuffer</code>.
* @param buffer
* @return
* @throws DataFormatException
*/
public static Destination createDestination(ByteBuffer buffer) throws DataFormatException {
byte[] bytes = new byte[388];
// read 384 bytes, leave the last 3 bytes zero
buffer.get(bytes, 0, 384);
Destination peer = new Destination();
peer.readBytes(bytes, 0);
return peer;
}
public static ThreadFactory createThreadFactory(final String threadName, final int stackSize) {
return new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
return new Thread(Thread.currentThread().getThreadGroup(), runnable, threadName, stackSize);
}
};
}
/**
* Creates a thread-safe <code>Iterable</code> from a thread-unsafe one.
* Modifications to the old <code>Iterable</code> will not affect the
* new one.
* @param <E>
* @param iterable
* @return
*/
public static <E> Iterable<E> synchronizedCopy(Iterable<E> iterable) {
synchronized(iterable) {
Collection<E> collection = new ArrayList<E>();
for (E element: iterable)
collection.add(element);
return collection;
}
}
/**
* Returns the <code>i</code>-th element of a <code>Collection</code>'s <code>Iterator</code>.
* @param <E>
* @param collection
* @param i
* @return
*/
public static <E> E get(Collection<E> collection, int i) {
for (E element: collection) {
if (i == 0)
return element;
i--;
}
return null;
}
public static String _(String messageKey) {
return Translate.getString(messageKey, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
}
public static String _(String messageKey, Object parameter) {
return Translate.getString(messageKey, parameter, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
}
public static String _(String messageKey, Object parameter1, Object parameter2) {
return Translate.getString(messageKey, parameter1, parameter2, I2PAppContext.getGlobalContext(), BUNDLE_NAME);
}
/**
* Removes all whitespace at the beginning and the end of a string,
* and replaces multiple whitespace characters with a single space.
* @param string
* @return
*/
public static String removeExtraWhitespace(String string) {
if (string == null)
return null;
return string.trim().replaceAll("\\s+", " ");
}
/**
* Removes whitespace from the beginning and end of an address.
* Also removes angle brackets if the address begins and ends
* with an angle bracket.
* @param address
* @return
*/
public static String fixAddress(String address) {
if (address == null)
return null;
address = address.trim();
if (address.startsWith("<") && address.endsWith(">"))
address = address.substring(1, address.length()-1);
return address;
}
public static UniqueId zeroId() {
return new UniqueId(new byte[UniqueId.LENGTH], 0);
}
public static String toBase32(Hash hash) {
return Base32.encode(hash.toByteArray());
}
}

View File

@@ -1,177 +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.addressbook;
import i2p.bote.email.EmailDestination;
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.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import net.i2p.util.Log;
/**
* Implements the private address book. Holds a set of <code>Addresses</code>.
*/
public class AddressBook implements Iterable<Contact> {
private Log log = new Log(AddressBook.class);
private File addressFile;
private List<Contact> contacts;
/**
* Reads an <code>AddressBook</code> from a text file. Each contact is defined
* by one line that contains an Email Destination and a name, separated by a
* tab character.
* @param addressFile
*/
public AddressBook(File addressFile) {
this.addressFile = addressFile;
contacts = Collections.synchronizedList(new ArrayList<Contact>());
if (!addressFile.exists()) {
log.debug("Address file does not exist: <" + addressFile.getAbsolutePath() + ">");
return;
}
log.debug("Reading address book from <" + addressFile.getAbsolutePath() + ">");
BufferedReader input = null;
try {
input = new BufferedReader(new FileReader(addressFile));
while (true) {
String line = input.readLine();
if (line == null) // EOF
break;
String[] fields = line.split("\\t", 2);
try {
EmailDestination destination = new EmailDestination(fields[0]);
String name = null;
if (fields.length > 1)
name = fields[1];
contacts.add(new Contact(destination, name));
}
catch (GeneralSecurityException e) {
log.error("Not a valid Email Destination: <" + fields[0] + ">", e);
}
}
} catch (IOException e) {
log.error("Can't read address book.", e);
}
finally {
if (input != null)
try {
input.close();
}
catch (IOException e) {
log.error("Error closing input stream.", e);
}
}
}
public void save() throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(addressFile));
try {
for (Contact contact: contacts) {
writer.write(contact.toBase64());
writer.write("\t");
writer.write(contact.getName());
writer.newLine();
}
}
catch (IOException e) {
log.error("Can't save address book to file <" + addressFile.getAbsolutePath() + ">.", e);
throw e;
}
finally {
writer.close();
}
}
public void add(Contact contact) {
contacts.add(contact);
}
public void remove(String destination) {
Contact contact = get(destination);
if (contact != null)
contacts.remove(contact);
}
public Contact get(int i) {
return contacts.get(i);
}
/**
* Looks up an {@link Contact} by its Base64 key. If none is found,
* <code>null</code> is returned.
* @param destination
* @return
*/
public Contact get(String destination) {
if (destination==null || destination.isEmpty())
return null;
for (Contact contact: contacts)
if (destination.equals(contact.toBase64()))
return contact;
return null;
}
/**
* Returns <code>true</code> if a given Base64-encoded Email Destination
* is in the address book.
* @param base64dest
* @return
*/
public boolean contains(String base64dest) {
if (base64dest == null)
return false;
for (Contact contact: contacts)
if (base64dest.equals(contact.toBase64()))
return true;
return false;
}
public Collection<Contact> getAll() {
return contacts;
}
public int size() {
return contacts.size();
}
@Override
public Iterator<Contact> iterator() {
return contacts.iterator();
}
}

View File

@@ -1,62 +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.crypto;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.i2p.util.Log;
public class CryptoFactory {
private static List<CryptoImplementation> instances;
public static CryptoImplementation getInstance(int id) {
if (instances == null)
init();
for (CryptoImplementation instance: instances)
if (instance.getId() == id)
return instance;
return null;
}
public static List<CryptoImplementation> getInstances() {
if (instances == null)
init();
return instances;
}
private static void init() {
instances = Collections.synchronizedList(new ArrayList<CryptoImplementation>());
instances.add(new ElGamal2048_DSA1024());
try {
instances.add(new ECDH256_ECDSA256());
instances.add(new ECDH521_ECDSA521());
}
catch (Exception e) {
Log log = new Log(CryptoFactory.class);
log.error("Error creating ECDH256_ECDSA256 or ECDH521_ECDSA521.", e);
}
}
}

View File

@@ -1,68 +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.addressbook.AddressBook;
import i2p.bote.addressbook.Contact;
/**
* This class is used for adding/replacing names in email addresses with
* local names (address book entries and email identities).
*/
public class AddressDisplayFilter {
private Identities identities;
private AddressBook addressBook;
public AddressDisplayFilter(Identities identities, AddressBook addressBook) {
this.identities = identities;
this.addressBook = addressBook;
}
/**
* Looks up the name associated with a Base64-encoded Email Destination,
* in the address book and the local identities, and returns a string
* that contains the name and the Base64-encoded destination.
* If <code>address</code> already contains a name, it is replaced with
* the one from the address book or identities.
* If no name is found in the address book or the identities, or if
* <code>address</code> does not contain a valid Email Destination,
* <code>address</code> is returned.
* @param address A Base64-encoded Email Destination, and optionally a name
* @return
*/
public String getNameAndDestination(String address) {
String base64dest = EmailDestination.extractBase64Dest(address);
if (base64dest != null) {
// try the address book
Contact contact = addressBook.get(base64dest);
if (contact != null)
return contact.getName() + "<" + contact.toBase64() + ">";
// if no address book entry, try the email identities
EmailIdentity identity = identities.get(base64dest);
if (identity != null)
return identity.getPublicName() + "<" + identity.toBase64() + ">";
}
return address;
}
}

View File

@@ -1,542 +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 static i2p.bote.Util._;
import i2p.bote.I2PBote;
import i2p.bote.UniqueId;
import i2p.bote.Util;
import i2p.bote.crypto.CryptoFactory;
import i2p.bote.crypto.CryptoImplementation;
import i2p.bote.packet.UnencryptedEmailPacket;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import javax.mail.Address;
import javax.mail.Header;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import net.i2p.data.Base64;
import net.i2p.data.DataFormatException;
import net.i2p.util.Log;
import com.nettgryppa.security.HashCash;
public class Email extends MimeMessage {
private static final int MAX_BYTES_PER_PACKET = 30 * 1024;
private static final String SIGNATURE_HEADER = "X-I2PBote-Signature"; // contains the sender's base64-encoded signature
private static final String SIGNATURE_VALID_HEADER = "X-I2PBote-Sig-Valid"; // contains the string "true" or "false"
private static final String[] HEADER_WHITELIST = new String[] {
"From", "Sender", "To", "CC", "BCC", "Reply-To", "Subject", "Date", "MIME-Version", "Content-Type",
"Content-Transfer-Encoding", "In-Reply-To", "X-HashCash", "X-Priority", SIGNATURE_HEADER
};
private static final String[] ADDRESS_HEADERS = new String[] {"From", "Sender", "To", "CC", "BCC", "Reply-To"};
private static Log log = new Log(Email.class);
private UniqueId messageId;
private boolean isNew = true;
public Email() {
super(Session.getDefaultInstance(new Properties()));
messageId = new UniqueId();
}
public Email(File file) throws FileNotFoundException, MessagingException {
this(new FileInputStream(file));
}
/**
* Creates an Email object from an InputStream containing a MIME email.
*
* @param inputStream
* @throws MessagingException
*/
private Email(InputStream inputStream) throws MessagingException {
super(Session.getDefaultInstance(new Properties()), inputStream);
messageId = new UniqueId();
}
/**
* Creates an Email object from a byte array containing a MIME email.
*
* @param bytes
* @throws MessagingException
*/
public Email(byte[] bytes) throws MessagingException {
super(Session.getDefaultInstance(new Properties()), new ByteArrayInputStream(bytes));
messageId = new UniqueId();
}
/**
* Returns <code>true</code> if the sender is anonymous.
* @return
* @throws MessagingException
*/
public boolean isAnonymous() throws MessagingException {
Address sender = getSender();
return sender==null || "Anonymous".equalsIgnoreCase(sender.toString());
}
public String getOneFromAddress() throws MessagingException {
Address[] fromAddresses = getFrom();
if (fromAddresses==null || fromAddresses.length==0)
return null;
else
return fromAddresses[0].toString();
}
public String getOneRecipient() throws MessagingException {
Address[] recipients = getAllRecipients();
if (recipients==null || recipients.length==0)
return null;
else
return recipients[0].toString();
}
public void setHashCash(HashCash hashCash) throws MessagingException {
setHeader("X-HashCash", hashCash.toString());
}
/**
* Removes all headers that are not on the whitelist, and initializes some
* basic header fields.
* Called by <code>saveChanges()</code>, see JavaMail JavaDoc.
* @throws MessagingException
*/
@Override
public void updateHeaders() throws MessagingException {
super.updateHeaders();
scrubHeaders();
removeRecipientNames();
// Set the send time if the "Include sent time" config setting is enabled;
// otherwise, remove the send time field.
if (I2PBote.getInstance().getConfiguration().getIncludeSentTime()) {
// Set the "Date" field in UTC time, using the English locale.
long currentTime = new Date().getTime();
long timeZoneOffset = TimeZone.getDefault().getOffset(currentTime);
currentTime -= timeZoneOffset;
DateFormat formatter = new SimpleDateFormat("EEE, dd MMM yyyy kk:mm:ss +0000", Locale.ENGLISH); // always use UTC for outgoing mail
setHeader("Date", formatter.format(currentTime));
}
else
removeHeader("Date");
}
/**
* Creates a digital signature of the email and stores it in the
* <code>SIGNATURE_HEADER</code> header field. It also removes the
* <code>SIGNATURE_VALID_FLAG</code> header.
* The signature is computed over the stream representation of the
* email, minus the signature header if it is present.
* The signature includes the ID number of the {@link CryptoImplementation}
* used (signature lengths can be different for the same algorithm).
* @param senderIdentity
* @throws MessagingException
* @throws GeneralSecurityException
*/
private void sign(EmailIdentity senderIdentity) throws MessagingException, GeneralSecurityException {
removeHeader(SIGNATURE_HEADER); // make sure there is no existing signature which would make the new signature invalid
removeHeader(SIGNATURE_VALID_HEADER); // remove the signature validity flag before signing
CryptoImplementation cryptoImpl = senderIdentity.getCryptoImpl();
PrivateKey signingKey = senderIdentity.getPrivateSigningKey();
byte[] signature = cryptoImpl.sign(toByteArray(), signingKey);
setHeader(SIGNATURE_HEADER, cryptoImpl.getId() + "_" + Base64.encode(signature));
}
/**
* Verifies the signature and sets the <code>SIGNATURE_VALID_FLAG</code>
* header field accordingly.
*/
public void setSignatureFlag() {
try {
removeHeader(SIGNATURE_VALID_HEADER); // remove the signature validity flag before verifying
boolean valid = verifySignature();
setHeader(SIGNATURE_VALID_HEADER, Boolean.valueOf(valid).toString());
} catch (MessagingException e) {
log.error("Cannot get header field: " + SIGNATURE_VALID_HEADER, e);
}
}
/**
* Verifies that the email contains a valid signature. If the
* <code>SIGNATURE_VALID_FLAG</code> is present, its value is used.
* If not, the value of the <code>SIGNATURE_HEADER</code> header
* field is verified (which is more CPU intensive).
* @return
*/
public boolean isSignatureValid() {
try {
String[] sigValidFlag = getHeader(SIGNATURE_VALID_HEADER);
if (sigValidFlag==null || sigValidFlag.length==0)
return verifySignature();
else
return "true".equalsIgnoreCase(sigValidFlag[0]);
} catch (MessagingException e) {
log.error("Cannot get header field: " + SIGNATURE_VALID_HEADER, e);
return false;
}
}
/**
* Verifies that the <code>SIGNATURE_HEADER</code> header field
* contains a valid signature.
* @return
*/
private boolean verifySignature() {
String[] signatureHeaders;
try {
signatureHeaders = getHeader(SIGNATURE_HEADER);
} catch (MessagingException e) {
log.error("Cannot get header field: " + SIGNATURE_HEADER, e);
return false;
}
if (signatureHeaders==null || signatureHeaders.length<=0)
return false;
String signatureHeader = signatureHeaders[0];
// the crypto implementation ID is the number before the underscore
int _index = signatureHeader.indexOf('_');
if (_index < 0)
return false;
String cryptoImplIdString = signatureHeader.substring(0, _index);
int cryptoImplId = 0;
try {
cryptoImplId = Integer.valueOf(cryptoImplIdString);
}
catch (NumberFormatException e) {
return false;
}
CryptoImplementation cryptoImpl = CryptoFactory.getInstance(cryptoImplId);
// the actual signature is everything after the underscore
String base64Signature = signatureHeader.substring(_index + 1);
try {
removeHeader(SIGNATURE_HEADER);
byte[] signature = Base64.decode(base64Signature);
EmailDestination senderDestination = new EmailDestination(getSender().toString());
return cryptoImpl.verify(toByteArray(), signature, senderDestination.getPublicSigningKey());
} catch (Exception e) {
log.error("Cannot verify email signature. Email: [" + this + "]", e);
return false;
} finally {
try {
setHeader(SIGNATURE_HEADER, signatureHeader);
} catch (MessagingException e) {
log.error("Cannot set signature header field.", e);
return false;
}
}
}
/**
* Throws an exception if one or more address fields contain an invalid
* Email Destination. If all addresses are valid, nothing happens.
* @throws MessagingException
* @throws DataFormatException
*/
public void checkAddresses() throws MessagingException, DataFormatException {
Collection<Header> headers = getAllAddressHeaders();
for (Header header: headers) {
String address = header.getValue();
if (!"Sender".equalsIgnoreCase(header.getName()) || !isAnonymous()) { // don't validate if this is the "sender" field and the sender is anonymous
boolean validEmailDest = false;
try {
new EmailDestination(address);
validEmailDest = true;
}
catch (GeneralSecurityException e) {
log.debug("Address contains no email destination: <" + address + ">, message: " + e.getLocalizedMessage());
}
try {
String adrString = address.toString();
new InternetAddress(adrString, true);
// InternetAddress accepts addresses without a domain, so check that there is a '.' after the '@'
if (adrString.indexOf('@') >= adrString.indexOf('.'))
throw new DataFormatException(_("Invalid address: {0}", address));
validEmailDest = true;
} catch (AddressException e) {
log.debug("Address contains no external email address: <" + address + ">, message: " + e.getLocalizedMessage());
}
if (!validEmailDest)
throw new DataFormatException(_("Address doesn't contain an Email Destination or an external address: {0}", address));
}
}
}
public void fixAddresses() throws MessagingException {
List<Header> addressHeaders = getAllAddressHeaders();
for (String headerName: ADDRESS_HEADERS)
removeHeader(headerName);
for (Header header: addressHeaders) {
String fixedAddress = Util.fixAddress(header.getValue());
addHeader(header.getName(), fixedAddress);
}
}
private List<Header> getAllAddressHeaders() throws MessagingException {
@SuppressWarnings("unchecked")
Enumeration<Header> addressHeaders = (Enumeration<Header>)getMatchingHeaders(ADDRESS_HEADERS);
return Collections.list(addressHeaders);
}
/**
* Returns all "Reply To" addresses (usually zero or one).
* Unlike {@link getReplyTo()}, this method does not return
* the "From" address if there is no "Reply To" address.
* @return
* @throws MessagingException
*/
public String[] getReplyToAddresses() throws MessagingException {
return getHeader("Reply-To");
}
public Address[] getToAddresses() throws MessagingException {
return getRecipients(RecipientType.TO);
}
public Address[] getCCAddresses() throws MessagingException {
return getRecipients(RecipientType.CC);
}
public Address[] getBCCAddresses() throws MessagingException {
return getRecipients(RecipientType.BCC);
}
private byte[] toByteArray() throws MessagingException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
try {
writeTo(byteStream);
} catch (IOException e) {
throw new MessagingException("Cannot write email to ByteArrayOutputStream.", e);
}
return byteStream.toByteArray();
}
/**
* Removes all mail headers except the ones in <code>HEADER_WHITELIST</code>.
* @throws MessagingException
*/
private void scrubHeaders() throws MessagingException {
@SuppressWarnings("unchecked")
List<Header> nonMatchingHeaders = Collections.list(getNonMatchingHeaders(HEADER_WHITELIST));
for (Header header: nonMatchingHeaders)
if (header != null) {
log.debug("Removing all instances of non-whitelisted header <" + header.getName() + ">");
removeHeader(header.getName());
}
}
/**
* Removes everything but the email destination from all recipient fields,
* in order to keep local contact names private.
* @throws MessagingException
*/
private void removeRecipientNames() throws MessagingException {
removeRecipientNames("To");
removeRecipientNames("CC");
removeRecipientNames("BCC");
}
private void removeRecipientNames(String headerName) throws MessagingException {
String[] headerValues = getHeader(headerName);
removeHeader(headerName);
if (headerValues != null)
for (String recipient: headerValues) {
String dest = EmailDestination.extractBase64Dest(recipient);
if (dest != null)
addHeader(headerName, dest);
// If there is no email destination, assume it is an external address and don't change it
else
addHeader(headerName, recipient);
}
}
/**
*
* @param messageIdString Must be a 44-character Base64-encoded string.
*/
public void setMessageID(String messageIdString) {
this.messageId = new UniqueId(messageIdString);
}
public void setMessageID(UniqueId messageId) {
this.messageId = messageId;
}
@Override
public String getMessageID() {
return messageId.toBase64();
}
public void setNew(boolean isNew) {
this.isNew = isNew;
}
/**
* Returns <code>true</code> if the email is unread (incoming mail), or
* if it has not been sent yet (outgoing mail).
* @return
*/
public boolean isNew() {
return isNew;
}
public String getText() {
try {
return getContent().toString();
} catch (Exception e) {
String errorMsg = "Error reading email content.";
log.error(errorMsg, e);
return errorMsg;
}
}
/**
* Updates headers, signs the email, and converts it into one or more email packets.
* If an error occurs, an empty <code>Collection</code> is returned.
*
* @param senderIdentity The sender's Email Identity, or <code>null</code> for anonymous emails
* @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 MessagingException
* @throws GeneralSecurityException
*/
public Collection<UnencryptedEmailPacket> createEmailPackets(EmailIdentity senderIdentity, String bccToKeep) throws MessagingException, GeneralSecurityException {
ArrayList<UnencryptedEmailPacket> packets = new ArrayList<UnencryptedEmailPacket>();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
String[] bccHeaders = null;
try {
bccHeaders = getHeader("BCC");
saveChanges();
if (bccToKeep!=null && isBCC(bccToKeep))
setHeader("BCC", bccToKeep); // set bccToKeep and remove any other existing BCC addresses
else
removeHeader("BCC");
if (!isAnonymous())
sign(senderIdentity);
writeTo(outputStream);
} catch (IOException e) {
throw new MessagingException("Can't write to ByteArrayOutputStream.", e);
} catch (GeneralSecurityException e) {
throw new GeneralSecurityException("Can't sign email.", e);
} finally {
// restore the BCC headers
removeHeader("BCC");
if (bccHeaders != null)
for (String bccAddress: bccHeaders)
addHeader("BCC", bccAddress);
}
byte[] emailArray = outputStream.toByteArray();
// calculate packet count
int numPackets = (emailArray.length+MAX_BYTES_PER_PACKET-1) / MAX_BYTES_PER_PACKET;
int packetIndex = 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);
UnencryptedEmailPacket packet = new UnencryptedEmailPacket(messageId, packetIndex, numPackets, block);
packets.add(packet);
packetIndex++;
blockStart += blockSize;
}
}
return packets;
}
/**
* Tests if <code>address</code> is a BCC address.
* @param address
* @return
* @throws MessagingException
*/
private boolean isBCC(String address) throws MessagingException {
String[] bccAddresses = getHeader("BCC");
if (bccAddresses == null)
return false;
for (String bccAddress: bccAddresses)
if (bccAddress.equals(address))
return true;
return false;
}
@Override
public String toString() {
StringBuilder result = new StringBuilder("MsgId: ").append(getMessageID());
try {
result = result.append("Sender: ").append(getSender());
result = result.append("Recipients: ");
for (Address recipient: getAllRecipients()) {
if (result.length() > 1000) {
result = result.append("...");
break;
}
if (result.length() > 0)
result = result.append(", ");
String recipientAddress = recipient.toString();
if (recipientAddress.length() > 20)
result = result.append(recipientAddress).append("...");
else
result = result.append(recipientAddress);
}
} catch (MessagingException e) {
log.error("Error getting sender or recipients.");
result.append("#Error#");
}
return result.toString();
}
}

View File

@@ -1,145 +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.crypto.CryptoFactory;
import i2p.bote.crypto.CryptoImplementation;
import i2p.bote.crypto.PrivateKeyPair;
import i2p.bote.crypto.PublicKeyPair;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.PrivateKey;
public class EmailIdentity extends EmailDestination {
private PrivateKey privateEncryptionKey;
private PrivateKey privateSigningKey;
private String publicName;
private String description; // optional
private String emailAddress; // optional
private boolean isDefault;
/**
* Creates a random <code>EmailIdentity</code>.
* @param cryptoImpl
* @throws GeneralSecurityException
*/
public EmailIdentity(CryptoImplementation cryptoImpl) throws GeneralSecurityException {
super();
this.cryptoImpl = cryptoImpl;
KeyPair encryptionKeys = cryptoImpl.generateEncryptionKeyPair();
KeyPair signingKeys = cryptoImpl.generateSigningKeyPair();
publicEncryptionKey = encryptionKeys.getPublic();
privateEncryptionKey = encryptionKeys.getPrivate();
publicSigningKey = signingKeys.getPublic();
privateSigningKey = signingKeys.getPrivate();
}
/**
* Creates a <code>EmailIdentity</code> from a Base64-encoded string.
* The format can be any format supported by one of the {@link CryptoImplementation}s.
* @param base64Key
* @throws GeneralSecurityException
*/
public EmailIdentity(String base64Key) throws GeneralSecurityException {
// find the crypto implementation for this key length
for (CryptoImplementation cryptoImpl: CryptoFactory.getInstances()) {
int base64Length = cryptoImpl.getBase64CompleteKeySetLength(); // length of an email identity with this CryptoImplementation
if (base64Key.length() == base64Length) {
this.cryptoImpl = cryptoImpl;
break;
}
}
if (cryptoImpl == null)
throw new InvalidKeyException("Not a valid Email Identity: <" + base64Key + ">");
PublicKeyPair publicKeys = cryptoImpl.createPublicKeyPair(base64Key);
String base64PrivateKeys = base64Key.substring(cryptoImpl.getBase64PublicKeyPairLength()); // the two private keys start after the two public keys
PrivateKeyPair privateKeys = cryptoImpl.createPrivateKeyPair(base64PrivateKeys);
publicEncryptionKey = publicKeys.encryptionKey;
privateEncryptionKey = privateKeys.encryptionKey;
publicSigningKey = publicKeys.signingKey;
privateSigningKey = privateKeys.signingKey;
}
public PrivateKey getPrivateEncryptionKey() {
return privateEncryptionKey;
}
public PrivateKey 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;
}
public void setDefault(boolean isDefault) {
this.isDefault = isDefault;
}
public boolean isDefault() {
return isDefault;
}
/**
* Returns the two key pairs (public + private) as one Base64-encoded string.
* @return
* @throws GeneralSecurityException
*/
public String getFullKey() throws GeneralSecurityException {
PublicKeyPair publicKeys = new PublicKeyPair(publicEncryptionKey, publicSigningKey);
PrivateKeyPair privateKeys = new PrivateKeyPair(privateEncryptionKey, privateSigningKey);
String pubKeys = cryptoImpl.toBase64(publicKeys);
String privKeys = cryptoImpl.toBase64(privateKeys);
return pubKeys + privKeys;
}
@Override
public String toString() {
return getKey() + " address=<" + getEmailAddress() + "> identity name=<" + getDescription() + "> visible name=<" + getPublicName() + ">";
}
}

View File

@@ -1,285 +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.security.GeneralSecurityException;
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.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;
/**
* Constructs <code>Identities</code> from a text file. Each identity is defined
* by one line that contains two to four tab-separated fields:
* Email Destination key, Public Name, Description, and Email Address.
* The first two are mandatory, the last two are optional.
*
* Additionally, the file can set a default Email Destination by including a
* line that starts with "Default ", followed by an Email Destination key.
* The destination key must match one of the Email Destinations defined in
* the file.
* @param identitiesFile
*/
public Identities(File identitiesFile) {
this.identitiesFile = identitiesFile;
identities = Collections.synchronizedList(new ArrayList<EmailIdentity>());
String defaultIdentityString = null;
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;
if (line.toLowerCase().startsWith("default"))
defaultIdentityString = line.substring("default ".length());
else {
EmailIdentity identity = parse(line);
if (identity != null)
identities.add(identity);
}
}
// set the default identity; if none defined, make the first one the default
EmailIdentity defaultIdentity = get(defaultIdentityString);
if (defaultIdentity != null)
defaultIdentity.setDefault(true);
else if (!identities.isEmpty())
identities.get(0).setDefault(true);
} catch (Exception e) {
log.error("Error reading the 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) {
String[] fields = emailIdentityString.split("\\t", 4);
if (fields.length < 2) {
log.debug("Unparseable email identity: <" + emailIdentityString + ">");
return null;
}
try {
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;
} catch (GeneralSecurityException e) {
log.debug("Invalid email identity: <" + fields[0] + ">");
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
* @throws GeneralSecurityException
*/
private String toFileFormat(EmailIdentity identity) throws GeneralSecurityException {
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, GeneralSecurityException {
String newLine = System.getProperty("line.separator");
Writer writer = new BufferedWriter(new FileWriter(identitiesFile));
try {
EmailIdentity defaultIdentity = getDefault();
if (defaultIdentity != null)
writer.write("Default " + defaultIdentity.getKey() + newLine);
for (EmailIdentity identity: identities)
writer.write(toFileFormat(identity) + newLine);
}
catch (IOException e) {
log.error("Can't save email identities to file <" + identitiesFile.getAbsolutePath() + ">.", e);
throw e;
}
catch (GeneralSecurityException e) {
log.error("Can't save email identities to file <" + identitiesFile.getAbsolutePath() + ">.", e);
throw e;
}
finally {
writer.close();
}
}
public void add(EmailIdentity identity) {
if (identities.isEmpty())
identity.setDefault(true);
identities.add(identity);
}
public void remove(String key) {
EmailIdentity identity = get(key);
if (identity != null) {
identities.remove(identity);
// if we deleted the default identity, set a new default
if (identity.isDefault() && !identities.isEmpty())
identities.get(0).setDefault(true);
}
}
/**
* Sets the default identity. Assumes this <code>Identities</code> already
* contains <code>defaultIdentity</code>.
* @return
*/
public void setDefault(EmailIdentity defaultIdentity) {
// clear the old default
for (EmailIdentity identity: identities)
identity.setDefault(false);
defaultIdentity.setDefault(true);
}
/**
* Returns the default identity, or <code>null</code> if no default is set.
* @return
*/
public EmailIdentity getDefault() {
for (EmailIdentity identity: identities)
if (identity.isDefault())
return identity;
return null;
}
public EmailIdentity get(int i) {
return identities.get(i);
}
/**
* Looks up an {@link EmailIdentity} that has the same public encryption key and the
* same public signing key as a given {@link EmailDestination}.
* Returns <code>null</code> if nothing is found.
* @param key
* @return
*/
public EmailIdentity get(EmailDestination destination) {
for (EmailIdentity identity: identities)
if (identity.getPublicEncryptionKey().equals(destination.getPublicEncryptionKey())
&& identity.getPublicSigningKey().equals(destination.getPublicSigningKey()))
return identity;
return null;
}
/**
* Looks up an {@link EmailIdentity} by its Base64 key (the two public keys, to be
* more precise).
* Returns <code>null</code> if nothing is found.
* @param key
* @return
*/
public EmailIdentity get(String key) {
for (EmailIdentity identity: identities)
if (identity.getKey().equals(key))
return identity;
return null;
}
public Collection<EmailIdentity> getAll() {
return identities;
}
/**
* Returns <code>true</code> if any of the <code>Identities</code> matches
* the two public keys of a given {@link EmailDestination}
* (which can be an <code>EmailIdentity</code>).
* @param destination A base64-encoded Email Destination
* @return
*/
public boolean contains(String base64dest) {
if (base64dest == null)
return false;
for (EmailIdentity identity: identities)
if (base64dest.equals(identity.toBase64()))
return true;
return false;
}
public int size() {
return identities.size();
}
@Override
public Iterator<EmailIdentity> iterator() {
return identities.iterator();
}
}

View File

@@ -1,338 +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.email.AddressDisplayFilter;
import i2p.bote.email.Email;
import i2p.bote.email.EmailAttribute;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.mail.MessagingException;
import net.i2p.util.Log;
/**
* Stores emails in a directory on the file system. Each email is stored in one file.
* Filenames are in the format <code><N, O>_<message ID>.mail</code>, where
* N is for new (unread or unsent) and O is for old (read or sent).
*/
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);
}
/**
* Stores an email in the folder. If an email with the same
* message ID exists already, nothing happens.
* @param email
* @throws IOException
* @throws MessagingException
*/
public void add(Email email) throws IOException, MessagingException {
// check if an email exists already with that message id
if (getEmailFile(email.getMessageID()) != null) {
log.debug("Not storing email because there is an existing one with the same message ID: <" + email.getMessageID()+ ">");
return;
}
// write out the email file
File emailFile = getEmailFile(email);
log.info("Mail folder <" + storageDir + ">: storing email file: <" + emailFile.getAbsolutePath() + ">");
OutputStream emailOutputStream = null;
try {
emailOutputStream = new FileOutputStream(emailFile);
email.writeTo(emailOutputStream);
}
finally {
if (emailOutputStream != null)
try {
emailOutputStream.close();
}
catch (IOException e) {
log.error("Can't close file: <" + emailFile + ">", e);
}
}
}
/**
* Returns all emails in the folder, in the order specified by <code>sortColumn</code>.
*/
public List<Email> getElements(AddressDisplayFilter displayFilter, EmailAttribute sortColumn, boolean descending) {
Comparator<Email> comparator = new EmailComparator(sortColumn, displayFilter);
if (descending)
comparator = Collections.reverseOrder(comparator);
List<Email> emails = getElements();
Collections.sort(emails, comparator);
return emails;
}
/**
* A <code>Comparator</code> for sorting emails by a given {@link EmailAttribute}.
* If <code>attribute</code> is <code>null</code>, the date field is used.
*/
private class EmailComparator implements Comparator<Email> {
private EmailAttribute attribute;
private AddressDisplayFilter displayFilter;
public EmailComparator(EmailAttribute attribute, AddressDisplayFilter displayFilter) {
if (attribute == null)
attribute = EmailAttribute.DATE;
this.attribute = attribute;
this.displayFilter = displayFilter;
}
@Override
public int compare(Email email1, Email email2) {
@SuppressWarnings("unchecked") Comparable value1 = 0;
@SuppressWarnings("unchecked") Comparable value2 = 0;
try {
switch(attribute) {
case DATE:
value1 = email1.getSentDate();
value2 = email2.getSentDate();
break;
case FROM:
value1 = displayFilter.getNameAndDestination(email1.getOneFromAddress());
value2 = displayFilter.getNameAndDestination(email2.getOneFromAddress());
break;
case TO:
value1 = displayFilter.getNameAndDestination(email1.getOneRecipient());
value2 = displayFilter.getNameAndDestination(email2.getOneRecipient());
break;
case SUBJECT:
value1 = email1.getSubject();
value2 = email2.getSubject();
break;
default:
log.error("Unknown email attribute type: " + attribute);
}
return nullSafeCompare(value1, value2);
}
catch (MessagingException e) {
log.error("Can't read the " + attribute + " attribute from an email", e);
return 0;
}
}
@SuppressWarnings("unchecked")
private int nullSafeCompare(Comparable value1, Comparable value2) {
if (value1 == null) {
if (value2 == null)
return 0;
else
return -1;
}
else {
if (value2 == null)
return 1;
else {
if (value1 instanceof String)
return ((String)value1).compareToIgnoreCase((String)value2);
else
return value1.compareTo(value2);
}
}
}
}
/**
* 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
* {@link UniqueId}.
* @param messageId
* @return
*/
public Email getEmail(String messageId) {
File file = getEmailFile(messageId);
if (file == null)
return null;
try {
return createFolderElement(file);
}
catch (Exception e) {
log.error("Can't read email from file: <" + file.getAbsolutePath() + ">", e);
return null;
}
}
/**
* Moves an email from this folder to another. May not work if the
* two folders are on different filesystems, or if a file with the
* same name exists already.
* @param email
* @param newFolder
* @return true if successful, false if not
*/
public boolean move(Email email, EmailFolder newFolder) {
File emailFile = getEmailFile(email);
if (emailFile == null) {
log.error("Cannot move email [" + email + "] to folder [" + newFolder + "]: email file doesn't exist.");
return false;
}
File newFile = new File(newFolder.getStorageDirectory(), emailFile.getName());
boolean success = emailFile.renameTo(newFile);
if (!success)
log.error("Cannot move <" + emailFile.getAbsolutePath() + "> to <" + newFile.getAbsolutePath() + ">");
return success;
}
/** @see move(Email, EmailFolder) */
public boolean move(String messageId, EmailFolder newFolder) {
Email email = getEmail(messageId);
if (email == null) {
log.error("Cannot move email: Email with message ID " + messageId + " not found in folder <" + getStorageDirectory() + ">.");
return false;
}
else
return move(email, newFolder);
}
private File getEmailFile(Email email) {
return getEmailFile(email.getMessageID(), email.isNew());
}
/**
* Returns a file in the file system for a given message ID, or <code>null</code> if
* none exists.
* @param messageId
* @return
*/
private File getEmailFile(String messageId) {
// try new email
File newEmailFile = getEmailFile(messageId, true);
if (newEmailFile.exists())
return newEmailFile;
// try old email
File oldEmailFile = getEmailFile(messageId, false);
if (oldEmailFile.exists())
return oldEmailFile;
return null;
}
private File getEmailFile(String messageId, boolean newIndicator) {
return new File(storageDir, (newIndicator?'N':'O') + "_" + messageId + EMAIL_FILE_EXTENSION);
}
/**
* @see Folder.getNumElements()
* @return
*/
public int getNumNewEmails() {
int numNew = 0;
for (File file: getFilenames())
if (isNew(file))
numNew++;
return numNew;
}
private boolean isNew(File file) {
switch (file.getName().charAt(0)) {
case 'N':
return true;
case 'O':
return false;
default:
throw new IllegalArgumentException("Illegal email filename, doesn't start with N or O: <" + file.getAbsolutePath() + ">");
}
}
public void setNew(Email email, boolean isNew) {
String messageId = email.getMessageID();
if (messageId != null) {
boolean success = setNew(messageId, isNew);
if (success)
email.setNew(isNew);
}
}
/**
* Flags an email "new" (if <code>isNew</code> is <code>true</code>) or
* "old" (if <code>isNew</code> is <code>false</code>).
* @param messageId
* @param isNew
* @return true if the email file was renamed, false if something went wrong
*/
public boolean setNew(String messageId, boolean isNew) {
File file = getEmailFile(messageId);
if (file != null) {
char newIndicator = isNew?'N':'O'; // the new start character
String newFilename = newIndicator + file.getName().substring(1);
File newFile = new File(file.getParentFile(), newFilename);
boolean success = file.renameTo(newFile);
if (!success)
log.error("Cannot rename <" + file.getAbsolutePath() + "> to <" + newFile.getAbsolutePath() + ">");
return success;
}
else {
log.error("No email found for message Id: <" + messageId + ">");
return false;
}
}
/**
* Deletes an email with a given message ID.
* @param messageId
* @return <code>true</code> if the email was deleted, <code>false</code> otherwise
*/
public boolean delete(String messageId) {
File emailFile = getEmailFile(messageId);
if (emailFile != null)
return emailFile.delete();
else
return false;
}
public void delete(Email email) {
if (!getEmailFile(email).delete())
log.error("Cannot delete file: '" + getEmailFile(email) + "'");
}
@Override
protected Email createFolderElement(File file) throws Exception {
Email email = new Email(file);
email.setNew(isNew(file));
String messageIdString = file.getName().substring(2, 46);
email.setMessageID(messageIdString);
return email;
}
}

View File

@@ -1,9 +0,0 @@
package i2p.bote.folder;
/** Interface for folders whose content expires */
public interface ExpirationListener {
final static long EXPIRATION_TIME_MILLISECONDS = 100 * 24 * 3600 * 1000L; // keep for up to 100 days
/** Deletes any expired content */
void deleteExpired();
}

View File

@@ -1,134 +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.Comparator;
import java.util.Iterator;
import java.util.List;
import net.i2p.util.Log;
/**
*
* @param <T> The type of objects the folder can store.
*/
public abstract class Folder<T> 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 int getNumElements() {
return getFilenames().length;
}
/**
* Returns the names of all files in the folder.
* @return
*/
public File[] getFilenames() {
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
// sort files by date, newest first
Arrays.sort(files, new Comparator<File>() {
@Override
public int compare(File f1, File f2) {
return (int)Math.signum(f2.lastModified() - f1.lastModified());
}
});
return files;
}
public List<T> getElements() {
List<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 = getFilenames();
log.debug(files.length + " files with the extension '" + fileExtension + "' found in '" + storageDir + "'.");
return new Iterator<T>() {
int nextIndex = 0;
File currentFile;
@Override
public boolean hasNext() {
return nextIndex < files.length;
}
@Override
public T next() {
currentFile = files[nextIndex];
nextIndex++;
String filePath = currentFile.getAbsolutePath();
log.debug("Reading file: '" + filePath + "'");
try {
T nextElement = createFolderElement(currentFile);
return nextElement;
}
catch (Exception e) {
log.error("Can't create a FolderElement from file: " + filePath, e);
return null;
}
}
@Override
public void remove() {
if (currentFile == null)
throw new IllegalStateException("remove() was called before next()");
if (!currentFile.delete())
log.error("Can't delete file: <" + currentFile.getAbsolutePath() + ">");
}
};
}
protected abstract T createFolderElement(File file) throws Exception;
}

View File

@@ -1,76 +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.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);
}
/**
* Saves a packet to a file in the folder. If the file already exists, it is overwritten.
* @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);
}
}
}
@Override
@SuppressWarnings("unchecked")
protected PacketType createFolderElement(File file) throws Exception {
return (PacketType)DataPacket.createPacket(file);
}
}

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.UniqueId;
import i2p.bote.packet.RelayDataPacket;
import java.io.File;
import java.util.Random;
import net.i2p.util.Log;
/**
* A <code>PacketFolder</code> that uses filenames that consist of
* the packet's scheduled send time and a random part.
*/
public class RelayPacketFolder extends PacketFolder<RelayDataPacket> {
private final Log log = new Log(RelayPacketFolder.class);
private Random random;
public RelayPacketFolder(File storageDir) {
super(storageDir);
random = new Random();
}
/**
* Stores a <code>RelayDataPacket</code> in the folder.
* @param packet
*/
public void add(RelayDataPacket packet) {
while (true) {
UniqueId id = new UniqueId();
long minDelay = packet.getMinimumDelay();
long maxDelay = packet.getMaximumDelay();
// generate a random time between minDelay and maxDelay milliseconds in the future
long sendTime;
if (minDelay == maxDelay)
sendTime = System.currentTimeMillis() + minDelay;
else
sendTime = System.currentTimeMillis() + minDelay + Math.abs(random.nextLong()) % Math.abs(maxDelay-minDelay);
String filename = sendTime + "_" + id.toBase32() + PACKET_FILE_EXTENSION;
File file = new File(storageDir, filename);
if (!file.exists()) {
add(packet, filename);
return;
}
}
}
@Override
protected RelayDataPacket createFolderElement(File file) throws Exception {
RelayDataPacket packet = super.createFolderElement(file);
try {
long sendTime = getSendTime(file.getName());
packet.setSendTime(sendTime);
}
catch (NumberFormatException e) {
log.error("Invalid send time in filename: <" + file.getAbsolutePath() + ">", e);
}
return packet;
}
private long getSendTime(String filename) throws NumberFormatException {
String[] parts = filename.split("_");
return Long.valueOf(parts[0]);
}
}

View File

@@ -1,80 +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 net.i2p.data.Destination;
public class RelayPeer extends Destination {
private long requestsSent;
private long responsesReceived;
/**
* Creates a new <code>RelayPeer</code> with the <code>requestsSent</code> and
* <code>responsesReceived</code> number set to <code>0</code>.
* @param destination
*/
public RelayPeer(Destination destination) {
this(destination, 0, 0);
}
public RelayPeer(Destination destination, long requestsSent, long responsesReceived) {
// initialize the Destination part of the RelayPeer
setCertificate(destination.getCertificate());
setSigningPublicKey(destination.getSigningPublicKey());
setPublicKey(destination.getPublicKey());
// initialize RelayPeer-specific fields
this.requestsSent = requestsSent;
this.responsesReceived = responsesReceived;
}
public synchronized long getRequestsSent() {
return requestsSent;
}
public synchronized long getResponsesReceived() {
return responsesReceived;
}
/** Increments the number of requests made to this <code>RelayPeer</code> by one */
public synchronized void requestSent() {
requestsSent++;
}
/** Increments the number of responses received from this <code>RelayPeer</code> by one */
public synchronized void responseReceived() {
responsesReceived++;
}
/**
* Returns the percentage of requests sent to this peer for which
* a response was received.
* If no request has been sent to the peer, <code>0</code> is returned.
* @return
*/
public synchronized int getReachability() {
if (requestsSent == 0)
return 0;
else
return (int)(100L * responsesReceived / requestsSent);
}
}

View File

@@ -1,4 +0,0 @@
# Each line in this file should be a 516-byte I2P destination key
# in Base64 format. Lines beginning with # are ignored.
AHZwTj~5kmXod-2jFj1RamSFMBijtEnp9x3FWrF19uJQQga~rH4OaAtqdrHBeKfSBwugWEQMI8~shhBpk3H~fgQEd24RntmItdFzCsdeKz~0WnYqvhZo-ZryXk6J08wTPX9hX8BWuJSTgQyJo7WvDEqxx2AxQUIDyWVPld7VdfrpNEFWTQPNo0YxQWqSlnhSZr~hIVEV6hRsRgAP89Il8tnRa0f2YqZI7Ac2p8btVTkXMExVfLqZ2Y6J71K53oJ1mXZCISGUVAJhRWhdl~QKT8x-V5~5iSLoGG0514E4KOGc1ViKhl4YvhfCVXezm-oVDT8e9QTgy1pYjk9U88ng7hg~vjlCx8g2F3zTbZMaMZch4K50j7cRHFxvWA47EiEw~AtlEWhzTyQY2HMfQE-Hj7CJISdoaPk3ehvpkSDPdLWDSeQ~7rSYujWBAH~KI1DViRElS-1oJ3rPLqNTA2IwywbbaCs0LnAX9NrTnwIx4X6~kr7Re8DLVw5Gn-vjsrYjAAAA
CYnzmb1axrzpDXEX9haV7qBT-jGxFmLmkV913DgPqgJ1lVcSfpIrTe4ETMsRRjd2JMvGJxBYznENH8oTlitVptNAe8HjXYxjPqCRkHeh3QCk9nZALTWxjGy90DUHytIytPwRYqIZlLneiePhVFgV-HXOne~Bsv-mT5zrfDIDNhkJlmyXq5vLcvTkqp-eDEMr6iC4njCNKjzHDxsTvwwecYSmzFDY2f0SMZhrmL3qKSofMVPwpEVwkBX7LF50TSOfPvIEVgX7uPKI~avIOrShksSdJ0ksDQkw5Q66tOp-yrgxh--FnQYnblfLMBhI5UyWuifV3HqGqctjjHfW2mEOVpIoarjgbdmN9knThRBlgC8gs7AffoYuKs~GbIsE4PpnJI2rS3skBfPoNcmBtUF2bfQZ6gb3zk8NH7alXWMciF3wXyLka2FBuQKQQz4fUuraVzQu0COncv0hpmV5CIO7HWTs8pdem6~r0NydoRF3wrGj8xDeySTVJfmDfXCKhi0GAAAA

View File

@@ -1,207 +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 static i2p.bote.network.kademlia.KademliaConstants.REPLICATE_INTERVAL;
import static i2p.bote.network.kademlia.KademliaConstants.REPLICATE_VARIANCE;
import i2p.bote.network.DhtStorageHandler;
import i2p.bote.network.I2PPacketDispatcher;
import i2p.bote.network.I2PSendQueue;
import i2p.bote.network.PacketListener;
import i2p.bote.packet.CommunicationPacket;
import i2p.bote.packet.DeleteRequest;
import i2p.bote.packet.dht.DhtStorablePacket;
import i2p.bote.packet.dht.StoreRequest;
import i2p.bote.service.I2PBoteThread;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
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 basic algorithm goes like this:
*
* 1. Do a lookup for the local node ID to refresh the s-bucket
* 2. For each locally stored DHT item (index packet entries and email packets) that has not been deleted:
* a. Store the entry on the k closest nodes, based on info from local buckets
* b. If at least one peer responds with a valid delete request,
* - delete it locally (this is already handled by code outside this class), and
* - send a delete request to the nodes that didn't respond (which they
* won't if they don't know the packet has been deleted)
* c. Otherwise, replication for that entry is finished.
*/
public class ReplicateThread extends I2PBoteThread implements PacketListener {
private static final int WAIT_TIME_SECONDS = 5; // amount of time to wait after sending <number of nodes> store requests
private final Log log = new Log(ReplicateThread.class);
private Destination localDestination;
private I2PSendQueue sendQueue;
private I2PPacketDispatcher i2pReceiver;
private BucketManager bucketManager;
private CountDownLatch startSignal;
private Random rng;
private long nextReplicationTime;
private Map<DhtStorageHandler, Set<Hash>> upToDateKeys; // all DHT keys that have been re-stored since the last replication
private Map<Destination, DeleteRequest> receivedDeleteRequests; // null when not replicating
public ReplicateThread(Destination localDestination, I2PSendQueue sendQueue, I2PPacketDispatcher i2pReceiver, BucketManager bucketManager, CountDownLatch startSignal) {
super("ReplicateThd");
this.localDestination = localDestination;
this.sendQueue = sendQueue;
this.i2pReceiver = i2pReceiver;
this.bucketManager = bucketManager;
this.startSignal = startSignal;
rng = new Random();
upToDateKeys = new ConcurrentHashMap<DhtStorageHandler, Set<Hash>>();
}
void addDhtStoreToReplicate(DhtStorageHandler dhtStore) {
upToDateKeys.put(dhtStore, new ConcurrentHashSet<Hash>());
}
private long randomTime(long min, long max) {
if (min < max)
return min + rng.nextLong() % (max-min);
else
return min;
}
private void replicate() throws InterruptedException {
log.debug("Replicating DHT data...");
// refresh peers close to the local dest (essentially a refresh of the s-bucket)
ClosestNodesLookupTask lookupTask = new ClosestNodesLookupTask(localDestination.calculateHash(), sendQueue, i2pReceiver, bucketManager);
lookupTask.run();
List<Destination> closestNodes = lookupTask.getResults();
closestNodes.remove(localDestination);
HashCash hashCash;
try {
hashCash = HashCash.mintCash("", 1); // TODO
}
catch (NoSuchAlgorithmException e) {
log.error("Can't generate HashCash for replication requests, aborting replication.", e);
return;
}
receivedDeleteRequests = new ConcurrentHashMap<Destination, DeleteRequest>();
// 3 possible ways of sending out the store requests:
//
// 1. Send the first store request to all k nodes, send the next store request to all k nodes, etc.
// Downside: If the first node responds with a delete request, all other store requests are sent unnecessarily;
// this can be fixed by waiting after each request, but replication will take much longer
// (numNodes*numPackets*waitTime).
// 2. Send all packets to the first node, wait for responses, send all packets to the second node, wait, etc.
// Downside: Nodes are bombarded with packets
// 3. Send packet 0 to node 0, send packet 1 to node 1, etc. until packet k-1 is sent to node k-1. Wait for
// responses, then send packet 0 to node 1, send packet 1 to node 2, etc. until packet k-1 is sent to node k.
// If the node index would exceed the number of nodes, subtract the number of nodes.
// Repeat [number of nodes] times.
// This method avoids the downsides of (1) and (2).
//
// For now, method (2) is used because it is easier to implement than (3).
//
for (Destination node: closestNodes) {
for (DhtStorageHandler dhtStore: upToDateKeys.keySet()) {
Iterator<? extends DhtStorablePacket> packetIterator = dhtStore.individualPackets();
while (packetIterator.hasNext()) {
DhtStorablePacket packet = packetIterator.next();
StoreRequest request = new StoreRequest(hashCash, packet);
sendQueue.send(request, node);
}
}
TimeUnit.SECONDS.sleep(WAIT_TIME_SECONDS);
DeleteRequest delRequest = receivedDeleteRequests.get(node);
if (delRequest != null)
// send the delete request to all other nodes
for (Destination otherNode: closestNodes)
sendQueue.send(delRequest, otherNode);
}
for (DhtStorageHandler dhtStore: upToDateKeys.keySet())
upToDateKeys.get(dhtStore).clear();
receivedDeleteRequests = null;
log.debug("Replication finished.");
}
/**
* Informs the <code>ReplicationThread</code> that a packet has been stored in a local folder.
* @param folder
* @param packet
*/
public void packetStored(DhtStorageHandler folder, DhtStorablePacket packet) {
Set<Hash> keys = upToDateKeys.get(folder);
keys.add(packet.getDhtKey());
}
@Override
public void run() {
// wait for startSignal
while (!shutdownRequested()) {
try {
if (startSignal.await(1, TimeUnit.SECONDS))
break;
} catch (InterruptedException e) {
log.error("Replication thread interrupted!", e);
}
}
// Replicate on startup and every REPLICATE_INTERVAL seconds after that
nextReplicationTime = System.currentTimeMillis();
while (!shutdownRequested()) {
try {
replicate();
} catch (InterruptedException e) {
log.error("Interrupted while replicating!", e);
return;
}
long waitTime = randomTime(REPLICATE_INTERVAL-REPLICATE_VARIANCE, REPLICATE_INTERVAL+REPLICATE_VARIANCE);
nextReplicationTime += waitTime;
log.debug("Next replication at " + new Date(nextReplicationTime));
awaitShutdownRequest(waitTime, TimeUnit.SECONDS);
}
}
// PacketListener implementation
@Override
public void packetReceived(CommunicationPacket packet, Destination sender, long receiveTime) {
if (packet instanceof DeleteRequest && receivedDeleteRequests!=null)
receivedDeleteRequests.put(sender, (DeleteRequest)packet);
}
}

View File

@@ -1,13 +0,0 @@
package i2p.bote.packet;
public abstract class DeleteRequest extends CommunicationPacket {
protected DeleteRequest() {
}
protected DeleteRequest(byte[] data) {
super(data);
}
public abstract Class<? extends I2PBotePacket> getDataType();
}

View File

@@ -1,130 +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.packet;
import i2p.bote.I2PBote;
import i2p.bote.packet.dht.FindClosePeersPacket;
import i2p.bote.packet.dht.RetrieveRequest;
import i2p.bote.packet.dht.StoreRequest;
import java.nio.ByteBuffer;
import net.i2p.data.Hash;
import net.i2p.util.Log;
public abstract class I2PBotePacket {
private static final int MAX_DATAGRAM_SIZE = 31 * 1024;
private static final Log log = new Log(I2PBotePacket.class);
@SuppressWarnings("unchecked")
private static Class<? extends I2PBotePacket>[] ALL_PACKET_TYPES = new Class[] {
RelayDataPacket.class, RelayRequest.class, ResponsePacket.class, RetrieveRequest.class, StoreRequest.class,
FindClosePeersPacket.class, PeerListRequest.class, PeerList.class,
EncryptedEmailPacket.class, UnencryptedEmailPacket.class, EmailPacketDeleteRequest.class,
IndexPacket.class, IndexPacketDeleteRequest.class, DeletionInfoPacket.class
};
private int protocolVersion;
/**
* Creates a new <code>I2PBotePacket</code> with the current protocol version.
*/
protected I2PBotePacket() {
protocolVersion = I2PBote.PROTOCOL_VERSION;
}
protected I2PBotePacket(int protocolVersion) {
this.protocolVersion = protocolVersion;
}
public abstract byte[] toByteArray();
/**
* Returns the size of the packet in bytes.
* @return
*/
// TODO rename to getPacketSize
// TODO override in subclasses to avoid calling toByteArray by adding field lengths
public int getSize() {
return toByteArray().length;
}
/**
* Returns <code>false</code> if this packet can't fit into an I2P datagram.
* @return
*/
public boolean isTooBig() {
return getSize() > MAX_DATAGRAM_SIZE;
}
protected char getPacketTypeCode(Class<? extends I2PBotePacket> dataType) {
return dataType.getAnnotation(TypeCode.class).value();
}
public char getPacketTypeCode() {
return getPacketTypeCode(getClass());
}
/**
* Logs an error if the packet type of the packet instance is not correct
* @param packetTypeCode
*/
protected void checkPacketType(char packetTypeCode) {
if (getPacketTypeCode() != packetTypeCode)
log.error("Packet type code of class " + getClass().getSimpleName() + " should be " + getPacketTypeCode() + ", is <" + packetTypeCode + ">");
}
protected void checkPacketType(byte packetTypeCode) {
checkPacketType((char)packetTypeCode);
}
/**
* Returns the version of the I2P-Bote network protocol used by this packet.
* @return
*/
public int getProtocolVersion() {
return protocolVersion;
}
/**
* Creates a {@link Hash} from bytes read from a {@link ByteBuffer}.
* No check is done to make sure the buffer has enough bytes available.
*/
protected Hash readHash(ByteBuffer buffer) {
byte[] bytes = new byte[Hash.HASH_LENGTH];
buffer.get(bytes);
return new Hash(bytes);
}
protected static Class<? extends I2PBotePacket> decodePacketTypeCode(char packetTypeCode) {
for (Class<? extends I2PBotePacket> packetType: ALL_PACKET_TYPES)
if (packetType.getAnnotation(TypeCode.class).value() == packetTypeCode)
return packetType;
log.debug("Invalid type code for I2PBotePacket: <" + packetTypeCode + ">");
return null;
}
@Override
public String toString() {
return "Type=" + getClass().getSimpleName() + ", code=<" + getPacketTypeCode() + ">, sizeBytes=" + getSize();
}
}

View File

@@ -1,191 +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.packet;
import i2p.bote.Util;
import i2p.bote.service.RelayPeerManager;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.util.Log;
/**
* A <code>RelayDataPacket</code> contains a {@link RelayRequest},
* an I2P destination to send it to, and a time window for the send time.
*/
@TypeCode('R')
public class RelayDataPacket extends DataPacket {
private Log log = new Log(RelayDataPacket.class);
private long minDelay;
private long maxDelay;
private long sendTime;
private Destination nextDestination;
private RelayRequest request;
/**
*
* @param nextDestination The I2P destination to send the packet to
* @param minDelayMilliseconds In milliseconds
* @param maxDelayMilliseconds In milliseconds
* @param request
*/
public RelayDataPacket(Destination nextDestination, long minDelayMilliseconds, long maxDelayMilliseconds, RelayRequest request) {
this.nextDestination = nextDestination;
this.minDelay = minDelayMilliseconds;
this.maxDelay = maxDelayMilliseconds;
this.request = request;
}
public RelayDataPacket(byte[] data) throws DataFormatException, MalformedDataPacketException {
super(data);
ByteBuffer buffer = ByteBuffer.wrap(data, HEADER_LENGTH, data.length-HEADER_LENGTH);
minDelay = buffer.getInt() * 1000L;
maxDelay = buffer.getInt() * 1000L;
nextDestination = Util.createDestination(buffer);
int requestDataLength = buffer.getShort();
byte[] requestBytes = new byte[requestDataLength];
buffer.get(requestBytes);
request = new RelayRequest(requestBytes);
if (buffer.hasRemaining())
log.debug("Relay Packet has " + buffer.remaining() + " extra bytes.");
}
/**
* Creates a <code>RelayDataPacket</code> containing <code>numHops</code> nested
* <code>RelayRequest</code>s, each containing a <code>RelayDataPacket</code>.
* Returns <code>null</code> if <code>numHops</code> is <code>0</code>.
*
* If <code>numHops = 1</code>, the finished packet looks as follows (outermost to innermost):
*
* Unencrypted RelayDataPacket
* RelayRequest
* Encrypted DataPacket
*
* For <code>numHops = 2</code>:
*
* Unencrypted RelayDataPacket
* RelayRequest
* Encrypted RelayDataPacket
* RelayRequest
* Encrypted DataPacket
*
* Each additional hop adds an encrypted <code>RelayDataPacket</code> and a <code>RelayRequest</code>.
* @param payload
* @param peerManager
* @param numHops
* @param minDelayMilliseconds
* @param maxDelayMilliseconds
* @return
*/
public static RelayDataPacket create(DataPacket payload, RelayPeerManager peerManager, int numHops, long minDelayMilliseconds, long maxDelayMilliseconds) {
List<Destination> relayPeers = peerManager.getRandomPeers(numHops);
Log log = new Log(RelayDataPacket.class);
if (log.shouldLog(Log.DEBUG)) {
StringBuilder debugMsg = new StringBuilder("Creating relay chain: [");
for (int i=relayPeers.size()-1; i>=0; i--) {
debugMsg.append(relayPeers.get(i).calculateHash().toBase64().substring(0, 8));
if (i > 0)
debugMsg.append("... --> ");
}
debugMsg.append("...]");
log.debug(debugMsg.toString());
}
DataPacket dataPacket = payload;
for (Iterator<Destination> iterator=relayPeers.iterator(); iterator.hasNext();) {
Destination relayPeer = iterator.next();
RelayRequest request = new RelayRequest(dataPacket, relayPeer);
dataPacket = new RelayDataPacket(relayPeer, minDelayMilliseconds, maxDelayMilliseconds, request);
}
return (RelayDataPacket)dataPacket;
}
public Destination getNextDestination() {
return nextDestination;
}
/** Returns the minimum delay time for this packet in milliseconds */
public long getMinimumDelay() {
return minDelay;
}
/** Returns the maximum delay time for this packet in milliseconds */
public long getMaximumDelay() {
return maxDelay;
}
/**
* @param The time the packet is scheduled for sending, in milliseconds since 1-1-1970
*/
public void setSendTime(long sendTime) {
this.sendTime = sendTime;
}
/**
* @return The time the packet is scheduled for sending, in milliseconds since 1-1-1970
*/
public long getSendTime() {
return sendTime;
}
/**
* Returns the <code>RelayRequest</code> this packet contains.
* @return
*/
public RelayRequest getRequest() {
return request;
}
@Override
public byte[] toByteArray() {
ByteArrayOutputStream arrayOutputStream = new ByteArrayOutputStream();
DataOutputStream dataStream = new DataOutputStream(arrayOutputStream);
try {
writeHeader(dataStream);
dataStream.writeInt((int)(minDelay/1000));
dataStream.writeInt((int)(maxDelay/1000));
// write the first 384 bytes (the two public keys)
dataStream.write(nextDestination.toByteArray(), 0, 384);
byte[] requestBytes = request.toByteArray();
dataStream.writeShort(requestBytes.length);
dataStream.write(requestBytes);
}
catch (IOException e) {
log.error("Can't write to ByteArrayOutputStream.", e);
}
return arrayOutputStream.toByteArray();
}
}

View File

@@ -1,140 +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.packet;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.security.NoSuchAlgorithmException;
import net.i2p.I2PAppContext;
import net.i2p.client.I2PSession;
import net.i2p.data.DataFormatException;
import net.i2p.data.Destination;
import net.i2p.data.PrivateKey;
import net.i2p.data.PublicKey;
import net.i2p.data.SessionKey;
import net.i2p.util.Log;
import com.nettgryppa.security.HashCash;
/**
* A <code>RelayRequest</code> contains an encrypted {@link RelayDataPacket} or {@link DhtStorablePacket}.
*/
@TypeCode('Y')
public class RelayRequest extends CommunicationPacket {
private static final int PADDED_SIZE = 16; // pad to the length of an AES-256 block (not to be confused with the AES key size)
private Log log = new Log(RelayRequest.class);
private HashCash hashCash;
private byte[] payload; // a DataPacket
/**
* Creates a <code>RelayRequest</code> that contains an encrypted <code>DataPacket</code>.
* @param payload
* @param destination
*/
public RelayRequest(DataPacket payload, Destination destination) {
try {
hashCash = HashCash.mintCash("", 1); // TODO
} catch (NoSuchAlgorithmException e) {
log.error("Cannot create HashCash.", e);
}
this.payload = encrypt(payload, destination);
}
public RelayRequest(byte[] data) throws MalformedDataPacketException {
super(data);
ByteBuffer buffer = ByteBuffer.wrap(data, HEADER_LENGTH, data.length-HEADER_LENGTH);
int hashCashLength = buffer.getShort();
byte[] hashCashData = new byte[hashCashLength];
buffer.get(hashCashData);
try {
hashCash = new HashCash(new String(hashCashData));
} catch (NoSuchAlgorithmException e) {
log.error("Cannot create HashCash.", e);
}
int payloadLength = buffer.getShort();
payload = new byte[payloadLength];
buffer.get(payload);
if (buffer.hasRemaining())
log.debug("Storage Request Packet has " + buffer.remaining() + " extra bytes.");
}
public HashCash getHashCash() {
return hashCash;
}
/**
* Returns the payload packet, i.e. the data that is being relayed.
* @return
* @throws DataFormatException
* @throws MalformedDataPacketException
*/
public DataPacket getStoredPacket(I2PSession i2pSession) throws DataFormatException, MalformedDataPacketException {
return decrypt(i2pSession);
}
@Override
public byte[] toByteArray() {
ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
DataOutputStream dataStream = new DataOutputStream(byteArrayStream);
try {
writeHeader(dataStream);
String hashCashString = hashCash.toString();
dataStream.writeShort(hashCashString.length());
dataStream.write(hashCashString.getBytes());
dataStream.writeShort(payload.length);
dataStream.write(payload);
}
catch (IOException e) {
log.error("Can't write to ByteArrayOutputStream.", e);
}
return byteArrayStream.toByteArray();
}
private byte[] encrypt(DataPacket dataPacket, Destination destination) {
PublicKey publicKey = destination.getPublicKey();
I2PAppContext appContext = I2PAppContext.getGlobalContext();
SessionKey sessionKey = appContext.sessionKeyManager().createSession(publicKey);
byte[] data = dataPacket.toByteArray();
return appContext.elGamalAESEngine().encrypt(data, publicKey, sessionKey, PADDED_SIZE);
}
/**
* Decrypts the <code>RelayDataPacket</code> inside this packet.
* @throws DataFormatException
* @throws MalformedDataPacketException
*/
private DataPacket decrypt(I2PSession i2pSession) throws DataFormatException, MalformedDataPacketException {
PrivateKey privateKey = i2pSession.getDecryptionKey();
I2PAppContext appContext = I2PAppContext.getGlobalContext();
byte[] decryptedData = appContext.elGamalAESEngine().decrypt(payload, privateKey, appContext.sessionKeyManager());
return DataPacket.createPacket(decryptedData);
}
}

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