JAMES-1916 Extract html from inner multipart when text/plain in main multipart


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/5fd8641a
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/5fd8641a
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/5fd8641a

Branch: refs/heads/master
Commit: 5fd8641a99434ecba4215d098f903e6ffe680722
Parents: 8e95555
Author: Raphael Ouazana <raphael.ouaz...@linagora.com>
Authored: Fri Jan 27 15:33:09 2017 +0100
Committer: Raphael Ouazana <raphael.ouaz...@linagora.com>
Committed: Fri Jan 27 15:33:09 2017 +0100

----------------------------------------------------------------------
 .../cucumber/GetMessagesMethodStepdefs.java     |  5 +
 .../test/resources/cucumber/GetMessages.feature | 10 +-
 .../textInMainMultipartHtmlInInnerMultipart.eml | 43 +++++++++
 .../jmap/model/MessageContentExtractor.java     | 17 +++-
 .../jmap/model/MessageContentExtractorTest.java | 97 ++++++++++++++++++++
 5 files changed, 170 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/5fd8641a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
 
b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
index e6c4c4c..450ffb1 100644
--- 
a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
+++ 
b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/GetMessagesMethodStepdefs.java
@@ -191,6 +191,11 @@ public class GetMessagesMethodStepdefs {
         appendMessage(messageName, 
"eml/embeddedMultipartWithInlineTextAttachment.eml");
     }
 
