Index: java/org/apache/james/core/AbstractJamesHandler.java
===================================================================
--- java/org/apache/james/core/AbstractJamesHandler.java	(revision 487826)
+++ java/org/apache/james/core/AbstractJamesHandler.java	(working copy)
@@ -31,7 +31,7 @@
 import org.apache.james.imapserver.debug.CopyInputStream;
 import org.apache.james.imapserver.debug.SplitOutputStream;
 import org.apache.james.services.DNSServer;
-import org.apache.james.util.CRLFTerminatedReader;
+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;
@@ -74,11 +74,11 @@
      * The incoming stream of bytes coming from the socket.
      */
     protected InputStream in;
-
+    
     /**
-     * The reader associated with incoming characters.
+     * Manage inputstream as a bytebuffer
      */
-    protected CRLFTerminatedReader inReader;
+    private CRLFDelimitedByteBuffer bytebufferHandler;
 
     /**
      * The socket's output stream
@@ -159,8 +159,8 @@
                 outs = new SplitOutputStream(outs, new FileOutputStream(tcplogprefix+"out"));
                 in = new CopyInputStream(in, new FileOutputStream(tcplogprefix+"in"));
             }
-            inReader = new CRLFTerminatedReader(in, "ASCII");
-            
+            bytebufferHandler = new CRLFDelimitedByteBuffer();
+
             out = new InternetPrintWriter(outs, true);
         } catch (RuntimeException e) {
             StringBuffer exceptionBuffer = 
@@ -211,15 +211,15 @@
         }
 
         // Clear the streams
-        try {
-            if (inReader != null) {
-                inReader.close();
-            }
-        } catch (IOException ioe) {
-            getLogger().warn("Handler: Unexpected exception occurred while closing reader: " + ioe);
-        } finally {
-            inReader = null;
-        }
+//        try {
+//            if (inReader != null) {
+//                inReader.close();
+//            }
+//        } catch (IOException ioe) {
+//            getLogger().warn("Handler: Unexpected exception occurred while closing reader: " + ioe);
+//        } finally {
+//            inReader = null;
+//        }
 
         in = null;
 
@@ -451,4 +451,23 @@
         this.dnsServer = dnsServer;
     }
 
+
+    public final byte[] readInputLine() throws IOException {
+        byte[] buffer = new byte[1000];
+        while (bytebufferHandler.isEmpty()) {
+            int length = in.read(buffer);
+            bytebufferHandler.write(buffer, length);
+        }
+        return bytebufferHandler.read();
+    }
+    
+    public final String readInputLineAsString() throws IOException {
+        byte[] buffer = new byte[1000];
+        while (bytebufferHandler.isEmpty()) {
+            int length = in.read(buffer);
+            bytebufferHandler.write(buffer, length);
+        }
+        return bytebufferHandler.readString();
+    }
+
 }
Index: java/org/apache/james/nntpserver/NNTPHandler.java
===================================================================
--- java/org/apache/james/nntpserver/NNTPHandler.java	(revision 487826)
+++ java/org/apache/james/nntpserver/NNTPHandler.java	(working copy)
@@ -282,7 +282,7 @@
         }
 
         theWatchdog.start();
-        while (parseCommand(inReader.readLine())) {
+        while (parseCommand(new String(readInputLine(), "US-ASCII"))) {
             theWatchdog.reset();
         }
         theWatchdog.stop();
Index: java/org/apache/james/pop3server/POP3Handler.java
===================================================================
--- java/org/apache/james/pop3server/POP3Handler.java	(revision 468922)
+++ java/org/apache/james/pop3server/POP3Handler.java	(working copy)
@@ -26,7 +26,7 @@
 import org.apache.james.core.AbstractJamesHandler;
 import org.apache.james.core.MailImpl;
 import org.apache.james.services.MailRepository;
-import org.apache.james.util.CRLFTerminatedReader;
+import org.apache.james.util.CRLFDelimitedByteBuffer;
 import org.apache.james.util.watchdog.Watchdog;
 import org.apache.mailet.Mail;
 
@@ -208,7 +208,13 @@
           mode = COMMAND_MODE;
 
           //parse the command
-          String cmdString =  readCommandLine();
+          String cmdString = null;
+          try {
+              cmdString = readInputLineAsString();
+          } catch (CRLFDelimitedByteBuffer.TerminationException te) {
+              writeLoggedFlushedResponse("-ERR Syntax error at character position " + te.position() + ". CR and LF must be CRLF paired.  See RFC 1939 #3.");
+          }
+
           if (cmdString == null) {
               break;
           }
@@ -306,24 +312,6 @@
     }
 
     /**
-     * Reads a line of characters off the command line.
-     *
-     * @return the trimmed input line
-     * @throws IOException if an exception is generated reading in the input characters
-     */
-    public final String readCommandLine() throws IOException {
-        for (;;) try {
-            String commandLine = inReader.readLine();
-            if (commandLine != null) {
-                commandLine = commandLine.trim();
-            }
-            return commandLine;
-        } catch (CRLFTerminatedReader.TerminationException te) {
-            writeLoggedFlushedResponse("-ERR Syntax error at character position " + te.position() + ". CR and LF must be CRLF paired.  See RFC 1939 #3.");
-        }
-    }
-
-    /**
      * This method parses POP3 commands read off the wire in handleConnection.
      * Actual processing of the command (possibly including additional back and
      * forth communication with the client) is delegated to one of a number of
Index: java/org/apache/james/pop3server/POP3Session.java
===================================================================
--- java/org/apache/james/pop3server/POP3Session.java	(revision 468922)
+++ java/org/apache/james/pop3server/POP3Session.java	(working copy)
@@ -25,7 +25,6 @@
 import org.apache.james.services.MailRepository;
 import org.apache.james.util.watchdog.Watchdog;
 
-import java.io.IOException;
 import java.io.OutputStream;
 import java.util.HashMap;
 import java.util.List;
@@ -44,14 +43,6 @@
      */
     void writeResponse(String respString);
 
-    /**
-     * Reads a line of characters off the command line.
-     *
-     * @return the trimmed input line
-     * @throws IOException if an exception is generated reading in the input characters
-     */
-    String readCommandLine() throws IOException;
-
 
     /**
      * Returns ResponseBuffer, this optimizes the unecessary creation of resources
Index: java/org/apache/james/remotemanager/RemoteManagerHandler.java
===================================================================
--- java/org/apache/james/remotemanager/RemoteManagerHandler.java	(revision 487826)
+++ java/org/apache/james/remotemanager/RemoteManagerHandler.java	(working copy)
@@ -151,9 +151,9 @@
                 writeLoggedFlushedResponse(message);
             }
             writeLoggedFlushedResponse("Login id:");
-            login = inReader.readLine().trim();
+            login = readInputLineAsString().trim();
             writeLoggedFlushedResponse("Password:");
-            password = inReader.readLine().trim();
+            password = readInputLineAsString().trim();
         } while (!password.equals(theConfigData.getAdministrativeAccountData().get(login)) || password.length() == 0);
 
         StringBuffer messageBuffer =
@@ -176,7 +176,7 @@
             out.print(theConfigData.getPrompt());
             out.flush();
             theWatchdog.start();
-            while (parseCommand(inReader.readLine())) {
+            while (parseCommand(readInputLineAsString())) {
                 theWatchdog.reset();
                 out.print(theConfigData.getPrompt());
                 out.flush();
Index: java/org/apache/james/smtpserver/CommandHandler.java
===================================================================
--- java/org/apache/james/smtpserver/CommandHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/CommandHandler.java	(working copy)
@@ -35,7 +35,7 @@
     /**
      * Handle the command
     **/
-    void onCommand(SMTPSession session);
+    SMTPResponse onCommand(SMTPSession session, String command, String parameters);
 
     /**
      * Return a Collection of implemented commands
Index: java/org/apache/james/smtpserver/SMTPHandler.java
===================================================================
--- java/org/apache/james/smtpserver/SMTPHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/SMTPHandler.java	(working copy)
@@ -24,8 +24,7 @@
 import org.apache.avalon.framework.container.ContainerUtil;
 import org.apache.james.Constants;
 import org.apache.james.core.AbstractJamesHandler;
-import org.apache.james.util.CRLFTerminatedReader;
-import org.apache.james.util.watchdog.Watchdog;
+import org.apache.james.util.CRLFDelimitedByteBuffer;
 import org.apache.mailet.Mail;
 import org.apache.mailet.dates.RFC822DateFormat;
 
@@ -30,11 +29,12 @@
 import org.apache.mailet.dates.RFC822DateFormat;
 
 import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
+import java.io.UnsupportedEncodingException;
+import java.net.Socket;
 import java.util.Collection;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
@@ -48,7 +48,7 @@
  */
 public class SMTPHandler
     extends AbstractJamesHandler
