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/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,47 @@
         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);
+                    ((CommandHandler)commandHandlers.get(i)).onCommand(this);
+                    
+                    //if the response is received, stop processing of command handlers
+                    if(mode != COMMAND_MODE || getStopHandlerProcessing()) {
+                        break;
+                    }
+                }
+
+            }        
+        } catch (UnsupportedEncodingException e) {
+            // TODO Define what to do
+            e.printStackTrace();
+        }
+    }
+    
     /**
      * Resets the handler data to a basic state.
      */
@@ -325,15 +342,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 +429,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 +529,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 +550,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 +579,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,16 @@
      */
     Map getConnectionState();
 
+    /**
+     * Put a new line handler in the chain
+     * @param overrideCommandHandler
+     */
+    void pushLineHandler(LineHandler overrideCommandHandler);
+    
+    /**
+     * Pop the last command handler 
+     */
+    void popLineHandler();
+
 }
 
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,7 @@
 package org.apache.james.smtpserver.core;
 
 import org.apache.james.smtpserver.CommandHandler;
+import org.apache.james.smtpserver.LineHandler;
 import org.apache.james.smtpserver.SMTPSession;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
@@ -31,7 +32,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 +51,7 @@
      * The text string for the SMTP AUTH type LOGIN.
      */
     private final static String AUTH_TYPE_LOGIN = "LOGIN";
-
+    
     /**
      * handles AUTH command
      *
@@ -57,14 +58,7 @@
      * @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();
-        }
+        doAUTH(session, session.getCommandArgument());
     }
 
 
@@ -76,8 +70,7 @@
      * @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 {
+    private void doAUTH(SMTPSession session, String argument) {
         String responseString = null;
         if (session.getUser() != null) {
             responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" User has previously authenticated. "
@@ -94,10 +87,48 @@
             }
             String authType = argument.toUpperCase(Locale.US);
             if (authType.equals(AUTH_TYPE_PLAIN)) {
-                doPlainAuth(session, initialResponse);
+                String userpass;
+                if (initialResponse == null) {
+                    responseString = "334 OK. Continue authentication";
+                    session.pushLineHandler(new LineHandler() {
+
+                        public void onLine(SMTPSession session, byte[] line) {
+                            try {
+                                doPlainAuthPass(session, new String(line, "US-ASCII"));
+                            } catch (UnsupportedEncodingException e) {
+                                // TODO should never happen
+                                e.printStackTrace();
+                            }
+                        }
+                        
+                    });
+                    session.writeResponse(responseString);
+                } else {
+                    userpass = initialResponse.trim();
+                    doPlainAuthPass(session, userpass);
+                }
                 return;
             } else if (authType.equals(AUTH_TYPE_LOGIN)) {
-                doLoginAuth(session, initialResponse);
+                
+                if (initialResponse == null) {
+                    responseString = "334 VXNlcm5hbWU6"; // base64 encoded "Username:"
+                    session.pushLineHandler(new LineHandler() {
+
+                        public void onLine(SMTPSession session, byte[] line) {
+                            try {
+                                doLoginAuthPass(session, new String(line, "US-ASCII"), true);
+                            } catch (UnsupportedEncodingException e) {
+                                // TODO should never happen
+                                e.printStackTrace();
+                            }
+                        }
+                        
+                    });
+                    session.writeResponse(responseString);
+                } else {
+                    String user = initialResponse.trim();
+                    doLoginAuthPass(session, user, false);
+                }
                 return;
             } else {
                 doUnknownAuth(session, authType, initialResponse);
@@ -120,16 +151,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 void doPlainAuthPass(SMTPSession session, String userpass) {
+        String user = null, pass = null, responseString = null;
         try {
             if (userpass != null) {
                 userpass = Base64.decodeAsString(userpass);
@@ -182,6 +205,7 @@
             // 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";
@@ -205,16 +229,8 @@
      * @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 void doLoginAuthPass(SMTPSession session, String user, boolean inCustomeHandler) {
+        String responseString = null;
         if (user != null) {
             try {
                 user = Base64.decodeAsString(user);
@@ -225,8 +241,33 @@
             }
         }
         responseString = "334 UGFzc3dvcmQ6"; // base64 encoded "Password:"
+        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));
         session.writeResponse(responseString);
-        pass = session.readCommandLine();
+    }
+    
+    private void doLoginAuthPassCheck(SMTPSession session, String user, String pass) {
+        String responseString = null;
         if (pass != null) {
             try {
                 pass = Base64.decodeAsString(pass);
@@ -251,6 +292,8 @@
             // TODO: Make this string a more useful error message
             getLogger().error("AUTH method LOGIN failed");
         }
+        session.popLineHandler();
+        session.popLineHandler();
         session.writeResponse(responseString);
         return;
     }
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,6 +27,7 @@
 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.SMTPSession;
 import org.apache.james.smtpserver.SizeLimitedInputStream;
@@ -33,7 +34,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 +43,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;
@@ -103,15 +106,84 @@
      * @param argument the argument passed in with the command by the SMTP client
      */
     private void doDATA(SMTPSession session, String argument) {
-
         String responseString = null;
         responseString = "354 Ok Send data ending with <CRLF>.<CRLF>";
+        
+        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();
+                    }
+                }
+
+                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();
+        }
+        
         session.writeResponse(responseString);
-        InputStream msgIn = new CharTerminatedInputStream(session
-                .getInputStream(), SMTPTerminator);
+        
+    }
+    
+
+    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 +240,7 @@
                 getLogger().error(
                         "Unknown error occurred while processing DATA.", me);
             }
+            session.popLineHandler();
             session.writeResponse(responseString);
             return;
         } finally {
@@ -311,6 +384,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 +431,5 @@
         return implCommands;
     }
 
+
 }
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)
@@ -149,19 +149,65 @@
             }
 
             
-
-            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)) {
+                            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);
+                            
+                            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;
+                            }
+                        }
+                    }
+                } else {
                     String toDomain = recipientAddress.getHost();
                     if (!session.getConfigurationData().getMailServer().isLocalServer(toDomain)) {
-                        responseString = "530 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Authentication Required";
+                        responseString = "550 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Requested action not taken: relaying denied";
                         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());
+                        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);
@@ -168,51 +214,6 @@
                         
                         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;
-                        }
-                    }
-                }
-            } 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) {
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/userrepository/AbstractUsersRepository.java
===================================================================
--- java/org/apache/james/userrepository/AbstractUsersRepository.java	(revision 468922)
+++ java/org/apache/james/userrepository/AbstractUsersRepository.java	(working copy)
@@ -126,7 +126,15 @@
             return false;
         }
 
-        doAddUser(user);
+        try {
+            doAddUser(user);
+        } catch (RuntimeException e) {
+            // runtime exception to be logged.
+            // As an example the doAddUser could throw CascadingRuntimeException with the
+            // following nested cause:
+            // com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Duplicate entry 'USERNAME' for key 1
+            return false;
+        }
         return true;
     }
 
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());
