You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ba...@apache.org on 2006/05/08 23:58:27 UTC

svn commit: r405184 [1/2] - /james/server/trunk/src/java/org/apache/james/pop3server/

Author: bago
Date: Mon May  8 14:58:26 2006
New Revision: 405184

URL: http://svn.apache.org/viewcvs?rev=405184&view=rev
Log:
Refactored POP3Handler to follow the same pattern of the SMTPHandler (JAMES-487)
Currently POP3Handler uses its own POP3Session, its own POP3HandlerChain and its own CommandHandler and ConnectHandler interfaces: we'll create common interfaces later.

Added:
    james/server/trunk/src/java/org/apache/james/pop3server/CommandHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/ConnectHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/DeleCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/ListCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/NoopCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/POP3HandlerChain.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/POP3Session.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/PassCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/QuitCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/RetrCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/RsetCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/StatCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/TopCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/UidlCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/UnknownCmdHandler.java   (with props)
    james/server/trunk/src/java/org/apache/james/pop3server/UserCmdHandler.java   (with props)
Modified:
    james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java
    james/server/trunk/src/java/org/apache/james/pop3server/POP3Server.java

Added: james/server/trunk/src/java/org/apache/james/pop3server/CommandHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/CommandHandler.java?rev=405184&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/CommandHandler.java (added)
+++ james/server/trunk/src/java/org/apache/james/pop3server/CommandHandler.java Mon May  8 14:58:26 2006
@@ -0,0 +1,32 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.pop3server;
+
+/**
+ * Custom command handlers must implement this interface
+ * The command handlers will be Server wide common to all the POP3Handlers,
+ * therefore the command handlers must store all the state information
+ * in the POP3Session object
+ */
+ public interface CommandHandler {
+    /*
+     * Handle the command
+    **/
+    void onCommand(POP3Session session);
+
+}

Propchange: james/server/trunk/src/java/org/apache/james/pop3server/CommandHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: james/server/trunk/src/java/org/apache/james/pop3server/ConnectHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/ConnectHandler.java?rev=405184&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/ConnectHandler.java (added)
+++ james/server/trunk/src/java/org/apache/james/pop3server/ConnectHandler.java Mon May  8 14:58:26 2006
@@ -0,0 +1,32 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.pop3server;
+
+/**
+ * Custom connect handlers must implement this interface
+ * The connect handlers will be server-wide common to all the POP3Handlers,
+ * therefore the handlers must store all the state information
+ * in the POP3Session object
+ */
+public interface ConnectHandler {
+    /*
+     * Handle connection
+    **/
+    void onConnect(POP3Session session);
+
+}

Propchange: james/server/trunk/src/java/org/apache/james/pop3server/ConnectHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: james/server/trunk/src/java/org/apache/james/pop3server/DeleCmdHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/DeleCmdHandler.java?rev=405184&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/DeleCmdHandler.java (added)
+++ james/server/trunk/src/java/org/apache/james/pop3server/DeleCmdHandler.java Mon May  8 14:58:26 2006
@@ -0,0 +1,85 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.pop3server;
+
+import org.apache.mailet.Mail;
+
+/**
+  * Handles DELE command
+  */
+public class DeleCmdHandler implements CommandHandler {
+
+    /**
+     * @see org.apache.james.pop3server.CommandHandler#onCommand(POP3Session)
+     */
+    public void onCommand(POP3Session session) {
+        doDELE(session,session.getCommandArgument());
+    }
+
+    /**
+     * Handler method called upon receipt of a DELE command.
+     * This command deletes a particular mail message from the
+     * mailbox.
+     *
+     * @param command the command parsed by the parseCommand method
+     * @param argument the first argument parsed by the parseCommand method
+     */
+    private void doDELE(POP3Session session,String argument) {
+        String responseString = null;
+        if (session.getHandlerState() == POP3Handler.TRANSACTION) {
+            int num = 0;
+            try {
+                num = Integer.parseInt(argument);
+            } catch (Exception e) {
+                responseString = POP3Handler.ERR_RESPONSE + " Usage: DELE [mail number]";
+                session.writeResponse(responseString);
+                return;
+            }
+            try {
+                Mail mc = (Mail) session.getUserMailbox().get(num);
+                if (mc == POP3Handler.DELETED) {
+                    StringBuffer responseBuffer =
+                        new StringBuffer(64)
+                                .append(POP3Handler.ERR_RESPONSE)
+                                .append(" Message (")
+                                .append(num)
+                                .append(") already deleted.");
+                    responseString = responseBuffer.toString();
+                    session.writeResponse(responseString);
+                } else {
+                    session.getUserMailbox().set(num, POP3Handler.DELETED);
+                    session.writeResponse(POP3Handler.OK_RESPONSE + " Message deleted");
+                }
+            } catch (IndexOutOfBoundsException iob) {
+                StringBuffer responseBuffer =
+                    new StringBuffer(64)
+                            .append(POP3Handler.ERR_RESPONSE)
+                            .append(" Message (")
+                            .append(num)
+                            .append(") does not exist.");
+                responseString = responseBuffer.toString();
+                session.writeResponse(responseString);
+            }
+        } else {
+            responseString = POP3Handler.ERR_RESPONSE;
+            session.writeResponse(responseString);
+        }
+    }
+
+
+}

