From 31719d30cfd3c704c9e380349f74f909e9459a24 Mon Sep 17 00:00:00 2001 From: zzz <zzz@mail.i2p> Date: Fri, 9 Feb 2018 22:53:25 +0000 Subject: [PATCH] SusiMail: Improve speed of subject sorter Use ID instead of hashcode for mailparts, so attachments are bookmarkable Recognize fw: --- .../src/src/i2p/susi/webmail/Mail.java | 3 +- .../src/src/i2p/susi/webmail/MailPart.java | 18 +++++- .../src/src/i2p/susi/webmail/WebMail.java | 63 ++++++++++--------- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/apps/susimail/src/src/i2p/susi/webmail/Mail.java b/apps/susimail/src/src/i2p/susi/webmail/Mail.java index 26506a2912..e4f1bcb73b 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/Mail.java +++ b/apps/susimail/src/src/i2p/susi/webmail/Mail.java @@ -45,6 +45,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.Locale; import java.util.TimeZone; +import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; import net.i2p.I2PAppContext; @@ -179,7 +180,7 @@ class Mail { // TODO just fail? if (headerLines == null) headerLines = new String[0]; - part = new MailPart(uidl, rb, in, in, headerLines); + part = new MailPart(uidl, new AtomicInteger(), rb, in, in, headerLines); rb.readComplete(true); // may only be available after reading and calling readComplete() size = rb.getLength(); diff --git a/apps/susimail/src/src/i2p/susi/webmail/MailPart.java b/apps/susimail/src/src/i2p/susi/webmail/MailPart.java index a57a6dda5d..543926b7e6 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/MailPart.java +++ b/apps/susimail/src/src/i2p/susi/webmail/MailPart.java @@ -44,6 +44,7 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.concurrent.atomic.AtomicInteger; import net.i2p.data.DataHelper; @@ -79,6 +80,7 @@ class MailPart { * @since 0.9.33 */ public final String uidl; + private final int intID; /** * @param readBuffer has zero offset for top-level MailPart. @@ -88,9 +90,10 @@ class MailPart { * @param hdrlines non-null for top-level MailPart, where they * were already parsed in Mail. Null otherwise */ - public MailPart(String uidl, Buffer readBuffer, InputStream in, ReadCounter counter, String[] hdrlines) throws IOException + public MailPart(String uidl, AtomicInteger id, Buffer readBuffer, InputStream in, ReadCounter counter, String[] hdrlines) throws IOException { this.uidl = uidl; + intID = id.getAndIncrement(); buffer = readBuffer; parts = new ArrayList<MailPart>(4); @@ -219,7 +222,7 @@ class MailPart { match = DataHelper.getASCII("\r\n--" + boundary); eofin = new EOFOnMatchInputStream(in, counter, match); } - MailPart newPart = new MailPart(uidl, buffer, eofin, eofin, null); + MailPart newPart = new MailPart(uidl, id, buffer, eofin, eofin, null); parts.add( newPart ); tmpEnd = (int) eofin.getRead(); if (!eofin.wasFound()) { @@ -233,7 +236,7 @@ class MailPart { } } else if( message ) { - MailPart newPart = new MailPart(uidl, buffer, in, counter, null); + MailPart newPart = new MailPart(uidl, id, buffer, in, counter, null); // TODO newPart doesn't save message headers we might like to display, // like From, To, and Subject parts.add( newPart ); @@ -251,6 +254,15 @@ class MailPart { // Debug.debug(Debug.DEBUG, "New " + this); } + /** + * A value unique across all the parts of this Mail, + * and constant across restarts, so it may be part of a bookmark. + * + * @since 0.9.34 + */ + public int getID() { return intID; } + + /** * Swallow "\r\n" or "--\r\n". * We don't have any pushback if this goes wrong. diff --git a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java index d91484548a..64038723cf 100644 --- a/apps/susimail/src/src/i2p/susi/webmail/WebMail.java +++ b/apps/susimail/src/src/i2p/susi/webmail/WebMail.java @@ -132,9 +132,9 @@ public class WebMail extends HttpServlet * hidden params */ private static final String SUSI_NONCE = "susiNonce"; - private static final String B64UIDL = "b64uidl"; - private static final String PREV_B64UIDL = "prevb64uidl"; - private static final String NEXT_B64UIDL = "nextb64uidl"; + private static final String B64UIDL = "msg"; + private static final String PREV_B64UIDL = "prevmsg"; + private static final String NEXT_B64UIDL = "nextmsg"; private static final String PREV_PAGE_NUM = "prevpagenum"; private static final String NEXT_PAGE_NUM = "nextpagenum"; private static final String CURRENT_SORT = "currentsort"; @@ -349,6 +349,8 @@ public class WebMail extends HttpServlet * @author susi */ private static class SubjectSorter extends SorterBase { + private static final String xre = _t("Re:").toLowerCase(Locale.US); + private static final String xfwd = _t("Fwd:").toLowerCase(Locale.US); private final Comparator<Object> collator = Collator.getInstance(); public SubjectSorter( MailCache mailCache ) @@ -359,31 +361,29 @@ public class WebMail extends HttpServlet protected int compare(Mail a, Mail b) { String as = a.subject; String bs = b.subject; - if (as.toLowerCase().startsWith("re:")) { + String aslc = as.toLowerCase(Locale.US); + String bslc = bs.toLowerCase(Locale.US); + if (aslc.startsWith("re:") || aslc.startsWith("fw:")) { as = as.substring(3).trim(); - } else if (as.toLowerCase().startsWith("fwd:")) { + } else if (aslc.startsWith("fwd:")) { as = as.substring(4).trim(); } else { - String xre = _t("Re:").toLowerCase(); - if (as.toLowerCase().startsWith(xre)) { + if (aslc.startsWith(xre)) { as = as.substring(xre.length()).trim(); } else { - String xfwd = _t("Fwd:").toLowerCase(); - if (as.toLowerCase().startsWith(xfwd)) + if (aslc.startsWith(xfwd)) as = as.substring(xfwd.length()).trim(); } } - if (bs.toLowerCase().startsWith("re:")) { + if (bslc.startsWith("re:") || bslc.startsWith("fw:")) { bs = bs.substring(3).trim(); - } else if (bs.toLowerCase().startsWith("fwd:")) { + } else if (bslc.startsWith("fwd:")) { bs = bs.substring(4).trim(); } else { - String xre = _t("Re:").toLowerCase(); - if (bs.toLowerCase().startsWith(xre)) { + if (bslc.startsWith(xre)) { bs = bs.substring(xre.length()).trim(); } else { - String xfwd = _t("Fwd:").toLowerCase(); - if (bs.toLowerCase().startsWith(xfwd)) + if (bslc.startsWith(xfwd)) bs = bs.substring(xfwd.length()).trim(); } } @@ -618,7 +618,7 @@ public class WebMail extends HttpServlet if( html ) { out.println( "<!-- " ); - out.println( "Debug: Showing Mail Part at level " + level + " with hash code " + mailPart.hashCode()); + out.println( "Debug: Showing Mail Part at level " + level + " with ID " + mailPart.getID()); out.println( "Debug: Mail Part headers follow"); for( int i = 0; i < mailPart.headerLines.length; i++ ) { // fix Content-Type: multipart/alternative; boundary="----------8CDE39ECAF2633" @@ -642,7 +642,7 @@ public class WebMail extends HttpServlet if (chosen.equals(subPart)) continue; out.println( "<!-- " ); - out.println( "Debug: Not showing alternative Mail Part at level " + (level + 1) + " with hash code " + subPart.hashCode()); + out.println( "Debug: Not showing alternative Mail Part at level " + (level + 1) + " with ID " + subPart.getID()); out.println( "Debug: Mail Part headers follow"); for( int i = 0; i < subPart.headerLines.length; i++ ) { out.println( subPart.headerLines[i].replace("--", "--") ); @@ -751,7 +751,7 @@ public class WebMail extends HttpServlet } name = quoteHTML(name); out.println("<img src=\"" + myself + '?' + RAW_ATTACHMENT + '=' + - mailPart.hashCode() + + mailPart.getID() + "&" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "\" alt=\"" + name + "\">"); } else if (type != null && ( @@ -765,14 +765,15 @@ public class WebMail extends HttpServlet type.equals("application/x-7z-compressed") || type.equals("application/x-rar-compressed") || type.equals("application/x-tar") || type.equals("application/x-bzip2") || type.equals("application/pdf") || type.equals("application/x-bittorrent") || + type.equals("application/pgp-encrypted") || type.equals("application/pgp-signature"))) { out.println( "<a href=\"" + myself + '?' + RAW_ATTACHMENT + '=' + - mailPart.hashCode() + + mailPart.getID() + "&" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "\">" + _t("Download attachment {0}", ident) + "</a>"); } else { out.println( "<a target=\"_blank\" href=\"" + myself + '?' + DOWNLOAD + '=' + - mailPart.hashCode() + + mailPart.getID() + "&" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "\">" + _t("Download attachment {0}", ident) + "</a>" + " (" + _t("File is packed into a zipfile for security reasons.") + ')'); @@ -788,7 +789,7 @@ public class WebMail extends HttpServlet } if( html ) { out.println( "<!-- " ); - out.println( "Debug: End of Mail Part at level " + level + " with hash code " + mailPart.hashCode()); + out.println( "Debug: End of Mail Part at level " + level + " with ID " + mailPart.getID()); out.println( "-->" ); } } @@ -1167,6 +1168,9 @@ public class WebMail extends HttpServlet if (!(sessionObject.subject.startsWith("Fwd:") || sessionObject.subject.startsWith("fwd:") || sessionObject.subject.startsWith("FWD:") || + sessionObject.subject.startsWith("Fw:") || + sessionObject.subject.startsWith("fw:") || + sessionObject.subject.startsWith("FW:") || sessionObject.subject.startsWith(_t("Fwd:")))) { sessionObject.subject = _t("Fwd:") + ' ' + sessionObject.subject; } @@ -1437,9 +1441,9 @@ public class WebMail extends HttpServlet } if( str != null ) { try { - int hashCode = Integer.parseInt( str ); + int id = Integer.parseInt( str ); Mail mail = sessionObject.mailCache.getMail(showUIDL, MailCache.FetchMode.ALL); - MailPart part = mail != null ? getMailPartFromHashCode( mail.getPart(), hashCode ) : null; + MailPart part = mail != null ? getMailPartFromID(mail.getPart(), id) : null; if( part != null ) { if (sendAttachment(sessionObject, part, response, isRaw)) return true; @@ -1484,21 +1488,20 @@ public class WebMail extends HttpServlet /** * Recursive. - * FIXME can't be bookmarked. - * @param hashCode + * @param id as retrieved from getID() * @return the part or null */ - private static MailPart getMailPartFromHashCode( MailPart part, int hashCode ) + private static MailPart getMailPartFromID(MailPart part, int id) { if( part == null ) return null; - if( part.hashCode() == hashCode ) + if (part.getID() == id) return part; if( part.multipart || part.message ) { for( MailPart p : part.parts ) { - MailPart subPart = getMailPartFromHashCode( p, hashCode ); + MailPart subPart = getMailPartFromID(p, id); if( subPart != null ) return subPart; } @@ -2132,7 +2135,7 @@ public class WebMail extends HttpServlet if (name == null) { name = part.description; if (name == null) - name = "part" + part.hashCode(); + name = "part" + part.getID(); } } String name2 = FilenameUtil.sanitizeFilename(name); @@ -2679,7 +2682,7 @@ public class WebMail extends HttpServlet "</p>"); } Mail mail = sessionObject.mailCache.getMail(showUIDL, MailCache.FetchMode.ALL); - if(!RELEASE && mail != null && mail.hasBody() && mail.getBody().getLength() < 4096) { + if(!RELEASE && mail != null && mail.hasBody() && mail.getBody().getLength() < 16384) { out.println( "<!--" ); out.println( "Debug: Mail header and body follow"); Buffer body = mail.getBody(); -- GitLab