JAMES-1794 Fix for handling text attachments
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/0be33d70 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/0be33d70 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/0be33d70 Branch: refs/heads/master Commit: 0be33d70226374330c657adb94df9d484fe4a6b7 Parents: 682aada Author: Raphael Ouazana <[email protected]> Authored: Fri Jul 8 14:36:02 2016 +0200 Committer: Raphael Ouazana <[email protected]> Committed: Fri Jul 8 16:47:53 2016 +0200 ---------------------------------------------------------------------- .../store/mail/model/impl/MessageParser.java | 26 +++---- .../mail/model/impl/MessageParserTest.java | 11 ++- .../eml/oneHtmlAttachmentAndSomeTextInlined.eml | 39 ++++++++++ .../integration/SetMessagesMethodTest.java | 76 ++++++++++++++++++++ 4 files changed, 134 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/0be33d70/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java index 9096efa..7e3f2fd 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/model/impl/MessageParser.java @@ -45,7 +45,7 @@ import com.google.common.collect.ImmutableList; public class MessageParser { - private static final String TEXT_MEDIA_TYPE = "text"; + private static final String MULTIPART_ALTERNATIVE = "multipart/alternative"; private static final String CONTENT_TYPE = "Content-Type"; private static final String CONTENT_ID = "Content-ID"; private static final String CONTENT_DISPOSITION = "Content-Disposition"; @@ -73,7 +73,7 @@ public class MessageParser { ImmutableList.Builder<MessageAttachment> attachments = ImmutableList.builder(); MessageWriter messageWriter = new DefaultMessageWriter(); for (Entity entity : multipart.getBodyParts()) { - if (entity.isMultipart() && entity.getBody() instanceof Multipart) { + if (isMultipart(entity) && !isMainBody(entity)) { attachments.addAll(listAttachments((Multipart) entity.getBody())); } else { if (isAttachment(entity)) { @@ -141,6 +141,14 @@ public class MessageParser { }).or(Optional.<String> absent()); } + private boolean isMultipart(Entity entity) { + return entity.isMultipart() && entity.getBody() instanceof Multipart; + } + + private boolean isMainBody(Entity entity) { + return entity.getMimeType().equalsIgnoreCase(MULTIPART_ALTERNATIVE); + } + private boolean isInline(Optional<ContentDispositionField> contentDispositionField) { return contentDispositionField.transform(new Function<ContentDispositionField, Boolean>() { @Override @@ -151,9 +159,6 @@ public class MessageParser { } private boolean isAttachment(Entity part) { - if (isTextPart(part)) { - return false; - } return Optional.fromNullable(part.getDispositionType()) .transform(new Function<String, Boolean>() { @@ -164,17 +169,6 @@ public class MessageParser { }).isPresent(); } - private boolean isTextPart(Entity part) { - Optional<ContentTypeField> contentTypeField = getContentTypeField(part); - if (contentTypeField.isPresent()) { - String mediaType = contentTypeField.get().getMediaType(); - if (mediaType != null && mediaType.equals(TEXT_MEDIA_TYPE)) { - return true; - } - } - return false; - } - private byte[] getBytes(MessageWriter messageWriter, Body body) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); messageWriter.writeBody(body, out); http://git-wip-us.apache.org/repos/asf/james-project/blob/0be33d70/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java index 2e3a15e..054ebd0 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/impl/MessageParserTest.java @@ -126,14 +126,14 @@ public class MessageParserTest { } @Test - public void getAttachmentsShouldNotRetrieveEmbeddedAttachmentsWhenSome() throws Exception { + public void getAttachmentsShouldRetrieveEmbeddedAttachmentsWhenSome() throws Exception { List<MessageAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/embeddedAttachmentWithInline.eml")); assertThat(attachments).hasSize(1); } @Test - public void getAttachmentsShouldNotRetrieveInlineAttachmentsWhenSome() throws Exception { + public void getAttachmentsShouldRetrieveInlineAttachmentsWhenSome() throws Exception { List<MessageAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/embeddedAttachmentWithAttachment.eml")); assertThat(attachments).hasSize(1); @@ -154,4 +154,11 @@ public class MessageParserTest { assertThat(attachments).hasSize(1); assertThat(attachments.get(0).isInline()).isTrue(); } + + @Test + public void getAttachementsShouldRetrieveHtmlAttachementsWhenSome() throws Exception { + List<MessageAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneHtmlAttachmentAndSomeTextInlined.eml")); + + assertThat(attachments).hasSize(1); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/0be33d70/mailbox/store/src/test/resources/eml/oneHtmlAttachmentAndSomeTextInlined.eml ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/resources/eml/oneHtmlAttachmentAndSomeTextInlined.eml b/mailbox/store/src/test/resources/eml/oneHtmlAttachmentAndSomeTextInlined.eml new file mode 100644 index 0000000..2fbb3e0 --- /dev/null +++ b/mailbox/store/src/test/resources/eml/oneHtmlAttachmentAndSomeTextInlined.eml @@ -0,0 +1,39 @@ +Mail content: +To: "=?utf-8?B?UmFuaSBBc3NhZg==?=" <[email protected]> +Subject: =?utf-8?B?VHIuIDogUGhvdG9zICE=?= +Importance: Normal +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_Part_0_1330682067197" + +------=_Part_0_1330682067197 +Content-Type: multipart/alternative; + boundary="----=_Part_2_1330682067197" + +------=_Part_2_1330682067197 +Content-Type: text/plain; + charset= utf-8 +Content-Transfer-Encoding: 8bit +Content-Disposition: inline + +Content of part 1-1 +------=_Part_2_1330682067197 +Content-Type: text/html; + charset= utf-8 +Content-Transfer-Encoding: 8bit +Content-Disposition: inline + +<b>Content of part 1-2</b> +------=_Part_2_1330682067197-- + +------=_Part_0_1330682067197 +Content-Type: text/html; + name="attachment.html" +Content-Transfer-Encoding: 8bit +Content-Disposition: attachment; + filename="attachment.html" +<html> + <body> + Hello! + </body> +</html> http://git-wip-us.apache.org/repos/asf/james-project/blob/0be33d70/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java index be3297b..e318778 100644 --- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java +++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java @@ -47,6 +47,7 @@ import java.util.concurrent.TimeUnit; import javax.mail.Flags; +import org.apache.commons.compress.utils.IOUtils; import org.apache.james.GuiceJamesServer; import org.apache.james.jmap.JmapAuthentication; import org.apache.james.jmap.api.access.AccessToken; @@ -1682,6 +1683,14 @@ public abstract class SetMessagesMethodTest { .post("/upload"); } + private void uploadTextAttachment(Attachment attachment) throws IOException { + with() + .header("Authorization", accessToken.serialize()) + .contentType(attachment.getType()) + .content(new String(IOUtils.toByteArray(attachment.getStream()), Charsets.UTF_8)) + .post("/upload"); + } + @Test public void attachmentsShouldBeRetrievedWhenChainingSetMessagesAndGetMessages() throws Exception { jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "sent"); @@ -1764,4 +1773,71 @@ public abstract class SetMessagesMethodTest { return false; } } + + @Test + public void attachmentsAndBodysShouldBeRetrievedWhenChainingSetMessagesAndGetMessagesWithMixedTextAndHtmlBodyAndHtmlAttachment() throws Exception { + jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "sent"); + + Attachment attachment = Attachment.builder() + .bytes(("<html>\n" + + " <body>attachment</body>\n" + // needed indentation, else restassured is adding some + "</html>").getBytes(Charsets.UTF_8)) + .type("text/html; charset=UTF-8") + .build(); + uploadTextAttachment(attachment); + + String messageCreationId = "creationId"; + String fromAddress = username; + String outboxId = getOutboxId(accessToken); + String requestBody = "[" + + " [" + + " \"setMessages\","+ + " {" + + " \"create\": { \"" + messageCreationId + "\" : {" + + " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," + + " \"to\": [{ \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}]," + + " \"subject\": \"Message with an attachment\"," + + " \"textBody\": \"Test body, plain text version\"," + + " \"htmlBody\": \"Test <b>body</b>, HTML version\"," + + " \"mailboxIds\": [\"" + outboxId + "\"], " + + " \"attachments\": [" + + " {\"blobId\" : \"" + attachment.getAttachmentId().getId() + "\", " + + " \"type\" : \"" + attachment.getType() + "\", " + + " \"size\" : " + attachment.getSize() + ", " + + " \"isInline\" : false }" + + " ]" + + " }}" + + " }," + + " \"#0\"" + + " ]" + + "]"; + + given() + .header("Authorization", accessToken.serialize()) + .body(requestBody) + .when() + .post("/jmap"); + + calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken)); + + String firstMessage = ARGUMENTS + ".list[0]"; + String firstAttachment = firstMessage + ".attachments[0]"; + String presumedMessageId = "[email protected]|INBOX|1"; + given() + .header("Authorization", accessToken.serialize()) + .body("[[\"getMessages\", {\"ids\": [\"" + presumedMessageId + "\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .log().ifValidationFails() + .body(NAME, equalTo("messages")) + .body(ARGUMENTS + ".list", hasSize(1)) + .body(firstMessage + ".textBody", equalTo("Test body, plain text version")) + .body(firstMessage + ".htmlBody", equalTo("Test <b>body</b>, HTML version")) + .body(firstMessage + ".attachments", hasSize(1)) + .body(firstAttachment + ".blobId", equalTo(attachment.getAttachmentId().getId())) + .body(firstAttachment + ".type", equalTo("text/html")) + .body(firstAttachment + ".size", equalTo((int) attachment.getSize())); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
