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 286bbb181dc105d55e8e10986e3352a91dea6916
Author: Benoit Tellier <[email protected]>
AuthorDate: Fri Apr 7 12:33:33 2023 +0700

    JAMES-3899 WithStorageDirective: Support flag storage directives
    
     - Seen
     - Flagged
     - Keyword
---
 .../WithStorageDirectiveIntegrationTest.java       | 62 ++++++++++++++
 .../james/transport/mailets/ToSenderFolder.java    |  6 +-
 .../transport/mailets/WithStorageDirective.java    | 70 +++++++++++++---
 .../transport/mailets/delivery/MailStore.java      |  3 +
 .../mailets/delivery/MailboxAppender.java          |  5 +-
 .../mailets/delivery/MailboxAppenderImpl.java      | 27 +++---
 .../mailets/delivery/SimpleMailStore.java          | 60 ++++++++++++-
 .../mailets/WithStorageDirectiveTest.java          | 97 ++++++++++++++++++++++
 .../mailets/delivery/MailboxAppenderImplTest.java  | 25 ++++--
 .../mailets/delivery/SimpleMailStoreTest.java      |  8 +-
 10 files changed, 325 insertions(+), 38 deletions(-)

diff --git 
a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/WithStorageDirectiveIntegrationTest.java
 
b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/WithStorageDirectiveIntegrationTest.java
index bf33b13891..506162e41f 100644
--- 
a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/WithStorageDirectiveIntegrationTest.java
+++ 
b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/WithStorageDirectiveIntegrationTest.java
@@ -25,6 +25,7 @@ import static 
org.apache.james.mailets.configuration.Constants.LOCALHOST_IP;
 import static org.apache.james.mailets.configuration.Constants.PASSWORD;
 import static org.apache.james.mailets.configuration.Constants.RECIPIENT;
 import static 
org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute;
+import static org.assertj.core.api.Assertions.assertThat;
 
 import java.io.File;
 
@@ -76,6 +77,67 @@ class WithStorageDirectiveIntegrationTest {
             .awaitMessage(awaitAtMostOneMinute);
     }
 
