FileDocCategorySizeDatePackage
SMTPServer.javaAPI DocApache James 2.3.117268Fri Jan 12 12:56:26 GMT 2007org.apache.james.smtpserver

SMTPServer

public class SMTPServer extends org.apache.james.core.AbstractJamesService implements SMTPServerMBean

Accepts SMTP connections on a server socket and dispatches them to SMTPHandlers.

Also responsible for loading and parsing SMTP specific configuration.

version
1.1.0, 06/02/2001

Fields Summary
SMTPHandlerChain
handlerChain
The handler chain - SMTPhandlers can lookup handlerchain to obtain Command handlers , Message handlers and connection handlers
org.apache.mailet.MailetContext
mailetcontext
The mailet context - we access it here to set the hello name for the Mailet API
private org.apache.james.services.UsersRepository
users
The user repository for this server - used to authenticate users.
private org.apache.james.services.MailServer
mailServer
The internal mail server service.
private static final int
AUTH_DISABLED
Whether authentication is required to use this SMTP server.
private static final int
AUTH_REQUIRED
private static final int
AUTH_ANNOUNCE
private int
authRequired
private boolean
verifyIdentity
Whether the server verifies that the user actually sending an email matches the authentication credentials attached to the SMTP interaction.
private boolean
heloEhloEnforcement
Whether the server needs helo to be send first
private org.apache.james.util.NetMatcher
authorizedNetworks
This is a Network Matcher that should be configured to contain authorized networks that bypass SMTP AUTH requirements.
private long
maxMessageSize
The maximum message size allowed by this SMTP server. The default value, 0, means no limit.
private int
lengthReset
The number of bytes to read before resetting the connection timeout timer. Defaults to 20 KB.
private org.apache.avalon.excalibur.pool.Pool
theHandlerPool
The pool used to provide SMTP Handler objects
private org.apache.avalon.excalibur.pool.ObjectFactory
theHandlerFactory
The pool used to provide SMTP Handler objects
private org.apache.james.util.watchdog.WatchdogFactory
theWatchdogFactory
The factory used to generate Watchdog objects
private SMTPHandlerConfigurationData
theConfigData
The configuration data to be passed to the handler
private org.apache.avalon.framework.service.ServiceManager
serviceManager
Constructors Summary
Methods Summary
public voidconfigure(org.apache.avalon.framework.configuration.Configuration configuration)

see
org.apache.avalon.framework.configuration.Configurable#configure(Configuration)

        super.configure(configuration);
        if (isEnabled()) {
            mailetcontext.setAttribute(Constants.HELLO_NAME, helloName);
            Configuration handlerConfiguration = configuration.getChild("handler");
            String authRequiredString = handlerConfiguration.getChild("authRequired").getValue("false").trim().toLowerCase();
            if (authRequiredString.equals("true")) authRequired = AUTH_REQUIRED;
            else if (authRequiredString.equals("announce")) authRequired = AUTH_ANNOUNCE;
            else authRequired = AUTH_DISABLED;
            verifyIdentity = handlerConfiguration.getChild("verifyIdentity").getValueAsBoolean(false);
            if (authRequired != AUTH_DISABLED) {
                if (verifyIdentity) {
                    getLogger().info("This SMTP server requires authentication and verifies that the authentication credentials match the sender address.");
                } else {
                    getLogger().info("This SMTP server requires authentication, but doesn't verify that the authentication credentials match the sender address.");
                }
            } else {
                getLogger().info("This SMTP server does not require authentication.");
            }

            String authorizedAddresses = handlerConfiguration.getChild("authorizedAddresses").getValue(null);
            if (authRequired == AUTH_DISABLED && authorizedAddresses == null) {
                /* if SMTP AUTH is not requred then we will use
                 * authorizedAddresses to determine whether or not to
                 * relay e-mail.  Therefore if SMTP AUTH is not
                 * required, we will not relay e-mail unless the
                 * sending IP address is authorized.
                 *
                 * Since this is a change in behavior for James v2,
                 * create a default authorizedAddresses network of
                 * 0.0.0.0/0, which matches all possible addresses, thus
                 * preserving the current behavior.
                 *
                 * James v3 should require the <authorizedAddresses>
                 * element.
                 */
                authorizedAddresses = "0.0.0.0/0.0.0.0";
            }

            if (authorizedAddresses != null) {
                java.util.StringTokenizer st = new java.util.StringTokenizer(authorizedAddresses, ", ", false);
                java.util.Collection networks = new java.util.ArrayList();
                while (st.hasMoreTokens()) {
                    String addr = st.nextToken();
                    networks.add(addr);
                }
                authorizedNetworks = new NetMatcher(networks);
            }

            if (authorizedNetworks != null) {
                getLogger().info("Authorized addresses: " + authorizedNetworks.toString());
            }

            // get the message size limit from the conf file and multiply
            // by 1024, to put it in bytes
            maxMessageSize = handlerConfiguration.getChild( "maxmessagesize" ).getValueAsLong( maxMessageSize ) * 1024;
            if (maxMessageSize > 0) {
                getLogger().info("The maximum allowed message size is " + maxMessageSize + " bytes.");
            } else {
                getLogger().info("No maximum message size is enforced for this server.");
            }
            // How many bytes to read before updating the timer that data is being transfered
            lengthReset = configuration.getChild("lengthReset").getValueAsInteger(lengthReset);
            if (lengthReset <= 0) {
                throw new ConfigurationException("The configured value for the idle timeout reset, " + lengthReset + ", is not valid.");
            }
            if (getLogger().isInfoEnabled()) {
                getLogger().info("The idle timeout will be reset every " + lengthReset + " bytes.");
            }
            
            heloEhloEnforcement = handlerConfiguration.getChild("heloEhloEnforcement").getValueAsBoolean(true);
            
            if (authRequiredString.equals("true")) authRequired = AUTH_REQUIRED;

            //set the logger
            ContainerUtil.enableLogging(handlerChain,getLogger());

            try {
                ContainerUtil.service(handlerChain,serviceManager);
            } catch (ServiceException e) {
                if (getLogger().isErrorEnabled()) {
                    getLogger().error("Failed to service handlerChain",e);
                }
                throw new ConfigurationException("Failed to service handlerChain");
            }
            
            //read from the XML configuration and create and configure each of the handlers
            ContainerUtil.configure(handlerChain,handlerConfiguration.getChild("handlerchain"));

        } else {
            mailetcontext.setAttribute(Constants.HELLO_NAME, "localhost");
        }
    
