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 rc...@apache.org on 2019/11/25 09:06:54 UTC
[james-project] 11/22: JAMES-2987 Add MessageHeaderViewFactory
This is an automated email from the ASF dual-hosted git repository.
rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit d1a8c287a7c6264afeeaa12c336d4d5e342b30b0
Author: Rene Cordier <rc...@linagora.com>
AuthorDate: Thu Nov 21 17:45:56 2019 +0700
JAMES-2987 Add MessageHeaderViewFactory
---
.../jmap/draft/methods/MIMEMessageConverter.java | 4 +-
.../model/message/view/MessageFullViewFactory.java | 86 +------------
.../model/message/view/MessageHeaderView.java | 2 +-
.../message/view/MessageHeaderViewFactory.java | 94 ++++++++++++++
.../model/message/view/MessageViewFactory.java | 72 +++++++++++
.../message/view/MessageHeaderViewFactoryTest.java | 141 +++++++++++++++++++++
.../jmap-draft/src/test/resources/fullMessage.eml | 60 +++++++++
7 files changed, 376 insertions(+), 83 deletions(-)
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MIMEMessageConverter.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MIMEMessageConverter.java
index c9e3dcd..eac8c13 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MIMEMessageConverter.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/MIMEMessageConverter.java
@@ -31,7 +31,7 @@ import java.util.stream.Collectors;
import org.apache.james.jmap.draft.model.CreationMessage;
import org.apache.james.jmap.draft.model.CreationMessage.DraftEmailer;
-import org.apache.james.jmap.draft.model.message.view.MessageFullViewFactory;
+import org.apache.james.jmap.draft.model.message.view.MessageViewFactory;
import org.apache.james.mailbox.model.MessageAttachment;
import org.apache.james.mime4j.codec.DecodeMonitor;
import org.apache.james.mime4j.codec.EncoderUtil;
@@ -176,7 +176,7 @@ public class MIMEMessageConverter {
}
private void addMultivaluedHeader(Message.Builder messageBuilder, String fieldName, String multipleValues) {
- Splitter.on(MessageFullViewFactory.JMAP_MULTIVALUED_FIELD_DELIMITER).split(multipleValues)
+ Splitter.on(MessageViewFactory.JMAP_MULTIVALUED_FIELD_DELIMITER).split(multipleValues)
.forEach(value -> addHeader(messageBuilder, fieldName, value));
}
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java
index ebef606..dec75d8 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageFullViewFactory.java
@@ -24,19 +24,14 @@ import java.time.Instant;
import java.util.Collection;
import java.util.Date;
import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.mail.internet.SharedInputStream;
import org.apache.james.jmap.draft.model.Attachment;
import org.apache.james.jmap.draft.model.BlobId;
-import org.apache.james.jmap.draft.model.Emailer;
import org.apache.james.jmap.draft.model.Keywords;
import org.apache.james.jmap.draft.model.MessagePreviewGenerator;
import org.apache.james.jmap.draft.utils.HtmlTextExtractor;
@@ -48,31 +43,21 @@ import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MessageAttachment;
import org.apache.james.mailbox.model.MessageId;
import org.apache.james.mailbox.model.MessageResult;
-import org.apache.james.mime4j.dom.address.AddressList;
-import org.apache.james.mime4j.dom.address.Mailbox;
-import org.apache.james.mime4j.dom.address.MailboxList;
-import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.dom.Message;
import org.apache.james.mime4j.stream.MimeConfig;
-import org.apache.james.mime4j.util.MimeUtil;
import org.apache.james.util.mime.MessageContentExtractor;
import org.apache.james.util.mime.MessageContentExtractor.MessageContent;
import com.github.steveash.guavate.Guavate;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Multimaps;
import com.google.common.collect.Sets;
public class MessageFullViewFactory implements MessageViewFactory<MessageFullView> {
- public static final String JMAP_MULTIVALUED_FIELD_DELIMITER = "\n";
-
private final BlobManager blobManager;
private final MessagePreviewGenerator messagePreview;
private final MessageContentExtractor messageContentExtractor;
private final HtmlTextExtractor htmlTextExtractor;
- private final Keywords.KeywordsFactory keywordsFactory;
@Inject
public MessageFullViewFactory(BlobManager blobManager, MessagePreviewGenerator messagePreview, MessageContentExtractor messageContentExtractor,
@@ -81,7 +66,6 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie
this.messagePreview = messagePreview;
this.messageContentExtractor = messageContentExtractor;
this.htmlTextExtractor = htmlTextExtractor;
- this.keywordsFactory = Keywords.lenientFactory();
}
@Override
@@ -90,7 +74,7 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie
}
public MessageFullView fromMetaDataWithContent(MetaDataWithContent message) throws MailboxException {
- org.apache.james.mime4j.dom.Message mimeMessage = parse(message);
+ Message mimeMessage = parse(message);
MessageContent messageContent = extractContent(mimeMessage);
Optional<String> htmlBody = messageContent.getHtmlBody();
Optional<String> mainTextContent = mainTextContent(messageContent);
@@ -133,7 +117,7 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie
.build();
}
- private Instant getDateFromHeaderOrInternalDateOtherwise(org.apache.james.mime4j.dom.Message mimeMessage, MetaDataWithContent message) {
+ private Instant getDateFromHeaderOrInternalDateOtherwise(Message mimeMessage, MetaDataWithContent message) {
return Optional.ofNullable(mimeMessage.getDate())
.map(Date::toInstant)
.orElse(message.getInternalDate());
@@ -153,9 +137,9 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie
.orElse(messageContent.getTextBody());
}
- private org.apache.james.mime4j.dom.Message parse(MetaDataWithContent message) throws MailboxException {
+ private Message parse(MetaDataWithContent message) throws MailboxException {
try {
- return org.apache.james.mime4j.dom.Message.Builder
+ return Message.Builder
.of()
.use(MimeConfig.PERMISSIVE)
.parse(message.getContent())
@@ -165,71 +149,13 @@ public class MessageFullViewFactory implements MessageViewFactory<MessageFullVie
}
}
- private MessageContent extractContent(org.apache.james.mime4j.dom.Message mimeMessage) throws MailboxException {
+ private MessageContent extractContent(Message mimeMessage) throws MailboxException {
try {
return messageContentExtractor.extract(mimeMessage);
} catch (IOException e) {
throw new MailboxException("Unable to extract content: " + e.getMessage(), e);
}
}
-
- private Emailer firstFromMailboxList(MailboxList list) {
- if (list == null) {
- return null;
- }
- return list.stream()
- .map(this::fromMailbox)
- .findFirst()
- .orElse(null);
- }
-
- private ImmutableList<Emailer> fromAddressList(AddressList list) {
- if (list == null) {
- return ImmutableList.of();
- }
- return list.flatten()
- .stream()
- .map(this::fromMailbox)
- .collect(Guavate.toImmutableList());
- }
-
- private Emailer fromMailbox(Mailbox mailbox) {
- return Emailer.builder()
- .name(getNameOrAddress(mailbox))
- .email(mailbox.getAddress())
- .allowInvalid()
- .build();
- }
-
- private String getNameOrAddress(Mailbox mailbox) {
- if (mailbox.getName() != null) {
- return mailbox.getName();
- }
- return mailbox.getAddress();
- }
-
- private ImmutableMap<String, String> toMap(List<Field> fields) {
- Function<Entry<String, Collection<Field>>, String> bodyConcatenator = fieldListEntry -> fieldListEntry.getValue()
- .stream()
- .map(Field::getBody)
- .map(MimeUtil::unscrambleHeaderValue)
- .collect(Collectors.toList())
- .stream()
- .collect(Collectors.joining(JMAP_MULTIVALUED_FIELD_DELIMITER));
- return Multimaps.index(fields, Field::getName)
- .asMap()
- .entrySet()
- .stream()
- .collect(Guavate.toImmutableMap(Map.Entry::getKey, bodyConcatenator));
- }
-
- private String getHeader(org.apache.james.mime4j.dom.Message message, String header) {
- Field field = message.getHeader().getField(header);
- if (field == null) {
- return null;
- }
- return field.getBody();
- }
private List<Attachment> getAttachments(List<MessageAttachment> attachments) {
return attachments.stream()
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java
index abb3a31..9ad4610 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderView.java
@@ -39,7 +39,7 @@ import com.google.common.collect.ImmutableMap;
public class MessageHeaderView extends MessageMetadataView {
- public static Builder messageHeaderBuilder() {
+ public static MessageHeaderView.Builder<? extends MessageHeaderView.Builder> messageHeaderBuilder() {
return new Builder();
}
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactory.java
new file mode 100644
index 0000000..6995b44
--- /dev/null
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactory.java
@@ -0,0 +1,94 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.draft.model.message.view;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.apache.james.jmap.draft.model.BlobId;
+import org.apache.james.mailbox.BlobManager;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageResult;
+import org.apache.james.mime4j.dom.Message;
+import org.apache.james.mime4j.stream.MimeConfig;
+
+import com.google.common.base.Strings;
+
+public class MessageHeaderViewFactory implements MessageViewFactory<MessageHeaderView> {
+ private final BlobManager blobManager;
+
+ @Inject
+ MessageHeaderViewFactory(BlobManager blobManager) {
+ this.blobManager = blobManager;
+ }
+
+ @Override
+ public MessageHeaderView fromMessageResults(Collection<MessageResult> messageResults) throws MailboxException {
+ assertOneMessageId(messageResults);
+
+ MessageResult firstMessageResult = messageResults.iterator().next();
+ List<MailboxId> mailboxIds = getMailboxIds(messageResults);
+
+ Message mimeMessage = parse(firstMessageResult);
+
+ return MessageHeaderView.messageHeaderBuilder()
+ .id(firstMessageResult.getMessageId())
+ .mailboxIds(mailboxIds)
+ .blobId(BlobId.of(blobManager.toBlobId(firstMessageResult.getMessageId())))
+ .threadId(firstMessageResult.getMessageId().serialize())
+ .keywords(getKeywords(messageResults))
+ .size(firstMessageResult.getSize())
+ .inReplyToMessageId(getHeader(mimeMessage, "in-reply-to"))
+ .subject(Strings.nullToEmpty(mimeMessage.getSubject()).trim())
+ .headers(toMap(mimeMessage.getHeader().getFields()))
+ .from(firstFromMailboxList(mimeMessage.getFrom()))
+ .to(fromAddressList(mimeMessage.getTo()))
+ .cc(fromAddressList(mimeMessage.getCc()))
+ .bcc(fromAddressList(mimeMessage.getBcc()))
+ .replyTo(fromAddressList(mimeMessage.getReplyTo()))
+ .date(getDateFromHeaderOrInternalDateOtherwise(mimeMessage, firstMessageResult))
+ .build();
+ }
+
+ private Message parse(MessageResult message) throws MailboxException {
+ try {
+ return Message.Builder
+ .of()
+ .use(MimeConfig.PERMISSIVE)
+ .parse(message.getFullContent().getInputStream())
+ .build();
+ } catch (IOException e) {
+ throw new MailboxException("Unable to parse message: " + e.getMessage(), e);
+ }
+ }
+
+ private Instant getDateFromHeaderOrInternalDateOtherwise(Message mimeMessage, MessageResult message) {
+ return Optional.ofNullable(mimeMessage.getDate())
+ .map(Date::toInstant)
+ .orElse(message.getInternalDate().toInstant());
+ }
+}
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java
index 5339c13..4afb117 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/model/message/view/MessageViewFactory.java
@@ -21,19 +21,32 @@ package org.apache.james.jmap.draft.model.message.view;
import java.util.Collection;
import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import org.apache.james.jmap.draft.model.Emailer;
import org.apache.james.jmap.draft.model.Keywords;
import org.apache.james.jmap.draft.utils.KeywordsCombiner;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MessageResult;
+import org.apache.james.mime4j.dom.address.AddressList;
+import org.apache.james.mime4j.dom.address.Mailbox;
+import org.apache.james.mime4j.dom.address.MailboxList;
+import org.apache.james.mime4j.stream.Field;
+import org.apache.james.mime4j.util.MimeUtil;
import com.github.steveash.guavate.Guavate;
import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Multimaps;
public interface MessageViewFactory<T extends MessageView> {
KeywordsCombiner KEYWORDS_COMBINER = new KeywordsCombiner();
Keywords.KeywordsFactory KEYWORDS_FACTORY = Keywords.lenientFactory();
+ String JMAP_MULTIVALUED_FIELD_DELIMITER = "\n";
T fromMessageResults(Collection<MessageResult> messageResults) throws MailboxException;
@@ -64,4 +77,63 @@ public interface MessageViewFactory<T extends MessageView> {
.reduce(KEYWORDS_COMBINER)
.get();
}
+
+ default String getHeader(org.apache.james.mime4j.dom.Message message, String header) {
+ Field field = message.getHeader().getField(header);
+ if (field == null) {
+ return null;
+ }
+ return field.getBody();
+ }
+
+ default ImmutableMap<String, String> toMap(List<Field> fields) {
+ Function<Map.Entry<String, Collection<Field>>, String> bodyConcatenator = fieldListEntry -> fieldListEntry.getValue()
+ .stream()
+ .map(Field::getBody)
+ .map(MimeUtil::unscrambleHeaderValue)
+ .collect(Collectors.toList())
+ .stream()
+ .collect(Collectors.joining(JMAP_MULTIVALUED_FIELD_DELIMITER));
+
+ return Multimaps.index(fields, Field::getName)
+ .asMap()
+ .entrySet()
+ .stream()
+ .collect(Guavate.toImmutableMap(Map.Entry::getKey, bodyConcatenator));
+ }
+
+ default Emailer firstFromMailboxList(MailboxList list) {
+ if (list == null) {
+ return null;
+ }
+ return list.stream()
+ .map(this::fromMailbox)
+ .findFirst()
+ .orElse(null);
+ }
+
+ default Emailer fromMailbox(Mailbox mailbox) {
+ return Emailer.builder()
+ .name(getNameOrAddress(mailbox))
+ .email(mailbox.getAddress())
+ .allowInvalid()
+ .build();
+ }
+
+ default String getNameOrAddress(Mailbox mailbox) {
+ if (mailbox.getName() != null) {
+ return mailbox.getName();
+ }
+ return mailbox.getAddress();
+ }
+
+ default ImmutableList<Emailer> fromAddressList(AddressList list) {
+ if (list == null) {
+ return ImmutableList.of();
+ }
+ return list.flatten()
+ .stream()
+ .map(this::fromMailbox)
+ .collect(Guavate.toImmutableList());
+ }
}
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactoryTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactoryTest.java
new file mode 100644
index 0000000..a60c17f
--- /dev/null
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/model/message/view/MessageHeaderViewFactoryTest.java
@@ -0,0 +1,141 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one *
+ * or more contributor license agreements. See the NOTICE file *
+ * distributed with this work for additional information *
+ * regarding copyright ownership. The ASF licenses this file *
+ * to you under the Apache License, Version 2.0 (the *
+ * "License"); you may not use this file except in compliance *
+ * with the License. You may obtain a copy of the License at *
+ * *
+ * http://www.apache.org/licenses/LICENSE-2.0 *
+ * *
+ * Unless required by applicable law or agreed to in writing, *
+ * software distributed under the License is distributed on an *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
+ * KIND, either express or implied. See the License for the *
+ * specific language governing permissions and limitations *
+ * under the License. *
+ ****************************************************************/
+
+package org.apache.james.jmap.draft.model.message.view;
+
+import java.util.List;
+import java.util.Optional;
+
+import javax.mail.Flags;
+
+import org.apache.james.core.Username;
+import org.apache.james.jmap.draft.model.BlobId;
+import org.apache.james.jmap.draft.model.Emailer;
+import org.apache.james.jmap.draft.model.Keyword;
+import org.apache.james.jmap.draft.model.Keywords;
+import org.apache.james.jmap.draft.model.Number;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageIdManager;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.FetchGroupImpl;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.model.MessageResult;
+import org.apache.james.util.ClassLoaderUtils;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+class MessageHeaderViewFactoryTest {
+ private static final Username BOB = Username.of("bob@local");
+
+ private MessageIdManager messageIdManager;
+ private MessageHeaderViewFactory testee;
+ private MailboxSession session;
+ private MessageManager bobInbox;
+ private MessageManager bobMailbox;
+ private ComposedMessageId message1;
+
+ @BeforeEach
+ void setUp() throws Exception {
+ InMemoryIntegrationResources resources = InMemoryIntegrationResources.defaultResources();
+ messageIdManager = resources.getMessageIdManager();
+ InMemoryMailboxManager mailboxManager = resources.getMailboxManager();
+
+ session = mailboxManager.createSystemSession(BOB);
+ MailboxId bobInboxId = mailboxManager.createMailbox(MailboxPath.inbox(session), session).get();
+ MailboxId bobMailboxId = mailboxManager.createMailbox(MailboxPath.forUser(BOB, "anotherMailbox"), session).get();
+
+ bobInbox = mailboxManager.getMailbox(bobInboxId, session);
+ bobMailbox = mailboxManager.getMailbox(bobMailboxId, session);
+
+ message1 = bobInbox.appendMessage(MessageManager.AppendCommand.builder()
+ .withFlags(new Flags(Flags.Flag.SEEN))
+ .build(ClassLoaderUtils.getSystemResourceAsSharedStream("fullMessage.eml")),
+ session);
+
+ testee = new MessageHeaderViewFactory(resources.getBlobManager());
+ }
+
+ @Test
+ void fromMessageResultsShouldReturnCorrectView() throws Exception {
+ List<MessageResult> messages = messageIdManager
+ .getMessages(ImmutableList.of(message1.getMessageId()), FetchGroupImpl.MINIMAL, session);
+
+ Emailer bobEmail = Emailer.builder().name(BOB.getLocalPart()).email(BOB.asString()).build();
+ Emailer aliceEmail = Emailer.builder().name("alice").email("alice@local").build();
+ Emailer jackEmail = Emailer.builder().name("jack").email("jack@local").build();
+ Emailer jacobEmail = Emailer.builder().name("jacob").email("jacob@local").build();
+
+ ImmutableMap<String, String> headersMap = ImmutableMap.<String, String>builder()
+ .put("Content-Type", "multipart/mixed; boundary=\"------------7AF1D14DE1DFA16229726B54\"")
+ .put("Date", "Tue, 7 Jun 2016 16:23:37 +0200")
+ .put("From", "alice <al...@local>")
+ .put("To", "bob <bo...@local>")
+ .put("Subject", "Full message")
+ .put("Mime-Version", "1.0")
+ .put("Message-ID", "<1c...@open-paas.org>")
+ .put("Cc", "jack <ja...@local>, jacob <ja...@local>")
+ .put("Bcc", "alice <al...@local>")
+ .put("Reply-to", "alice <al...@local>")
+ .put("In-reply-to", "bob@local")
+ .build();
+
+ MessageHeaderView actual = testee.fromMessageResults(messages);
+ SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(actual.getId()).isEqualTo(message1.getMessageId());
+ softly.assertThat(actual.getMailboxIds()).containsExactly(bobInbox.getId());
+ softly.assertThat(actual.getThreadId()).isEqualTo(message1.getMessageId().serialize());
+ softly.assertThat(actual.getSize()).isEqualTo(Number.fromLong(2255));
+ softly.assertThat(actual.getKeywords()).isEqualTo(Keywords.strictFactory().from(Keyword.SEEN).asMap());
+ softly.assertThat(actual.getBlobId()).isEqualTo(BlobId.of(message1.getMessageId().serialize()));
+ softly.assertThat(actual.getInReplyToMessageId()).isEqualTo(Optional.of(BOB.asString()));
+ softly.assertThat(actual.getHeaders()).isEqualTo(headersMap);
+ softly.assertThat(actual.getFrom()).isEqualTo(Optional.of(aliceEmail));
+ softly.assertThat(actual.getTo()).isEqualTo(ImmutableList.of(bobEmail));
+ softly.assertThat(actual.getCc()).isEqualTo(ImmutableList.of(jackEmail, jacobEmail));
+ softly.assertThat(actual.getBcc()).isEqualTo(ImmutableList.of(aliceEmail));
+ softly.assertThat(actual.getReplyTo()).isEqualTo(ImmutableList.of(aliceEmail));
+ softly.assertThat(actual.getSubject()).isEqualTo("Full message");
+ softly.assertThat(actual.getDate()).isEqualTo("2016-06-07T14:23:37Z");
+ });
+ }
+
+ @Test
+ void fromMessageResultsShouldCombineKeywords() throws Exception {
+ messageIdManager.setInMailboxes(message1.getMessageId(), ImmutableList.of(bobInbox.getId(), bobMailbox.getId()), session);
+ bobMailbox.setFlags(new Flags(Flags.Flag.FLAGGED), MessageManager.FlagsUpdateMode.REPLACE, MessageRange.all(), session);
+
+ List<MessageResult> messages = messageIdManager
+ .getMessages(ImmutableList.of(message1.getMessageId()), FetchGroupImpl.MINIMAL, session);
+
+ MessageHeaderView actual = testee.fromMessageResults(messages);
+ SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(actual.getId()).isEqualTo(message1.getMessageId());
+ softly.assertThat(actual.getKeywords()).isEqualTo(Keywords.strictFactory().from(Keyword.SEEN, Keyword.FLAGGED).asMap());
+ });
+ }
+}
diff --git a/server/protocols/jmap-draft/src/test/resources/fullMessage.eml b/server/protocols/jmap-draft/src/test/resources/fullMessage.eml
new file mode 100644
index 0000000..daf28d3
--- /dev/null
+++ b/server/protocols/jmap-draft/src/test/resources/fullMessage.eml
@@ -0,0 +1,60 @@
+Reply-to: alice <al...@local>
+In-reply-to: bob@local
+Mime-Version: 1.0
+To: bob <bo...@local>
+From: alice <al...@local>
+Cc: jack <ja...@local>, jacob <ja...@local>
+Bcc: alice <al...@local>
+Subject: Full message
+Message-ID: <1c...@open-paas.org>
+Date: Tue, 7 Jun 2016 16:23:37 +0200
+Content-Type: multipart/mixed;
+ boundary="------------7AF1D14DE1DFA16229726B54"
+
+This is a multi-part message in MIME format.
+--------------7AF1D14DE1DFA16229726B54
+Content-Type: multipart/alternative;
+ boundary="------------172F9470CFA3BF3417835D92"
+
+
+--------------172F9470CFA3BF3417835D92
+Content-Type: text/plain; charset=utf-8; format=flowed
+Content-Transfer-Encoding: 7bit
+
+/blabla/
+*bloblo*
+
+--------------172F9470CFA3BF3417835D92
+Content-Type: text/html; charset=utf-8
+Content-Transfer-Encoding: 7bit
+
+<i>blabla</i>
+<b>bloblo</b>
+
+--------------172F9470CFA3BF3417835D92--
+
+--------------7AF1D14DE1DFA16229726B54
+Content-Type: image/jpeg;
+ name="4037_014.jpg"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment;
+ filename="4037_014.jpg"
+
+/9j/4X2cRXhpZgAASUkqAAgAAAANAA8BAgAKAAAAqgAAABABAgAJAAAAtAAAABIBAwABAAAA
+AQAAABoBBQABAAAAvgAAABsBBQABAAAAxgAAACgBAwABAAAAAgAAADEBAgAKAAAAzgAAADIB
+AgAUAAAA2AAAABMCAwABAAAAAgAAAGmHBAABAAAAfAIAAKXEBwDQAAAA7AAAANLGBwBAAAAA
+vAEAANPGBwCAAAAA/AEAAEwqAABQYW5hc29uaWMARE1DLUZaNDUAALQAAAABAAAAtAAAAAEA
+AABWZXIuMS4wICAAMjAxNDowMjoyNSAxMDozMjowOQBQcmludElNADAyNTAAAA4AAQAWABYA
+AgAAAAAAAwBkAAAABwAAAAAACAAAAAAACQAAAAAACgAAAAAACwCsAAAADAAAAAAADQAAAAAA
+DgDEAAAAAAEFAAAAAQEBAAAAEAGAAAAACREAABAnAAALDwAAECcAAJcFAAAQJwAAsAgAABAn
+AAABHAAAECcAAF4CAAAQJwAAiwAAABAnAADLAwAAECcAAOUbAAAQJwAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+
+--------------7AF1D14DE1DFA16229726B54--
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org