+    @Test
+    void seenShouldWork(@TempDir File temporaryFolder) throws Exception {
+        setUp(temporaryFolder, MailetConfiguration.builder()
+            .matcher(SenderIsLocal.class)
+            .mailet(WithStorageDirective.class)
+            .addProperty("seen", "true"));
+
+        testIMAPClient.connect(LOCALHOST_IP, 
jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+            .login(RECIPIENT, PASSWORD);
+
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(FROM, PASSWORD)
+            .sendMessage(FROM, RECIPIENT);
+
+        testIMAPClient.select("INBOX")
+            .awaitMessage(awaitAtMostOneMinute);
+
+        assertThat(testIMAPClient.hasAMessageWithFlags("\\Seen")).isTrue();
+    }
+
+    @Test
+    void importantShouldWork(@TempDir File temporaryFolder) throws Exception {
+        setUp(temporaryFolder, MailetConfiguration.builder()
+            .matcher(SenderIsLocal.class)
+            .mailet(WithStorageDirective.class)
+            .addProperty("important", "true"));
+
+        testIMAPClient.connect(LOCALHOST_IP, 
jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+            .login(RECIPIENT, PASSWORD);
+
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(FROM, PASSWORD)
+            .sendMessage(FROM, RECIPIENT);
+
+        testIMAPClient.select("INBOX")
+            .awaitMessage(awaitAtMostOneMinute);
+
+        assertThat(testIMAPClient.hasAMessageWithFlags("\\Flagged")).isTrue();
+    }
+
+    @Test
+    void keywordsShouldWork(@TempDir File temporaryFolder) throws Exception {
+        setUp(temporaryFolder, MailetConfiguration.builder()
+            .matcher(SenderIsLocal.class)
+            .mailet(WithStorageDirective.class)
+            .addProperty("keywords", "abc,def"));
+
+        testIMAPClient.connect(LOCALHOST_IP, 
jamesServer.getProbe(ImapGuiceProbe.class).getImapPort())
+            .login(RECIPIENT, PASSWORD);
+
+        messageSender.connect(LOCALHOST_IP, 
jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+            .authenticate(FROM, PASSWORD)
+            .sendMessage(FROM, RECIPIENT);
+
+        testIMAPClient.select("INBOX")
+            .awaitMessage(awaitAtMostOneMinute);
+
+        assertThat(testIMAPClient.hasAMessageWithFlags("abc")).isTrue();
+        assertThat(testIMAPClient.hasAMessageWithFlags("def")).isTrue();
+    }
+
     private void setUp(File temporaryFolder, MailetConfiguration.Builder 
mailet) throws Exception {
         jamesServer = TemporaryJamesServer.builder()
             
.withMailetContainer(TemporaryJamesServer.defaultMailetContainerConfiguration()
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
index 311ba38768..d808b81874 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java
@@ -18,8 +18,11 @@
  ****************************************************************/
 package org.apache.james.transport.mailets;
 
+import java.util.Optional;
+
 import javax.inject.Inject;
 import javax.inject.Named;
+import javax.mail.Flags;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
@@ -53,6 +56,7 @@ import org.slf4j.LoggerFactory;
 @Experimental
 public class ToSenderFolder extends GenericMailet {
     private static final Logger LOGGER = 
LoggerFactory.getLogger(ToSenderFolder.class);
+    private static final Optional<Flags> NO_FLAGS = Optional.empty();
 
     private final UsersRepository usersRepository;
     private final MailboxManager mailboxManager;
@@ -84,7 +88,7 @@ public class ToSenderFolder extends GenericMailet {
             MailAddress sender = mail.getMaybeSender().get();
             Username username = retrieveUser(sender);
 
-            mailboxAppender.append(mail.getMessage(), username, 
folder).block();
+            mailboxAppender.append(mail.getMessage(), username, folder, 
NO_FLAGS).block();
 
             LOGGER.error("Local delivery with ToSenderFolder mailet for mail 
{} with sender {} in folder {}", mail.getName(), sender, folder);
         }
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java
index 178b51aeae..857f69b48e 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java
@@ -19,10 +19,14 @@
 
 package org.apache.james.transport.mailets;
 
+import java.util.Collection;
+import java.util.Optional;
+
 import javax.inject.Inject;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
+import org.apache.james.core.Username;
 import org.apache.james.transport.mailets.delivery.MailStore;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.mailet.Attribute;
@@ -33,7 +37,9 @@ import org.apache.mailet.base.GenericMailet;
 
 import com.github.fge.lambdas.consumers.ThrowingConsumer;
 import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.primitives.Booleans;
 
 /**
  * WithStorageDirective position storage directive for the recipients of this 
email.
@@ -41,21 +47,37 @@ import com.google.common.base.Strings;
  * These directives are used by <strong>LocalDelivery</strong> mailet when 
adding the email to the recipients mailboxes.
  *
  * The following storage directives can be set:
- *  - targetFolderName: the folder to append the email in. (compulsory)
+ *  - targetFolderName: the folder to append the email in. Defaults to none 
(INBOX).
+ *  - seen: boolean, whether the message should be automatically marked as 
seen. Defaults to false.
+ *  - important: boolean, whether the message should be automatically marked 
as important. Defaults to false.
+ *  - keywords: set of string, encoded as a string (value are coma separated). 
IMAP user flags to set for the message. Defaults to none.
+ *
+ *  At least one of the storage directives should be set.
  *
  *  Example:
  *
  *  <mailet match="IsMarkedAsSpam" class="WithStorageDirective">
  *      <targetFolderName>Spam</targetFolderName>
+ *      <seen>true</seen>
+ *      <important>true</important>
+ *      <keywords>keyword1,keyword2</targetFolderName>
  *  </mailet>
  */
 public class WithStorageDirective extends GenericMailet {
-
-    public static final String TARGET_FOLDER_NAME = "targetFolderName";
+    static final String TARGET_FOLDER_NAME = "targetFolderName";
+    static final String SEEN = "seen";
+    static final String IMPORTANT = "important";
+    static final String KEYWORDS = "keywords";
+    private static final Splitter KEYWORD_SPLITTER = Splitter.on(',')
+        .omitEmptyStrings()
+        .trimResults();
 
     private final UsersRepository usersRepository;
 
-    private AttributeValue<String> targetFolderName;
+    private Optional<AttributeValue<String>> targetFolderName;
+    private Optional<AttributeValue<Boolean>> seen;
+    private Optional<AttributeValue<Boolean>> important;
+    private Optional<AttributeValue<Collection<AttributeValue<?>>>> keywords;
 
     @Inject
     public WithStorageDirective(UsersRepository usersRepository) {
@@ -64,13 +86,33 @@ public class WithStorageDirective extends GenericMailet {
 
     @Override
     public void init() throws MessagingException {
-        targetFolderName = 
AttributeValue.of(validateMailetConfiguration(TARGET_FOLDER_NAME));
+        Preconditions.checkState(
+            Booleans.countTrue(
+                getInitParameterAsOptional(TARGET_FOLDER_NAME).isPresent(),
+                getInitParameterAsOptional(SEEN).isPresent(),
+                getInitParameterAsOptional(IMPORTANT).isPresent(),
+                getInitParameterAsOptional(KEYWORDS).isPresent()) > 0,
+                "Expecting one of the storage directives to be specified: [%s, 
%s, %s, %s]",
+                TARGET_FOLDER_NAME, SEEN, IMPORTANT, KEYWORDS);
+        
Preconditions.checkState(validBooleanParameter(getInitParameterAsOptional(SEEN)),
 "'%s' needs to be a boolean", SEEN);
+        
Preconditions.checkState(validBooleanParameter(getInitParameterAsOptional(IMPORTANT)),
 "'%s' needs to be a boolean", IMPORTANT);
+
+        targetFolderName = 
getInitParameterAsOptional(TARGET_FOLDER_NAME).map(AttributeValue::of);
+        seen = 
getInitParameterAsOptional(SEEN).map(Boolean::parseBoolean).map(AttributeValue::of);
+        important = 
getInitParameterAsOptional(IMPORTANT).map(Boolean::parseBoolean).map(AttributeValue::of);
+        keywords = 
getInitParameterAsOptional(KEYWORDS).map(this::parseKeywords).map(AttributeValue::of);
     }
 
-    private String validateMailetConfiguration(String initParameterName) {
-        String initParameterValue = getInitParameter(initParameterName);
-        Preconditions.checkState(!Strings.isNullOrEmpty(initParameterValue), 
"You need to specify %s", initParameterName);
-        return initParameterValue;
+    private Collection<AttributeValue<?>> parseKeywords(String s) {
+        return KEYWORD_SPLITTER
+            .splitToStream(s)
+            .map(AttributeValue::of)
+            .collect(ImmutableSet.toImmutableSet());
+    }
+
+    private boolean validBooleanParameter(Optional<String> parameter) {
+        return parameter.map(v -> v.equals("true") || v.equals("false"))
+            .orElse(true);
     }
 
     @Override
@@ -81,9 +123,11 @@ public class WithStorageDirective extends GenericMailet {
 
     public ThrowingConsumer<MailAddress> addStorageDirective(Mail mail) {
         return recipient -> {
-            AttributeName attributeNameForUser = 
AttributeName.of(MailStore.DELIVERY_PATH_PREFIX + 
usersRepository.getUsername(recipient).asString());
-            mail.setAttribute(new Attribute(attributeNameForUser, 
targetFolderName));
+            Username username = usersRepository.getUsername(recipient);
+            targetFolderName.ifPresent(value -> mail.setAttribute(new 
Attribute(AttributeName.of(MailStore.DELIVERY_PATH_PREFIX + 
username.asString()), value)));
+            seen.ifPresent(value -> mail.setAttribute(new 
Attribute(AttributeName.of(MailStore.SEEN_PREFIX + username.asString()), 
value)));
+            important.ifPresent(value -> mail.setAttribute(new 
Attribute(AttributeName.of(MailStore.IMPORTANT_PREFIX + username.asString()), 
value)));
+            keywords.ifPresent(value -> mail.setAttribute(new 
Attribute(AttributeName.of(MailStore.KEYWORDS_PREFIX + username.asString()), 
value)));
         };
-
     }
 }
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java
index 598f934658..22241067e9 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java
@@ -25,6 +25,9 @@ import org.reactivestreams.Publisher;
 
 public interface MailStore {
     String DELIVERY_PATH_PREFIX = "DeliveryPath_";
+    String SEEN_PREFIX = "Seen_";
+    String IMPORTANT_PREFIX = "Important_";
+    String KEYWORDS_PREFIX = "Keywords_";
 
     Publisher<Void> storeMail(MailAddress recipient, Mail mail);
 }
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java
index 097b073d3e..0303f20976 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java
@@ -19,6 +19,9 @@
 
 package org.apache.james.transport.mailets.delivery;
 
+import java.util.Optional;
+
+import javax.mail.Flags;
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 
@@ -27,5 +30,5 @@ import org.apache.james.mailbox.model.ComposedMessageId;
 import org.reactivestreams.Publisher;
 
 public interface MailboxAppender {
-    Publisher<ComposedMessageId> append(MimeMessage mail, Username user, 
String folder) throws MessagingException;
+    Publisher<ComposedMessageId> append(MimeMessage mail, Username user, 
String folder, Optional<Flags> flags) throws MessagingException;
 }
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImpl.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImpl.java
index 76e500fd6e..ab59df51a1 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImpl.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImpl.java
@@ -21,7 +21,9 @@ package org.apache.james.transport.mailets.delivery;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Optional;
 
+import javax.mail.Flags;
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 
@@ -54,9 +56,9 @@ public class MailboxAppenderImpl implements MailboxAppender {
         this.mailboxManager = mailboxManager;
     }
 
-    public Mono<ComposedMessageId> append(MimeMessage mail, Username user, 
String folder) throws MessagingException {
+    public Mono<ComposedMessageId> append(MimeMessage mail, Username user, 
String folder, Optional<Flags> flags) throws MessagingException {
         MailboxSession session = createMailboxSession(user);
-        return append(mail, user, useSlashAsSeparator(folder, session), 
session)
+        return append(mail, user, useSlashAsSeparator(folder, session), flags, 
session)
             .map(AppendResult::getId);
     }
 
@@ -71,26 +73,29 @@ public class MailboxAppenderImpl implements MailboxAppender 
{
         return destination;
     }
 
-    private Mono<AppendResult> append(MimeMessage mail, Username user, String 
folder, MailboxSession mailboxSession) {
+    private Mono<AppendResult> append(MimeMessage mail, Username user, String 
folder, Optional<Flags> flags, MailboxSession mailboxSession) {
         MailboxPath mailboxPath = MailboxPath.forUser(user, folder);
         return Mono.using(
             () -> {
                 mailboxManager.startProcessingRequest(mailboxSession);
                 return mailboxSession;
             },
-            session -> appendMessageToMailbox(mail, session, mailboxPath),
+            session -> appendMessageToMailbox(mail, session, mailboxPath, 
flags),
             this::closeProcessing)
             .onErrorMap(MailboxException.class, e -> new 
MessagingException("Unable to access mailbox.", e));
     }
 
-    protected Mono<AppendResult> appendMessageToMailbox(MimeMessage mail, 
MailboxSession session, MailboxPath path) {
+    protected Mono<AppendResult> appendMessageToMailbox(MimeMessage mail, 
MailboxSession session, MailboxPath path, Optional<Flags> flags) {
         return createMailboxIfNotExist(session, path)
-            .flatMap(mailbox -> Mono.from(mailbox.appendMessageReactive(
-                MessageManager.AppendCommand.builder()
-                    .recent()
-                    .delivery()
-                    .build(extractContent(mail)),
-                session)));
+            .flatMap(mailbox -> 
Mono.from(mailbox.appendMessageReactive(appendCommand(flags).build(extractContent(mail)),
 session)));
+    }
+
+    private MessageManager.AppendCommand.Builder appendCommand(Optional<Flags> 
flags) {
+        MessageManager.AppendCommand.Builder builder = 
MessageManager.AppendCommand.builder()
+            .recent()
+            .delivery();
+        return flags.map(builder::withFlags)
+            .orElse(builder);
     }
 
     private Content extractContent(MimeMessage mail) {
diff --git 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java
 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java
index 96edbbeb4a..44d2de771b 100644
--- 
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java
+++ 
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java
@@ -19,6 +19,11 @@
 
 package org.apache.james.transport.mailets.delivery;
 
+import java.util.Collection;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import javax.mail.Flags;
 import javax.mail.MessagingException;
 
 import org.apache.james.core.MailAddress;
@@ -26,8 +31,10 @@ import org.apache.james.core.Username;
 import org.apache.james.metrics.api.Metric;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.mailet.Attribute;
 import org.apache.mailet.AttributeName;
 import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
 import org.apache.mailet.Mail;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -97,7 +104,9 @@ public class SimpleMailStore implements MailStore {
         String locatedFolder = locateFolder(username, mail);
 
         try {
-            return Mono.from(mailboxAppender.append(mail.getMessage(), 
username, locatedFolder))
+            return Mono.from(mailboxAppender.append(mail.getMessage(), 
username,
+                locateFolder(username, mail),
+                extractFlags(username, mail)))
                 .doOnSuccess(ids -> {
                     metric.increment();
                     LOGGER.info("Local delivered mail {} with messageId {} 
successfully from {} to {} in folder {} with composedMessageId {}",
@@ -108,7 +117,54 @@ public class SimpleMailStore implements MailStore {
             throw new RuntimeException("Could not retrieve mail message 
content", e);
         }
     }
-    
+
+    private Optional<Flags> extractFlags(Username username, Mail mail) {
+        Optional<Attribute> seen = 
mail.getAttribute(AttributeName.of(MailStore.SEEN_PREFIX + 
username.asString()));
+        Optional<Attribute> important = 
mail.getAttribute(AttributeName.of(MailStore.IMPORTANT_PREFIX + 
username.asString()));
+        Optional<Attribute> keywords = 
mail.getAttribute(AttributeName.of(MailStore.KEYWORDS_PREFIX + 
username.asString()));
+
+        if (seen.isEmpty() && important.isEmpty() && keywords.isEmpty()) {
+            return Optional.empty();
+        }
+
+        Flags flags = new Flags();
+        flags.add(encodeFlag(seen, Flags.Flag.SEEN));
+        flags.add(encodeFlag(important, Flags.Flag.FLAGGED));
+        extractKeywords(keywords).forEach(flags::add);
+
+        return Optional.of(flags);
+    }
+
+    @SuppressWarnings("unchecked")
+    private Stream<String> extractKeywords(Optional<Attribute> keywords) {
+        return keywords
+            .map(Attribute::getValue)
+            .map(AttributeValue::getValue)
+            .filter(Collection.class::isInstance)
+            .map(Collection.class::cast)
+            .stream()
+            .flatMap(Collection::stream)
+            .filter(AttributeValue.class::isInstance)
+            .map(AttributeValue.class::cast)
+            .map(a -> ((AttributeValue<?>) a).getValue())
+            .filter(String.class::isInstance)
+            .map(String.class::cast);
+    }
+
+    private Flags encodeFlag(Optional<Attribute> attr, Flags.Flag flag) {
+        Flags flags = new Flags();
+        attr.map(Attribute::getValue)
+            .map(AttributeValue::getValue)
+            .filter(Boolean.class::isInstance)
+            .map(Boolean.class::cast)
+            .ifPresent(seenFlag -> {
+                if (seenFlag) {
+                    flags.add(flag);
+                }
+            });
+        return flags;
+    }
+
     private String getMessageId(Mail mail) {
         try {
             return mail.getMessage().getMessageID();
diff --git 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java
 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java
index 5338cb8cc0..6ba7bf81c7 100644
--- 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java
+++ 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java
@@ -33,6 +33,7 @@ import org.apache.mailet.base.test.FakeMailetConfig;
 import org.assertj.core.api.SoftAssertions;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.testcontainers.shaded.com.google.common.collect.ImmutableSet;
 
 class WithStorageDirectiveTest {
     private static final DomainList NO_DOMAIN_LIST = null;
@@ -81,6 +82,102 @@ class WithStorageDirectiveTest {
                 new Attribute(recipient2, 
AttributeValue.of(targetFolderName)));
     }
 
+    @Test
+    void shouldSupportSeen() throws Exception {
+        testee.init(FakeMailetConfig.builder()
+            .setProperty(WithStorageDirective.SEEN, "true")
+            .build());
+
+        FakeMail mail = FakeMail.builder()
+            .name("name")
+            .recipients(MailAddressFixture.RECIPIENT1)
+            .build();
+
+        testee.service(mail);
+
+        AttributeName recipient1 = 
AttributeName.of("Seen_recipient1@localhost");
+        assertThat(mail.attributes())
+            .containsOnly(
+                new Attribute(recipient1, AttributeValue.of(true)));
+    }
+
+    @Test
+    void shouldSupportImportant() throws Exception {
+        testee.init(FakeMailetConfig.builder()
+            .setProperty(WithStorageDirective.IMPORTANT, "true")
+            .build());
+
+        FakeMail mail = FakeMail.builder()
+            .name("name")
+            .recipients(MailAddressFixture.RECIPIENT1)
+            .build();
+
+        testee.service(mail);
+
+        AttributeName recipient1 = 
AttributeName.of("Important_recipient1@localhost");
+        assertThat(mail.attributes())
+            .containsOnly(
+                new Attribute(recipient1, AttributeValue.of(true)));
+    }
+
+    @Test
+    void shouldSupportKeywords() throws Exception {
+        testee.init(FakeMailetConfig.builder()
+            .setProperty(WithStorageDirective.KEYWORDS, "abc,def")
+            .build());
+
+        FakeMail mail = FakeMail.builder()
+            .name("name")
+            .recipients(MailAddressFixture.RECIPIENT1)
+            .build();
+
+        testee.service(mail);
+
+        AttributeName recipient1 = 
AttributeName.of("Keywords_recipient1@localhost");
+        assertThat(mail.attributes())
+            .containsOnly(
+                new Attribute(recipient1, AttributeValue.of(ImmutableSet.of(
+                    AttributeValue.of("abc"),
+                    AttributeValue.of("def")))));
+    }
+
+    @Test
+    void shouldSanitizeKeywords() throws Exception {
+        testee.init(FakeMailetConfig.builder()
+            .setProperty(WithStorageDirective.KEYWORDS, "abc, def,,")
+            .build());
+
+        FakeMail mail = FakeMail.builder()
+            .name("name")
+            .recipients(MailAddressFixture.RECIPIENT1)
+            .build();
+
+        testee.service(mail);
+
+        AttributeName recipient1 = 
AttributeName.of("Keywords_recipient1@localhost");
+        assertThat(mail.attributes())
+            .containsOnly(
+                new Attribute(recipient1, AttributeValue.of(ImmutableSet.of(
+                    AttributeValue.of("abc"),
+                    AttributeValue.of("def")))));
+    }
+
+    @Test
+    void shouldRejectBadSeenValue() {
+        assertThatThrownBy(() -> testee.init(FakeMailetConfig.builder()
+            .setProperty(WithStorageDirective.SEEN, "bad")
+            .build()))
+            .isInstanceOf(IllegalStateException.class);
+    }
+
+    @Test
+    void shouldRejectBadImportantValue() {
+        assertThatThrownBy(() -> testee.init(FakeMailetConfig.builder()
+            .setProperty(WithStorageDirective.IMPORTANT, "bad")
+            .build()))
+            .isInstanceOf(IllegalStateException.class);
+    }
+
     @Test
     void serviceShouldNotThrowWhenNoRecipients() throws Exception {
         String targetFolderName = "Spam";
diff --git 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImplTest.java
 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImplTest.java
index e50ffa49d6..e9a007975e 100644
--- 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImplTest.java
+++ 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImplTest.java
@@ -23,7 +23,9 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.time.Duration;
+import java.util.Optional;
 
+import javax.mail.Flags;
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 
@@ -48,6 +50,7 @@ class MailboxAppenderImplTest {
     public static final Username USER = Username.of("user");
     public static final String FOLDER = "folder";
     public static final String EMPTY_FOLDER = "";
+    private static final Optional<Flags> NO_FLAGS = Optional.empty();
 
     private MailboxAppenderImpl testee;
     private MailboxManager mailboxManager;
@@ -70,7 +73,7 @@ class MailboxAppenderImplTest {
 
     @Test
     void appendShouldAddMessageToDesiredMailbox() throws Exception {
-        Mono.from(testee.append(mimeMessage, USER, FOLDER)).block();
+        Mono.from(testee.append(mimeMessage, USER, FOLDER, NO_FLAGS)).block();
 
         MessageResultIterator messages = 
mailboxManager.getMailbox(MailboxPath.forUser(USER, FOLDER), session)
             .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session);
@@ -84,7 +87,7 @@ class MailboxAppenderImplTest {
         MailboxPath mailboxPath = MailboxPath.forUser(USER, FOLDER);
         mailboxManager.createMailbox(mailboxPath, session);
 
-        Mono.from(testee.append(mimeMessage, USER, FOLDER)).block();
+        Mono.from(testee.append(mimeMessage, USER, FOLDER, NO_FLAGS)).block();
 
         MessageResultIterator messages = 
mailboxManager.getMailbox(mailboxPath, session)
             .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session);
@@ -95,13 +98,13 @@ class MailboxAppenderImplTest {
 
     @Test
     void appendShouldNotAppendToEmptyFolder() {
-        assertThatThrownBy(() -> Mono.from(testee.append(mimeMessage, USER, 
EMPTY_FOLDER)).block())
+        assertThatThrownBy(() -> Mono.from(testee.append(mimeMessage, USER, 
EMPTY_FOLDER, NO_FLAGS)).block())
             .isInstanceOf(MessagingException.class);
     }
 
     @Test
     void appendShouldRemovePathSeparatorAsFirstChar() throws Exception {
-        Mono.from(testee.append(mimeMessage, USER, "." + FOLDER)).block();
+        Mono.from(testee.append(mimeMessage, USER, "." + FOLDER, 
NO_FLAGS)).block();
 
         MessageResultIterator messages = 
mailboxManager.getMailbox(MailboxPath.forUser(USER, FOLDER), session)
             .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session);
@@ -110,9 +113,19 @@ class MailboxAppenderImplTest {
             .hasSize(1);
     }
 
+    @Test
+    void appendShouldSupportFlags() throws Exception {
+        Mono.from(testee.append(mimeMessage, USER, "." + FOLDER, 
Optional.of(new Flags(Flags.Flag.SEEN)))).block();
+
+        MessageResultIterator messages = 
mailboxManager.getMailbox(MailboxPath.forUser(USER, FOLDER), session)
+            .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session);
+
+        
assertThat(messages.next().getFlags().contains(Flags.Flag.SEEN)).isTrue();
+    }
+
     @Test
     void appendShouldReplaceSlashBySeparator() throws Exception {
-        Mono.from(testee.append(mimeMessage, USER, FOLDER + "/any")).block();
+        Mono.from(testee.append(mimeMessage, USER, FOLDER + "/any", 
NO_FLAGS)).block();
 
         MessageResultIterator messages = 
mailboxManager.getMailbox(MailboxPath.forUser(USER, FOLDER + ".any"), session)
             .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session);
@@ -124,7 +137,7 @@ class MailboxAppenderImplTest {
     @RepeatedTest(20)
     void appendShouldNotFailInConcurrentEnvironment() throws Exception {
         ConcurrentTestRunner.builder()
-            .reactorOperation((a, b) -> Mono.from(testee.append(mimeMessage, 
USER, FOLDER + "/any")).then())
+            .reactorOperation((a, b) -> Mono.from(testee.append(mimeMessage, 
USER, FOLDER + "/any", NO_FLAGS)).then())
             .threadCount(100)
             .runSuccessfullyWithin(Duration.ofMinutes(1));
     }
diff --git 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java
 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java
index d57e070e59..fabb57a14f 100644
--- 
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java
+++ 
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java
@@ -50,7 +50,7 @@ class SimpleMailStoreTest {
     @BeforeEach
     void setUp() throws Exception {
         mailboxAppender = mock(MailboxAppenderImpl.class);
-        when(mailboxAppender.append(any(), any(), 
any())).thenReturn(Mono.empty());
+        when(mailboxAppender.append(any(), any(), any(), 
any())).thenReturn(Mono.empty());
         usersRepository = mock(UsersRepository.class);
         testee = SimpleMailStore.builder()
             .usersRepository(usersRepository)
@@ -76,7 +76,7 @@ class SimpleMailStoreTest {
             .build();
         testee.storeMail(recipient, mail);
 
-        verify(mailboxAppender).append(any(MimeMessage.class), 
eq(Username.of(recipient.asString())), eq(FOLDER));
+        verify(mailboxAppender).append(any(MimeMessage.class), 
eq(Username.of(recipient.asString())), eq(FOLDER), any());
     }
 
     @Test
@@ -89,7 +89,7 @@ class SimpleMailStoreTest {
             .build();
         testee.storeMail(recipient, mail);
 
-        verify(mailboxAppender).append(any(MimeMessage.class), 
eq(Username.of(recipient.getLocalPart())), eq(FOLDER));
+        verify(mailboxAppender).append(any(MimeMessage.class), 
eq(Username.of(recipient.getLocalPart())), eq(FOLDER), any());
     }
 
     @Test
@@ -102,6 +102,6 @@ class SimpleMailStoreTest {
             .build();
         testee.storeMail(recipient, mail);
 
-        verify(mailboxAppender).append(any(MimeMessage.class), 
eq(Username.of(recipient.toString())), eq(FOLDER));
+        verify(mailboxAppender).append(any(MimeMessage.class), 
eq(Username.of(recipient.toString())), eq(FOLDER), any());
     }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to