JAMES-1854 Split responsibility of class SieveMailet
- Customizing Mime Message before delivery
- Delivering Mime message to someone INBOX
- Extract pretty printing of MailAddresses
JAMES-1854 DeliveryUtils test
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/ca85c529
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/ca85c529
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/ca85c529
Branch: refs/heads/master
Commit: ca85c529a6a13a0501445f9cfb3eb325d5b35288
Parents: 4362338
Author: Benoit Tellier <[email protected]>
Authored: Thu Oct 27 18:10:08 2016 +0200
Committer: Benoit Tellier <[email protected]>
Committed: Fri Nov 18 18:46:46 2016 +0700
----------------------------------------------------------------------
.../mailets/delivery/DeliveryUtils.java | 52 +
.../mailets/delivery/LocalDelivery.java | 53 +-
.../mailets/delivery/MailDispatcher.java | 149 +++
.../transport/mailets/delivery/MailStorer.java | 29 +
.../mailets/delivery/SieveMailStorer.java | 196 ++++
.../transport/mailets/delivery/SieveMailet.java | 315 ------
.../mailets/delivery/ToRecipientFolder.java | 45 +-
.../mailets/jsieve/CommonsLoggingAdapter.java | 45 +-
.../mailets/delivery/DeliveryUtilsTest.java | 40 +
.../mailets/delivery/SieveIntegrationTest.java | 992 +++++++++++++++++++
.../mailets/delivery/SieveMailetTest.java | 953 ------------------
11 files changed, 1547 insertions(+), 1322 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/DeliveryUtils.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/DeliveryUtils.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/DeliveryUtils.java
new file mode 100644
index 0000000..9c1abef
--- /dev/null
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/DeliveryUtils.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * 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.delivery;
+
+import org.apache.commons.logging.Log;
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.mailet.MailAddress;
+
+public class DeliveryUtils {
+
+ public static String getUsername(MailAddress m, UsersRepository
usersRepository, Log log) {
+ try {
+ if (usersRepository.supportVirtualHosting()) {
+ return m.toString();
+ } else {
+ return m.getLocalPart() + "@localhost";
+ }
+ } catch (UsersRepositoryException e) {
+ log.error("Unable to access UsersRepository", e);
+ return m.getLocalPart() + "@localhost";
+
+ }
+ }
+
+ public static String prettyPrint(MailAddress mailAddress) {
+ if (mailAddress != null) {
+ return "<" + mailAddress.toString() + ">";
+ } else {
+ return "<>";
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/LocalDelivery.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/LocalDelivery.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/LocalDelivery.java
index 8db7444..47a96ae 100644
---
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/LocalDelivery.java
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/LocalDelivery.java
@@ -19,23 +19,21 @@
package org.apache.james.transport.mailets.delivery;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Lists;
+import org.apache.commons.logging.Log;
import org.apache.james.domainlist.api.DomainList;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.sieverepository.api.SieveRepository;
import org.apache.james.transport.mailets.RecipientRewriteTable;
import org.apache.james.transport.mailets.ResourceLocatorImpl;
+import org.apache.james.transport.mailets.jsieve.CommonsLoggingAdapter;
import org.apache.james.user.api.UsersRepository;
import org.apache.mailet.Mail;
import org.apache.mailet.MailetConfig;
-import org.apache.mailet.MailetContext;
import org.apache.mailet.base.GenericMailet;
import javax.inject.Inject;
import javax.inject.Named;
import javax.mail.MessagingException;
-import java.util.Iterator;
/**
* Receives a Mail from the Queue and takes care of delivery of the
@@ -78,52 +76,45 @@ public class LocalDelivery extends GenericMailet {
this.domainList = domainList;
}
- private SieveMailet sieveMailet; // Mailet that actually stores the
message
+ private MailDispatcher mailDispatcher; // Mailet that actually stores the
message
private RecipientRewriteTable recipientRewriteTable; // Mailet that
applies RecipientRewriteTable
- /**
- * Delivers a mail to a local mailbox.
- *
- * @param mail the mail being processed
- *
- * @throws MessagingException if an error occurs while storing the mail
- */
public void service(Mail mail) throws MessagingException {
recipientRewriteTable.service(mail);
if (!mail.getState().equals(Mail.GHOST)) {
- sieveMailet.service(mail);
+ mailDispatcher.dispatch(mail);
}
}
- /**
- * Return a string describing this mailet.
- *
- * @return a string describing this mailet
- */
public String getMailetInfo() {
return "Local Delivery Mailet";
}
- /**
- * @see org.apache.mailet.base.GenericMailet#init()
- */
- public void init(MailetConfig mailetConfig) throws MessagingException {
- super.init(mailetConfig);
+ public void init() throws MessagingException {
recipientRewriteTable = new RecipientRewriteTable();
recipientRewriteTable.setDomainList(domainList);
recipientRewriteTable.setRecipientRewriteTable(rrt);
recipientRewriteTable.init(getMailetConfig());
- sieveMailet = SieveMailet.builder()
- .mailboxManager(mailboxManager)
- .userRepository(usersRepository)
- .resourceLocator(ResourceLocatorImpl.instanciate(usersRepository,
sieveRepository))
- .mailetContext(getMailetContext())
- .consume(getInitParameter("consume", true))
+ Log log = CommonsLoggingAdapter.builder()
+ .mailet(this)
.quiet(getInitParameter("quiet", false))
.verbose(getInitParameter("verbose", false))
- .folder("INBOX")
.build();
- sieveMailet.init(mailetConfig);
+ String folder = "INBOX";
+ mailDispatcher = MailDispatcher.builder()
+ .mailStorer(SieveMailStorer.builder()
+ .sievePoster(new SievePoster(mailboxManager, folder,
usersRepository, getMailetContext()))
+ .usersRepository(usersRepository)
+ .mailboxManager(mailboxManager)
+
.resourceLocator(ResourceLocatorImpl.instanciate(usersRepository,
sieveRepository))
+ .mailetContext(getMailetContext())
+ .folder(folder)
+ .log(log)
+ .build())
+ .consume(getInitParameter("consume", true))
+ .mailetContext(getMailetContext())
+ .log(log)
+ .build();
}
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailDispatcher.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailDispatcher.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailDispatcher.java
new file mode 100644
index 0000000..fe62364
--- /dev/null
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailDispatcher.java
@@ -0,0 +1,149 @@
+/****************************************************************
+ * 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.delivery;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Vector;
+
+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.apache.mailet.MailetContext;
+import org.apache.mailet.base.RFC2822Headers;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Contains resource bindings.
+ */
+public class MailDispatcher {
+
+ public static final String DELIVERED_TO = "Delivered-To";
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private MailStorer mailStorer;
+ private boolean consume;
+ private MailetContext mailetContext;
+ private Log log;
+
+ public Builder consume(boolean consume) {
+ this.consume = consume;
+ return this;
+ }
+
+ public Builder mailStorer(MailStorer mailStorer) {
+ this.mailStorer = mailStorer;
+ return this;
+ }
+
+ public Builder log(Log log) {
+ this.log = log;
+ return this;
+ }
+
+ public Builder mailetContext(MailetContext mailetContext) {
+ this.mailetContext = mailetContext;
+ return this;
+ }
+
+ public MailDispatcher build() throws MessagingException {
+ Preconditions.checkNotNull(mailStorer);
+ Preconditions.checkNotNull(log);
+ Preconditions.checkNotNull(mailetContext);
+ return new MailDispatcher(mailStorer, consume, log, mailetContext);
+ }
+
+ }
+
+ private final MailStorer mailStorer;
+ private final boolean consume;
+ private final MailetContext mailetContext;
+ private final Log log;
+
+ private MailDispatcher(MailStorer mailStorer, boolean consume, Log log,
MailetContext mailetContext) {
+ this.mailStorer = mailStorer;
+ this.consume = consume;
+ this.log = log;
+ this.mailetContext = mailetContext;
+ }
+
+ /**
+ * Delivers a mail to a local mailbox.
+ *
+ * @param mail
+ * the mail being processed
+ *
+ * @throws MessagingException
+ * if an error occurs while storing the mail
+ */
+ @SuppressWarnings("unchecked")
+ public void dispatch(Mail mail) throws MessagingException {
+ Collection<MailAddress> recipients = mail.getRecipients();
+ Collection<MailAddress> errors = new Vector<MailAddress>();
+
+ MimeMessage message = mail.getMessage();
+
+ // Set Return-Path and remove all other Return-Path headers from the
+ // message
+ // This only works because there is a placeholder inserted by
+ // MimeMessageWrapper
+ message.setHeader(RFC2822Headers.RETURN_PATH,
DeliveryUtils.prettyPrint(mail.getSender()));
+
+ List<String> deliveredToHeader =
Collections.list(message.getMatchingHeaders(new String[] { DELIVERED_TO }));
+ message.removeHeader(DELIVERED_TO);
+
+ for (MailAddress recipient : recipients) {
+ try {
+ // Add qmail's de facto standard Delivered-To header
+ message.addHeader(DELIVERED_TO, recipient.toString());
+ mailStorer.storeMail(mail.getSender(), recipient, mail);
+ message.removeHeader(DELIVERED_TO);
+ } catch (Exception ex) {
+ log.error("Error while storing mail.", ex);
+ errors.add(recipient);
+ }
+ }
+ for (String deliveredTo : deliveredToHeader) {
+ message.addHeader(DELIVERED_TO, deliveredTo);
+ }
+ if (!errors.isEmpty()) {
+ // If there were errors, we redirect the email to the ERROR
+ // processor.
+ // In order for this server to meet the requirements of the SMTP
+ // specification, mails on the ERROR processor must be returned to
+ // the sender. Note that this email doesn't include any details
+ // regarding the details of the failure(s).
+ // In the future we may wish to address this.
+ mailetContext.sendMail(mail.getSender(), errors,
mail.getMessage(), Mail.ERROR);
+ }
+ if (consume) {
+ // Consume this message
+ mail.setState(Mail.GHOST);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStorer.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStorer.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStorer.java
new file mode 100644
index 0000000..d95ee62
--- /dev/null
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStorer.java
@@ -0,0 +1,29 @@
+/****************************************************************
+ * 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.delivery;
+
+import javax.mail.MessagingException;
+
+import org.apache.mailet.Mail;
+import org.apache.mailet.MailAddress;
+
+public interface MailStorer {
+ void storeMail(MailAddress sender, MailAddress recipient, Mail mail)
throws MessagingException;
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailStorer.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailStorer.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailStorer.java
new file mode 100644
index 0000000..56736ba
--- /dev/null
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailStorer.java
@@ -0,0 +1,196 @@
+/****************************************************************
+ * 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.delivery;
+
+import java.io.IOException;
+
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.commons.logging.Log;
+import org.apache.james.mailbox.MailboxManager;
+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.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 SieveMailStorer implements MailStorer {
+
+ 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;
+ private MailboxManager mailboxManager;
+
+ 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 Builder mailboxManager(MailboxManager mailboxManager) {
+ this.mailboxManager = mailboxManager;
+ return this;
+ }
+
+ public SieveMailStorer build() throws MessagingException {
+ Preconditions.checkNotNull(mailetContext);
+ Preconditions.checkNotNull(usersRepos);
+ Preconditions.checkNotNull(folder);
+ Preconditions.checkNotNull(resourceLocator);
+ Preconditions.checkNotNull(log);
+ Preconditions.checkNotNull(sievePoster);
+ return new SieveMailStorer(mailetContext, usersRepos,
mailboxManager, 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 SieveMailStorer(MailetContext mailetContext, UsersRepository
usersRepos, MailboxManager mailboxManager, String folder,
+ ResourceLocator resourceLocator, Log log) throws
MessagingException {
+ this.mailetContext = mailetContext;
+ this.usersRepos = usersRepos;
+ this.sievePoster = new SievePoster(mailboxManager, folder, usersRepos,
mailetContext);
+ this.folder = folder;
+ this.resourceLocator = resourceLocator;
+ try {
+ final ConfigurationManager configurationManager = new
ConfigurationManager();
+ configurationManager.setLog(log);
+ factory = configurationManager.build();
+ } catch (SieveConfigurationException e) {
+ throw new MessagingException("Failed to load standard Sieve
configuration.", e);
+ }
+ this.actionDispatcher = new ActionDispatcher();
+ this.log = log;
+ }
+
+ public void storeMail(MailAddress sender, 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(sender) + " to " +
DeliveryUtils.prettyPrint(recipient)
+ + " in folder " + this.folder);
+ }
+
+ protected void sieveMessage(MailAddress recipient, Mail aMail, Log log)
throws MessagingException {
+ String username = DeliveryUtils.getUsername(recipient, usersRepos,
log);
+ try {
+ final ResourceLocator.UserSieveInformation userSieveInformation =
resourceLocator.get(getScriptUri(recipient, log));
+ 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(username, 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, log) + "\"");
+ factory.evaluate(aMailAdapter,
factory.parse(userSieveInformation.getScriptContent()));
+ } catch (SieveException ex) {
+ handleFailure(recipient, aMail, ex, log);
+ }
+ catch (ParseException ex) {
+ handleFailure(recipient, aMail, ex, log);
+ }
+ catch (TokenMgrError ex) {
+ handleFailure(recipient, aMail, new SieveException(ex), log);
+ }
+ }
+
+ protected String getScriptUri(MailAddress m, Log log) {
+ return "//" + DeliveryUtils.getUsername(m, usersRepos, log) + "/sieve";
+ }
+
+ protected void handleFailure(MailAddress recipient, Mail aMail, Exception
ex, Log log) throws MessagingException, IOException {
+ String user = DeliveryUtils.getUsername(recipient, usersRepos, log);
+ storeMessageInbox(user,
SieveFailureMessageComposer.composeMessage(aMail, ex, user));
+ }
+
+ protected void storeMessageInbox(String username, MimeMessage message)
throws MessagingException {
+ sievePoster.post("mailbox://" + username + "/", message);
+ }
+
+
+
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailet.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailet.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailet.java
deleted file mode 100644
index 5a6ea59..0000000
---
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailet.java
+++ /dev/null
@@ -1,315 +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.delivery;
-
-import java.io.IOException;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Vector;
-
-import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
-
-import org.apache.commons.logging.Log;
-import org.apache.james.mailbox.MailboxManager;
-import org.apache.james.transport.mailets.jsieve.ActionDispatcher;
-import org.apache.james.transport.mailets.jsieve.CommonsLoggingAdapter;
-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 org.apache.mailet.MailetException;
-import org.apache.mailet.base.GenericMailet;
-import org.apache.mailet.base.RFC2822Headers;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
-/**
- * Contains resource bindings.
- */
-public class SieveMailet extends GenericMailet {
-
- public static final String DELIVERED_TO = "Delivered-To";
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
- private UsersRepository usersRepos;
- private MailboxManager mailboxManager;
- private String folder;
- private ResourceLocator resourceLocator;
- private MailetContext mailetContext;
- private boolean consume;
- private Optional<Boolean> verbose = Optional.absent();
- private Optional<Boolean> quiet = Optional.absent();
-
- public Builder userRepository(UsersRepository usersRepository) {
- this.usersRepos = usersRepository;
- return this;
- }
-
- public Builder mailboxManager(MailboxManager mailboxManager) {
- this.mailboxManager = mailboxManager;
- return this;
- }
-
- public Builder folder(String folder) {
- this.folder = folder;
- return this;
- }
-
- public Builder resourceLocator(ResourceLocator resourceLocator) {
- this.resourceLocator = resourceLocator;
- return this;
- }
-
- public Builder verbose(boolean verbose) {
- this.verbose = Optional.of(verbose);
- return this;
- }
-
- public Builder consume(boolean consume) {
- this.consume = consume;
- return this;
- }
-
- public Builder quiet(boolean quiet) {
- this.quiet = Optional.of(quiet);
- return this;
- }
-
- public Builder mailetContext(MailetContext mailetContext) {
- this.mailetContext = mailetContext;
- return this;
- }
-
- public SieveMailet build() throws MessagingException {
- if (resourceLocator == null) {
- throw new MailetException("Not initialised. Please ensure that
the mailet container supports either setter or constructor injection");
- }
- return new SieveMailet(usersRepos, mailboxManager,
resourceLocator, mailetContext, folder, consume, verbose.or(false),
quiet.or(false));
- }
-
- }
-
- private final UsersRepository usersRepos;
- private final SievePoster sievePoster;
- private final String folder;
- private final ResourceLocator resourceLocator;
- private final boolean isInfo;
- private final boolean verbose;
- private final boolean consume;
- private final SieveFactory factory;
- private final ActionDispatcher actionDispatcher;
- private final Log log;
-
- private SieveMailet(UsersRepository usersRepos, MailboxManager
mailboxManager, ResourceLocator resourceLocator, MailetContext mailetContext,
String folder,
- boolean consume, boolean verbose, boolean quiet)
throws MessagingException {
- this.sievePoster = new SievePoster(mailboxManager, folder, usersRepos,
mailetContext);
- this.usersRepos = usersRepos;
- this.resourceLocator = resourceLocator;
- this.folder = folder;
- this.actionDispatcher = new ActionDispatcher();
- this.consume = consume;
- this.isInfo = verbose || !quiet;
- this.verbose = verbose;
- this.log = new CommonsLoggingAdapter(this, computeLogLevel(quiet,
verbose));
- try {
- final ConfigurationManager configurationManager = new
ConfigurationManager();
- configurationManager.setLog(log);
- factory = configurationManager.build();
- } catch (SieveConfigurationException e) {
- throw new MessagingException("Failed to load standard Sieve
configuration.", e);
- }
- }
-
- private int computeLogLevel(boolean quiet, boolean verbose) {
- if (verbose) {
- return CommonsLoggingAdapter.TRACE;
- } else if (quiet) {
- return CommonsLoggingAdapter.FATAL;
- } else {
- return CommonsLoggingAdapter.WARN;
- }
- }
-
- protected String getUsername(MailAddress m) {
- try {
- if (usersRepos.supportVirtualHosting()) {
- return m.toString();
- } else {
- return m.getLocalPart() + "@localhost";
- }
- } catch (UsersRepositoryException e) {
- log.error("Unable to access UsersRepository", e);
- return m.getLocalPart() + "@localhost";
-
- }
- }
-
- public void storeMail(MailAddress sender, 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);
- // If no exception was thrown the message was successfully stored in
the mailbox
- log.info("Local delivered mail " + mail.getName() + " sucessfully from
" + prettyPrint(sender) + " to " + prettyPrint(recipient)
- + " in folder " + this.folder);
- }
-
- private String prettyPrint(MailAddress mailAddress) {
- if (mailAddress != null) {
- return "<" + mailAddress.toString() + ">";
- } else {
- return "<>";
- }
- }
-
-
- /**
- * Delivers a mail to a local mailbox.
- *
- * @param mail
- * the mail being processed
- *
- * @throws MessagingException
- * if an error occurs while storing the mail
- */
- @SuppressWarnings("unchecked")
- @Override
- public void service(Mail mail) throws MessagingException {
- Collection<MailAddress> recipients = mail.getRecipients();
- Collection<MailAddress> errors = new Vector<MailAddress>();
-
- MimeMessage message = mail.getMessage();
-
- // Set Return-Path and remove all other Return-Path headers from the
- // message
- // This only works because there is a placeholder inserted by
- // MimeMessageWrapper
- message.setHeader(RFC2822Headers.RETURN_PATH,
prettyPrint(mail.getSender()));
-
- List<String> deliveredToHeader =
Collections.list(message.getMatchingHeaders(new String[] { DELIVERED_TO }));
- message.removeHeader(DELIVERED_TO);
-
- for (MailAddress recipient : recipients) {
- try {
- // Add qmail's de facto standard Delivered-To header
- message.addHeader(DELIVERED_TO, recipient.toString());
- storeMail(mail.getSender(), recipient, mail);
- message.removeHeader(DELIVERED_TO);
- } catch (Exception ex) {
- log.error("Error while storing mail.", ex);
- errors.add(recipient);
- }
- }
- for (String deliveredTo : deliveredToHeader) {
- message.addHeader(DELIVERED_TO, deliveredTo);
- }
- if (!errors.isEmpty()) {
- // If there were errors, we redirect the email to the ERROR
- // processor.
- // In order for this server to meet the requirements of the SMTP
- // specification, mails on the ERROR processor must be returned to
- // the sender. Note that this email doesn't include any details
- // regarding the details of the failure(s).
- // In the future we may wish to address this.
- getMailetContext().sendMail(mail.getSender(), errors,
mail.getMessage(), Mail.ERROR);
- }
- if (consume) {
- // Consume this message
- mail.setState(Mail.GHOST);
- }
- }
-
- protected void sieveMessage(MailAddress recipient, Mail aMail) throws
MessagingException {
- String username = getUsername(recipient);
- try {
- final ResourceLocator.UserSieveInformation userSieveInformation =
resourceLocator.get(getScriptUri(recipient));
- sieveMessageEvaluate(recipient, aMail, userSieveInformation);
- } 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
- if (isInfo) {
- log.error("Cannot evaluate Sieve script. Storing mail in user
INBOX.", ex);
- }
- storeMessageInbox(username, aMail.getMessage());
- }
- }
-
- private void sieveMessageEvaluate(MailAddress recipient, Mail aMail,
ResourceLocator.UserSieveInformation userSieveInformation) throws
MessagingException, IOException {
- try {
- SieveMailAdapter aMailAdapter = new SieveMailAdapter(aMail,
- getMailetContext(), actionDispatcher, sievePoster,
userSieveInformation.getScriptActivationDate(),
- userSieveInformation.getScriptInterpretationDate(), recipient);
- aMailAdapter.setLog(log);
- // This logging operation is potentially costly
- if (verbose) {
- log.error("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 void storeMessageInbox(String username, MimeMessage message)
throws MessagingException {
- sievePoster.post("mailbox://" + username + "/", message);
- }
-
-
- /**
- * Return the URI for the sieve script
- *
- * @param m
- * @return
- */
- protected String getScriptUri(MailAddress m) {
- return "//" + getUsername(m) + "/sieve";
- }
-
- protected void handleFailure(MailAddress recipient, Mail aMail, Exception
ex) throws MessagingException, IOException {
- String user = getUsername(recipient);
- storeMessageInbox(user,
SieveFailureMessageComposer.composeMessage(aMail, ex, user));
- }
-
-}
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/ToRecipientFolder.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/ToRecipientFolder.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/ToRecipientFolder.java
index c26b3f1..e791d9a 100644
---
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/ToRecipientFolder.java
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/ToRecipientFolder.java
@@ -18,21 +18,19 @@
****************************************************************/
package org.apache.james.transport.mailets.delivery;
-import com.google.common.collect.Iterators;
+import org.apache.commons.logging.Log;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.sieverepository.api.SieveRepository;
import org.apache.james.transport.mailets.ResourceLocatorImpl;
+import org.apache.james.transport.mailets.jsieve.CommonsLoggingAdapter;
import org.apache.james.user.api.UsersRepository;
import org.apache.mailet.Mail;
import org.apache.mailet.MailetConfig;
-import org.apache.mailet.MailetContext;
import org.apache.mailet.base.GenericMailet;
import javax.inject.Inject;
import javax.inject.Named;
import javax.mail.MessagingException;
-import java.util.Arrays;
-import java.util.Iterator;
/**
* Receives a Mail from the Queue and takes care to deliver the message
@@ -74,34 +72,37 @@ public class ToRecipientFolder extends GenericMailet {
this.usersRepository = usersRepository;
}
- private SieveMailet sieveMailet; // Mailet that actually stores the
message
+ private MailDispatcher mailDispatcher;
- /**
- * Delivers a mail to a local mailbox in a given folder.
- *
- * @see
org.apache.mailet.base.GenericMailet#service(org.apache.mailet.Mail)
- */
@Override
public void service(Mail mail) throws MessagingException {
if (!mail.getState().equals(Mail.GHOST)) {
- sieveMailet.service(mail);
+ mailDispatcher.dispatch(mail);
}
}
@Override
- public void init(MailetConfig mailetConfig) throws MessagingException {
- super.init(mailetConfig);
- sieveMailet = SieveMailet.builder()
- .mailboxManager(mailboxManager)
- .userRepository(usersRepository)
- .resourceLocator(ResourceLocatorImpl.instanciate(usersRepository,
sieveRepository))
- .mailetContext(getMailetContext())
- .folder(getInitParameter(FOLDER_PARAMETER, "INBOX"))
- .consume(getInitParameter(CONSUME_PARAMETER, false))
- .verbose(getInitParameter("verbose", false))
+ public void init() throws MessagingException {
+ Log log = CommonsLoggingAdapter.builder()
+ .mailet(this)
.quiet(getInitParameter("quiet", true))
+ .verbose(getInitParameter("verbose", false))
+ .build();
+ String folder = getInitParameter(FOLDER_PARAMETER, "INBOX");
+ mailDispatcher = MailDispatcher.builder()
+ .mailStorer(SieveMailStorer.builder()
+ .sievePoster(new SievePoster(mailboxManager, folder,
usersRepository, getMailetContext()))
+ .usersRepository(usersRepository)
+
.resourceLocator(ResourceLocatorImpl.instanciate(usersRepository,
sieveRepository))
+ .mailetContext(getMailetContext())
+ .mailboxManager(mailboxManager)
+ .folder(folder)
+ .log(log)
+ .build())
+ .consume(getInitParameter(CONSUME_PARAMETER, false))
+ .mailetContext(getMailetContext())
+ .log(log)
.build();
- sieveMailet.init(mailetConfig);
}
@Override
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/CommonsLoggingAdapter.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/CommonsLoggingAdapter.java
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/CommonsLoggingAdapter.java
index 66628af..20845ef 100644
---
a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/CommonsLoggingAdapter.java
+++
b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/CommonsLoggingAdapter.java
@@ -21,11 +21,54 @@ package org.apache.james.transport.mailets.jsieve;
import org.apache.commons.logging.Log;
import org.apache.mailet.base.GenericMailet;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
/**
* Adapts commons logging to mailet logging.
*/
public class CommonsLoggingAdapter implements Log {
-
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private Optional<Boolean> verbose = Optional.absent();
+ private Optional<Boolean> quiet = Optional.absent();
+ private GenericMailet genericMailet;
+
+ public Builder mailet(GenericMailet genericMailet) {
+ this.genericMailet = genericMailet;
+ return this;
+ }
+
+ public Builder verbose(boolean verbose) {
+ this.verbose = Optional.of(verbose);
+ return this;
+ }
+
+ public Builder quiet(boolean quiet) {
+ this.quiet = Optional.of(quiet);
+ return this;
+ }
+
+ public CommonsLoggingAdapter build() {
+ Preconditions.checkNotNull(genericMailet);
+ return new CommonsLoggingAdapter(genericMailet,
computeLogLevel(quiet.or(false), verbose.or(false)));
+ }
+
+ private int computeLogLevel(boolean quiet, boolean verbose) {
+ if (verbose) {
+ return CommonsLoggingAdapter.TRACE;
+ } else if (quiet) {
+ return CommonsLoggingAdapter.FATAL;
+ } else {
+ return CommonsLoggingAdapter.WARN;
+ }
+ }
+ }
+
public static final int TRACE = 6;
public static final int DEBUG = 5;
public static final int INFO = 4;
http://git-wip-us.apache.org/repos/asf/james-project/blob/ca85c529/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/DeliveryUtilsTest.java
----------------------------------------------------------------------
diff --git
a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/DeliveryUtilsTest.java
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/DeliveryUtilsTest.java
new file mode 100644
index 0000000..287f771
--- /dev/null
+++
b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/DeliveryUtilsTest.java
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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.delivery;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.mailet.base.MailAddressFixture;
+import org.junit.Test;
+
+public class DeliveryUtilsTest {
+
+ @Test
+ public void prettyPrintShouldDisplayNullAddresses() {
+ assertThat(DeliveryUtils.prettyPrint(null)).isEqualTo("<>");
+ }
+
+ @Test
+ public void prettyPrintShouldDisplayAddresses() {
+ assertThat(DeliveryUtils.prettyPrint(MailAddressFixture.ANY_AT_JAMES))
+ .isEqualTo("<" + MailAddressFixture.ANY_AT_JAMES + ">");
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]