diff --git a/app/src/main/java/eu/faircode/email/MessageHelper.java b/app/src/main/java/eu/faircode/email/MessageHelper.java index 5a8ec9a4f0..c4f03dcef2 100644 --- a/app/src/main/java/eu/faircode/email/MessageHelper.java +++ b/app/src/main/java/eu/faircode/email/MessageHelper.java @@ -844,7 +844,7 @@ public class MessageHelper { String amsgid = null; MessageParts parts = new MessageParts(); - getMessageParts(imessage, parts, null); + getMessageParts(null, imessage, parts, null); for (AttachmentPart apart : parts.attachments) if ("text/rfc822-headers".equalsIgnoreCase(apart.attachment.type)) { InternetHeaders iheaders = new InternetHeaders(apart.part.getInputStream()); @@ -1614,27 +1614,70 @@ public class MessageHelper { return address.getAddress(); } + class PartHolder { + Multipart parent; + Part part; + String contentType; + + PartHolder(Multipart parent, Part part, String contentType) { + this.parent = parent; + this.part = part; + this.contentType = contentType; + } + } + class MessageParts { - private List plain = new ArrayList<>(); - private List html = new ArrayList<>(); - private List extra = new ArrayList<>(); + private List text = new ArrayList<>(); + private List extra = new ArrayList<>(); private List attachments = new ArrayList<>(); private ArrayList warnings = new ArrayList<>(); + MessageParts select() { + Map> map = new HashMap<>(); + for (PartHolder h : text) + if (h.parent != null) { + if (!map.containsKey(h.parent)) + map.put(h.parent, new ArrayList<>()); + map.get(h.parent).add(h); + } + + for (Multipart mp : map.keySet()) + try { + if (new ContentType(mp.getContentType()) + .getBaseType().equalsIgnoreCase("multipart/alternative")) { + boolean plain = true; + for (PartHolder h : map.get(mp)) + if (!"text/plain".equalsIgnoreCase(h.contentType)) { + plain = false; + break; + } + for (PartHolder h : map.get(mp)) + if (!plain && "text/plain".equalsIgnoreCase(h.contentType)) + text.remove(h); + } + } catch (Throwable ex) { + Log.w(ex); + } + + return this; + } + Boolean isPlainOnly() { - if (plain.size() + html.size() + extra.size() == 0) + if (text.size() + extra.size() == 0) return null; - return (html.size() == 0); + for (PartHolder h : text) + if (!"text/plain".equalsIgnoreCase(h.contentType)) + return false; + return true; } boolean hasBody() throws MessagingException { - List all = new ArrayList<>(); - all.addAll(plain); - all.addAll(html); + List all = new ArrayList<>(); + all.addAll(text); all.addAll(extra); - for (Part p : all) - if (p.getSize() > 0) + for (PartHolder h : all) + if (h.part.getSize() > 0) return true; return false; @@ -1643,12 +1686,11 @@ public class MessageHelper { Long getBodySize() throws MessagingException { Long size = null; - List all = new ArrayList<>(); - all.addAll(plain); - all.addAll(html); + List all = new ArrayList<>(); + all.addAll(text); all.addAll(extra); - for (Part p : all) { - int s = p.getSize(); + for (PartHolder h : all) { + int s = h.part.getSize(); if (s >= 0) if (size == null) size = (long) s; @@ -1670,21 +1712,18 @@ public class MessageHelper { } String getHtml(Context context) throws MessagingException, IOException { - if (plain.size() + html.size() == 0) { + if (text.size() == 0) { Log.i("No body part"); return null; } StringBuilder sb = new StringBuilder(); - List parts = new ArrayList<>(); - if (html.size() > 0) - parts.addAll(html); - else - parts.addAll(plain); + List parts = new ArrayList<>(); + parts.addAll(text); parts.addAll(extra); - for (Part part : parts) { - if (part.getSize() > MAX_MESSAGE_SIZE) { + for (PartHolder h : parts) { + if (h.part.getSize() > MAX_MESSAGE_SIZE) { warnings.add(context.getString(R.string.title_insufficient_memory)); return null; } @@ -1692,7 +1731,7 @@ public class MessageHelper { String result; try { - Object content = part.getContent(); + Object content = h.part.getContent(); Log.i("Content class=" + (content == null ? null : content.getClass().getName())); if (content == null) { @@ -1718,7 +1757,7 @@ public class MessageHelper { // Get content type ContentType ct; try { - ct = new ContentType(part.getContentType()); + ct = new ContentType(h.part.getContentType()); } catch (ParseException ex) { Log.e(ex); ct = new ContentType(); @@ -1732,7 +1771,7 @@ public class MessageHelper { if ((TextUtils.isEmpty(charset) || charset.equalsIgnoreCase(StandardCharsets.US_ASCII.name()))) charset = null; - if (part.isMimeType("text/plain")) { + if (h.part.isMimeType("text/plain")) { if (charset == null) { Charset detected = CharsetHelper.detect(result); if (detected == null) { @@ -1749,7 +1788,7 @@ public class MessageHelper { if ("flowed".equalsIgnoreCase(ct.getParameter("format"))) result = HtmlHelper.flow(result); result = "
" + HtmlHelper.formatPre(result) + "
"; - } else if (part.isMimeType("text/html")) { + } else if (h.part.isMimeType("text/html")) { if (charset == null) { // // @@ -1779,8 +1818,8 @@ public class MessageHelper { } } } - } else if (part.isMimeType("message/delivery-status") || - part.isMimeType("message/disposition-notification")) { + } else if (h.part.isMimeType("message/delivery-status") || + h.part.isMimeType("message/disposition-notification")) { StringBuilder report = new StringBuilder(); report.append("
"); for (String line : result.split("\\r?\\n")) { @@ -2069,8 +2108,8 @@ public class MessageHelper { "application/x-pkcs7-signature".equals(protocol)) { Multipart multipart = (Multipart) part.getContent(); if (multipart.getCount() == 2) { - getMessageParts(multipart.getBodyPart(0), parts, null); - getMessageParts(multipart.getBodyPart(1), parts, + getMessageParts(null, multipart.getBodyPart(0), parts, null); + getMessageParts(null, multipart.getBodyPart(1), parts, "application/pgp-signature".equals(protocol) ? EntityAttachment.PGP_SIGNATURE : EntityAttachment.SMIME_SIGNATURE); @@ -2102,7 +2141,7 @@ public class MessageHelper { Multipart multipart = (Multipart) part.getContent(); if (multipart.getCount() == 2) { // Ignore header - getMessageParts(multipart.getBodyPart(1), parts, EntityAttachment.PGP_MESSAGE); + getMessageParts(null, multipart.getBodyPart(1), parts, EntityAttachment.PGP_MESSAGE); return parts; } } @@ -2111,10 +2150,10 @@ public class MessageHelper { ContentType ct = new ContentType(part.getContentType()); String smimeType = ct.getParameter("smime-type"); if ("enveloped-data".equals(smimeType)) { - getMessageParts(part, parts, EntityAttachment.SMIME_MESSAGE); + getMessageParts(null, part, parts, EntityAttachment.SMIME_MESSAGE); return parts; } else if ("signed-data".equals(smimeType)) { - getMessageParts(part, parts, EntityAttachment.SMIME_SIGNED_DATA); + getMessageParts(null, part, parts, EntityAttachment.SMIME_SIGNED_DATA); return parts; } } @@ -2122,11 +2161,11 @@ public class MessageHelper { Log.w(ex); } - getMessageParts(imessage, parts, null); - return parts; + getMessageParts(null, imessage, parts, null); + return parts.select(); } - private void getMessageParts(Part part, MessageParts parts, Integer encrypt) throws IOException, MessagingException { + private void getMessageParts(Multipart parent, Part part, MessageParts parts, Integer encrypt) throws IOException, MessagingException { try { Log.d("Part class=" + part.getClass() + " type=" + part.getContentType()); if (part.isMimeType("multipart/*")) { @@ -2143,7 +2182,7 @@ public class MessageHelper { for (int i = 0; i < multipart.getCount(); i++) try { - getMessageParts(multipart.getBodyPart(i), parts, encrypt); + getMessageParts(multipart, multipart.getBodyPart(i), parts, encrypt); } catch (ParseException ex) { // Nested body: try to continue // ParseException: In parameter list boundary="...">, expected parameter name, got ";" @@ -2185,18 +2224,14 @@ public class MessageHelper { contentType = new ContentType(Helper.guessMimeType(filename)); } - boolean plain = "text/plain".equalsIgnoreCase(contentType.getBaseType()); - boolean html = "text/html".equalsIgnoreCase(contentType.getBaseType()); - if ((plain || html) && + String ct = contentType.getBaseType(); + if (("text/plain".equalsIgnoreCase(ct) || "text/html".equalsIgnoreCase(ct)) && !Part.ATTACHMENT.equalsIgnoreCase(disposition) && TextUtils.isEmpty(filename)) { - if (plain) - parts.plain.add(part); - else if (html) - parts.html.add(part); + parts.text.add(new PartHolder(parent, part, ct)); } else { if ("message/delivery-status".equalsIgnoreCase(contentType.getBaseType()) || "message/disposition-notification".equalsIgnoreCase(contentType.getBaseType())) - parts.extra.add(part); + parts.extra.add(new PartHolder(parent, part, ct)); AttachmentPart apart = new AttachmentPart(); apart.disposition = disposition;