Propchange: james/server/trunk/src/java/org/apache/james/pop3server/DeleCmdHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: james/server/trunk/src/java/org/apache/james/pop3server/ListCmdHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/ListCmdHandler.java?rev=405184&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/ListCmdHandler.java (added)
+++ james/server/trunk/src/java/org/apache/james/pop3server/ListCmdHandler.java Mon May  8 14:58:26 2006
@@ -0,0 +1,143 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.pop3server;
+
+import org.apache.mailet.Mail;
+
+import javax.mail.MessagingException;
+
+import java.util.Iterator;
+
+/**
+  * Handles LIST command
+  */
+public class ListCmdHandler implements CommandHandler {
+
+    /**
+     * @see org.apache.james.pop3server.CommandHandler#onCommand(POP3Session)
+     */
+    public void onCommand(POP3Session session) {
+        doLIST(session,session.getCommandArgument());
+    }
+
+    /**
+     * Handler method called upon receipt of a LIST command.
+     * Returns the number of messages in the mailbox and its
+     * aggregate size, or optionally, the number and size of
+     * a single message.
+     *
+     * @param command the command parsed by the parseCommand method
+     * @param argument the first argument parsed by the parseCommand method
+     */
+    private void doLIST(POP3Session session,String argument) {
+        String responseString = null;
+        if (session.getHandlerState() == POP3Handler.TRANSACTION) {
+            if (argument == null) {
+                long size = 0;
+                int count = 0;
+                try {
+                    for (Iterator i = session.getUserMailbox().iterator(); i.hasNext(); ) {
+                        Mail mc = (Mail) i.next();
+                        if (mc != POP3Handler.DELETED) {
+                            size += mc.getMessageSize();
+                            count++;
+                        }
+                    }
+                    StringBuffer responseBuffer =
+                        new StringBuffer(32)
+                                .append(POP3Handler.OK_RESPONSE)
+                                .append(" ")
+                                .append(count)
+                                .append(" ")
+                                .append(size);
+                    responseString = responseBuffer.toString();
+                    session.writeResponse(responseString);
+                    count = 0;
+                    for (Iterator i = session.getUserMailbox().iterator(); i.hasNext(); count++) {
+                        Mail mc = (Mail) i.next();
+
+                        if (mc != POP3Handler.DELETED) {
+                            responseBuffer =
+                                new StringBuffer(16)
+                                        .append(count)
+                                        .append(" ")
+                                        .append(mc.getMessageSize());
+                            session.writeResponse(responseBuffer.toString());
+                        }
+                    }
+                    session.writeResponse(".");
+                } catch (MessagingException me) {
+                    responseString = POP3Handler.ERR_RESPONSE;
+                    session.writeResponse(responseString);
+                }
+            } else {
+                int num = 0;
+                try {
+                    num = Integer.parseInt(argument);
+                    Mail mc = (Mail) session.getUserMailbox().get(num);
+                    if (mc != POP3Handler.DELETED) {
+                        StringBuffer responseBuffer =
+                            new StringBuffer(64)
+                                    .append(POP3Handler.OK_RESPONSE)
+                                    .append(" ")
+                                    .append(num)
+                                    .append(" ")
+                                    .append(mc.getMessageSize());
+                        responseString = responseBuffer.toString();
+                        session.writeResponse(responseString);
+                    } else {
+                        StringBuffer responseBuffer =
+                            new StringBuffer(64)
+                                    .append(POP3Handler.ERR_RESPONSE)
+                                    .append(" Message (")
+                                    .append(num)
+                                    .append(") already deleted.");
+                        responseString = responseBuffer.toString();
+                        session.writeResponse(responseString);
+                    }
+                } catch (IndexOutOfBoundsException npe) {
+                    StringBuffer responseBuffer =
+                        new StringBuffer(64)
+                                .append(POP3Handler.ERR_RESPONSE)
+                                .append(" Message (")
+                                .append(num)
+                                .append(") does not exist.");
+                    responseString = responseBuffer.toString();
+                    session.writeResponse(responseString);
+                } catch (NumberFormatException nfe) {
+                    StringBuffer responseBuffer =
+                        new StringBuffer(64)
+                                .append(POP3Handler.ERR_RESPONSE)
+                                .append(" ")
+                                .append(argument)
+                                .append(" is not a valid number");
+                    responseString = responseBuffer.toString();
+                    session.writeResponse(responseString);
+                } catch (MessagingException me) {
+                    responseString = POP3Handler.ERR_RESPONSE;
+                    session.writeResponse(responseString);
+               }
+            }
+        } else {
+            responseString = POP3Handler.ERR_RESPONSE;
+            session.writeResponse(responseString);
+        }
+    }
+
+
+}

Propchange: james/server/trunk/src/java/org/apache/james/pop3server/ListCmdHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: james/server/trunk/src/java/org/apache/james/pop3server/NoopCmdHandler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/NoopCmdHandler.java?rev=405184&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/NoopCmdHandler.java (added)
+++ james/server/trunk/src/java/org/apache/james/pop3server/NoopCmdHandler.java Mon May  8 14:58:26 2006
@@ -0,0 +1,51 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.pop3server;
+
+/**
+  * Handles NOOP command
+  */
+public class NoopCmdHandler implements CommandHandler {
+
+    /**
+     * @see org.apache.james.pop3server.CommandHandler#onCommand(POP3Session)
+     */
+    public void onCommand(POP3Session session) {
+        doNOOP(session,session.getCommandArgument());
+    }
+
+    /**
+     * Handler method called upon receipt of a NOOP command.
+     * Like all good NOOPs, does nothing much.
+     *
+     * @param command the command parsed by the parseCommand method
+     * @param argument the first argument parsed by the parseCommand method
+     */
+    private void doNOOP(POP3Session session,String argument) {
+        String responseString = null;
+        if (session.getHandlerState() == POP3Handler.TRANSACTION) {
+            responseString = POP3Handler.OK_RESPONSE;
+            session.writeResponse(responseString);
+        } else {
+            responseString = POP3Handler.ERR_RESPONSE;
+            session.writeResponse(responseString);
+        }
+    }
+
+
+}

Propchange: james/server/trunk/src/java/org/apache/james/pop3server/NoopCmdHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java?rev=405184&r1=405183&r2=405184&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java (original)
+++ james/server/trunk/src/java/org/apache/james/pop3server/POP3Handler.java Mon May  8 14:58:26 2006
@@ -17,63 +17,60 @@
 
 package org.apache.james.pop3server;
 
-import org.apache.commons.collections.ListUtils;
 import org.apache.james.Constants;
 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.ExtraDotOutputStream;
-import org.apache.james.util.watchdog.BytesWrittenResetOutputStream;
+import org.apache.james.util.watchdog.Watchdog;
 import org.apache.mailet.Mail;
 
 import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.util.ArrayList;
-import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-import java.util.StringTokenizer;
 
 /**
  * The handler class for POP3 connections.
  *
  */
 public class POP3Handler
