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 bt...@apache.org on 2020/07/09 01:51:32 UTC
[james-project] 03/06: JAMES-3265 Fasten fetching all flags
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit e995a086616d3c29722490451700c3c4c89b2392
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Tue Jul 7 14:28:39 2020 +0700
JAMES-3265 Fasten fetching all flags
As we disabled buggy CONDSTORE extension upon reconnection, TBird has no
choice than to do a full scan of all uid & flags to resync.
This operation is costly.
On top of the Cassandra backend, 99+% of the time is spent reading the
messagev2 table that is not needed for this Fetch request, effectively
slowing down the request.
By adding a method allowing to retrieve ComposedMessageIdWithMetaDatas for
a range in a given mailbox on top of the MessageManager, we allow
significant performance enhancement for IMAP on top of the Cassandra backend.
---
.../org/apache/james/mailbox/MessageManager.java | 4 +
.../apache/james/mailbox/MailboxManagerTest.java | 58 ++++++++++++++
.../cassandra/mail/CassandraMessageMapper.java | 6 ++
.../james/mailbox/store/StoreMessageManager.java | 8 ++
.../james/mailbox/store/mail/MessageMapper.java | 14 ++++
.../apache/james/imap/api/message/FetchData.java | 10 +++
.../james/imap/processor/fetch/FetchProcessor.java | 86 ++++++++++++++------
.../imap/processor/fetch/FetchResponseBuilder.java | 92 ++++++++++++++++------
8 files changed, 228 insertions(+), 50 deletions(-)
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
index 6c21579..88c0476 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageManager.java
@@ -39,6 +39,7 @@ import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.UnsupportedCriteriaException;
import org.apache.james.mailbox.exception.UnsupportedRightException;
import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
import org.apache.james.mailbox.model.FetchGroup;
import org.apache.james.mailbox.model.Mailbox;
import org.apache.james.mailbox.model.MailboxACL;
@@ -53,6 +54,7 @@ import org.apache.james.mailbox.model.SearchQuery;
import org.apache.james.mailbox.model.UidValidity;
import org.apache.james.mime4j.dom.Message;
import org.apache.james.mime4j.message.DefaultMessageWriter;
+import org.reactivestreams.Publisher;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
@@ -321,6 +323,8 @@ public interface MessageManager {
*/
MessageResultIterator getMessages(MessageRange set, FetchGroup fetchGroup, MailboxSession mailboxSession) throws MailboxException;
+ Publisher<ComposedMessageIdWithMetaData> listMessagesMetadata(MessageRange set, MailboxSession session);
+
/**
* Return the underlying {@link Mailbox}
*/
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index 7a8dbe5..c1692e9 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -19,6 +19,7 @@
package org.apache.james.mailbox;
import static org.apache.james.mailbox.MailboxManager.RenameOption.RENAME_SUBSCRIPTIONS;
+import static org.apache.james.mailbox.MessageManager.FlagsUpdateMode.REPLACE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -63,6 +64,7 @@ import org.apache.james.mailbox.exception.TooLongMailboxNameException;
import org.apache.james.mailbox.extension.PreDeletionHook;
import org.apache.james.mailbox.mock.DataProvisioner;
import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
import org.apache.james.mailbox.model.FetchGroup;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxAnnotation;
@@ -2665,6 +2667,62 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
}
@Test
+ void listMessagesMetadataShouldReturnEmptyWhenNoMessages() {
+ assertThat(Flux.from(inboxManager.listMessagesMetadata(MessageRange.all(), session))
+ .collectList().block())
+ .isEmpty();
+ }
+
+ @Test
+ void listMessagesMetadataShouldReturnAppendedMessage() throws Exception {
+ Flags flags = new Flags(Flags.Flag.DELETED);
+ ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
+ .withFlags(flags)
+ .build(ClassLoaderUtils.getSystemResourceAsSharedStream("eml/twoAttachmentsApi.eml")), session).getId();
+
+ assertThat(Flux.from(inboxManager.listMessagesMetadata(MessageRange.all(), session))
+ .collectList().block())
+ .hasSize(1)
+ .allSatisfy(ids -> SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(ids.getComposedMessageId().getMailboxId()).isEqualTo(composeId.getMailboxId());
+ softly.assertThat(ids.getComposedMessageId().getUid()).isEqualTo(composeId.getUid());
+ softly.assertThat(ids.getFlags()).isEqualTo(flags);
+ }));
+ }
+
+ @Test
+ void listMessagesMetadataShouldReturnUpdatedMessage() throws Exception {
+ Flags flags = new Flags(Flags.Flag.SEEN);
+ ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
+ .withFlags(new Flags(Flags.Flag.DELETED))
+ .build(ClassLoaderUtils.getSystemResourceAsSharedStream("eml/twoAttachmentsApi.eml")), session).getId();
+
+ inboxManager.setFlags(flags, REPLACE, MessageRange.all(), session);
+
+ assertThat(Flux.from(inboxManager.listMessagesMetadata(MessageRange.all(), session))
+ .collectList().block())
+ .hasSize(1)
+ .allSatisfy(ids -> SoftAssertions.assertSoftly(softly -> {
+ softly.assertThat(ids.getComposedMessageId().getMailboxId()).isEqualTo(composeId.getMailboxId());
+ softly.assertThat(ids.getComposedMessageId().getUid()).isEqualTo(composeId.getUid());
+ softly.assertThat(ids.getFlags()).isEqualTo(flags);
+ }));
+ }
+
+ @Test
+ void listMessagesMetadataShouldNotReturnDeletedMessage() throws Exception {
+ inboxManager.appendMessage(AppendCommand.builder()
+ .withFlags(new Flags(Flags.Flag.DELETED))
+ .build(ClassLoaderUtils.getSystemResourceAsSharedStream("eml/twoAttachmentsApi.eml")), session).getId();
+
+ inboxManager.expunge(MessageRange.all(), session);
+
+ assertThat(Flux.from(inboxManager.listMessagesMetadata(MessageRange.all(), session))
+ .collectList().block())
+ .isEmpty();
+ }
+
+ @Test
void getMessagesShouldIncludeHasAttachmentInformation() throws Exception {
ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
index fb94eff..75adad6 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
@@ -172,6 +172,12 @@ public class CassandraMessageMapper implements MessageMapper {
}
@Override
+ public Flux<ComposedMessageIdWithMetaData> listMessagesMetadata(Mailbox mailbox, MessageRange set) {
+ CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
+ return messageIdDAO.retrieveMessages(mailboxId, set, Limit.unlimited());
+ }
+
+ @Override
public Flux<MailboxMessage> findInMailboxReactive(Mailbox mailbox, MessageRange messageRange, FetchType ftype, int limitAsInt) {
CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
index d4a8c6a..53079f4 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageManager.java
@@ -60,6 +60,7 @@ import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.ReadOnlyException;
import org.apache.james.mailbox.exception.UnsupportedRightException;
import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
import org.apache.james.mailbox.model.FetchGroup;
import org.apache.james.mailbox.model.Mailbox;
import org.apache.james.mailbox.model.MailboxACL;
@@ -97,6 +98,7 @@ import org.apache.james.util.IteratorWrapper;
import org.apache.james.util.io.BodyOffsetInputStream;
import org.apache.james.util.io.InputStreamConsummer;
import org.apache.james.util.streams.Iterators;
+import org.reactivestreams.Publisher;
import com.github.steveash.guavate.Guavate;
import com.google.common.collect.ImmutableList;
@@ -651,6 +653,12 @@ public class StoreMessageManager implements MessageManager {
return new StoreMessageResultIterator(messageMapper, mailbox, set, batchSizes, fetchGroup);
}
+ @Override
+ public Publisher<ComposedMessageIdWithMetaData> listMessagesMetadata(MessageRange set, MailboxSession session) {
+ MessageMapper messageMapper = mapperFactory.getMessageMapper(session);
+ return messageMapper.listMessagesMetadata(mailbox, set);
+ }
+
/**
* Return a List which holds all uids of recent messages and optional reset
* the recent flag on the messages for the uids
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
index d92be02..1d4f6f4 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageMapper.java
@@ -31,6 +31,8 @@ import org.apache.james.mailbox.MessageManager.FlagsUpdateMode;
import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
import org.apache.james.mailbox.model.Mailbox;
import org.apache.james.mailbox.model.MailboxCounters;
import org.apache.james.mailbox.model.MessageMetaData;
@@ -52,6 +54,7 @@ import reactor.core.publisher.Mono;
* to the end of the request.
*/
public interface MessageMapper extends Mapper {
+ int UNLIMITED = -1;
/**
* Return a {@link Iterator} which holds the messages for the given criterias
@@ -65,6 +68,17 @@ public interface MessageMapper extends Mapper {
Iterator<MailboxMessage> findInMailbox(Mailbox mailbox, MessageRange set, FetchType type, int limit)
throws MailboxException;
+ default Flux<ComposedMessageIdWithMetaData> listMessagesMetadata(Mailbox mailbox, MessageRange set) {
+ return findInMailboxReactive(mailbox, set, FetchType.Metadata, UNLIMITED)
+ .map(message -> new ComposedMessageIdWithMetaData(
+ new ComposedMessageId(
+ message.getMailboxId(),
+ message.getMessageId(),
+ message.getUid()),
+ message.createFlags(),
+ message.getModSeq()));
+ }
+
default Flux<MailboxMessage> findInMailboxReactive(Mailbox mailbox, MessageRange set, FetchType type, int limit) {
try {
return Iterators.toFlux(findInMailbox(mailbox, set, type, limit));
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/api/message/FetchData.java b/protocols/imap/src/main/java/org/apache/james/imap/api/message/FetchData.java
index 3a4b305..822dfa2 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/api/message/FetchData.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/api/message/FetchData.java
@@ -142,6 +142,16 @@ public class FetchData {
return vanished;
}
+ public boolean isOnlyFlags() {
+ return bodyElements.isEmpty()
+ && itemToFetch.stream()
+ .filter(item -> item != Item.FLAGS)
+ .filter(item -> item != Item.UID)
+ .filter(item -> item != Item.MODSEQ)
+ .findAny()
+ .isEmpty();
+ }
+
@Override
public final int hashCode() {
return Objects.hash(itemToFetch, bodyElements, setSeen, changedSince);
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
index 4fe3a81..53cdff2 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java
@@ -21,6 +21,7 @@ package org.apache.james.imap.processor.fetch;
import java.io.Closeable;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import org.apache.james.imap.api.ImapConstants;
@@ -41,6 +42,7 @@ import org.apache.james.mailbox.MessageManager;
import org.apache.james.mailbox.MessageManager.MailboxMetaData;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.MessageRangeException;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
import org.apache.james.mailbox.model.FetchGroup;
import org.apache.james.mailbox.model.MessageRange;
import org.apache.james.mailbox.model.MessageResult;
@@ -50,6 +52,8 @@ import org.apache.james.util.MDCBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Flux;
+
public class FetchProcessor extends AbstractMailboxProcessor<FetchRequest> {
private static final Logger LOGGER = LoggerFactory.getLogger(FetchProcessor.class);
@@ -140,37 +144,71 @@ public class FetchProcessor extends AbstractMailboxProcessor<FetchRequest> {
FetchGroup resultToFetch = FetchDataConverter.getFetchGroup(fetch);
for (MessageRange range : ranges) {
- MessageResultIterator messages = mailbox.getMessages(range, resultToFetch, mailboxSession);
- while (messages.hasNext()) {
- final MessageResult result = messages.next();
+ if (fetch.isOnlyFlags()) {
+ processMessageRangeForFlags(session, mailbox, fetch, mailboxSession, responder, builder, range);
+ } else {
+ processMessageRange(session, mailbox, fetch, useUids, mailboxSession, responder, builder, resultToFetch, range);
+ }
+ }
- //skip unchanged messages - this should be filtered at the mailbox level to take advantage of indexes
- if (fetch.contains(Item.MODSEQ) && result.getModSeq().asLong() <= fetch.getChangedSince()) {
- continue;
- }
+ }
- try {
- final FetchResponse response = builder.build(fetch, result, mailbox, session, useUids);
- responder.respond(response);
- } catch (MessageRangeException e) {
- // we can't for whatever reason find the message so
- // just skip it and log it to debug
- LOGGER.debug("Unable to find message with uid {}", result.getUid(), e);
- } catch (MailboxException e) {
- // we can't for whatever reason find parse all requested parts of the message. This may because it was deleted while try to access the parts.
- // So we just skip it
- //
- // See IMAP-347
- LOGGER.error("Unable to fetch message with uid {}, so skip it", result.getUid(), e);
- }
+ private void processMessageRangeForFlags(ImapSession session, MessageManager mailbox, FetchData fetch, MailboxSession mailboxSession, Responder responder, FetchResponseBuilder builder, MessageRange range) {
+ Iterator<ComposedMessageIdWithMetaData> results = Flux.from(mailbox.listMessagesMetadata(range, mailboxSession))
+ .filter(ids -> !fetch.contains(Item.MODSEQ) || ids.getModSeq().asLong() > fetch.getChangedSince())
+ .toStream()
+ .iterator();
+
+ while (results.hasNext()) {
+ ComposedMessageIdWithMetaData result = results.next();
+
+ try {
+ final FetchResponse response = builder.build(fetch, result, mailbox, session);
+ responder.respond(response);
+ } catch (MessageRangeException e) {
+ // we can't for whatever reason find the message so
+ // just skip it and log it to debug
+ LOGGER.debug("Unable to find message with uid {}", result.getComposedMessageId().getUid(), e);
+ } catch (MailboxException e) {
+ // we can't for whatever reason find parse all requested parts of the message. This may because it was deleted while try to access the parts.
+ // So we just skip it
+ //
+ // See IMAP-347
+ LOGGER.error("Unable to fetch message with uid {}, so skip it", result.getComposedMessageId().getUid(), e);
}
+ }
+ }
+
+ private void processMessageRange(ImapSession session, MessageManager mailbox, FetchData fetch, boolean useUids, MailboxSession mailboxSession, Responder responder, FetchResponseBuilder builder, FetchGroup resultToFetch, MessageRange range) throws MailboxException {
+ MessageResultIterator messages = mailbox.getMessages(range, resultToFetch, mailboxSession);
+ while (messages.hasNext()) {
+ final MessageResult result = messages.next();
- // Throw the exception if we received one
- if (messages.getException() != null) {
- throw messages.getException();
+ //skip unchanged messages - this should be filtered at the mailbox level to take advantage of indexes
+ if (fetch.contains(Item.MODSEQ) && result.getModSeq().asLong() <= fetch.getChangedSince()) {
+ continue;
+ }
+
+ try {
+ final FetchResponse response = builder.build(fetch, result, mailbox, session, useUids);
+ responder.respond(response);
+ } catch (MessageRangeException e) {
+ // we can't for whatever reason find the message so
+ // just skip it and log it to debug
+ LOGGER.debug("Unable to find message with uid {}", result.getUid(), e);
+ } catch (MailboxException e) {
+ // we can't for whatever reason find parse all requested parts of the message. This may because it was deleted while try to access the parts.
+ // So we just skip it
+ //
+ // See IMAP-347
+ LOGGER.error("Unable to fetch message with uid {}, so skip it", result.getUid(), e);
}
}
+ // Throw the exception if we received one
+ if (messages.getException() != null) {
+ throw messages.getException();
+ }
}
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
index bc978b7..73f18f7 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/fetch/FetchResponseBuilder.java
@@ -47,6 +47,7 @@ import org.apache.james.mailbox.MessageUid;
import org.apache.james.mailbox.ModSeq;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.MessageRangeException;
+import org.apache.james.mailbox.model.ComposedMessageIdWithMetaData;
import org.apache.james.mailbox.model.Content;
import org.apache.james.mailbox.model.Header;
import org.apache.james.mailbox.model.MessageRange;
@@ -125,21 +126,9 @@ public final class FetchResponseBuilder {
// message. If so, update the flags, and ensure that a flags response is
// included in the response.
final MailboxSession mailboxSession = session.getMailboxSession();
- boolean ensureFlagsResponse = false;
- final Flags resultFlags = result.getFlags();
- if (fetch.isSetSeen() && !resultFlags.contains(Flags.Flag.SEEN)) {
- mailbox.setFlags(new Flags(Flags.Flag.SEEN), MessageManager.FlagsUpdateMode.ADD, MessageRange.one(resultUid), mailboxSession);
- resultFlags.add(Flags.Flag.SEEN);
- ensureFlagsResponse = true;
- }
// FLAGS response
- if (fetch.contains(Item.FLAGS) || ensureFlagsResponse) {
- if (selected.isRecent(resultUid)) {
- resultFlags.add(Flags.Flag.RECENT);
- }
- setFlags(resultFlags);
- }
+ addFlags(fetch, mailbox, selected, resultUid, mailboxSession, result.getFlags());
// INTERNALDATE response
if (fetch.contains(Item.INTERNAL_DATE)) {
@@ -183,23 +172,74 @@ public final class FetchResponseBuilder {
bodystructure = new MimeDescriptorStructure(true, result.getMimeDescriptor(), envelopeBuilder);
}
}
- // UID response
- if (fetch.contains(Item.UID)) {
- setUid(resultUid);
- }
+ addUid(fetch, resultUid);
- if (fetch.contains(Item.MODSEQ)) {
- long changedSince = fetch.getChangedSince();
- if (changedSince != -1) {
- // check if the modsequence if higher then the one specified by the CHANGEDSINCE option
- if (changedSince < result.getModSeq().asLong()) {
- setModSeq(result.getModSeq());
- }
- } else {
- setModSeq(result.getModSeq());
+ addModSeq(fetch, result.getModSeq());
+
+ return build();
+ });
+ }
+
+ private void addUid(FetchData fetch, MessageUid resultUid) {
+ // UID response
+ if (fetch.contains(Item.UID)) {
+ setUid(resultUid);
+ }
+ }
+
+ private void addModSeq(FetchData fetch, ModSeq modSeq) {
+ if (fetch.contains(Item.MODSEQ)) {
+ long changedSince = fetch.getChangedSince();
+ if (changedSince != -1) {
+ // check if the modsequence if higher then the one specified by the CHANGEDSINCE option
+ if (changedSince < modSeq.asLong()) {
+ setModSeq(modSeq);
}
+ } else {
+ setModSeq(modSeq);
+ }
+ }
+ }
+
+ private void addFlags(FetchData fetch, MessageManager mailbox, SelectedMailbox selected, MessageUid resultUid, MailboxSession mailboxSession, Flags flags) throws MailboxException {
+ boolean ensureFlagsResponse = false;
+ final Flags resultFlags = flags;
+ if (fetch.isSetSeen() && !resultFlags.contains(Flags.Flag.SEEN)) {
+ mailbox.setFlags(new Flags(Flags.Flag.SEEN), MessageManager.FlagsUpdateMode.ADD, MessageRange.one(resultUid), mailboxSession);
+ resultFlags.add(Flags.Flag.SEEN);
+ ensureFlagsResponse = true;
+ }
+
+ if (fetch.contains(Item.FLAGS) || ensureFlagsResponse) {
+ if (selected.isRecent(resultUid)) {
+ resultFlags.add(Flags.Flag.RECENT);
}
+ setFlags(resultFlags);
+ }
+ }
+
+ public FetchResponse build(FetchData fetch, ComposedMessageIdWithMetaData result, MessageManager mailbox, ImapSession session) throws MessageRangeException, MailboxException {
+ final SelectedMailbox selected = session.getSelected();
+ final MessageUid resultUid = result.getComposedMessageId().getUid();
+ return selected.msn(resultUid).fold(() -> {
+ throw new MessageRangeException("No such message found with uid " + resultUid);
+ }, msn -> {
+
+ reset(msn);
+ // setMsn(resultMsn);
+
+ // Check if this fetch will cause the "SEEN" flag to be set on this
+ // message. If so, update the flags, and ensure that a flags response is
+ // included in the response.
+ final MailboxSession mailboxSession = session.getMailboxSession();
+ // FLAGS response
+ addFlags(fetch, mailbox, selected, resultUid, mailboxSession, result.getFlags());
+ // UID response
+ addUid(fetch, resultUid);
+
+
+ addModSeq(fetch, result.getModSeq());
return build();
});
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org