You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by no...@apache.org on 2009/08/18 17:42:13 UTC

svn commit: r805459 [1/7] - in /james/server/trunk: avalon-socket-library/src/main/java/org/apache/james/socket/ avalon-socket-library/src/main/java/org/apache/james/util/ core-library/src/main/java/org/apache/james/core/ phoenix-deployment-refactor/sr...

Author: norman
Date: Tue Aug 18 15:42:09 2009
New Revision: 805459

URL: http://svn.apache.org/viewvc?rev=805459&view=rev
Log:
Merge sandbox (smtpserver refactoring) to trunk 

Added:
    james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/util/CRLFDelimitedByteBuffer.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/ExtensibleHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/HandlersPackage.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/LineHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPResponse.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPRetCode.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServer.xinfo
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/WiringException.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/AbstractHookableCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/AcceptRecipientIfRelayingIsAllowed.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/AddDefaultAttributesMessageHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/AuthRequiredToRelayRcptHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/CoreMessageHookLoader.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/DataLineFilter.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/DataLineMessageHookHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/PostmasterAbuseRcptHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/SMTPCommandDispatcherLineHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/SenderAuthIdentifyVerificationRcptHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/UsersRepositoryAuthHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/WelcomeMessageHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/AuthCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/EhloCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/EhloExtension.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/esmtp/MailSizeEsmtpExtension.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/SpamTrapHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/TLDLookup.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/URIScanner.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/AuthHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/HeloHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/HookResult.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/HookResultHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/HookReturnCode.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/MailHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/MailParametersHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/MessageHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/QuitHook.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/hook/RcptHook.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SpamTrapHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/Util.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/test/mock/MockMimeMessage.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/test/mock/mailet/
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/test/mock/mailet/MockMail.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/test/mock/mailet/MockMailContext.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/test/mock/mailet/MockMailetConfig.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/test/mock/mailet/MockMatcherConfig.java
Removed:
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/CommandsHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/MessageHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/MessageSizeException.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/ReaderInputStream.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SizeLimitedInputStream.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/AuthCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/EhloCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/CoreFilterCmdHandlerLoader.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/DataFilterCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/EhloFilterCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/HeloFilterCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/MailFilterCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/RcptFilterCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/AbstractJunkHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/JunkHandlerData.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/JunkScoreHandler.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/JunkScoreHandlerTest.java
Modified:
    james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesHandler.java
    james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java
    james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java
    james/server/trunk/core-library/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java
    james/server/trunk/phoenix-deployment-refactor/src/main/config/james-smtphandlerchain.xml
    james/server/trunk/phoenix-deployment/pom.xml
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/CommandHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandlerChain.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPServer.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPSession.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/CoreCmdHandlerLoader.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/DataCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/ExpnCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/HeloCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/HelpCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/MailCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/NoopCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/QuitCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/RcptCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/RsetCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/SendMailHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/SetMimeHeaderHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/UnknownCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/VrfyCmdHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/DNSRBLHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/GreylistHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/MaxRcptHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/ResolvableEhloHeloHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/ReverseEqualsEhloHeloHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/SPFHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/SpamAssassinHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/SupressDuplicateRcptHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/TarpitHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/URIRBLHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/ValidRcptHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/ValidRcptMX.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/core/filter/fastfail/ValidSenderDomainHandler.java
    james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/package.html
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/AbstractSMTPSession.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/DNSRBLHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/MaxRcptHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ResolvableEhloHeloHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPServerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SMTPTestConfiguration.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SPFHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SetMimeHeaderHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/SpamAssassinHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/TarpitHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/URIRBLHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ValidRcptHandlerTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ValidRcptMXTest.java
    james/server/trunk/smtpserver-function/src/test/java/org/apache/james/smtpserver/ValidSenderDomainHandlerTest.java

Modified: james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesHandler.java?rev=805459&r1=805458&r2=805459&view=diff
==============================================================================
--- james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesHandler.java (original)
+++ james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesHandler.java Tue Aug 18 15:42:09 2009
@@ -30,6 +30,7 @@
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.avalon.framework.service.Serviceable;
 import org.apache.james.api.dnsservice.DNSService;
+import org.apache.james.util.CRLFDelimitedByteBuffer;
 import org.apache.james.util.InternetPrintWriter;
 import org.apache.james.util.watchdog.Watchdog;
 import org.apache.james.util.watchdog.WatchdogTarget;
@@ -81,6 +82,12 @@
     protected InputStream in;
 
     /**
+     * Manage inputstream as a bytebuffer
+     */
+    private CRLFDelimitedByteBuffer bytebufferHandler;
+
+    
+    /**
      * The reader associated with incoming characters.
      */
     protected CRLFTerminatedReader inReader;
@@ -166,7 +173,8 @@
                 outs = new SplitOutputStream(outs, new FileOutputStream(tcplogprefix+"out"));
                 in = new CopyInputStream(in, new FileOutputStream(tcplogprefix+"in"));
             }
-            
+            bytebufferHandler = new CRLFDelimitedByteBuffer(in);
+
             // An ASCII encoding can be used because all transmissions other
             // that those in the message body command are guaranteed
             // to be ASCII
@@ -505,4 +513,18 @@
     public String toString() {
         return name;
     }
+    
+
+    public final byte[] readInputLine() throws IOException {
+        return bytebufferHandler.read();
+    }
+    
+    public final String readInputLineAsString() throws IOException {
+        String line = bytebufferHandler.readString();
+        if (line != null && line.length() >= 2) {
+            return line.substring(0,line.length()-2);
+        } else {
+            return line;
+        }
+    }
 }

