JAMES-1854 Move Sieve related classes in SIEVE package
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/05b9040d Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/05b9040d Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/05b9040d Branch: refs/heads/master Commit: 05b9040d380f8ef7b6d63de492f8fd612a95604a Parents: e9cba9c Author: Benoit Tellier <[email protected]> Authored: Fri Oct 28 15:58:56 2016 +0200 Committer: Benoit Tellier <[email protected]> Committed: Fri Nov 18 18:46:46 2016 +0700 ---------------------------------------------------------------------- .../transport/mailets/SieveLocalDelivery.java | 6 +- .../mailets/SieveToRecipientFolder.java | 4 +- .../delivery/SieveFailureMessageComposer.java | 57 ------ .../mailets/delivery/SieveMailStorer.java | 184 ------------------ .../transport/mailets/delivery/SievePoster.java | 106 ----------- .../delivery/SieveFailureMessageComposer.java | 57 ++++++ .../jsieve/delivery/SieveMailStorer.java | 186 +++++++++++++++++++ .../mailets/jsieve/delivery/SievePoster.java | 108 +++++++++++ .../mailets/delivery/SieveIntegrationTest.java | 2 + 9 files changed, 357 insertions(+), 353 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/05b9040d/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 index 9dfa5f2..6826c83 100644 --- 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 @@ -27,12 +27,10 @@ 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.delivery.MailDispatcher; import org.apache.james.transport.mailets.delivery.MailboxAppender; -import org.apache.james.transport.mailets.delivery.SieveMailStorer; -import org.apache.james.transport.mailets.delivery.SievePoster; +import org.apache.james.transport.mailets.jsieve.delivery.SieveMailStorer; +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; http://git-wip-us.apache.org/repos/asf/james-project/blob/05b9040d/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 index a574a15..56d3a7c 100644 --- 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 @@ -27,8 +27,8 @@ import org.apache.james.mailbox.MailboxManager; 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.delivery.SieveMailStorer; -import org.apache.james.transport.mailets.delivery.SievePoster; +import org.apache.james.transport.mailets.jsieve.delivery.SieveMailStorer; +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; http://git-wip-us.apache.org/repos/asf/james-project/blob/05b9040d/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveFailureMessageComposer.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveFailureMessageComposer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveFailureMessageComposer.java deleted file mode 100644 index 241c714..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveFailureMessageComposer.java +++ /dev/null @@ -1,57 +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 javax.mail.MessagingException; -import javax.mail.internet.MimeBodyPart; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeMultipart; - -import org.apache.mailet.Mail; - -public class SieveFailureMessageComposer { - - public static MimeMessage composeMessage(Mail aMail, Exception ex, String user) throws MessagingException { - MimeMessage originalMessage = aMail.getMessage(); - MimeMessage message = new MimeMessage(originalMessage); - MimeMultipart multipart = new MimeMultipart(); - - MimeBodyPart noticePart = new MimeBodyPart(); - noticePart.setText("An error was encountered while processing this mail with the active sieve script for user \"" - + user + "\". The error encountered was:\r\n" + ex.getLocalizedMessage() + "\r\n"); - multipart.addBodyPart(noticePart); - - MimeBodyPart originalPart = new MimeBodyPart(); - originalPart.setContent(originalMessage, "message/rfc822"); - if ((originalMessage.getSubject() != null) && (!originalMessage.getSubject().trim().isEmpty())) { - originalPart.setFileName(originalMessage.getSubject().trim()); - } else { - originalPart.setFileName("No Subject"); - } - originalPart.setDisposition(MimeBodyPart.INLINE); - multipart.addBodyPart(originalPart); - - message.setContent(multipart); - message.setSubject("[SIEVE ERROR] " + originalMessage.getSubject()); - message.setHeader("X-Priority", "1"); - message.saveChanges(); - return message; - } -} http://git-wip-us.apache.org/repos/asf/james-project/blob/05b9040d/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 deleted file mode 100644 index 5cfd2c0..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SieveMailStorer.java +++ /dev/null @@ -1,184 +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 javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; - -import org.apache.commons.logging.Log; -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; - - 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 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, 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 SieveMailStorer(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; - 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/05b9040d/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SievePoster.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SievePoster.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SievePoster.java deleted file mode 100644 index ce6ba76..0000000 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SievePoster.java +++ /dev/null @@ -1,106 +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 javax.mail.MessagingException; -import javax.mail.internet.MimeMessage; - -import org.apache.james.mailbox.MailboxSession; -import org.apache.james.mailbox.model.MailboxConstants; -import org.apache.james.mailbox.model.MailboxPath; -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.MailetContext; - -import com.google.common.base.Strings; - -public class SievePoster implements Poster { - - private final MailboxAppender mailboxAppender; - private final String folder; - private final UsersRepository usersRepos; - private final MailetContext mailetContext; - - public SievePoster(MailboxAppender mailboxAppender, String folder, UsersRepository usersRepos, MailetContext mailetContext) { - this.mailboxAppender = mailboxAppender; - this.folder = folder; - this.usersRepos = usersRepos; - this.mailetContext = mailetContext; - } - - @Override - public void post(String url, MimeMessage mail) throws MessagingException { - final int endOfScheme = url.indexOf(':'); - if (endOfScheme < 0) { - throw new MessagingException("Malformed URI"); - } else { - final String scheme = url.substring(0, endOfScheme); - if (scheme.equals("mailbox")) { - handleMailboxProtocol(url, mail, endOfScheme); - } else { - throw new MessagingException("Unsupported protocol"); - } - } - } - - private void handleMailboxProtocol(String url, MimeMessage mail, int endOfScheme) throws MessagingException { - int startOfUser = endOfScheme + 3; - int endOfUser = url.indexOf('@', startOfUser); - int startOfHost = endOfUser + 1; - int endOfHost = url.indexOf('/', startOfHost); - if (endOfUser < 0) { - // TODO: When user missing, append to a default location - throw new MessagingException("Shared mailbox is not supported"); - } else { - String host = url.substring(startOfHost, endOfHost); - String user = parseUser(url, startOfUser, endOfUser, host); - String urlPath = parseUrlPath(url, endOfHost); - - mailboxAppender.appendAndUseSlashAsSeparator(mail, user, urlPath, folder); - } - } - - private String parseUrlPath(String url, int endOfHost) { - String urlPath; - int length = url.length(); - if (endOfHost + 1 == length) { - urlPath = this.folder; - } else { - urlPath = url.substring(endOfHost, length); - } - return urlPath; - } - - private String parseUser(String url, int startOfUser, int endOfUser, String host) throws MessagingException { - // lowerCase the user - see - // https://issues.apache.org/jira/browse/JAMES-1369 - String user = url.substring(startOfUser, endOfUser).toLowerCase(); - // Check if we should use the full email address as username - try { - if (usersRepos.supportVirtualHosting()) { - return user + "@" + host; - } - return user; - } catch (UsersRepositoryException e) { - throw new MessagingException("Unable to accessUsersRepository", e); - } - } -} http://git-wip-us.apache.org/repos/asf/james-project/blob/05b9040d/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveFailureMessageComposer.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveFailureMessageComposer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveFailureMessageComposer.java new file mode 100644 index 0000000..ba22dfe --- /dev/null +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveFailureMessageComposer.java @@ -0,0 +1,57 @@ +/**************************************************************** + * 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 javax.mail.MessagingException; +import javax.mail.internet.MimeBodyPart; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimeMultipart; + +import org.apache.mailet.Mail; + +public class SieveFailureMessageComposer { + + public static MimeMessage composeMessage(Mail aMail, Exception ex, String user) throws MessagingException { + MimeMessage originalMessage = aMail.getMessage(); + MimeMessage message = new MimeMessage(originalMessage); + MimeMultipart multipart = new MimeMultipart(); + + MimeBodyPart noticePart = new MimeBodyPart(); + noticePart.setText("An error was encountered while processing this mail with the active sieve script for user \"" + + user + "\". The error encountered was:\r\n" + ex.getLocalizedMessage() + "\r\n"); + multipart.addBodyPart(noticePart); + + MimeBodyPart originalPart = new MimeBodyPart(); + originalPart.setContent(originalMessage, "message/rfc822"); + if ((originalMessage.getSubject() != null) && (!originalMessage.getSubject().trim().isEmpty())) { + originalPart.setFileName(originalMessage.getSubject().trim()); + } else { + originalPart.setFileName("No Subject"); + } + originalPart.setDisposition(MimeBodyPart.INLINE); + multipart.addBodyPart(originalPart); + + message.setContent(multipart); + message.setSubject("[SIEVE ERROR] " + originalMessage.getSubject()); + message.setHeader("X-Priority", "1"); + message.saveChanges(); + return message; + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/05b9040d/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveMailStorer.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveMailStorer.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveMailStorer.java new file mode 100644 index 0000000..f4c04f2 --- /dev/null +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SieveMailStorer.java @@ -0,0 +1,186 @@ +/**************************************************************** + * 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.MailStorer; +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; + + 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 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, 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 SieveMailStorer(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; + 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/05b9040d/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 new file mode 100644 index 0000000..f530ad3 --- /dev/null +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/jsieve/delivery/SievePoster.java @@ -0,0 +1,108 @@ +/**************************************************************** + * 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 javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.model.MailboxConstants; +import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.transport.mailets.delivery.DeliveryUtils; +import org.apache.james.transport.mailets.delivery.MailboxAppender; +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.MailetContext; + +import com.google.common.base.Strings; + +public class SievePoster implements Poster { + + private final MailboxAppender mailboxAppender; + private final String folder; + private final UsersRepository usersRepos; + private final MailetContext mailetContext; + + public SievePoster(MailboxAppender mailboxAppender, String folder, UsersRepository usersRepos, MailetContext mailetContext) { + this.mailboxAppender = mailboxAppender; + this.folder = folder; + this.usersRepos = usersRepos; + this.mailetContext = mailetContext; + } + + @Override + public void post(String url, MimeMessage mail) throws MessagingException { + final int endOfScheme = url.indexOf(':'); + if (endOfScheme < 0) { + throw new MessagingException("Malformed URI"); + } else { + final String scheme = url.substring(0, endOfScheme); + if (scheme.equals("mailbox")) { + handleMailboxProtocol(url, mail, endOfScheme); + } else { + throw new MessagingException("Unsupported protocol"); + } + } + } + + private void handleMailboxProtocol(String url, MimeMessage mail, int endOfScheme) throws MessagingException { + int startOfUser = endOfScheme + 3; + int endOfUser = url.indexOf('@', startOfUser); + int startOfHost = endOfUser + 1; + int endOfHost = url.indexOf('/', startOfHost); + if (endOfUser < 0) { + // TODO: When user missing, append to a default location + throw new MessagingException("Shared mailbox is not supported"); + } else { + String host = url.substring(startOfHost, endOfHost); + String user = parseUser(url, startOfUser, endOfUser, host); + String urlPath = parseUrlPath(url, endOfHost); + + mailboxAppender.appendAndUseSlashAsSeparator(mail, user, urlPath, folder); + } + } + + private String parseUrlPath(String url, int endOfHost) { + String urlPath; + int length = url.length(); + if (endOfHost + 1 == length) { + urlPath = this.folder; + } else { + urlPath = url.substring(endOfHost, length); + } + return urlPath; + } + + private String parseUser(String url, int startOfUser, int endOfUser, String host) throws MessagingException { + // lowerCase the user - see + // https://issues.apache.org/jira/browse/JAMES-1369 + String user = url.substring(startOfUser, endOfUser).toLowerCase(); + // Check if we should use the full email address as username + try { + if (usersRepos.supportVirtualHosting()) { + return user + "@" + host; + } + return user; + } catch (UsersRepositoryException e) { + throw new MessagingException("Unable to accessUsersRepository", e); + } + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/05b9040d/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java ---------------------------------------------------------------------- diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java index 4158231..8c502fd 100644 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SieveIntegrationTest.java @@ -51,6 +51,8 @@ import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.sieverepository.api.exception.ScriptNotFoundException; import org.apache.james.transport.mailets.jsieve.ResourceLocator; +import org.apache.james.transport.mailets.jsieve.delivery.SieveMailStorer; +import org.apache.james.transport.mailets.jsieve.delivery.SievePoster; import org.apache.james.user.api.UsersRepository; import org.apache.mailet.Mail; import org.apache.mailet.MailAddress; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
