org.apache.james.protocols.smtp.core.MailCmdHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.james.protocols.smtp.core.MailCmdHandler.java

Source

/****************************************************************
 * 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.protocols.smtp.core;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.james.protocols.api.ProtocolSession.State;
import org.apache.james.protocols.api.Request;
import org.apache.james.protocols.api.Response;
import org.apache.james.protocols.smtp.MailAddress;
import org.apache.james.protocols.smtp.SMTPResponse;
import org.apache.james.protocols.smtp.SMTPRetCode;
import org.apache.james.protocols.smtp.SMTPSession;
import org.apache.james.protocols.smtp.dsn.DSNStatus;
import org.apache.james.protocols.smtp.hook.HookResult;
import org.apache.james.protocols.smtp.hook.MailHook;
import org.apache.james.protocols.smtp.hook.MailParametersHook;

/**
 * Handles MAIL command
 */
public class MailCmdHandler extends AbstractHookableCmdHandler<MailHook> {
    private static final Collection<String> COMMANDS = Collections.unmodifiableCollection(Arrays.asList("MAIL"));
    private static final Response SENDER_ALREADY_SPECIFIED = new SMTPResponse(SMTPRetCode.BAD_SEQUENCE,
            DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_OTHER) + " Sender already specified")
                    .immutable();
    private static final Response EHLO_HELO_NEEDED = new SMTPResponse(SMTPRetCode.BAD_SEQUENCE,
            DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_OTHER) + " Need HELO or EHLO before MAIL")
                    .immutable();
    private static final Response SYNTAX_ERROR_ARG = new SMTPResponse(SMTPRetCode.SYNTAX_ERROR_ARGUMENTS,
            DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_ARG) + " Usage: MAIL FROM:<sender>")
                    .immutable();
    private static final Response SYNTAX_ERROR = new SMTPResponse(SMTPRetCode.SYNTAX_ERROR_ARGUMENTS,
            DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.ADDRESS_SYNTAX_SENDER)
                    + " Syntax error in MAIL command").immutable();
    private static final Response SYNTAX_ERROR_ADDRESS = new SMTPResponse(SMTPRetCode.SYNTAX_ERROR_ARGUMENTS,
            DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.ADDRESS_SYNTAX_SENDER)
                    + " Syntax error in sender address").immutable();
    /**
     * A map of parameterHooks
     */
    private Map<String, MailParametersHook> paramHooks;

    @Override
    public void init(Configuration config) throws ConfigurationException {

    }

    @Override
    public void destroy() {

    }

    /**
     * @see
     * org.apache.james.protocols.smtp.core.AbstractHookableCmdHandler
     * #onCommand(SMTPSession, Request)
     */
    public Response onCommand(SMTPSession session, Request request) {
        Response response = super.onCommand(session, request);
        // Check if the response was not ok
        if (response.getRetCode().equals(SMTPRetCode.MAIL_OK) == false) {
            // cleanup the session
            session.setAttachment(SMTPSession.SENDER, null, State.Transaction);
        }

        return response;
    }

    /**
      * Handler method called upon receipt of a MAIL command. Sets up handler to
      * deliver mail as the stated sender.
      * 
      * @param session
      *            SMTP session object
      * @param argument
      *            the argument passed in with the command by the SMTP client
      */
    private Response doMAIL(SMTPSession session, String argument) {
        StringBuilder responseBuffer = new StringBuilder();
        MailAddress sender = (MailAddress) session.getAttachment(SMTPSession.SENDER, State.Transaction);
        responseBuffer.append(DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.ADDRESS_OTHER)).append(" Sender <");
        if (sender != null) {
            responseBuffer.append(sender);
        }
        responseBuffer.append("> OK");
        return new SMTPResponse(SMTPRetCode.MAIL_OK, responseBuffer);
    }

    /**
     * @see org.apache.james.protocols.api.handler.CommandHandler#getImplCommands()
     */
    public Collection<String> getImplCommands() {
        return COMMANDS;
    }

    /**
     * @see org.apache.james.protocols.smtp.core.AbstractHookableCmdHandler#doCoreCmd(org.apache.james.protocols.smtp.SMTPSession,
     *      java.lang.String, java.lang.String)
     */
    protected Response doCoreCmd(SMTPSession session, String command, String parameters) {
        return doMAIL(session, parameters);
    }

    /**
     * @see org.apache.james.protocols.smtp.core.AbstractHookableCmdHandler#doFilterChecks(org.apache.james.protocols.smtp.SMTPSession,
     *      java.lang.String, java.lang.String)
     */
    protected Response doFilterChecks(SMTPSession session, String command, String parameters) {
        return doMAILFilter(session, parameters);
    }

    /**
     * @param session
     *            SMTP session object
     * @param argument
     *            the argument passed in with the command by the SMTP client
     */
    private Response doMAILFilter(SMTPSession session, String argument) {
        String sender = null;

        if ((argument != null) && (argument.indexOf(":") > 0)) {
            int colonIndex = argument.indexOf(":");
            sender = argument.substring(colonIndex + 1);
            argument = argument.substring(0, colonIndex);
        }
        if (session.getAttachment(SMTPSession.SENDER, State.Transaction) != null) {
            return SENDER_ALREADY_SPECIFIED;
        } else if (session.getAttachment(SMTPSession.CURRENT_HELO_MODE, State.Connection) == null
                && session.getConfiguration().useHeloEhloEnforcement()) {
            return EHLO_HELO_NEEDED;
        } else if (argument == null || !argument.toUpperCase(Locale.US).equals("FROM") || sender == null) {
            return SYNTAX_ERROR_ARG;
        } else {
            sender = sender.trim();
            // the next gt after the first lt ... AUTH may add more <>
            int lastChar = sender.indexOf('>', sender.indexOf('<'));
            // Check to see if any options are present and, if so, whether they
            // are correctly formatted
            // (separated from the closing angle bracket by a ' ').
            if ((lastChar > 0) && (sender.length() > lastChar + 2) && (sender.charAt(lastChar + 1) == ' ')) {
                String mailOptionString = sender.substring(lastChar + 2);

                // Remove the options from the sender
                sender = sender.substring(0, lastChar + 1);

                StringTokenizer optionTokenizer = new StringTokenizer(mailOptionString, " ");
                while (optionTokenizer.hasMoreElements()) {
                    String mailOption = optionTokenizer.nextToken();
                    int equalIndex = mailOption.indexOf('=');
                    String mailOptionName = mailOption;
                    String mailOptionValue = "";
                    if (equalIndex > 0) {
                        mailOptionName = mailOption.substring(0, equalIndex).toUpperCase(Locale.US);
                        mailOptionValue = mailOption.substring(equalIndex + 1);
                    }

                    // Handle the SIZE extension keyword

                    if (paramHooks.containsKey(mailOptionName)) {
                        MailParametersHook hook = paramHooks.get(mailOptionName);
                        SMTPResponse res = calcDefaultSMTPResponse(
                                hook.doMailParameter(session, mailOptionName, mailOptionValue));
                        if (res != null) {
                            return res;
                        }
                    } else {
                        // Unexpected option attached to the Mail command
                        if (session.getLogger().isDebugEnabled()) {
                            StringBuilder debugBuffer = new StringBuilder(128)
                                    .append("MAIL command had unrecognized/unexpected option ")
                                    .append(mailOptionName).append(" with value ").append(mailOptionValue);
                            session.getLogger().debug(debugBuffer.toString());
                        }
                    }
                }
            }
            if (session.getConfiguration().useAddressBracketsEnforcement()
                    && (!sender.startsWith("<") || !sender.endsWith(">"))) {
                if (session.getLogger().isInfoEnabled()) {
                    StringBuilder errorBuffer = new StringBuilder(128).append("Error parsing sender address: ")
                            .append(sender).append(": did not start and end with < >");
                    session.getLogger().info(errorBuffer.toString());
                }
                return SYNTAX_ERROR;
            }
            MailAddress senderAddress = null;

            if (session.getConfiguration().useAddressBracketsEnforcement()
                    || (sender.startsWith("<") && sender.endsWith(">"))) {
                // Remove < and >
                sender = sender.substring(1, sender.length() - 1);
            }

            if (sender.length() == 0) {
                // This is the <> case. Let senderAddress == null
            } else {

                if (!sender.contains("@")) {
                    sender = sender + "@" + getDefaultDomain();
                }

                try {
                    senderAddress = new MailAddress(sender);
                } catch (Exception pe) {
                    if (session.getLogger().isInfoEnabled()) {
                        StringBuilder errorBuffer = new StringBuilder(256).append("Error parsing sender address: ")
                                .append(sender).append(": ").append(pe.getMessage());
                        session.getLogger().info(errorBuffer.toString());
                    }
                    return SYNTAX_ERROR_ADDRESS;
                }
            }
            if ((senderAddress == null) || ((senderAddress.getLocalPart().length() == 0)
                    && (senderAddress.getDomain().length() == 0))) {
                senderAddress = MailAddress.nullSender();
            }
            // Store the senderAddress in session map
            session.setAttachment(SMTPSession.SENDER, senderAddress, State.Transaction);
        }
        return null;
    }

    /**
     * @see org.apache.james.protocols.smtp.core.AbstractHookableCmdHandler#getHookInterface()
     */
    protected Class<MailHook> getHookInterface() {
        return MailHook.class;
    }

    /**
     * {@inheritDoc}
     */
    protected HookResult callHook(MailHook rawHook, SMTPSession session, String parameters) {
        MailAddress sender = (MailAddress) session.getAttachment(SMTPSession.SENDER, State.Transaction);
        if (sender.isNullSender()) {
            sender = null;
        }
        return rawHook.doMail(session, sender);
    }

    /**
     * @see org.apache.james.protocols.smtp.core.AbstractHookableCmdHandler#getMarkerInterfaces()
     */
    public List<Class<?>> getMarkerInterfaces() {
        List<Class<?>> l = super.getMarkerInterfaces();
        l.add(MailParametersHook.class);
        return l;
    }

    /**
     * @see org.apache.james.protocols.smtp.core.AbstractHookableCmdHandler#wireExtensions(java.lang.Class, java.util.List)
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public void wireExtensions(Class interfaceName, List extension) {
        if (MailParametersHook.class.equals(interfaceName)) {
            this.paramHooks = new HashMap<String, MailParametersHook>();
            for (MailParametersHook hook : (Iterable<MailParametersHook>) extension) {
                String[] params = hook.getMailParamNames();
                for (String param : params) {
                    paramHooks.put(param, hook);
                }
            }
        } else {
            super.wireExtensions(interfaceName, extension);
        }
    }

    /**
     * Return the default domain to append if the sender contains none
     * 
     * @return defaultDomain
     */
    protected String getDefaultDomain() {
        return "localhost";
    }

}