+    @Given("^the user has a message \"([^\"]*)\" in \"([^\"]*)\" mailbox with 
text in main multipart and html in inner multipart$")
+    public void 
appendMessageWithTextInMainMultipartAndHtmlInInnerMultipart(String messageName, 
String mailbox) throws Throwable {
+        appendMessage(messageName, 
"eml/textInMainMultipartHtmlInInnerMultipart.eml");
+    }
+
     private void appendMessage(String messageName, String emlFileName) throws 
Exception {
         ZonedDateTime dateTime = ZonedDateTime.parse("2014-10-30T14:12:00Z");
         MessageId id = 
mainStepdefs.jmapServer.serverProbe().appendMessage(userStepdefs.lastConnectedUser,

http://git-wip-us.apache.org/repos/asf/james-project/blob/5fd8641a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
 
b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
index 9cbd0c1..0cd93d1 100644
--- 
a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
+++ 
b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/GetMessages.feature
@@ -230,4 +230,12 @@ Feature: GetMessages method
     Then no error is returned
     And the list should contain 1 message
     And the textBody of the message is "/blabla/\n*bloblo*\n"
-    And the htmlBody of the message is "<i>blabla</i>\n<b>bloblo</b>\n"
\ No newline at end of file
+    And the htmlBody of the message is "<i>blabla</i>\n<b>bloblo</b>\n"
+
+  Scenario: Retrieving message should find html body when text in main 
multipart and html in inner multipart
+    Given the user has a message "m1" in "inbox" mailbox with text in main 
multipart and html in inner multipart
+    When the user ask for messages "m1"
+    Then no error is returned
+    And the list should contain 1 message
+    And the textBody of the message is "/blabla/\r\n*bloblo*\r\n"
+    And the htmlBody of the message is "<i>blabla</i>\r\n<b>bloblo</b>\r\n"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/5fd8641a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/textInMainMultipartHtmlInInnerMultipart.eml
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/textInMainMultipartHtmlInInnerMultipart.eml
 
b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/textInMainMultipartHtmlInInnerMultipart.eml
new file mode 100644
index 0000000..6e42d91
--- /dev/null
+++ 
b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/eml/textInMainMultipartHtmlInInnerMultipart.eml
@@ -0,0 +1,43 @@
+To: David DOLCIMASCOLO <david....@linagora.com>
+From: David DOLCIMASCOLO <david....@linagora.com>
+Subject: Inline twice
+Message-ID: <03947d9b-4188-4d3a-b072-475278063...@linagora.com>
+Date: Tue, 3 Jan 2017 17:59:01 +0100
+User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
+ Thunderbird/45.5.1
+Content-Type: multipart/alternative;
+ boundary="------------41916E9CB699BB85B7A39ABF"
+
+This is a multi-part message in MIME format.
+--------------41916E9CB699BB85B7A39ABF
+Content-Type: text/plain; charset=utf-8; format=flowed
+Content-Transfer-Encoding: 8bit
+
+/blabla/
+*bloblo*
+
+--------------41916E9CB699BB85B7A39ABF
+Content-Type: multipart/related;
+ boundary="------------7562AB559B6C67B3BE780AA2"
+
+
+--------------7562AB559B6C67B3BE780AA2
+Content-Type: text/html; charset=utf-8
+Content-Transfer-Encoding: 8bit
+
+<i>blabla</i>
+<b>bloblo</b>
+
+--------------7562AB559B6C67B3BE780AA2
+Content-Type: image/png;
+ name="=?UTF-8?Q?S=c3=a9lection=5f014.png?="
+Content-Transfer-Encoding: base64
+Content-ID: <part1.c774cd18.95513...@linagora.com>
+Content-Disposition: inline;
+ filename*=utf-8''%53%C3%A9%6C%65%63%74%69%6F%6E%5F%30%31%34%2E%70%6E%67
+
+iVBORw0KGgoAAAANSUhEUgAAAUcAAAJCCAIAAADcDpISAAAAA3NCSVQICAjb4U/gAAAAEHRF
+ASEB8/ejg6KNLS31fZ+u8hQAPj/AXiuIAuF4TyOAAAAAElFTkSuQmCC
+--------------7562AB559B6C67B3BE780AA2--
+
+--------------41916E9CB699BB85B7A39ABF--

http://git-wip-us.apache.org/repos/asf/james-project/blob/5fd8641a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
index 721e641..b5baf53 100644
--- 
a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
+++ 
b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageContentExtractor.java
@@ -92,7 +92,12 @@ public class MessageContentExtractor {
     private MessageContent retrieveHtmlAndPlainTextContent(Multipart 
multipart) throws IOException {
         Optional<String> textBody = getFirstMatchingTextBody(multipart, 
"text/plain");
         Optional<String> htmlBody = getFirstMatchingTextBody(multipart, 
"text/html");
-        return new MessageContent(textBody, htmlBody);
+        MessageContent directChildTextBodies = new MessageContent(textBody, 
htmlBody);
+        if (!directChildTextBodies.isComplete()) {
+            MessageContent fromInnerMultipart = 
parseFirstFoundMultipart(multipart);
+            return directChildTextBodies.merge(fromInnerMultipart);
+        }
+        return directChildTextBodies;
     }
 
     private MessageContent retrieveFirstReadablePart(Multipart multipart) 
throws IOException {
@@ -180,6 +185,16 @@ public class MessageContentExtractor {
             return equals(empty());
         }
 
+        public boolean isComplete() {
+            return textBody.isPresent() && htmlBody.isPresent();
+        }
+
+        public MessageContent merge(MessageContent fromInnerMultipart) {
+            return new MessageContent(
+                    
textBody.map(Optional::of).orElse(fromInnerMultipart.getTextBody()),
+                    
htmlBody.map(Optional::of).orElse(fromInnerMultipart.getHtmlBody()));
+        }
+
         @Override
         public boolean equals(Object other) {
             if (other == null || !(other instanceof MessageContent)) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/5fd8641a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
----------------------------------------------------------------------
diff --git 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
index 0a05e5d..84f78c4 100644
--- 
a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
+++ 
b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageContentExtractorTest.java
@@ -21,6 +21,7 @@ package org.apache.james.jmap.model;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.IOException;
+import java.util.Optional;
 
 import javax.mail.internet.MimeMessage;
 
@@ -45,6 +46,8 @@ public class MessageContentExtractorTest {
     private static final String BINARY_CONTENT = "binary";
     private static final String TEXT_CONTENT = "text content";
     private static final String HTML_CONTENT = "<b>html</b> content";
+    private static final String TEXT_CONTENT2 = "other text content";
+    private static final String HTML_CONTENT2 = "other <b>html</b> content";
     private static final String ATTACHMENT_CONTENT = "attachment content";
     private static final String ANY_VALUE = "anyValue";
     private static final Field CONTENT_ID_FIELD = new Field() {
@@ -70,6 +73,7 @@ public class MessageContentExtractorTest {
     private BodyPart textPart;
     private BodyPart textAttachment;
     private BodyPart inlineText;
+    private BodyPart inlineImage;
 
     @Before
     public void setup() throws IOException {
@@ -84,6 +88,10 @@ public class MessageContentExtractorTest {
                 .setBody(ATTACHMENT_CONTENT, "plain", Charsets.UTF_8)
                 .setContentDisposition("inline")
                 .build();
+        inlineImage = BodyPartBuilder.create()
+                .setBody(new byte[0], "image/png")
+                .setContentDisposition("inline")
+                .build();
     }
 
     @Test
@@ -368,4 +376,93 @@ public class MessageContentExtractorTest {
         assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
         assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
     }
+
+    @Test
+    public void 
extractShouldRetrieveTextBodyAndHtmlBodyWhenTextBodyInMainMultipartAndHtmlBodyInInnerMultipart()
 throws IOException {
+        BodyPart multipartRelated = BodyPartBuilder.create()
+                .setBody(MultipartBuilder.create("related")
+                        .addBodyPart(htmlPart)
+                        .addBodyPart(inlineImage)
+                        .build())
+                .build();
+
+        Multipart multipartAlternative = MultipartBuilder.create("alternative")
+                .addBodyPart(textPart)
+                .addBodyPart(multipartRelated)
+                .build();
+
+        Message message = MessageBuilder.create()
+                .setBody(multipartAlternative)
+                .build();
+
+        MessageContent actual = testee.extract(message);
+        assertThat(actual.getTextBody()).contains(TEXT_CONTENT);
+        assertThat(actual.getHtmlBody()).contains(HTML_CONTENT);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnEmptyWhenAllEmpty() {
+        MessageContent messageContent1 = MessageContent.empty();
+        MessageContent messageContent2 = MessageContent.empty();
+        MessageContent expected = MessageContent.empty();
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnFirstWhenSecondEmpty() {
+        MessageContent messageContent1 = new 
MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+        MessageContent messageContent2 = MessageContent.empty();
+        MessageContent expected = messageContent1;
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnSecondWhenFirstEmpty() {
+        MessageContent messageContent1 = MessageContent.empty();
+        MessageContent messageContent2 = new 
MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+        MessageContent expected = messageContent2;
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void 
mergeMessageContentShouldReturnMixWhenFirstTextOnlyAndSecondHtmlOnly() {
+        MessageContent messageContent1 = 
MessageContent.ofTextOnly(TEXT_CONTENT);
+        MessageContent messageContent2 = 
MessageContent.ofHtmlOnly(HTML_CONTENT);
+        MessageContent expected = new 
MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void 
mergeMessageContentShouldReturnMixWhenFirstHtmlOnlyAndSecondTextOnly() {
+        MessageContent messageContent1 = 
MessageContent.ofHtmlOnly(HTML_CONTENT);
+        MessageContent messageContent2 = 
MessageContent.ofTextOnly(TEXT_CONTENT);
+        MessageContent expected = new 
MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
+
+    @Test
+    public void mergeMessageContentShouldReturnFirstWhenTwiceAreComplete() {
+        MessageContent messageContent1 = new 
MessageContent(Optional.of(TEXT_CONTENT), Optional.of(HTML_CONTENT));
+        MessageContent messageContent2 = new 
MessageContent(Optional.of(TEXT_CONTENT2), Optional.of(HTML_CONTENT2));
+        MessageContent expected = messageContent1;
+
+        MessageContent actual = messageContent1.merge(messageContent2);
+
+        assertThat(actual).isEqualTo(expected);
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org
For additional commands, e-mail: server-dev-h...@james.apache.org

Reply via email to