001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    package org.apache.james.protocols.smtp;
020    
021    import java.util.ArrayList;
022    import java.util.Collections;
023    import java.util.List;
024    
025    import org.apache.james.protocols.api.handler.AbstractProtocolHandlerChain;
026    import org.apache.james.protocols.api.handler.ProtocolHandlerChain;
027    import org.apache.james.protocols.api.handler.WiringException;
028    import org.apache.james.protocols.smtp.core.DataCmdHandler;
029    import org.apache.james.protocols.smtp.core.DataLineMessageHookHandler;
030    import org.apache.james.protocols.smtp.core.ExpnCmdHandler;
031    import org.apache.james.protocols.smtp.core.HeloCmdHandler;
032    import org.apache.james.protocols.smtp.core.HelpCmdHandler;
033    import org.apache.james.protocols.smtp.core.MailCmdHandler;
034    import org.apache.james.protocols.smtp.core.NoopCmdHandler;
035    import org.apache.james.protocols.smtp.core.PostmasterAbuseRcptHook;
036    import org.apache.james.protocols.smtp.core.QuitCmdHandler;
037    import org.apache.james.protocols.smtp.core.RcptCmdHandler;
038    import org.apache.james.protocols.smtp.core.ReceivedDataLineFilter;
039    import org.apache.james.protocols.smtp.core.RsetCmdHandler;
040    import org.apache.james.protocols.smtp.core.SMTPCommandDispatcherLineHandler;
041    import org.apache.james.protocols.smtp.core.VrfyCmdHandler;
042    import org.apache.james.protocols.smtp.core.WelcomeMessageHandler;
043    import org.apache.james.protocols.smtp.core.esmtp.AuthCmdHandler;
044    import org.apache.james.protocols.smtp.core.esmtp.EhloCmdHandler;
045    import org.apache.james.protocols.smtp.core.esmtp.MailSizeEsmtpExtension;
046    import org.apache.james.protocols.smtp.core.esmtp.StartTlsCmdHandler;
047    import org.apache.james.protocols.smtp.hook.AuthHook;
048    import org.apache.james.protocols.smtp.hook.Hook;
049    import org.apache.james.protocols.smtp.hook.MessageHook;
050    
051    /**
052     * This {@link ProtocolHandlerChain} implementation add all needed handlers to
053     * the chain to act as full blown SMTPServer. By default messages will just get
054     * rejected after the DATA command.
055     * 
056     * If you want to accept the messagejust add a {@link MessageHook}
057     * implementation to the chain and handle the queuing
058     * 
059     * 
060     * 
061     */
062    public class SMTPProtocolHandlerChain extends AbstractProtocolHandlerChain {
063        private final List<Object> defaultHandlers = new ArrayList<Object>();
064        private final List<Hook> hooks = new ArrayList<Hook>();
065        private final List<Object> handlers = new ArrayList<Object>();
066        private boolean authHandler = false;
067        
068        public SMTPProtocolHandlerChain() throws WiringException {
069            defaultHandlers.addAll(initDefaultHandlers());
070            copy();
071            
072            wireExtensibleHandlers();
073        }
074    
075        protected List<Object> initDefaultHandlers() {
076            List<Object> defaultHandlers = new ArrayList<Object>();
077            defaultHandlers.add(new SMTPCommandDispatcherLineHandler());
078            defaultHandlers.add(new ExpnCmdHandler());
079            defaultHandlers.add(new EhloCmdHandler());
080            defaultHandlers.add(new HeloCmdHandler());
081            defaultHandlers.add(new HelpCmdHandler());
082            defaultHandlers.add(new MailCmdHandler());
083            defaultHandlers.add(new NoopCmdHandler());
084            defaultHandlers.add(new QuitCmdHandler());
085            defaultHandlers.add(new RcptCmdHandler());
086            defaultHandlers.add(new RsetCmdHandler());
087            defaultHandlers.add(new VrfyCmdHandler());
088            defaultHandlers.add(new DataCmdHandler());
089            defaultHandlers.add(new MailSizeEsmtpExtension());
090            defaultHandlers.add(new WelcomeMessageHandler());
091            defaultHandlers.add(new PostmasterAbuseRcptHook());
092            defaultHandlers.add(new ReceivedDataLineFilter());
093            defaultHandlers.add(new DataLineMessageHookHandler());
094            defaultHandlers.add(new StartTlsCmdHandler());
095            return defaultHandlers;
096        }
097        
098    
099        /**
100         * Add the hook to the chain
101         * 
102         * @param hook
103         * @throws WiringException
104         */
105        public final synchronized void addHook(Hook hook) throws WiringException {
106            if (hook instanceof AuthHook && !authHandler) {
107                defaultHandlers.add(new AuthCmdHandler());
108                authHandler = true;
109            }
110            addHook(hooks.size(), hook);
111        }
112    
113        /**
114         * Add the hook to the chain on the given index
115         * 
116         * @param index
117         * @param hook
118         * @throws WiringException
119         */
120        public final synchronized void addHook(int index, Hook hook) throws WiringException {
121            hooks.add(index, hook);
122            copy();
123            wireExtensibleHandlers();
124    
125        }
126    
127        /**
128         * Remove the Hook found on the given index from the chain
129         * 
130         * @param index
131         * @return hook
132         * @throws WiringException
133         */
134        public final synchronized Hook removeHook(int index) throws WiringException {
135            Hook hook = hooks.remove(index);
136            handlers.remove(hook);
137            wireExtensibleHandlers();
138            return hook;
139    
140        }
141    
142        /**
143         * Return the index of the given hook
144         * 
145         * @param hook
146         * @return index
147         */
148        public synchronized int getIndexOfHook(Hook hook) {
149            return hooks.indexOf(hook);
150        }
151    
152        /**
153         * @see
154         * org.apache.james.protocols.api.handler.AbstractProtocolHandlerChain#getHandlers()
155         */
156        @Override
157        protected synchronized List<Object> getHandlers() {
158            return Collections.unmodifiableList(handlers);
159        }
160    
161        /**
162         * Copy the lists
163         */
164        private void copy() {
165            handlers.clear();
166            handlers.addAll(defaultHandlers);
167            handlers.addAll(hooks);
168        }
169    }