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 2017/09/27 08:00:10 UTC

[1/6] james-project git commit: JAMES-2161 Keyword should support underscore character in flags

Repository: james-project
Updated Branches:
  refs/heads/master 0e5872cdf -> 4c3e0403c


JAMES-2161 Keyword should support underscore character in flags


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

Branch: refs/heads/master
Commit: 9c5b001b6670ef1667e6ef3d67e8815a2b9a0a42
Parents: 0e5872c
Author: Antoine Duprat <ad...@linagora.com>
Authored: Tue Sep 26 12:31:12 2017 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue Sep 26 12:31:12 2017 +0200

----------------------------------------------------------------------
 .../java/org/apache/james/jmap/model/Keyword.java     |  6 +++++-
 .../java/org/apache/james/jmap/model/KeywordTest.java | 14 ++++++++++++--
 2 files changed, 17 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/9c5b001b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java
index ff1a2f0..72918d0 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keyword.java
@@ -20,6 +20,7 @@
 package org.apache.james.jmap.model;
 
 import java.util.Optional;
+
 import javax.mail.Flags;
 
 import org.apache.commons.lang.StringUtils;
@@ -34,7 +35,10 @@ import com.google.common.collect.ImmutableList;
 public class Keyword {
     private final static int FLAG_NAME_MIN_LENGTH = 1;
     private final static int FLAG_NAME_MAX_LENGTH = 255;
-    private final static CharMatcher FLAG_NAME_PATTERN = CharMatcher.JAVA_LETTER_OR_DIGIT.or(CharMatcher.is('$'));
+    private final static CharMatcher FLAG_NAME_PATTERN = 
+            CharMatcher.JAVA_LETTER_OR_DIGIT
+                .or(CharMatcher.is('$'))
+                .or(CharMatcher.is('_'));
 
     public final static Keyword DRAFT = new Keyword("$Draft");
     public final static Keyword SEEN = new Keyword("$Seen");

http://git-wip-us.apache.org/repos/asf/james-project/blob/9c5b001b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java
index 3eeb6f5..58fdb24 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/KeywordTest.java
@@ -20,16 +20,18 @@
 package org.apache.james.jmap.model;
 
 import static org.assertj.core.api.Assertions.assertThat;
+
 import java.util.Optional;
+
 import javax.mail.Flags;
 
 import org.apache.commons.lang3.StringUtils;
-
-import nl.jqno.equalsverifier.EqualsVerifier;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
 
+import nl.jqno.equalsverifier.EqualsVerifier;
+
 public class KeywordTest {
     private final static int FLAG_NAME_MAX_LENTH = 255;
     private final static String ANY_KEYWORD = "AnyKeyword";
@@ -185,4 +187,12 @@ public class KeywordTest {
         assertThat(keyword.asFlags())
             .isEqualTo(new Flags(ANY_KEYWORD));
     }
+
+    @Test
+    public void asFlagsShouldReturnFlagsWhenUserFlagContainsUnderscore() throws Exception {
+        String userFlag = "$has_cal";
+        Keyword keyword = new Keyword(userFlag);
+        assertThat(keyword.asFlags())
+            .isEqualTo(new Flags(userFlag));
+    }
 }
\ No newline at end of file


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


[4/6] james-project git commit: JAMES-2160 Handle JMAP headers provided at creation time

Posted by ma...@apache.org.
JAMES-2160 Handle JMAP headers provided at creation time


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

Branch: refs/heads/master
Commit: 93cef1ddd0ef1deb8092710f473cacc2e5328e50
Parents: 0e5872c
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Mon Sep 25 15:22:13 2017 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Sep 27 09:58:16 2017 +0200

----------------------------------------------------------------------
 .../integration/SetMessagesMethodTest.java      | 151 +++++++++++++++++++
 .../jmap/methods/MIMEMessageConverter.java      |  40 ++++-
 .../jmap/methods/MIMEMessageConverterTest.java  | 138 +++++++++++++++++
 3 files changed, 321 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/93cef1dd/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 f22b2de..f22472b 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
@@ -3375,6 +3375,157 @@ public abstract class SetMessagesMethodTest {
     }
 
     @Test
+    public void setMessagesShouldSetUserAddedHeaders() throws Exception {
+        String messageCreationId = "creationId1337";
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + USERNAME + "\"}," +
+            "        \"to\": [{ \"name\": \"Me\", \"email\": \"" + USERNAME + "\"}]," +
+            "        \"headers\": { \"X-MY-SPECIAL-HEADER\": \"first header value\", \"OTHER-HEADER\": \"other value\"}," +
+            "        \"subject\": \"Thank you for joining example.com!\"," +
+            "        \"textBody\": \"Hello someone, and thank you for joining example.com!\"," +
+            "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        String messageId = given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        // When
+        .post("/jmap")
+        .then()
+            .extract()
+            .body()
+            .<String>path(ARGUMENTS + ".created."+ messageCreationId +".id");
+
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+
+        String message = ARGUMENTS + ".list[0]";
+
+        with()
+            .header("Authorization", accessToken.serialize())
+            .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, \"#0\"]]")
+        .when()
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .log().ifValidationFails()
+            .body(NAME, equalTo("messages"))
+            .body(ARGUMENTS + ".list", hasSize(1))
+            .body(message + ".headers", Matchers.allOf(
+                hasEntry("X-MY-SPECIAL-HEADER", "first header value"),
+                hasEntry("OTHER-HEADER", "other value")));
+    }
+
+    @Test
+    public void setMessagesShouldSetUserAddedHeadersInSent() throws Exception {
+        String toUsername = "username1@" + USERS_DOMAIN;
+        String password = "password";
+        dataProbe.addUser(toUsername, password);
+        mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, toUsername, DefaultMailboxes.INBOX);
+
+        String messageCreationId = "creationId1337";
+        String fromAddress = USERNAME;
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"" + toUsername + "\"}]," +
+            "        \"headers\": { \"X-MY-SPECIAL-HEADER\": \"first header value\", \"OTHER-HEADER\": \"other value\"}," +
+            "        \"subject\": \"Thank you for joining example.com!\"," +
+            "        \"textBody\": \"Hello someone, and thank you for joining example.com!\"," +
+            "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        .post("/jmap");
+
+        String sentMailboxId = getMailboxId(accessToken, Role.SENT);
+
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> messageHasBeenMovedToSentBox(sentMailboxId));
+
+        String message = SECOND_ARGUMENTS + ".list[0]";
+        with()
+            .header("Authorization", this.accessToken.serialize())
+            .body("[[\"getMessageList\", {\"fetchMessages\":true, \"fetchMessageProperties\": [\"headers\"], \"filter\":{\"inMailboxes\":[\"" + sentMailboxId + "\"]}}, \"#0\"]]")
+        .when()
+            .post("/jmap")
+        .then()
+            .log().ifValidationFails()
+            .statusCode(200)
+            .body(SECOND_NAME, equalTo("messages"))
+            .body(SECOND_ARGUMENTS + ".list", hasSize(1))
+            .body(message + ".headers", Matchers.allOf(
+                hasEntry("X-MY-SPECIAL-HEADER", "first header value"),
+                hasEntry("OTHER-HEADER", "other value")));
+    }
+
+    @Test
+    public void setMessagesShouldFilterComputedHeadersFromUserAddedHeaders() throws Exception {
+        String messageCreationId = "creationId1337";
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + USERNAME + "\"}," +
+            "        \"to\": [{ \"name\": \"Me\", \"email\": \"" + USERNAME + "\"}]," +
+            "        \"headers\": { \"From\": \"hacker@example.com\", \"X-MY-SPECIAL-HEADER\": \"first header value\", \"OTHER-HEADER\": \"other value\"}," +
+            "        \"subject\": \"Thank you for joining example.com!\"," +
+            "        \"textBody\": \"Hello someone, and thank you for joining example.com!\"," +
+            "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        String messageId = with()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        // When
+        .post("/jmap")
+        .then()
+            .extract()
+            .body()
+            .<String>path(ARGUMENTS + ".created."+ messageCreationId +".id");
+
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+
+        String message = ARGUMENTS + ".list[0]";
+
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, \"#0\"]]")
+        .when()
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .log().ifValidationFails()
+            .body(NAME, equalTo("messages"))
+            .body(ARGUMENTS + ".list", hasSize(1))
+            .body(message + ".headers", Matchers.allOf(
+                hasEntry("X-MY-SPECIAL-HEADER", "first header value"),
+                hasEntry("OTHER-HEADER", "other value"),
+                not(hasEntry("From", "hacker@example.com")),
+                hasEntry("From", "Me <" + USERNAME + ">")));
+    }
+
+    @Test
     public void setMessagesShouldCreateMessageWhenSendingMessageWithNonIndexableAttachment() throws Exception {
         Attachment nonIndexableAttachment = Attachment.builder()
                 .bytes(IOUtils.toByteArray(ClassLoader.getSystemResourceAsStream("attachment/nonIndexableAttachment.html")))

http://git-wip-us.apache.org/repos/asf/james-project/blob/93cef1dd/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 4fdecf1..c964c7d 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
@@ -22,6 +22,8 @@ package org.apache.james.jmap.methods;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Date;
+import java.util.List;
+import java.util.Locale;
 import java.util.Optional;
 import java.util.TimeZone;
 import java.util.function.Consumer;
@@ -42,6 +44,7 @@ import org.apache.james.mime4j.dom.TextBody;
 import org.apache.james.mime4j.dom.address.Mailbox;
 import org.apache.james.mime4j.dom.field.ContentDispositionField;
 import org.apache.james.mime4j.dom.field.ContentTypeField;
+import org.apache.james.mime4j.dom.field.FieldName;
 import org.apache.james.mime4j.dom.field.UnstructuredField;
 import org.apache.james.mime4j.field.Fields;
 import org.apache.james.mime4j.field.UnstructuredFieldImpl;
@@ -50,12 +53,12 @@ import org.apache.james.mime4j.message.BodyPart;
 import org.apache.james.mime4j.message.BodyPartBuilder;
 import org.apache.james.mime4j.message.DefaultMessageWriter;
 import org.apache.james.mime4j.message.MultipartBuilder;
-import org.apache.james.mime4j.stream.Field;
 import org.apache.james.mime4j.stream.NameValuePair;
 import org.apache.james.mime4j.stream.RawField;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Splitter;
 import com.google.common.base.Throwables;
@@ -77,6 +80,24 @@ public class MIMEMessageConverter {
     private static final String FIELD_PARAMETERS_SEPARATOR = ";";
     private static final String QUOTED_PRINTABLE = "quoted-printable";
     private static final String BASE64 = "base64";
+    private static final String IN_REPLY_TO_HEADER = "In-Reply-To";
+    private static final List<String> COMPUTED_HEADERS = ImmutableList.of(
+            FieldName.FROM,
+            FieldName.SENDER,
+            FieldName.REPLY_TO,
+            FieldName.TO,
+            FieldName.CC,
+            FieldName.BCC,
+            FieldName.SUBJECT,
+            FieldName.MESSAGE_ID,
+            FieldName.DATE,
+            IN_REPLY_TO_HEADER,
+            FieldName.CONTENT_TYPE,
+            FieldName.MIME_VERSION,
+            FieldName.CONTENT_TRANSFER_ENCODING);
+    private static final List<String> LOWERCASED_COMPUTED_HEADERS = COMPUTED_HEADERS.stream()
+            .map(s -> s.toLowerCase(Locale.ENGLISH))
+            .collect(Guavate.toImmutableList());
 
     private final BasicBodyFactory bodyFactory;
 
@@ -137,18 +158,21 @@ public class MIMEMessageConverter {
 
         // note that date conversion probably lose milliseconds!
         messageBuilder.setDate(Date.from(newMessage.getDate().toInstant()), TimeZone.getTimeZone(newMessage.getDate().getZone()));
-        newMessage.getInReplyToMessageId().ifPresent(addInReplyToHeader(messageBuilder::addField));
+        newMessage.getInReplyToMessageId()
+            .ifPresent(id -> addHeader(messageBuilder, IN_REPLY_TO_HEADER, id));
         if (!isMultipart(newMessage, messageAttachments)) {
             newMessage.getHtmlBody().ifPresent(x -> messageBuilder.setContentType(HTML_MEDIA_TYPE, UTF_8_CHARSET));
         }
+        newMessage.getHeaders().entrySet().stream()
+            .filter(header -> ! header.getKey().trim().isEmpty())
+            .filter(header -> ! LOWERCASED_COMPUTED_HEADERS.contains(header.getKey().toLowerCase(Locale.ENGLISH)))
+            .forEach(header -> addHeader(messageBuilder, header.getKey(), header.getValue()));
     }
 
-    private Consumer<String> addInReplyToHeader(Consumer<Field> headerAppender) {
-        return msgId -> {
-            FieldParser<UnstructuredField> parser = UnstructuredFieldImpl.PARSER;
-            RawField rawField = new RawField("In-Reply-To", msgId);
-            headerAppender.accept(parser.parse(rawField, DecodeMonitor.SILENT));
-        };
+    private void addHeader(Message.Builder messageBuilder, String fieldName, String value) {
+        FieldParser<UnstructuredField> parser = UnstructuredFieldImpl.PARSER;
+        RawField rawField = new RawField(fieldName, value);
+        messageBuilder.addField(parser.parse(rawField, DecodeMonitor.SILENT));
     }
 
     private boolean isMultipart(CreationMessage newMessage, ImmutableList<MessageAttachment> messageAttachments) {

http://git-wip-us.apache.org/repos/asf/james-project/blob/93cef1dd/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 6fbb98d..9e9a2cf 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
@@ -47,6 +47,7 @@ import org.apache.james.mime4j.stream.Field;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 
 public class MIMEMessageConverterTest {
     @Test
@@ -71,6 +72,143 @@ public class MIMEMessageConverterTest {
                 .containsOnly(matchingMessageId);
     }
 
+    @Test
+    public void convertToMimeShouldAddHeaderWhenProvided() {
+        // Given
+        MIMEMessageConverter sut = new MIMEMessageConverter();
+
+        CreationMessage messageHavingInReplyTo = CreationMessage.builder()
+                .from(DraftEmailer.builder().name("sender").build())
+                .headers(ImmutableMap.of("FIRST", "first value"))
+                .mailboxIds(ImmutableList.of("dead-beef-1337"))
+                .subject("subject")
+                .build();
+
+        // When
+        Message result = sut.convertToMime(new ValueWithId.CreationMessageEntry(
+                CreationMessageId.of("user|mailbox|1"), messageHavingInReplyTo), ImmutableList.of());
+
+        // Then
+        assertThat(result.getHeader().getFields("FIRST")).extracting(Field::getBody)
+                .containsOnly("first value");
+    }
+
+    @Test
+    public void convertToMimeShouldAddHeadersWhenProvided() {
+        // Given
+        MIMEMessageConverter sut = new MIMEMessageConverter();
+
+        CreationMessage messageHavingInReplyTo = CreationMessage.builder()
+                .from(DraftEmailer.builder().name("sender").build())
+                .headers(ImmutableMap.of("FIRST", "first value", "SECOND", "second value"))
+                .mailboxIds(ImmutableList.of("dead-beef-1337"))
+                .subject("subject")
+                .build();
+
+        // When
+        Message result = sut.convertToMime(new ValueWithId.CreationMessageEntry(
+                CreationMessageId.of("user|mailbox|1"), messageHavingInReplyTo), ImmutableList.of());
+
+        // Then
+        assertThat(result.getHeader().getFields("FIRST")).extracting(Field::getBody)
+                .containsOnly("first value");
+        assertThat(result.getHeader().getFields("SECOND")).extracting(Field::getBody)
+            .containsOnly("second value");
+    }
+
+    @Test
+    public void convertToMimeShouldFilterGeneratedHeadersWhenProvided() {
+        // Given
+        MIMEMessageConverter sut = new MIMEMessageConverter();
+
+        String joesEmail = "joe@example.com";
+        CreationMessage messageHavingInReplyTo = CreationMessage.builder()
+                .from(DraftEmailer.builder().email(joesEmail).name("joe").build())
+                .headers(ImmutableMap.of("From", "hacker@example.com", "VALID", "valid header value"))
+                .mailboxIds(ImmutableList.of("dead-beef-1337"))
+                .subject("subject")
+                .build();
+
+        // When
+        Message result = sut.convertToMime(new ValueWithId.CreationMessageEntry(
+                CreationMessageId.of("user|mailbox|1"), messageHavingInReplyTo), ImmutableList.of());
+
+        // Then
+        assertThat(result.getFrom()).extracting(Mailbox::getAddress)
+            .allMatch(f -> f.equals(joesEmail));
+        assertThat(result.getHeader().getFields("VALID")).extracting(Field::getBody)
+            .containsOnly("valid header value");
+        assertThat(result.getHeader().getFields("From")).extracting(Field::getBody)
+            .containsOnly("joe <jo...@example.com>");
+    }
+
+    @Test
+    public void convertToMimeShouldFilterGeneratedHeadersRegardlessOfCaseWhenProvided() {
+        // Given
+        MIMEMessageConverter sut = new MIMEMessageConverter();
+
+        String joesEmail = "joe@example.com";
+        CreationMessage messageHavingInReplyTo = CreationMessage.builder()
+                .from(DraftEmailer.builder().email(joesEmail).name("joe").build())
+                .headers(ImmutableMap.of("frOM", "hacker@example.com", "VALID", "valid header value"))
+                .mailboxIds(ImmutableList.of("dead-beef-1337"))
+                .subject("subject")
+                .build();
+
+        // When
+        Message result = sut.convertToMime(new ValueWithId.CreationMessageEntry(
+                CreationMessageId.of("user|mailbox|1"), messageHavingInReplyTo), ImmutableList.of());
+
+        // Then
+        assertThat(result.getFrom()).extracting(Mailbox::getAddress)
+            .allMatch(f -> f.equals(joesEmail));
+        assertThat(result.getHeader().getFields("VALID")).extracting(Field::getBody)
+            .containsOnly("valid header value");
+        assertThat(result.getHeader().getFields("From")).extracting(Field::getBody)
+            .containsOnly("joe <jo...@example.com>");
+    }
+
+    @Test
+    public void convertToMimeShouldFilterEmptyHeaderNames() {
+        // Given
+        MIMEMessageConverter sut = new MIMEMessageConverter();
+
+        CreationMessage messageHavingInReplyTo = CreationMessage.builder()
+                .from(DraftEmailer.builder().name("joe").build())
+                .headers(ImmutableMap.of("", "empty header name value"))
+                .mailboxIds(ImmutableList.of("dead-beef-1337"))
+                .subject("subject")
+                .build();
+
+        // When
+        Message result = sut.convertToMime(new ValueWithId.CreationMessageEntry(
+                CreationMessageId.of("user|mailbox|1"), messageHavingInReplyTo), ImmutableList.of());
+
+        // Then
+        assertThat(result.getHeader().getFields("")).isEmpty();
+    }
+
+    @Test
+    public void convertToMimeShouldFilterWhiteSpacesOnlyHeaderNames() {
+        // Given
+        MIMEMessageConverter sut = new MIMEMessageConverter();
+
+        CreationMessage messageHavingInReplyTo = CreationMessage.builder()
+                .from(DraftEmailer.builder().name("joe").build())
+                .headers(ImmutableMap.of("   ", "only spaces header name values"))
+                .mailboxIds(ImmutableList.of("dead-beef-1337"))
+                .subject("subject")
+                .build();
+
+        // When
+        Message result = sut.convertToMime(new ValueWithId.CreationMessageEntry(
+                CreationMessageId.of("user|mailbox|1"), messageHavingInReplyTo), ImmutableList.of());
+
+        // Then
+        assertThat(result.getHeader().getFields("   ")).isEmpty();
+        assertThat(result.getHeader().getFields("")).isEmpty();
+    }
+
     @Test(expected = IllegalArgumentException.class)
     public void convertToMimeShouldThrowWhenMessageIsNull() {
         MIMEMessageConverter sut = new MIMEMessageConverter();


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


[2/6] james-project git commit: JAMES-2161 Don't throw when failing to parse a flag

Posted by ma...@apache.org.
JAMES-2161 Don't throw when failing to parse a flag


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

Branch: refs/heads/master
Commit: 036096bb92ffb4896faf8ad4fd8873d71591495d
Parents: 9c5b001
Author: Antoine Duprat <ad...@linagora.com>
Authored: Tue Sep 26 12:33:30 2017 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Wed Sep 27 08:52:04 2017 +0200

----------------------------------------------------------------------
 .../org/apache/james/jmap/model/Keywords.java   | 16 +++++++-
 .../apache/james/jmap/model/MessageTest.java    | 43 ++++++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/036096bb/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java
index 91aff31..ed07982 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/Keywords.java
@@ -25,9 +25,12 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
+
 import javax.mail.Flags;
 
 import org.apache.james.mailbox.FlagsBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.github.steveash.guavate.Guavate;
 import com.google.common.annotations.VisibleForTesting;
@@ -38,7 +41,9 @@ import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 
 public class Keywords {
+
     public static final Keywords DEFAULT_VALUE = factory().fromSet(ImmutableSet.of());
+    private static final Logger LOGGER = LoggerFactory.getLogger(Keywords.class);
 
     public interface KeywordsValidator {
         void validate(Set<Keyword> keywords);
@@ -121,12 +126,21 @@ public class Keywords {
         public Keywords fromFlags(Flags flags) {
             return fromSet(Stream.concat(
                     Stream.of(flags.getUserFlags())
-                        .map(Keyword::new),
+                        .flatMap(this::asKeyword),
                     Stream.of(flags.getSystemFlags())
                         .map(Keyword::fromFlag))
                 .collect(Guavate.toImmutableSet()));
         }
 
+        private Stream<Keyword> asKeyword(String flagName) {
+            try {
+                return Stream.of(new Keyword(flagName));
+            } catch (IllegalArgumentException e) {
+                LOGGER.warn("Fail to parse {} flag", flagName);
+                return Stream.of();
+            }
+        }
+
         public Optional<Keywords> fromMapOrOldKeyword(Optional<Map<String, Boolean>> mapKeyword, Optional<OldKeyword> oldKeyword) {
             Preconditions.checkArgument(!(mapKeyword.isPresent() && oldKeyword.isPresent()), "Does not support keyword and is* at the same time");
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/036096bb/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
index d1c0914..2e690ba 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageTest.java
@@ -32,6 +32,7 @@ import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Maps;
 
 public class MessageTest {
 
@@ -262,6 +263,48 @@ public class MessageTest {
     }
 
     @Test
+    public void buildShouldNotThrowWhenNonValidFlags() throws Exception {
+        Message.builder()
+            .id(TestMessageId.of(1))
+            .blobId(BlobId.of("blobId"))
+            .threadId("threadId")
+            .mailboxId(InMemoryId.of(456))
+            .headers(ImmutableMap.of("key", "value"))
+            .subject("subject")
+            .size(1)
+            .date(Instant.now())
+            .preview("preview")
+            .attachments(ImmutableList.of())
+            .flags(FlagsBuilder.builder()
+                    .add("@ert", "t^a", "op§")
+                    .build())
+            .build();
+    }
+
+    @Test
+    public void buildShouldIgnoreNonValidFlag() throws Exception {
+        Message message = Message.builder()
+            .id(TestMessageId.of(1))
+            .blobId(BlobId.of("blobId"))
+            .threadId("threadId")
+            .mailboxId(InMemoryId.of(456))
+            .headers(ImmutableMap.of("key", "value"))
+            .subject("subject")
+            .size(1)
+            .date(Instant.now())
+            .preview("preview")
+            .attachments(ImmutableList.of())
+            .flags(FlagsBuilder.builder()
+                    .add("$Draft", "@ert", "t^a", "op§", "$user_flag")
+                    .build())
+            .build();
+
+        assertThat(message.getKeywords()).containsOnly(
+                Maps.immutableEntry("$Draft", true), 
+                Maps.immutableEntry("$user_flag", true));
+    }
+
+    @Test
     public void hasAttachmentShouldReturnFalseWhenNoAttachment() throws Exception {
         Message message = Message.builder()
             .id(TestMessageId.of(1))


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


[3/6] james-project git commit: JAMES-2160 Following the JMAP specification, multi-valued fields should be separated by \n

Posted by ma...@apache.org.
JAMES-2160 Following the JMAP specification, multi-valued fields should be separated by \n


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

Branch: refs/heads/master
Commit: 4258cc6adbe78b14d8f5f963d47d73ac519c348e
Parents: 93cef1d
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Mon Sep 25 16:43:38 2017 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Sep 27 09:58:16 2017 +0200

----------------------------------------------------------------------
 .../integration/SetMessagesMethodTest.java      | 125 ++++++++++++++++---
 .../java/org/apache/james/jmap/JMAPServlet.java |   2 +
 .../jmap/methods/MIMEMessageConverter.java      |   8 +-
 .../apache/james/jmap/model/MessageFactory.java |   4 +-
 .../jmap/methods/MIMEMessageConverterTest.java  |  21 ++++
 .../james/jmap/model/MessageFactoryTest.java    |  49 ++++++++
 6 files changed, 187 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/4258cc6a/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 f22472b..0e2e40f 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
@@ -77,6 +77,7 @@ import org.apache.james.modules.MailboxProbeImpl;
 import org.apache.james.probe.DataProbe;
 import org.apache.james.util.ZeroedInputStream;
 import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.IMAPMessageReader;
 import org.apache.james.utils.JmapGuiceProbe;
 import org.apache.james.utils.MessageIdProbe;
 import org.apache.james.utils.SMTPMessageSender;
@@ -101,11 +102,13 @@ import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.builder.RequestSpecBuilder;
 import com.jayway.restassured.builder.ResponseSpecBuilder;
 import com.jayway.restassured.http.ContentType;
+import com.jayway.restassured.parsing.Parser;
 import com.jayway.restassured.specification.ResponseSpecification;
 
 public abstract class SetMessagesMethodTest {
     private static final String LOCALHOST_IP = "127.0.0.1";
     private static final int SMTP_PORT = 1025;
+    private static final int IMAP_PORT = 1143;
     private static final String FORWARDED = "$Forwarded";
     private static final int _1MB = 1024*1024;
     private static final String NAME = "[0][0]";
@@ -114,7 +117,8 @@ public abstract class SetMessagesMethodTest {
     private static final String SECOND_ARGUMENTS = "[1][1]";
     private static final String USERS_DOMAIN = "domain.tld";
     private static final String USERNAME = "username@" + USERS_DOMAIN;
-    public static final MailboxPath USER_MAILBOX = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
+    private static final String PASSWORD = "password";
+    private static final MailboxPath USER_MAILBOX = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox");
     private static final String NOT_UPDATED = ARGUMENTS + ".notUpdated";
 
     private ConditionFactory calmlyAwait;
@@ -146,12 +150,12 @@ public abstract class SetMessagesMethodTest {
                 .setPort(jmapServer.getProbe(JmapGuiceProbe.class).getJmapPort())
                 .build();
         RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
+        RestAssured.defaultParser = Parser.JSON;
 
-        String password = "password";
         dataProbe.addDomain(USERS_DOMAIN);
-        dataProbe.addUser(USERNAME, password);
+        dataProbe.addUser(USERNAME, PASSWORD);
         mailboxProbe.createMailbox("#private", USERNAME, DefaultMailboxes.INBOX);
-        accessToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), USERNAME, password);
+        accessToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), USERNAME, PASSWORD);
 
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, DefaultMailboxes.OUTBOX);
         mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, DefaultMailboxes.TRASH);
@@ -3433,23 +3437,23 @@ public abstract class SetMessagesMethodTest {
         String messageCreationId = "creationId1337";
         String fromAddress = USERNAME;
         String requestBody = "[" +
-            "  [" +
-            "    \"setMessages\","+
-            "    {" +
-            "      \"create\": { \"" + messageCreationId  + "\" : {" +
-            "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
-            "        \"to\": [{ \"name\": \"BOB\", \"email\": \"" + toUsername + "\"}]," +
-            "        \"headers\": { \"X-MY-SPECIAL-HEADER\": \"first header value\", \"OTHER-HEADER\": \"other value\"}," +
-            "        \"subject\": \"Thank you for joining example.com!\"," +
-            "        \"textBody\": \"Hello someone, and thank you for joining example.com!\"," +
-            "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
-            "      }}" +
-            "    }," +
-            "    \"#0\"" +
-            "  ]" +
-            "]";
+                "  [" +
+                "    \"setMessages\","+
+                "    {" +
+                "      \"create\": { \"" + messageCreationId  + "\" : {" +
+                "        \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," +
+                "        \"to\": [{ \"name\": \"BOB\", \"email\": \"" + toUsername + "\"}]," +
+                "        \"headers\": { \"X-MY-SPECIAL-HEADER\": \"first header value\", \"OTHER-HEADER\": \"other value\"}," +
+                "        \"subject\": \"Thank you for joining example.com!\"," +
+                "        \"textBody\": \"Hello someone, and thank you for joining example.com!\"," +
+                "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+                "      }}" +
+                "    }," +
+                "    \"#0\"" +
+                "  ]" +
+                "]";
 
-        given()
+        with()
             .header("Authorization", accessToken.serialize())
             .body(requestBody)
         .post("/jmap");
@@ -3475,6 +3479,87 @@ public abstract class SetMessagesMethodTest {
     }
 
     @Test
+    public void setMessagesShouldSetMultivaluedUserAddedHeaders() throws Exception {
+        String messageCreationId = "creationId1337";
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + USERNAME + "\"}," +
+            "        \"to\": [{ \"name\": \"Me\", \"email\": \"" + USERNAME + "\"}]," +
+            "        \"headers\": { \"X-MY-MULTIVALUATED-HEADER\": \"first value\nsecond value\"}," +
+            "        \"subject\": \"Thank you for joining example.com!\"," +
+            "        \"textBody\": \"Hello someone, and thank you for joining example.com!\"," +
+            "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        String messageId = given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        // When
+        .post("/jmap")
+        .then()
+            .extract()
+            .body()
+            .<String>path(ARGUMENTS + ".created."+ messageCreationId +".id");
+
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+
+        String message = ARGUMENTS + ".list[0]";
+
+        with()
+            .header("Authorization", accessToken.serialize())
+            .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, \"#0\"]]")
+        .when()
+            .post("/jmap")
+        .then()
+            .statusCode(200)
+            .log().ifValidationFails()
+            .body(NAME, equalTo("messages"))
+            .body(ARGUMENTS + ".list", hasSize(1))
+            .body(message + ".headers", hasEntry("X-MY-MULTIVALUATED-HEADER", "first value\nsecond value"));
+    }
+
+    @Test
+    public void setMessagesShouldRenderCorrectlyInIMAPMultivaluedUserAddedHeaders() throws Exception {
+        String messageCreationId = "creationId1337";
+        String requestBody = "[" +
+            "  [" +
+            "    \"setMessages\","+
+            "    {" +
+            "      \"create\": { \"" + messageCreationId  + "\" : {" +
+            "        \"from\": { \"name\": \"Me\", \"email\": \"" + USERNAME + "\"}," +
+            "        \"to\": [{ \"name\": \"Me\", \"email\": \"" + USERNAME + "\"}]," +
+            "        \"headers\": { \"X-MY-MULTIVALUATED-HEADER\": \"first value\nsecond value\"}," +
+            "        \"subject\": \"Thank you for joining example.com!\"," +
+            "        \"textBody\": \"Hello someone, and thank you for joining example.com!\"," +
+            "        \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" +
+            "      }}" +
+            "    }," +
+            "    \"#0\"" +
+            "  ]" +
+            "]";
+
+        given()
+            .header("Authorization", accessToken.serialize())
+            .body(requestBody)
+        .post("/jmap");
+
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+
+        try (IMAPMessageReader imapMessageReader = new IMAPMessageReader(LOCALHOST_IP, IMAP_PORT);) {
+            assertThat(imapMessageReader.readFirstMessageHeadersInInbox(USERNAME, PASSWORD))
+                .contains("X-MY-MULTIVALUATED-HEADER: first value")
+                .contains("X-MY-MULTIVALUATED-HEADER: second value");
+        }
+    }
+
+    @Test
     public void setMessagesShouldFilterComputedHeadersFromUserAddedHeaders() throws Exception {
         String messageCreationId = "creationId1337";
         String requestBody = "[" +

http://git-wip-us.apache.org/repos/asf/james-project/blob/4258cc6a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServlet.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServlet.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServlet.java
index 8ace83e..c1f1fea 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServlet.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/JMAPServlet.java
@@ -42,6 +42,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonParser.Feature;
 import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -62,6 +63,7 @@ public class JMAPServlet extends HttpServlet {
         this.requestHandler = requestHandler;
         this.metricFactory = metricFactory;
         this.objectMapper = new ObjectMapper();
+        objectMapper.configure(Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/james-project/blob/4258cc6a/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 c964c7d..cf6ce7e 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
@@ -32,6 +32,7 @@ import java.util.stream.Collectors;
 import org.apache.james.jmap.model.CreationMessage;
 import org.apache.james.jmap.model.CreationMessage.DraftEmailer;
 import org.apache.james.jmap.model.CreationMessageId;
+import org.apache.james.jmap.model.MessageFactory;
 import org.apache.james.mailbox.model.MessageAttachment;
 import org.apache.james.mime4j.Charsets;
 import org.apache.james.mime4j.codec.DecodeMonitor;
@@ -166,9 +167,14 @@ public class MIMEMessageConverter {
         newMessage.getHeaders().entrySet().stream()
             .filter(header -> ! header.getKey().trim().isEmpty())
             .filter(header -> ! LOWERCASED_COMPUTED_HEADERS.contains(header.getKey().toLowerCase(Locale.ENGLISH)))
-            .forEach(header -> addHeader(messageBuilder, header.getKey(), header.getValue()));
+            .forEach(header -> addMultivaluedHeader(messageBuilder, header.getKey(), header.getValue()));
     }
 
+    private void addMultivaluedHeader(Message.Builder messageBuilder, String fieldName, String multipleValues) {
+        Splitter.on(MessageFactory.JMAP_MULTIVALUED_FIELD_DELIMITER).split(multipleValues)
+            .forEach(value -> addHeader(messageBuilder, fieldName, value));
+    }
+    
     private void addHeader(Message.Builder messageBuilder, String fieldName, String value) {
         FieldParser<UnstructuredField> parser = UnstructuredFieldImpl.PARSER;
         RawField rawField = new RawField(fieldName, value);

http://git-wip-us.apache.org/repos/asf/james-project/blob/4258cc6a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
index 236be87..05f2589 100644
--- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
+++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageFactory.java
@@ -63,6 +63,8 @@ import com.google.common.collect.Sets;
 
 public class MessageFactory {
 
+    public static final String JMAP_MULTIVALUED_FIELD_DELIMITER = "\n";
+
     private static final MimeConfig MIME_ENTITY_CONFIG = MimeConfig.custom()
         .setMaxContentLen(-1)
         .setMaxHeaderCount(-1)
@@ -196,7 +198,7 @@ public class MessageFactory {
                 .map(MimeUtil::unscrambleHeaderValue)
                 .collect(Collectors.toList())
                 .stream()
-                .collect(Collectors.joining(","));
+                .collect(Collectors.joining(JMAP_MULTIVALUED_FIELD_DELIMITER));
         return Multimaps.index(fields, Field::getName)
                 .asMap()
                 .entrySet()

http://git-wip-us.apache.org/repos/asf/james-project/blob/4258cc6a/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 9e9a2cf..167408b 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
@@ -169,6 +169,27 @@ public class MIMEMessageConverterTest {
     }
 
     @Test
+    public void convertToMimeShouldAddMultivaluedHeadersWhenProvided() {
+        // Given
+        MIMEMessageConverter sut = new MIMEMessageConverter();
+
+        CreationMessage messageHavingInReplyTo = CreationMessage.builder()
+                .from(DraftEmailer.builder().name("sender").build())
+                .headers(ImmutableMap.of("FIRST", "first value\nsecond value"))
+                .mailboxIds(ImmutableList.of("dead-beef-1337"))
+                .subject("subject")
+                .build();
+
+        // When
+        Message result = sut.convertToMime(new ValueWithId.CreationMessageEntry(
+                CreationMessageId.of("user|mailbox|1"), messageHavingInReplyTo), ImmutableList.of());
+
+        // Then
+        assertThat(result.getHeader().getFields("FIRST")).extracting(Field::getBody)
+            .containsOnly("first value", "second value");
+    }
+
+    @Test
     public void convertToMimeShouldFilterEmptyHeaderNames() {
         // Given
         MIMEMessageConverter sut = new MIMEMessageConverter();

http://git-wip-us.apache.org/repos/asf/james-project/blob/4258cc6a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
index 2d86294..24b0a1e 100644
--- a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
+++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/MessageFactoryTest.java
@@ -233,6 +233,55 @@ public class MessageFactoryTest {
     }
 
     @Test
+    public void multivaluedHeadersShouldBeSeparatedByLineFeed() throws Exception {
+        Flags flags = new Flags(Flag.SEEN);
+        String headers = "From: user <us...@domain>\n"
+            + "Subject: test subject\n"
+            + "Multi-header: first value\n"
+            + "To: user1 <us...@domain>\n"
+            + "Multi-header: second value\n";
+        MetaDataWithContent testMail = MetaDataWithContent.builder()
+            .uid(MessageUid.of(2))
+            .flags(flags)
+            .size(headers.length())
+            .internalDate(INTERNAL_DATE)
+            .content(new ByteArrayInputStream(headers.getBytes(Charsets.UTF_8)))
+            .attachments(ImmutableList.of())
+            .mailboxId(MAILBOX_ID)
+            .messageId(TestMessageId.of(2))
+            .build();
+
+        Emailer user = Emailer.builder().name("user").email("user@domain").build();
+        Emailer user1 = Emailer.builder().name("user1").email("user1@domain").build();
+        ImmutableMap<String, String> headersMap = ImmutableMap.<String, String>builder()
+            .put("From", "user <us...@domain>")
+            .put("Subject", "test subject")
+            .put("Multi-header", "first value\nsecond value")
+            .put("To", "user1 <us...@domain>")
+            .put("MIME-Version", "1.0")
+            .build();
+        Message testee = messageFactory.fromMetaDataWithContent(testMail);
+        Message expected = Message.builder()
+            .id(TestMessageId.of(2))
+            .blobId(BlobId.of("blobId"))
+            .threadId("2")
+            .mailboxId(MAILBOX_ID)
+            .headers(headersMap)
+            .from(user)
+            .to(ImmutableList.of(user1))
+            .subject("test subject")
+            .date(Instant.parse("2012-02-03T14:30:42.000Z"))
+            .size(headers.length())
+            .preview("(Empty)")
+            .textBody(Optional.of(""))
+            .htmlBody(Optional.empty())
+            .flags(flags)
+            .build();
+
+        assertThat(testee).isEqualToComparingFieldByField(expected);
+    }
+
+    @Test
     public void textBodyShouldBeSetIntoMessage() throws Exception {
         String headers = "Subject: test subject\n";
         String body = "Mail body";


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


[6/6] james-project git commit: Merge remote-tracking branch 'linagora/pr/988'

Posted by ma...@apache.org.
Merge remote-tracking branch 'linagora/pr/988'


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

Branch: refs/heads/master
Commit: 4c3e0403c860beab9ace2df0e212375d9592011d
Parents: 28282fe 036096b
Author: Matthieu Baechler <ma...@apache.org>
Authored: Wed Sep 27 09:59:31 2017 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Sep 27 09:59:31 2017 +0200

----------------------------------------------------------------------
 .../org/apache/james/jmap/model/Keyword.java    |  6 ++-
 .../org/apache/james/jmap/model/Keywords.java   | 16 +++++++-
 .../apache/james/jmap/model/KeywordTest.java    | 14 ++++++-
 .../apache/james/jmap/model/MessageTest.java    | 43 ++++++++++++++++++++
 4 files changed, 75 insertions(+), 4 deletions(-)
----------------------------------------------------------------------



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


[5/6] james-project git commit: JAMES-2160 Indent: no space between two open parenthesis

Posted by ma...@apache.org.
JAMES-2160 Indent: no space between two open parenthesis


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

Branch: refs/heads/master
Commit: 28282fe0b89d2f924f144c62e06c75ab878f8ae3
Parents: 4258cc6
Author: Raphael Ouazana <ra...@linagora.com>
Authored: Tue Sep 26 14:23:32 2017 +0200
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Wed Sep 27 09:58:16 2017 +0200

----------------------------------------------------------------------
 .../james/jmap/VacationIntegrationTest.java     |  6 +--
 .../integration/SetMessagesMethodTest.java      | 48 ++++++++++----------
 2 files changed, 27 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/28282fe0/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java
index 7b37044..de160b9 100644
--- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java
+++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java
@@ -151,7 +151,7 @@ public abstract class VacationIntegrationTest {
             .until(() -> isTextMessageReceived(user1AccessToken, getInboxId(user1AccessToken), ORIGINAL_MESSAGE_TEXT_BODY, USER_2, USER_1));
         // User 2 should well receive a notification about user 1 vacation
         calmlyAwait.atMost(30, TimeUnit.SECONDS)
-            .until( () -> isTextMessageReceived(user2AccessToken, getInboxId(user2AccessToken), REASON, USER_1, USER_2));
+            .until(() -> isTextMessageReceived(user2AccessToken, getInboxId(user2AccessToken), REASON, USER_1, USER_2));
     }
 
     @Test
@@ -175,7 +175,7 @@ public abstract class VacationIntegrationTest {
             .until(() -> isTextMessageReceived(user1AccessToken, getInboxId(user1AccessToken), ORIGINAL_MESSAGE_TEXT_BODY, USER_2, USER_1));
         // User 2 should well receive a notification about user 1 vacation
         calmlyAwait.atMost(30, TimeUnit.SECONDS)
-            .until( () -> isTextMessageReceived(user2AccessToken, getInboxId(user2AccessToken), "", USER_1, USER_2));
+            .until(() -> isTextMessageReceived(user2AccessToken, getInboxId(user2AccessToken), "", USER_1, USER_2));
     }
 
     @Test
@@ -193,7 +193,7 @@ public abstract class VacationIntegrationTest {
         calmlyAwait.atMost(10, TimeUnit.SECONDS)
             .until(() -> isTextMessageReceived(user1AccessToken, getInboxId(user1AccessToken), ORIGINAL_MESSAGE_TEXT_BODY, USER_2, USER_1));
         calmlyAwait.atMost(10, TimeUnit.SECONDS)
-                .until( () -> assertOneMessageWithHtmlBodyReceived(user2AccessToken, getInboxId(user2AccessToken), HTML_REASON, USER_1, USER_2));
+                .until(() -> assertOneMessageWithHtmlBodyReceived(user2AccessToken, getInboxId(user2AccessToken), HTML_REASON, USER_1, USER_2));
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/james-project/blob/28282fe0/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 0e2e40f..06e2cec 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
@@ -1367,7 +1367,7 @@ public abstract class SetMessagesMethodTest {
             .post("/jmap");
 
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> messageHasBeenMovedToSentBox(sentMailboxId));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> messageHasBeenMovedToSentBox(sentMailboxId));
     }
 
     private boolean messageHasBeenMovedToSentBox(String sentMailboxId) {
@@ -1565,7 +1565,7 @@ public abstract class SetMessagesMethodTest {
         .when()
             .post("/jmap");
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> messageHasBeenMovedToSentBox(sentMailboxId));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> messageHasBeenMovedToSentBox(sentMailboxId));
     }
 
     @Test
@@ -1676,7 +1676,7 @@ public abstract class SetMessagesMethodTest {
             .post("/jmap");
 
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInRecipientsMailboxes(recipientToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInRecipientsMailboxes(recipientToken));
     }
 
     @Test
@@ -1720,7 +1720,7 @@ public abstract class SetMessagesMethodTest {
             .post("/jmap");
 
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInRecipientsMailboxes(recipientToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInRecipientsMailboxes(recipientToken));
         with()
             .header("Authorization", recipientToken.serialize())
             .body("[[\"getMessageList\", {\"fetchMessages\": true, \"fetchMessageProperties\": [\"bcc\"] }, \"#0\"]]")
@@ -1775,7 +1775,7 @@ public abstract class SetMessagesMethodTest {
             .post("/jmap");
 
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> messageHasBeenMovedToSentBox(sentMailboxId));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> messageHasBeenMovedToSentBox(sentMailboxId));
         with()
             .header("Authorization", this.accessToken.serialize())
             .body("[[\"getMessageList\", {\"fetchMessages\":true, \"fetchMessageProperties\": [\"bcc\"], \"filter\":{\"inMailboxes\":[\"" + sentMailboxId + "\"]}}, \"#0\"]]")
@@ -1834,7 +1834,7 @@ public abstract class SetMessagesMethodTest {
             .post("/jmap");
 
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInRecipientsMailboxes(bccToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInRecipientsMailboxes(bccToken));
         with()
             .header("Authorization", bccToken.serialize())
             .body("[[\"getMessageList\", {\"fetchMessages\": true, \"fetchMessageProperties\": [\"bcc\"] }, \"#0\"]]")
@@ -1904,7 +1904,7 @@ public abstract class SetMessagesMethodTest {
             .post("/jmap");
 
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isHtmlMessageReceived(recipientToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isHtmlMessageReceived(recipientToken));
     }
 
 
@@ -2053,7 +2053,7 @@ public abstract class SetMessagesMethodTest {
             .post("/jmap");
 
         // Then
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isTextPlusHtmlMessageReceived(recipientToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isTextPlusHtmlMessageReceived(recipientToken));
     }
 
     private boolean isTextPlusHtmlMessageReceived(AccessToken recipientToken) {
@@ -2827,7 +2827,7 @@ public abstract class SetMessagesMethodTest {
         .when()
             .post("/jmap").then();
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String message = ARGUMENTS + ".list[0]";
         String firstAttachment = message + ".attachments[0]";
@@ -2923,7 +2923,7 @@ public abstract class SetMessagesMethodTest {
             .body(requestBody)
         .post("/jmap");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String inboxId = getMailboxId(accessToken, Role.INBOX);
         String receivedMessageId =
@@ -2995,7 +2995,7 @@ public abstract class SetMessagesMethodTest {
         .when()
             .post("/jmap");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String inboxId = getMailboxId(accessToken, Role.INBOX);
         String receivedMessageId =
@@ -3087,7 +3087,7 @@ public abstract class SetMessagesMethodTest {
         .when()
             .post("/jmap");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String inboxId = getMailboxId(accessToken, Role.INBOX);
         String receivedMessageId =
@@ -3160,7 +3160,7 @@ public abstract class SetMessagesMethodTest {
         .when()
             .post("/jmap");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String inboxId = getMailboxId(accessToken, Role.INBOX);
         String receivedMessageId =
@@ -3229,7 +3229,7 @@ public abstract class SetMessagesMethodTest {
         .when()
             .post("/jmap");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String inboxId = getMailboxId(accessToken, Role.INBOX);
         String receivedMessageId =
@@ -3293,7 +3293,7 @@ public abstract class SetMessagesMethodTest {
         accessToken = HttpJmapAuthentication.authenticateJamesUser(baseUri(), toUsername, password);
         String inboxMailboxId = getMailboxId(accessToken, Role.INBOX);
 
-        calmlyAwait.atMost(60, TimeUnit.SECONDS).until( () -> messageInMailboxHasHeaders(inboxMailboxId, buildExpectedHeaders()));
+        calmlyAwait.atMost(60, TimeUnit.SECONDS).until(() -> messageInMailboxHasHeaders(inboxMailboxId, buildExpectedHeaders()));
 
     }
 
@@ -3329,7 +3329,7 @@ public abstract class SetMessagesMethodTest {
 
         String sentMailboxId = getMailboxId(accessToken, Role.SENT);
 
-        calmlyAwait.atMost(60, TimeUnit.SECONDS).until( () -> messageInMailboxHasHeaders(sentMailboxId, buildExpectedHeaders()));
+        calmlyAwait.atMost(60, TimeUnit.SECONDS).until(() -> messageInMailboxHasHeaders(sentMailboxId, buildExpectedHeaders()));
 
     }
 
@@ -3408,7 +3408,7 @@ public abstract class SetMessagesMethodTest {
             .body()
             .<String>path(ARGUMENTS + ".created."+ messageCreationId +".id");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String message = ARGUMENTS + ".list[0]";
 
@@ -3460,7 +3460,7 @@ public abstract class SetMessagesMethodTest {
 
         String sentMailboxId = getMailboxId(accessToken, Role.SENT);
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> messageHasBeenMovedToSentBox(sentMailboxId));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> messageHasBeenMovedToSentBox(sentMailboxId));
 
         String message = SECOND_ARGUMENTS + ".list[0]";
         with()
@@ -3508,7 +3508,7 @@ public abstract class SetMessagesMethodTest {
             .body()
             .<String>path(ARGUMENTS + ".created."+ messageCreationId +".id");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String message = ARGUMENTS + ".list[0]";
 
@@ -3550,7 +3550,7 @@ public abstract class SetMessagesMethodTest {
             .body(requestBody)
         .post("/jmap");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         try (IMAPMessageReader imapMessageReader = new IMAPMessageReader(LOCALHOST_IP, IMAP_PORT);) {
             assertThat(imapMessageReader.readFirstMessageHeadersInInbox(USERNAME, PASSWORD))
@@ -3589,7 +3589,7 @@ public abstract class SetMessagesMethodTest {
             .body()
             .<String>path(ARGUMENTS + ".created."+ messageCreationId +".id");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String message = ARGUMENTS + ".list[0]";
 
@@ -3705,7 +3705,7 @@ public abstract class SetMessagesMethodTest {
             .body()
             .<String>path(ARGUMENTS + ".created."+ messageCreationId +".id");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String message = ARGUMENTS + ".list[0]";
 
@@ -3765,7 +3765,7 @@ public abstract class SetMessagesMethodTest {
             .body()
             .<String>path(ARGUMENTS + ".created."+ messageCreationId +".id");
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         given()
             .header("Authorization", accessToken.serialize())
@@ -3949,7 +3949,7 @@ public abstract class SetMessagesMethodTest {
             calmlyAwait.atMost(Duration.ONE_MINUTE).until(messageSender::messageHasBeenSent);
         }
 
-        calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken));
+        calmlyAwait.atMost(30, TimeUnit.SECONDS).until(() -> isAnyMessageFoundInInbox(accessToken));
 
         String message = ARGUMENTS + ".list[0]";
         String firstAttachment = message + ".attachments[0]";


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