All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.jsieve.mailet.SieveMailboxMailet Maven / Gradle / Ivy

Go to download

Apache jSieve is a server side mail filtering system implementing RFC3028. Apache jSieve is developed by the James project.

There is a newer version: 0.5
Show newest version
/****************************************************************
 * 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.jsieve.mailet;

import java.io.InputStream;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

import javax.mail.Header;
import javax.mail.MessagingException;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeMessage;

import org.apache.commons.logging.Log;
import org.apache.jsieve.ConfigurationManager;
import org.apache.jsieve.SieveConfigurationException;
import org.apache.jsieve.SieveFactory;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.apache.mailet.MailetConfig;
import org.apache.mailet.MailetException;
import org.apache.mailet.base.GenericMailet;
import org.apache.mailet.base.RFC2822Headers;

/**
 * 

Executes a Sieve * script against incoming mail. The script applied is based on the recipient.

*

Init Parameters

* * * * *
NameRequiredValuesRole
verboseNo - defaults to falsetrue (ignoring case) to enable, otherwise disable * Enables verbose logging. *
*/ public class SieveMailboxMailet extends GenericMailet { /** * The delivery header */ private String deliveryHeader; /** * resetReturnPath */ private boolean resetReturnPath; /** Experimental */ private Poster poster; /** Experimental */ private ResourceLocator locator; /** Indicates whether this mailet should log verbosely */ private boolean verbose = false; private boolean consume = true; /** Indicates whether this mailet should log minimal information */ private boolean quiet = true; private SieveFactory factory; private ActionDispatcher actionDispatcher; private Log log; /** * For SDI */ public SieveMailboxMailet() {} /** * CDI * @param poster not null */ public SieveMailboxMailet(Poster poster, ResourceLocator locator) { this(); this.poster = poster; this.locator = locator; } public ResourceLocator getLocator() { return locator; } /** * For SDI * @param locator not null */ public void setLocator(ResourceLocator locator) { this.locator = locator; } public Poster getPoster() { return poster; } /** * For SDI * @param poster not null */ public void setPoster(Poster poster) { this.poster = poster; } /** * Is this mailet GHOSTing all mail it processes? * @return true when mailet consumes all mail, false otherwise */ public boolean isConsume() { return consume; } /** * Sets whether this mailet should GHOST all mail. * @param consume true when the mailet should consume all mail, * false otherwise */ public void setConsume(boolean consume) { this.consume = consume; } /** * Is this mailet logging verbosely? * This property is set by init parameters. * @return true if logging should be verbose, false otherwise */ public boolean isVerbose() { return verbose; } /** * Sets whether logging should be verbose for this mailet. * This property is set by init parameters. * This setting overrides {@link #isQuiet()}. * @param verbose true when logging should be verbose, * false otherwise */ public void setVerbose(boolean verbose) { this.verbose = verbose; } /** * Is the logging for this mailet set to minimal? * @return true */ public boolean isQuiet() { return quiet; } /** * Sets the logging for this mailet to minimal. * This is overriden by {@link #setVerbose(boolean)}. * @param quiet true for minimal logging, false otherwise */ public void setQuiet(boolean quiet) { this.quiet = quiet; } /** * Is informational logging turned on? * @return true when minimal logging is off, * false when logging is minimal */ public boolean isInfoLoggingOn() { return verbose || !quiet; } //@Override public void init(MailetConfig config) throws MessagingException { super.init(config); try { final ConfigurationManager configurationManager = new ConfigurationManager(); final int logLevel; if (verbose) { logLevel = CommonsLoggingAdapter.TRACE; } else if (quiet) { logLevel = CommonsLoggingAdapter.FATAL; } else { logLevel = CommonsLoggingAdapter.WARN; } log = new CommonsLoggingAdapter(this, logLevel); configurationManager.setLog(log); factory = configurationManager.build(); } catch (SieveConfigurationException e) { throw new MessagingException("Failed to load standard Sieve configuration.", e); } } /** * 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 { Collection recipients = mail.getRecipients(); Collection errors = new Vector(); MimeMessage message = null; if (deliveryHeader != null || resetReturnPath) { message = mail.getMessage(); } if (resetReturnPath) { // 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, (mail.getSender() == null ? "<>" : "<" + mail.getSender() + ">")); } Enumeration headers; InternetHeaders deliveredTo = new InternetHeaders(); if (deliveryHeader != null) { // Copy any Delivered-To headers from the message headers = message .getMatchingHeaders(new String[] { deliveryHeader }); while (headers.hasMoreElements()) { Header header = (Header) headers.nextElement(); deliveredTo.addHeader(header.getName(), header.getValue()); } } for (Iterator i = recipients.iterator(); i.hasNext();) { MailAddress recipient = (MailAddress) i.next(); try { if (deliveryHeader != null) { // Add qmail's de facto standard Delivered-To header message.addHeader(deliveryHeader, recipient.toString()); } storeMail(mail.getSender(), recipient, mail); if (deliveryHeader != null) { if (i.hasNext()) { // Remove headers but leave all placeholders message.removeHeader(deliveryHeader); headers = deliveredTo.getAllHeaders(); // And restore any original Delivered-To headers while (headers.hasMoreElements()) { Header header = (Header) headers.nextElement(); message.addHeader(header.getName(), header .getValue()); } } } } catch (Exception ex) { log("Error while storing mail.", ex); errors.add(recipient); } } 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); } } /** * Return a string describing this mailet. * * @return a string describing this mailet */ public String getMailetInfo() { return "Sieve Mailbox Mailet"; } /** * * @param sender * @param recipient * @param mail * @throws MessagingException */ public void storeMail(MailAddress sender, MailAddress recipient, Mail mail) throws MessagingException { String username; if (recipient == null) { throw new IllegalArgumentException( "Recipient for mail to be spooled cannot be null."); } if (mail.getMessage() == null) { throw new IllegalArgumentException( "Mail message to be spooled cannot be null."); } // recipient.toString was used here (JD) username = recipient.getUser(); sieveMessage(username, mail); } void sieveMessage(String username, Mail aMail) throws MessagingException { // Evaluate the script against the mail String relativeUri = "//" + username + "@" + "localhost/sieve"; try { final InputStream ins = locator.get(relativeUri); SieveMailAdapter aMailAdapter = new SieveMailAdapter(aMail, getMailetContext(), actionDispatcher, poster); aMailAdapter.setLog(log); // This logging operation is potentially costly if (verbose) { log("Evaluating " + aMailAdapter.toString() + "against \"" + relativeUri + "\""); } factory.evaluate(aMailAdapter, factory.parse(ins)); } catch (Exception ex) { // // SLIEVE is a mail filtering protocol. // Rejecting the mail because it cannot be filtered // seems very unfriendly. // So just log and store in INBOX. // if (isInfoLoggingOn()) { log("Cannot evaluate Sieve script. Storing mail in user INBOX.", ex); } storeMessageInbox(username, aMail); } } void storeMessageInbox(String username, Mail mail) throws MessagingException { String url = "mailbox://" + username + "@localhost/"; poster.post(url, mail.getMessage()); } /** * @see org.apache.mailet.base.GenericMailet#init() */ public void init() throws MessagingException { super.init(); if (poster == null || locator == null) { throw new MailetException("Not initialised. Please ensure that the mailet container supports either" + " setter or constructor injection"); } this.deliveryHeader = getInitParameter("addDeliveryHeader"); this.resetReturnPath = getInitParameter("resetReturnPath", true); this.consume = getInitParameter("consume", true); this.verbose = getInitParameter("verbose", false); this.quiet = getInitParameter("quiet", false); actionDispatcher = new ActionDispatcher(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy