SusiMail: Improve speed of subject sorter

Use ID instead of hashcode for mailparts, so attachments are bookmarkable
Recognize fw:
This commit is contained in:
zzz
2018-02-09 22:53:25 +00:00
parent afad22a8cb
commit 31719d30cf
3 changed files with 50 additions and 34 deletions

View File

@@ -45,6 +45,7 @@ import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.i2p.I2PAppContext; import net.i2p.I2PAppContext;
@@ -179,7 +180,7 @@ class Mail {
// TODO just fail? // TODO just fail?
if (headerLines == null) if (headerLines == null)
headerLines = new String[0]; 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); rb.readComplete(true);
// may only be available after reading and calling readComplete() // may only be available after reading and calling readComplete()
size = rb.getLength(); size = rb.getLength();

View File

@@ -44,6 +44,7 @@ import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.atomic.AtomicInteger;
import net.i2p.data.DataHelper; import net.i2p.data.DataHelper;
@@ -79,6 +80,7 @@ class MailPart {
* @since 0.9.33 * @since 0.9.33
*/ */
public final String uidl; public final String uidl;
private final int intID;
/** /**
* @param readBuffer has zero offset for top-level MailPart. * @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 * @param hdrlines non-null for top-level MailPart, where they
* were already parsed in Mail. Null otherwise * 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; this.uidl = uidl;
intID = id.getAndIncrement();
buffer = readBuffer; buffer = readBuffer;
parts = new ArrayList<MailPart>(4); parts = new ArrayList<MailPart>(4);
@@ -219,7 +222,7 @@ class MailPart {
match = DataHelper.getASCII("\r\n--" + boundary); match = DataHelper.getASCII("\r\n--" + boundary);
eofin = new EOFOnMatchInputStream(in, counter, match); 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 ); parts.add( newPart );
tmpEnd = (int) eofin.getRead(); tmpEnd = (int) eofin.getRead();
if (!eofin.wasFound()) { if (!eofin.wasFound()) {
@@ -233,7 +236,7 @@ class MailPart {
} }
} }
else if( message ) { 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, // TODO newPart doesn't save message headers we might like to display,
// like From, To, and Subject // like From, To, and Subject
parts.add( newPart ); parts.add( newPart );
@@ -251,6 +254,15 @@ class MailPart {
// Debug.debug(Debug.DEBUG, "New " + this); // 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". * Swallow "\r\n" or "--\r\n".
* We don't have any pushback if this goes wrong. * We don't have any pushback if this goes wrong.

View File

@@ -132,9 +132,9 @@ public class WebMail extends HttpServlet
* hidden params * hidden params
*/ */
private static final String SUSI_NONCE = "susiNonce"; private static final String SUSI_NONCE = "susiNonce";
private static final String B64UIDL = "b64uidl"; private static final String B64UIDL = "msg";
private static final String PREV_B64UIDL = "prevb64uidl"; private static final String PREV_B64UIDL = "prevmsg";
private static final String NEXT_B64UIDL = "nextb64uidl"; private static final String NEXT_B64UIDL = "nextmsg";
private static final String PREV_PAGE_NUM = "prevpagenum"; private static final String PREV_PAGE_NUM = "prevpagenum";
private static final String NEXT_PAGE_NUM = "nextpagenum"; private static final String NEXT_PAGE_NUM = "nextpagenum";
private static final String CURRENT_SORT = "currentsort"; private static final String CURRENT_SORT = "currentsort";
@@ -349,6 +349,8 @@ public class WebMail extends HttpServlet
* @author susi * @author susi
*/ */
private static class SubjectSorter extends SorterBase { 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(); private final Comparator<Object> collator = Collator.getInstance();
public SubjectSorter( MailCache mailCache ) public SubjectSorter( MailCache mailCache )
@@ -359,31 +361,29 @@ public class WebMail extends HttpServlet
protected int compare(Mail a, Mail b) { protected int compare(Mail a, Mail b) {
String as = a.subject; String as = a.subject;
String bs = b.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(); as = as.substring(3).trim();
} else if (as.toLowerCase().startsWith("fwd:")) { } else if (aslc.startsWith("fwd:")) {
as = as.substring(4).trim(); as = as.substring(4).trim();
} else { } else {
String xre = _t("Re:").toLowerCase(); if (aslc.startsWith(xre)) {
if (as.toLowerCase().startsWith(xre)) {
as = as.substring(xre.length()).trim(); as = as.substring(xre.length()).trim();
} else { } else {
String xfwd = _t("Fwd:").toLowerCase(); if (aslc.startsWith(xfwd))
if (as.toLowerCase().startsWith(xfwd))
as = as.substring(xfwd.length()).trim(); as = as.substring(xfwd.length()).trim();
} }
} }
if (bs.toLowerCase().startsWith("re:")) { if (bslc.startsWith("re:") || bslc.startsWith("fw:")) {
bs = bs.substring(3).trim(); bs = bs.substring(3).trim();
} else if (bs.toLowerCase().startsWith("fwd:")) { } else if (bslc.startsWith("fwd:")) {
bs = bs.substring(4).trim(); bs = bs.substring(4).trim();
} else { } else {
String xre = _t("Re:").toLowerCase(); if (bslc.startsWith(xre)) {
if (bs.toLowerCase().startsWith(xre)) {
bs = bs.substring(xre.length()).trim(); bs = bs.substring(xre.length()).trim();
} else { } else {
String xfwd = _t("Fwd:").toLowerCase(); if (bslc.startsWith(xfwd))
if (bs.toLowerCase().startsWith(xfwd))
bs = bs.substring(xfwd.length()).trim(); bs = bs.substring(xfwd.length()).trim();
} }
} }
@@ -618,7 +618,7 @@ public class WebMail extends HttpServlet
if( html ) { if( html ) {
out.println( "<!-- " ); 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"); out.println( "Debug: Mail Part headers follow");
for( int i = 0; i < mailPart.headerLines.length; i++ ) { for( int i = 0; i < mailPart.headerLines.length; i++ ) {
// fix Content-Type: multipart/alternative; boundary="----------8CDE39ECAF2633" // fix Content-Type: multipart/alternative; boundary="----------8CDE39ECAF2633"
@@ -642,7 +642,7 @@ public class WebMail extends HttpServlet
if (chosen.equals(subPart)) if (chosen.equals(subPart))
continue; continue;
out.println( "<!-- " ); 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"); out.println( "Debug: Mail Part headers follow");
for( int i = 0; i < subPart.headerLines.length; i++ ) { for( int i = 0; i < subPart.headerLines.length; i++ ) {
out.println( subPart.headerLines[i].replace("--", "&#45;&#45;") ); out.println( subPart.headerLines[i].replace("--", "&#45;&#45;") );
@@ -751,7 +751,7 @@ public class WebMail extends HttpServlet
} }
name = quoteHTML(name); name = quoteHTML(name);
out.println("<img src=\"" + myself + '?' + RAW_ATTACHMENT + '=' + out.println("<img src=\"" + myself + '?' + RAW_ATTACHMENT + '=' +
mailPart.hashCode() + mailPart.getID() +
"&amp;" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "&amp;" + B64UIDL + '=' + Base64.encode(mailPart.uidl) +
"\" alt=\"" + name + "\">"); "\" alt=\"" + name + "\">");
} else if (type != null && ( } 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-7z-compressed") || type.equals("application/x-rar-compressed") ||
type.equals("application/x-tar") || type.equals("application/x-bzip2") || type.equals("application/x-tar") || type.equals("application/x-bzip2") ||
type.equals("application/pdf") || type.equals("application/x-bittorrent") || type.equals("application/pdf") || type.equals("application/x-bittorrent") ||
type.equals("application/pgp-encrypted") ||
type.equals("application/pgp-signature"))) { type.equals("application/pgp-signature"))) {
out.println( "<a href=\"" + myself + '?' + RAW_ATTACHMENT + '=' + out.println( "<a href=\"" + myself + '?' + RAW_ATTACHMENT + '=' +
mailPart.hashCode() + mailPart.getID() +
"&amp;" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "\">" + "&amp;" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "\">" +
_t("Download attachment {0}", ident) + "</a>"); _t("Download attachment {0}", ident) + "</a>");
} else { } else {
out.println( "<a target=\"_blank\" href=\"" + myself + '?' + DOWNLOAD + '=' + out.println( "<a target=\"_blank\" href=\"" + myself + '?' + DOWNLOAD + '=' +
mailPart.hashCode() + mailPart.getID() +
"&amp;" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "\">" + "&amp;" + B64UIDL + '=' + Base64.encode(mailPart.uidl) + "\">" +
_t("Download attachment {0}", ident) + "</a>" + _t("Download attachment {0}", ident) + "</a>" +
" (" + _t("File is packed into a zipfile for security reasons.") + ')'); " (" + _t("File is packed into a zipfile for security reasons.") + ')');
@@ -788,7 +789,7 @@ public class WebMail extends HttpServlet
} }
if( html ) { if( html ) {
out.println( "<!-- " ); 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( "-->" ); out.println( "-->" );
} }
} }
@@ -1167,6 +1168,9 @@ public class WebMail extends HttpServlet
if (!(sessionObject.subject.startsWith("Fwd:") || if (!(sessionObject.subject.startsWith("Fwd:") ||
sessionObject.subject.startsWith("fwd:") || 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.startsWith(_t("Fwd:")))) {
sessionObject.subject = _t("Fwd:") + ' ' + sessionObject.subject; sessionObject.subject = _t("Fwd:") + ' ' + sessionObject.subject;
} }
@@ -1437,9 +1441,9 @@ public class WebMail extends HttpServlet
} }
if( str != null ) { if( str != null ) {
try { try {
int hashCode = Integer.parseInt( str ); int id = Integer.parseInt( str );
Mail mail = sessionObject.mailCache.getMail(showUIDL, MailCache.FetchMode.ALL); 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( part != null ) {
if (sendAttachment(sessionObject, part, response, isRaw)) if (sendAttachment(sessionObject, part, response, isRaw))
return true; return true;
@@ -1484,21 +1488,20 @@ public class WebMail extends HttpServlet
/** /**
* Recursive. * Recursive.
* FIXME can't be bookmarked. * @param id as retrieved from getID()
* @param hashCode
* @return the part or null * @return the part or null
*/ */
private static MailPart getMailPartFromHashCode( MailPart part, int hashCode ) private static MailPart getMailPartFromID(MailPart part, int id)
{ {
if( part == null ) if( part == null )
return null; return null;
if( part.hashCode() == hashCode ) if (part.getID() == id)
return part; return part;
if( part.multipart || part.message ) { if( part.multipart || part.message ) {
for( MailPart p : part.parts ) { for( MailPart p : part.parts ) {
MailPart subPart = getMailPartFromHashCode( p, hashCode ); MailPart subPart = getMailPartFromID(p, id);
if( subPart != null ) if( subPart != null )
return subPart; return subPart;
} }
@@ -2132,7 +2135,7 @@ public class WebMail extends HttpServlet
if (name == null) { if (name == null) {
name = part.description; name = part.description;
if (name == null) if (name == null)
name = "part" + part.hashCode(); name = "part" + part.getID();
} }
} }
String name2 = FilenameUtil.sanitizeFilename(name); String name2 = FilenameUtil.sanitizeFilename(name);
@@ -2679,7 +2682,7 @@ public class WebMail extends HttpServlet
"</p>"); "</p>");
} }
Mail mail = sessionObject.mailCache.getMail(showUIDL, MailCache.FetchMode.ALL); 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( "<!--" );
out.println( "Debug: Mail header and body follow"); out.println( "Debug: Mail header and body follow");
Buffer body = mail.getBody(); Buffer body = mail.getBody();