You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ma...@apache.org on 2016/07/08 17:01:09 UTC

[4/5] james-project git commit: JAMES-1794 Fix for handling text attachments

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 <ra...@linagora.com>
Authored: Fri Jul 8 14:36:02 2016 +0200
Committer: Raphael Ouazana <ra...@linagora.com>
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==?=" <ra...@jri.obm.lng.org>
+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 = "username@domain.tld|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: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org