You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2021/09/06 07:34:02 UTC

[james-project] branch master updated: JAMES-3642 Fix Buggy behavior with Android Email mobile application (#629)

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


The following commit(s) were added to refs/heads/master by this push:
     new d7e8b78  JAMES-3642 Fix Buggy behavior with Android Email mobile application (#629)
d7e8b78 is described below

commit d7e8b782835b301f4a3f86ae5a3de1fd7b8de9be
Author: Benoit TELLIER <bt...@linagora.com>
AuthorDate: Mon Sep 6 14:33:42 2021 +0700

    JAMES-3642 Fix Buggy behavior with Android Email mobile application (#629)
    
    
    Co-authored-by: Rene Cordier <re...@gmail.com>
---
 protocols/imap/pom.xml                             |   8 +-
 .../imap/processor/AbstractMailboxProcessor.java   |  18 +--
 .../imap/processor/AbstractSelectionProcessor.java |   2 +-
 .../james/imap/processor/fetch/FetchProcessor.java |   2 +-
 .../james/imap/processor/SelectProcessorTest.java  | 173 +++++++++++++++++++++
 5 files changed, 191 insertions(+), 12 deletions(-)

diff --git a/protocols/imap/pom.xml b/protocols/imap/pom.xml
index 92e5b4f..d462ac7 100644
--- a/protocols/imap/pom.xml
+++ b/protocols/imap/pom.xml
@@ -45,7 +45,13 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
-            <artifactId>apache-james-mailbox-store</artifactId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <type>test-jar</type>
             <scope>test</scope>
         </dependency>
         <dependency>
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
index e02e99b..786a7e7 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
@@ -24,7 +24,6 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
-import java.util.stream.Stream;
 
 import javax.mail.Flags;
 
@@ -535,7 +534,7 @@ public abstract class AbstractMailboxProcessor<R extends ImapRequest> extends Ab
     /**
      * Send VANISHED responses if needed. 
      */
-    protected void respondVanished(MailboxSession session, MessageManager mailbox, List<MessageRange> ranges, long changedSince, MailboxMetaData metaData, Responder responder) throws MailboxException {
+    protected void respondVanished(SelectedMailbox selectedMailbox, List<MessageRange> ranges, long changedSince, MailboxMetaData metaData, Responder responder) throws MailboxException {
         // RFC5162 4.2. Server Implementations Storing Minimal State
         //  
         //      A server that stores the HIGHESTMODSEQ value at the time of the last
@@ -561,16 +560,17 @@ public abstract class AbstractMailboxProcessor<R extends ImapRequest> extends Ab
                 MessageUid from = nr.getLowValue();
                 MessageUid to = nr.getHighValue();
                 while (from.compareTo(to) <= 0) {
-                    vanishedUids.add(from);
+                    MessageUid copy = from;
+                    selectedMailbox.msn(from).fold(
+                        () -> vanishedUids.add(copy),
+                        msn -> {
+                            // ignore still there
+                            return true;
+                        });
                     from = from.next();
                 }
                 nRanges[i] = nr;
-                
-            }
-            searchQuery.andCriteria(SearchQuery.uid(nRanges));
-            searchQuery.andCriteria(SearchQuery.modSeqGreaterThan(changedSince));
-            try (Stream<MessageUid> uids = Flux.from(mailbox.search(searchQuery.build(), session)).toStream()) {
-                uids.forEach(vanishedUids::remove);
+
             }
             UidRange[] vanishedIdRanges = uidRanges(MessageRange.toRanges(vanishedUids));
             responder.respond(new VanishedResponse(vanishedIdRanges, true));
diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
index 556aa38..0230e86 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
@@ -299,7 +299,7 @@ abstract class AbstractSelectionProcessor<R extends AbstractMailboxSelectionRequ
                     //          expunges have not happened, or happen only toward the end of the
                     //          mailbox.
                     //
-                    respondVanished(mailboxSession, mailbox, ranges, modSeq, metaData, responder);
+                    respondVanished(selected, ranges, modSeq, metaData, responder);
                 }
                 taggedOk(responder, request, metaData, HumanReadableText.SELECT);
             } else {
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 8be367d..74b02cc 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
@@ -112,7 +112,7 @@ public class FetchProcessor extends AbstractMailboxProcessor<FetchRequest> {
             if (vanished) {
                 // TODO: From the QRESYNC RFC it seems ok to send the VANISHED responses after the FETCH Responses. 
                 //       If we do so we could prolly save one mailbox access which should give use some more speed up
-                respondVanished(mailboxSession, mailbox, ranges, changedSince, metaData.get(), responder);
+                respondVanished(session.getSelected(), ranges, changedSince, metaData.get(), responder);
             }
             processMessageRanges(session, mailbox, ranges, fetch, useUids, mailboxSession, responder);
 
diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/SelectProcessorTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/SelectProcessorTest.java
new file mode 100644
index 0000000..97eb73f
--- /dev/null
+++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/SelectProcessorTest.java
@@ -0,0 +1,173 @@
+/****************************************************************
+ * 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.imap.processor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.ByteArrayOutputStream;
+
+import javax.mail.Flags;
+import javax.mail.util.SharedByteArrayInputStream;
+
+import org.apache.james.core.Username;
+import org.apache.james.imap.api.ImapConfiguration;
+import org.apache.james.imap.api.ImapConstants;
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.api.Tag;
+import org.apache.james.imap.api.message.IdRange;
+import org.apache.james.imap.api.message.UidRange;
+import org.apache.james.imap.api.process.ImapProcessor;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.decode.main.OutputStreamImapResponseWriter;
+import org.apache.james.imap.encode.FakeImapSession;
+import org.apache.james.imap.encode.base.ImapResponseComposerImpl;
+import org.apache.james.imap.encode.main.DefaultImapEncoderFactory;
+import org.apache.james.imap.encode.main.DefaultLocalizer;
+import org.apache.james.imap.main.ResponseEncoder;
+import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest;
+import org.apache.james.imap.message.request.SelectRequest;
+import org.apache.james.imap.message.response.UnpooledStatusResponseFactory;
+import org.apache.james.mailbox.MailboxSession;
+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.MailboxPath;
+import org.apache.james.mailbox.model.UidValidity;
+import org.apache.james.metrics.tests.RecordingMetricFactory;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+
+class SelectProcessorTest {
+    private static final Username BOB = Username.of("bob");
+
+    private SelectProcessor testee;
+    private InMemoryMailboxManager mailboxManager;
+    private MailboxSession mailboxSession;
+    private UidValidity uidValidity;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        InMemoryIntegrationResources integrationResources = InMemoryIntegrationResources.defaultResources();
+
+        mailboxManager = integrationResources.getMailboxManager();
+        testee = new SelectProcessor(new ImapProcessor() {
+            @Override
+            public void process(ImapMessage message, Responder responder, ImapSession session) {
+
+            }
+
+            @Override
+            public void configure(ImapConfiguration imapConfiguration) {
+
+            }
+        }, mailboxManager,
+            integrationResources.getEventBus(),
+            new UnpooledStatusResponseFactory(),
+            new RecordingMetricFactory());
+
+        mailboxSession = mailboxManager.createSystemSession(Username.of("bob"));
+        mailboxManager.createMailbox(MailboxPath.inbox(BOB), mailboxSession);
+        uidValidity = mailboxManager.getMailbox(MailboxPath.inbox(BOB), mailboxSession).getMailboxEntity().getUidValidity();
+    }
+
+    @Test
+    void vanishedResponsesShouldNotBeSentWhenNoDeletes() throws Exception {
+        FakeImapSession session = new FakeImapSession();
+        session.authenticated();
+        session.setMailboxSession(mailboxSession);
+        EnableProcessor.getEnabledCapabilities(session)
+            .add(ImapConstants.SUPPORTS_QRESYNC);
+
+        MessageManager mailbox = mailboxManager.getMailbox(MailboxPath.inbox(BOB), mailboxSession);
+        MessageManager.AppendCommand appendCommand = MessageManager.AppendCommand
+            .builder()
+            .withFlags(new Flags(Flags.Flag.SEEN))
+            .notRecent()
+            .build(new SharedByteArrayInputStream("header: value\r\n\r\nbody".getBytes()));
+        mailbox.appendMessage(appendCommand, mailboxSession);
+        mailbox.appendMessage(appendCommand, mailboxSession);
+        mailbox.appendMessage(appendCommand, mailboxSession);
+        mailbox.appendMessage(appendCommand, mailboxSession);
+        mailbox.appendMessage(appendCommand, mailboxSession);
+
+        UidRange[] uidRanges = null;
+        IdRange[] sequences = null;
+        SelectRequest message = new SelectRequest("INBOX", false,
+            AbstractMailboxSelectionRequest.ClientSpecifiedUidValidity.valid(uidValidity),
+            4L, uidRanges, uidRanges, sequences, new Tag("AA"));
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        testee.process(message,
+            new ResponseEncoder(
+                new DefaultImapEncoderFactory(new DefaultLocalizer(), true).buildImapEncoder(),
+                new ImapResponseComposerImpl(new OutputStreamImapResponseWriter(outputStream))),
+            session);
+
+        assertThat(new String(outputStream.toByteArray()))
+            .doesNotContain("* VANISHED (EARLIER) 1:4");
+    }
+
+    @Test
+    void vanishedResponsesShouldBeSentWhenDeletes() throws Exception {
+        FakeImapSession session = new FakeImapSession();
+        session.authenticated();
+        session.setMailboxSession(mailboxSession);
+        EnableProcessor.getEnabledCapabilities(session)
+            .add(ImapConstants.SUPPORTS_QRESYNC);
+
+        MessageManager mailbox = mailboxManager.getMailbox(MailboxPath.inbox(BOB), mailboxSession);
+        MessageManager.AppendCommand appendCommand = MessageManager.AppendCommand
+            .builder()
+            .withFlags(new Flags(Flags.Flag.SEEN))
+            .notRecent()
+            .build(new SharedByteArrayInputStream("header: value\r\n\r\nbody".getBytes()));
+        mailbox.appendMessage(appendCommand, mailboxSession);
+
+        MessageManager.AppendResult msg2 = mailbox.appendMessage(appendCommand, mailboxSession);
+
+        mailbox.appendMessage(appendCommand, mailboxSession);
+
+        MessageManager.AppendResult msg4 = mailbox.appendMessage(appendCommand, mailboxSession);
+
+        mailbox.appendMessage(appendCommand, mailboxSession);
+
+        mailbox.delete(ImmutableList.of(msg2.getId().getUid(), msg4.getId().getUid()), mailboxSession);
+
+        UidRange[] uidRanges = null;
+        IdRange[] sequences = null;
+        SelectRequest message = new SelectRequest("INBOX", false,
+            AbstractMailboxSelectionRequest.ClientSpecifiedUidValidity.valid(uidValidity),
+            4L, uidRanges, uidRanges, sequences, new Tag("AA"));
+
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        testee.process(message,
+            new ResponseEncoder(
+                new DefaultImapEncoderFactory(new DefaultLocalizer(), true).buildImapEncoder(),
+                new ImapResponseComposerImpl(new OutputStreamImapResponseWriter(outputStream))),
+            session);
+
+        assertThat(new String(outputStream.toByteArray()))
+            .contains("* VANISHED (EARLIER) 2,4");
+    }
+}
\ No newline at end of file

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