FileDocCategorySizeDatePackage
UsersRepositoryAliasingForwarding.javaAPI DocApache James 2.3.111131Fri Jan 12 12:56:30 GMT 2007org.apache.james.transport.mailets

UsersRepositoryAliasingForwarding.java

/****************************************************************
 * 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 org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.james.Constants;
import org.apache.james.services.JamesUser;
import org.apache.james.services.User;
import org.apache.james.services.UsersRepository;
import org.apache.james.services.UsersStore;
import org.apache.mailet.RFC2822Headers;

import org.apache.mailet.GenericMailet;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;

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

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Vector;

/**
 * Receives a Mail from JamesSpoolManager and takes care of delivery of the
 * message to local inboxes.
 * 
 * Available configurations are:
 * 
 * <enableAliases>true</enableAliases>: specify wether the user aliases should
 * be looked up or not. Default is false.
 * 
 * <enableForwarding>true</enableForwarding>: enable the forwarding. Default to
 * false.
 * 
 * <usersRepository>LocalAdmins</usersRepository>: specific users repository
 * name. Default to empty. If empty does lookup the default userRepository.
 */
public class UsersRepositoryAliasingForwarding extends GenericMailet {

    /**
     * The user repository for this mail server. Contains all the users with
     * inboxes on this server.
     */
    private UsersRepository usersRepository;

    /**
     * Whether to enable aliasing for users on this server
     */
    private boolean enableAliases;

    /**
     * Whether to enable forwarding for users on this server
     */
    private boolean enableForwarding;

    /**
     * Whether to ignore case when looking up user names on this server
     */
    private boolean ignoreCase;

    /**
     * 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 = 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,
                        (mail.getSender() == null ? "<>" : "<"
                                + mail.getSender() + ">"));

        Collection newRecipients = new LinkedList();
        for (Iterator i = recipients.iterator(); i.hasNext();) {
            MailAddress recipient = (MailAddress) i.next();
            try {
                String username = processMail(mail.getSender(), recipient,
                        message);

                // if the username is null or changed we remove it from the
                // remaining recipients
                if (username == null) {
                    i.remove();
                } else if (!username.equals(recipient.getUser())) {
                    i.remove();
                    // if the username has been changed we add a new recipient
                    // with the new name.
                    newRecipients.add(new MailAddress(username, recipient
                            .getHost()));
                }

            } catch (Exception ex) {
                getMailetContext().log("Error while storing mail.", ex);
                errors.add(recipient);
            }
        }

        if (newRecipients.size() > 0) {
            recipients.addAll(newRecipients);
        }

        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, message,
                    Mail.ERROR);
        }

        if (recipients.size() == 0) {
            // We always consume this message
            mail.setState(Mail.GHOST);
        }
    }

    /**
     * Return a string describing this mailet.
     * 
     * @return a string describing this mailet
     */
    public String getMailetInfo() {
        return "Local User Aliasing and Forwarding Mailet";
    }

    /**
     * Return null when the mail should be GHOSTed, the username string when it
     * should be changed due to the ignoreUser configuration.
     * 
     * @param sender
     * @param recipient
     * @param message
     * @throws MessagingException
     */
    public String processMail(MailAddress sender, MailAddress recipient,
            MimeMessage message) throws MessagingException {
        String username;
        if (recipient == null) {
            throw new IllegalArgumentException(
                    "Recipient for mail to be spooled cannot be null.");
        }
        if (message == null) {
            throw new IllegalArgumentException(
                    "Mail message to be spooled cannot be null.");
        }
        if (ignoreCase) {
            String originalUsername = recipient.getUser();
            username = usersRepository.getRealName(originalUsername);
            if (username == null) {
                StringBuffer errorBuffer = new StringBuffer(128).append(
                        "The inbox for user ").append(originalUsername).append(
                        " was not found on this server.");
                throw new MessagingException(errorBuffer.toString());
            }
        } else {
            username = recipient.getUser();
        }
        User user;
        if (enableAliases || enableForwarding) {
            user = usersRepository.getUserByName(username);
            if (user instanceof JamesUser) {
                if (enableAliases && ((JamesUser) user).getAliasing()) {
                    username = ((JamesUser) user).getAlias();
                }
                // Forwarding takes precedence over local aliases
                if (enableForwarding && ((JamesUser) user).getForwarding()) {
                    MailAddress forwardTo = ((JamesUser) user).getForwardingDestination();
                    if (forwardTo == null) {
                        StringBuffer errorBuffer = new StringBuffer(128)
                                .append("Forwarding was enabled for ")
                                .append(username)
                                .append(
                                        " but no forwarding address was set for this account.");
                        throw new MessagingException(errorBuffer.toString());
                    }
                    Collection recipients = new HashSet();
                    recipients.add(forwardTo);
                    try {
                        getMailetContext().sendMail(sender, recipients, message);
                        StringBuffer logBuffer = new StringBuffer(128).append(
                                "Mail for ").append(username).append(
                                " forwarded to ").append(forwardTo.toString());
                        getMailetContext().log(logBuffer.toString());
                        return null;
                    } catch (MessagingException me) {
                        StringBuffer logBuffer = new StringBuffer(128).append(
                                "Error forwarding mail to ").append(
                                forwardTo.toString()).append(
                                "attempting local delivery");
                        getMailetContext().log(logBuffer.toString());
                        throw me;
                    }
                }
            }
        }
        return username;
    }

    /**
     * @see org.apache.mailet.GenericMailet#init()
     */
    public void init() throws MessagingException {
        super.init();
        ServiceManager compMgr = (ServiceManager) getMailetContext()
                .getAttribute(Constants.AVALON_COMPONENT_MANAGER);

        UsersStore usersStore;
        try {
            usersStore = (UsersStore) compMgr.lookup(UsersStore.ROLE);


            enableAliases = new Boolean(getInitParameter("enableAliases",
                    getMailetContext().getAttribute(Constants.DEFAULT_ENABLE_ALIASES).toString()
                    )).booleanValue();
            enableForwarding = new Boolean(getInitParameter("enableForwarding",
                    getMailetContext().getAttribute(Constants.DEFAULT_ENABLE_FORWARDING).toString()
                    )).booleanValue();
            ignoreCase = new Boolean(getInitParameter("ignoreCase",
                    getMailetContext().getAttribute(Constants.DEFAULT_IGNORE_USERNAME_CASE).toString()
                    )).booleanValue();
            
            String userRep = getInitParameter("usersRepository");
            if (userRep == null || userRep.length() == 0) {
                try {
                    usersRepository = (UsersRepository) compMgr
                            .lookup(UsersRepository.ROLE);
                } catch (ServiceException e) {
                    log("Failed to retrieve UsersRepository component:"
                            + e.getMessage());
                }
            } else {
                usersRepository = usersStore.getRepository(userRep);
            }

        } catch (ServiceException cnfe) {
            log("Failed to retrieve UsersStore component:" + cnfe.getMessage());
        }

    }

}