Changeset 8161f099
- Timestamp:
- Feb 8, 2018 2:46:41 PM (3 years ago)
- Branches:
- master
- Children:
- 3d25a9f
- Parents:
- 7da3de2
- Files:
-
- 1 added
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
apps/susimail/src/src/i2p/susi/webmail/Mail.java
r7da3de2 r8161f099 29 29 import i2p.susi.util.CountingInputStream; 30 30 import i2p.susi.util.EOFOnMatchInputStream; 31 import i2p.susi.util.FileBuffer; 31 32 import i2p.susi.util.MemoryBuffer; 32 33 import i2p.susi.webmail.encoding.Encoding; … … 47 48 import java.util.regex.Pattern; 48 49 50 import net.i2p.I2PAppContext; 49 51 import net.i2p.data.DataHelper; 50 52 import net.i2p.servlet.util.ServletUtil; 53 import net.i2p.util.RFC822Date; 51 54 import net.i2p.util.SystemVersion; 52 55 … … 130 133 if (closeIn) 131 134 rb.readComplete(true); 135 // set a date if we didn't get one in the headers 136 if (date == null) { 137 long dateLong; 138 if (rb instanceof FileBuffer) { 139 dateLong = ((FileBuffer) rb).getFile().lastModified(); 140 } else { 141 dateLong = I2PAppContext.getGlobalContext().clock().now(); 142 } 143 setDate(dateLong); 144 } 132 145 return rv; 133 146 } … … 176 189 Debug.debug(Debug.ERROR, "Parse error", e); 177 190 } finally { 178 try { in.close(); } catch (IOException ioe) {}191 if (in != null) try { in.close(); } catch (IOException ioe) {} 179 192 rb.readComplete(success); 180 193 } … … 324 337 private static final DateFormat localDateFormatter = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); 325 338 private static final DateFormat longLocalDateFormatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); 326 private static final DateFormat mailDateFormatter = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH );327 339 static { 328 340 // the router sets the JVM time zone to UTC but saves the original here so we can get it … … 330 342 localDateFormatter.setTimeZone(tz); 331 343 longLocalDateFormatter.setTimeZone(tz); 344 } 345 346 /** 347 * @param dateLong non-negative 348 * @since 0.9.34 pulled from parseHeaders() 349 */ 350 private void setDate(long dateLong) { 351 date = new Date(dateLong); 352 synchronized(dateFormatter) { 353 formattedDate = dateFormatter.format( date ); 354 localFormattedDate = localDateFormatter.format( date ); 355 quotedDate = longLocalDateFormatter.format(date); 356 } 332 357 } 333 358 … … 391 416 else if (hlc.startsWith("date:")) { 392 417 dateString = line.substring( 5 ).trim(); 393 try { 394 synchronized(mailDateFormatter) { 395 date = mailDateFormatter.parse( dateString ); 396 formattedDate = dateFormatter.format( date ); 397 localFormattedDate = localDateFormatter.format( date ); 398 //quotedDate = html.encode( dateString ); 399 quotedDate = longLocalDateFormatter.format(date); 400 } 401 } 402 catch (ParseException e) { 403 date = null; 404 e.printStackTrace(); 405 } 418 long dateLong = RFC822Date.parse822Date(dateString); 419 if (dateLong > 0) 420 setDate(dateLong); 406 421 } 407 422 else if (hlc.startsWith("subject:")) { -
apps/susimail/src/src/i2p/susi/webmail/MailCache.java
r7da3de2 r8161f099 73 73 PersistentMailCache pmc = null; 74 74 try { 75 pmc = new PersistentMailCache( host, port, user, pass, PersistentMailCache.DIR_FOLDER);75 pmc = new PersistentMailCache(ctx, host, port, user, pass, PersistentMailCache.DIR_FOLDER); 76 76 // TODO Drafts, Sent, Trash 77 77 } catch (IOException ioe) { -
apps/susimail/src/src/i2p/susi/webmail/MailPart.java
r7da3de2 r8161f099 203 203 DataHelper.copy(eofin, dummy); 204 204 if (!eofin.wasFound()) 205 Debug.debug(Debug.DEBUG, "EOF hit before first boundary " + boundary );205 Debug.debug(Debug.DEBUG, "EOF hit before first boundary " + boundary + " UIDL: " + uidl); 206 206 if (readBoundaryTrailer(in)) { 207 207 if (!eofin.wasFound()) 208 Debug.debug(Debug.DEBUG, "EOF hit before first part body " + boundary );208 Debug.debug(Debug.DEBUG, "EOF hit before first part body " + boundary + " UIDL: " + uidl); 209 209 tmpEnd = (int) eofin.getRead(); 210 210 break; … … 221 221 DataHelper.copy(eofin, DUMMY_OUTPUT); 222 222 if (!eofin.wasFound()) 223 Debug.debug(Debug.DEBUG, "EOF hit before end of body " + i + " boundary: " + boundary );223 Debug.debug(Debug.DEBUG, "EOF hit before end of body " + i + " boundary: " + boundary + " UIDL: " + uidl); 224 224 } 225 225 if (readBoundaryTrailer(in)) … … 352 352 } 353 353 354 /** 355 * @param attributeName must be lower case, will be matched case-insensitively 356 * @return as found, not necessarily lower case 357 */ 354 358 private static String getHeaderLineAttribute( String line, String attributeName ) 355 359 { 360 String lineLC = line.toLowerCase(Locale.US); 356 361 String result = null; 357 362 int h = 0; 358 363 int l = attributeName.length(); 359 364 while( true ) { 360 int i = line .indexOf( attributeName, h);365 int i = lineLC.indexOf(attributeName, h); 361 366 // System.err.println( "i=" + i ); 362 367 if( i == -1 ) -
apps/susimail/src/src/i2p/susi/webmail/PersistentMailCache.java
r7da3de2 r8161f099 5 5 import i2p.susi.util.Buffer; 6 6 import i2p.susi.util.FileBuffer; 7 import i2p.susi.util.FixCRLFOutputStream; 7 8 import i2p.susi.util.GzipFileBuffer; 8 9 import i2p.susi.util.ReadBuffer; … … 20 21 import java.util.Hashtable; 21 22 import java.util.List; 23 import java.util.Locale; 22 24 import java.util.concurrent.ConcurrentHashMap; 23 25 import java.util.zip.GZIPInputStream; … … 61 63 private final Object _lock; 62 64 private final File _cacheDir; 65 private final I2PAppContext _context; 63 66 64 67 private static final String DIR_SUSI = "susimail"; … … 69 72 public static final String DIR_SENT = "Sent"; // MailDir-like 70 73 public static final String DIR_TRASH = "Trash"; // MailDir-like 74 public static final String DIR_SPAM = "Bulk Mail"; // MailDir-like 75 public static final String DIR_IMPORT = "import"; // Flat with .eml files, debug only for now 71 76 private static final String DIR_PREFIX = "s"; 72 77 private static final String FILE_PREFIX = "mail-"; … … 80 85 * @param folder use DIR_FOLDER 81 86 */ 82 public PersistentMailCache(String host, int port, String user, String pass, String folder) throws IOException { 87 public PersistentMailCache(I2PAppContext ctx, String host, int port, String user, String pass, String folder) throws IOException { 88 _context = ctx; 83 89 _lock = getLock(host, port, user, pass); 84 90 synchronized(_lock) { 85 91 _cacheDir = makeCacheDirs(host, port, user, pass, folder); 92 // Debugging only for now. 93 if (folder.equals(DIR_FOLDER)) 94 importMail(); 86 95 } 87 96 } … … 210 219 * folder1 is the base. 211 220 */ 212 private staticFile makeCacheDirs(String host, int port, String user, String pass, String folder) throws IOException {213 File f = new SecureDirectory( I2PAppContext.getGlobalContext().getConfigDir(), DIR_SUSI);221 private File makeCacheDirs(String host, int port, String user, String pass, String folder) throws IOException { 222 File f = new SecureDirectory(_context.getConfigDir(), DIR_SUSI); 214 223 if (!f.exists() && !f.mkdir()) 215 224 throw new IOException("Cannot create " + f); … … 308 317 return mail; 309 318 } 319 320 /** 321 * For debugging. Import .eml files from the import/ directory 322 * @since 0.9.34 323 */ 324 private void importMail() { 325 File importDir = new File(_cacheDir.getParentFile(), DIR_IMPORT); 326 if (importDir.exists() && importDir.isDirectory()) { 327 File[] files = importDir.listFiles(); 328 if (files == null) 329 return; 330 for (int i = 0; i < files.length; i++) { 331 File f = files[i]; 332 if (!f.isFile()) 333 continue; 334 if (!f.getName().toLowerCase(Locale.US).endsWith(".eml")) 335 continue; 336 // Read in the headers to get the X-UIDL that Thunderbird stuck in there 337 String uidl = Long.toString(_context.random().nextLong()); 338 InputStream in = null; 339 try { 340 in = new FileInputStream(f); 341 for (int j = 0; j < 20; j++) { 342 String line = DataHelper.readLine(in); 343 if (line.length() < 2) 344 break; 345 if (line.startsWith("X-UIDL:")) { 346 uidl = line.substring(7).trim(); 347 break; 348 } 349 } 350 } catch (IOException ioe) { 351 Debug.debug(Debug.ERROR, "Import failed " + f, ioe); 352 continue; 353 } finally { 354 if (in != null) 355 try { in.close(); } catch (IOException ioe) {} 356 } 357 if (uidl == null) 358 uidl = Long.toString(_context.random().nextLong()); 359 File to = getFullFile(uidl); 360 if (to.exists()) { 361 Debug.debug(Debug.DEBUG, "Already have " + f + " as UIDL " + uidl); 362 f.delete(); 363 continue; 364 } 365 in = null; 366 OutputStream out = null; 367 try { 368 in = new FileInputStream(f); 369 GzipFileBuffer gb = new GzipFileBuffer(to); 370 // Thunderbird exports aren't CRLF terminated 371 out = new FixCRLFOutputStream(gb.getOutputStream()); 372 DataHelper.copy(in, out); 373 } catch (IOException ioe) { 374 Debug.debug(Debug.ERROR, "Import failed " + f, ioe); 375 continue; 376 } finally { 377 if (in != null) 378 try { in.close(); } catch (IOException ioe) {} 379 if (out != null) 380 try { out.close(); } catch (IOException ioe) {} 381 } 382 f.delete(); 383 Debug.debug(Debug.DEBUG, "Imported " + f + " as UIDL " + uidl); 384 } 385 } 386 } 310 387 } -
apps/susimail/src/src/i2p/susi/webmail/WebMail.java
r7da3de2 r8161f099 636 636 if( chosen != null ) { 637 637 showPart( out, chosen, level + 1, html ); 638 if (html) { 639 // DEBUG 640 for (MailPart subPart : mailPart.parts) { 641 if (chosen.equals(subPart)) 642 continue; 643 out.println( "<!-- " ); 644 out.println( "Debug: Not showing alternative Mail Part at level " + (level + 1) + " with hash code " + mailPart.hashCode()); 645 out.println( "Debug: Mail Part headers follow"); 646 for( int i = 0; i < subPart.headerLines.length; i++ ) { 647 out.println( subPart.headerLines[i].replace("--", "--") ); 648 } 649 out.println( "-->" ); 650 } 651 } 638 652 return; 639 653 } … … 1500 1514 * process paging buttons 1501 1515 */ 1516 /**** not on the folder view any more, handled in processConfigButtons() 1502 1517 if (buttonPressed(request, SETPAGESIZE)) { 1503 1518 try { … … 1511 1526 } 1512 1527 } 1528 ****/ 1513 1529 if( buttonPressed( request, PREVPAGE ) ) { 1514 1530 String sp = request.getParameter(PREV_PAGE_NUM); … … 1627 1643 sessionObject.error += _t("Host unchanged. Edit configation file {0} to change host.", cfg.getAbsolutePath()) + '\n'; 1628 1644 } 1629 Config.saveConfiguration(props);1630 1645 String ps = props.getProperty(Folder.PAGESIZE); 1631 1646 if (sessionObject.folder != null && ps != null) { … … 1637 1652 } catch( NumberFormatException nfe ) {} 1638 1653 } 1654 Config.saveConfiguration(props); 1639 1655 boolean release = !Boolean.parseBoolean(props.getProperty(CONFIG_DEBUG)); 1640 1656 Debug.setLevel( release ? Debug.ERROR : Debug.DEBUG ); … … 1647 1663 try { 1648 1664 int pageSize = Math.max(5, Integer.parseInt(request.getParameter(PAGESIZE))); 1649 Properties props = Config.getProperties();1650 props.setProperty(Folder.PAGESIZE, String.valueOf(pageSize));1651 Config.saveConfiguration(props);1652 1665 if (sessionObject.folder != null) { 1653 1666 int oldPageSize = sessionObject.folder.getPageSize(); … … 1658 1671 state = State.AUTH; 1659 1672 } 1673 Properties props = Config.getProperties(); 1674 props.setProperty(Folder.PAGESIZE, String.valueOf(pageSize)); 1675 Config.saveConfiguration(props); 1660 1676 } catch (IOException ioe) { 1661 1677 sessionObject.error = ioe.toString(); … … 1898 1914 } 1899 1915 1900 //// End state determination, state will not change after here1901 Debug.debug(Debug.DEBUG, "Final state is " + state);1902 1903 1916 /* 1904 1917 * update folder content … … 1906 1919 */ 1907 1920 Folder<String> folder = sessionObject.folder; 1921 // folder could be null after an error, we can't proceed if it is 1922 if (folder == null && (state == State.LIST || state == State.SHOW)) { 1923 sessionObject.error += "Internal error, no folder\n"; 1924 state = State.AUTH; 1925 } 1926 1927 //// End state determination, state will not change after here 1928 Debug.debug(Debug.DEBUG, "Final state is " + state); 1929 1908 1930 if (state == State.LIST || state == State.SHOW) { 1931 1909 1932 // sort buttons are GETs 1910 1933 String oldSort = folder.getCurrentSortBy(); -
apps/susimail/src/src/i2p/susi/webmail/encoding/HeaderLine.java
r7da3de2 r8161f099 30 30 import i2p.susi.util.MemoryBuffer; 31 31 32 import java.io.EOFException; 32 33 import java.io.IOException; 33 34 import java.io.InputStream; … … 210 211 return out.toString(); 211 212 } 213 214 // could be 75 for quoted-printable only 215 private static final int DECODE_MAX = 256; 212 216 213 217 /** … … 236 240 } 237 241 if( c == '=' ) { 238 // An encoded-word is75 chars max including the delimiters, and must be on a single line242 // An encoded-word should be 75 chars max including the delimiters, and must be on a single line 239 243 // Store the full encoded word, including =? through ?=, in the buffer 244 // Sadly, base64 can be a lot longer 240 245 if (encodedWord == null) 241 encodedWord = new byte[ 75];246 encodedWord = new byte[DECODE_MAX]; 242 247 int offset = 0; 243 248 int f1 = 0, f2 = 0, f3 = 0, f4 = 0; … … 247 252 // We make a small attempt to pushback one char if it's not what we expect, 248 253 // but for the most part it gets thrown out, as RFC 2047 allows 249 for (; offset < 75; offset++) {254 for (; offset < DECODE_MAX; offset++) { 250 255 c = in.read(); 251 256 if (c == '?') { … … 319 324 Encoding e = EncodingFactory.getEncoding( enc ); 320 325 if( e != null ) { 321 // System.err.println( "encoder found" );322 326 try { 323 327 // System.err.println( "decode(" + (f3 + 1) + "," + ( f4 - f3 - 1 ) + ")" ); 324 328 ReadBuffer tmpIn = new ReadBuffer(encodedWord, f3 + 1, f4 - f3 - 1); 325 MemoryBuffer tmp = new MemoryBuffer(75); 326 e.decode(tmpIn, tmp); 329 MemoryBuffer tmp = new MemoryBuffer(DECODE_MAX); 330 try { 331 e.decode(tmpIn, tmp); 332 } catch (EOFException eof) { 333 // probably Base64 exceeded DECODE_MAX 334 // Keep going and output what we got, if any 335 if (Debug.getLevel() >= Debug.DEBUG) { 336 Debug.debug(Debug.DEBUG, "q-w " + enc, eof); 337 Debug.debug(Debug.DEBUG, net.i2p.util.HexDump.dump(encodedWord)); 338 } 339 } 327 340 tmp.writeComplete(true); 328 341 // get charset … … 358 371 continue; 359 372 } catch (IOException e1) { 360 Debug.debug(Debug.DEBUG, "q-w", e1); 361 Debug.debug(Debug.DEBUG, "Decoder: " + enc + " Input:"); 362 Debug.debug(Debug.DEBUG, net.i2p.util.HexDump.dump(encodedWord, f3 + 1, f4 - f3 - 1)); 373 Debug.debug(Debug.ERROR, "q-w " + enc, e1); 374 if (Debug.getLevel() >= Debug.DEBUG) { 375 Debug.debug(Debug.DEBUG, net.i2p.util.HexDump.dump(encodedWord)); 376 } 363 377 } catch (RuntimeException e1) { 364 Debug.debug(Debug.DEBUG, "q-w", e1); 365 Debug.debug(Debug.DEBUG, "Decoder: " + enc + " Input:"); 366 Debug.debug(Debug.DEBUG, net.i2p.util.HexDump.dump(encodedWord, f3 + 1, f4 - f3 - 1)); 378 Debug.debug(Debug.ERROR, "q-w " + enc, e1); 379 if (Debug.getLevel() >= Debug.DEBUG) { 380 Debug.debug(Debug.DEBUG, net.i2p.util.HexDump.dump(encodedWord)); 381 } 367 382 } 368 383 } else { -
history.txt
r7da3de2 r8161f099 1 2018-02-08 zzz 2 * SusiMail: 3 - Error handling fixes 4 - More tolerant parsing of Date headers 5 - Set a date if we don't get a Date header 6 - Fix parsing long Base64 encoded headers 7 - Fix page count after changing page size 8 - Make attribute name parsing case-insensitive 9 - Import mail method for debugging 10 1 11 2018-02-07 zzz 2 12 * SusiMail: Use input streams for reading mail (ticket #2119) -
router/java/src/net/i2p/router/RouterVersion.java
r7da3de2 r8161f099 19 19 public final static String ID = "Monotone"; 20 20 public final static String VERSION = CoreVersion.VERSION; 21 public final static long BUILD = 2;21 public final static long BUILD = 3; 22 22 23 23 /** for example "-test" */
Note: See TracChangeset
for help on using the changeset viewer.