Modified: james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java
URL: http://svn.apache.org/viewvc/james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java?rev=805459&r1=805458&r2=805459&view=diff
==============================================================================
--- james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java (original)
+++ james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/AbstractJamesService.java Tue Aug 18 15:42:09 2009
@@ -677,7 +677,7 @@
      */
     protected ConnectionHandler newHandler()
             throws Exception {
-        AbstractJamesHandler theHandler = (AbstractJamesHandler)theHandlerPool.get();
+        DelegatingJamesHandler theHandler = (DelegatingJamesHandler)theHandlerPool.get();
         
         if (getLogger().isDebugEnabled()) {
             getLogger().debug("Handler [" +  theHandler + "] obtained from pool.");
@@ -796,7 +796,7 @@
      * @see org.apache.avalon.excalibur.pool.ObjectFactory#newInstance()
      */
     public Object newInstance() throws Exception {
-        final AbstractJamesHandler delegatingJamesHandler = new DelegatingJamesHandler(newProtocolHandlerInstance());
+        final DelegatingJamesHandler delegatingJamesHandler = new DelegatingJamesHandler(newProtocolHandlerInstance(), dnsServer);
         delegatingJamesHandler.setName("Handler-" + handlerCount.getAndAdd(1));
         return delegatingJamesHandler;
     }

Modified: james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java?rev=805459&r1=805458&r2=805459&view=diff
==============================================================================
--- james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java (original)
+++ james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/socket/DelegatingJamesHandler.java Tue Aug 18 15:42:09 2009
@@ -19,27 +19,448 @@
 
 package org.apache.james.socket;
 
-import org.apache.avalon.framework.logger.Logger;
-import org.apache.james.util.watchdog.Watchdog;
-
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InterruptedIOException;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.net.Socket;
+import java.net.SocketException;
+
+import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
+import org.apache.avalon.excalibur.pool.Poolable;
+import org.apache.avalon.framework.container.ContainerUtil;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.james.api.dnsservice.DNSService;
+import org.apache.james.util.InternetPrintWriter;
+import org.apache.james.util.watchdog.Watchdog;
+import org.apache.james.util.watchdog.WatchdogTarget;
 
 /**
  * Common Handler code
  */
-public class DelegatingJamesHandler extends AbstractJamesHandler implements ProtocolHandlerHelper {
+public class DelegatingJamesHandler extends AbstractLogEnabled implements ProtocolHandlerHelper, ConnectionHandler, Poolable {
+ 
+    private static final int DEFAULT_OUTPUT_BUFFER_SIZE = 1024;
+
+    private static final int DEFAULT_INPUT_BUFFER_SIZE = 1024;
+
+    /** Name used by default */
+    private static final String DEFAULT_NAME = "Handler-ANON";
+
+    /**
+     * The thread executing this handler
+     */
+    private Thread handlerThread;
+
+    /**
+     * The TCP/IP socket over which the service interaction
+     * is occurring
+     */
+    private Socket socket;
+
+    /**
+     * The writer to which outgoing messages are written.
+     */
+    private PrintWriter out;
+    
+    /**
+     * The incoming stream of bytes coming from the socket.
+     */
+    private InputStream in;
+
+    /**
+     * The reader associated with incoming characters.
+     */
+    private CRLFTerminatedReader inReader;
+
+    /**
+     * The socket's output stream
+     */
+    private OutputStream outs;
+    
+    /**
+     * The watchdog being used by this handler to deal with idle timeouts.
+     */
+    private Watchdog theWatchdog;
+
+    /**
+     * The watchdog target that idles out this handler.
+     */
+    private final WatchdogTarget theWatchdogTarget = new JamesWatchdogTarget();
+    
+    /**
+     * The remote host name obtained by lookup on the socket.
+     */
+    private String remoteHost = null;
+
+    /**
+     * The remote IP address of the socket.
+     */
+    private String remoteIP = null;
+
+    /**
+     * Used for debug: if not null enable tcp stream dump.
+     */
+    private String tcplogprefix = null;
+
+    /**
+     * Names the handler.
+     * This name is used for contextual logging.
+     */
+    private String name = DEFAULT_NAME;
+    
 
-    protected ProtocolHandler protocolHandler;
+    /**
+     * The DNSService
+     */
+    private final DNSService dnsServer;
     
+    private final ProtocolHandler protocolHandler;
     
-    public DelegatingJamesHandler(ProtocolHandler delegated) {
+    public DelegatingJamesHandler(final ProtocolHandler delegated, final DNSService dnsServer) {
         this.protocolHandler = delegated;
+        this.dnsServer = dnsServer;
         this.protocolHandler.setProtocolHandlerHelper(this);
     }
+
+    /**
+     * Helper method for accepting connections.
+     * This MUST be called in the specializations.
+     *
+     * @param connection The Socket which belongs to the connection 
+     * @throws IOException get thrown if an IO error is detected
+     */
+    protected void initHandler( Socket connection ) throws IOException {
+        this.socket = connection;
+        remoteIP = socket.getInetAddress().getHostAddress();
+        remoteHost = dnsServer.getHostName(socket.getInetAddress());
+
+        try {
+            synchronized (this) {
+                handlerThread = Thread.currentThread();
+            }
+            in = new BufferedInputStream(socket.getInputStream(), DEFAULT_INPUT_BUFFER_SIZE);
+            outs = new BufferedOutputStream(socket.getOutputStream(), DEFAULT_OUTPUT_BUFFER_SIZE);
+            // enable tcp dump for debug
+            if (tcplogprefix != null) {
+                outs = new SplitOutputStream(outs, new FileOutputStream(tcplogprefix+"out"));
+                in = new CopyInputStream(in, new FileOutputStream(tcplogprefix+"in"));
+            }
+            
+            // An ASCII encoding can be used because all transmissions other
+            // that those in the message body command are guaranteed
+            // to be ASCII
+            inReader = new CRLFTerminatedReader(in, "ASCII");
+            
+            out = new InternetPrintWriter(outs, true);
+        } catch (RuntimeException e) {
+            StringBuffer exceptionBuffer = 
+                new StringBuffer(256)
+                    .append("[" + toString() + "] Unexpected exception opening from ")
+                    .append(remoteHost)
+                    .append(" (")
+                    .append(remoteIP)
+                    .append("): ")
+                    .append(e.getMessage());
+            String exceptionString = exceptionBuffer.toString();
+            getLogger().error(exceptionString, e);
+            throw e;
+        } catch (IOException e) {
+            StringBuffer exceptionBuffer = 
+                new StringBuffer(256)
+                    .append("[" + toString() + "] Cannot open connection from ")
+                    .append(remoteHost)
+                    .append(" (")
+                    .append(remoteIP)
+                    .append("): ")
+                    .append(e.getMessage());
+            String exceptionString = exceptionBuffer.toString();
+            getLogger().error(exceptionString, e);
+            throw e;
+        }
+        
+        if (getLogger().isInfoEnabled()) {
+            StringBuffer infoBuffer =
+                new StringBuffer(128)
+                        .append("[" + toString() + "]Connection from ")
+                        .append(remoteHost)
+                        .append(" (")
+                        .append(remoteIP)
+                        .append(")");
+            getLogger().info(infoBuffer.toString());
+        }
+    }
+
+    /**
+     * The method clean up and close the allocated resources
+     */
+    private void cleanHandler() {
+        // Clear the Watchdog
+        if (theWatchdog != null) {
+            ContainerUtil.dispose(theWatchdog);
+            theWatchdog = null;
+        }
+
+        // Clear the streams
+        try {
+            if (inReader != null) {
+                inReader.close();
+            }
+        } catch (IOException ioe) {
+            getLogger().warn("[" + toString() + "] Unexpected exception occurred while closing reader: " + ioe);
+        } finally {
+            inReader = null;
+        }
+
+        in = null;
+
+        if (out != null) {
+            out.close();
+            out = null;
+        }
+        outs = null;
+
+        try {
+            if (socket != null) {
+                socket.close();
+            }
+        } catch (IOException ioe) {
+            getLogger().warn("[" + toString() + "] Unexpected exception occurred while closing socket: " + ioe);
+        } finally {
+            socket = null;
+        }
+        
+        remoteIP = null;
+        remoteHost = null;
+
+        synchronized (this) {
+            handlerThread = null;
+        }
+    }
+
+    /**
+     * @see org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(java.net.Socket)
+     */
+    public void handleConnection(Socket connection) throws IOException {
+        initHandler(connection);
+
+        final Logger logger = getLogger();
+        try {
+            
+            // Do something:
+            handleProtocol();
+            
+            logger.debug("[" + toString() + "] Closing socket");
+        } catch (SocketException se) {
+            // Indicates a problem at the underlying protocol level
+            if (logger.isWarnEnabled()) {
+                String message =
+                    new StringBuffer(64)
+                        .append("[" + toString() + "]Socket to ")
+                        .append(remoteHost)
+                        .append(" (")
+                        .append(remoteIP)
+                        .append("): ")
+                        .append(se.getMessage()).toString();
+                logger.warn(message);
+                logger.debug(se.getMessage(), se);
+            }
+        } catch ( InterruptedIOException iioe ) {
+            if (logger.isErrorEnabled()) {
+                StringBuffer errorBuffer =
+                    new StringBuffer(64)
+                        .append("[" + toString() + "] Socket to ")
+                        .append(remoteHost)
+                        .append(" (")
+                        .append(remoteIP)
+                        .append(") timeout.");
+                logger.error( errorBuffer.toString(), iioe );
+            }
+        } catch ( IOException ioe ) {
+            if (logger.isWarnEnabled()) {
+                String message =
+                    new StringBuffer(256)
+                            .append("[" + toString() + "] Exception handling socket to ")
+                            .append(remoteHost)
+                            .append(" (")
+                            .append(remoteIP)
+                            .append(") : ")
+                            .append(ioe.getMessage()).toString();
+                logger.warn(message);
+                logger.debug( ioe.getMessage(), ioe );
+            }
+        } catch (RuntimeException e) {
+            errorHandler(e);
+        } finally {
+            //Clear all the session state variables
+            cleanHandler();
+            resetHandler();
+        }
+    }
+
+    /**
+     * Set the Watchdog for use by this handler.
+     *
+     * @param theWatchdog the watchdog
+     */
+    public void setWatchdog(Watchdog theWatchdog) {
+        this.theWatchdog = theWatchdog;
+    }
+
+    /**
+     * Gets the Watchdog Target that should be used by Watchdogs managing
+     * this connection.
+     *
+     * @return the WatchdogTarget
+     */
+    WatchdogTarget getWatchdogTarget() {
+        return theWatchdogTarget;
+    }
+
+    /**
+     * Idle out this connection
+     */
+    void idleClose() {
+        if (getLogger() != null) {
+            getLogger().error("[" + toString() + "] Service Connection has idled out.");
+        }
+        try {
+            if (socket != null) {
+                socket.close();
+            }
+        } catch (Exception e) {
+            // ignored
+        } finally {
+            socket = null;
+        }
+
+        synchronized (this) {
+            // Interrupt the thread to recover from internal hangs
+            if (handlerThread != null) {
+                handlerThread.interrupt();
+                handlerThread = null;
+            }
+        }
+
+    }
+
+    /**
+     * This method logs at a "DEBUG" level the response string that
+     * was sent to the service client.  The method is provided largely
+     * as syntactic sugar to neaten up the code base.  It is declared
+     * private and final to encourage compiler inlining.
+     *
+     * @param responseString the response string sent to the client
+     */
+    private final void logResponseString(String responseString) {
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("[" + toString() + "] Sent: " + responseString);
+        }
+    }
+
+    /**
+     * Write and flush a response string.  The response is also logged.
+     * Should be used for the last line of a multi-line response or
+     * for a single line response.
+     *
+     * @param responseString the response string sent to the client
+     */
+    public final void writeLoggedFlushedResponse(String responseString) {
+        out.println(responseString);
+        out.flush();
+        logResponseString(responseString);
+    }
+
+    /**
+     * Write a response string.  The response is also logged.
+     * Used for multi-line responses.
+     *
+     * @param responseString the response string sent to the client
+     */
+    public final void writeLoggedResponse(String responseString) {
+        out.println(responseString);
+        logResponseString(responseString);
+    }
+
+    /**
+     * A private inner class which serves as an adaptor
+     * between the WatchdogTarget interface and this
+     * handler class.
+     */
+    private class JamesWatchdogTarget
+        implements WatchdogTarget {
+
+        /**
+         * @see org.apache.james.util.watchdog.WatchdogTarget#execute()
+         */
+        public void execute() {
+            DelegatingJamesHandler.this.idleClose();
+        }
+
+        /**
+         * Used for context sensitive logging
+         */
+        @Override
+        public String toString() {
+            return DelegatingJamesHandler.this.toString();
+        }
+    }
+
+    /**
+     * If not null, this will enable dump to file for tcp connections
+     * 
+     * @param streamDumpDir the dir
+     */
+    public void setStreamDumpDir(String streamDumpDir) {
+        if (streamDumpDir != null) {
+            String streamdumpDir=streamDumpDir;
+            this.tcplogprefix = streamdumpDir+"/" + getName() + "_TCP-DUMP."+System.currentTimeMillis()+".";
+            File logdir = new File(streamdumpDir);
+            if (!logdir.exists()) {
+                logdir.mkdir();
+            }
+        } else {
+            this.tcplogprefix = null;
+        }
+    }
+
+    /**
+     * The name of this handler.
+     * Used for context sensitive logging.
+     * @return the name, not null
+     */
+    public final String getName() {
+        return name;
+    }
+
+    /**
+     * The name of this handler.
+     * Note that this name should be file-system safe.
+     * Used for context sensitive logging.
+     * @param name the name to set
+     */
+    public final void setName(final String name) {
+        if (name == null) {
+            this.name = DEFAULT_NAME;
+        } else {
+            this.name = name;
+        }
+    }
+
+    /**
+     * Use for context sensitive logging.
+     * @return the name of the handler
+     */
+    @Override
+    public String toString() {
+        return name;
+    }
     
     /**
      * This method will be implemented checking for the correct class
@@ -80,7 +501,10 @@
      * @see org.apache.james.socket.ProtocolHandlerHelper#defaultErrorHandler(java.lang.RuntimeException)
      */
     public void defaultErrorHandler(RuntimeException e) {
-        super.errorHandler(e);
+        if (getLogger().isErrorEnabled()) {
+            getLogger().error( "[" + toString() + "] Unexpected runtime exception: "
+                               + e.getMessage(), e );
+        }
     }
     
     /**

Added: james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/util/CRLFDelimitedByteBuffer.java
URL: http://svn.apache.org/viewvc/james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/util/CRLFDelimitedByteBuffer.java?rev=805459&view=auto
==============================================================================
--- james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/util/CRLFDelimitedByteBuffer.java (added)
+++ james/server/trunk/avalon-socket-library/src/main/java/org/apache/james/util/CRLFDelimitedByteBuffer.java Tue Aug 18 15:42:09 2009
@@ -0,0 +1,331 @@
+/****************************************************************
+ * 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.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/*
+ * A simple, synchronized, queue of CRLF-delimited lines.
+ *
+ * NOTA BENE: as bytes arrive, they are buffered internally up to a
+ * configured maximum.  The maximum is intended to reflect a line length
+ * limiter, but there is a potential corner case that should be
+ * understood.  If the working buffer is almost full, and a new packet
+ * arrives with enough data to overflow the buffer, the code will
+ * consider that an error and discard the entire working buffer, even
+ * though the beginning of the new packet might have terminated the
+ * currently accumulating line.  And the reported position of the
+ * overflow is based upon the buffer position before scanning for lines,
+ * not an actualy line length (perhaps we need not even report the
+ * position).  Since the purpose for this maximum is to prevent memory
+ * flooding attacks, this does not appear to be a particularly critical
+ * corner case.  We simply need to make sure that the working buffer is
+ * at least twice the size of the maximum desired line length.
+ *
+ * After buffering the incoming data, it is scanned for CRLF.  As each
+ * line is found, it is moved to an ArrayList of Line objects.  When all
+ * data has been scanned, any remaining bytes are shifted within the
+ * working buffer to prepare for the next packet.
+ *
+ * The code enforces CRLF pairing (RFC 2821 #2.7.1).  The Line object,
+ * which is for internal use only, can hold the bytes for each line or
+ * record an exception (line termination or line length) associated
+ * with processing the data that would otherwise have.  The exceptions
+ * are rethrown during the read operation, rather than during the write
+ * operation, so that the order of responses perserves the order of
+ * input.
+ *
+ * This code does not handle dot stuffing.  Dot Stuffing, Message size
+ * limiting, and buffering of the message in a file are all expected to
+ * be performed by the I/O handler associated with the DATA accumulation
+ * state.
+ */
+
+public class CRLFDelimitedByteBuffer {
+    static public class TerminationException extends java.io.IOException {
+        private int where;
+        public TerminationException(int where) {
+            super();
+            this.where = where;
+        }
+
+        public TerminationException(String s, int where) {
+            super(s);
+            this.where = where;
+        }
+
+        public int position() {
+            return where;
+        }
+    }
+
+    static public class LineLengthExceededException extends java.io.IOException {
+        public LineLengthExceededException(String s) {
+            super(s);
+        }
+    }
+
+    private InputStream input;
+
+    public CRLFDelimitedByteBuffer(InputStream input) {
+        this(input, 2048);
+    }
+
+    public CRLFDelimitedByteBuffer(InputStream input, int maxLineLength) {
+        this.input = input; 
+        lines = new java.util.ArrayList();
+        workLine = new byte[maxLineLength];
+    }
+
+    synchronized public boolean isEmpty() {
+        return lines.isEmpty();
+    }
+
+    synchronized public byte[] read() throws IOException, LineLengthExceededException, TerminationException {
+        byte[] buffer = new byte[1000];
+        int length;
+        while (lines.isEmpty() && isEmpty() && (length = input.read(buffer))!=-1) {
+            write(buffer, length);
+        }
+        return lines.isEmpty() ? null : ((Line) lines.remove(0)).getBytes();
+    }
+
+    synchronized public String readString() throws IOException, LineLengthExceededException, TerminationException {
+        byte[] buffer = new byte[1000];
+        int length;
+        while (lines.isEmpty() && isEmpty() && (length = input.read(buffer))!=-1) {
+            write(buffer, length);
+        }
+        if (lines.isEmpty()) return null;
+        else {
+            byte[] bytes = ((Line) lines.remove(0)).getBytes();
+            try {
+                return new String(bytes, "US-ASCII");
+            } catch (java.io.UnsupportedEncodingException uee) {
+                return new String(bytes);
+            }
+        }
+    }
+
+    synchronized public void write(byte[] data, int length) {
+        if (canFit(length)) {
+            System.arraycopy(data, 0, workLine, writeindex, length);
+            writeindex += length;
+            buildlines();
+        }
+    }
+
+    synchronized public void write(byte data) {
+        if (canFit(1)) {
+            workLine[writeindex++] = data;
+            buildlines();
+        }
+    }
+
+    synchronized public void write(String s) {
+        write(s.getBytes(), s.getBytes().length);
+    }
+
+    private boolean canFit(int length) {
+        if (writeindex + length > workLine.length) {
+            reset();
+            lines.add(new Line(new LineLengthExceededException("Exceeded maximum line length")));
+            return false;
+        } else return true;
+    }
+
+    static private class Line {
+        java.io.IOException e;
+        byte[] bytes;
+
+        public Line(byte[] data) {
+            bytes = data;
+        }
+
+        public Line(String data) {
+            bytes = data.getBytes();
+        }
+
+        public Line(java.io.IOException e) {
+            this.e = e;
+        }
+
+        public Line(byte[] data, int offset, int length) {
+            bytes = new byte[length];
+            System.arraycopy(data, offset, bytes, 0, length);
+        }
+
+        public byte[] getBytes() throws LineLengthExceededException, TerminationException {
+            if (e != null) {
+                if (e instanceof LineLengthExceededException) throw (LineLengthExceededException) e;
+                else  throw (TerminationException) e;
+            }
+            return bytes;
+        }
+    }
+
+    private java.util.ArrayList lines;
+
+    private byte[] workLine;
+    private int writeindex = 0;
+    private int readindex = 0;
+    private int scanindex = 0;      // current index for matching within the working buffer
+
+    private void reset() {
+        writeindex = 0;
+        readindex = 0;
+        scanindex = 0;
+    }
+
+    private void shift() {
+        System.arraycopy(workLine, readindex, workLine, 0, writeindex - readindex);
+        writeindex -= readindex;
+        scanindex -= readindex;
+        readindex = 0;
+    }
+
+    private void buildlines() {
+        for (; scanindex < writeindex; scanindex++) {
+            if (workLine[scanindex] == '\n') {
+                final int pos = scanindex;
+                reset();
+                lines.add(new Line(new TerminationException("\"bare\" LF in data stream.", pos)));
+                break;
+            } else if (workLine[scanindex] == '\r') {
+                if (scanindex+1 == writeindex) break;
+                else if (workLine[++scanindex] == '\n') {
+                    lines.add(new Line(workLine, readindex, scanindex - readindex + 1));
+                    readindex = scanindex + 1;
+                } else {
+                    final int pos = scanindex - 1;
+                    reset();
+                    lines.add(new Line(new TerminationException("\"bare\" CR in data stream.", pos)));
+                    break;
+                }
+            }
+        }
+
+        if (readindex != 0) shift();
+    }
+
+    /*** THE CODE BELOW IS PURELY FOR TESTING ***/
+    /*
+    synchronized private void status() {
+        System.out.println("\n--------------------------------------------------\n");
+        if (lines.isEmpty()) System.out.println("Lines: None");
+        else {
+            System.out.println("Lines:");
+            java.util.Iterator i = lines.iterator();
+            while (i.hasNext()) {
+                Line line = (Line) i.next();
+                try {
+                    System.out.println("\tData[" + line.getBytes().length + "]: " + new String(line.getBytes(), 0, line.getBytes().length, "US-ASCII"));
+                } catch (java.io.UnsupportedEncodingException uee) {
+                } catch (TerminationException te) {
+                    System.out.println("\tSyntax error at character position " + te.position() + ". CR and LF must be CRLF paired.  See RFC 2821 #2.7.1.");
+                } catch (LineLengthExceededException llee) {
+                    System.out.println("\tLine length exceeded. See RFC 2821 #4.5.3.1.");
+                }
+            }
+        }
+
+        System.out.println("Buffer Status:");
+        System.out.println("\tworkline length: " + workLine.length);
+        System.out.println("\tnext read index: " + readindex);
+        System.out.println("\tnext scan index: " + scanindex);
+        System.out.println("\tnext write index: " + writeindex);
+
+        try {
+            System.out.println("\tOld data: " + new String(workLine, 0, readindex, "US-ASCII"));
+            System.out.println("\tData: " + new String(workLine, readindex, writeindex - readindex, "US-ASCII"));
+        } catch (java.io.UnsupportedEncodingException uee) {
+            System.err.println(uee);
+        }
+        System.out.println("\n--------------------------------------------------\n");
+    }
+
+
+    static public void main(String[] args) throws java.io.IOException {
+        CRLFDelimitedByteBuffer dbb = new CRLFDelimitedByteBuffer();
+        dbb.status();
+        dbb.write("Hello"); dbb.status();
+        dbb.write(" "); dbb.status();
+        dbb.write("World."); dbb.status();
+        dbb.write("\r"); dbb.status();
+        dbb.write("\n"); dbb.status();
+        dbb.write("\r\n"); dbb.status();
+        dbb.write("\n"); dbb.status();
+        dbb.write("\r\r"); dbb.status();
+        dbb.write("stuff\n"); dbb.status();
+        dbb.write("morestuff\r\r"); dbb.status();
+        for (int i = 0; i < 2500; i++) dbb.write("\0"); dbb.status();
+
+        while (!dbb.isEmpty()) {
+            try {
+                byte[] line = dbb.read();
+                System.out.println("Read line[" + line.length + "]: " + new String(line, 0, line.length, "US-ASCII"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+            } catch (TerminationException te) {
+                System.out.println("Syntax error at character position " + te.position() + ". CR and LF must be CRLF paired.  See RFC 2821 #2.7.1.");
+            } catch (LineLengthExceededException llee) {
+                System.out.println("Line length exceeded. See RFC 2821 #4.5.3.1.");
+            }
+        }
+        dbb.status();
+
+        dbb.write("This is a test.\015\012.... Three dots\015\012.\015\012");
+        dbb.status();
+
+        while (!dbb.isEmpty()) {
+            try {
+                byte[] line = dbb.read();
+                System.out.println("Read line[" + line.length + "]: " + new String(line, 0, line.length, "US-ASCII"));
+            } catch (java.io.UnsupportedEncodingException uee) {
+            } catch (TerminationException te) {
+                System.out.println("Syntax error at character position " + te.position() + ". CR and LF must be CRLF paired.  See RFC 2821 #2.7.1.");
+            } catch (LineLengthExceededException llee) {
+                System.out.println("Line length exceeded. See RFC 2821 #4.5.3.1.");
+            }
+        }
+        dbb.status();
+
+        dbb.write("This is"); dbb.status();
+        dbb.write(" a tes"); dbb.status();
+        dbb.write("t.\015"); dbb.status();
+        dbb.write("\012..."); dbb.status();
+        dbb.write(". Three dot"); dbb.status();
+        dbb.write("s\015\012.\015\012"); dbb.status();
+
+        while (!dbb.isEmpty()) {
+            try {
+                String text = dbb.readString();
+                System.out.println ("read : " + text);
+                dbb.status();
+            } catch (TerminationException te) {
+                System.out.println("Syntax error at character position " + te.position() + ". CR and LF must be CRLF paired.  See RFC 2821 #2.7.1.");
+            } catch (LineLengthExceededException llee) {
+                System.out.println("Line length exceeded. See RFC 2821 #4.5.3.1.");
+            }
+        }
+    }
+    */
+}

Modified: james/server/trunk/core-library/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java
URL: http://svn.apache.org/viewvc/james/server/trunk/core-library/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java?rev=805459&r1=805458&r2=805459&view=diff
==============================================================================
--- james/server/trunk/core-library/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java (original)
+++ james/server/trunk/core-library/src/main/java/org/apache/james/core/MimeMessageInputStreamSource.java Tue Aug 18 15:42:09 2009
@@ -26,6 +26,7 @@
 
 import java.io.BufferedOutputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -110,6 +111,21 @@
         }
     }
 
+    public MimeMessageInputStreamSource(String key) throws MessagingException {
+        try {
+            file = File.createTempFile(key, ".m64");
+            sourceId = file.getCanonicalPath();
+        } catch (IOException e) {
+            throw new MessagingException("Unable to get canonical file path: " + e.getMessage(), e);
+        } finally {
+            // if sourceId is null while file is not null then we had
+            // an IOxception and we have to clean the file.
+            if (sourceId == null && file != null) {
+                file.delete();
+            }
+        }
+    }
+    
     /**
      * Returns the unique identifier of this input stream source
      *
@@ -140,6 +156,14 @@
     }
 
     /**
+     * @return
+     * @throws FileNotFoundException
+     */
+    public OutputStream getWritableOutputStream() throws FileNotFoundException {
+        return new FileOutputStream(file);
+    }
+    
+    /**
      * @see org.apache.avalon.framework.activity.Disposable#dispose()
      */
     public void dispose() {

Modified: james/server/trunk/phoenix-deployment-refactor/src/main/config/james-smtphandlerchain.xml
URL: http://svn.apache.org/viewvc/james/server/trunk/phoenix-deployment-refactor/src/main/config/james-smtphandlerchain.xml?rev=805459&r1=805458&r2=805459&view=diff
==============================================================================
--- james/server/trunk/phoenix-deployment-refactor/src/main/config/james-smtphandlerchain.xml (original)
+++ james/server/trunk/phoenix-deployment-refactor/src/main/config/james-smtphandlerchain.xml Tue Aug 18 15:42:09 2009
@@ -20,9 +20,6 @@
 <!-- Please note that this is EXPERIMENTAL and will be changed in future -->
 <!-- releases -->
 <handlerchain>
-<!-- Load the core filter command handlers-->
-    <handler class="org.apache.james.smtpserver.core.filter.CoreFilterCmdHandlerLoader"></handler>        
-
     <!-- This connect handler can be used to enable POP3 before SMTP support -->
     <!-- Plz note that only the ip get stored to indentify an authenticated client -->
     <!-- The expireTime is the time after which an ipAddress is handled as expired -->
@@ -75,8 +72,7 @@
      <!-- If checkAuthNetworks is set to true sender domain will be checked also for clients that -->
      <!-- are allowed to relay. Default is false. -->  
      <!--
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.SPFHandler" command="MAIL,RCPT">
-         <action> reject </action>
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.SPFHandler">
          <checkAuthNetworks> false </checkAuthNetworks>
          <blockSoftFail> false </blockSoftFail>
          <blockPermError> true </blockPermError>
@@ -90,8 +86,7 @@
      <!-- If checkAuthNetworks is set to true sender domain will be checked also for clients that -->
      <!-- are allowed to relay. Default is false. -->
      <!--
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.ResolvableEhloHeloHandler" command="EHLO,HELO,RCPT">
-         <action> reject </action>
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.ResolvableEhloHeloHandler">
          <checkAuthNetworks> false </checkAuthNetworks>
          <checkAuthUsers> false </checkAuthUsers>
      </handler>  
@@ -101,8 +96,7 @@
      <!-- If checkAuthNetworks is set to true sender domain will be checked also for clients that -->
      <!-- are allowed to relay. Default is false. -->
      <!--
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.ReverseEqualsEhloHeloHandler" command="EHLO,HELO">
-         <action> reject </action>
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.ReverseEqualsEhloHeloHandler">
          <checkAuthClients> false </checkAuthClients>
          <checkAuthUsers> false </checkAuthUsers>
      </handler>
@@ -113,8 +107,7 @@
      <!-- If checkAuthNetworks is set to true sender domain will be checked also for clients that -->
      <!-- are allowed to relay. Default is false. -->
      <!--
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.ValidSenderDomainHandler" command="MAIL">
-         <action> reject </action>
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.ValidSenderDomainHandler">
          <checkAuthClients> false </checkAuthClients>
          <checkAuthUsers> false </checkAuthUsers>
      </handler>
@@ -125,7 +118,7 @@
      <!-- You need to add the recipient to the validRecipient list if you want -->
      <!-- to accept email for a recipient which not exist on the server -->
      <!-- 
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.ValidRcptHandler" command="RCPT">
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.ValidRcptHandler">
          <validRecipients> </validRecipients>
          <validDomains> </validDomains>
          <validRegexPattern> </validRegexPattern>
@@ -134,8 +127,7 @@
             
      <!-- If activated you can limit the maximal recipients -->
      <!-- 
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.MaxRcptHandler" command="RCPT">
-         <action> reject </action>
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.MaxRcptHandler">
          <maxRcpt> 10 </maxRcpt>                
      </handler>
      -->
@@ -143,7 +135,7 @@
      <!-- If uncomment this block you can enable greylisting. For more infos-->
      <!-- how greylisting work see: http://projects.puremagic.com/greylisting/whitepaper.html -->
      <!--
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.GreylistHandler" command="RCPT">
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.GreylistHandler">
          <repositoryPath> db://maildb </repositoryPath>
          <sqlFile>file://conf/sqlResources.xml</sqlFile>
          <tempBlockTime> 1 hour </tempBlockTime>
@@ -158,7 +150,7 @@
      <!-- Default is set to 0 (disabled). -->
      <!-- You can also configure the time to sleep in milliseconds -->
      <!--
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.TarpitHandler" command="RCPT">
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.TarpitHandler">
          <tarpitRcptCount> 5 </tarpitRcptCount>
          <tarpitSleepTime> 5000 </tarpitSleepTime>
      </handler>
@@ -167,10 +159,11 @@
      <!-- This handler ignore duplicated recipients per session. So the email will get only send on time even -->
      <!-- if the recipient is specified more then once -->
      <!--
-     <handler class="org.apache.james.smtpserver.core.filter.fastfail.SuppressDuplicateRcptHandler" command="RCPT"/>
+     <handler class="org.apache.james.smtpserver.core.filter.fastfail.SuppressDuplicateRcptHandler"/>
      -->
      
      <!-- Load the core command handlers -->
+     <!-- Only touch this if you really know what you are doing -->
      <handler class="org.apache.james.smtpserver.core.CoreCmdHandlerLoader"></handler>        
       
      <!-- The message handler configuration -->
@@ -192,7 +185,6 @@
      <!-- The message get rejected if a domain matched . -->
      <!--
      <handler class="org.apache.james.smtpserver.core.filter.fastfail.URIRBLHandler">
-         <action> reject </action>
          <getDetail> true </getDetail>
          <checkAuthNetworks> false </checkAuthNetworks>
          <uriRblServers> 

Modified: james/server/trunk/phoenix-deployment/pom.xml
URL: http://svn.apache.org/viewvc/james/server/trunk/phoenix-deployment/pom.xml?rev=805459&r1=805458&r2=805459&view=diff
==============================================================================
--- james/server/trunk/phoenix-deployment/pom.xml (original)
+++ james/server/trunk/phoenix-deployment/pom.xml Tue Aug 18 15:42:09 2009
@@ -208,7 +208,7 @@
     <dependency>
       <groupId>org.apache.jackrabbit</groupId>
       <artifactId>jackrabbit-jcr-rmi</artifactId>
-      <version>1.3</version>
+      <version>1.4.1</version>
       <exclusions>
       	<exclusion>
       		<groupId>xerces</groupId>
@@ -219,7 +219,7 @@
     <dependency>
       <groupId>org.apache.jackrabbit</groupId>
       <artifactId>jackrabbit-api</artifactId>
-      <version>1.3</version>
+      <version>1.4</version>
     </dependency>
 
     <dependency>

Modified: james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/CommandHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/CommandHandler.java?rev=805459&r1=805458&r2=805459&view=diff
==============================================================================
--- james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/CommandHandler.java (original)
+++ james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/CommandHandler.java Tue Aug 18 15:42:09 2009
@@ -35,13 +35,13 @@
     /**
      * Handle the command
     **/
-    void onCommand(SMTPSession session);
+    SMTPResponse onCommand(SMTPSession session, String command, String parameters);
 
     /**
      * Return a Collection of implemented commands
      * 
      * @return Collection which contains implemented commands
      */
-    Collection getImplCommands();
+    Collection<String> getImplCommands();
     
 }

Added: james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/ExtensibleHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/ExtensibleHandler.java?rev=805459&view=auto
==============================================================================
--- james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/ExtensibleHandler.java (added)
+++ james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/ExtensibleHandler.java Tue Aug 18 15:42:09 2009
@@ -0,0 +1,45 @@
+/****************************************************************
+ * 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.smtpserver;
+
+import java.util.List;
+
+/**
+ * Handlers extends this interface to be notified of available
+ * extensions of the given type.
+ */
+public interface ExtensibleHandler {
+     
+    /**
+     * Return a List of interfaces of plugins that will
+     * extend this.
+     */
+    List getMarkerInterfaces();
+    
+    /**
+     * Method called during initialization after all the handlers have been declared
+     * in the handlerchain.
+     * 
+     * @param interfaceName
+     * @param extension a list of objects implementing the marker interface
+     */
+    void wireExtensions(Class interfaceName, List extension) throws WiringException;
+    
+}

Added: james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/HandlersPackage.java
URL: http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/HandlersPackage.java?rev=805459&view=auto
==============================================================================
--- james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/HandlersPackage.java (added)
+++ james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/HandlersPackage.java Tue Aug 18 15:42:09 2009
@@ -0,0 +1,40 @@
+/****************************************************************
+ * 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.smtpserver;
+
+import java.util.List;
+
+/**
+ * Provides a mean to bundle a set of handlers (defined by their classnames) within
+ * a single object.
+ * This is used for the default set of CoreCommands.
+ */
+public interface HandlersPackage {
+    
+    /**
+     * Return a Map which contains a set of CommandHandlers
+     * 
+     * @return Map
+     */
+    List<CommandHandler> getHandlers();
+
+}

Added: james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/LineHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/LineHandler.java?rev=805459&view=auto
==============================================================================
--- james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/LineHandler.java (added)
+++ james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/LineHandler.java Tue Aug 18 15:42:09 2009
@@ -0,0 +1,32 @@
+/****************************************************************
+ * 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.smtpserver;
+
+/**
+ * Custom line handlers must implement this interface
+ */
+public interface LineHandler {
+     
+    /**
+     * Handle the command
+    **/
+    void onLine(SMTPSession session, byte[] line);
+    
+}

Modified: james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java
URL: http://svn.apache.org/viewvc/james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java?rev=805459&r1=805458&r2=805459&view=diff
==============================================================================
--- james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java (original)
+++ james/server/trunk/smtpserver-function/src/main/java/org/apache/james/smtpserver/SMTPHandler.java Tue Aug 18 15:42:09 2009
@@ -21,26 +21,18 @@
 
 package org.apache.james.smtpserver;
 
-import org.apache.avalon.framework.container.ContainerUtil;
-import org.apache.james.Constants;
-import org.apache.james.socket.CRLFTerminatedReader;
-import org.apache.james.socket.ProtocolHandler;
-import org.apache.james.socket.ProtocolHandlerHelper;
-import org.apache.james.util.watchdog.Watchdog;
-import org.apache.mailet.Mail;
-import org.apache.mailet.base.RFC822DateFormat;
-
 import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Date;
 import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
+import java.util.LinkedList;
 import java.util.Map;
 import java.util.Random;
 
+import org.apache.james.socket.ProtocolHandler;
+import org.apache.james.socket.ProtocolHandlerHelper;
+import org.apache.james.util.CRLFDelimitedByteBuffer;
+import org.apache.mailet.base.RFC822DateFormat;
+
 /**
  * Provides SMTP functionality by carrying out the server side of the SMTP
  * interaction.
@@ -49,119 +41,59 @@
  */
 public class SMTPHandler implements ProtocolHandler, SMTPSession {
 
-    private ProtocolHandlerHelper helper;
-
-    /**
-     * The constants to indicate the current processing mode of the session
-     */
-    private final static byte COMMAND_MODE = 1;
-    private final static byte RESPONSE_MODE = 2;
-    private final static byte MESSAGE_RECEIVED_MODE = 3;
-    private final static byte MESSAGE_ABORT_MODE = 4;
-
-    /**
-     * SMTP Server identification string used in SMTP headers
-     */
-    private final static String SOFTWARE_TYPE = "JAMES SMTP Server "
-                                                 + Constants.SOFTWARE_VERSION;
-
-    /**
-     * Static Random instance used to generate SMTP ids
-     */
-    private final static Random random = new Random();
-
-    /**
-     * Static RFC822DateFormat used to generate date headers
-     */
-    private final static RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
-
-    /**
-     * The name of the currently parsed command
-     */
-    String curCommandName =  null;
-
-    /**
-     * The value of the currently parsed command
-     */
-    String curCommandArgument =  null;
-
-    /**
-     * The SMTPHandlerChain object set by SMTPServer
-     */
-    SMTPHandlerChain handlerChain = null;
+	private ProtocolHandlerHelper helper;
 
+	private boolean sessionEnded = false;
 
+	/**
+	 * Static Random instance used to generate SMTP ids
+	 */
+	private final static Random random = new Random();
+
+	/**
+	 * Static RFC822DateFormat used to generate date headers
+	 */
+	private final static RFC822DateFormat rfc822DateFormat = new RFC822DateFormat();
+
+	/**
+	 * The name of the currently parsed command
+	 */
+	String curCommandName = null;
+
+	/**
+	 * The value of the currently parsed command
+	 */
+	String curCommandArgument = null;
+	
     /**
-     * The mode of the current session
-     */
-    private byte mode;
-
-    /**
-     * The MailImpl object set by the DATA command
+     * The hash map holds states which should be used in the whole connection
      */
-    private Mail mail = null;
-
+    private HashMap connectionState = new HashMap();
+    
     /**
-     * The session termination status
+     * If not null every line is sent to this command handler instead
+     * of the default "command parsing -> dipatching" procedure.
      */
-    private boolean sessionEnded = false;
+    private LinkedList lineHandlers;
 
     /**
-     * The user name of the authenticated user associated with this SMTP transaction.
+     * Connect Handlers
      */
-    private String authenticatedUser;
+    private LinkedList connectHandlers;
 
-    /**
-     * whether or not authorization is required for this connection
-     */
-    private boolean authRequired;
+	private SMTPHandlerConfigurationData theConfigData;
 
-    /**
-     * whether or not this connection can relay without authentication
-     */
-    private boolean relayingAllowed;
+	private boolean relayingAllowed;
 
-    /**
-     * Whether the remote Server must send HELO/EHLO 
-     */
-    private boolean heloEhloEnforcement;
-    
+	private boolean authSupported;
 
-    /**
-     * The SMTPGreeting
-     */
-    private String smtpGreeting = null;
-    
-    /**
-     * The id associated with this particular SMTP interaction.
-     */
-    private String smtpID;
+	private SMTPHandlerChain handlerChain;
 
-    /**
-     * The per-service configuration data that applies to all handlers
-     */
-    private SMTPHandlerConfigurationData theConfigData;
+	private String authenticatedUser;
 
-    /**
-     * The hash map that holds variables for the SMTP message transfer in progress.
-     *
-     * This hash map should only be used to store variable set in a particular
-     * set of sequential MAIL-RCPT-DATA commands, as described in RFC 2821.  Per
-     * connection values should be stored as member variables in this class.
-     */
-    private HashMap state = new HashMap();
+	private String smtpID;
 
-    /**
-     * The hash map holds states which should be used in the whole connection
-     */
-    private HashMap connectionState = new HashMap();
-    
-    /**
-     * The per-handler response buffer used to marshal responses.
-     */
-    private StringBuffer responseBuffer = new StringBuffer(256);
-    
-    private boolean stopHandlerProcessing = false;
+	
 
     /**
      * Set the configuration data for the handler
@@ -176,36 +108,19 @@
         }
     }
     
-    /**
-     * @see org.apache.james.socket.AbstractJamesHandler#handleProtocol()
+    /*
+     * (non-Javadoc)
+     * @see org.apache.james.socket.ProtocolHandler#handleProtocol()
      */
     public void handleProtocol() throws IOException {
         smtpID = random.nextInt(1024) + "";
         relayingAllowed = theConfigData.isRelayingAllowed(helper.getRemoteIP());
-        authRequired = theConfigData.isAuthRequired(helper.getRemoteIP());
-        heloEhloEnforcement = theConfigData.useHeloEhloEnforcement();
-        sessionEnded = false;
-        smtpGreeting = theConfigData.getSMTPGreeting();
-        resetState();
-        resetConnectionState();
+        authSupported = theConfigData.isAuthRequired(helper.getRemoteIP());
 
-        // if no greeting was configured use a default
-        if (smtpGreeting == null) {
-            // Initially greet the connector
-            // Format is:  Sat, 24 Jan 1998 13:16:09 -0500
-
-            responseBuffer.append("220 ")
-                          .append(theConfigData.getHelloName())
-                          .append(" SMTP Server (")
-                          .append(SOFTWARE_TYPE)
-                          .append(") ready ")
-                          .append(rfc822DateFormat.format(new Date()));
-        } else {
-            responseBuffer.append("220 ")
-                          .append(smtpGreeting);
-        }
-        String responseString = clearResponseBuffer();
-        helper.writeLoggedFlushedResponse(responseString);
+        // Both called in resetHandler, we don't need to call them again here.
+        // sessionEnded = false;
+        // resetState();
+        // resetConnectionState();
 
         //the core in-protocol handling logic
         //run all the connection handlers, if it fast fails, end the session
@@ -233,7 +148,6 @@
         //message will not spooled.
 
         //Session started - RUN all connect handlers
-        List connectHandlers = handlerChain.getConnectHandlers();
         if(connectHandlers != null) {
             int count = connectHandlers.size();
             for(int i = 0; i < count; i++) {
@@ -244,95 +158,80 @@
             }
         }
 
+        CRLFDelimitedByteBuffer bytebufferHandler = new CRLFDelimitedByteBuffer(helper.getInputStream());
         helper.getWatchdog().start();
         while(!sessionEnded) {
-          //Reset the current command values
-          curCommandName = null;
-          curCommandArgument = null;
-          mode = COMMAND_MODE;
-
           //parse the command
-          String cmdString =  readCommandLine();
-          if (cmdString == null) {
-              break;
+          byte[] line =  null;
+          try {
+              line = bytebufferHandler.read();
+          } catch (CRLFDelimitedByteBuffer.TerminationException e) {
+              writeSMTPResponse(new SMTPResponse(SMTPRetCode.SYNTAX_ERROR_ARGUMENTS, "Syntax error at character position " + e.position() + ". CR and LF must be CRLF paired.  See RFC 2821 #2.7.1."));
+          } catch (CRLFDelimitedByteBuffer.LineLengthExceededException e) {
+              writeSMTPResponse(new SMTPResponse(SMTPRetCode.SYNTAX_ERROR_COMMAND_UNRECOGNIZED, "Line length exceeded. See RFC 2821 #4.5.3.1."));
           }
-          int spaceIndex = cmdString.indexOf(" ");
-          if (spaceIndex > 0) {
-              curCommandName = cmdString.substring(0, spaceIndex);
-              curCommandArgument = cmdString.substring(spaceIndex + 1);
-          } else {
-              curCommandName = cmdString;
-          }
-          curCommandName = curCommandName.toUpperCase(Locale.US);
-
-          //fetch the command handlers registered to the command
-          List commandHandlers = handlerChain.getCommandHandlers(curCommandName);
-          if(commandHandlers == null) {
-              //end the session
+          if (line == null) {
               break;
-          } else {
-              int count = commandHandlers.size();
-              for(int i = 0; i < count; i++) {
-                  setStopHandlerProcessing(false);
-                  ((CommandHandler)commandHandlers.get(i)).onCommand(this);
-                  
-                  helper.getWatchdog().reset();
-                  
-                  //if the response is received, stop processing of command handlers
-                  if(mode != COMMAND_MODE || getStopHandlerProcessing()) {
-                      break;
-                  }
-              }
-
           }
 
-          //handle messages
-          if(mode == MESSAGE_RECEIVED_MODE) {
-              try {
-                  helper.getAvalonLogger().debug("executing message handlers");
-                  List messageHandlers = handlerChain.getMessageHandlers();
-                  int count = messageHandlers.size();
-                  for(int i =0; i < count; i++) {
-                      ((MessageHandler)messageHandlers.get(i)).onMessage(this);
-                      //if the response is received, stop processing of command handlers
-                      if(mode == MESSAGE_ABORT_MODE) {
-                          break;
-                      }
-                  }
-              } finally {
-                  //do the clean up
-                  if(mail != null) {
-                      ContainerUtil.dispose(mail);
-              
-                      // remember the ehlo mode
-                      Object currentHeloMode = state.get(CURRENT_HELO_MODE);
-              
-                      mail = null;
-                      resetState();
-
-                      // start again with the old helo mode
-                      if (currentHeloMode != null) {
-                          state.put(CURRENT_HELO_MODE,currentHeloMode);
-                      }
-                  }
-              }
+          if (lineHandlers.size() > 0) {
+              ((LineHandler) lineHandlers.getLast()).onLine(this, line);
+          } else {
+              sessionEnded = true;
           }
+          helper.getWatchdog().reset();
+          
         }
         helper.getWatchdog().stop();
         helper.getAvalonLogger().debug("Closing socket.");
     }
 
     /**
+     * @see org.apache.james.smtpserver.SMTPSession#writeSMTPResponse(org.apache.james.smtpserver.SMTPResponse)
+     */
+    public void writeSMTPResponse(SMTPResponse response) {
+        // Write a single-line or multiline response
+        if (response != null) {
+            if (response.getRawLine() != null) {
+                helper.writeLoggedFlushedResponse(response.getRawLine());
+            } else {
+                // Iterator i = esmtpextensions.iterator();
+                for (int k = 0; k < response.getLines().size(); k++) {
+                    StringBuffer respBuff = new StringBuffer(256);
+                    respBuff.append(response.getRetCode());
+                    if (k == response.getLines().size() - 1) {
+                        respBuff.append(" ");
+                        respBuff.append(response.getLines().get(k));
+                        helper.writeLoggedFlushedResponse(respBuff.toString());
+                    } else {
+                        respBuff.append("-");
+                        respBuff.append(response.getLines().get(k));
+                        helper.writeLoggedResponse(respBuff.toString());
+                    }
+                }
+            }
+            
+            if (response.isEndSession()) {
+                sessionEnded = true;
+            }
+        }
+    }
+    
+    /**
      * Resets the handler data to a basic state.
      */
     public void resetHandler() {
-        resetState();
+        // not needed anymore because state is inside the connection state
+        // resetState();
         resetConnectionState();
 
-        clearResponseBuffer();
+        // empty any previous line handler and add self (command dispatcher)
+        // as the default.
+        lineHandlers = handlerChain.getHandlers(LineHandler.class);
 
         authenticatedUser = null;
         smtpID = null;
+        sessionEnded = false;
     }
 
    /**
@@ -342,47 +241,10 @@
      */
     public void setHandlerChain(SMTPHandlerChain handlerChain) {
         this.handlerChain = handlerChain;
+        connectHandlers = handlerChain.getHandlers(ConnectHandler.class);
+        lineHandlers = handlerChain.getHandlers(LineHandler.class);
     }
 
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#writeResponse(String)
-     */
-    public void writeResponse(String respString) {
-        helper.writeLoggedFlushedResponse(respString);
-        //TODO Explain this well
-        if(mode == COMMAND_MODE) {
-            mode = RESPONSE_MODE;
-        }
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#getCommandName()
-     */
-    public String getCommandName() {
-        return curCommandName;
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#getCommandArgument()
-     */
-    public String getCommandArgument() {
-        return curCommandArgument;
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#getMail()
-     */
-    public Mail getMail() {
-        return mail;
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#setMail(Mail)
-     */
-    public void setMail(Mail mail) {
-        this.mail = mail;
-        this.mode = MESSAGE_RECEIVED_MODE;
-    }
 
     /**
      * @see org.apache.james.smtpserver.SMTPSession#getRemoteHost()
@@ -399,35 +261,36 @@
     }
 
     /**
-     * @see org.apache.james.smtpserver.SMTPSession#endSession()
-     */
-    public void endSession() {
-        sessionEnded = true;
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#isSessionEnded()
-     */
-    public boolean isSessionEnded() {
-        return sessionEnded;
-    }
-
-    /**
      * @see org.apache.james.smtpserver.SMTPSession#resetState()
      */
     public void resetState() {
-        ArrayList recipients = (ArrayList)state.get(RCPT_LIST);
-        if (recipients != null) {
-            recipients.clear();
+        // remember the ehlo mode between resets
+        Object currentHeloMode = getState().get(CURRENT_HELO_MODE);
+
+        getState().clear();
+
+        // start again with the old helo mode
+        if (currentHeloMode != null) {
+            getState().put(CURRENT_HELO_MODE,currentHeloMode);
         }
-        state.clear();
     }
 
     /**
+     * The hash map that holds variables for the SMTP message transfer in progress.
+     *
+     * This hash map should only be used to store variable set in a particular
+     * set of sequential MAIL-RCPT-DATA commands, as described in RFC 2821.  Per
+     * connection values should be stored as member variables in this class.
+     * 
      * @see org.apache.james.smtpserver.SMTPSession#getState()
      */
     public Map getState() {
-        return state;
+        Object res = getConnectionState().get(SMTPSession.SESSION_STATE_MAP);
+        if (res == null || !(res instanceof Map)) {
+            res = new HashMap();
+            getConnectionState().put(SMTPSession.SESSION_STATE_MAP, res);
+        }
+        return (Map) res;
     }
 
     /**
@@ -451,19 +314,13 @@
     }
 
     /**
-     * @see org.apache.james.smtpserver.SMTPSession#isAuthRequired()
+     * @see org.apache.james.smtpserver.SMTPSession#isAuthSupported()
      */
-    public boolean isAuthRequired() {
-        return authRequired;
+    public boolean isAuthSupported() {
+        return authSupported;
     }
 
     /**
-     * @see org.apache.james.smtpserver.SMTPSession#useHeloEhloEnforcement()
-     */
-    public boolean useHeloEhloEnforcement() {
-        return heloEhloEnforcement;
-    }
-    /**
      * @see org.apache.james.smtpserver.SMTPSession#getUser()
      */
     public String getUser() {
@@ -478,66 +335,11 @@
     }
 
     /**
-     * @see org.apache.james.smtpserver.SMTPSession#getResponseBuffer()
-     */
-    public StringBuffer getResponseBuffer() {
-        return responseBuffer;
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#clearResponseBuffer()
-     */
-    public String clearResponseBuffer() {
-        String responseString = responseBuffer.toString();
-        responseBuffer.delete(0,responseBuffer.length());
-        return responseString;
-    }
-
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#readCommandLine()
-     */
-    public final String readCommandLine() throws IOException {
-        for (;;) try {
-            String commandLine = helper.getInputReader().readLine();
-            if (commandLine != null) {
-                commandLine = commandLine.trim();
-            }
-            return commandLine;
-        } catch (CRLFTerminatedReader.TerminationException te) {
-            helper.writeLoggedFlushedResponse("501 Syntax error at character position " + te.position() + ". CR and LF must be CRLF paired.  See RFC 2821 #2.7.1.");
-        } catch (CRLFTerminatedReader.LineLengthExceededException llee) {
-            helper.writeLoggedFlushedResponse("500 Line length exceeded. See RFC 2821 #4.5.3.1.");
-        }
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#getWatchdog()
-     */
-    public Watchdog getWatchdog() {
-        return helper.getWatchdog();
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#getInputStream()
-     */
-    public InputStream getInputStream() {
-        return helper.getInputStream();
-    }
-
-    /**
      * @see org.apache.james.smtpserver.SMTPSession#getSessionID()
      */
     public String getSessionID() {
         return smtpID;
     }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#abortMessage()
-     */
-    public void abortMessage() {
-        mode = MESSAGE_ABORT_MODE;
-    }
     
     /**
      * @see org.apache.james.smtpserver.SMTPSession#getRcptCount()
@@ -546,41 +348,60 @@
         int count = 0;
 
         // check if the key exists
-        if (state.get(SMTPSession.RCPT_LIST) != null) {
-            count = ((Collection) state.get(SMTPSession.RCPT_LIST)).size();
+        if (getState().get(SMTPSession.RCPT_LIST) != null) {
+            count = ((Collection) getState().get(SMTPSession.RCPT_LIST)).size();
         }
 
         return count;
     }
     
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#setStopHandlerProcessing(boolean)
-     */
-    public void setStopHandlerProcessing(boolean stopHandlerProcessing) {
-        this.stopHandlerProcessing = stopHandlerProcessing;
-    }
-    
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#getStopHandlerProcessing()
-     */
-    public boolean getStopHandlerProcessing() {
-        return stopHandlerProcessing;
-    }
-    
     public void resetConnectionState() {
         connectionState.clear();
     }
     
+    /**
+     * @see org.apache.james.smtpserver.SMTPSession#getConnectionState()
+     */
     public Map getConnectionState() {
         return connectionState;
     }
 
-    public void setProtocolHandlerHelper(ProtocolHandlerHelper phh) {
-        this.helper = phh;
+    /**
+     * @see org.apache.james.smtpserver.SMTPSession#popLineHandler()
+     */
+    public void popLineHandler() {
+        if (lineHandlers != null) {
+            lineHandlers.removeLast();
+        }
     }
 
-    public void errorHandler(RuntimeException e) {
-        helper.defaultErrorHandler(e);
+    /**
+     * @see org.apache.james.smtpserver.SMTPSession#pushLineHandler(org.apache.james.smtpserver.LineHandler)
+     */
+    public void pushLineHandler(LineHandler lineHandler) {
+        if (lineHandlers == null) {
+            lineHandlers = new LinkedList();
+        }
+        lineHandlers.addLast(lineHandler);
+    }
+    
+    /**
+     * @see org.apache.james.smtpserver.SMTPSession#sleep(long)
+     */
+    public void sleep(long ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException e) {
+            // ignore
+        }
     }
 
+	public void errorHandler(RuntimeException e) {
+		helper.defaultErrorHandler(e);
+	}
+
+	public void setProtocolHandlerHelper(ProtocolHandlerHelper phh) {
+		helper = phh;
+	}
+
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org