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 ro...@apache.org on 2016/09/22 07:47:31 UTC

[1/5] james-project git commit: JAMES-1814 Decoding filename in received messages

Repository: james-project
Updated Branches:
  refs/heads/master 3c15732e7 -> 3c8c176a0


JAMES-1814 Decoding filename in received messages


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

Branch: refs/heads/master
Commit: 3403ca18234402098224390fd46eefd580e16cee
Parents: 986d15f
Author: Laura Royet <lr...@linagora.com>
Authored: Wed Sep 21 12:11:59 2016 +0200
Committer: Laura Royet <lr...@linagora.com>
Committed: Wed Sep 21 12:11:59 2016 +0200

----------------------------------------------------------------------
 mailbox/store/pom.xml                           |   5 +
 .../store/mail/model/impl/MessageParser.java    |  11 +-
 .../mail/model/impl/MessageParserTest.java      |   8 +
 .../messageWithNonASCIIFilenameAttachment.eml   | 234 +++++++++++++++++++
 ...331\206\330\247\330\265\331\210\330\261.odt" | Bin 0 -> 10675 bytes
 5 files changed, 257 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/3403ca18/mailbox/store/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/store/pom.xml b/mailbox/store/pom.xml
index fd4993a..60ebc49 100644
--- a/mailbox/store/pom.xml
+++ b/mailbox/store/pom.xml
@@ -130,5 +130,10 @@
             <version>${assertj-1.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.assertj</groupId>
+            <artifactId>assertj-guava</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>

http://git-wip-us.apache.org/repos/asf/james-project/blob/3403ca18/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 1588302..6a80385 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
@@ -28,6 +28,8 @@ import org.apache.james.mailbox.model.Attachment;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mime4j.MimeException;
+import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.codec.DecoderUtil;
 import org.apache.james.mime4j.dom.Body;
 import org.apache.james.mime4j.dom.Entity;
 import org.apache.james.mime4j.dom.MessageWriter;
@@ -129,7 +131,14 @@ public class MessageParser {
         return contentTypeField.transform(new Function<ContentTypeField, Optional<String>>() {
             @Override
             public Optional<String> apply(ContentTypeField field) {
-                return Optional.fromNullable(field.getParameter("name"));
+                return Optional.fromNullable(field.getParameter("name"))
+                  .transform(
+                          new Function<String, String>() {
+                              public String apply(String input) {
+                                  DecodeMonitor monitor = null;
+                                  return DecoderUtil.decodeEncodedWords(input, monitor);
+                              }
+                          });
             }
         }).or(Optional.<String> absent());
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/3403ca18/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 6eb0584..02aeaa1 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
@@ -20,6 +20,7 @@
 package org.apache.james.mailbox.store.mail.model.impl;
 
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
 
 import java.util.List;
 
@@ -64,6 +65,13 @@ public class MessageParserTest {
     }
 
     @Test
+    public void getAttachmentsShouldRetrieveAttachmentNameWhenOneContainingNonASCIICharacters() throws Exception {
+        List<MessageAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/messageWithNonASCIIFilenameAttachment.eml"));
+        assertThat(attachments).hasSize(1);
+        assertThat(attachments.get(0).getName()).contains("\u062f\u064a\u0646\u0627\u0635\u0648\u0631.odt");
+    }
+
+    @Test
     public void getAttachmentsShouldRetrieveEmptyNameWhenNone() throws Exception {
         List<MessageAttachment> attachments = testee.retrieveAttachments(ClassLoader.getSystemResourceAsStream("eml/oneAttachmentWithoutName.eml"));
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/3403ca18/mailbox/store/src/test/resources/eml/messageWithNonASCIIFilenameAttachment.eml
----------------------------------------------------------------------
diff --git a/mailbox/store/src/test/resources/eml/messageWithNonASCIIFilenameAttachment.eml b/mailbox/store/src/test/resources/eml/messageWithNonASCIIFilenameAttachment.eml
new file mode 100644
index 0000000..0864178
--- /dev/null
+++ b/mailbox/store/src/test/resources/eml/messageWithNonASCIIFilenameAttachment.eml
@@ -0,0 +1,234 @@
+Return-Path: <lr...@linagora.com>
+Received: from alderaan.linagora.com (smtp.linagora.dc1 [172.16.18.53])
+	 by imap (Cyrus v2.2.13-Debian-2.2.13-19+squeeze3) with LMTPA;
+	 Fri, 26 Aug 2016 10:00:36 +0200
+X-Sieve: CMU Sieve 2.2
+Received: from [10.69.0.146] (mne69-10-88-173-78-196.fbx.proxad.net [88.173.78.196])
+	(using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits))
+	(No client certificate requested)
+	by alderaan.linagora.com (Postfix) with ESMTPSA id A863676F
+	for <lr...@linagora.com>; Fri, 26 Aug 2016 10:00:36 +0200 (CEST)
+To: Laura ROYET <lr...@linagora.com>
+From: Laura Royet <lr...@linagora.com>
+Subject: message with non ASCII filename attachment
+Message-ID: <d9...@linagora.com>
+Date: Fri, 26 Aug 2016 10:00:35 +0200
+User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101
+ Thunderbird/45.2.0
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="------------9F1006EBC7F5F7758497FD08"
+
+This is a multi-part message in MIME format.
+--------------9F1006EBC7F5F7758497FD08
+Content-Type: text/plain; charset=utf-8; format=flowed
+Content-Transfer-Encoding: 7bit
+
+
+
+--------------9F1006EBC7F5F7758497FD08
+Content-Type: application/vnd.oasis.opendocument.text;
+ name="=?UTF-8?B?2K/ZitmG2KfYtdmI2LEub2R0?="
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename*=utf-8''%D8%AF%D9%8A%D9%86%D8%A7%D8%B5%D9%88%D8%B1%2E%6F%64%74
+
+UEsDBBQAAAgAAOB8GElexjIMJwAAACcAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92bmQu
+b2FzaXMub3BlbmRvY3VtZW50LnRleHRQSwMEFAAACAAA4HwYSQ5gBad3CQAAdwkAABgAAABU
+aHVtYm5haWxzL3RodW1ibmFpbC5wbmeJUE5HDQoaCgAAAA1JSERSAAAAtQAAAQAIAgAAAHpB
+oIwAAAk+SURBVHic7dvJT1TpAobxYihmmSQCojIICYao6Q6ioGHlgo2b3nWivei9/1ivOr2Q
+hYZIolFDwAQktCIgQeIEMg8y3pf65KSA229fSuWyeH7pVE6dOnWw+3vqO+cr6czt7e0Y8A8y
+/99/ABxr9AGHPuDQBxz6gEMfcOgDDn3AoQ849AGHPuDQBxz6gEMfcOgDzuH62N7eTktL0+PW
+1paeajs9PT38BknYH21HT8MBevqvpw3nDE/1Lj0N7wpPwwn9efDdHa6PMDwhiyiUsJH86lZC
+OCaMejhs36j/048ISWVkZMR244iKTH5XyOV/6Q8pS2X+WFxcfPbs2fr6emVl5eXLl2dmZoqL
+i7V/aWlpbGwsLy9PT0tLS3XA+Ph4fX19eNe+CSB5RMP+d+/eZWVlLS8vT09PV1dX9/f3l5WV
+6dWNjY2mpqZ4PL4vqYPnxHeXyv1HQYI+369evdLgffnyRSPa0dHx+vXrBw8etLW1jYyMbG5u
+ak9vb69eVSjDw8O1tbXNzc3d3d1VVVXa+eHDhxMnTugk8/Pzubm5V69effLkifbk5OQohcHB
+wUuXLn3+/Pn9+/eaIVZWVu7du3fx4sWJiYn8/HxVWFRUpB+hR/24MFd99/80iKVwfQmDkZm5
+80ZNEm/evNEY63Fubk6jW15ePjU1pWlDB+iTrblEZWhi0B6Nuvp4+vSphvn06dMaeA32yZMn
+dU7NGaOjo6urq3qLJiftqaio0AGrCXqqnrTx4sWLoaGh8+fP6+Saqx49enTz5s0f858FX6Vy
+fdHGuXPntK1HzR8qpqWlRa3oo3/9+nUN3rVr11SDjlQQ4ZOt0S0sLNTGnTt3NFuEAhSWDtPs
+Es5569Yt7dHcc+bMGU0SKqYyQS+pvPb2dr165cqVcBOjnfop2h/be6nC95XK/anoziD5tjR0
+o4uOxjXaL4og+QBta7zDU10ako+M7mR1WQkLnwsXLoSXwnsPniraoI8f59D3H9ESNxra5CXJ
+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
+yMsQLAkpEpWMarVyUEm6+kDA1dkJXScTWuIn3f975cOfUEsHCFFmdozQCAAA/TIAAFBLAwQU
+AAgICADgfBhJAAAAAAAAAAAAAAAADAAAAG1hbmlmZXN0LnJkZs2TzW6DMBCE7zyFZc7YQC8F
+BXIoyrlqn8A1hlgFL/KaEt6+jpNWUaSq6p/U465GM9+OtJvtYRzIi7KowVQ0Yyklykhotekr
+OrsuuaXbOtrYtisfmh3xaoOlnyq6d24qOV+WhS03DGzPs6IoeJrzPE+8IsHVOHFIDMa0jggJ
+Ho1CafXkfBo5zuIJZldRdOugkHn3ID2L3TqpoLIKYbZSvYe2IJGBQI0JTMqEdIMcuk5LxTOW
+81E5waHt4sdgvdODojxg8CuOz9jeiAym5V7gvbDuXIPffJVoeu5jenXTxfHfI5RgnDLuT+q7
+O3n/5/4uz/8Z4q+0dkRsQM6jZ/qQ57TyH1VHr1BLBwi092jSBQEAAIMDAABQSwMEFAAACAAA
+4HwYSQAAAAAAAAAAAAAAABoAAABDb25maWd1cmF0aW9uczIvdG9vbHBhbmVsL1BLAwQUAAAI
+AADgfBhJAAAAAAAAAAAAAAAAHAAAAENvbmZpZ3VyYXRpb25zMi9wcm9ncmVzc2Jhci9QSwME
+FAAICAgA4HwYSQAAAAAAAAAAAAAAACcAAABDb25maWd1cmF0aW9uczIvYWNjZWxlcmF0b3Iv
+Y3VycmVudC54bWwDAFBLBwgAAAAAAgAAAAAAAABQSwMEFAAACAAA4HwYSQAAAAAAAAAAAAAA
+ABgAAABDb25maWd1cmF0aW9uczIvZmxvYXRlci9QSwMEFAAACAAA4HwYSQAAAAAAAAAAAAAA
+AB8AAABDb25maWd1cmF0aW9uczIvaW1hZ2VzL0JpdG1hcHMvUEsDBBQAAAgAAOB8GEkAAAAA
+AAAAAAAAAAAYAAAAQ29uZmlndXJhdGlvbnMyL3Rvb2xiYXIvUEsDBBQAAAgAAOB8GEkAAAAA
+AAAAAAAAAAAYAAAAQ29uZmlndXJhdGlvbnMyL21lbnViYXIvUEsDBBQAAAgAAOB8GEkAAAAA
+AAAAAAAAAAAaAAAAQ29uZmlndXJhdGlvbnMyL3N0YXR1c2Jhci9QSwMEFAAACAAA4HwYSQAA
+AAAAAAAAAAAAABoAAABDb25maWd1cmF0aW9uczIvcG9wdXBtZW51L1BLAwQUAAgICADgfBhJ
+AAAAAAAAAAAAAAAAFQAAAE1FVEEtSU5GL21hbmlmZXN0LnhtbLWUwW7DIAyG732KiOsU2Hqa
+UNIeKu0JugdgxEmRwERgqvbtR6q1yTRlarTuZmPz/58wUG1PzhZHCNF4rNkLf2YFoPaNwa5m
+7/u38pVtN6vKKTQtRJLXoMj7MN7SmqWA0qtookTlIErS0veAjdfJAZL83i8vTrdsArBmm1Ux
++rXGQpn3h/PY3SZry17RoWZiTmRcdtAYVdK5h5qpvrdGK8pt4ogNvwDzKScnOBETSxj2h+Q+
+UBkbBV1D3mM3w2Cc6kAM9UUu2iMNfPkcZ4QHcjGUF+lGIMrDjg8XdkDq8bR0tvAPrF9rPDTt
+HVcndz0t9th5bE2XwkUiroXSGizk1AehUwi/D/dvXnc+h5hwQODJcD1VGMwr8eMP2HwCUEsH
+CB2A81kcAQAAPgQAAFBLAQIUABQAAAgAAOB8GElexjIMJwAAACcAAAAIAAAAAAAAAAAAAAAA
+AAAAAABtaW1ldHlwZVBLAQIUABQAAAgAAOB8GEkOYAWndwkAAHcJAAAYAAAAAAAAAAAAAAAA
+AE0AAABUaHVtYm5haWxzL3RodW1ibmFpbC5wbmdQSwECFAAUAAgICADgfBhJ+ay9rfoEAADL
+EwAACwAAAAAAAAAAAAAAAAD6CQAAY29udGVudC54bWxQSwECFAAUAAgICADgfBhJkUI+C+0F
+AABvJwAADAAAAAAAAAAAAAAAAAAtDwAAc2V0dGluZ3MueG1sUEsBAhQAFAAICAgA4HwYScPE
+aGDlAQAALQQAAAgAAAAAAAAAAAAAAAAAVBUAAG1ldGEueG1sUEsBAhQAFAAICAgA4HwYSVFm
+dozQCAAA/TIAAAoAAAAAAAAAAAAAAAAAbxcAAHN0eWxlcy54bWxQSwECFAAUAAgICADgfBhJ
+tPdo0gUBAACDAwAADAAAAAAAAAAAAAAAAAB3IAAAbWFuaWZlc3QucmRmUEsBAhQAFAAACAAA
+4HwYSQAAAAAAAAAAAAAAABoAAAAAAAAAAAAAAAAAtiEAAENvbmZpZ3VyYXRpb25zMi90b29s
+cGFuZWwvUEsBAhQAFAAACAAA4HwYSQAAAAAAAAAAAAAAABwAAAAAAAAAAAAAAAAA7iEAAENv
+bmZpZ3VyYXRpb25zMi9wcm9ncmVzc2Jhci9QSwECFAAUAAgICADgfBhJAAAAAAIAAAAAAAAA
+JwAAAAAAAAAAAAAAAAAoIgAAQ29uZmlndXJhdGlvbnMyL2FjY2VsZXJhdG9yL2N1cnJlbnQu
+eG1sUEsBAhQAFAAACAAA4HwYSQAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAfyIAAENvbmZp
+Z3VyYXRpb25zMi9mbG9hdGVyL1BLAQIUABQAAAgAAOB8GEkAAAAAAAAAAAAAAAAfAAAAAAAA
+AAAAAAAAALUiAABDb25maWd1cmF0aW9uczIvaW1hZ2VzL0JpdG1hcHMvUEsBAhQAFAAACAAA
+4HwYSQAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAA8iIAAENvbmZpZ3VyYXRpb25zMi90b29s
+YmFyL1BLAQIUABQAAAgAAOB8GEkAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAACgjAABDb25m
+aWd1cmF0aW9uczIvbWVudWJhci9QSwECFAAUAAAIAADgfBhJAAAAAAAAAAAAAAAAGgAAAAAA
+AAAAAAAAAABeIwAAQ29uZmlndXJhdGlvbnMyL3N0YXR1c2Jhci9QSwECFAAUAAAIAADgfBhJ
+AAAAAAAAAAAAAAAAGgAAAAAAAAAAAAAAAACWIwAAQ29uZmlndXJhdGlvbnMyL3BvcHVwbWVu
+dS9QSwECFAAUAAgICADgfBhJHYDzWRwBAAA+BAAAFQAAAAAAAAAAAAAAAADOIwAATUVUQS1J
+TkYvbWFuaWZlc3QueG1sUEsFBgAAAAARABEAcAQAAC0lAAAAAA==
+--------------9F1006EBC7F5F7758497FD08--

http://git-wip-us.apache.org/repos/asf/james-project/blob/3403ca18/"mailbox/store/src/test/resources/eml/\330\257\331\212\331\206\330\247\330\265\331\210\330\261.odt"
----------------------------------------------------------------------


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


[3/5] james-project git commit: JAMES-1814 Encode Content-Disposition header in download servlet when necessary

Posted by ro...@apache.org.
JAMES-1814 Encode Content-Disposition header in download servlet when necessary


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

Branch: refs/heads/master
Commit: abb21de13fefe2c99626d2178f99a7002fd2b4f8
Parents: 7443396
Author: Laura Royet <lr...@linagora.com>
Authored: Wed Sep 21 12:20:48 2016 +0200
Committer: Laura Royet <lr...@linagora.com>
Committed: Wed Sep 21 12:20:48 2016 +0200

----------------------------------------------------------------------
 .../integration/cucumber/DownloadStepdefs.java  | 26 +++++++++++++++++++-
 .../test/resources/cucumber/DownloadGet.feature |  6 +++++
 .../org/apache/james/jmap/DownloadServlet.java  | 14 +++++++++--
 3 files changed, 43 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/abb21de1/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java
index 6ef8a03..d000bb3 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/cucumber/DownloadStepdefs.java
@@ -41,7 +41,9 @@ import org.apache.james.jmap.api.access.AccessToken;
 import org.apache.james.jmap.model.AttachmentAccessToken;
 import org.apache.james.mailbox.model.MailboxConstants;
 import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mime4j.codec.DecoderUtil;
 
+import com.google.common.base.CharMatcher;
 import com.google.common.base.Charsets;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Objects;
@@ -63,6 +65,7 @@ public class DownloadStepdefs {
     private static final String INVALID_ATTACHMENT_TOKEN = "usera@domain.tld_"
             + "2015-06-29T13:41:22.124Z_"
             + "DiZa0O14MjLWrAA8P6MG35Gt5CBp7mt5U1EH/M++rIoZK7nlGJ4dPW0dvZD7h4m3o5b/Yd8DXU5x2x4+s0HOOKzD7X0RMlsU7JHJMNLvTvRGWF/C+MUyC8Zce7DtnRVPEQX2uAZhL2PBABV07Vpa8kH+NxoS9CL955Bc1Obr4G+KN2JorADlocFQA6ElXryF5YS/HPZSvq1MTC6aJIP0ku8WRpRnbwgwJnn26YpcHXcJjbkCBtd9/BhlMV6xNd2hTBkfZmYdoNo+UKBaXWzLxAlbLuxjpxwvDNJfOEyWFPgHDoRvzP+G7KzhVWjanHAHrhF0GilEa/MKpOI1qHBSwA==";
+    private static final String UTF8_CONTENT_DIPOSITION_START = "Content-Disposition: attachment; filename*=\"";
 
     private final UserStepdefs userStepdefs;
     private final MainStepdefs mainStepdefs;
@@ -330,6 +333,27 @@ public class DownloadStepdefs {
 
     @Then("^the attachment is named \"([^\"]*)\"$")
     public void assertContentDisposition(String name) throws IOException {
-        assertThat(response.getHeaders("Content-Disposition")).extracting(Header::toString).containsExactly("Content-Disposition: attachment; filename=\"" + name + "\"");
+        if (!CharMatcher.ASCII.matchesAllOf(name)) {
+            assertEncodedFilenameMatches(name);
+        } else {
+            assertThat(response.getFirstHeader("Content-Disposition").getValue()).isEqualTo("attachment; filename=\"" + name + "\"");
+        }
+    }
+
+    private void assertEncodedFilenameMatches(String name) {
+        String contentDispositionHeader = response.getHeaders("Content-Disposition")[0].toString();
+        assertThat(contentDispositionHeader).startsWith(UTF8_CONTENT_DIPOSITION_START);
+
+        String expectedFilename = decode(extractFilename(contentDispositionHeader));
+        assertThat(name).isEqualTo(expectedFilename);
+    }
+
+    private String extractFilename(String contentDispositionHeader) {
+        return contentDispositionHeader.substring(UTF8_CONTENT_DIPOSITION_START.length(), 
+                contentDispositionHeader.length() - 1);
+    }
+
+    private String decode(String name) {
+        return DecoderUtil.decodeEncodedWords(name, Charsets.UTF_8);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/abb21de1/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature
index 6772e4f..82828d1 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/resources/cucumber/DownloadGet.feature
@@ -22,3 +22,9 @@ Feature: Download GET
     When "username@domain.tld" downloads "2" with "myFileName.txt" name
     Then the user should receive that attachment
     And the attachment is named "myFileName.txt"
+
+  Scenario: Getting an attachment previously stored with a non ASCII name
+    Given "username@domain.tld" mailbox "inbox" contains a message "1" with an attachment "2"
+    When "username@domain.tld" downloads "2" with "\u062f\u064a\u0646\u0627\u0635\u0648\u0631.odt" name
+    Then the user should receive that attachment
+    And the attachment is named "\u062f\u064a\u0646\u0627\u0635\u0648\u0631.odt"
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/james-project/blob/abb21de1/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java
index 0d140e6..45f5dcc 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/DownloadServlet.java
@@ -41,10 +41,13 @@ import org.apache.james.mailbox.exception.AttachmentNotFoundException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.Attachment;
 import org.apache.james.mailbox.model.AttachmentId;
+import org.apache.james.mime4j.codec.EncoderUtil;
+import org.apache.james.mime4j.codec.EncoderUtil.Usage;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.CharMatcher;
 
 public class DownloadServlet extends HttpServlet {
 
@@ -126,10 +129,17 @@ public class DownloadServlet extends HttpServlet {
     }
 
     private void addContentDispositionHeader(Optional<String> optionalName, HttpServletResponse resp) {
-        optionalName.ifPresent(name -> resp.addHeader("Content-Disposition", "attachment; filename=\"" + name + "\""));
+        optionalName.ifPresent(name -> addContentDispositionHeaderRegardingEncoding(name, resp));
+    }
+
+    private void addContentDispositionHeaderRegardingEncoding(String name, HttpServletResponse resp) {
+        if (CharMatcher.ASCII.matchesAllOf(name)) {
+            resp.addHeader("Content-Disposition", "attachment; filename=\"" + name + "\"");
+        } else {
+            resp.addHeader("Content-Disposition", "attachment; filename*=\"" + EncoderUtil.encodeEncodedWord(name, Usage.TEXT_TOKEN) + "\"");
+        }
     }
 
-    
     private MailboxSession getMailboxSession(HttpServletRequest req) {
         return (MailboxSession) req.getAttribute(AuthenticationFilter.MAILBOX_SESSION);
     }


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


[5/5] james-project git commit: Merge remote-tracking branch 'laura/JAMES-1814-2'

Posted by ro...@apache.org.
Merge remote-tracking branch 'laura/JAMES-1814-2'


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

Branch: refs/heads/master
Commit: 3c8c176a0811e525b9ec1e5527e3a21479f44a9e
Parents: 3c15732 c07b64b
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Thu Sep 22 09:46:34 2016 +0200
Committer: Raphael Ouazana <ra...@linagora.com>
Committed: Thu Sep 22 09:46:34 2016 +0200

----------------------------------------------------------------------
 mailbox/store/pom.xml                           |   5 +
 .../store/mail/model/impl/MessageParser.java    |  11 +-
 .../mail/model/impl/MessageParserTest.java      |   8 +
 .../messageWithNonASCIIFilenameAttachment.eml   | 234 +++++++++++++++++++
 ...331\206\330\247\330\265\331\210\330\261.odt" | Bin 0 -> 10675 bytes
 .../integration/SetMessagesMethodTest.java      | 188 ++++++++++++++-
 .../integration/cucumber/DownloadStepdefs.java  |  26 ++-
 .../test/resources/cucumber/DownloadGet.feature |   6 +
 .../org/apache/james/jmap/DownloadServlet.java  |  14 +-
 .../jmap/methods/MIMEMessageConverter.java      |   8 +-
 .../jmap/methods/MIMEMessageConverterTest.java  |  52 ++++-
 11 files changed, 545 insertions(+), 7 deletions(-)
----------------------------------------------------------------------



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


[2/5] james-project git commit: JAMES-1814 Encoding filename in created messages

Posted by ro...@apache.org.
JAMES-1814 Encoding filename in created messages


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

Branch: refs/heads/master
Commit: 7443396fd824ce7448d2f7045fdecd8c9abe19c7
Parents: 3403ca1
Author: Laura Royet <lr...@linagora.com>
Authored: Wed Sep 21 12:14:15 2016 +0200
Committer: Laura Royet <lr...@linagora.com>
Committed: Wed Sep 21 12:14:15 2016 +0200

----------------------------------------------------------------------
 .../jmap/methods/MIMEMessageConverter.java      |  8 ++-
 .../jmap/methods/MIMEMessageConverterTest.java  | 52 +++++++++++++++++++-
 2 files changed, 58 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/7443396f/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MIMEMessageConverter.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MIMEMessageConverter.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MIMEMessageConverter.java
index 886fd4e..4eb54db 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MIMEMessageConverter.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/MIMEMessageConverter.java
@@ -33,6 +33,8 @@ import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.jmap.model.CreationMessageId;
 import org.apache.james.mime4j.Charsets;
 import org.apache.james.mime4j.codec.DecodeMonitor;
+import org.apache.james.mime4j.codec.EncoderUtil;
+import org.apache.james.mime4j.codec.EncoderUtil.Usage;
 import org.apache.james.mime4j.dom.FieldParser;
 import org.apache.james.mime4j.dom.Message;
 import org.apache.james.mime4j.dom.Multipart;
@@ -259,7 +261,7 @@ public class MIMEMessageConverter {
     private ContentTypeField contentTypeField(MessageAttachment att) {
         Builder<String, String> parameters = ImmutableMap.<String, String> builder();
         if (att.getName().isPresent()) {
-            parameters.put("name", att.getName().get());
+            parameters.put("name", encode(att.getName().get()));
         }
         String type = att.getAttachment().getType();
         if (type.contains(FIELD_PARAMETERS_SEPARATOR)) {
@@ -268,6 +270,10 @@ public class MIMEMessageConverter {
         return Fields.contentType(type, parameters.build());
     }
 
+    private String encode(String name) {
+        return EncoderUtil.encodeEncodedWord(name, Usage.TEXT_TOKEN);
+    }
+
     private String contentTypeWithoutParameters(String type) {
         return FluentIterable.from(Splitter.on(FIELD_PARAMETERS_SEPARATOR).split(type)).get(0);
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/7443396f/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/MIMEMessageConverterTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/MIMEMessageConverterTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/MIMEMessageConverterTest.java
index a5f4556..6fbb98d 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/MIMEMessageConverterTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/methods/MIMEMessageConverterTest.java
@@ -34,11 +34,14 @@ import org.apache.james.mailbox.model.AttachmentId;
 import org.apache.james.mailbox.model.Cid;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mime4j.Charsets;
+import org.apache.james.mime4j.codec.EncoderUtil;
+import org.apache.james.mime4j.codec.EncoderUtil.Usage;
 import org.apache.james.mime4j.dom.Entity;
 import org.apache.james.mime4j.dom.Message;
 import org.apache.james.mime4j.dom.Multipart;
 import org.apache.james.mime4j.dom.TextBody;
 import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.dom.field.ContentTypeField;
 import org.apache.james.mime4j.message.BasicBodyFactory;
 import org.apache.james.mime4j.stream.Field;
 import org.junit.Test;
@@ -470,4 +473,51 @@ public class MIMEMessageConverterTest {
         String actual = new String(convert, Charsets.US_ASCII);
         assertThat(actual).contains(expectedEncodedContent);
     }
-}
\ No newline at end of file
+
+    @Test
+    public void convertToMimeShouldAddAttachmentAndContainsIndicationAboutTheWayToEncodeFilenamesAttachmentInTheInputStreamWhenSending() {
+        // Given
+        MIMEMessageConverter sut = new MIMEMessageConverter();
+
+        CreationMessage testMessage = CreationMessage.builder()
+                .mailboxIds(ImmutableList.of("dead-bada55"))
+                .subject("subject")
+                .from(DraftEmailer.builder().name("sender").build())
+                .htmlBody("Hello <b>all<b>!")
+                .build();
+
+        String expectedCID = "cid";
+        String expectedMimeType = "image/png";
+        String text = "123456";
+        String name = "\u062f\u064a\u0646\u0627\u0635\u0648\u0631.png";
+        String expectedName = EncoderUtil.encodeEncodedWord(name, Usage.TEXT_TOKEN);
+        MessageAttachment attachment = MessageAttachment.builder()
+                .name(name)
+                .attachment(org.apache.james.mailbox.model.Attachment.builder()
+                    .attachmentId(AttachmentId.from("blodId"))
+                    .bytes(text.getBytes())
+                    .type(expectedMimeType)
+                    .build())
+                .cid(Cid.from(expectedCID))
+                .isInline(true)
+                .build();
+
+        // When
+        Message result = sut.convertToMime(new ValueWithId.CreationMessageEntry(
+                CreationMessageId.of("user|mailbox|1"), testMessage), ImmutableList.of(attachment));
+
+        // Then
+        assertThat(result.getBody()).isInstanceOf(Multipart.class);
+        assertThat(result.isMultipart()).isTrue();
+        Multipart typedResult = (Multipart)result.getBody();
+        assertThat(typedResult.getBodyParts()).hasSize(2);
+
+        Entity attachmentPart = typedResult.getBodyParts().get(1);
+        String filename = getNameParameterValue(attachmentPart);
+        assertThat(filename).isEqualTo(expectedName);
+    }
+
+    private String getNameParameterValue(Entity attachmentPart) {
+        return ((ContentTypeField) attachmentPart.getHeader().getField("Content-Type")).getParameter("name");
+    }
+}


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


[4/5] james-project git commit: JAMES-1814 Special filenames integration test

Posted by ro...@apache.org.
JAMES-1814 Special filenames integration test


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

Branch: refs/heads/master
Commit: c07b64b752d684fc38861b8db3b9a07f1abcd74c
Parents: abb21de
Author: Laura Royet <lr...@linagora.com>
Authored: Wed Sep 21 12:21:40 2016 +0200
Committer: Laura Royet <lr...@linagora.com>
Committed: Wed Sep 21 12:21:40 2016 +0200

----------------------------------------------------------------------
 .../integration/SetMessagesMethodTest.java      | 188 ++++++++++++++++++-
 1 file changed, 187 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/c07b64b7/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 d85c1bc..58e2609 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
@@ -37,7 +37,6 @@ import static org.hamcrest.Matchers.nullValue;
 import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
 import static org.hamcrest.collection.IsMapWithSize.anEmptyMap;
 
-
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.time.ZonedDateTime;
@@ -1775,6 +1774,193 @@ public abstract class SetMessagesMethodTest {
             .body(secondAttachment + ".isInline", equalTo(true));
     }
 
+    @Test
+    public void setMessagesShouldReturnAttachmentsWithNonASCIINames() throws Exception {
+        jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "sent");
+
+        Attachment attachment = Attachment.builder()
+                .bytes("attachment".getBytes(Charsets.UTF_8))
+                .type("application/octet-stream")
+                .build();
+        uploadAttachment(attachment);
+        Attachment attachment2 = Attachment.builder()
+                .bytes("attachment2".getBytes(Charsets.UTF_8))
+                .type("application/octet-stream")
+                .build();
+        uploadAttachment(attachment2);
+        Attachment attachment3 = Attachment.builder()
+                .bytes("attachment3".getBytes(Charsets.UTF_8))
+                .type("application/octet-stream")
+                .build();
+        uploadAttachment(attachment3);
+
+        String messageCreationId = "creationId";
+        String fromAddress = username;
+        String outboxId = getOutboxId(accessToken);
+        String requestBody = "[" +
+                "  [" +
+                "    \"setMessages\","+
+                "    {" +
+                "      \"create\":" +
+                "      {" +
+                "        \"" + messageCreationId  + "\" : "+
+                "        {" +
+                "          \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+                "          \"to\": [{ \"name\": \"BOB\", \"email\": \"someone@example.com\"}]," +
+                "          \"subject\": \"Message with three attachments with non ASCII name\"," +
+                "          \"textBody\": \"Test body\"," +
+                "          \"mailboxIds\": [\"" + outboxId + "\"], " +
+                "          \"attachments\":" +
+                "          [" +
+                "            {" +
+                "              \"blobId\" : \"" + attachment.getAttachmentId().getId() + "\", " +
+                "              \"type\" : \"" + attachment.getType() + "\", " +
+                "              \"size\" : " + attachment.getSize() + "," +
+                "              \"name\" : \"\u062f\u064a\u0646\u0627\u0635\u0648\u0631.png\", " +
+                "              \"isInline\" : false" +
+                "            }," +
+                "            {" +
+                "              \"blobId\" : \"" + attachment2.getAttachmentId().getId() + "\", " +
+                "              \"type\" : \"" + attachment2.getType() + "\", " +
+                "              \"size\" : " + attachment2.getSize() + "," +
+                "              \"name\" : \"\u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c.png\", " +
+                "              \"isInline\" : false" +
+                "            }," +
+                "            {" +
+                "              \"blobId\" : \"" + attachment3.getAttachmentId().getId() + "\", " +
+                "              \"type\" : \"" + attachment3.getType() + "\", " +
+                "              \"size\" : " + attachment3.getSize() + "," +
+                "              \"name\" : \"\u8fdb\u5316\u8fd8\u662f\u4e0d.png\"," +
+                "              \"isInline\" : false" +
+                "            }" +
+                "          ]" +
+                "        }" +
+                "      }" +
+                "    }," +
+                "    \"#0\"" +
+                "  ]" +
+                "]";
+
+        String createdPath = ARGUMENTS + ".created[\""+messageCreationId+"\"]";
+        String firstAttachment = createdPath + ".attachments[0]";
+        String secondAttachment = createdPath + ".attachments[1]";
+        String thirdAttachment = createdPath + ".attachments[2]";
+
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        .when()
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .body(NAME, equalTo("messagesSet"))
+            .body(ARGUMENTS + ".notCreated", aMapWithSize(0))
+            .body(ARGUMENTS + ".created", aMapWithSize(1))
+            .body(createdPath + ".attachments", hasSize(3))
+            .body(firstAttachment + ".name", equalTo("\u062f\u064a\u0646\u0627\u0635\u0648\u0631.png"))
+            .body(secondAttachment + ".name", equalTo("\u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c.png"))
+            .body(thirdAttachment + ".name", equalTo("\u8fdb\u5316\u8fd8\u662f\u4e0d.png"));
+    }
+
+    @Test
+    public void filenamesAttachmentsWithNonASCIICharactersShouldBeRetrievedWhenChainingSetMessagesAndGetMessages() throws Exception {
+        jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "sent");
+
+        Attachment attachment = Attachment.builder()
+                .bytes("attachment".getBytes(Charsets.UTF_8))
+                .type("application/octet-stream")
+                .build();
+        uploadAttachment(attachment);
+
+        Attachment attachment2 = Attachment.builder()
+                .bytes("attachment2".getBytes(Charsets.UTF_8))
+                .type("application/octet-stream")
+                .build();
+        uploadAttachment(attachment2);
+
+        Attachment attachment3 = Attachment.builder()
+                .bytes("attachment3".getBytes(Charsets.UTF_8))
+                .type("application/octet-stream")
+                .build();
+        uploadAttachment(attachment3);
+
+        String messageCreationId = "creationId";
+        String fromAddress = username;
+        String outboxId = getOutboxId(accessToken);
+        String requestBody = "[" +
+                "  [" +
+                "    \"setMessages\","+
+                "    {" +
+                "      \"create\":" +
+                "      {" +
+                "        \"" + messageCreationId  + "\" : "+
+                "        {" +
+                "          \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+                "          \"to\": [{ \"name\": \"BOB\", \"email\": \"" + fromAddress + "\"}]," +
+                "          \"subject\": \"Message with three attachments with non ASCII name\"," +
+                "          \"textBody\": \"Test body\"," +
+                "          \"mailboxIds\": [\"" + outboxId + "\"], " +
+                "          \"attachments\":" +
+                "          [" +
+                "            {" +
+                "              \"blobId\" : \"" + attachment.getAttachmentId().getId() + "\", " +
+                "              \"type\" : \"" + attachment.getType() + "\", " +
+                "              \"size\" : " + attachment.getSize() + "," +
+                "              \"name\" : \"\u062f\u064a\u0646\u0627\u0635\u0648\u0631.png\", " +
+                "              \"isInline\" : false" +
+                "            }," +
+                "            {" +
+                "              \"blobId\" : \"" + attachment2.getAttachmentId().getId() + "\", " +
+                "              \"type\" : \"" + attachment2.getType() + "\", " +
+                "              \"size\" : " + attachment2.getSize() + "," +
+                "              \"name\" : \"\u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c.png\", " +
+                "              \"isInline\" : false" +
+                "            }," +
+                "            {" +
+                "              \"blobId\" : \"" + attachment3.getAttachmentId().getId() + "\", " +
+                "              \"type\" : \"" + attachment3.getType() + "\", " +
+                "              \"size\" : " + attachment3.getSize() + "," +
+                "              \"name\" : \"\u8fdb\u5316\u8fd8\u662f\u4e0d.png\"," +
+                "              \"isInline\" : false" +
+                "            }" +
+                "          ]" +
+                "        }" +
+                "      }" +
+                "    }," +
+                "    \"#0\"" +
+                "  ]" +
+                "]";
+
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        .when()
+            .post("/jmap").then();
+
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+
+        String message = ARGUMENTS + ".list[0]";
+        String firstAttachment = message + ".attachments[0]";
+        String secondAttachment = message + ".attachments[1]";
+        String thirdAttachment = message + ".attachments[2]";
+        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(message + ".attachments", hasSize(3))
+            .body(firstAttachment + ".name", equalTo("\u062f\u064a\u0646\u0627\u0635\u0648\u0631.png"))
+            .body(secondAttachment + ".name",  equalTo("\u044d\u0432\u043e\u043b\u044e\u0446\u0438\u043e\u043d\u0438\u0440\u043e\u0432\u0430\u0442\u044c.png"))
+            .body(thirdAttachment + ".name", equalTo("\u8fdb\u5316\u8fd8\u662f\u4e0d.png"));
+    }
+
     private void uploadAttachment(Attachment attachment) throws IOException {
         with()
             .header("Authorization", accessToken.serialize())


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