diff --git a/k9mail/src/main/java/com/fsck/k9/mailstore/MimePartStreamParser.java b/k9mail/src/main/java/com/fsck/k9/mailstore/MimePartStreamParser.java index 3eb7d1962..574164f02 100644 --- a/k9mail/src/main/java/com/fsck/k9/mailstore/MimePartStreamParser.java +++ b/k9mail/src/main/java/com/fsck/k9/mailstore/MimePartStreamParser.java @@ -16,6 +16,7 @@ import com.fsck.k9.mail.Part; import com.fsck.k9.mail.internet.MimeBodyPart; import com.fsck.k9.mail.internet.MimeMessage; import com.fsck.k9.mail.internet.MimeMultipart; +import com.fsck.k9.mail.internet.MimeUtility; import com.fsck.k9.mailstore.util.FileFactory; import org.apache.commons.io.IOUtils; import org.apache.james.mime4j.MimeException; @@ -39,7 +40,7 @@ public class MimePartStreamParser { .build(); MimeStreamParser parser = new MimeStreamParser(parserConfig); - parser.setContentHandler(new PartBuilder(fileFactory, parsedRootPart)); + parser.setContentHandler(new PartBuilder(parser, fileFactory, parsedRootPart)); parser.setRecurse(); try { @@ -66,11 +67,17 @@ public class MimePartStreamParser { private static class PartBuilder implements ContentHandler { + private MimeStreamParser parser; private final FileFactory fileFactory; private final MimeBodyPart decryptedRootPart; private final Stack stack = new Stack<>(); - public PartBuilder(FileFactory fileFactory, MimeBodyPart decryptedRootPart) { + private boolean isMessagePart; + private boolean isContentDispositionAttachment; + + PartBuilder(MimeStreamParser parser, FileFactory fileFactory, + MimeBodyPart decryptedRootPart) { + this.parser = parser; this.fileFactory = fileFactory; this.decryptedRootPart = decryptedRootPart; } @@ -111,11 +118,13 @@ public class MimePartStreamParser { @Override public void endBodyPart() throws MimeException { stack.pop(); + parser.setRecurse(); } @Override public void startHeader() throws MimeException { - // Do nothing + isMessagePart = false; + isContentDispositionAttachment = false; } @Override @@ -125,11 +134,22 @@ public class MimePartStreamParser { Part part = (Part) stack.peek(); part.addRawHeader(name, raw); + + String fieldImmediateValue = MimeUtility.getHeaderParameter(parsedField.getBody(), null); + if ("Content-Type".equalsIgnoreCase(name) && MimeUtility.isMessage(fieldImmediateValue)) { + isMessagePart = true; + } + + if ("Content-Disposition".equalsIgnoreCase(name) && "attachment".equalsIgnoreCase(fieldImmediateValue)) { + isContentDispositionAttachment = true; + } } @Override public void endHeader() throws MimeException { - // Do nothing + if (isMessagePart && isContentDispositionAttachment) { + parser.setFlat(); + } } @Override diff --git a/k9mail/src/test/java/com/fsck/k9/mailstore/MimePartStreamParserTest.kt b/k9mail/src/test/java/com/fsck/k9/mailstore/MimePartStreamParserTest.kt new file mode 100644 index 000000000..f84467dbb --- /dev/null +++ b/k9mail/src/test/java/com/fsck/k9/mailstore/MimePartStreamParserTest.kt @@ -0,0 +1,75 @@ +package com.fsck.k9.mailstore + + +import java.io.ByteArrayInputStream + +import com.fsck.k9.mail.internet.MimeBodyPart +import com.fsck.k9.mail.internet.MimeMessage +import com.fsck.k9.mail.internet.MimeMultipart +import org.junit.Test + +import org.junit.Assert.* + + +class MimePartStreamParserTest { + @Test + fun innerMessage_DispositionInline() { + val msg = MimePartStreamParser.parse(null, ByteArrayInputStream(("""From: +To: +Subject: Testmail 1 +Content-Type: multipart/mixed; boundary=1 + +--1 +Content-Type: text/plain + +some text in the first part +--1 +Content-Type: message/rfc822; name="message" + +To: +Subject: Hi +Date: now +Content-Type: text/plain + +inner text +--1--""").toByteArray())) + + val body = msg.body as MimeMultipart + assertEquals(2, body.count.toLong()) + + val messagePart = body.getBodyPart(1) as MimeBodyPart + assertEquals("message/rfc822", messagePart.mimeType) + assertTrue(messagePart.body is MimeMessage) + } + + @Test + fun innerMessage_dispositionAttachment() { + val msg = MimePartStreamParser.parse(null, ByteArrayInputStream(("""From: +To: +Subject: Testmail 2 +Content-Type: multipart/mixed; boundary=1 + +--1 +Content-Type: text/plain + +some text in the first part +--1 +Content-Type: message/rfc822; name="message" +Content-Disposition: attachment + +To: +Subject: Hi +Date: now +Content-Type: text/plain + +inner text +--1--""").toByteArray())) + + val body = msg.body as MimeMultipart + assertEquals(2, body.count) + + val messagePart = body.getBodyPart(1) as MimeBodyPart + assertEquals("message/rfc822", messagePart.mimeType) + assertTrue(messagePart.body is DeferredFileBody) + } +} \ No newline at end of file