JAMES-1854 Sieve should be handled as a separate mailet
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/71accd66 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/71accd66 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/71accd66 Branch: refs/heads/master Commit: 71accd66d33dfec90a3efe3011170b5e90d4b90b Parents: 6a2d188 Author: Benoit Tellier <[email protected]> Authored: Fri Nov 18 14:33:32 2016 +0700 Committer: Benoit Tellier <[email protected]> Committed: Wed Nov 23 18:19:35 2016 +0700 ---------------------------------------------------------------------- .../guice/destination/conf/mailetcontainer.xml | 1 + .../spring/destination/conf/mailetcontainer.xml | 1 + .../main/resources/mailetcontainer-template.xml | 1 + .../apache/james/utils/ExtendedServerProbe.java | 2 + .../apache/james/utils/GuiceServerProbe.java | 7 +- .../org/apache/james/mailets/SieveDelivery.java | 98 ++++ .../mailets/configuration/CommonProcessors.java | 4 + .../james/mailets/utils/IMAPMessageReader.java | 6 +- .../apache/james/transport/mailets/Sieve.java | 135 +++++ .../transport/mailets/SieveLocalDelivery.java | 103 ---- .../mailets/SieveToRecipientFolder.java | 105 ---- .../transport/mailets/delivery/MailStore.java | 2 + .../mailets/delivery/MailboxAppender.java | 11 +- .../mailets/delivery/SimpleMailStore.java | 12 +- .../transport/mailets/jsieve/ActionContext.java | 3 +- .../mailets/jsieve/FileIntoAction.java | 35 +- .../james/transport/mailets/jsieve/Poster.java | 4 +- .../mailets/jsieve/RedirectAction.java | 1 - .../transport/mailets/jsieve/RejectAction.java | 2 - .../mailets/jsieve/SieveMailAdapter.java | 3 +- .../mailets/jsieve/delivery/SieveExecutor.java | 192 +++++++ .../mailets/jsieve/delivery/SieveMailStore.java | 202 -------- .../mailets/jsieve/delivery/SievePoster.java | 20 +- .../mailets/delivery/LocalDeliveryTest.java | 107 +--- .../mailets/delivery/MailDispatcherTest.java | 1 - .../mailets/delivery/MailboxAppenderTest.java | 47 +- .../mailets/delivery/SieveIntegrationTest.java | 495 ++++++++----------- .../mailets/delivery/SimpleMailStoreTest.java | 6 +- .../mailets/delivery/ToRecipientFolderTest.java | 130 ++--- .../src/test/resources/mailetcontainer.xml | 1 + .../src/test/resources/mailetcontainer.xml | 1 + .../src/test/resources/mailetcontainer.xml | 1 + 32 files changed, 774 insertions(+), 965 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/dockerfiles/run/guice/destination/conf/mailetcontainer.xml ---------------------------------------------------------------------- diff --git a/dockerfiles/run/guice/destination/conf/mailetcontainer.xml b/dockerfiles/run/guice/destination/conf/mailetcontainer.xml index 25195ea..5008caa 100644 --- a/dockerfiles/run/guice/destination/conf/mailetcontainer.xml +++ b/dockerfiles/run/guice/destination/conf/mailetcontainer.xml @@ -85,6 +85,7 @@ </mailet> <mailet match="All" class="RecipientRewriteTable" /> <mailet match="RecipientIsLocal" class="org.apache.james.jmap.mailet.VacationMailet"/> + <mailet match="RecipientIsLocal" class="Sieve"/> <mailet match="RecipientIsLocal" class="LocalDelivery"/> <!-- <mailet match="HostIsLocal" class="ToProcessor"> http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/dockerfiles/run/spring/destination/conf/mailetcontainer.xml ---------------------------------------------------------------------- diff --git a/dockerfiles/run/spring/destination/conf/mailetcontainer.xml b/dockerfiles/run/spring/destination/conf/mailetcontainer.xml index a62885c..710fd8c 100644 --- a/dockerfiles/run/spring/destination/conf/mailetcontainer.xml +++ b/dockerfiles/run/spring/destination/conf/mailetcontainer.xml @@ -81,6 +81,7 @@ <value>true</value> </mailet> <mailet match="All" class="RecipientRewriteTable" /> + <mailet match="RecipientIsLocal" class="Sieve"/> <mailet match="RecipientIsLocal" class="LocalDelivery"/> <mailet match="HostIsLocal" class="ToProcessor"> <processor>local-address-error</processor> http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/app/src/main/resources/mailetcontainer-template.xml ---------------------------------------------------------------------- diff --git a/server/app/src/main/resources/mailetcontainer-template.xml b/server/app/src/main/resources/mailetcontainer-template.xml index 9ca8191..2e3901a 100644 --- a/server/app/src/main/resources/mailetcontainer-template.xml +++ b/server/app/src/main/resources/mailetcontainer-template.xml @@ -430,6 +430,7 @@ Regards, Postmaster XXX.YYY </mailet> <!-- Is the recipient is for a local account, deliver it locally --> + <mailet match="RecipientIsLocal" class="Sieve"/> <mailet match="RecipientIsLocal" class="LocalDelivery"/> <!-- If the host is handled by this server and it did not get --> http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/container/guice/guice-common/src/main/java/org/apache/james/utils/ExtendedServerProbe.java ---------------------------------------------------------------------- diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/ExtendedServerProbe.java b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/ExtendedServerProbe.java index 7bc1a39..663215f 100644 --- a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/ExtendedServerProbe.java +++ b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/ExtendedServerProbe.java @@ -37,4 +37,6 @@ public interface ExtendedServerProbe extends ServerProbe { Mailbox getMailbox(String namespace, String user, String name); + void addActiveSieveScript(String user, String name, String script) throws Exception; + } http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/container/guice/guice-common/src/main/java/org/apache/james/utils/GuiceServerProbe.java ---------------------------------------------------------------------- diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/GuiceServerProbe.java b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/GuiceServerProbe.java index e7457dd..61fd063 100644 --- a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/GuiceServerProbe.java +++ b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/GuiceServerProbe.java @@ -62,8 +62,8 @@ public class GuiceServerProbe implements ExtendedServerProbe, GuiceProbe { private final MailboxMapperFactory mailboxMapperFactory; private final DomainList domainList; private final UsersRepository usersRepository; - private final SieveRepository sieveRepository; private final RecipientRewriteTable recipientRewriteTable; + private final SieveRepository sieveRepository; @Inject private GuiceServerProbe(MailboxManager mailboxManager, MailboxMapperFactory mailboxMapperFactory, @@ -349,4 +349,9 @@ public class GuiceServerProbe implements ExtendedServerProbe, GuiceProbe { sieveRepository.removeQuota(user); } + @Override + public void addActiveSieveScript(String user, String name, String script) throws Exception { + sieveRepository.putScript(user, name, script); + sieveRepository.setActive(user, name); + } } http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SieveDelivery.java ---------------------------------------------------------------------- diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SieveDelivery.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SieveDelivery.java new file mode 100644 index 0000000..950eefd --- /dev/null +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/SieveDelivery.java @@ -0,0 +1,98 @@ +/**************************************************************** + * 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.mailets; + +import org.apache.james.mailbox.model.MailboxConstants; +import org.apache.james.mailets.configuration.CommonProcessors; +import org.apache.james.mailets.configuration.MailetContainer; +import org.apache.james.mailets.utils.IMAPMessageReader; +import org.apache.james.mailets.utils.SMTPMessageSender; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import com.jayway.awaitility.Awaitility; +import com.jayway.awaitility.Duration; +import com.jayway.awaitility.core.ConditionFactory; + +public class SieveDelivery { + + private static final String DEFAULT_DOMAIN = "james.org"; + private static final String LOCALHOST_IP = "127.0.0.1"; + private static final int IMAP_PORT = 1143; + private static final int SMTP_PORT = 1025; + private static final String PASSWORD = "secret"; + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + private TemporaryJamesServer jamesServer; + private ConditionFactory calmlyAwait; + + @Before + public void setup() throws Exception { + MailetContainer mailetContainer = MailetContainer.builder() + .postmaster("postmaster@" + DEFAULT_DOMAIN) + .threads(5) + .addProcessor(CommonProcessors.root()) + .addProcessor(CommonProcessors.error()) + .addProcessor(CommonProcessors.transport()) + .addProcessor(CommonProcessors.spam()) + .addProcessor(CommonProcessors.localAddressError()) + .addProcessor(CommonProcessors.relayDenied()) + .addProcessor(CommonProcessors.bounces()) + .addProcessor(CommonProcessors.sieveManagerCheck()) + .build(); + + jamesServer = new TemporaryJamesServer(temporaryFolder, mailetContainer); + Duration slowPacedPollInterval = Duration.FIVE_HUNDRED_MILLISECONDS; + calmlyAwait = Awaitility.with().pollInterval(slowPacedPollInterval).and().with().pollDelay(slowPacedPollInterval).await(); + } + + @After + public void tearDown() { + jamesServer.shutdown(); + } + + @Test + public void simpleMailShouldBeSent() throws Exception { + String from = "user@" + DEFAULT_DOMAIN; + String recipient = "user2@" + DEFAULT_DOMAIN; + String targetedMailbox = "INBOX.any"; + + jamesServer.getServerProbe().addDomain(DEFAULT_DOMAIN); + jamesServer.getServerProbe().addUser(from, PASSWORD); + jamesServer.getServerProbe().addUser(recipient, PASSWORD); + jamesServer.getServerProbe().createMailbox(MailboxConstants.USER_NAMESPACE, recipient, "INBOX"); + jamesServer.getServerProbe().createMailbox(MailboxConstants.USER_NAMESPACE, recipient, targetedMailbox); + jamesServer.getServerProbe().addActiveSieveScript(recipient, "myscript.sieve", "require \"fileinto\";\n" + + "\n" + + "fileinto \"" + targetedMailbox + "\";"); + + try (SMTPMessageSender messageSender = SMTPMessageSender.noAuthentication(LOCALHOST_IP, SMTP_PORT, DEFAULT_DOMAIN); + IMAPMessageReader imapMessageReader = new IMAPMessageReader(LOCALHOST_IP, IMAP_PORT)) { + messageSender.sendMessage(from, recipient); + calmlyAwait.atMost(Duration.ONE_MINUTE).until(messageSender::messageHasBeenSent); + calmlyAwait.atMost(Duration.ONE_MINUTE).until(() -> imapMessageReader.userReceivedMessageInMailbox(recipient, PASSWORD, targetedMailbox)); + } + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/CommonProcessors.java ---------------------------------------------------------------------- diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/CommonProcessors.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/CommonProcessors.java index 294f01c..a259504 100644 --- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/CommonProcessors.java +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/configuration/CommonProcessors.java @@ -120,6 +120,10 @@ public class CommonProcessors { .build()) .addMailet(MailetConfiguration.builder() .match("RecipientIsLocal") + .clazz("Sieve") + .build()) + .addMailet(MailetConfiguration.builder() + .match("RecipientIsLocal") .clazz("LocalDelivery") .build()) .addMailet(MailetConfiguration.builder() http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/utils/IMAPMessageReader.java ---------------------------------------------------------------------- diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/utils/IMAPMessageReader.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/utils/IMAPMessageReader.java index 219040c..cfeda6c 100644 --- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/utils/IMAPMessageReader.java +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/utils/IMAPMessageReader.java @@ -34,8 +34,12 @@ public class IMAPMessageReader implements Closeable { } public boolean userReceivedMessage(String user, String password) throws IOException { + return userReceivedMessageInMailbox(user, password, "INBOX"); + } + + public boolean userReceivedMessageInMailbox(String user, String password, String mailbox) throws IOException { imapClient.login(user, password); - imapClient.select("INBOX"); + imapClient.select(mailbox); imapClient.fetch("1:1", "ALL"); return imapClient.getReplyString() .contains("OK FETCH completed"); http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Sieve.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Sieve.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Sieve.java new file mode 100644 index 0000000..56c7f1d --- /dev/null +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/Sieve.java @@ -0,0 +1,135 @@ +/**************************************************************** + * 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.transport.mailets; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; +import javax.mail.MessagingException; + +import org.apache.commons.logging.Log; +import org.apache.james.mailbox.model.MailboxConstants; +import org.apache.james.sieverepository.api.SieveRepository; +import org.apache.james.transport.mailets.delivery.MailStore; +import org.apache.james.transport.mailets.jsieve.CommonsLoggingAdapter; +import org.apache.james.transport.mailets.jsieve.ResourceLocator; +import org.apache.james.transport.mailets.jsieve.delivery.SieveExecutor; +import org.apache.james.transport.mailets.jsieve.delivery.SievePoster; +import org.apache.james.user.api.UsersRepository; +import org.apache.james.user.api.UsersRepositoryException; +import org.apache.mailet.Mail; +import org.apache.mailet.MailAddress; +import org.apache.mailet.base.GenericMailet; + +import com.google.common.base.Predicate; +import com.google.common.collect.FluentIterable; +import com.google.common.collect.ImmutableList; + +/** + * Execute Sieve scripts for incoming emails, and set the result of the execution as attributes of the mail + */ +public class Sieve extends GenericMailet { + + private final UsersRepository usersRepository; + private final ResourceLocator resourceLocator; + private SieveExecutor sieveExecutor; + + @Inject + public Sieve(UsersRepository usersRepository, SieveRepository sieveRepository) throws MessagingException { + this(usersRepository, ResourceLocatorImpl.instanciate(usersRepository, sieveRepository)); + } + + public Sieve(UsersRepository usersRepository, ResourceLocator resourceLocator) throws MessagingException { + this.usersRepository = usersRepository; + this.resourceLocator = resourceLocator; + } + + @Override + public String getMailetInfo() { + return "Sieve Mailet"; + } + + @Override + public void init() throws MessagingException { + Log log = CommonsLoggingAdapter.builder() + .wrappedLogger(getMailetContext().getLogger()) + .quiet(getInitParameter("quiet", false)) + .verbose(getInitParameter("verbose", false)) + .build(); + sieveExecutor = SieveExecutor.builder() + .resourceLocator(resourceLocator) + .usersRepository(usersRepository) + .mailetContext(getMailetContext()) + .log(log) + .sievePoster(new SievePoster(usersRepository, MailboxConstants.INBOX)) + .build(); + } + + @Override + public void service(Mail mail) throws MessagingException { + for(MailAddress recipient: mail.getRecipients()) { + executeSieveScript(mail, recipient); + } + mail.setRecipients(keepNonDiscardedRecipients(mail)); + } + + private void executeSieveScript(Mail mail, MailAddress recipient) { + try { + sieveExecutor.execute(recipient, mail); + } catch (Exception e) { + getMailetContext().getLogger().warn("Failed to execute Sieve script for user " + recipient.asPrettyString(), e); + } + } + + + private ImmutableList<MailAddress> keepNonDiscardedRecipients(Mail mail) { + final List<MailAddress> discardedRecipients = retrieveDiscardedRecipients(mail); + return FluentIterable.from(mail.getRecipients()).filter(new Predicate<MailAddress>() { + @Override + public boolean apply(MailAddress input) { + return !discardedRecipients.contains(input); + } + }).toList(); + } + + private List<MailAddress> retrieveDiscardedRecipients(Mail mail) { + final List<MailAddress> discardedRecipients = new ArrayList<MailAddress>(); + for(MailAddress recipient: mail.getRecipients()) { + if (isDiscarded(mail, recipient)) { + discardedRecipients.add(recipient); + } + } + return discardedRecipients; + } + + private boolean isDiscarded(Mail mail, MailAddress recipient) { + return !(mail.getAttribute(MailStore.DELIVERY_PATH_PREFIX + retrieveUser(recipient)) instanceof String); + } + + private String retrieveUser(MailAddress recipient) { + try { + return usersRepository.getUser(recipient); + } catch (UsersRepositoryException e) { + log("Can not retrieve username for mail address " + recipient.asPrettyString(), e); + return recipient.asString(); + } + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SieveLocalDelivery.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SieveLocalDelivery.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SieveLocalDelivery.java deleted file mode 100644 index 99154bc..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SieveLocalDelivery.java +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************** - * 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.transport.mailets; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.mail.MessagingException; - -import org.apache.commons.logging.Log; -import org.apache.james.domainlist.api.DomainList; -import org.apache.james.mailbox.MailboxManager; -import org.apache.james.mailbox.model.MailboxConstants; -import org.apache.james.sieverepository.api.SieveRepository; -import org.apache.james.transport.mailets.delivery.MailDispatcher; -import org.apache.james.transport.mailets.delivery.MailboxAppender; -import org.apache.james.transport.mailets.jsieve.delivery.SieveMailStore; -import org.apache.james.transport.mailets.jsieve.delivery.SievePoster; -import org.apache.james.transport.mailets.jsieve.CommonsLoggingAdapter; -import org.apache.james.user.api.UsersRepository; -import org.apache.mailet.Mail; -import org.apache.mailet.base.GenericMailet; - -/** - * Receives a Mail from the Queue and takes care of delivery of the - * message to local inboxes applying SIEVE rules. - * - * This mailet is a composition of RecipientRewriteTable, SieveMailet - * and MailboxManager configured to mimic the old "LocalDelivery" - * James 2.3 behavior. - */ -public class SieveLocalDelivery extends GenericMailet { - - private final UsersRepository usersRepository; - private final MailboxManager mailboxManager; - private final SieveRepository sieveRepository; - private final RecipientRewriteTable recipientRewriteTable; - private MailDispatcher mailDispatcher; - - @Inject - public SieveLocalDelivery(UsersRepository usersRepository, @Named("mailboxmanager") MailboxManager mailboxManager, - SieveRepository sieveRepository, org.apache.james.rrt.api.RecipientRewriteTable rrt, DomainList domainList) { - this.usersRepository = usersRepository; - this.mailboxManager = mailboxManager; - this.sieveRepository = sieveRepository; - this.recipientRewriteTable = new RecipientRewriteTable(); - this.recipientRewriteTable.setDomainList(domainList); - this.recipientRewriteTable.setRecipientRewriteTable(rrt); - } - - public void service(Mail mail) throws MessagingException { - recipientRewriteTable.service(mail); - mailDispatcher.dispatch(mail); - } - - public String getMailetInfo() { - return "Sieve Local Delivery Mailet"; - } - - public void init() throws MessagingException { - recipientRewriteTable.init(getMailetConfig()); - - Log log = CommonsLoggingAdapter.builder() - .wrappedLogger(getMailetContext().getLogger()) - .quiet(getInitParameter("quiet", false)) - .verbose(getInitParameter("verbose", false)) - .build(); - - mailDispatcher = MailDispatcher.builder() - .mailStore(SieveMailStore.builder() - .sievePoster(new SievePoster( - new MailboxAppender(mailboxManager, getMailetContext().getLogger()), - MailboxConstants.INBOX, - usersRepository)) - .usersRepository(usersRepository) - .resourceLocator(ResourceLocatorImpl.instanciate(usersRepository, sieveRepository)) - .mailetContext(getMailetContext()) - .folder(MailboxConstants.INBOX) - .log(log) - .build()) - .consume(getInitParameter("consume", true)) - .mailetContext(getMailetContext()) - .log(log) - .build(); - } - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SieveToRecipientFolder.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SieveToRecipientFolder.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SieveToRecipientFolder.java deleted file mode 100644 index ca66055..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/SieveToRecipientFolder.java +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************** - * 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.transport.mailets; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.mail.MessagingException; - -import org.apache.commons.logging.Log; -import org.apache.james.mailbox.MailboxManager; -import org.apache.james.mailbox.model.MailboxConstants; -import org.apache.james.sieverepository.api.SieveRepository; -import org.apache.james.transport.mailets.delivery.MailDispatcher; -import org.apache.james.transport.mailets.delivery.MailboxAppender; -import org.apache.james.transport.mailets.jsieve.delivery.SieveMailStore; -import org.apache.james.transport.mailets.jsieve.delivery.SievePoster; -import org.apache.james.transport.mailets.jsieve.CommonsLoggingAdapter; -import org.apache.james.user.api.UsersRepository; -import org.apache.mailet.Mail; -import org.apache.mailet.base.GenericMailet; - -/** - * Receives a Mail from the Queue and takes care to deliver the message - * to a defined folder of the recipient(s) applying SIEVE rules. - * - * You have to define the folder name of the recipient(s). - * The flag 'consume' will tell is the mail will be further - * processed by the upcoming processor mailets, or not. - * - * <pre> - * <mailet match="RecipientIsLocal" class="ToRecipientFolder"> - * <folder> <i>Junk</i> </folder> - * <consume> <i>false</i> </consume> - * </mailet> - * </pre> - * - */ -public class SieveToRecipientFolder extends GenericMailet { - - public static final String FOLDER_PARAMETER = "folder"; - public static final String CONSUME_PARAMETER = "consume"; - - private final MailboxManager mailboxManager; - private final SieveRepository sieveRepository; - private final UsersRepository usersRepository; - private MailDispatcher mailDispatcher; - - @Inject - public SieveToRecipientFolder(@Named("mailboxmanager")MailboxManager mailboxManager, SieveRepository sieveRepository, - UsersRepository usersRepository) { - this.mailboxManager = mailboxManager; - this.sieveRepository = sieveRepository; - this.usersRepository = usersRepository; - } - - @Override - public void service(Mail mail) throws MessagingException { - mailDispatcher.dispatch(mail); - } - - @Override - public void init() throws MessagingException { - Log log = CommonsLoggingAdapter.builder() - .wrappedLogger(getMailetContext().getLogger()) - .quiet(getInitParameter("quiet", true)) - .verbose(getInitParameter("verbose", false)) - .build(); - String folder = getInitParameter(FOLDER_PARAMETER, MailboxConstants.INBOX); - mailDispatcher = MailDispatcher.builder() - .mailStore(SieveMailStore.builder() - .sievePoster(new SievePoster(new MailboxAppender(mailboxManager, getMailetContext().getLogger()), folder, usersRepository)) - .usersRepository(usersRepository) - .resourceLocator(ResourceLocatorImpl.instanciate(usersRepository, sieveRepository)) - .mailetContext(getMailetContext()) - .folder(folder) - .log(log) - .build()) - .consume(getInitParameter(CONSUME_PARAMETER, false)) - .mailetContext(getMailetContext()) - .log(log) - .build(); - } - - @Override - public String getMailetInfo() { - return SieveToRecipientFolder.class.getName() + " Mailet"; - } - -} http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java ---------------------------------------------------------------------- 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 567e9ec..4082d4f 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,5 +25,7 @@ import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; public interface MailStore { + String DELIVERY_PATH_PREFIX = "DeliveryPath_"; + void storeMail(MailAddress recipient, Mail mail) throws MessagingException; } http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java ---------------------------------------------------------------------- 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 64c72cb..c8dacb9 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 @@ -50,18 +50,13 @@ public class MailboxAppender { public void append(MimeMessage mail, String user, String folder) throws MessagingException { MailboxSession session = createMailboxSession(user); - append(mail, user, folder, session); + append(mail, user, useSlashAsSeparator(folder, session), session); } - public void appendAndUseSlashAsSeparator(MimeMessage mail, String user, String folder, String fallbackFolder) throws MessagingException { - MailboxSession session = createMailboxSession(user); - append(mail, user, useSlashAsSeparator(folder, session, fallbackFolder)); - } - - private String useSlashAsSeparator(String urlPath, MailboxSession session, String fallbackFolder) { + private String useSlashAsSeparator(String urlPath, MailboxSession session) throws MessagingException { String destination = urlPath.replace('/', session.getPathDelimiter()); if (Strings.isNullOrEmpty(destination)) { - destination = fallbackFolder; + throw new MessagingException("Mail can not be delivered to empty folder"); } if (destination.charAt(0) == session.getPathDelimiter()) { destination = destination.substring(1); http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java ---------------------------------------------------------------------- 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 db21a22..d693065 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 @@ -86,10 +86,18 @@ public class SimpleMailStore implements MailStore { public void storeMail(MailAddress recipient, Mail mail) throws MessagingException { String username = computeUsername(recipient); - mailboxAppender.append(mail.getMessage(), username, folder); + String locatedFolder = locateFolder(username, mail); + mailboxAppender.append(mail.getMessage(), username, locatedFolder); log.info("Local delivered mail " + mail.getName() + " successfully from " + DeliveryUtils.prettyPrint(mail.getSender()) - + " to " + DeliveryUtils.prettyPrint(recipient) + " in folder " + this.folder); + + " to " + DeliveryUtils.prettyPrint(recipient) + " in folder " + locatedFolder); + } + + private String locateFolder(String username, Mail mail) { + if (mail.getAttribute(DELIVERY_PATH_PREFIX + username) instanceof String) { + return (String) mail.getAttribute(DELIVERY_PATH_PREFIX + username); + } + return folder; } private String computeUsername(MailAddress recipient) throws MessagingException { http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionContext.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionContext.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionContext.java index 0f78115..5203279 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionContext.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/ActionContext.java @@ -24,6 +24,7 @@ import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import org.apache.commons.logging.Log; +import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; import org.joda.time.DateTime; @@ -62,7 +63,7 @@ public interface ActionContext { * the value should be mailbox://<user>@localhost/<mailbox-path> * @param mail not null */ - public void post(String uri, MimeMessage mail) throws MessagingException; + public void post(String uri, Mail mail) throws MessagingException; /** * Posts the given mail. http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/FileIntoAction.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/FileIntoAction.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/FileIntoAction.java index 3d2bcd7..1c91bba 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/FileIntoAction.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/FileIntoAction.java @@ -77,7 +77,6 @@ public class FileIntoAction implements MailAction { try { recipient = ActionUtils.getSoleRecipient(aMail); - MimeMessage localMessage = createMimeMessage(aMail, recipient); if (!(destinationMailbox.length() > 0 && destinationMailbox.charAt(0) == HIERARCHY_DELIMITER)) { @@ -85,15 +84,9 @@ public class FileIntoAction implements MailAction { } final String mailbox = destinationMailbox.replace(HIERARCHY_DELIMITER, '/'); - final String host; - if (mailbox.charAt(0) == '/') { - host = "@localhost"; - } else { - host = "@localhost/"; - } - final String url = "mailbox://" + recipient.getUser() + host + mailbox; + final String url = "mailbox://" + recipient.asString() + mailbox; //TODO: copying this message so many times seems a waste - context.post(url, localMessage); + context.post(url, aMail); delivered = true; } catch (MessagingException ex) @@ -104,11 +97,6 @@ public class FileIntoAction implements MailAction { } throw ex; } - finally - { - // Ensure the mail is always ghosted - aMail.setState(Mail.GHOST); - } if (delivered) { final Log log = context.getLog(); @@ -120,23 +108,4 @@ public class FileIntoAction implements MailAction { } } } - - private static MimeMessage createMimeMessage(Mail aMail, MailAddress recipient) throws MessagingException { - // Adapted from LocalDelivery Mailet - // Add qmail's de facto standard Delivered-To header - MimeMessage localMessage = new MimeMessage(aMail.getMessage()) - { - protected void updateHeaders() throws MessagingException - { - if (getMessageID() == null) - super.updateHeaders(); - else - modified = false; - } - }; - localMessage.addHeader("Delivered-To", recipient.toString()); - - localMessage.saveChanges(); - return localMessage; - } } http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/Poster.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/Poster.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/Poster.java index aa77e0b..c86d352 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/Poster.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/Poster.java @@ -22,6 +22,8 @@ package org.apache.james.transport.mailets.jsieve; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; +import org.apache.mailet.Mail; + /** * Experimental interface. */ @@ -36,5 +38,5 @@ public interface Poster { * the value should be mailbox://<user>@localhost/<mailbox-path> * @param mail not null */ - public void post(String uri, MimeMessage mail) throws MessagingException; + void post(String uri, Mail mail) throws MessagingException; } http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RedirectAction.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RedirectAction.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RedirectAction.java index c56fe4f..4096e34 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RedirectAction.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RedirectAction.java @@ -61,7 +61,6 @@ public class RedirectAction implements MailAction { recipients.add(new MailAddress(new InternetAddress(anAction.getAddress()))); MailAddress sender = aMail.getSender(); context.post(sender, recipients, aMail.getMessage()); - aMail.setState(Mail.GHOST); Log log = context.getLog(); if (log.isDebugEnabled()) { log.debug("Redirected Message ID: " http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RejectAction.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RejectAction.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RejectAction.java index f792f82..ecd6f9a 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RejectAction.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/RejectAction.java @@ -137,8 +137,6 @@ public class RejectAction implements MailAction { { context.getLog().info("Unable to send reject MDN. Could not determine the recipient."); } - // Ghost the original mail - aMail.setState(Mail.GHOST); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/SieveMailAdapter.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/SieveMailAdapter.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/SieveMailAdapter.java index e70bd6d..b046341 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/SieveMailAdapter.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/SieveMailAdapter.java @@ -440,7 +440,8 @@ public class SieveMailAdapter implements MailAdapter, EnvelopeAccessors, ActionC public String getServerInfo() { return getMailetContext().getServerInfo(); } - public void post(String uri, MimeMessage mail) throws MessagingException { + + public void post(String uri, Mail mail) throws MessagingException { poster.post(uri, mail); } http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveExecutor.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveExecutor.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveExecutor.java new file mode 100644 index 0000000..341a710 --- /dev/null +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveExecutor.java @@ -0,0 +1,192 @@ +/**************************************************************** + * 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.transport.mailets.jsieve.delivery; + +import java.io.IOException; + +import javax.mail.MessagingException; + +import org.apache.commons.logging.Log; +import org.apache.james.transport.mailets.delivery.DeliveryUtils; +import org.apache.james.transport.mailets.jsieve.ActionDispatcher; +import org.apache.james.transport.mailets.jsieve.ResourceLocator; +import org.apache.james.transport.mailets.jsieve.SieveMailAdapter; +import org.apache.james.user.api.UsersRepository; +import org.apache.james.user.api.UsersRepositoryException; +import org.apache.jsieve.ConfigurationManager; +import org.apache.jsieve.SieveConfigurationException; +import org.apache.jsieve.SieveFactory; +import org.apache.jsieve.exception.SieveException; +import org.apache.jsieve.parser.generated.ParseException; +import org.apache.jsieve.parser.generated.TokenMgrError; +import org.apache.mailet.Mail; +import org.apache.mailet.MailAddress; +import org.apache.mailet.MailetContext; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; + +public class SieveExecutor { + + public static Builder builder() { + return new Builder(); + } + + public static class Builder { + private MailetContext mailetContext; + private UsersRepository usersRepos; + private SievePoster sievePoster; + private ResourceLocator resourceLocator; + private Log log; + + public Builder usersRepository(UsersRepository usersRepository) { + this.usersRepos = usersRepository; + return this; + } + + public Builder sievePoster(SievePoster sievePoster) { + this.sievePoster = sievePoster; + return this; + } + + public Builder mailetContext(MailetContext mailetContext) { + this.mailetContext = mailetContext; + return this; + } + + public Builder resourceLocator(ResourceLocator resourceLocator) { + this.resourceLocator = resourceLocator; + return this; + } + + public Builder log(Log log) { + this.log = log; + return this; + } + + public SieveExecutor build() throws MessagingException { + Preconditions.checkNotNull(mailetContext); + Preconditions.checkNotNull(usersRepos); + Preconditions.checkNotNull(resourceLocator); + Preconditions.checkNotNull(log); + Preconditions.checkNotNull(sievePoster); + return new SieveExecutor(mailetContext, usersRepos, sievePoster, resourceLocator, log); + } + } + + private final MailetContext mailetContext; + private final UsersRepository usersRepos; + private final SievePoster sievePoster; + private final ResourceLocator resourceLocator; + private final SieveFactory factory; + private final ActionDispatcher actionDispatcher; + private final Log log; + + public SieveExecutor(MailetContext mailetContext, UsersRepository usersRepos, SievePoster sievePoster, + ResourceLocator resourceLocator, Log log) throws MessagingException { + this.mailetContext = mailetContext; + this.usersRepos = usersRepos; + this.sievePoster = sievePoster; + this.resourceLocator = resourceLocator; + factory = createFactory(log); + this.actionDispatcher = new ActionDispatcher(); + this.log = log; + } + + private SieveFactory createFactory(Log log) throws MessagingException { + try { + final ConfigurationManager configurationManager = new ConfigurationManager(); + configurationManager.setLog(log); + return configurationManager.build(); + } catch (SieveConfigurationException e) { + throw new MessagingException("Failed to load standard Sieve configuration.", e); + } + } + + public void execute(MailAddress recipient, Mail mail) throws MessagingException { + Preconditions.checkNotNull(recipient, "Recipient for mail to be spooled cannot be null."); + Preconditions.checkNotNull(mail.getMessage(), "Mail message to be spooled cannot be null."); + + sieveMessage(recipient, mail, log); + // If no exception was thrown the message was successfully stored in the mailbox + log.info("Local delivered mail " + mail.getName() + " sucessfully from " + DeliveryUtils.prettyPrint(mail.getSender()) + " to " + DeliveryUtils.prettyPrint(recipient) + + " in folder " + this.folder); + } + + protected void sieveMessage(MailAddress recipient, Mail aMail, Log log) throws MessagingException { + try { + ResourceLocator.UserSieveInformation userSieveInformation = resourceLocator.get(getScriptUri(recipient)); + sieveMessageEvaluate(recipient, aMail, userSieveInformation, log); + } catch (Exception ex) { + // SIEVE is a mail filtering protocol. + // Rejecting the mail because it cannot be filtered + // seems very unfriendly. + // So just log and store in INBOX + log.error("Cannot evaluate Sieve script. Storing mail in user INBOX.", ex); + storeMessageInbox(recipient, aMail); + } + } + + private void sieveMessageEvaluate(MailAddress recipient, Mail aMail, ResourceLocator.UserSieveInformation userSieveInformation, Log log) throws MessagingException, IOException { + try { + SieveMailAdapter aMailAdapter = new SieveMailAdapter(aMail, + mailetContext, actionDispatcher, sievePoster, userSieveInformation.getScriptActivationDate(), + userSieveInformation.getScriptInterpretationDate(), recipient); + aMailAdapter.setLog(log); + // This logging operation is potentially costly + log.debug("Evaluating " + aMailAdapter.toString() + "against \"" + getScriptUri(recipient) + "\""); + factory.evaluate(aMailAdapter, factory.parse(userSieveInformation.getScriptContent())); + } catch (SieveException ex) { + handleFailure(recipient, aMail, ex); + } + catch (ParseException ex) { + handleFailure(recipient, aMail, ex); + } + catch (TokenMgrError ex) { + handleFailure(recipient, aMail, new SieveException(ex)); + } + } + + protected String getScriptUri(MailAddress m) { + return "//" + retrieveUserNameUsedForScriptStorage(m) + "/sieve"; + } + + protected void handleFailure(MailAddress recipient, Mail aMail, Exception ex) throws MessagingException, IOException { + mailetContext.sendMail(recipient, ImmutableList.of(recipient), SieveFailureMessageComposer.composeMessage(aMail, ex, recipient.toString())); + } + + protected void storeMessageInbox(MailAddress mailAddress, Mail mail) throws MessagingException { + sievePoster.post("mailbox://" + retrieveUserNameUsedForScriptStorage(mailAddress) + "/", mail); + } + + public String retrieveUserNameUsedForScriptStorage(MailAddress mailAddress) { + try { + if (usersRepos.supportVirtualHosting()) { + return mailAddress.asString(); + } else { + return mailAddress.getLocalPart() + "@localhost"; + } + } catch (UsersRepositoryException e) { + log.warn("Can not determine if virtual hosting is used for " + mailAddress.asPrettyString(), e); + return mailAddress.getLocalPart() + "@localhost"; + } + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveMailStore.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveMailStore.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveMailStore.java deleted file mode 100644 index fa13bf4..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveMailStore.java +++ /dev/null @@ -1,202 +0,0 @@ -/**************************************************************** - * 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.transport.mailets.jsieve.delivery; - -import java.io.IOException; - -import javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; - -import org.apache.commons.logging.Log; -import org.apache.james.transport.mailets.delivery.DeliveryUtils; -import org.apache.james.transport.mailets.delivery.MailStore; -import org.apache.james.transport.mailets.jsieve.ActionDispatcher; -import org.apache.james.transport.mailets.jsieve.ResourceLocator; -import org.apache.james.transport.mailets.jsieve.SieveMailAdapter; -import org.apache.james.user.api.UsersRepository; -import org.apache.james.user.api.UsersRepositoryException; -import org.apache.jsieve.ConfigurationManager; -import org.apache.jsieve.SieveConfigurationException; -import org.apache.jsieve.SieveFactory; -import org.apache.jsieve.exception.SieveException; -import org.apache.jsieve.parser.generated.ParseException; -import org.apache.jsieve.parser.generated.TokenMgrError; -import org.apache.mailet.Mail; -import org.apache.mailet.MailAddress; -import org.apache.mailet.MailetContext; - -import com.google.common.base.Preconditions; - -public class SieveMailStore implements MailStore { - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - private MailetContext mailetContext; - private UsersRepository usersRepos; - private SievePoster sievePoster; - private String folder; - private ResourceLocator resourceLocator; - private Log log; - - public Builder folder(String folder) { - this.folder = folder; - return this; - } - - public Builder usersRepository(UsersRepository usersRepository) { - this.usersRepos = usersRepository; - return this; - } - - public Builder sievePoster(SievePoster sievePoster) { - this.sievePoster = sievePoster; - return this; - } - - public Builder mailetContext(MailetContext mailetContext) { - this.mailetContext = mailetContext; - return this; - } - - public Builder resourceLocator(ResourceLocator resourceLocator) { - this.resourceLocator = resourceLocator; - return this; - } - - public Builder log(Log log) { - this.log = log; - return this; - } - - public SieveMailStore build() throws MessagingException { - Preconditions.checkNotNull(mailetContext); - Preconditions.checkNotNull(usersRepos); - Preconditions.checkNotNull(folder); - Preconditions.checkNotNull(resourceLocator); - Preconditions.checkNotNull(log); - Preconditions.checkNotNull(sievePoster); - return new SieveMailStore(mailetContext, usersRepos, sievePoster, folder, resourceLocator, log); - } - } - - private final MailetContext mailetContext; - private final UsersRepository usersRepos; - private final SievePoster sievePoster; - private final String folder; - private final ResourceLocator resourceLocator; - private final SieveFactory factory; - private final ActionDispatcher actionDispatcher; - private final Log log; - - public SieveMailStore(MailetContext mailetContext, UsersRepository usersRepos, SievePoster sievePoster, String folder, - ResourceLocator resourceLocator, Log log) throws MessagingException { - this.mailetContext = mailetContext; - this.usersRepos = usersRepos; - this.sievePoster = sievePoster; - this.folder = folder; - this.resourceLocator = resourceLocator; - factory = createFactory(log); - this.actionDispatcher = new ActionDispatcher(); - this.log = log; - } - - private SieveFactory createFactory(Log log) throws MessagingException { - try { - final ConfigurationManager configurationManager = new ConfigurationManager(); - configurationManager.setLog(log); - return configurationManager.build(); - } catch (SieveConfigurationException e) { - throw new MessagingException("Failed to load standard Sieve configuration.", e); - } - } - - public void storeMail(MailAddress recipient, Mail mail) throws MessagingException { - Preconditions.checkNotNull(recipient, "Recipient for mail to be spooled cannot be null."); - Preconditions.checkNotNull(mail.getMessage(), "Mail message to be spooled cannot be null."); - - sieveMessage(recipient, mail, log); - // If no exception was thrown the message was successfully stored in the mailbox - log.info("Local delivered mail " + mail.getName() + " sucessfully from " + DeliveryUtils.prettyPrint(mail.getSender()) + " to " + DeliveryUtils.prettyPrint(recipient) - + " in folder " + this.folder); - } - - protected void sieveMessage(MailAddress recipient, Mail aMail, Log log) throws MessagingException { - try { - ResourceLocator.UserSieveInformation userSieveInformation = resourceLocator.get(getScriptUri(recipient)); - sieveMessageEvaluate(recipient, aMail, userSieveInformation, log); - } catch (Exception ex) { - // SIEVE is a mail filtering protocol. - // Rejecting the mail because it cannot be filtered - // seems very unfriendly. - // So just log and store in INBOX - log.error("Cannot evaluate Sieve script. Storing mail in user INBOX.", ex); - storeMessageInbox(recipient, aMail.getMessage()); - } - } - - private void sieveMessageEvaluate(MailAddress recipient, Mail aMail, ResourceLocator.UserSieveInformation userSieveInformation, Log log) throws MessagingException, IOException { - try { - SieveMailAdapter aMailAdapter = new SieveMailAdapter(aMail, - mailetContext, actionDispatcher, sievePoster, userSieveInformation.getScriptActivationDate(), - userSieveInformation.getScriptInterpretationDate(), recipient); - aMailAdapter.setLog(log); - // This logging operation is potentially costly - log.debug("Evaluating " + aMailAdapter.toString() + "against \"" + getScriptUri(recipient) + "\""); - factory.evaluate(aMailAdapter, factory.parse(userSieveInformation.getScriptContent())); - } catch (SieveException ex) { - handleFailure(recipient, aMail, ex); - } - catch (ParseException ex) { - handleFailure(recipient, aMail, ex); - } - catch (TokenMgrError ex) { - handleFailure(recipient, aMail, new SieveException(ex)); - } - } - - protected String getScriptUri(MailAddress m) { - return "//" + retrieveUserNameUsedForScriptStorage(m) + "/sieve"; - } - - protected void handleFailure(MailAddress recipient, Mail aMail, Exception ex) throws MessagingException, IOException { - storeMessageInbox(recipient, SieveFailureMessageComposer.composeMessage(aMail, ex, recipient.toString())); - } - - protected void storeMessageInbox(MailAddress mailAddress, MimeMessage message) throws MessagingException { - sievePoster.post("mailbox://" + retrieveUserNameUsedForScriptStorage(mailAddress) + "/", message); - } - - public String retrieveUserNameUsedForScriptStorage(MailAddress mailAddress) { - try { - if (usersRepos.supportVirtualHosting()) { - return mailAddress.asString(); - } else { - return mailAddress.getLocalPart() + "@localhost"; - } - } catch (UsersRepositoryException e) { - log.warn("Can not determine if virtual hosting is used for " + mailAddress.asPrettyString(), e); - return mailAddress.getLocalPart() + "@localhost"; - } - } -} http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java index 9717df5..b0ca0ae 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java @@ -20,28 +20,25 @@ package org.apache.james.transport.mailets.jsieve.delivery; import javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; -import org.apache.james.transport.mailets.delivery.MailboxAppender; +import org.apache.james.transport.mailets.delivery.MailStore; import org.apache.james.transport.mailets.jsieve.Poster; import org.apache.james.user.api.UsersRepository; import org.apache.james.user.api.UsersRepositoryException; +import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; public class SievePoster implements Poster { - - private final MailboxAppender mailboxAppender; private final String folder; - private final UsersRepository usersRepos; + private final UsersRepository usersRepository; - public SievePoster(MailboxAppender mailboxAppender, String folder, UsersRepository usersRepos) { - this.mailboxAppender = mailboxAppender; + public SievePoster(UsersRepository usersRepository, String folder) { + this.usersRepository = usersRepository; this.folder = folder; - this.usersRepos = usersRepos; } @Override - public void post(String url, MimeMessage mail) throws MessagingException { + public void post(String url, Mail mail) throws MessagingException { int endOfScheme = url.indexOf(':'); if (endOfScheme < 0) { throw new MessagingException("Malformed URI"); @@ -49,7 +46,8 @@ public class SievePoster implements Poster { String scheme = url.substring(0, endOfScheme); if (scheme.equals("mailbox")) { UserAndPath userAndPath = retrieveUserAndPath(url, endOfScheme); - mailboxAppender.appendAndUseSlashAsSeparator(mail, userAndPath.user, userAndPath.path, folder); + + mail.setAttribute(MailStore.DELIVERY_PATH_PREFIX + userAndPath.user, userAndPath.path); } else { throw new MessagingException("Unsupported protocol"); } @@ -88,7 +86,7 @@ public class SievePoster implements Poster { String user = url.substring(startOfUser, endOfUser).toLowerCase(); // Check if we should use the full email address as username try { - return usersRepos.getUser(new MailAddress(user, host)); + return usersRepository.getUser(new MailAddress(user, host)); } catch (UsersRepositoryException e) { throw new MessagingException("Unable to accessUsersRepository", e); } http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java index 9931bcf..05e9653 100644 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/LocalDeliveryTest.java @@ -21,14 +21,12 @@ package org.apache.james.transport.mailets.delivery; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.io.InputStream; -import java.util.Collection; import java.util.Date; import java.util.Properties; @@ -49,82 +47,39 @@ import org.apache.james.mailbox.MessageManager; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.rrt.api.RecipientRewriteTable; -import org.apache.james.sieverepository.api.SieveRepository; -import org.apache.james.sieverepository.api.exception.ScriptNotFoundException; import org.apache.james.transport.mailets.LocalDelivery; -import org.apache.james.transport.mailets.SieveLocalDelivery; import org.apache.james.user.api.UsersRepository; import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; -import org.apache.mailet.Mailet; import org.apache.mailet.base.test.FakeMail; import org.apache.mailet.base.test.FakeMailContext; import org.apache.mailet.base.test.FakeMailetConfig; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; import org.slf4j.Logger; import com.google.common.base.Throwables; -import com.google.common.collect.ImmutableList; -@RunWith(Parameterized.class) public class LocalDeliveryTest { public static final String RECEIVER_DOMAIN_COM = "[email protected]"; + private UsersRepository usersRepository; + private MailboxManager mailboxManager; + private MailboxSession.User user; + private FakeMailetConfig config; + private LocalDelivery testee; - public static class Parameter { - private final UsersRepository usersRepository; - private final MailboxManager mailboxManager; - private final SieveRepository sieveRepository; - private final Mailet mailet; - private final MailboxSession.User user; - - public Parameter(UsersRepository usersRepository, MailboxManager mailboxManager, SieveRepository sieveRepository, - Mailet mailet, MailboxSession.User user) { - this.usersRepository = usersRepository; - this.mailboxManager = mailboxManager; - this.sieveRepository = sieveRepository; - this.mailet = mailet; - this.user = user; - } - - public UsersRepository getUsersRepository() { - return usersRepository; - } - - public MailboxManager getMailboxManager() { - return mailboxManager; - } - - public SieveRepository getSieveRepository() { - return sieveRepository; - } - - public Mailet getMailet() { - return mailet; - } - - public MailboxSession.User getUser() { - return user; - } - } - - @Parameterized.Parameters - public static Collection<Object[]> getLocalDeliveryClasses() { - SieveRepository sieveRepository = mock(SieveRepository.class); - UsersRepository usersRepository = mock(UsersRepository.class); - MailboxManager mailboxManager = mock(MailboxManager.class); + @Before + public void setUp() { + usersRepository = mock(UsersRepository.class); + mailboxManager = mock(MailboxManager.class); RecipientRewriteTable recipientRewriteTable = mock(RecipientRewriteTable.class); DomainList domainList = mock(DomainList.class); - SieveLocalDelivery sieveLocalDelivery = new SieveLocalDelivery(usersRepository, mailboxManager, sieveRepository, - recipientRewriteTable, domainList); - LocalDelivery localDelivery = new LocalDelivery(recipientRewriteTable, usersRepository, mailboxManager, domainList); + testee = new LocalDelivery(recipientRewriteTable, usersRepository, mailboxManager, domainList); - MailboxSession.User user = mock(MailboxSession.User.class); + user = mock(MailboxSession.User.class); MailboxSession session = mock(MailboxSession.class); when(session.getPathDelimiter()).thenReturn('.'); try { @@ -134,18 +89,6 @@ public class LocalDeliveryTest { } when(session.getUser()).thenReturn(user); - return ImmutableList.of( - new Object[]{new Parameter(usersRepository, mailboxManager, sieveRepository, sieveLocalDelivery, user)}, - new Object[]{new Parameter(usersRepository, mailboxManager, sieveRepository, localDelivery, user)} - ); - } - - @Parameterized.Parameter - public Parameter parameter; - private FakeMailetConfig config; - - @Before - public void setUp() { config = new FakeMailetConfig("Local delivery", FakeMailContext.builder().logger(mock(Logger.class)).build()); } @@ -156,16 +99,15 @@ public class LocalDeliveryTest { MailboxPath inbox = new MailboxPath("#private", username, "INBOX"); MessageManager messageManager = mock(MessageManager.class); - when(parameter.getUsersRepository().supportVirtualHosting()).thenReturn(true); - when(parameter.getUsersRepository().getUser(new MailAddress(username))).thenReturn(username); - doThrow(new ScriptNotFoundException()).when(parameter.getSieveRepository()).getActive(username); - when(parameter.getMailboxManager().getMailbox(eq(inbox), any(MailboxSession.class))).thenReturn(messageManager); - when(parameter.getUser().getUserName()).thenReturn(username); + when(usersRepository.supportVirtualHosting()).thenReturn(true); + when(usersRepository.getUser(new MailAddress(username))).thenReturn(username); + when(mailboxManager.getMailbox(eq(inbox), any(MailboxSession.class))).thenReturn(messageManager); + when(user.getUserName()).thenReturn(username); // When Mail mail = createMail(); - parameter.getMailet().init(config); - parameter.getMailet().service(mail); + testee.init(config); + testee.service(mail); // Then verify(messageManager).appendMessage(any(InputStream.class), any(Date.class), any(MailboxSession.class), eq(true), any(Flags.class)); @@ -177,17 +119,16 @@ public class LocalDeliveryTest { String username = "receiver"; MailboxPath inbox = new MailboxPath("#private", username, "INBOX"); MessageManager messageManager = mock(MessageManager.class); - when(parameter.getUsersRepository().supportVirtualHosting()).thenReturn(false); - when(parameter.getUsersRepository().getUser(new MailAddress("receiver@localhost"))).thenReturn(username); - when(parameter.getUsersRepository().getUser(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(username); - doThrow(new ScriptNotFoundException()).when(parameter.getSieveRepository()).getActive(username); - when(parameter.getMailboxManager().getMailbox(eq(inbox), any(MailboxSession.class))).thenReturn(messageManager); - when(parameter.getUser().getUserName()).thenReturn(username); + when(usersRepository.supportVirtualHosting()).thenReturn(false); + when(usersRepository.getUser(new MailAddress("receiver@localhost"))).thenReturn(username); + when(usersRepository.getUser(new MailAddress(RECEIVER_DOMAIN_COM))).thenReturn(username); + when(mailboxManager.getMailbox(eq(inbox), any(MailboxSession.class))).thenReturn(messageManager); + when(user.getUserName()).thenReturn(username); // When Mail mail = createMail(); - parameter.getMailet().init(config); - parameter.getMailet().service(mail); + testee.init(config); + testee.service(mail); // Then verify(messageManager).appendMessage(any(InputStream.class), any(Date.class), any(MailboxSession.class), eq(true), any(Flags.class)); http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java index 3c70b96..be24ca1 100644 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailDispatcherTest.java @@ -52,7 +52,6 @@ import org.junit.Test; import org.mockito.ArgumentCaptor; import com.google.common.base.Charsets; -import com.google.common.collect.ImmutableList; public class MailDispatcherTest { private FakeMailContext fakeMailContext; http://git-wip-us.apache.org/repos/asf/james-project/blob/71accd66/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderTest.java index 184f0ea..d4b7e6c 100644 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderTest.java +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderTest.java @@ -26,6 +26,7 @@ import static org.mockito.Mockito.mock; import java.util.Properties; import javax.activation.DataHandler; +import javax.mail.MessagingException; import javax.mail.Multipart; import javax.mail.Session; import javax.mail.internet.MimeBodyPart; @@ -57,7 +58,6 @@ public class MailboxAppenderTest { public static final String USER = "user"; public static final String FOLDER = "folder"; - public static final String FALLBACK_FOLDER = "fallback_folder"; public static final String EMPTY_FOLDER = ""; @Rule public ExpectedException expectedException = ExpectedException.none(); @@ -107,17 +107,6 @@ public class MailboxAppenderTest { } @Test - public void appendAndUseSlashAsSeparatorShouldAddMessageToDesiredMailbox() throws Exception { - testee.appendAndUseSlashAsSeparator(mimeMessage, USER, FOLDER, FALLBACK_FOLDER); - - MessageResultIterator messages = mailboxManager.getMailbox(new MailboxPath("#private", USER, FOLDER), session) - .getMessages(MessageRange.all(), new FetchGroupImpl(MessageResult.FetchGroup.FULL_CONTENT), session); - - assertThat(messages).hasSize(1); - } - - - @Test public void appendShouldAddMessageToDesiredMailboxWhenMailboxExists() throws Exception { MailboxPath mailboxPath = new MailboxPath("#private", USER, FOLDER); mailboxManager.createMailbox(mailboxPath, session); @@ -131,43 +120,27 @@ public class MailboxAppenderTest { } @Test - public void appendAndUseSlashAsSeparatorShouldAddMessageToDesiredMailboxWhenMailboxExists() throws Exception { - MailboxPath mailboxPath = new MailboxPath("#private", USER, FOLDER); - mailboxManager.createMailbox(mailboxPath, session); - - testee.appendAndUseSlashAsSeparator(mimeMessage, USER, FOLDER, FALLBACK_FOLDER); - - MessageResultIterator messages = mailboxManager.getMailbox(mailboxPath, session) - .getMessages(MessageRange.all(), new FetchGroupImpl(MessageResult.FetchGroup.FULL_CONTENT), session); - - assertThat(messages).hasSize(1); - } - - @Test - public void appendAndUseSlashAsSeparatorShouldNotAppendToEmptyFolder() throws Exception { - testee.appendAndUseSlashAsSeparator(mimeMessage, USER, EMPTY_FOLDER, FALLBACK_FOLDER); - - expectedException.expect(MailboxNotFoundException.class); + public void appendShouldNotAppendToEmptyFolder() throws Exception { + expectedException.expect(MessagingException.class); - mailboxManager.getMailbox(new MailboxPath("#private", USER, EMPTY_FOLDER), session); + testee.append(mimeMessage, USER, EMPTY_FOLDER); } - @Test - public void appendAndUseSlashAsSeparatorShouldAppendToFallback() throws Exception { - testee.appendAndUseSlashAsSeparator(mimeMessage, USER, EMPTY_FOLDER, FALLBACK_FOLDER); + public void appendShouldRemovePathSeparatorAsFirstChar() throws Exception { + testee.append(mimeMessage, USER, "." + FOLDER); - MessageResultIterator messages = mailboxManager.getMailbox(new MailboxPath("#private", USER, FALLBACK_FOLDER), session) + MessageResultIterator messages = mailboxManager.getMailbox(new MailboxPath("#private", USER, FOLDER), session) .getMessages(MessageRange.all(), new FetchGroupImpl(MessageResult.FetchGroup.FULL_CONTENT), session); assertThat(messages).hasSize(1); } @Test - public void appendAndUseSlashAsSeparatorShouldRemovePathSeparatorAsFirstChar() throws Exception { - testee.appendAndUseSlashAsSeparator(mimeMessage, USER, "." + FOLDER, FALLBACK_FOLDER); + public void appendShouldReplaceSlashBySeparator() throws Exception { + testee.append(mimeMessage, USER, FOLDER + "/any"); - MessageResultIterator messages = mailboxManager.getMailbox(new MailboxPath("#private", USER, FOLDER), session) + MessageResultIterator messages = mailboxManager.getMailbox(new MailboxPath("#private", USER, FOLDER + ".any"), session) .getMessages(MessageRange.all(), new FetchGroupImpl(MessageResult.FetchGroup.FULL_CONTENT), session); assertThat(messages).hasSize(1); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