-    extends AbstractJamesHandler {
+    extends AbstractJamesHandler implements POP3Session {
+
+    private final static byte COMMAND_MODE = 1;
+    private final static byte RESPONSE_MODE = 2;
 
     // POP3 Server identification string used in POP3 headers
     private static final String softwaretype        = "JAMES POP3 Server "
                                                         + Constants.SOFTWARE_VERSION;
 
     // POP3 response prefixes
-    private final static String OK_RESPONSE = "+OK";    // OK response.  Requested content
+    final static String OK_RESPONSE = "+OK";    // OK response.  Requested content
                                                         // will follow
 
-    private final static String ERR_RESPONSE = "-ERR";  // Error response.  Requested content
+    final static String ERR_RESPONSE = "-ERR";  // Error response.  Requested content
                                                         // will not be provided.  This prefix
                                                         // is followed by a more detailed
                                                         // error message
 
     // Authentication states for the POP3 interaction
 
-    private final static int AUTHENTICATION_READY = 0;    // Waiting for user id
+    final static int AUTHENTICATION_READY = 0;    // Waiting for user id
 
-    private final static int AUTHENTICATION_USERSET = 1;  // User id provided, waiting for
+    final static int AUTHENTICATION_USERSET = 1;  // User id provided, waiting for
                                                           // password
 
-    private final static int TRANSACTION = 2;             // A valid user id/password combination
+    final static int TRANSACTION = 2;             // A valid user id/password combination
                                                           // has been provided.  In this state
                                                           // the client can access the mailbox
                                                           // of the specified user
 
-    private static final Mail DELETED = new MailImpl();   // A placeholder for emails deleted
+    static final Mail DELETED = new MailImpl();   // A placeholder for emails deleted
                                                           // during the course of the POP3
                                                           // transaction.  This Mail instance
                                                           // is used to enable fast checks as
@@ -93,12 +90,7 @@
     /**
      * The current transaction state of the handler
      */
-    private int state;
-
-    /**
-     * The user id associated with the POP3 dialogue
-     */
-    private String user;
+    private int handlerState;
 
     /**
      * A dynamic list representing the set of
@@ -112,6 +104,53 @@
                                                  // of the transaction
 
     /**
+     * The per-handler response buffer used to marshal responses.
+     */
+    private StringBuffer responseBuffer = new StringBuffer(256);
+
+
+    /**
+     * The name of the currently parsed command
+     */
+    String curCommandName =  null;
+
+    /**
+     * The value of the currently parsed command
+     */
+    String curCommandArgument =  null;
+
+    /**
+     * The POP3HandlerChain object set by POP3Server
+     */
+    POP3HandlerChain handlerChain = null;
+
+    /**
+     * The session termination status
+     */
+    private boolean sessionEnded = false;
+
+
+    /**
+     * The hash map that holds variables for the POP3 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 user name of the authenticated user associated with this POP3 transaction.
+     */
+    private String authenticatedUser;
+
+    /**
+     * The mode of the current session
+     */
+    private byte mode;
+    
+    
+    /**
      * Set the configuration data for the handler.
      *
      * @param theData the configuration data
@@ -128,29 +167,89 @@
      * @see org.apache.james.core.AbstractJamesHandler#handleProtocol()
      */
     protected void handleProtocol() throws IOException {
-        state = AUTHENTICATION_READY;
-        user = "unknown";
-        StringBuffer responseBuffer =
-            new StringBuffer(256)
-                    .append(OK_RESPONSE)
+        handlerState = AUTHENTICATION_READY;
+        authenticatedUser = "unknown";
+        
+        resetState();
+
+        // Initially greet the connector
+        // Format is:  Sat, 24 Jan 1998 13:16:09 -0500
+        responseBuffer.append(OK_RESPONSE)
                     .append(" ")
                     .append(theConfigData.getHelloName())
                     .append(" POP3 server (")
                     .append(POP3Handler.softwaretype)
                     .append(") ready ");
-        out.println(responseBuffer.toString());
-        out.flush();
+        String responseString = clearResponseBuffer();
+        writeLoggedFlushedResponse(responseString);
+
+        //Session started - RUN all connect handlers
+        List connectHandlers = handlerChain.getConnectHandlers();
+        if(connectHandlers != null) {
+            int count = connectHandlers.size();
+            for(int i = 0; i < count; i++) {
+                ((ConnectHandler)connectHandlers.get(i)).onConnect(this);
+                if(sessionEnded) {
+                    break;
+                }
+            }
+        }
 
+        
         theWatchdog.start();
-        while (parseCommand(readCommandLine())) {
-            theWatchdog.reset();
+        while(!sessionEnded) {
+          //Reset the current command values
+          curCommandName = null;
+          curCommandArgument = null;
+          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;
+          }
+          curCommandName = curCommandName.toUpperCase(Locale.US);
+
+          if (getLogger().isDebugEnabled()) {
+              // Don't display password in logger
+              if (!curCommandName.equals("PASS")) {
+                  getLogger().debug("Command received: " + cmdString);
+              } else {
+                  getLogger().debug("Command received: PASS <password omitted>");
+              }
+          }
+
+          //fetch the command handlers registered to the command
+          List commandHandlers = handlerChain.getCommandHandlers(curCommandName);
+          if(commandHandlers == null) {
+              //end the session
+              break;
+          } else {
+              int count = commandHandlers.size();
+              for(int i = 0; i < count; i++) {
+                  ((CommandHandler)commandHandlers.get(i)).onCommand(this);
+                  theWatchdog.reset();
+                  //if the response is received, stop processing of command handlers
+                  if(mode != COMMAND_MODE) {
+                      break;
+                  }
+              }
+
+          }
         }
         theWatchdog.stop();
         if (getLogger().isInfoEnabled()) {
             StringBuffer logBuffer =
                 new StringBuffer(128)
                     .append("Connection for ")
-                    .append(user)
+                    .append(getUser())
                     .append(" from ")
                     .append(remoteHost)
                     .append(" (")
@@ -178,7 +277,7 @@
      */
     protected void resetHandler() {
         // Clear user data
-        user = null;
+        authenticatedUser = null;
         userInbox = null;
         if (userMailbox != null) {
             userMailbox.clear();
@@ -203,7 +302,7 @@
      * user inbox.
      *
      */
-    private void stat() {
+    public void stat() {
         userMailbox = new ArrayList();
         userMailbox.add(DELETED);
         try {
@@ -232,7 +331,7 @@
      * @return the trimmed input line
      * @throws IOException if an exception is generated reading in the input characters
      */
-    final String readCommandLine() throws IOException {
+    public final String readCommandLine() throws IOException {
         for (;;) try {
             String commandLine = inReader.readLine();
             if (commandLine != null) {
@@ -251,663 +350,182 @@
      * command specific handler methods.  The primary purpose of this method is
      * to parse the raw command string to determine exactly which handler should
      * be called.  It returns true if expecting additional commands, false otherwise.
-     *
-     * @param rawCommand the raw command string passed in over the socket
-     *
-     * @return whether additional commands are expected.
      */
-    private boolean parseCommand(String rawCommand) {
-        if (rawCommand == null) {
-            return false;
-        }
-        boolean returnValue = true;
-        String command = rawCommand;
-        StringTokenizer commandLine = new StringTokenizer(command, " ");
-        int arguments = commandLine.countTokens();
-        if (arguments == 0) {
-            return true;
-        } else if(arguments > 0) {
-            command = commandLine.nextToken().toUpperCase(Locale.US);
-        }
-        if (getLogger().isDebugEnabled()) {
-            // Don't display password in logger
-            if (!command.equals("PASS")) {
-                getLogger().debug("Command received: " + rawCommand);
-            } else {
-                getLogger().debug("Command received: PASS <password omitted>");
-            }
-        }
-        String argument = null;
-        if(arguments > 1) {
-            argument = commandLine.nextToken();
-        }
-        String argument1 = null;
-        if(arguments > 2) {
-            argument1 = commandLine.nextToken();
-        }
-
-        if (command.equals("USER")) {
-            doUSER(command,argument,argument1);
-        } else if (command.equals("PASS")) {
-            doPASS(command,argument,argument1);
-        } else if (command.equals("STAT")) {
-            doSTAT(command,argument,argument1);
-        } else if (command.equals("LIST")) {
-            doLIST(command,argument,argument1);
-        } else if (command.equals("UIDL")) {
-            doUIDL(command,argument,argument1);
-        } else if (command.equals("RSET")) {
-            doRSET(command,argument,argument1);
-        } else if (command.equals("DELE")) {
-            doDELE(command,argument,argument1);
-        } else if (command.equals("NOOP")) {
-            doNOOP(command,argument,argument1);
-        } else if (command.equals("RETR")) {
-            doRETR(command,argument,argument1);
-        } else if (command.equals("TOP")) {
-            doTOP(command,argument,argument1);
-        } else if (command.equals("QUIT")) {
-            returnValue = false;
-            doQUIT(command,argument,argument1);
-        } else {
-            doUnknownCmd(command,argument,argument1);
-        }
-        return returnValue;
+    
+    /**
+     * @see org.apache.james.pop3server.POP3Session#getRemoteHost()
+     */
+    public String getRemoteHost() {
+        return remoteHost;
     }
 
     /**
-     * Handler method called upon receipt of a USER command.
-     * Reads in the user id.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doUSER(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == AUTHENTICATION_READY && argument != null) {
-            user = argument;
-            state = AUTHENTICATION_USERSET;
-            responseString = OK_RESPONSE;
-        } else {
-            responseString = ERR_RESPONSE;
-        }
-        writeLoggedFlushedResponse(responseString);
+     * @see org.apache.james.pop3server.POP3Session#getRemoteIPAddress()
+     */
+    public String getRemoteIPAddress() {
+        return remoteIP;
     }
 
     /**
-     * Handler method called upon receipt of a PASS command.
-     * Reads in and validates the password.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doPASS(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == AUTHENTICATION_USERSET && argument != null) {
-            String passArg = argument;
-            if (theConfigData.getUsersRepository().test(user, passArg)) {
-                StringBuffer responseBuffer =
-                    new StringBuffer(64)
-                            .append(OK_RESPONSE)
-                            .append(" Welcome ")
-                            .append(user);
-                responseString = responseBuffer.toString();
-                state = TRANSACTION;
-                writeLoggedFlushedResponse(responseString);
-                userInbox = theConfigData.getMailServer().getUserInbox(user);
-                stat();
-            } else {
-                responseString = ERR_RESPONSE + " Authentication failed.";
-                state = AUTHENTICATION_READY;
-                writeLoggedFlushedResponse(responseString);
-            }
-        } else {
-            responseString = ERR_RESPONSE;
-            writeLoggedFlushedResponse(responseString);
-        }
+     * @see org.apache.james.pop3server.POP3Session#endSession()
+     */
+    public void endSession() {
+        sessionEnded = true;
     }
 
     /**
-     * Handler method called upon receipt of a STAT command.
-     * Returns the number of messages in the mailbox and its
-     * aggregate size.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doSTAT(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == TRANSACTION) {
-            long size = 0;
-            int count = 0;
-            try {
-                for (Iterator i = userMailbox.iterator(); i.hasNext(); ) {
-                    Mail mc = (Mail) i.next();
-                    if (mc != DELETED) {
-                        size += mc.getMessageSize();
-                        count++;
-                    }
-                }
-                StringBuffer responseBuffer =
-                    new StringBuffer(32)
-                            .append(OK_RESPONSE)
-                            .append(" ")
-                            .append(count)
-                            .append(" ")
-                            .append(size);
-                responseString = responseBuffer.toString();
-                writeLoggedFlushedResponse(responseString);
-            } catch (MessagingException me) {
-                responseString = ERR_RESPONSE;
-                writeLoggedFlushedResponse(responseString);
-            }
-        } else {
-            responseString = ERR_RESPONSE;
-            writeLoggedFlushedResponse(responseString);
-        }
+     * @see org.apache.james.pop3server.POP3Session#isSessionEnded()
+     */
+    public boolean isSessionEnded() {
+        return sessionEnded;
     }
 
     /**
-     * Handler method called upon receipt of a LIST command.
-     * Returns the number of messages in the mailbox and its
-     * aggregate size, or optionally, the number and size of
-     * a single message.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doLIST(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == TRANSACTION) {
-            if (argument == null) {
-                long size = 0;
-                int count = 0;
-                try {
-                    for (Iterator i = userMailbox.iterator(); i.hasNext(); ) {
-                        Mail mc = (Mail) i.next();
-                        if (mc != DELETED) {
-                            size += mc.getMessageSize();
-                            count++;
-                        }
-                    }
-                    StringBuffer responseBuffer =
-                        new StringBuffer(32)
-                                .append(OK_RESPONSE)
-                                .append(" ")
-                                .append(count)
-                                .append(" ")
-                                .append(size);
-                    responseString = responseBuffer.toString();
-                    writeLoggedFlushedResponse(responseString);
-                    count = 0;
-                    for (Iterator i = userMailbox.iterator(); i.hasNext(); count++) {
-                        Mail mc = (Mail) i.next();
-
-                        if (mc != DELETED) {
-                            responseBuffer =
-                                new StringBuffer(16)
-                                        .append(count)
-                                        .append(" ")
-                                        .append(mc.getMessageSize());
-                            out.println(responseBuffer.toString());
-                        }
-                    }
-                    out.println(".");
-                    out.flush();
-                } catch (MessagingException me) {
-                    responseString = ERR_RESPONSE;
-                    writeLoggedFlushedResponse(responseString);
-                }
-            } else {
-                int num = 0;
-                try {
-                    num = Integer.parseInt(argument);
-                    Mail mc = (Mail) userMailbox.get(num);
-                    if (mc != DELETED) {
-                        StringBuffer responseBuffer =
-                            new StringBuffer(64)
-                                    .append(OK_RESPONSE)
-                                    .append(" ")
-                                    .append(num)
-                                    .append(" ")
-                                    .append(mc.getMessageSize());
-                        responseString = responseBuffer.toString();
-                        writeLoggedFlushedResponse(responseString);
-                    } else {
-                        StringBuffer responseBuffer =
-                            new StringBuffer(64)
-                                    .append(ERR_RESPONSE)
-                                    .append(" Message (")
-                                    .append(num)
-                                    .append(") already deleted.");
-                        responseString = responseBuffer.toString();
-                        writeLoggedFlushedResponse(responseString);
-                    }
-                } catch (IndexOutOfBoundsException npe) {
-                    StringBuffer responseBuffer =
-                        new StringBuffer(64)
-                                .append(ERR_RESPONSE)
-                                .append(" Message (")
-                                .append(num)
-                                .append(") does not exist.");
-                    responseString = responseBuffer.toString();
-                    writeLoggedFlushedResponse(responseString);
-                } catch (NumberFormatException nfe) {
-                    StringBuffer responseBuffer =
-                        new StringBuffer(64)
-                                .append(ERR_RESPONSE)
-                                .append(" ")
-                                .append(argument)
-                                .append(" is not a valid number");
-                    responseString = responseBuffer.toString();
-                    writeLoggedFlushedResponse(responseString);
-                } catch (MessagingException me) {
-                    responseString = ERR_RESPONSE;
-                    writeLoggedFlushedResponse(responseString);
-               }
-            }
-        } else {
-            responseString = ERR_RESPONSE;
-            writeLoggedFlushedResponse(responseString);
-        }
+     * @see org.apache.james.pop3server.POP3Session#resetState()
+     */
+    public void resetState() {
+        state.clear();
     }
 
     /**
-     * Handler method called upon receipt of a UIDL command.
-     * Returns a listing of message ids to the client.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doUIDL(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == TRANSACTION) {
-            if (argument == null) {
-                responseString = OK_RESPONSE + " unique-id listing follows";
-                writeLoggedFlushedResponse(responseString);
-                int count = 0;
-                for (Iterator i = userMailbox.iterator(); i.hasNext(); count++) {
-                    Mail mc = (Mail) i.next();
-                    if (mc != DELETED) {
-                        StringBuffer responseBuffer =
-                            new StringBuffer(64)
-                                    .append(count)
-                                    .append(" ")
-                                    .append(mc.getName());
-                        out.println(responseBuffer.toString());
-                    }
-                }
-                out.println(".");
-                out.flush();
-            } else {
-                int num = 0;
-                try {
-                    num = Integer.parseInt(argument);
-                    Mail mc = (Mail) userMailbox.get(num);
-                    if (mc != DELETED) {
-                        StringBuffer responseBuffer =
-                            new StringBuffer(64)
-                                    .append(OK_RESPONSE)
-                                    .append(" ")
-                                    .append(num)
-                                    .append(" ")
-                                    .append(mc.getName());
-                        responseString = responseBuffer.toString();
-                        writeLoggedFlushedResponse(responseString);
-                    } else {
-                        StringBuffer responseBuffer =
-                            new StringBuffer(64)
-                                    .append(ERR_RESPONSE)
-                                    .append(" Message (")
-                                    .append(num)
-                                    .append(") already deleted.");
-                        responseString = responseBuffer.toString();
-                        writeLoggedFlushedResponse(responseString);
-                    }
-                } catch (IndexOutOfBoundsException npe) {
-                    StringBuffer responseBuffer =
-                        new StringBuffer(64)
-                                .append(ERR_RESPONSE)
-                                .append(" Message (")
-                                .append(num)
-                                .append(") does not exist.");
-                    responseString = responseBuffer.toString();
-                    writeLoggedFlushedResponse(responseString);
-                } catch (NumberFormatException nfe) {
-                    StringBuffer responseBuffer =
-                        new StringBuffer(64)
-                                .append(ERR_RESPONSE)
-                                .append(" ")
-                                .append(argument)
-                                .append(" is not a valid number");
-                    responseString = responseBuffer.toString();
-                    writeLoggedFlushedResponse(responseString);
-                }
-            }
-        } else {
-            writeLoggedFlushedResponse(ERR_RESPONSE);
-        }
+     * @see org.apache.james.pop3server.POP3Session#getState()
+     */
+    public HashMap getState() {
+        return state;
     }
 
     /**
-     * Handler method called upon receipt of a RSET command.
-     * Calls stat() to reset the mailbox.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doRSET(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == TRANSACTION) {
-            stat();
-            responseString = OK_RESPONSE;
-        } else {
-            responseString = ERR_RESPONSE;
-        }
-        writeLoggedFlushedResponse(responseString);
+     * @see org.apache.james.pop3server.POP3Session#getUser()
+     */
+    public String getUser() {
+        return authenticatedUser;
     }
 
     /**
-     * Handler method called upon receipt of a DELE command.
-     * This command deletes a particular mail message from the
-     * mailbox.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doDELE(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == TRANSACTION) {
-            int num = 0;
-            try {
-                num = Integer.parseInt(argument);
-            } catch (Exception e) {
-                responseString = ERR_RESPONSE + " Usage: DELE [mail number]";
-                writeLoggedFlushedResponse(responseString);
-                return;
-            }
-            try {
-                Mail mc = (Mail) userMailbox.get(num);
-                if (mc == DELETED) {
-                    StringBuffer responseBuffer =
-                        new StringBuffer(64)
-                                .append(ERR_RESPONSE)
-                                .append(" Message (")
-                                .append(num)
-                                .append(") already deleted.");
-                    responseString = responseBuffer.toString();
-                    writeLoggedFlushedResponse(responseString);
-                } else {
-                    userMailbox.set(num, DELETED);
-                    writeLoggedFlushedResponse(OK_RESPONSE + " Message deleted");
-                }
-            } catch (IndexOutOfBoundsException iob) {
-                StringBuffer responseBuffer =
-                    new StringBuffer(64)
-                            .append(ERR_RESPONSE)
-                            .append(" Message (")
-                            .append(num)
-                            .append(") does not exist.");
-                responseString = responseBuffer.toString();
-                writeLoggedFlushedResponse(responseString);
-            }
-        } else {
-            responseString = ERR_RESPONSE;
-            writeLoggedFlushedResponse(responseString);
-        }
+     * @see org.apache.james.pop3server.POP3Session#setUser(java.lang.String)
+     */
+    public void setUser(String userID) {
+        authenticatedUser = userID;
     }
 
     /**
-     * Handler method called upon receipt of a NOOP command.
-     * Like all good NOOPs, does nothing much.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doNOOP(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == TRANSACTION) {
-            responseString = OK_RESPONSE;
-            writeLoggedFlushedResponse(responseString);
-        } else {
-            responseString = ERR_RESPONSE;
-            writeLoggedFlushedResponse(responseString);
-        }
+     * @see org.apache.james.pop3server.POP3Session#getResponseBuffer()
+     */
+    public StringBuffer getResponseBuffer() {
+        return responseBuffer;
     }
 
     /**
-     * Handler method called upon receipt of a RETR command.
-     * This command retrieves a particular mail message from the
-     * mailbox.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doRETR(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == TRANSACTION) {
-            int num = 0;
-            try {
-                num = Integer.parseInt(argument.trim());
-            } catch (Exception e) {
-                responseString = ERR_RESPONSE + " Usage: RETR [mail number]";
-                writeLoggedFlushedResponse(responseString);
-                return;
-            }
-            try {
-                Mail mc = (Mail) userMailbox.get(num);
-                if (mc != DELETED) {
-                    responseString = OK_RESPONSE + " Message follows";
-                    writeLoggedFlushedResponse(responseString);
-                    try {
-                        ExtraDotOutputStream edouts =
-                                new ExtraDotOutputStream(outs);
-                        OutputStream nouts = new BytesWrittenResetOutputStream(edouts,
-                                                                  theWatchdog,
-                                                                  theConfigData.getResetLength());
-                        mc.getMessage().writeTo(nouts);
-                        nouts.flush();
-                        edouts.checkCRLFTerminator();
-                        edouts.flush();
-                    } finally {
-                        out.println(".");
-                        out.flush();
-                    }
-                } else {
-                    StringBuffer responseBuffer =
-                        new StringBuffer(64)
-                                .append(ERR_RESPONSE)
-                                .append(" Message (")
-                                .append(num)
-                                .append(") already deleted.");
-                    responseString = responseBuffer.toString();
-                    writeLoggedFlushedResponse(responseString);
-                }
-            } catch (IOException ioe) {
-                responseString = ERR_RESPONSE + " Error while retrieving message.";
-                writeLoggedFlushedResponse(responseString);
-            } catch (MessagingException me) {
-                responseString = ERR_RESPONSE + " Error while retrieving message.";
-                writeLoggedFlushedResponse(responseString);
-            } catch (IndexOutOfBoundsException iob) {
-                StringBuffer responseBuffer =
-                    new StringBuffer(64)
-                            .append(ERR_RESPONSE)
-                            .append(" Message (")
-                            .append(num)
-                            .append(") does not exist.");
-                responseString = responseBuffer.toString();
-                writeLoggedFlushedResponse(responseString);
-            }
-        } else {
-            responseString = ERR_RESPONSE;
-            writeLoggedFlushedResponse(responseString);
-        }
+     * @see org.apache.james.pop3server.POP3Session#clearResponseBuffer()
+     */
+    public String clearResponseBuffer() {
+        String responseString = responseBuffer.toString();
+        responseBuffer.delete(0,responseBuffer.length());
+        return responseString;
     }
 
     /**
-     * Handler method called upon receipt of a TOP command.
-     * This command retrieves the top N lines of a specified
-     * message in the mailbox.
-     *
-     * The expected command format is
-     *  TOP [mail message number] [number of lines to return]
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doTOP(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == TRANSACTION) {
-            int num = 0;
-            int lines = 0;
-            try {
-                num = Integer.parseInt(argument);
-                lines = Integer.parseInt(argument1);
-            } catch (NumberFormatException nfe) {
-                responseString = ERR_RESPONSE + " Usage: TOP [mail number] [Line number]";
-                writeLoggedFlushedResponse(responseString);
-                return;
-            }
-            try {
-                Mail mc = (Mail) userMailbox.get(num);
-                if (mc != DELETED) {
-                    responseString = OK_RESPONSE + " Message follows";
-                    writeLoggedFlushedResponse(responseString);
-                    try {
-                        for (Enumeration e = mc.getMessage().getAllHeaderLines(); e.hasMoreElements(); ) {
-                            out.println(e.nextElement());
-                        }
-                        out.println();
-                        ExtraDotOutputStream edouts =
-                                new ExtraDotOutputStream(outs);
-                        OutputStream nouts = new BytesWrittenResetOutputStream(edouts,
-                                                                  theWatchdog,
-                                                                  theConfigData.getResetLength());
-                        writeMessageContentTo(mc.getMessage(),nouts,lines);
-                        nouts.flush();
-                        edouts.checkCRLFTerminator();
-                        edouts.flush();
-                    } finally {
-                        out.println(".");
-                        out.flush();
-                    }
-                } else {
-                    StringBuffer responseBuffer =
-                        new StringBuffer(64)
-                                .append(ERR_RESPONSE)
-                                .append(" Message (")
-                                .append(num)
-                                .append(") already deleted.");
-                    responseString = responseBuffer.toString();
-                    writeLoggedFlushedResponse(responseString);
-                }
-            } catch (IOException ioe) {
-                responseString = ERR_RESPONSE + " Error while retrieving message.";
-                writeLoggedFlushedResponse(responseString);
-            } catch (MessagingException me) {
-                responseString = ERR_RESPONSE + " Error while retrieving message.";
-                writeLoggedFlushedResponse(responseString);
-            } catch (IndexOutOfBoundsException iob) {
-                StringBuffer exceptionBuffer =
-                    new StringBuffer(64)
-                            .append(ERR_RESPONSE)
-                            .append(" Message (")
-                            .append(num)
-                            .append(") does not exist.");
-                responseString = exceptionBuffer.toString();
-                writeLoggedFlushedResponse(responseString);
-            }
-        } else {
-            responseString = ERR_RESPONSE;
-            writeLoggedFlushedResponse(responseString);
-        }
+     * @see org.apache.james.pop3server.POP3Session#getWatchdog()
+     */
+    public Watchdog getWatchdog() {
+        return theWatchdog;
     }
 
     /**
-     * Writes the content of the message, up to a total number of lines, out to 
-     * an OutputStream.
+     * Sets the POP3HandlerChain
      *
-     * @param out the OutputStream to which to write the content
-     * @param lines the number of lines to write to the stream
-     *
-     * @throws MessagingException if the MimeMessage is not set for this MailImpl
-     * @throws IOException if an error occurs while reading or writing from the stream
+     * @param handlerChain POP3Handler object
      */
-    public void writeMessageContentTo(MimeMessage message, OutputStream out, int lines)
-        throws IOException, MessagingException {
-        String line;
-        BufferedReader br;
-        if (message != null) {
-            br = new BufferedReader(new InputStreamReader(message.getRawInputStream()));
-            try {
-                while (lines-- > 0) {
-                    if ((line = br.readLine()) == null) {
-                        break;
-                    }
-                    line += "\r\n";
-                    out.write(line.getBytes());
-                }
-            } finally {
-                br.close();
-            }
-        } else {
-            throw new MessagingException("No message set for this MailImpl.");
-        }
+    public void setHandlerChain(POP3HandlerChain handlerChain) {
+        this.handlerChain = handlerChain;
     }
 
     /**
-     * Handler method called upon receipt of a QUIT command.
-     * This method handles cleanup of the POP3Handler state.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
-     */
-    private void doQUIT(String command,String argument,String argument1) {
-        String responseString = null;
-        if (state == AUTHENTICATION_READY ||  state == AUTHENTICATION_USERSET) {
-            responseString = OK_RESPONSE + " Apache James POP3 Server signing off.";
-            writeLoggedFlushedResponse(responseString);
-            return;
-        }
-        List toBeRemoved =  ListUtils.subtract(backupUserMailbox, userMailbox);
-        try {
-            userInbox.remove(toBeRemoved);
-            // for (Iterator it = toBeRemoved.iterator(); it.hasNext(); ) {
-            //    Mail mc = (Mail) it.next();
-            //    userInbox.remove(mc.getName());
-            //}
-            responseString = OK_RESPONSE + " Apache James POP3 Server signing off.";
-            writeLoggedFlushedResponse(responseString);
-        } catch (Exception ex) {
-            responseString = ERR_RESPONSE + " Some deleted messages were not removed";
-            writeLoggedFlushedResponse(responseString);
-            getLogger().error("Some deleted messages were not removed: " + ex.getMessage());
+     * @see org.apache.james.pop3server.POP3Session#writeResponse(java.lang.String)
+     */
+    public void writeResponse(String respString) {
+        writeLoggedFlushedResponse(respString);
+        //TODO Explain this well
+        if(mode == COMMAND_MODE) {
+            mode = RESPONSE_MODE;
         }
     }
 
     /**
-     * Handler method called upon receipt of an unrecognized command.
-     * Returns an error response and logs the command.
-     *
-     * @param command the command parsed by the parseCommand method
-     * @param argument the first argument parsed by the parseCommand method
-     * @param argument1 the second argument parsed by the parseCommand method
+     * @see org.apache.james.pop3server.POP3Session#getCommandName()
      */
-    private void doUnknownCmd(String command,String argument,String argument1) {
-        writeLoggedFlushedResponse(ERR_RESPONSE);
+    public String getCommandName() {
+        return curCommandName;
     }
 
-}
+    /**
+     * @see org.apache.james.pop3server.POP3Session#getCommandArgument()
+     */
+    public String getCommandArgument() {
+        return curCommandArgument;
+    }
+
+    /**
+     * @see org.apache.james.pop3server.POP3Session#getConfigurationData()
+     */
+    public POP3HandlerConfigurationData getConfigurationData() {
+        return theConfigData;
+    }
+
+    /**
+     * @see org.apache.james.pop3server.POP3Session#getHandlerState()
+     */
+    public int getHandlerState() {
+        return handlerState;
+    }
 
+    /**
+     * @see org.apache.james.pop3server.POP3Session#setHandlerState(int)
+     */
+    public void setHandlerState(int handlerState) {
+        this.handlerState = handlerState;
+    }
+
+    /**
+     * @see org.apache.james.pop3server.POP3Session#getUserInbox()
+     */
+    public MailRepository getUserInbox() {
+        return userInbox;
+    }
+
+    /**
+     * @see org.apache.james.pop3server.POP3Session#setUserInbox(org.apache.james.services.MailRepository)
+     */
+    public void setUserInbox(MailRepository userInbox) {
+        this.userInbox = userInbox;
+    }
+
+    /**
+     * @see org.apache.james.pop3server.POP3Session#getUserMailbox()
+     */
+    public ArrayList getUserMailbox() {
+        return userMailbox;
+    }
+
+    /**
+     * @see org.apache.james.pop3server.POP3Session#setUserMailbox(java.util.ArrayList)
+     */
+    public void setUserMailbox(ArrayList userMailbox) {
+        this.userMailbox = userMailbox;
+    }
+
+    /**
+     * @see org.apache.james.pop3server.POP3Session#getBackupUserMailbox()
+     */
+    public List getBackupUserMailbox() {
+        return backupUserMailbox;
+    }
+
+    /**
+     * @see org.apache.james.pop3server.POP3Session#getOutputStream()
+     */
+    public OutputStream getOutputStream() {
+        return outs;
+    }
+
+}

Added: james/server/trunk/src/java/org/apache/james/pop3server/POP3HandlerChain.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/POP3HandlerChain.java?rev=405184&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/POP3HandlerChain.java (added)
+++ james/server/trunk/src/java/org/apache/james/pop3server/POP3HandlerChain.java Mon May  8 14:58:26 2006
@@ -0,0 +1,226 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.pop3server;
+
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.configuration.DefaultConfiguration;
+import org.apache.avalon.framework.container.ContainerUtil;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+
+/**
+  * The POP3HandlerChain is per service object providing access
+  * ConnectHandlers, Commandhandlers and message handlers
+  */
+public class POP3HandlerChain extends AbstractLogEnabled implements Configurable, Serviceable {
+
+    private HashMap commandHandlerMap = new HashMap();
+    private ArrayList messageHandlers = new ArrayList();
+    private ArrayList connectHandlers = new ArrayList();
+
+    private final CommandHandler unknownHandler = new UnknownCmdHandler();
+    private ServiceManager serviceManager;
+
+    private final static String[] mandatoryCommands = { "USER" , "PASS", "LIST"};
+
+    public void service(ServiceManager arg0) throws ServiceException {
+        serviceManager = arg0;
+    }
+
+
+    /**
+     * loads the various handlers from the configuration
+     * @param configuration configuration under handlerchain node
+     */
+    public void configure(Configuration configuration) throws  ConfigurationException {
+        addToMap(UnknownCmdHandler.UNKNOWN_COMMAND, unknownHandler);
+        if(configuration == null || configuration.getChildren("handler") == null || configuration.getChildren("handler").length == 0) {
+            configuration = new DefaultConfiguration("handlerchain");
+            Properties cmds = new Properties();
+            cmds.setProperty("USER",UserCmdHandler.class.getName());
+            cmds.setProperty("PASS",PassCmdHandler.class.getName());
+            cmds.setProperty("LIST",ListCmdHandler.class.getName());
+            cmds.setProperty("UIDL",UidlCmdHandler.class.getName());
+            cmds.setProperty("RSET",RsetCmdHandler.class.getName());
+            cmds.setProperty("DELE",DeleCmdHandler.class.getName());
+            cmds.setProperty("NOOP",NoopCmdHandler.class.getName());
+            cmds.setProperty("RETR",RetrCmdHandler.class.getName());
+            cmds.setProperty("TOP" ,TopCmdHandler.class.getName());
+            cmds.setProperty("QUIT",QuitCmdHandler.class.getName());
+            Enumeration e = cmds.keys();
+            while (e.hasMoreElements()) {
+                String cmdName = (String) e.nextElement();
+                String className = cmds.getProperty(cmdName);
+                DefaultConfiguration cmdConf = new DefaultConfiguration("handler");
+                cmdConf.setAttribute("command",cmdName);
+                cmdConf.setAttribute("class",className);
+                ((DefaultConfiguration) configuration).addChild(cmdConf);
+            }
+        }
+        if(configuration != null) {
+            Configuration[] children = configuration.getChildren("handler");
+            if ( children != null ) {
+                ClassLoader classLoader = getClass().getClassLoader();
+                for ( int i = 0 ; i < children.length ; i++ ) {
+                    String className = children[i].getAttribute("class");
+                    if(className != null) {
+                        //load the handler
+                        try {
+                            Object handler = classLoader.loadClass(className).newInstance();
+
+                            //enable logging
+                            ContainerUtil.enableLogging(handler, getLogger());
+
+                            //servicing the handler
+                            ContainerUtil.service(handler,serviceManager);
+
+                            //configure the handler
+                            ContainerUtil.configure(handler,children[i]);
+
+                            //if it is a connect handler add it to list of connect handlers
+                            if(handler instanceof ConnectHandler) {
+                                connectHandlers.add((ConnectHandler)handler);
+                                if (getLogger().isInfoEnabled()) {
+                                    getLogger().info("Added ConnectHandler: " + className);
+                                }
+                            }
+
+                            //if it is a command handler add it to the map with key as command name
+                            if(handler instanceof CommandHandler) {
+                                String commandName = children[i].getAttribute("command");
+                                commandName = commandName.toUpperCase(Locale.US);
+                                addToMap(commandName, (CommandHandler)handler);
+                                if (getLogger().isInfoEnabled()) {
+                                    getLogger().info("Added Commandhandler: " + className);
+                                }
+
+                            }
+
+                        } catch (ClassNotFoundException ex) {
+                           if (getLogger().isErrorEnabled()) {
+                               getLogger().error("Failed to add Commandhandler: " + className,ex);
+                           }
+                        } catch (IllegalAccessException ex) {
+                           if (getLogger().isErrorEnabled()) {
+                               getLogger().error("Failed to add Commandhandler: " + className,ex);
+                           }
+                        } catch (InstantiationException ex) {
+                           if (getLogger().isErrorEnabled()) {
+                               getLogger().error("Failed to add Commandhandler: " + className,ex);
+                           }
+                        } catch (ServiceException e) {
+                            if (getLogger().isErrorEnabled()) {
+                                getLogger().error("Failed to service Commandhandler: " + className,e);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        //the size must be greater than 1 because we added UnknownCmdHandler to the map
+        if(commandHandlerMap.size() < 2) {
+            if (getLogger().isErrorEnabled()) {
+                getLogger().error("No commandhandlers configured");
+            }
+            throw new ConfigurationException("No commandhandlers configured");
+        } else {
+            boolean found = true;
+            for (int i = 0; i < mandatoryCommands.length; i++) {
+                if(!commandHandlerMap.containsKey(mandatoryCommands[i])) {
+                    if (getLogger().isErrorEnabled()) {
+                        getLogger().error("No commandhandlers configured for the command:" + mandatoryCommands[i]);
+                    }
+                    found = false;
+                    break;
+                }
+            }
+
+            if(!found) {
+                throw new ConfigurationException("No commandhandlers configured for mandatory commands");
+            }
+            
+        }
+    }
+
+    /**
+     * Add it to map (key as command name, value is an array list of commandhandlers)
+     *
+     * @param commandName the command name which will be key
+     * @param cmdHandler The commandhandler object
+     */
+    private void addToMap(String commandName, CommandHandler cmdHandler) {
+        ArrayList handlers = (ArrayList)commandHandlerMap.get(commandName);
+        if(handlers == null) {
+            handlers = new ArrayList();
+            commandHandlerMap.put(commandName, handlers);
+        }
+        handlers.add(cmdHandler);
+    }
+
+    /**
+     * Returns all the configured commandhandlers for the specified command
+     *
+     * @param commandName the command name which will be key
+     * @return List of commandhandlers
+     */
+    List getCommandHandlers(String command) {
+        if (command == null) {
+            return null;
+        }
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("Lookup command handler for command: " + command);
+        }
+        List handlers =  (List)commandHandlerMap.get(command);
+        if(handlers == null) {
+            handlers = (List)commandHandlerMap.get(UnknownCmdHandler.UNKNOWN_COMMAND);
+        }
+
+        return handlers;
+    }
+
+    /**
+     * Returns all the configured message handlers
+     *
+     * @return List of message handlers
+     */
+    List getMessageHandlers() {
+        return messageHandlers;
+    }
+
+    /**
+     * Returns all the configured connect handlers
+     *
+     * @return List of connect handlers
+     */
+    List getConnectHandlers() {
+        return connectHandlers;
+    }
+
+}

Propchange: james/server/trunk/src/java/org/apache/james/pop3server/POP3HandlerChain.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: james/server/trunk/src/java/org/apache/james/pop3server/POP3Server.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/POP3Server.java?rev=405184&r1=405183&r2=405184&view=diff
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/POP3Server.java (original)
+++ james/server/trunk/src/java/org/apache/james/pop3server/POP3Server.java Mon May  8 14:58:26 2006
@@ -17,9 +17,11 @@
 
 package org.apache.james.pop3server;
 
+import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
 import org.apache.avalon.excalibur.pool.ObjectFactory;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.container.ContainerUtil;
 import org.apache.avalon.framework.service.ServiceException;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.james.core.AbstractJamesService;
@@ -36,6 +38,12 @@
 public class POP3Server extends AbstractJamesService implements POP3ServerMBean {
 
     /**
+     * The handler chain - POP3handlers can lookup handlerchain to obtain
+     * Command handlers , Message handlers and connection handlers
+     */
+    POP3HandlerChain handlerChain = new POP3HandlerChain();
+
+    /**
      * The internal mail server service
      */
     private MailServer mailServer;
@@ -58,12 +66,15 @@
     private POP3HandlerConfigurationData theConfigData
         = new POP3HandlerConfigurationDataImpl();
 
+    private ServiceManager serviceManager;
+
     /**
      * @see org.apache.avalon.framework.service.Serviceable#compose(ServiceManager)
      */
     public void service( final ServiceManager componentManager )
         throws ServiceException {
         super.service(componentManager);
+        serviceManager = componentManager;
         mailServer = (MailServer)componentManager.lookup( MailServer.ROLE );
         users = (UsersRepository)componentManager.lookup( UsersRepository.ROLE );
     }
@@ -79,6 +90,21 @@
             if (getLogger().isInfoEnabled()) {
                 getLogger().info("The idle timeout will be reset every " + lengthReset + " bytes.");
             }
+            //set the logger
+            ContainerUtil.enableLogging(handlerChain,getLogger());
+
+            try {
+                ContainerUtil.service(handlerChain,serviceManager);
+            } catch (ServiceException e) {
+                if (getLogger().isErrorEnabled()) {
+                    getLogger().error("Failed to service handlerChain",e);
+                }
+                throw new ConfigurationException("Failed to service handlerChain");
+            }
+            
+            //read from the XML configuration and create and configure each of the handlers
+            ContainerUtil.configure(handlerChain,handlerConfiguration.getChild("handlerchain"));
+
         }
         theHandlerFactory = new POP3HandlerFactory();
     }
@@ -95,6 +121,21 @@
      */
     public String getServiceType() {
         return "POP3 Service";
+    }
+
+
+    /**
+     * @see org.apache.avalon.cornerstone.services.connection.AbstractHandlerFactory#newHandler()
+     */
+    protected ConnectionHandler newHandler()
+            throws Exception {
+        
+        POP3Handler theHandler = (POP3Handler) super.newHandler();
+
+        //pass the handler chain to every POP3handler
+        theHandler.setHandlerChain(handlerChain);
+
+        return theHandler;
     }
 
     /**

Added: james/server/trunk/src/java/org/apache/james/pop3server/POP3Session.java
URL: http://svn.apache.org/viewcvs/james/server/trunk/src/java/org/apache/james/pop3server/POP3Session.java?rev=405184&view=auto
==============================================================================
--- james/server/trunk/src/java/org/apache/james/pop3server/POP3Session.java (added)
+++ james/server/trunk/src/java/org/apache/james/pop3server/POP3Session.java Mon May  8 14:58:26 2006
@@ -0,0 +1,212 @@
+/***********************************************************************
+ * Copyright (c) 1999-2006 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed 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.pop3server;
+
+
+import org.apache.james.services.MailRepository;
+import org.apache.james.util.watchdog.Watchdog;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * All the handlers access this interface to communicate with
+ * POP3Handler object
+ */
+
+public interface POP3Session {
+
+    /**
+     * Writes response string to the client
+     *
+     * @param respString String that needs to send to the client
+     */
+    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
+     * by each handler object
+     *
+     * @return responseBuffer
+     */
+    StringBuffer getResponseBuffer();
+
+    /**
+     * Clears the response buffer, returning the String of characters in the buffer.
+     *
+     * @return the data in the response buffer
+     */
+    String clearResponseBuffer();
+
+    /**
+     * Returns currently process command name
+     *
+     * @return current command name
+     */
+    String getCommandName();
+
+    /**
+     * Returns currently process command argument
+     *
+     * @return current command argument
+     */
+    String getCommandArgument();
+
+    /**
+     * Returns host name of the client
+     *
+     * @return hostname of the client
+     */
+    String getRemoteHost();
+
+    /**
+     * Returns host ip address of the client
+     *
+     * @return host ip address of the client
+     */
+    String getRemoteIPAddress();
+
+    /**
+     * this makes the session to close
+     *
+     */
+    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 POP3Session
+     *
+     * @return map of the current POP3Session state
+     */
+    HashMap getState();
+
+    /**
+     * Resets message-specific, but not authenticated user, state.
+     *
+     */
+    void resetState();
+
+    /**
+     * Returns POP3Handler service wide configuration
+     *
+     * @return POP3HandlerConfigurationData
+     */
+    POP3HandlerConfigurationData getConfigurationData();
+
+    /**
+     * Returns the user name associated with this POP3 interaction.
+     *
+     * @return the user name
+     */
+    String getUser();
+
+    /**
+     * Sets the user name associated with this POP3 interaction.
+     *
+     * @param userID the user name
+     */
+    void setUser(String user);
+
+    /**
+     * Returns Watchdog object used for handling timeout
+     *
+     * @return Watchdog object
+     */
+    Watchdog getWatchdog();
+    
+    /**
+     * Returns the current handler state
+     *
+     * @return handler state
+     */
+    int getHandlerState();
+
+    /**
+     * Sets the new handler state
+     * 
+     * @param handlerState state
+     */
+    void setHandlerState(int handlerState);
+
+    /**
+     * Returns the current user inbox
+     *
+     * @return MailRepository
+     */
+    MailRepository getUserInbox();
+
+    /**
+     * Sets the user's mail repository
+     * 
+     * @param userInbox userInbox
+     */
+    void setUserInbox(MailRepository userInbox);
+
+    /**
+     * Returns the mail list contained in the mailbox
+     * 
+     * @return mailbox content
+     */
+    ArrayList getUserMailbox();
+
+    /**
+     * Sets a new mailbox content
+     * 
+     * @param userMailbox mailbox
+     */
+    void setUserMailbox(ArrayList userMailbox);
+    
+    /**
+     * Inizialize the mailbox
+     */
+    void stat();
+
+    /**
+     * Returns the backup mailbox
+     * 
+     * @return list backup
+     */
+    List getBackupUserMailbox();
+
+    /**
+     * Returns the raw output stream
+     *
+     * @return the raw outputstream
+     */
+    OutputStream getOutputStream();
+
+}
+

Propchange: james/server/trunk/src/java/org/apache/james/pop3server/POP3Session.java
------------------------------------------------------------------------------
    svn:eol-style = native



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