-    implements SMTPSession {
+    implements SMTPSession, LineHandler {
 
     /**
      * The constants to indicate the current processing mode of the session
@@ -142,15 +142,6 @@
     private SMTPHandlerConfigurationData theConfigData;
 
     /**
-     * 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();
-
-    /**
      * The hash map holds states which should be used in the whole connection
      */
     private HashMap connectionState = new HashMap();
@@ -161,6 +152,17 @@
     private StringBuffer responseBuffer = new StringBuffer(256);
     
     private boolean stopHandlerProcessing = false;
+    
+    /**
+     * If not null every line is sent to this command handler instead
+     * of the default "command parsing -> dipatching" procedure.
+     */
+    private LinkedList lineHandlers;
+
+    protected void initHandler(Socket connection) throws IOException {
+        super.initHandler(connection);
+        pushLineHandler(this); 
+    }
 
     /**
      * Set the configuration data for the handler
@@ -183,10 +185,11 @@
         relayingAllowed = theConfigData.isRelayingAllowed(remoteIP);
         authRequired = theConfigData.isAuthRequired(remoteIP);
         heloEhloEnforcement = theConfigData.useHeloEhloEnforcement();
-        sessionEnded = false;
         smtpGreeting = theConfigData.getSMTPGreeting();
-        resetState();
-        resetConnectionState();
+        // Both called in resetHandler, we don't need to call them again here.
+        // sessionEnded = false;
+        // resetState();
+        // resetConnectionState();
 
         // if no greeting was configured use a default
         if (smtpGreeting == null) {
@@ -251,40 +254,21 @@
           mode = COMMAND_MODE;
 
           //parse the command
-          String cmdString =  readCommandLine();
-          if (cmdString == null) {
-              break;
-          }
-          int spaceIndex = cmdString.indexOf(" ");
-          if (spaceIndex > 0) {
-              curCommandName = cmdString.substring(0, spaceIndex);
-              curCommandArgument = cmdString.substring(spaceIndex + 1);
-          } else {
-              curCommandName = cmdString;
+          byte[] line =  null;
+          try {
+              line = readInputLine();
+          } catch (CRLFDelimitedByteBuffer.TerminationException e) {
+              writeLoggedFlushedResponse("501 Syntax error at character position " + e.position() + ". CR and LF must be CRLF paired.  See RFC 2821 #2.7.1.");
+          } catch (CRLFDelimitedByteBuffer.LineLengthExceededException e) {
+              writeLoggedFlushedResponse("500 Line length exceeded. See RFC 2821 #4.5.3.1.");
           }
-          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);
-                  
-                  theWatchdog.reset();
-                  
-                  //if the response is received, stop processing of command handlers
-                  if(mode != COMMAND_MODE || getStopHandlerProcessing()) {
-                      break;
-                  }
-              }
-
           }
 
+          ((LineHandler) lineHandlers.getLast()).onLine(this, line);
+          theWatchdog.reset();
+          
           //handle messages
           if(mode == MESSAGE_RECEIVED_MODE) {
               try {
@@ -303,16 +287,8 @@
                   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);
-                      }
                   }
               }
           }
@@ -321,6 +297,77 @@
         getLogger().debug("Closing socket.");
     }
 
+    public void onLine(SMTPSession session, byte[] line) {
+        String cmdString;
+        try {
+            cmdString = new String(line, "US-ASCII");
+            if (cmdString != null) {
+                cmdString = cmdString.trim();
+            }
+            
+            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
+                sessionEnded = true;
+            } else {
+                int count = commandHandlers.size();
+                for(int i = 0; i < count; i++) {
+                    setStopHandlerProcessing(false);
+                    SMTPResponse response = ((CommandHandler)commandHandlers.get(i)).onCommand(this, curCommandName, curCommandArgument);
+                    
+                    writeSMTPResponse(response);
+                    
+                    //if the response is received, stop processing of command handlers
+                    if(mode != COMMAND_MODE || response != null) {
+                        break;
+                    }
+                }
+
+            }        
+        } catch (UnsupportedEncodingException e) {
+            // TODO Define what to do
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * @param response
+     */
+    public void writeSMTPResponse(SMTPResponse response) {
+        // Write a single-line or multiline response
+        if (response != null) {
+            if (response.getRawLine() != null) {
+                writeResponse(response.getRawLine());
+            } else {
+                // Iterator i = esmtpextensions.iterator();
+                for (int k = 0; k < response.getLines().size(); k++) {
+                    responseBuffer.append(response.getRetCode());
+                    if (k == response.getLines().size() - 1) {
+                        responseBuffer.append(" ");
+                    } else {
+                        responseBuffer.append("-");
+                    }
+                    responseBuffer.append(response.getLines().get(k));
+                    writeResponse(clearResponseBuffer());
+                }
+            }
+            
+            if (response.isEndSession()) {
+                endSession();
+            }
+        }
+    }
+    
     /**
      * Resets the handler data to a basic state.
      */
@@ -325,15 +372,20 @@
      * Resets the handler data to a basic state.
      */
     protected void resetHandler() {
-        resetState();
+        // not needed anymore because state is inside the connection state
+        // resetState();
         resetConnectionState();
 
+        // empty any previous line handler and add self (command dispatcher)
+        // as the default.
+        lineHandlers = null;
+        pushLineHandler(this);
+
         clearResponseBuffer();
 
-        remoteHost = null;
-        remoteIP = null;
         authenticatedUser = null;
         smtpID = null;
+        sessionEnded = false;
     }
 
    /**
@@ -407,28 +459,41 @@
     }
 
     /**
-     * @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();
+        // We already clear the map, it should be enough
+//        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;
     }
 
     /**
@@ -494,38 +559,6 @@
         return responseString;
     }
 
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#readCommandLine()
-     */
-    public final String readCommandLine() throws IOException {
-        for (;;) try {
-            String commandLine = inReader.readLine();
-            if (commandLine != null) {
-                commandLine = commandLine.trim();
-            }
-            return commandLine;
-        } catch (CRLFTerminatedReader.TerminationException te) {
-            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) {
-            writeLoggedFlushedResponse("500 Line length exceeded. See RFC 2821 #4.5.3.1.");
-        }
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#getWatchdog()
-     */
-    public Watchdog getWatchdog() {
-        return theWatchdog;
-    }
-
-    /**
-     * @see org.apache.james.smtpserver.SMTPSession#getInputStream()
-     */
-    public InputStream getInputStream() {
-        return in;
-    }
-
     /**
      * @see org.apache.james.smtpserver.SMTPSession#getSessionID()
      */
@@ -547,8 +580,8 @@
         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;
@@ -576,4 +609,17 @@
         return connectionState;
     }
 
+    public void popLineHandler() {
+        if (lineHandlers != null) {
+            lineHandlers.removeLast();
+        }
+    }
+
+    public void pushLineHandler(LineHandler lineHandler) {
+        if (lineHandlers == null) {
+            lineHandlers = new LinkedList();
+        }
+        lineHandlers.addLast(lineHandler);
+    }
+
 }
Index: java/org/apache/james/smtpserver/SMTPServer.java
===================================================================
--- java/org/apache/james/smtpserver/SMTPServer.java	(revision 487826)
+++ java/org/apache/james/smtpserver/SMTPServer.java	(working copy)
@@ -338,7 +338,7 @@
          * @see org.apache.james.smtpserver.SMTPHandlerConfigurationData#isAuthRequired(String)
          */
         public boolean isAuthRequired(String remoteIP) {
-              if (SMTPServer.this.authRequired == AUTH_ANNOUNCE) return true;
+            if (SMTPServer.this.authRequired == AUTH_ANNOUNCE) return true;
             boolean authRequired = SMTPServer.this.authRequired != AUTH_DISABLED;
             if (authorizedNetworks != null) {
                 authRequired = authRequired && !SMTPServer.this.authorizedNetworks.matchInetNetwork(remoteIP);
Index: java/org/apache/james/smtpserver/SMTPSession.java
===================================================================
--- java/org/apache/james/smtpserver/SMTPSession.java	(revision 468922)
+++ java/org/apache/james/smtpserver/SMTPSession.java	(working copy)
@@ -22,11 +22,8 @@
 package org.apache.james.smtpserver;
 
 
-import org.apache.james.util.watchdog.Watchdog;
 import org.apache.mailet.Mail;
 
-import java.io.IOException;
-import java.io.InputStream;
 import java.util.Map;
 
 /**
@@ -43,6 +40,7 @@
     public final static String CURRENT_HELO_MODE = "CURRENT_HELO_MODE"; // HELO or EHLO
     public final static String CURRENT_HELO_NAME = "CURRENT_HELO_NAME"; 
     public static final Object CURRENT_RECIPIENT = "CURRENT_RECIPIENT"; // Current recipient
+    public final static String SESSION_STATE_MAP = "SESSION_STATE_MAP"; // the Session state 
 
     /**
      * Writes response string to the client
@@ -57,7 +55,7 @@
      * @return the trimmed input line
      * @throws IOException if an exception is generated reading in the input characters
      */
-    String readCommandLine() throws IOException;
+    // String readCommandLine() throws IOException;
 
 
     /**
@@ -76,13 +74,6 @@
     String clearResponseBuffer();
 
     /**
-     * Returns Inputstream for handling messages and commands
-     *
-     * @return InputStream object
-     */
-    InputStream getInputStream();
-
-    /**
      * Returns currently process command name
      *
      * @return current command name
@@ -137,13 +128,6 @@
     void endSession();
 
     /**
-     * Returns the session status
-     *
-     * @return if the session is open or closed
-     */
-    boolean isSessionEnded();
-
-    /**
      * Returns Map that consists of the state of the SMTPSession per mail
      *
      * @return map of the current SMTPSession state per mail
@@ -206,13 +190,6 @@
     void setUser(String user);
 
     /**
-     * Returns Watchdog object used for handling timeout
-     *
-     * @return Watchdog object
-     */
-    Watchdog getWatchdog();
-
-    /**
      * Returns the SMTP session id
      *
      * @return SMTP session id
@@ -240,12 +217,6 @@
      */
     boolean getStopHandlerProcessing();
     
-    
-    /**
-     * Reset the Connection state
-     */
-    void resetConnectionState();
-    
     /**
      * Returns Map that consists of the state of the SMTPSession per connection
      *
@@ -253,5 +224,20 @@
      */
     Map getConnectionState();
 
+    /**
+     * Put a new line handler in the chain
+     * @param overrideCommandHandler
+     */
+    void pushLineHandler(LineHandler overrideCommandHandler);
+    
+    /**
+     * Pop the last command handler 
+     */
+    void popLineHandler();
+
+    /**
+     * Write an SMTPResponse to the client
+     */
+    void writeSMTPResponse(SMTPResponse response);
 }
 
Index: java/org/apache/james/smtpserver/core/AuthCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/AuthCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/AuthCmdHandler.java	(working copy)
@@ -22,6 +22,8 @@
 package org.apache.james.smtpserver.core;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.LineHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
@@ -31,7 +33,7 @@
 import java.util.Locale;
 import java.util.StringTokenizer;
 import org.apache.james.util.Base64;
-import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 
 
 /**
@@ -50,7 +52,7 @@
      * The text string for the SMTP AUTH type LOGIN.
      */
     private final static String AUTH_TYPE_LOGIN = "LOGIN";
-
+    
     /**
      * handles AUTH command
      *
@@ -56,15 +58,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        //deviation from the Main code
-        //Instead of throwing exception just end the session
-        try{
-            doAUTH(session, session.getCommandArgument());
-        } catch (Exception ex) {
-            getLogger().error("Exception occured:" + ex.getMessage());
-            session.endSession();
-        }
+    public SMTPResponse onCommand(SMTPSession session, String command, String argument) {
+        return doAUTH(session, argument);
     }
 
 
@@ -76,16 +71,12 @@
      * @param session SMTP session
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doAUTH(SMTPSession session, String argument)
-            throws Exception {
-        String responseString = null;
+    private SMTPResponse doAUTH(SMTPSession session, String argument) {
         if (session.getUser() != null) {
-            responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" User has previously authenticated. "
-                        + " Further authentication is not required!";
-            session.writeResponse(responseString);
+            return new SMTPResponse("503", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" User has previously authenticated. "
+                    + " Further authentication is not required!");
         } else if (argument == null) {
-            responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Usage: AUTH (authentication type) <challenge>";
-            session.writeResponse(responseString);
+            return new SMTPResponse("501", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Usage: AUTH (authentication type) <challenge>");
         } else {
             String initialResponse = null;
             if ((argument != null) && (argument.indexOf(" ") > 0)) {
@@ -94,14 +85,50 @@
             }
             String authType = argument.toUpperCase(Locale.US);
             if (authType.equals(AUTH_TYPE_PLAIN)) {
-                doPlainAuth(session, initialResponse);
-                return;
+                String userpass;
+                if (initialResponse == null) {
+                    session.pushLineHandler(new LineHandler() {
+
+                        public void onLine(SMTPSession session, byte[] line) {
+                            try {
+                                String l = new String(line, "US-ASCII");
+                                System.err.println("((("+line+")))");
+                                SMTPResponse res = doPlainAuthPass(session, l);
+                                session.writeSMTPResponse(res);
+                            } catch (UnsupportedEncodingException e) {
+                                // TODO should never happen
+                                e.printStackTrace();
+                            }
+                        }
+                        
+                    });
+                    return new SMTPResponse("334", "OK. Continue authentication");
+                } else {
+                    userpass = initialResponse.trim();
+                    return doPlainAuthPass(session, userpass);
+                }
             } else if (authType.equals(AUTH_TYPE_LOGIN)) {
-                doLoginAuth(session, initialResponse);
-                return;
+                
+                if (initialResponse == null) {
+                    session.pushLineHandler(new LineHandler() {
+
+                        public void onLine(SMTPSession session, byte[] line) {
+                            try {
+                                session.writeSMTPResponse(doLoginAuthPass(session, new String(line, "US-ASCII"), true));
+                            } catch (UnsupportedEncodingException e) {
+                                // TODO should never happen
+                                e.printStackTrace();
+                            }
+                        }
+                        
+                    });
+                    return new SMTPResponse("334", "VXNlcm5hbWU6"); // base64 encoded "Username:"
+                } else {
+                    String user = initialResponse.trim();
+                    return doLoginAuthPass(session, user, false);
+                }
             } else {
-                doUnknownAuth(session, authType, initialResponse);
-                return;
+                return doUnknownAuth(session, authType, initialResponse);
             }
         }
     }
@@ -120,16 +147,8 @@
      * @param session SMTP session object
      * @param initialResponse the initial response line passed in with the AUTH command
      */
-    private void doPlainAuth(SMTPSession session, String initialResponse)
-            throws IOException {
-        String userpass = null, user = null, pass = null, responseString = null;
-        if (initialResponse == null) {
-            responseString = "334 OK. Continue authentication";
-            session.writeResponse(responseString);
-            userpass = session.readCommandLine();
-        } else {
-            userpass = initialResponse.trim();
-        }
+    private SMTPResponse doPlainAuthPass(SMTPSession session, String userpass) {
+        String user = null, pass = null;
         try {
             if (userpass != null) {
                 userpass = Base64.decodeAsString(userpass);
@@ -182,21 +201,18 @@
             // Ignored - this exception in parsing will be dealt
             // with in the if clause below
         }
+        session.popLineHandler();
         // Authenticate user
         if ((user == null) || (pass == null)) {
-            responseString = "501 Could not decode parameters for AUTH PLAIN";
-            session.writeResponse(responseString);
+            return new SMTPResponse("501", "Could not decode parameters for AUTH PLAIN");
         } else if (session.getConfigurationData().getUsersRepository().test(user, pass)) {
             session.setUser(user);
-            responseString = "235 Authentication Successful";
-            session.writeResponse(responseString);
             getLogger().info("AUTH method PLAIN succeeded");
+            return new SMTPResponse("235", "Authentication Successful");
         } else {
-            responseString = "535 Authentication Failed";
-            session.writeResponse(responseString);
             getLogger().error("AUTH method PLAIN failed");
+            return new SMTPResponse("535", "Authentication Failed");
         }
-        return;
     }
 
     /**
@@ -205,16 +221,7 @@
      * @param session SMTP session object
      * @param initialResponse the initial response line passed in with the AUTH command
      */
-    private void doLoginAuth(SMTPSession session, String initialResponse)
-            throws IOException {
-        String user = null, pass = null, responseString = null;
-        if (initialResponse == null) {
-            responseString = "334 VXNlcm5hbWU6"; // base64 encoded "Username:"
-            session.writeResponse(responseString);
-            user = session.readCommandLine();
-        } else {
-            user = initialResponse.trim();
-        }
+    private SMTPResponse doLoginAuthPass(SMTPSession session, String user, boolean inCustomeHandler) {
         if (user != null) {
             try {
                 user = Base64.decodeAsString(user);
@@ -224,9 +231,33 @@
                 user = null;
             }
         }
-        responseString = "334 UGFzc3dvcmQ6"; // base64 encoded "Password:"
-        session.writeResponse(responseString);
-        pass = session.readCommandLine();
+        if (inCustomeHandler) {
+            session.popLineHandler();
+        }
+        session.pushLineHandler(new LineHandler() {
+
+            private String user;
+
+            public void onLine(SMTPSession session, byte[] line) {
+                try {
+                    doLoginAuthPassCheck(session, user, new String(line, "US-ASCII"));
+                } catch (UnsupportedEncodingException e) {
+                    // TODO should never happen
+                    e.printStackTrace();
+                }
+            }
+
+            public LineHandler setUser(String user) {
+                this.user = user;
+                return this;
+            }
+            
+        }.setUser(user));
+        return new SMTPResponse("334", "UGFzc3dvcmQ6"); // base64 encoded "Password:"
+    }
+    
+    private void doLoginAuthPassCheck(SMTPSession session, String user, String pass) {
+        String responseString = null;
         if (pass != null) {
             try {
                 pass = Base64.decodeAsString(pass);
@@ -251,6 +282,8 @@
             // TODO: Make this string a more useful error message
             getLogger().error("AUTH method LOGIN failed");
         }
+        session.popLineHandler();
+        session.popLineHandler();
         session.writeResponse(responseString);
         return;
     }
@@ -262,9 +295,7 @@
      * @param authType the unknown auth type
      * @param initialResponse the initial response line passed in with the AUTH command
      */
-    private void doUnknownAuth(SMTPSession session, String authType, String initialResponse) {
-        String responseString = "504 Unrecognized Authentication Type";
-        session.writeResponse(responseString);
+    private SMTPResponse doUnknownAuth(SMTPSession session, String authType, String initialResponse) {
         if (getLogger().isErrorEnabled()) {
             StringBuffer errorBuffer =
                 new StringBuffer(128)
@@ -273,7 +304,7 @@
                         .append(" is an unrecognized authentication type");
             getLogger().error(errorBuffer.toString());
         }
-        return;
+        return new SMTPResponse("504", "Unrecognized Authentication Type");
     }
 
 
Index: java/org/apache/james/smtpserver/core/DataCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/DataCmdHandler.java	(revision 487826)
+++ java/org/apache/james/smtpserver/core/DataCmdHandler.java	(working copy)
@@ -27,7 +27,9 @@
 import org.apache.james.core.MailImpl;
 import org.apache.james.fetchmail.ReaderInputStream;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.LineHandler;
 import org.apache.james.smtpserver.MessageSizeException;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.smtpserver.SizeLimitedInputStream;
 import org.apache.james.util.CharTerminatedInputStream;
@@ -33,7 +35,6 @@
 import org.apache.james.util.CharTerminatedInputStream;
 import org.apache.james.util.DotStuffingInputStream;
 import org.apache.james.util.mail.dsn.DSNStatus;
-import org.apache.james.util.watchdog.BytesReadResetInputStream;
 import org.apache.mailet.MailAddress;
 import org.apache.mailet.RFC2822Headers;
 import org.apache.mailet.dates.RFC822DateFormat;
@@ -43,6 +44,9 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
 import java.io.SequenceInputStream;
 import java.io.StringReader;
 import java.util.ArrayList;
@@ -89,8 +93,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doDATA(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return doDATA(session, parameters);
     }
 
 
@@ -102,16 +106,81 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doDATA(SMTPSession session, String argument) {
+    private SMTPResponse doDATA(SMTPSession session, String argument) {
+        PipedInputStream messageIn = new PipedInputStream();
+        Thread t = new Thread() {
+            private PipedInputStream in;
+            private SMTPSession session;
+
+            public void run() {
+                handleStream(session, in);
+            }
+
+            public Thread setParam(SMTPSession session, PipedInputStream in) {
+                this.in = in;
+                this.session = session;
+                return this;
+            }
+        }.setParam(session, messageIn);
+        
+        t.start();
+        
+        OutputStream out;
+        try {
+            out = new PipedOutputStream(messageIn);
+            session.pushLineHandler(new LineHandler() {
+
+                private OutputStream out;
+                private Thread worker;
+
+                public void onLine(SMTPSession session, byte[] line) {
+                    try {
+                        out.write(line);
+//                        out.write(13);
+//                        out.write(10);
+                        out.flush();
+                        // 46 is "."
+                        if (line.length == 3 && line[0] == 46) {
+                            try {
+                                worker.join();
+                            } catch (InterruptedException e) {
+                                // TODO Auto-generated catch block
+                                e.printStackTrace();
+                            }
+                        }
+                        
+                    } catch (IOException e) {
+                        // TODO Define what we have to do here!
+                        e.printStackTrace();
+                    }
+                }
 
-        String responseString = null;
-        responseString = "354 Ok Send data ending with <CRLF>.<CRLF>";
-        session.writeResponse(responseString);
-        InputStream msgIn = new CharTerminatedInputStream(session
-                .getInputStream(), SMTPTerminator);
+                public LineHandler setParam(OutputStream out, Thread t) {
+                    this.out = out;
+                    this.worker = t;
+                    return this;
+                };
+            
+            }.setParam(out,t));
+        } catch (IOException e1) {
+            // TODO Define what to do.
+            e1.printStackTrace();
+        }
+        
+        return new SMTPResponse("354", "Ok Send data ending with <CRLF>.<CRLF>");
+    }
+    
+
+    public void handleStream(SMTPSession session, InputStream stream) {
+        String responseString;
+        InputStream msgIn = new CharTerminatedInputStream(stream, SMTPTerminator);
         try {
-            msgIn = new BytesReadResetInputStream(msgIn, session.getWatchdog(),
-                    session.getConfigurationData().getResetLength());
+            // 2006/12/24 - We can remove this now that every single line is pushed and
+            // reset the watchdog already in the handler.
+            // This means we don't use resetLength anymore and we can remove
+            // watchdog from the SMTPSession interface
+            // msgIn = new BytesReadResetInputStream(msgIn, session.getWatchdog(),
+            //         session.getConfigurationData().getResetLength());
 
             // if the message size limit has been set, we'll
             // wrap msgIn with a SizeLimitedInputStream
@@ -168,6 +237,7 @@
                 getLogger().error(
                         "Unknown error occurred while processing DATA.", me);
             }
+            session.popLineHandler();
             session.writeResponse(responseString);
             return;
         } finally {
@@ -311,6 +381,8 @@
                 mail.setAttribute(SMTP_AUTH_NETWORK_NAME,"true");
             }
             
+            session.popLineHandler();
+            
             session.setMail(mail);
         } catch (MessagingException me) {
             // if we get here, it means that we received a
@@ -356,4 +428,5 @@
         return implCommands;
     }
 
+
 }
Index: java/org/apache/james/smtpserver/core/EhloCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/EhloCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/EhloCmdHandler.java	(working copy)
@@ -26,7 +26,9 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
+import org.apache.james.util.mail.SMTPRetCode;
 
 /**
  * Handles EHLO command
@@ -44,8 +46,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      **/
-    public void onCommand(SMTPSession session) {
-        doEHLO(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return doEHLO(session, arguments);
     }
 
     /**
@@ -56,17 +58,16 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doEHLO(SMTPSession session, String argument) {
-        StringBuffer responseBuffer = session.getResponseBuffer();
-
+    private SMTPResponse doEHLO(SMTPSession session, String argument) {
+        SMTPResponse resp = new SMTPResponse();
+        resp.setRetCode(SMTPRetCode.MAIL_OK);
+        
         session.getConnectionState().put(SMTPSession.CURRENT_HELO_MODE, COMMAND_NAME);
 
-        ArrayList esmtpextensions = new ArrayList();
-
-        esmtpextensions.add(new StringBuffer(session.getConfigurationData()
+        resp.appendLine(new StringBuffer(session.getConfigurationData()
                 .getHelloName()).append(" Hello ").append(argument)
                 .append(" (").append(session.getRemoteHost()).append(" [")
-                .append(session.getRemoteIPAddress()).append("])").toString());
+                .append(session.getRemoteIPAddress()).append("])"));
 
         // Extension defined in RFC 1870
         long maxMessageSize = session.getConfigurationData()
@@ -72,31 +73,19 @@
         long maxMessageSize = session.getConfigurationData()
                 .getMaxMessageSize();
         if (maxMessageSize > 0) {
-            esmtpextensions.add("SIZE " + maxMessageSize);
+            resp.appendLine("SIZE " + maxMessageSize);
         }
 
         if (session.isAuthRequired()) {
-            esmtpextensions.add("AUTH LOGIN PLAIN");
-            esmtpextensions.add("AUTH=LOGIN PLAIN");
+            resp.appendLine("AUTH LOGIN PLAIN");
+            resp.appendLine("AUTH=LOGIN PLAIN");
         }
 
-        esmtpextensions.add("PIPELINING");
-        esmtpextensions.add("ENHANCEDSTATUSCODES");
+        resp.appendLine("PIPELINING");
+        resp.appendLine("ENHANCEDSTATUSCODES");
         // see http://issues.apache.org/jira/browse/JAMES-419 
-        esmtpextensions.add("8BITMIME");
-
-        // Iterator i = esmtpextensions.iterator();
-        for (int i = 0; i < esmtpextensions.size(); i++) {
-            if (i == esmtpextensions.size() - 1) {
-                responseBuffer.append("250 ");
-                responseBuffer.append((String) esmtpextensions.get(i));
-                session.writeResponse(session.clearResponseBuffer());
-            } else {
-                responseBuffer.append("250-");
-                responseBuffer.append((String) esmtpextensions.get(i));
-                session.writeResponse(session.clearResponseBuffer());
-            }
-        }
+        resp.appendLine("8BITMIME");
+        return resp;
 
     }
     
Index: java/org/apache/james/smtpserver/core/ExpnCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/ExpnCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/ExpnCmdHandler.java	(working copy)
@@ -25,6 +25,7 @@
 import java.util.Collection;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
@@ -45,9 +46,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        String responseString = "502 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SYSTEM_NOT_CAPABLE)+" EXPN is not supported";
-        session.writeResponse(responseString);
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return new SMTPResponse("502", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SYSTEM_NOT_CAPABLE)+" EXPN is not supported");
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/HeloCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/HeloCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/HeloCmdHandler.java	(working copy)
@@ -27,6 +27,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 
 
@@ -45,8 +46,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
-        doHELO(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return doHELO(session, arguments);
     }
 
     /**
@@ -53,17 +54,14 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doHELO(SMTPSession session, String argument) {
-        String responseString = null;
-
+    private SMTPResponse doHELO(SMTPSession session, String argument) {
         session.getConnectionState().put(SMTPSession.CURRENT_HELO_MODE, COMMAND_NAME);
-        session.getResponseBuffer().append("250 ").append(
-                session.getConfigurationData().getHelloName())
+        StringBuffer response = new StringBuffer();
+        response.append(session.getConfigurationData().getHelloName())
                 .append(" Hello ").append(argument).append(" (").append(
                         session.getRemoteHost()).append(" [").append(
                         session.getRemoteIPAddress()).append("])");
-        responseString = session.clearResponseBuffer();
-        session.writeResponse(responseString);
+        return new SMTPResponse("250", response);
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/HelpCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/HelpCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/HelpCmdHandler.java	(working copy)
@@ -25,6 +25,7 @@
 import java.util.Collection;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
@@ -43,9 +44,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
-        String responseString = "502 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SYSTEM_NOT_CAPABLE)+" HELP is not supported";
-        session.writeResponse(responseString);
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return new SMTPResponse("502", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SYSTEM_NOT_CAPABLE)+" HELP is not supported");
     }
 
     /**
Index: java/org/apache/james/smtpserver/core/MailCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/MailCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/MailCmdHandler.java	(working copy)
@@ -26,6 +26,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.MailAddress;
@@ -43,8 +44,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doMAIL(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return doMAIL(session, arguments);
     }
 
 
@@ -55,21 +56,12 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doMAIL(SMTPSession session, String argument) {
-      
-        StringBuffer responseBuffer = session.getResponseBuffer();
-        String responseString = null;
-
-        MailAddress sender = (MailAddress) session.getState().get(
-                SMTPSession.SENDER);
-        responseBuffer.append(
-                "250 "
-                        + DSNStatus.getStatus(DSNStatus.SUCCESS,
-                                DSNStatus.ADDRESS_OTHER) + " Sender <").append(
-                sender).append("> OK");
-        responseString = session.clearResponseBuffer();
-        session.writeResponse(responseString);
-        
+    private SMTPResponse doMAIL(SMTPSession session, String argument) {
+        StringBuffer responseBuffer = new StringBuffer();
+        MailAddress sender = (MailAddress) session.getState().get(SMTPSession.SENDER);
+        responseBuffer.append(DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.ADDRESS_OTHER) + " Sender <")
+                .append(sender).append("> OK");
+        return new SMTPResponse("250", responseBuffer);
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/NoopCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/NoopCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/NoopCmdHandler.java	(working copy)
@@ -25,6 +25,7 @@
 import java.util.Collection;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
@@ -44,9 +45,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        String responseString = "250 "+DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.UNDEFINED_STATUS)+" OK";
-        session.writeResponse(responseString);
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return new SMTPResponse("250", DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.UNDEFINED_STATUS)+" OK");
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/QuitCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/QuitCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/QuitCmdHandler.java	(working copy)
@@ -25,6 +25,7 @@
 import java.util.Collection;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
@@ -43,8 +44,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doQUIT(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return doQUIT(session, parameters);
 
     }
 
@@ -57,19 +58,20 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doQUIT(SMTPSession session, String argument) {
-
-        String responseString = "";
+    private SMTPResponse doQUIT(SMTPSession session, String argument) {
+        SMTPResponse ret;
         if ((argument == null) || (argument.length() == 0)) {
-            session.getResponseBuffer().append("221 "+DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.UNDEFINED_STATUS)+" ")
-                          .append(session.getConfigurationData().getHelloName())
-                          .append(" Service closing transmission channel");
-            responseString = session.clearResponseBuffer();
+            StringBuffer response = new StringBuffer();
+            response.append(DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.UNDEFINED_STATUS))
+                    .append(" ")
+                    .append(session.getConfigurationData().getHelloName())
+                    .append(" Service closing transmission channel");
+            ret = new SMTPResponse("221", response);
         } else {
-            responseString = "500 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Unexpected argument provided with QUIT command";
+            ret = new SMTPResponse("500", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Unexpected argument provided with QUIT command");
         }
-        session.writeResponse(responseString);
-        session.endSession();
+        ret.setEndSession(true);
+        return ret;
     }
 
     /**
Index: java/org/apache/james/smtpserver/core/RcptCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/RcptCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/RcptCmdHandler.java	(working copy)
@@ -26,6 +26,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.MailAddress;
@@ -41,8 +42,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
-        doRCPT(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return doRCPT(session, parameters);
     }
 
 
@@ -54,11 +55,7 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doRCPT(SMTPSession session, String argument) {
-       
-        String responseString = null;
-        StringBuffer responseBuffer = session.getResponseBuffer();
-
+    private SMTPResponse doRCPT(SMTPSession session, String argument) {
         Collection rcptColl = (Collection) session.getState().get(
                 SMTPSession.RCPT_LIST);
         if (rcptColl == null) {
@@ -68,13 +65,12 @@
                 SMTPSession.CURRENT_RECIPIENT);
         rcptColl.add(recipientAddress);
         session.getState().put(SMTPSession.RCPT_LIST, rcptColl);
-        responseBuffer.append(
-                "250 "
-                        + DSNStatus.getStatus(DSNStatus.SUCCESS,
-                                DSNStatus.ADDRESS_VALID) + " Recipient <")
-                .append(recipientAddress).append("> OK");
-        responseString = session.clearResponseBuffer();
-        session.writeResponse(responseString);
+        StringBuffer response = new StringBuffer();
+        response.append(DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.ADDRESS_VALID))
+                .append(" Recipient <")
+                .append(recipientAddress)
+                .append("> OK");
+        return new SMTPResponse("250", response);
              
     }
     
Index: java/org/apache/james/smtpserver/core/RsetCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/RsetCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/RsetCmdHandler.java	(working copy)
@@ -25,6 +25,7 @@
 import java.util.Collection;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
@@ -42,8 +43,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
-        doRSET(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return doRSET(session, session.getCommandArgument());
     }
 
 
@@ -53,18 +54,15 @@
      *
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
+     * @return 
      */
-    private void doRSET(SMTPSession session, String argument) {
-        String responseString = "";
+    private SMTPResponse doRSET(SMTPSession session, String argument) {
         if ((argument == null) || (argument.length() == 0)) {
-
             session.resetState();
-
-            responseString = "250 "+DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.UNDEFINED_STATUS)+" OK";
+            return new SMTPResponse("250", DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.UNDEFINED_STATUS)+" OK");
         } else {
-            responseString = "500 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Unexpected argument provided with RSET command";
+            return new SMTPResponse("500", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Unexpected argument provided with RSET command");
         }
-        session.writeResponse(responseString);
     }
 
     /**
Index: java/org/apache/james/smtpserver/core/UnknownCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/UnknownCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/UnknownCmdHandler.java	(working copy)
@@ -25,6 +25,7 @@
 import java.util.Collection;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
@@ -38,8 +39,6 @@
      */
     public static final String UNKNOWN_COMMAND = "UNKNOWN";
     
-    private boolean stopHandlerProcessing = true;
-
     /**
      * Handler method called upon receipt of an unrecognized command.
      * Returns an error response and logs the command.
@@ -46,20 +45,19 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
 
         //If there was message failure, don't consider it as an unknown command
         if (session.getState().get(SMTPSession.MESG_FAILED) != null) {
-            return;
+            return null;
         }
 
-        session.getResponseBuffer().append("500 "+DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_CMD))
+        StringBuffer result = new StringBuffer();
+        result.append(DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_CMD))
                       .append(" Command ")
                       .append(session.getCommandName())
                       .append(" unrecognized.");
-        String responseString = session.clearResponseBuffer();
-
-        session.writeResponse(responseString);
+        return new SMTPResponse("500", result);
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/VrfyCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/VrfyCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/VrfyCmdHandler.java	(working copy)
@@ -25,7 +25,9 @@
 import java.util.Collection;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
+import org.apache.james.util.mail.SMTPRetCode;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
 /**
@@ -42,9 +44,9 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
-        String responseString = "502 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SYSTEM_NOT_CAPABLE)+" VRFY is not supported";
-        session.writeResponse(responseString);
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return new SMTPResponse(SMTPRetCode.UNIMPLEMENTED_COMMAND, 
+                DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SYSTEM_NOT_CAPABLE)+" VRFY is not supported");
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/filter/DataFilterCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/DataFilterCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/filter/DataFilterCmdHandler.java	(working copy)
@@ -26,6 +26,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
@@ -42,8 +43,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doDATA(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return doDATA(session, parameters);
     }
 
 
@@ -51,28 +52,16 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doDATA(SMTPSession session, String argument) {
-        String responseString = null;
+    private SMTPResponse doDATA(SMTPSession session, String argument) {
         if ((argument != null) && (argument.length() > 0)) {
-            responseString = "500 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Unexpected argument provided with DATA command";
-            session.writeResponse(responseString);
-            
-            //TODO: Check if this should been!
+            return new SMTPResponse("500", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Unexpected argument provided with DATA command");
         }
         if (!session.getState().containsKey(SMTPSession.SENDER)) {
-            responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" No sender specified";
-            session.writeResponse(responseString);
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-            
+            return new SMTPResponse("503", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" No sender specified");
         } else if (!session.getState().containsKey(SMTPSession.RCPT_LIST)) {
-            responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" No recipients specified";
-            session.writeResponse(responseString);
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
+            return new SMTPResponse("503", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" No recipients specified");
         }
+        return null;
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/filter/EhloFilterCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/EhloFilterCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/filter/EhloFilterCmdHandler.java	(working copy)
@@ -26,6 +26,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
@@ -44,8 +45,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
-        doEHLO(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return doEHLO(session, arguments);
     }
 
     /**
@@ -52,20 +53,15 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doEHLO(SMTPSession session, String argument) {
-        String responseString = null;        
-     
+    private SMTPResponse doEHLO(SMTPSession session, String argument) {
         session.resetState();
         
         if (argument == null) {
-            responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Domain address required: " + COMMAND_NAME;
-            session.writeResponse(responseString);
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
+            return new SMTPResponse("501", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Domain address required: " + COMMAND_NAME);
         } else {
             // store provided name
             session.getState().put(SMTPSession.CURRENT_HELO_NAME,argument);
+            return null;
         }
     }
     
Index: java/org/apache/james/smtpserver/core/filter/HeloFilterCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/HeloFilterCmdHandler.java	(revision 468922)
+++ java/org/apache/james/smtpserver/core/filter/HeloFilterCmdHandler.java	(working copy)
@@ -27,6 +27,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 
 
@@ -45,8 +46,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
-        doHELO(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return doHELO(session, arguments);
     }
 
     /**
@@ -53,22 +54,17 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doHELO(SMTPSession session, String argument) {
-        String responseString = null;        
-
+    private SMTPResponse doHELO(SMTPSession session, String argument) {
         session.resetState();
               
         if (argument == null) {
-            responseString = "501 Domain address required: " + COMMAND_NAME;
-            session.writeResponse(responseString);
+            String responseString = "Domain address required: " + COMMAND_NAME;
             getLogger().info(responseString);
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-         
+            return new SMTPResponse("501", responseString);
         } else {
             // store provided name
             session.getState().put(SMTPSession.CURRENT_HELO_NAME,argument);
+            return null;
         }
     }
     
Index: java/org/apache/james/smtpserver/core/filter/MailFilterCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/MailFilterCmdHandler.java	(revision 487826)
+++ java/org/apache/james/smtpserver/core/filter/MailFilterCmdHandler.java	(working copy)
@@ -28,6 +28,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.MailAddress;
@@ -48,8 +49,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doMAIL(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
+        return doMAIL(session, arguments);
     }
 
 
@@ -57,8 +58,7 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doMAIL(SMTPSession session, String argument) {
-        String responseString = null;
+    private SMTPResponse doMAIL(SMTPSession session, String argument) {
         String sender = null;
         
         if ((argument != null) && (argument.indexOf(":") > 0)) {
@@ -67,27 +67,12 @@
             argument = argument.substring(0, colonIndex);
         }
         if (session.getState().containsKey(SMTPSession.SENDER)) {
-            responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" Sender already specified";
-            session.writeResponse(responseString);
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-            
+            return new SMTPResponse("503", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" Sender already specified");
         } else if (!session.getConnectionState().containsKey(SMTPSession.CURRENT_HELO_MODE) && session.useHeloEhloEnforcement()) {
-            responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" Need HELO or EHLO before MAIL";
-            session.writeResponse(responseString);
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-            
+            return new SMTPResponse("503", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" Need HELO or EHLO before MAIL");
         } else if (argument == null || !argument.toUpperCase(Locale.US).equals("FROM")
                    || sender == null) {
-            responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Usage: MAIL FROM:<sender>";
-            session.writeResponse(responseString);
-        
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-            
+            return new SMTPResponse("501", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Usage: MAIL FROM:<sender>");
         } else {
             sender = sender.trim();
             // the next gt after the first lt ... AUTH may add more <>
@@ -114,8 +99,9 @@
                     // Handle the SIZE extension keyword
 
                     if (mailOptionName.startsWith(MAIL_OPTION_SIZE)) {
-                        if (!(doMailSize(session, mailOptionValue, sender))) {
-                            return;
+                        SMTPResponse res = doMailSize(session, mailOptionValue, sender);
+                        if (res != null) {
+                            return res;
                         }
                     } else {
                         // Unexpected option attached to the Mail command
@@ -132,8 +118,6 @@
                 }
             }
             if ( session.getConfigurationData().useAddressBracketsEnforcement() && (!sender.startsWith("<") || !sender.endsWith(">"))) {
-                responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX_SENDER)+" Syntax error in MAIL command";
-                session.writeResponse(responseString);
                 if (getLogger().isErrorEnabled()) {
                     StringBuffer errorBuffer =
                         new StringBuffer(128)
@@ -142,10 +126,7 @@
                             .append(": did not start and end with < >");
                     getLogger().error(errorBuffer.toString());
                 }
-                // After this filter match we should not call any other handler!
-                session.setStopHandlerProcessing(true);
-                
-                return;
+                return new SMTPResponse("501", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX_SENDER)+" Syntax error in MAIL command");
             }
             MailAddress senderAddress = null;
             
@@ -165,8 +146,6 @@
                 try {
                     senderAddress = new MailAddress(sender);
                 } catch (Exception pe) {
-                    responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX_SENDER)+" Syntax error in sender address";
-                    session.writeResponse(responseString);
                     if (getLogger().isErrorEnabled()) {
                         StringBuffer errorBuffer =
                             new StringBuffer(256)
@@ -176,11 +155,7 @@
                                     .append(pe.getMessage());
                         getLogger().error(errorBuffer.toString());
                     }
-                    
-                    // After this filter match we should not call any other handler!
-                    session.setStopHandlerProcessing(true);
-                    
-                    return;
+                    return new SMTPResponse("501", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX_SENDER)+" Syntax error in sender address");
                 }
             }
          
@@ -187,6 +162,7 @@
             // Store the senderAddress in session map
             session.getState().put(SMTPSession.SENDER, senderAddress);
         }
+        return null;
     }
 
     /**
@@ -197,7 +173,7 @@
      * @param tempSender the sender specified in this mail command (for logging purpose)
      * @return true if further options should be processed, false otherwise
      */
-    private boolean doMailSize(SMTPSession session, String mailOptionValue, String tempSender) {
+    private SMTPResponse doMailSize(SMTPSession session, String mailOptionValue, String tempSender) {
         int size = 0;
         try {
             size = Integer.parseInt(mailOptionValue);
@@ -202,15 +178,9 @@
         try {
             size = Integer.parseInt(mailOptionValue);
         } catch (NumberFormatException pe) {
-            // This is a malformed option value.  We return an error
-            String responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Syntactically incorrect value for SIZE parameter";
-            session.writeResponse(responseString);
             getLogger().error("Rejected syntactically incorrect value for SIZE parameter.");
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-            
-            return false;
+            // This is a malformed option value.  We return an error
+            return new SMTPResponse("501", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Syntactically incorrect value for SIZE parameter");
         }
         if (getLogger().isDebugEnabled()) {
             StringBuffer debugBuffer =
@@ -223,8 +193,6 @@
         long maxMessageSize = session.getConfigurationData().getMaxMessageSize();
         if ((maxMessageSize > 0) && (size > maxMessageSize)) {
             // Let the client know that the size limit has been hit.
-            String responseString = "552 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SYSTEM_MSG_TOO_BIG)+" Message size exceeds fixed maximum message size";
-            session.writeResponse(responseString);
             StringBuffer errorBuffer =
                 new StringBuffer(256)
                     .append("Rejected message from ")
@@ -240,10 +208,7 @@
                     .append("based on SIZE option.");
             getLogger().error(errorBuffer.toString());
             
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-            
-            return false;
+            return new SMTPResponse("552", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SYSTEM_MSG_TOO_BIG)+" Message size exceeds fixed maximum message size");
         } else {
             // put the message size in the message state so it can be used
             // later to restrict messages for user quotas, etc.
@@ -249,7 +214,7 @@
             // later to restrict messages for user quotas, etc.
             session.getState().put(MESG_SIZE, new Integer(size));
         }
-        return true;
+        return null;
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/filter/RcptFilterCmdHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/RcptFilterCmdHandler.java	(revision 487826)
+++ java/org/apache/james/smtpserver/core/filter/RcptFilterCmdHandler.java	(working copy)
@@ -29,7 +29,9 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
+import org.apache.james.util.mail.SMTPRetCode;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.MailAddress;
 
@@ -45,8 +47,8 @@
      *
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
     **/
-    public void onCommand(SMTPSession session) {
-        doRCPT(session, session.getCommandArgument());
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return doRCPT(session, parameters);
     }
 
 
@@ -54,9 +56,7 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doRCPT(SMTPSession session, String argument) {
-        String responseString = null;
-        
+    private SMTPResponse doRCPT(SMTPSession session, String argument) {
         String recipient = null;
         if ((argument != null) && (argument.indexOf(":") > 0)) {
             int colonIndex = argument.indexOf(":");
@@ -64,20 +64,10 @@
             argument = argument.substring(0, colonIndex);
         }
         if (!session.getState().containsKey(SMTPSession.SENDER)) {
-            responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" Need MAIL before RCPT";
-            session.writeResponse(responseString);
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-            
+            return new SMTPResponse("503", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" Need MAIL before RCPT");
         } else if (argument == null || !argument.toUpperCase(Locale.US).equals("TO")
                    || recipient == null) {
-            responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_SYNTAX)+" Usage: RCPT TO:<recipient>";
-            session.writeResponse(responseString);
-            
-            // After this filter match we should not call any other handler!
-            session.setStopHandlerProcessing(true);
-            
+            return new SMTPResponse("501", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_SYNTAX)+" Usage: RCPT TO:<recipient>");
         } else {
             Collection rcptColl = (Collection) session.getState().get(SMTPSession.RCPT_LIST);
             if (rcptColl == null) {
@@ -95,8 +85,6 @@
                 recipient = recipient.substring(0, lastChar + 1);
             }
             if (session.getConfigurationData().useAddressBracketsEnforcement() && (!recipient.startsWith("<") || !recipient.endsWith(">"))) {
-                responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_SYNTAX)+" Syntax error in parameters or arguments";
-                session.writeResponse(responseString);
                 if (getLogger().isErrorEnabled()) {
                     StringBuffer errorBuffer =
                         new StringBuffer(192)
@@ -105,11 +93,7 @@
                                 .append(getContext(session,null,recipient));
                     getLogger().error(errorBuffer.toString());
                 }
-                
-                // After this filter match we should not call any other handler!
-                session.setStopHandlerProcessing(true);
-                
-                return;
+                return new SMTPResponse("501", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_SYNTAX)+" Syntax error in parameters or arguments");
             }
             MailAddress recipientAddress = null;
             //Remove < and >
@@ -125,14 +109,6 @@
             try {
                 recipientAddress = new MailAddress(recipient);
             } catch (Exception pe) {
-                /*
-                 * from RFC2822;
-                 * 553 Requested action not taken: mailbox name not allowed
-                 *     (e.g., mailbox syntax incorrect)
-                 */
-                responseString = "553 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX)+" Syntax error in recipient address";
-                session.writeResponse(responseString);
-
                 if (getLogger().isErrorEnabled()) {
                     StringBuffer errorBuffer =
                         new StringBuffer(192)
@@ -141,79 +117,65 @@
                                 .append(pe.getMessage());
                     getLogger().error(errorBuffer.toString());
                 }
-                
-                // After this filter match we should not call any other handler!
-                session.setStopHandlerProcessing(true);
-                
-                return;
+                /*
+                 * from RFC2822;
+                 * 553 Requested action not taken: mailbox name not allowed
+                 *     (e.g., mailbox syntax incorrect)
+                 */
+                return new SMTPResponse("553", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX)+" Syntax error in recipient address");
             }
 
             
-
-            if (session.isAuthRequired() && !session.isRelayingAllowed()) {
-                // Make sure the mail is being sent locally if not
-                // authenticated else reject.
-                if (session.getUser() == null) {
+            if (!session.isRelayingAllowed()) {
+                if (session.isAuthRequired()) {
+                    // Make sure the mail is being sent locally if not
+                    // authenticated else reject.
+                    if (session.getUser() == null) {
+                        String toDomain = recipientAddress.getHost();
+                        if (!session.getConfigurationData().getMailServer().isLocalServer(toDomain)) {
+                            StringBuffer sb = new StringBuffer(128);
+                            sb.append("Rejected message - authentication is required for mail request");
+                            sb.append(getContext(session,recipientAddress,recipient));
+                            getLogger().error(sb.toString());
+                            return new SMTPResponse("530", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Authentication Required");
+                        }
+                    } else {
+                        // Identity verification checking
+                        if (session.getConfigurationData().isVerifyIdentity()) {
+                            String authUser = (session.getUser()).toLowerCase(Locale.US);
+                            MailAddress senderAddress = (MailAddress) session.getState().get(SMTPSession.SENDER);
+    
+                            if ((senderAddress == null) || (!authUser.equals(senderAddress.getUser())) ||
+                                (!session.getConfigurationData().getMailServer().isLocalServer(senderAddress.getHost()))) {
+                                if (getLogger().isErrorEnabled()) {
+                                    StringBuffer errorBuffer =
+                                        new StringBuffer(128)
+                                            .append("User ")
+                                            .append(authUser)
+                                            .append(" authenticated, however tried sending email as ")
+                                            .append(senderAddress)
+                                            .append(getContext(session,recipientAddress,recipient));
+                                    getLogger().error(errorBuffer.toString());
+                                }
+                                
+                                return new SMTPResponse("503", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Incorrect Authentication for Specified Email Address");
+                            }
+                        }
+                    }
+                } else {
                     String toDomain = recipientAddress.getHost();
                     if (!session.getConfigurationData().getMailServer().isLocalServer(toDomain)) {
-                        responseString = "530 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Authentication Required";
-                        session.writeResponse(responseString);
-                        StringBuffer sb = new StringBuffer(128);
-                        sb.append("Rejected message - authentication is required for mail request");
-                        sb.append(getContext(session,recipientAddress,recipient));
-                        getLogger().error(sb.toString());
-                        
-                        // After this filter match we should not call any other handler!
-                        session.setStopHandlerProcessing(true);
+                        StringBuffer errorBuffer = new StringBuffer(128)
+                            .append("Rejected message - ")
+                            .append(session.getRemoteIPAddress())
+                            .append(" not authorized to relay to ")
+                            .append(toDomain)
+                            .append(getContext(session,recipientAddress,recipient));
+                        getLogger().error(errorBuffer.toString());
                         
-                        return;
-                    }
-                } else {
-                    // Identity verification checking
-                    if (session.getConfigurationData().isVerifyIdentity()) {
-                        String authUser = (session.getUser()).toLowerCase(Locale.US);
-                        MailAddress senderAddress = (MailAddress) session.getState().get(SMTPSession.SENDER);
-
-                        if ((senderAddress == null) || (!authUser.equals(senderAddress.getUser())) ||
-                            (!session.getConfigurationData().getMailServer().isLocalServer(senderAddress.getHost()))) {
-                            responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Incorrect Authentication for Specified Email Address";
-                            session.writeResponse(responseString);
-                            if (getLogger().isErrorEnabled()) {
-                                StringBuffer errorBuffer =
-                                    new StringBuffer(128)
-                                        .append("User ")
-                                        .append(authUser)
-                                        .append(" authenticated, however tried sending email as ")
-                                        .append(senderAddress)
-                                        .append(getContext(session,recipientAddress,recipient));
-                                getLogger().error(errorBuffer.toString());
-                            }
-                            
-                            // After this filter match we should not call any other handler!
-                            session.setStopHandlerProcessing(true);
-                            
-                            return;
-                        }
+                        return new SMTPResponse("550", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Requested action not taken: relaying denied");
                     }
                 }
-            } else if (!session.isRelayingAllowed()) {
-                String toDomain = recipientAddress.getHost();
-                if (!session.getConfigurationData().getMailServer().isLocalServer(toDomain)) {
-                    responseString = "550 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Requested action not taken: relaying denied";
-                    session.writeResponse(responseString);
-                    StringBuffer errorBuffer = new StringBuffer(128)
-                        .append("Rejected message - ")
-                        .append(session.getRemoteIPAddress())
-                        .append(" not authorized to relay to ")
-                        .append(toDomain)
-                        .append(getContext(session,recipientAddress,recipient));
-                    getLogger().error(errorBuffer.toString());
-                    
-                    // After this filter match we should not call any other handler!
-                    session.setStopHandlerProcessing(true);
-                    
-                    return;
-                }
             }
             if (rcptOptionString != null) {
 
@@ -239,9 +201,7 @@
                       getLogger().debug(debugBuffer.toString());
                   }
                   
-                  // After this filter match we should not call any other handler!
-                  session.setStopHandlerProcessing(true);
-                  
+                  return new SMTPResponse(SMTPRetCode.PARAMETER_NOT_IMPLEMENTED, "Unrecognized or unsupported option: "+rcptOptionName);
               }
               optionTokenizer = null;
             }
@@ -248,6 +208,7 @@
     
             session.getState().put(SMTPSession.CURRENT_RECIPIENT,recipientAddress);
         }
+        return null;
     }
 
 
Index: java/org/apache/james/smtpserver/core/filter/fastfail/AbstractJunkHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/AbstractJunkHandler.java	(revision 476826)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/AbstractJunkHandler.java	(working copy)
@@ -25,6 +25,7 @@
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.junkscore.JunkScore;
 import org.apache.james.util.junkscore.JunkScoreConfigUtil;
@@ -95,7 +96,7 @@
      * 
      * @param session the SMTPSession
      */
-    protected void doProcessing(SMTPSession session) {
+    protected SMTPResponse doProcessing(SMTPSession session) {
         if (check(session)) {
             JunkHandlerData data = getJunkHandlerData(session);
             
@@ -113,8 +114,11 @@
                 session.writeResponse(response);
                 // After this filter match we should not call any other handler!
                 session.setStopHandlerProcessing(true);
+                
+                return new SMTPResponse(response);
             }
-        } 
+        }
+        return null;
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/filter/fastfail/DNSRBLHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/DNSRBLHandler.java	(revision 476504)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/DNSRBLHandler.java	(working copy)
@@ -30,6 +30,7 @@
 import org.apache.james.services.DNSServer;
 import org.apache.james.smtpserver.CommandHandler;
 import org.apache.james.smtpserver.ConnectHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.junkscore.JunkScore;
 import org.apache.james.util.mail.dsn.DSNStatus;
@@ -256,8 +257,9 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doProcessing(session);       
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        doProcessing(session);
+        return null;
     }
 
     /**
@@ -299,4 +301,5 @@
         data.setScoreName("DNSRBLCheck");
         return data;
     }
+
 }
Index: java/org/apache/james/smtpserver/core/filter/fastfail/GreylistHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/GreylistHandler.java	(revision 476504)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/GreylistHandler.java	(working copy)
@@ -47,6 +47,7 @@
 import org.apache.james.services.DNSServer;
 import org.apache.james.services.FileSystem;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.JDBCUtil;
 import org.apache.james.util.NetMatcher;
@@ -287,11 +288,11 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
         if (!session.isRelayingAllowed() && !(session.isAuthRequired() && session.getUser() != null)) {
 
             if ((wNetworks == null) || (!wNetworks.matchInetNetwork(session.getRemoteIPAddress()))) {
-                doGreyListCheck(session, session.getCommandArgument());
+                return doGreyListCheck(session, session.getCommandArgument());
             } else {
                 getLogger().info("IpAddress " + session.getRemoteIPAddress() + " is whitelisted. Skip greylisting.");
             }
@@ -298,6 +299,7 @@
         } else {
             getLogger().info("IpAddress " + session.getRemoteIPAddress() + " is allowed to send. Skip greylisting.");
         }
+        return null;
     }
 
     /**
@@ -309,7 +311,7 @@
      *            SMTP session object
      * @param argument
      */
-    private void doGreyListCheck(SMTPSession session, String argument) {
+    private SMTPResponse doGreyListCheck(SMTPSession session, String argument) {
         String recip = "";
         String sender = "";
         MailAddress recipAddress = (MailAddress) session.getState().get(SMTPSession.CURRENT_RECIPIENT);
@@ -321,6 +323,7 @@
         long time = System.currentTimeMillis();
         String ipAddress = session.getRemoteIPAddress();
     
+        SMTPResponse ret = null;
         try {
             long createTimeStamp = 0;
             int count = 0;
@@ -341,13 +344,8 @@
                 long acceptTime = createTimeStamp + tempBlockTime;
         
                 if ((time < acceptTime) && (count == 0)) {
-                    String responseString = "451 " + DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.NETWORK_DIR_SERVER) 
-                        + " Temporary rejected: Reconnect to fast. Please try again later";
-
-                    // reconnect to fast block it again
-                    session.writeResponse(responseString);
-                    session.setStopHandlerProcessing(true);
-
+                    ret = new SMTPResponse("451", DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.NETWORK_DIR_SERVER) 
+                        + " Temporary rejected: Reconnect to fast. Please try again later");
                 } else {
                     
                     getLogger().debug("Update triplet " + ipAddress + " | " + sender + " | " + recip + " -> timestamp: " + time);
@@ -363,11 +361,8 @@
                 insertTriplet(datasource.getConnection(), ipAddress, sender, recip, count, time);
       
                 // Tempory block on new triplet!
-                String responseString = "451 " + DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.NETWORK_DIR_SERVER) 
-                    + " Temporary rejected: Please try again later";
-
-                session.writeResponse(responseString);
-                session.setStopHandlerProcessing(true);
+                ret = new SMTPResponse("451", DSNStatus.getStatus(DSNStatus.TRANSIENT, DSNStatus.NETWORK_DIR_SERVER) 
+                    + " Temporary rejected: Please try again later");
             }
 
             // some kind of random cleanup process
@@ -384,6 +379,7 @@
             // just log the exception
             getLogger().error("Error on SQLquery: " + e.getMessage());
         }
+        return ret;
     }
 
     /**
Index: java/org/apache/james/smtpserver/core/filter/fastfail/MaxRcptHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/MaxRcptHandler.java	(revision 476504)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/MaxRcptHandler.java	(working copy)
@@ -28,6 +28,7 @@
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 
 import org.apache.james.util.mail.dsn.DSNStatus;
@@ -67,8 +68,9 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
+    public SMTPResponse onCommand(SMTPSession session, String command, String arguments) {
         doProcessing(session);
+        return null;
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/filter/fastfail/ResolvableEhloHeloHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/ResolvableEhloHeloHandler.java	(revision 476504)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/ResolvableEhloHeloHandler.java	(working copy)
@@ -27,6 +27,7 @@
 import org.apache.avalon.framework.service.Serviceable;
 import org.apache.james.services.DNSServer;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.junkscore.JunkScore;
 import org.apache.james.util.mail.dsn.DSNStatus;
@@ -110,15 +111,14 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        String argument = session.getCommandArgument();
-        String command = session.getCommandName();
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
         if (command.equals("HELO")
                 || command.equals("EHLO")) {
-            checkEhloHelo(session, argument);
+            checkEhloHelo(session, parameters);
         } else if (command.equals("RCPT")) {
-            doProcessing(session);
+            return doProcessing(session);
         }
+        return null;
     }
 
     /**
Index: java/org/apache/james/smtpserver/core/filter/fastfail/SPFHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/SPFHandler.java	(revision 489926)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/SPFHandler.java	(working copy)
@@ -33,6 +33,7 @@
 import org.apache.james.jspf.core.DNSService;
 import org.apache.james.smtpserver.CommandHandler;
 import org.apache.james.smtpserver.MessageHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.Mail;
@@ -160,12 +161,13 @@
      * 
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
         if (session.getCommandName().equals("MAIL")) {
             doSPFCheck(session);
         } else if (session.getCommandName().equals("RCPT")) {
-            doProcessing(session);
+            return doProcessing(session);
         }
+        return null;
     }
 
     /**
Index: java/org/apache/james/smtpserver/core/filter/fastfail/SupressDuplicateRcptHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/SupressDuplicateRcptHandler.java	(revision 476504)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/SupressDuplicateRcptHandler.java	(working copy)
@@ -27,6 +27,7 @@
 
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.MailAddress;
@@ -50,7 +51,7 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
         MailAddress rcpt = (MailAddress) session.getState().get(SMTPSession.CURRENT_RECIPIENT);
         Collection rcptList = (Collection) session.getState().get(SMTPSession.RCPT_LIST);
     
@@ -58,12 +59,13 @@
         if(rcptList != null && rcptList.contains(rcpt)) {
             StringBuffer responseBuffer = new StringBuffer();
         
-            responseBuffer.append("250 " + DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.ADDRESS_VALID) + " Recipient <")
-                          .append(rcpt.toString()).append("> OK");
-            session.writeResponse(responseBuffer.toString());
-            session.setStopHandlerProcessing(true);
-            
+            responseBuffer.append(DSNStatus.getStatus(DSNStatus.SUCCESS, DSNStatus.ADDRESS_VALID))
+                          .append(" Recipient <")
+                          .append(rcpt.toString())
+                          .append("> OK");
             getLogger().debug("Duplicate recipient not add to recipient list: " + rcpt.toString());
+            return new SMTPResponse("250", responseBuffer);
         }
+        return null;
     }
 }
Index: java/org/apache/james/smtpserver/core/filter/fastfail/TarpitHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/TarpitHandler.java	(revision 476504)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/TarpitHandler.java	(working copy)
@@ -29,6 +29,7 @@
 import org.apache.avalon.framework.configuration.ConfigurationException;
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 
 public class TarpitHandler extends AbstractLogEnabled implements
@@ -99,7 +100,7 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
 
         int rcptCount = 0;
         rcptCount = session.getRcptCount();
@@ -111,6 +112,8 @@
             } catch (InterruptedException e) {
             }
         }
+        
+        return null;
     }
     
     /**
Index: java/org/apache/james/smtpserver/core/filter/fastfail/ValidRcptHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/ValidRcptHandler.java	(revision 476504)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/ValidRcptHandler.java	(working copy)
@@ -37,6 +37,7 @@
 import org.apache.james.services.VirtualUserTable;
 import org.apache.james.services.VirtualUserTableStore;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.james.vut.ErrorMappingException;
@@ -172,11 +173,12 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
         if (!session.isRelayingAllowed() && !(session.isAuthRequired() && session.getUser() != null)) {
-            checkValidRcpt(session);
+            return checkValidRcpt(session);
         } else {
             getLogger().debug("Sender allowed");
+            return null;
         }
     }
     
@@ -186,8 +188,9 @@
      * Check if the recipient should be accepted
      * 
      * @param session The SMTPSession
+     * @return 
      */
-    private void checkValidRcpt(SMTPSession session) {
+    private SMTPResponse checkValidRcpt(SMTPSession session) {
         MailAddress rcpt = (MailAddress) session.getState().get(SMTPSession.CURRENT_RECIPIENT);
         boolean invalidUser = true;
 
@@ -209,8 +212,7 @@
                 
                 getLogger().info("Rejected message. Reject Message: " + responseString);
             
-                session.writeResponse(responseString);
-                session.setStopHandlerProcessing(true);
+                return new SMTPResponse(responseString);
             }
         }
         
@@ -229,12 +231,9 @@
     
         if (invalidUser == true) {
             //user not exist
-            String responseString = "554 " + DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_MAILBOX) + " Unknown user: " + rcpt.toString();
-        
             getLogger().info("Rejected message. Unknown user: " + rcpt.toString());
-        
-            session.writeResponse(responseString);
-            session.setStopHandlerProcessing(true);
+            return new SMTPResponse("554", DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_MAILBOX) + " Unknown user: " + rcpt.toString());
         }
+        return null;
     }
 }
Index: java/org/apache/james/smtpserver/core/filter/fastfail/ValidRcptMX.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/ValidRcptMX.java	(revision 487826)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/ValidRcptMX.java	(working copy)
@@ -33,6 +33,7 @@
 import org.apache.james.dnsserver.TemporaryResolutionException;
 import org.apache.james.services.DNSServer;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.NetMatcher;
 import org.apache.james.util.mail.dsn.DSNStatus;
@@ -116,8 +117,8 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doProcessing(session);
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return doProcessing(session);
     }
 
     /**
Index: java/org/apache/james/smtpserver/core/filter/fastfail/ValidSenderDomainHandler.java
===================================================================
--- java/org/apache/james/smtpserver/core/filter/fastfail/ValidSenderDomainHandler.java	(revision 487826)
+++ java/org/apache/james/smtpserver/core/filter/fastfail/ValidSenderDomainHandler.java	(working copy)
@@ -16,9 +16,6 @@
  * specific language governing permissions and limitations      *
  * under the License.                                           *
  ****************************************************************/
-
-
-
 package org.apache.james.smtpserver.core.filter.fastfail;
 
 import java.util.ArrayList;
@@ -33,6 +30,7 @@
 import org.apache.james.dnsserver.TemporaryResolutionException;
 import org.apache.james.services.DNSServer;
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.SMTPResponse;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.MailAddress;
@@ -87,8 +85,8 @@
     /**
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doProcessing(session);
+    public SMTPResponse onCommand(SMTPSession session, String command, String parameters) {
+        return doProcessing(session);
     }
     
     /**
Index: java/org/apache/james/smtpserver/LineHandler.java
===================================================================
--- java/org/apache/james/smtpserver/LineHandler.java	
+++ java/org/apache/james/smtpserver/LineHandler.java	
@@ -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);
+    
+}
Index: java/org/apache/james/smtpserver/SMTPResponse.java
===================================================================
--- java/org/apache/james/smtpserver/SMTPResponse.java	
+++ java/org/apache/james/smtpserver/SMTPResponse.java	
@@ -0,0 +1,91 @@
+/****************************************************************
+ * 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.LinkedList;
+import java.util.List;
+
+/**
+ * Contains an SMTP result
+ */
+public class SMTPResponse {
+
+    private String retCode = null;
+    private List lines = null;
+    private String rawLine = null;
+    private boolean endSession = false;
+    
+    public SMTPResponse() {
+        
+    }
+    
+    public SMTPResponse(String code, String description) {
+        this.setRetCode(code);
+        this.appendLine(description);
+    }
+    
+    public SMTPResponse(String code, StringBuffer description) {
+        this.setRetCode(code);
+        this.appendLine(description);
+    }
+    
+    public SMTPResponse(String rawLine) {
+        this.rawLine = rawLine;
+    }
+    
+    public void appendLine(String line) {
+        if (lines == null) {
+            lines = new LinkedList();
+        }
+        lines.add(line);
+    }
+    
+    public void appendLine(StringBuffer line) {
+        if (lines == null) {
+            lines = new LinkedList();
+        }
+        lines.add(line);
+    }
+
+    public String getRetCode() {
+        return retCode;
+    }
+
+    public void setRetCode(String retCode) {
+        this.retCode = retCode;
+    }
+
+    public List getLines() {
+        return lines;
+    }
+
+    public String getRawLine() {
+        return rawLine;
+    }
+
+    public boolean isEndSession() {
+        return endSession;
+    }
+
+    public void setEndSession(boolean endSession) {
+        this.endSession = endSession;
+    }
+
+}
Index: java/org/apache/james/util/mail/SMTPRetCode.java
===================================================================
--- java/org/apache/james/util/mail/SMTPRetCode.java	
+++ java/org/apache/james/util/mail/SMTPRetCode.java	
@@ -0,0 +1,106 @@
+/****************************************************************
+ * 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.mail;
+
+/**
+ * Result code defined in RFC 2821
+ */
+public class SMTPRetCode {
+    // System status, or system help reply
+    public static final String SYSTEM_STATUS = "211";
+
+    // Help message
+    // (Information on how to use the receiver or the meaning of a
+    // particular non-standard command; this reply is useful only
+    // to the human user)
+    public static final String HELP_MESSAGE = "214";
+
+    // <domain> Service ready
+    public static final String SERVICE_READY = "220";
+
+    // <domain> Service closing transmission channel
+    public static final String SYSTEM_QUIT = "221";
+
+    // Requested mail action okay, completed
+    public static final String MAIL_OK = "250";
+
+    // 251 User not local; will forward to <forward-path>
+    // (See section 3.4)
+    public static final String MAIL_FORWARDING = "251";
+
+    // Cannot VRFY user, but will accept message and attempt
+    // delivery
+    // (See section 3.5.3)
+    public static final String MAIL_UNDEFINDED = "252";
+
+    // Start mail input; end with <CRLF>.<CRLF>
+    public static final String DATA_READY = "354";
+
+    // <domain> Service not available, closing transmission channel
+    // (This may be a reply to any command if the service knows it
+    // must shut down)
+    public static final String SERVICE_NOT_AVAILABLE = "421";
+
+    // Requested mail action not taken: mailbox unavailable
+    // (e.g., mailbox busy)
+    public static final String MAILBOX_TEMP_UNAVAILABLE = "450";
+
+    // Requested action aborted: local error in processing
+    public static final String LOCAL_ERROR = "451";
+
+    // Requested action not taken: insufficient system storage
+    public static final String SYSTEM_STORAGE_ERROR = "452";
+
+    // Syntax error, command unrecognized
+    // (This may include errors such as command line too long)
+    public static final String SYNTAX_ERROR_COMMAND_UNRECOGNIZED = "500";
+
+    // Syntax error in parameters or arguments
+    public static final String SYNTAX_ERROR_ARGUMENTS = "501";
+
+    // Command not implemented (see section 4.2.4)
+    public static final String UNIMPLEMENTED_COMMAND = "502";
+
+    // Bad sequence of commands
+    public static final String BAD_SEQUENCE = "503";
+
+    // Command parameter not implemented
+    public static final String PARAMETER_NOT_IMPLEMENTED = "504";
+
+    // Requested action not taken: mailbox unavailable
+    // (e.g., mailbox not found, no access, or command rejected
+    // for policy reasons)
+    public static final String MAILBOX_PERM_UNAVAILABLE = "550";
+
+    // User not local; please try <forward-path> (See section 3.4)
+    public static final String USER_NOT_LOCAL = "551";
+
+    // Requested mail action aborted: exceeded storage allocation
+    public static final String QUOTA_EXCEEDED = "552";
+
+    // Requested action not taken: mailbox name not allowed
+    // (e.g., mailbox syntax incorrect)
+    public static final String SYNTAX_ERROR_MAILBOX = "553";
+
+    // Transaction failed (Or, in the case of a connection-opening
+    // response, "No SMTP service here")
+    public static final String TRANSACTION_FAILED = "554";
+
+}
Index: java/org/apache/james/util/CRLFDelimitedByteBuffer.java
===================================================================
--- java/org/apache/james/util/CRLFDelimitedByteBuffer.java	
+++ java/org/apache/james/util/CRLFDelimitedByteBuffer.java	
@@ -0,0 +1,315 @@
+/****************************************************************
+ * 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;
+
+/*
+ * 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);
+		}
+	}
+
+	public CRLFDelimitedByteBuffer() {
+		this(2048);
+	}
+
+	public CRLFDelimitedByteBuffer(int maxLineLength) {
+		lines = new java.util.ArrayList();
+		workLine = new byte[maxLineLength];
+	}
+
+	synchronized public boolean isEmpty() {
+		return lines.isEmpty();
+	}
+
+	synchronized public byte[] read() throws LineLengthExceededException, TerminationException {
+		return lines.isEmpty() ? null : ((Line) lines.remove(0)).getBytes();
+	}
+
+	synchronized public String readString() throws LineLengthExceededException, TerminationException {
+		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.");
+			}
+		}
+	}
+	*/
+}
Index: test/org/apache/james/smtpserver/AbstractSMTPSession.java
===================================================================
--- test/org/apache/james/smtpserver/AbstractSMTPSession.java	(revision 475939)
+++ test/org/apache/james/smtpserver/AbstractSMTPSession.java	(working copy)
@@ -242,4 +242,12 @@
         throw new UnsupportedOperationException("Unimplemented Stub Method");
     }
 
+    public void popLineHandler() {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+
+    public void pushLineHandler(LineHandler overrideCommandHandler) {
+        throw new UnsupportedOperationException("Unimplemented Stub Method");
+    }
+
 }
Index: test/org/apache/james/smtpserver/SMTPServerTest.java
===================================================================
--- test/org/apache/james/smtpserver/SMTPServerTest.java	(revision 475939)
+++ test/org/apache/james/smtpserver/SMTPServerTest.java	(working copy)
@@ -1003,6 +1003,8 @@
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
+        wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100\r\n");
+        // add a CRLF in the middle, to be sure we don't use more than 1000 bytes by RFC.
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
@@ -1008,8 +1010,7 @@
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
         wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
-        wr.write("1234567810123456782012345678301234567840123456785012345678601234567870123456788012345678901234567100");
-        wr.write("1234567810123456782012\r\n"); // 1022 + CRLF = 1024
+        wr.write("12345678101234567820\r\n"); // 500 + CRLF + 520 + CRLF = 1024
         wr.close();
         
         assertTrue(smtpProtocol.completePendingCommand());