protected intgetDefaultPort()

see
org.apache.james.core.AbstractJamesService#getDefaultPort()

        return 25;
     
public java.lang.StringgetServiceType()

see
org.apache.james.core.AbstractJamesService#getServiceType()

        return "SMTP Service";
    
public voidinitialize()

see
org.apache.avalon.framework.activity.Initializable#initialize()

        super.initialize();
        if (!isEnabled()) {
            return;
        }

        if (connectionLimit != null) {
            theHandlerPool = new HardResourceLimitingPool(theHandlerFactory, 5, connectionLimit.intValue());
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("Using a bounded pool for SMTP handlers with upper limit " + connectionLimit.intValue());
            }
        } else {
            // NOTE: The maximum here is not a real maximum.  The handler pool will continue to
            //       provide handlers beyond this value.
            theHandlerPool = new DefaultPool(theHandlerFactory, null, 5, 30);
            getLogger().debug("Using an unbounded pool for SMTP handlers.");
        }
        if (theHandlerPool instanceof LogEnabled) {
            ((LogEnabled)theHandlerPool).enableLogging(getLogger());
        }
        if (theHandlerPool instanceof Initializable) {
            ((Initializable)theHandlerPool).initialize();
        }

        theWatchdogFactory = getWatchdogFactory();
    
protected org.apache.avalon.cornerstone.services.connection.ConnectionHandlernewHandler()

see
org.apache.avalon.cornerstone.services.connection.AbstractHandlerFactory#newHandler()

        SMTPHandler theHandler = (SMTPHandler)theHandlerPool.get();

        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Getting SMTPHandler from pool.");
        }
        Watchdog theWatchdog = theWatchdogFactory.getWatchdog(theHandler.getWatchdogTarget());

        theHandler.setConfigurationData(theConfigData);

        theHandler.setWatchdog(theWatchdog);

        //pass the handler chain to every SMTPhandler
        theHandler.setHandlerChain(handlerChain);

        return theHandler;
    
public voidreleaseConnectionHandler(org.apache.avalon.cornerstone.services.connection.ConnectionHandler connectionHandler)

see
org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory#releaseConnectionHandler(ConnectionHandler)

        if (!(connectionHandler instanceof SMTPHandler)) {
            throw new IllegalArgumentException("Attempted to return non-SMTPHandler to pool.");
        }
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("Returning SMTPHandler to pool.");
        }
        theHandlerPool.put((Poolable)connectionHandler);
    
public voidservice(org.apache.avalon.framework.service.ServiceManager manager)

see
org.apache.avalon.framework.service.Serviceable#service(ServiceManager)


           
             
        super.service( manager );
        serviceManager = manager;
        mailetcontext = (MailetContext) manager.lookup("org.apache.mailet.MailetContext");
        mailServer = (MailServer) manager.lookup(MailServer.ROLE);
        users = (UsersRepository) manager.lookup(UsersRepository.ROLE);