Index: /home/maurer/stuff/workspace/james-trunk2/src/conf/james-config.xml
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/conf/james-config.xml	(revision 417037)
+++ /home/maurer/stuff/workspace/james-trunk2/src/conf/james-config.xml	(working copy)
@@ -932,83 +932,70 @@
             -->            
             
             <!-- The command handler configuration -->
-            <handler command="HELO" class="org.apache.james.smtpserver.HeloCmdHandler">
-                <!-- If is set to true helo is only accepted if it can be resolved -->
-                <!--
-                <checkResolvableHelo> false </checkResolvableHelo>
-                -->
-                
-                <!-- If is set to true helo is only accepted if it is equal the reverse of the -->
-                <!-- connecting client -->
-                <!--
-                <checkReverseEqualsHelo> false </checkReverseEqualsHelo>
-                -->
-                
-                <!-- If is set to true sender domain will be checked also for clients that -->
-                <!-- are allowed to relay. Default is false. -->
-                <!--
+            <handler command="HELO" class="org.apache.james.smtpserver.HeloCmdHandler"></handler>
+            <handler command="EHLO" class="org.apache.james.smtpserver.EhloCmdHandler"></handler>
+            <handler command="AUTH" class="org.apache.james.smtpserver.AuthCmdHandler"></handler>
+            <handler command="VRFY" class="org.apache.james.smtpserver.VrfyCmdHandler"></handler>
+            <handler command="EXPN" class="org.apache.james.smtpserver.ExpnCmdHandler"></handler>
+            <handler command="MAIL" class="org.apache.james.smtpserver.MailCmdHandler"></handler>
+            <handler command="RCPT" class="org.apache.james.smtpserver.RcptCmdHandler"></handler>
+            <handler command="DATA" class="org.apache.james.smtpserver.DataCmdHandler"></handler>
+            <handler command="RSET" class="org.apache.james.smtpserver.RsetCmdHandler"></handler>
+            <handler command="HELP" class="org.apache.james.smtpserver.HelpCmdHandler"></handler>
+            <handler command="QUIT" class="org.apache.james.smtpserver.QuitCmdHandler"></handler>
+            
+            <!-- The filter handler configuration -->
+
+            <!-- checks for resolvable HELO/EHLO before accept the HELO/EHLO -->
+            <!-- If checkAuthNetworks is set to true sender domain will be checked also for clients that -->
+            <!-- are allowed to relay. Default is false. -->
+            <!--
+            <handler class="org.apache.james.smtpserver.filter.ResolvableEhloHeloFilterHandler">
                 <checkAuthNetworks> false </checkAuthNetworks>
-                -->
-            </handler>
-            <handler command="EHLO" class="org.apache.james.smtpserver.EhloCmdHandler">
-                <!-- If is set to true ehlo is only accepted if it can be resolved -->
-                <!--
-                <checkResolvableEhlo> false </checkResolvableEhlo>
-                -->
-                
-                <!-- If is set to true ehlo is only accepted if it is equal the reverse of the -->
-                <!-- connecting client -->
-                <!--
-                <checkReverseEqualsEhlo> false </checkReverseEqualsEhlo>
-                -->
-                
-                <!-- If is set to true sender domain will be checked also for clients that -->
-                <!-- are allowed to relay. Default is false. -->
-                <!--
+            </handler>  
+            -->
+            
+            <!-- Checks HELO/EHLO is equal the reverse of the connecting client before accept it -->
+            <!-- If checkAuthNetworks is set to true sender domain will be checked also for clients that -->
+            <!-- are allowed to relay. Default is false. -->
+            <!--
+            <handler class="org.apache.james.smtpserver.filter.ReverseEqualsEhloHeloFilterHandler">
                 <checkAuthNetworks> false </checkAuthNetworks>
-                -->
             </handler>
-            <handler command="AUTH" class="org.apache.james.smtpserver.AuthCmdHandler"></handler>
-            <handler command="VRFY" class="org.apache.james.smtpserver.VrfyCmdHandler"></handler>
-            <handler command="EXPN" class="org.apache.james.smtpserver.ExpnCmdHandler"></handler>
-            <handler command="MAIL" class="org.apache.james.smtpserver.MailCmdHandler">
-                <!-- If is set to true mail is only accepted if the sender contains -->
-                <!-- a resolvable domain having a valid MX Record or A Record associated! -->
-                <!--
-                <checkValidSenderDomain> false </checkValidSenderDomain>
-                -->
-                <!-- If is set to true sender domain from clients that are allowed to -->
-                <!-- relay will be checked, too. Default is false. -->
-                <!-- 
+            -->
+            
+            <!-- If activated mail is only accepted if the sender contains -->
+            <!-- a resolvable domain having a valid MX Record or A Record associated! -->
+            <!-- If checkAuthNetworks is set to true sender domain will be checked also for clients that -->
+            <!-- are allowed to relay. Default is false. -->
+            <!--
+            <handler class="org.apache.james.smtpserver.filter.ValidSenderDomainFilterHandler">
                 <checkAuthClients> false </checkAuthClients>
-                -->
+            </handler>
+            -->
+            
+            <!-- If activated you can limit the maximal recipients -->
+            <!-- 
+            <handler class="org.apache.james.smtpserver.filter.MaxRcptFilterHandler">
+                <maxRcpt> 10 </maxRcpt>
             </handler>
-            <handler command="RCPT" class="org.apache.james.smtpserver.RcptCmdHandler">
-                <!-- If is set to a bigger value as 0 you can limit the maximal recipients -->
-                <!-- per email. Default is set to 0. -->
-                <!-- 
-                <maxRcpt> 0 </maxRcpt>
-                -->
+            -->
+        
                 
-                <!-- If is set to a bigger value as 0 you can set the recipients after which -->
-                <!-- tarpitting get activated. -->
-                <!-- Tarpitting is a method to insert a small sleep after each rcpt. For more -->
-                <!-- infos read this: http://www.palomine.net/qmail/tarpit.html . -->
-                <!-- Default is set to 0 (disabled). -->
-                <!--
-                <tarpitRcptCount> 0 </tarpitRcptCount>
-                -->
-                <!-- See timeout in milliseconds to insert after the rcpt. Only is used if -->
-                <!-- tarpitting is activated. -->
-                <!--
+            <!-- If is set to a bigger value as 0 you can set the recipients after which -->
+            <!-- tarpitting get activated. -->
+            <!-- Tarpitting is a method to insert a small sleep after each rcpt. For more -->
+            <!-- infos read this: http://www.palomine.net/qmail/tarpit.html . -->
+            <!-- Default is set to 0 (disabled). -->
+            <!-- You can also configure the time to sleep in milliseconds -->
+            <!--
+            <handler class="org.apache.james.smtpserver.filter.TarpitFilterHandler">
+                <tarpitRcptCount> 5 </tarpitRcptCount>
                 <tarpitSleepTime> 5000 </tarpitSleepTime>
-                -->
             </handler>
-            <handler command="DATA" class="org.apache.james.smtpserver.DataCmdHandler"></handler>
-            <handler command="RSET" class="org.apache.james.smtpserver.RsetCmdHandler"></handler>
-            <handler command="HELP" class="org.apache.james.smtpserver.HelpCmdHandler"></handler>
-            <handler command="QUIT" class="org.apache.james.smtpserver.QuitCmdHandler"></handler>
-         
+            -->
+            
+            
             <!-- The message handler configuration -->
             <!-- 
             <handler class="org.apache.james.smtpserver.SetMimeHeaderHandler">
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/EhloCmdHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/EhloCmdHandler.java	(revision 416301)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/EhloCmdHandler.java	(working copy)
@@ -17,23 +17,15 @@
 
 package org.apache.james.smtpserver;
 
-import org.apache.avalon.framework.configuration.Configurable;
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
+import java.util.ArrayList;
+
 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 org.apache.james.services.DNSServer;
 import org.apache.james.util.mail.dsn.DSNStatus;
 
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-
 /**
   * Handles EHLO command
   */
-public class EhloCmdHandler extends AbstractLogEnabled implements CommandHandler,Configurable,  Serviceable {
+public class EhloCmdHandler extends AbstractLogEnabled implements ExtendableCommandHandler {
 
     /**
      * The name of the command handled by the command handler
@@ -39,91 +31,10 @@
      * The name of the command handled by the command handler
      */
     private final static String COMMAND_NAME = "EHLO";
-
-    /**
-     * set checkResolvableEhlo to false as default value
-     */
-    private boolean checkResolvableEhlo = false;
-
-    private boolean checkReverseEqualsEhlo = false;
-    
-    private boolean checkAuthNetworks = false;
-    
-    private DNSServer dnsServer = null;
-    
-    /**
-     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
-     */
-    public void configure(Configuration handlerConfiguration) throws ConfigurationException {
-        Configuration configuration = handlerConfiguration.getChild("checkResolvableEhlo",false);
-        if(configuration != null) {
-           setCheckResolvableEhlo(configuration.getValueAsBoolean(false));
-        }
-        
-        Configuration config = handlerConfiguration.getChild(
-                "checkReverseEqualsEhlo", false);
-        if (config != null) {
-            setCheckReverseEqualsEhlo(config.getValueAsBoolean(false));
-        }
-        
-        Configuration configRelay = handlerConfiguration.getChild("checkAuthNetworks",false);
-        if(configRelay != null) {
-            setCheckAuthNetworks(configRelay.getValueAsBoolean(false));
-        }
-    }
-    
-    /**
-     * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
-     */
-    public void service(ServiceManager serviceMan) throws ServiceException {
-        setDnsServer((DNSServer) serviceMan.lookup(DNSServer.ROLE));
-    }
-    
-    /**
-     * Set to true to enable check for resolvable EHLO
-     * 
-     * @param checkResolvableEhlo Set to true for enable check
-     */
-    public void setCheckResolvableEhlo(boolean checkResolvableEhlo) {
-        this.checkResolvableEhlo = checkResolvableEhlo;
-    }
     
-    /**
-     * Set to true to enable check for reverse equal EHLO
-     * 
-     * @param checkReverseEqualsEhlo
-     *            Set to true for enable check
-     */
-    public void setCheckReverseEqualsEhlo(boolean checkReverseEqualsEhlo) {
-        this.checkReverseEqualsEhlo = checkReverseEqualsEhlo;
-    }
 
-    /**
-     * Set to true if AuthNetworks should be included in the EHLO check
-     * 
-     * @param checkAuthNetworks
-     *            Set to true to enable
-     */
-    public void setCheckAuthNetworks(boolean checkAuthNetworks) {
-        this.checkAuthNetworks = checkAuthNetworks;
-    }
-    
-    /**
-     * Set the DNSServer
-     * 
-     * @param dnsServer The DNSServer
-     */
-    public void setDnsServer(DNSServer dnsServer) {
-        this.dnsServer = dnsServer;
-    }
-
-    /*
-     * processes EHLO command
-     *
-     * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
-    **/
-    public void onCommand(SMTPSession session) {
-        doEHLO(session, session.getCommandArgument());
+    public boolean onCommand(SMTPSession session) {
+        return doEHLO(session, session.getCommandArgument());
     }
 
     /**
@@ -134,105 +45,62 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doEHLO(SMTPSession session, String argument) {
+    private boolean doEHLO(SMTPSession session, String argument) {
         String responseString = null;
-        StringBuffer responseBuffer = session.getResponseBuffer();
-        boolean badEhlo = false;
-        
-        /**
-         * don't check if the ip address is allowed to relay. Only check if it
-         * is set in the config. ed.
-         */
-        if (!session.isRelayingAllowed() || checkAuthNetworks) {
-            // check for resolvable EHLO if its set in config
-            if (checkResolvableEhlo) {
-                // try to resolv the provided helo. If it can not resolved do not accept it.
-                try {
-                    dnsServer.getByName(argument);
-                } catch (UnknownHostException e) {
-                    badEhlo = true;
-                    responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Provided EHLO " + argument + " can not resolved";
-                    session.writeResponse(responseString);
-                    getLogger().info(responseString);
-                }
-            } else if (checkReverseEqualsEhlo) {
-                try {
-                    // get reverse entry
-                    String reverse = dnsServer.getByName(
-                            session.getRemoteIPAddress()).getHostName();
 
-                    if (!argument.equals(reverse)) {
-                        badEhlo = true;
-                        responseString = "501 "
-                                + DSNStatus.getStatus(DSNStatus.PERMANENT,
-                                        DSNStatus.DELIVERY_INVALID_ARG)
-                                + " Provided EHLO " + argument
-                                + " not equal reverse of "
-                                + session.getRemoteIPAddress();
-
-                        session.writeResponse(responseString);
-                        getLogger().info(responseString);
-                    }
-                } catch (UnknownHostException e) {
-                    badEhlo = true;
-                    responseString = "501 "
-                            + DSNStatus.getStatus(DSNStatus.PERMANENT,
-                                    DSNStatus.DELIVERY_INVALID_ARG)
-                            + " Ipaddress " + session.getRemoteIPAddress()
-                            + " can not resolved";
-
-                    session.writeResponse(responseString);
-                    getLogger().info(responseString);
-                }
-            }
-        }
-        
         if (argument == null) {
             responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Domain address required: " + COMMAND_NAME;
             session.writeResponse(responseString);
-        } else if (!badEhlo){
-            session.resetState();
-            session.getState().put(SMTPSession.CURRENT_HELO_MODE, COMMAND_NAME);
+            return true;
+        }
+        return false;
+    }
 
-            ArrayList esmtpextensions = new ArrayList();
+    public void finalizeCommand(SMTPSession session)
+    {
+        String argument = session.getCommandArgument();
+        StringBuffer responseBuffer = session.getResponseBuffer();
+        session.resetState();
+        session.getState().put(SMTPSession.CURRENT_HELO_MODE, COMMAND_NAME);
 
-            esmtpextensions.add(new StringBuffer(session.getConfigurationData().getHelloName())
-                .append(" Hello ")
-                .append(argument)
-                .append(" (")
-                .append(session.getRemoteHost())
-                .append(" [")
-                .append(session.getRemoteIPAddress())
-                .append("])").toString());
+        ArrayList esmtpextensions = new ArrayList();
 
-            // Extension defined in RFC 1870
-            long maxMessageSize = session.getConfigurationData().getMaxMessageSize();
-            if (maxMessageSize > 0) {
-                esmtpextensions.add("SIZE " + maxMessageSize);
-            }
+        esmtpextensions.add(new StringBuffer(session.getConfigurationData().getHelloName())
+            .append(" Hello ")
+            .append(argument)
+            .append(" (")
+            .append(session.getRemoteHost())
+            .append(" [")
+            .append(session.getRemoteIPAddress())
+            .append("])").toString());
 
-            if (session.isAuthRequired()) {
-                esmtpextensions.add("AUTH LOGIN PLAIN");
-                esmtpextensions.add("AUTH=LOGIN PLAIN");
-            }
+        // Extension defined in RFC 1870
+        long maxMessageSize = session.getConfigurationData().getMaxMessageSize();
+        if (maxMessageSize > 0) {
+            esmtpextensions.add("SIZE " + maxMessageSize);
+        }
 
-            esmtpextensions.add("PIPELINING");
-            esmtpextensions.add("ENHANCEDSTATUSCODES");
-            // see http://issues.apache.org/jira/browse/JAMES-419 
-            //esmtpextensions.add("8BITMIME");
+        if (session.isAuthRequired()) {
+            esmtpextensions.add("AUTH LOGIN PLAIN");
+            esmtpextensions.add("AUTH=LOGIN PLAIN");
+        }
 
+        esmtpextensions.add("PIPELINING");
+        esmtpextensions.add("ENHANCEDSTATUSCODES");
+        // see http://issues.apache.org/jira/browse/JAMES-419 
+        //esmtpextensions.add("8BITMIME");
 
-            // Iterator i = esmtpextensions.iterator();
-            for (int i = 0; i < esmtpextensions.size(); i++) {
-                if (i == esmtpextensions.size() - 1) {
-                    responseBuffer.append("250 ");
-                    responseBuffer.append((String) esmtpextensions.get(i));
-                    session.writeResponse(session.clearResponseBuffer());
-                } else {
-                    responseBuffer.append("250-");
-                    responseBuffer.append((String) esmtpextensions.get(i));
-                    session.writeResponse(session.clearResponseBuffer());
-                }
+
+        // Iterator i = esmtpextensions.iterator();
+        for (int i = 0; i < esmtpextensions.size(); i++) {
+            if (i == esmtpextensions.size() - 1) {
+                responseBuffer.append("250 ");
+                responseBuffer.append((String) esmtpextensions.get(i));
+                session.writeResponse(session.clearResponseBuffer());
+            } else {
+                responseBuffer.append("250-");
+                responseBuffer.append((String) esmtpextensions.get(i));
+                session.writeResponse(session.clearResponseBuffer());
             }
         }
     }
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/HeloCmdHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/HeloCmdHandler.java	(revision 416301)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/HeloCmdHandler.java	(working copy)
@@ -17,23 +17,13 @@
 
 package org.apache.james.smtpserver;
 
-
-import java.net.UnknownHostException;
-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.logger.AbstractLogEnabled;
-import org.apache.avalon.framework.service.ServiceException;
-import org.apache.avalon.framework.service.ServiceManager;
-import org.apache.avalon.framework.service.Serviceable;
-import org.apache.james.services.DNSServer;
-import org.apache.james.util.mail.dsn.DSNStatus;
-
 
 /**
-  * Handles HELO command
-  */
-public class HeloCmdHandler extends AbstractLogEnabled implements CommandHandler,Configurable, Serviceable {
+ * Handles HELO command
+ */
+public class HeloCmdHandler extends AbstractLogEnabled implements
+        ExtendableCommandHandler {
 
     /**
      * The name of the command handled by the command handler
@@ -40,155 +30,13 @@
      */
     private final static String COMMAND_NAME = "HELO";
 
-    /**
-     * set checkValidHelo to false as default value
-     */
-    private boolean checkResolvableHelo = false;
-    
-    private boolean checkReverseEqualsHelo = false;
-    
-    private boolean checkAuthNetworks = false;
-    
-    private DNSServer dnsServer = null;
-    
-    /**
-     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
-     */
-    public void configure(Configuration handlerConfiguration) throws ConfigurationException {
-        Configuration configuration = handlerConfiguration.getChild("checkResolvableHelo",false);
-        if(configuration != null) {
-           setCheckResolvableHelo(configuration.getValueAsBoolean(false));
-        }
-          
-        Configuration config = handlerConfiguration.getChild(
-                "checkReverseEqualsHelo", false);
-        if (config != null) {
-            setCheckReverseEqualsHelo(config.getValueAsBoolean(false));
-        }
-        
-        Configuration configRelay = handlerConfiguration.getChild("checkAuthNetworks",false);
-        if(configRelay != null) {
-            setCheckAuthNetworks(configRelay.getValueAsBoolean(false));
-        }
-        
-    }
-    
-    /**
-     * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
-     */
-    public void service(ServiceManager serviceMan) throws ServiceException {
-        dnsServer = (DNSServer) serviceMan.lookup(DNSServer.ROLE);
-    }
-    
-    /**
-     * Set to true to enable check for resolvable EHLO
-     * 
-     * @param checkResolvableHelo Set to true for enable check
-     */
-    public void setCheckResolvableHelo(boolean checkResolvableHelo) {
-        this.checkResolvableHelo = checkResolvableHelo;
-    }
-    
-    /**
-     * Set to true to enable check for reverse equal HELO
-     * 
-     * @param checkReverseEqualsHelo
-     *            Set to true for enable check
-     */
-    public void setCheckReverseEqualsHelo(boolean checkReverseEqualsHelo) {
-        this.checkReverseEqualsHelo = checkReverseEqualsHelo;
+    public boolean onCommand(SMTPSession session) {
+        return doHELO(session, session.getCommandArgument());
     }
 
-    /**
-     * Set to true if AuthNetworks should be included in the EHLO check
-     * 
-     * @param checkAuthNetworks Set to true to enable
-     */
-    public void setCheckAuthNetworks(boolean checkAuthNetworks) {
-        this.checkAuthNetworks = checkAuthNetworks;
-    }
-    
-    /**
-     * Set the DNSServer
-     * 
-     * @param dnsServer The DNSServer
-     */
-    public void setDnsServer(DNSServer dnsServer) {
-        this.dnsServer = dnsServer;
-    }
-      
-    /*
-     * process HELO command
-     *
-     * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
-    **/
-    public void onCommand(SMTPSession session) {
-        doHELO(session, session.getCommandArgument());
-    }
-
-    /**
-     * Handler method called upon receipt of a HELO command.
-     * Responds with a greeting and informs the client whether
-     * client authentication is required.
-     *
-     * @param session SMTP session object
-     * @param argument the argument passed in with the command by the SMTP client
-     */
-    private void doHELO(SMTPSession session, String argument) {
+    private boolean doHELO(SMTPSession session, String argument) {
         String responseString = null;
-        boolean badHelo = false;
-                
-        /**
-         * don't check if the ip address is allowed to relay. Only check if it is set in the config. ed.
-         */
-        if (!session.isRelayingAllowed() || checkAuthNetworks) {
 
-            // check for resolvable HELO if its set in config
-            if (checkResolvableHelo) {
-            
-
-                // try to resolv the provided helo. If it can not resolved do not accept it.
-                try {
-                    dnsServer.getByName(argument);
-                } catch (UnknownHostException e) {
-                    badHelo = true;
-                    responseString = "501 Provided HELO " + argument + " can not resolved";
-                    session.writeResponse(responseString);
-                    getLogger().info(responseString);
-                } 
-
-            } else if (checkReverseEqualsHelo) {
-                try {
-                    // get reverse entry
-                    String reverse = dnsServer.getByName(
-                            session.getRemoteIPAddress()).getHostName();
-
-                    if (!argument.equals(reverse)) {
-                        badHelo = true;
-                        responseString = "501 "
-                                + DSNStatus.getStatus(DSNStatus.PERMANENT,
-                                        DSNStatus.DELIVERY_INVALID_ARG)
-                                + " Provided HELO " + argument
-                                + " not equal reverse of "
-                                + session.getRemoteIPAddress();
-
-                        session.writeResponse(responseString);
-                        getLogger().info(responseString);
-                    }
-                } catch (UnknownHostException e) {
-                    badHelo = true;
-                    responseString = "501 "
-                            + DSNStatus.getStatus(DSNStatus.PERMANENT,
-                                    DSNStatus.DELIVERY_INVALID_ARG)
-                            + " Ipaddress " + session.getRemoteIPAddress()
-                            + " can not resolved";
-
-                    session.writeResponse(responseString);
-                    getLogger().info(responseString);
-                }
-            }
-        }
-        
         if (argument == null) {
             responseString = "501 Domain address required: " + COMMAND_NAME;
             session.writeResponse(responseString);
@@ -193,20 +41,23 @@
             responseString = "501 Domain address required: " + COMMAND_NAME;
             session.writeResponse(responseString);
             getLogger().info(responseString);
-        } else if (!badHelo) {
-            session.resetState();
-            session.getState().put(SMTPSession.CURRENT_HELO_MODE, COMMAND_NAME);
-            session.getResponseBuffer().append("250 ")
-                          .append(session.getConfigurationData().getHelloName())
-                          .append(" Hello ")
-                          .append(argument)
-                          .append(" (")
-                          .append(session.getRemoteHost())
-                          .append(" [")
-                          .append(session.getRemoteIPAddress())
-                          .append("])");
-            responseString = session.clearResponseBuffer();
-            session.writeResponse(responseString);
+            return true;
         }
+        return false;
+    }
+
+    public void finalizeCommand(SMTPSession session) {
+        String responseString = null;
+        String argument = session.getCommandArgument();
+
+        session.resetState();
+        session.getState().put(SMTPSession.CURRENT_HELO_MODE, COMMAND_NAME);
+        session.getResponseBuffer().append("250 ").append(
+                session.getConfigurationData().getHelloName())
+                .append(" Hello ").append(argument).append(" (").append(
+                        session.getRemoteHost()).append(" [").append(
+                        session.getRemoteIPAddress()).append("])");
+        responseString = session.clearResponseBuffer();
+        session.writeResponse(responseString);
     }
 }
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/MailCmdHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/MailCmdHandler.java	(revision 416301)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/MailCmdHandler.java	(working copy)
@@ -17,21 +17,13 @@
 
 package org.apache.james.smtpserver;
 
-import org.apache.avalon.framework.configuration.Configurable;
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
 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 org.apache.james.services.DNSServer;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.MailAddress;
 
-import java.util.Collection;
-import java.util.Locale;
-import java.util.StringTokenizer;
-
 /**
   * Handles MAIL command
   */
@@ -37,7 +29,7 @@
   */
 public class MailCmdHandler
     extends AbstractLogEnabled
-    implements CommandHandler,Configurable, Serviceable {
+    implements ExtendableCommandHandler {
 
     private final static String MAIL_OPTION_SIZE = "SIZE";
 
@@ -43,63 +35,7 @@
 
     private final static String MESG_SIZE = "MESG_SIZE"; // The size of the message
 
-    private boolean checkValidSenderDomain = false;
-    
-    private boolean checkAuthClients = false;
-    
-    private DNSServer dnsServer = null;
-    
-    /**
-     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
-     */
-    public void configure(Configuration handlerConfiguration) throws ConfigurationException {
-        Configuration configuration = handlerConfiguration.getChild("checkValidSenderDomain",false);
-        if(configuration != null) {
-           setCheckValidSenderDomain(configuration.getValueAsBoolean(false));
-           if (checkValidSenderDomain && dnsServer == null) {
-               throw new ConfigurationException("checkValidSenderDomain enabled but no DNSServer service provided to SMTPServer");
-           }
-        }
-        
-        Configuration configRelay = handlerConfiguration.getChild("checkAuthClients",false);
-        if(configRelay != null) {
-            setCheckAuthClients(configRelay.getValueAsBoolean(false));
-        }
-    }
-    
-    /**
-     * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
-     */
-    public void service(ServiceManager serviceMan) throws ServiceException {
-        setDnsServer((DNSServer) serviceMan.lookup(DNSServer.ROLE));
-    }
-    
-    /**
-     * Set the DnsServer
-     * 
-     * @param dnsServer The DnsServer
-     */
-    public void setDnsServer(DNSServer dnsServer) {
-        this.dnsServer = dnsServer;
-    }
-    
-    /**
-     * Enable checkvalidsenderdomain feature
-     * 
-     * @param checkValidSenderDomain Set to true to enable
-     */
-    public void setCheckValidSenderDomain(boolean checkValidSenderDomain) {
-        this.checkValidSenderDomain = checkValidSenderDomain;
-    }
-    
-    /**
-     * Enable checking of authorized clients
-     * 
-     * @param checkAuthClients Set to true to enable
-     */
-    public void setCheckAuthClients(boolean checkAuthClients) {
-        this.checkAuthClients = checkAuthClients;
-    }
+
     
     /**
      * handles MAIL command
@@ -104,10 +40,10 @@
     /**
      * handles MAIL command
      *
-     * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
+     * @see org.apache.james.smtpserver.ExtendableCommandHandler#onCommand(SMTPSession)
      */
-    public void onCommand(SMTPSession session) {
-        doMAIL(session, session.getCommandArgument());
+    public boolean onCommand(SMTPSession session) {
+        return doMAIL(session, session.getCommandArgument());
     }
 
 
@@ -118,11 +54,9 @@
      * @param session SMTP session object
      * @param argument the argument passed in with the command by the SMTP client
      */
-    private void doMAIL(SMTPSession session, String argument) {
+    private boolean doMAIL(SMTPSession session, String argument) {
         String responseString = null;
-        StringBuffer responseBuffer = session.getResponseBuffer();
         String sender = null;
-        boolean badSenderDomain = false;
         
         if ((argument != null) && (argument.indexOf(":") > 0)) {
             int colonIndex = argument.indexOf(":");
@@ -166,7 +100,7 @@
 
                     if (mailOptionName.startsWith(MAIL_OPTION_SIZE)) {
                         if (!(doMailSize(session, mailOptionValue, sender))) {
-                            return;
+                            return true;
                         }
                     } else {
                         // Unexpected option attached to the Mail command
@@ -193,7 +127,7 @@
                             .append(": did not start and end with < >");
                     getLogger().error(errorBuffer.toString());
                 }
-                return;
+                return true;
             }
             MailAddress senderAddress = null;
             //Remove < and >
@@ -208,6 +142,7 @@
                 
                 try {
                     senderAddress = new MailAddress(sender);
+                    session.getState().put(SMTPSession.SENDER, senderAddress);
                 } catch (Exception pe) {
                     responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX_SENDER)+" Syntax error in sender address";
                     session.writeResponse(responseString);
@@ -220,43 +155,12 @@
                                     .append(pe.getMessage());
                         getLogger().error(errorBuffer.toString());
                     }
-                    return;
+                    return true;
                 }
             }
-            
-            if (checkValidSenderDomain == true) {
-                
-                /**
-                 * don't check if the ip address is allowed to relay. Only check if it is set in the config. 
-                 */
-                if (checkAuthClients || !session.isRelayingAllowed()) {
-     
-                    // Maybe we should build a static method in org.apache.james.dnsserver.DNSServer ?
-                    Collection records;
-                
-                    records = dnsServer.findMXRecords(senderAddress.getHost());
-                    if (records == null || records.size() == 0) {
-                        badSenderDomain = true;
-                    }
-                
-                    // try to resolv the provided domain in the senderaddress. If it can not resolved do not accept it.
-                    if (badSenderDomain) {
-                        responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX_SENDER)+ " sender " + senderAddress + " contains a domain with no valid MX records";
-                        session.writeResponse(responseString);
-                        getLogger().info(responseString);
-                    }
-                }
-            }
-            
-            if (!badSenderDomain) {
-                session.getState().put(SMTPSession.SENDER, senderAddress);
-                responseBuffer.append("250 "+DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.ADDRESS_OTHER)+" Sender <")
-                              .append(sender)
-                              .append("> OK");
-                responseString = session.clearResponseBuffer();
-                session.writeResponse(responseString);
-            }
+
         }
+        return false;
     }
 
     /**
@@ -314,5 +218,16 @@
         return true;
     }
 
+    public void finalizeCommand(SMTPSession session) {
+        String responseString = null;
+        StringBuffer responseBuffer = session.getResponseBuffer();
+        responseBuffer.append("250 "+DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.ADDRESS_OTHER)+" Sender <")
+                      .append(session.getState().get(SMTPSession.SENDER))
+                      .append("> OK");
+        responseString = session.clearResponseBuffer();
+        session.writeResponse(responseString);
+        
+    }
+
 
 }
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/RcptCmdHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/RcptCmdHandler.java	(revision 416301)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/RcptCmdHandler.java	(working copy)
@@ -17,105 +17,43 @@
 
 package org.apache.james.smtpserver;
 
-import org.apache.avalon.framework.configuration.Configurable;
-import org.apache.avalon.framework.configuration.Configuration;
-import org.apache.avalon.framework.configuration.ConfigurationException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.StringTokenizer;
+
 import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.james.util.mail.dsn.DSNStatus;
 import org.apache.mailet.MailAddress;
-import java.util.Collection;
-import java.util.ArrayList;
-import java.util.StringTokenizer;
-import java.util.Locale;
 
 /**
-  * Handles RCPT command
-  */
-public class RcptCmdHandler
-    extends AbstractLogEnabled
-    implements CommandHandler,Configurable {
+ * Handles RCPT command
+ */
+public class RcptCmdHandler extends AbstractLogEnabled implements
+        ExtendableCommandHandler {
 
-    /**
-     * The keys used to store sender and recepients in the SMTPSession state
-     */
-    private final static String RCPTCOUNT = "RCPT_COUNT";
-    private int maxRcpt = 0;
-    private int tarpitRcptCount = 0;
-    private long tarpitSleepTime = 5000;
-    
-    /**
-     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+    /*
+     * handles RCPT command
+     * 
+     * @see org.apache.james.smtpserver.ExtendableCommandHandler#onCommand(SMTPSession)
      */
-    public void configure(Configuration handlerConfiguration) throws ConfigurationException {
-        Configuration configuration = handlerConfiguration.getChild("maxRcpt",false);
-        if(configuration != null) {
-           setMaxRcpt(configuration.getValueAsInteger(0));
-        }
-        
-        Configuration configTarpitRcptCount = handlerConfiguration.getChild("tarpitRcptCount",false);
-        if(configTarpitRcptCount != null) {
-           setTarpitRcptCount(configTarpitRcptCount.getValueAsInteger(0));
-        }
-        
-        Configuration configTarpitSleepTime = handlerConfiguration.getChild("tarpitSleepTime",false);
-        if(configTarpitSleepTime != null) {
-           setTarpitSleepTime(configTarpitSleepTime.getValueAsLong(5000));
-        }
+    public boolean onCommand(SMTPSession session) {
+        return doRCPT(session, session.getCommandArgument());
     }
-    
-    /**
-     * Set the max rcpt for wich should be accepted
-     *  
-     * @param maxRcpt The max rcpt count
-     */
-    public void setMaxRcpt(int maxRcpt) {
-        this.maxRcpt = maxRcpt;
-    }
-    
+
     /**
-     * Set the tarpit count after which the tarpit sleep time will be activated
+     * Handler method called upon receipt of a RCPT command. Reads recipient.
+     * Does some connection validation.
      * 
-     * @param tarpitRcptCount
-     */
-    public void setTarpitRcptCount(int tarpitRcptCount) {
-        this.tarpitRcptCount = tarpitRcptCount;
-    }
-    
-    /**
-     * Set the tarpit sleep time 
      * 
-     * @param tarpitSleepTime Time in milliseconds
+     * @param session
+     *            SMTP session object
+     * @param argument
+     *            the argument passed in with the command by the SMTP client
      */
-    public void setTarpitSleepTime(long tarpitSleepTime) {
-        this.tarpitSleepTime = tarpitSleepTime;
-    }
-    
-    
-    
-    /*
-     * handles RCPT command
-     *
-     * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
-    **/
-    public void onCommand(SMTPSession session) {
-        doRCPT(session, session.getCommandArgument());
-    }
-
+    private boolean doRCPT(SMTPSession session, String argument) {
+        String responseString = null;
 
-    /**
-     * Handler method called upon receipt of a RCPT command.
-     * Reads recipient.  Does some connection validation.
-     *
-     *
-     * @param session SMTP session object
-     * @param argument the argument passed in with the command by the SMTP client
-     */
-    private void doRCPT(SMTPSession session, String argument) {
-        String responseString = null;
-        StringBuffer responseBuffer = session.getResponseBuffer();
-        boolean maxRcptReached = false;
-        boolean useTarpit = false;
-        
         String recipient = null;
         if ((argument != null) && (argument.indexOf(":") > 0)) {
             int colonIndex = argument.indexOf(":");
@@ -123,14 +61,22 @@
             argument = argument.substring(0, colonIndex);
         }
         if (!session.getState().containsKey(SMTPSession.SENDER)) {
-            responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" Need MAIL before RCPT";
+            responseString = "503 "
+                    + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                            DSNStatus.DELIVERY_OTHER)
+                    + " Need MAIL before RCPT";
             session.writeResponse(responseString);
-        } else if (argument == null || !argument.toUpperCase(Locale.US).equals("TO")
-                   || recipient == null) {
-            responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_SYNTAX)+" Usage: RCPT TO:<recipient>";
+        } else if (argument == null
+                || !argument.toUpperCase(Locale.US).equals("TO")
+                || recipient == null) {
+            responseString = "501 "
+                    + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                            DSNStatus.DELIVERY_SYNTAX)
+                    + " Usage: RCPT TO:<recipient>";
             session.writeResponse(responseString);
         } else {
-            Collection rcptColl = (Collection) session.getState().get(SMTPSession.RCPT_LIST);
+            Collection rcptColl = (Collection) session.getState().get(
+                    SMTPSession.RCPT_LIST);
             if (rcptColl == null) {
                 rcptColl = new ArrayList();
             }
@@ -136,10 +82,12 @@
             }
             recipient = recipient.trim();
             int lastChar = recipient.lastIndexOf('>');
-            // Check to see if any options are present and, if so, whether they are correctly formatted
+            // Check to see if any options are present and, if so, whether they
+            // are correctly formatted
             // (separated from the closing angle bracket by a ' ').
             String rcptOptionString = null;
-            if ((lastChar > 0) && (recipient.length() > lastChar + 2) && (recipient.charAt(lastChar + 1) == ' ')) {
+            if ((lastChar > 0) && (recipient.length() > lastChar + 2)
+                    && (recipient.charAt(lastChar + 1) == ' ')) {
                 rcptOptionString = recipient.substring(lastChar + 2);
 
                 // Remove the options from the recipient
@@ -146,20 +94,22 @@
                 recipient = recipient.substring(0, lastChar + 1);
             }
             if (!recipient.startsWith("<") || !recipient.endsWith(">")) {
-                responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_SYNTAX)+" Syntax error in parameters or arguments";
+                responseString = "501 "
+                        + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                                DSNStatus.DELIVERY_SYNTAX)
+                        + " Syntax error in parameters or arguments";
                 session.writeResponse(responseString);
                 if (getLogger().isErrorEnabled()) {
-                    StringBuffer errorBuffer =
-                        new StringBuffer(192)
-                                .append("Error parsing recipient address: ")
-                                .append("Address did not start and end with < >")
-                                .append(getContext(session,null,recipient));
+                    StringBuffer errorBuffer = new StringBuffer(192).append(
+                            "Error parsing recipient address: ").append(
+                            "Address did not start and end with < >").append(
+                            getContext(session, null, recipient));
                     getLogger().error(errorBuffer.toString());
                 }
-                return;
+                return true;
             }
             MailAddress recipientAddress = null;
-            //Remove < and >
+            // Remove < and >
             recipient = recipient.substring(1, recipient.length() - 1);
             if (recipient.indexOf("@") < 0) {
                 recipient = recipient + "@localhost";
@@ -164,41 +114,58 @@
             if (recipient.indexOf("@") < 0) {
                 recipient = recipient + "@localhost";
             }
-            
+
             try {
                 recipientAddress = new MailAddress(recipient);
+
+                session.getState().put(SMTPSession.CURRENT_RCPT,
+                        recipientAddress);
             } catch (Exception pe) {
                 /*
-                 * from RFC2822;
-                 * 553 Requested action not taken: mailbox name not allowed
-                 *     (e.g., mailbox syntax incorrect)
+                 * from RFC2822; 553 Requested action not taken: mailbox name
+                 * not allowed (e.g., mailbox syntax incorrect)
                  */
-                responseString = "553 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX)+" Syntax error in recipient address";
+                responseString = "553 "
+                        + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                                DSNStatus.ADDRESS_SYNTAX)
+                        + " Syntax error in recipient address";
                 session.writeResponse(responseString);
 
                 if (getLogger().isErrorEnabled()) {
-                    StringBuffer errorBuffer =
-                        new StringBuffer(192)
-                                .append("Error parsing recipient address: ")
-                                .append(getContext(session,recipientAddress,recipient))
-                                .append(pe.getMessage());
+                    StringBuffer errorBuffer = new StringBuffer(192).append(
+                            "Error parsing recipient address: ").append(
+                            getContext(session, recipientAddress, recipient))
+                            .append(pe.getMessage());
                     getLogger().error(errorBuffer.toString());
                 }
-                return;
+                return true;
             }
 
-            if (session.isBlockListed() &&                                                // was found in the RBL
-                (!session.isRelayingAllowed() || (session.isAuthRequired() && session.getUser() == null)) &&  // Not an authorized IP or SMTP AUTH is enabled and not authenticated
-                !(recipientAddress.getUser().equalsIgnoreCase("postmaster") || recipientAddress.getUser().equalsIgnoreCase("abuse"))) {
-                
+            if (session.isBlockListed()
+                    && // was found in the RBL
+                    (!session.isRelayingAllowed() || (session.isAuthRequired() && session
+                            .getUser() == null))
+                    && // Not an authorized IP or SMTP AUTH is enabled and not
+                        // authenticated
+                    !(recipientAddress.getUser().equalsIgnoreCase("postmaster") || recipientAddress
+                            .getUser().equalsIgnoreCase("abuse"))) {
+
                 // trying to send e-mail to other than postmaster or abuse
                 if (session.getBlockListedDetail() != null) {
-                    responseString = "530 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" " + session.getBlockListedDetail();
+                    responseString = "530 "
+                            + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                                    DSNStatus.SECURITY_AUTH) + " "
+                            + session.getBlockListedDetail();
                 } else {
-                    responseString = "530 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_AUTH)+" Rejected: unauthenticated e-mail from " + session.getRemoteIPAddress() + " is restricted.  Contact the postmaster for details.";
+                    responseString = "530 "
+                            + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                                    DSNStatus.SECURITY_AUTH)
+                            + " Rejected: unauthenticated e-mail from "
+                            + session.getRemoteIPAddress()
+                            + " is restricted.  Contact the postmaster for details.";
                 }
                 session.writeResponse(responseString);
-                return;
+                return true;
             }
 
             if (session.isAuthRequired() && !session.isRelayingAllowed()) {
@@ -206,14 +173,20 @@
                 // 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";
+                    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));
+                        sb
+                                .append("Rejected message - authentication is required for mail request");
+                        sb.append(getContext(session, recipientAddress,
+                                recipient));
                         getLogger().error(sb.toString());
-                        return;
+                        return true;
                     }
                 } else {
                     // Identity verification checking
@@ -218,24 +191,34 @@
                 } else {
                     // Identity verification checking
                     if (session.getConfigurationData().isVerifyIdentity()) {
-                        String authUser = (session.getUser()).toLowerCase(Locale.US);
-                        MailAddress senderAddress = (MailAddress) session.getState().get(SMTPSession.SENDER);
+                        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";
+                        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)
+                                StringBuffer errorBuffer = new StringBuffer(128)
                                         .append("User ")
                                         .append(authUser)
-                                        .append(" authenticated, however tried sending email as ")
-                                        .append(senderAddress)
-                                        .append(getContext(session,recipientAddress,recipient));
+                                        .append(
+                                                " authenticated, however tried sending email as ")
+                                        .append(senderAddress).append(
+                                                getContext(session,
+                                                        recipientAddress,
+                                                        recipient));
                                 getLogger().error(errorBuffer.toString());
                             }
-                            return;
+                            return true;
                         }
                     }
                 }
@@ -241,17 +224,22 @@
                 }
             } 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";
+                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));
+                    StringBuffer errorBuffer = new StringBuffer(128).append(
+                            "Rejected message - ").append(
+                            session.getRemoteIPAddress()).append(
+                            " not authorized to relay to ").append(toDomain)
+                            .append(
+                                    getContext(session, recipientAddress,
+                                            recipient));
                     getLogger().error(errorBuffer.toString());
-                    return;
+                    return true;
                 }
             }
             if (rcptOptionString != null) {
@@ -256,114 +244,77 @@
             }
             if (rcptOptionString != null) {
 
-              StringTokenizer optionTokenizer = new StringTokenizer(rcptOptionString, " ");
-              while (optionTokenizer.hasMoreElements()) {
-                  String rcptOption = optionTokenizer.nextToken();
-                  int equalIndex = rcptOption.indexOf('=');
-                  String rcptOptionName = rcptOption;
-                  String rcptOptionValue = "";
-                  if (equalIndex > 0) {
-                      rcptOptionName = rcptOption.substring(0, equalIndex).toUpperCase(Locale.US);
-                      rcptOptionValue = rcptOption.substring(equalIndex + 1);
-                  }
-                  // Unexpected option attached to the RCPT command
-                  if (getLogger().isDebugEnabled()) {
-                      StringBuffer debugBuffer =
-                          new StringBuffer(128)
-                              .append("RCPT command had unrecognized/unexpected option ")
-                              .append(rcptOptionName)
-                              .append(" with value ")
-                              .append(rcptOptionValue)
-                              .append(getContext(session,recipientAddress,recipient));
-                      getLogger().debug(debugBuffer.toString());
-                  }
-              }
-              optionTokenizer = null;
-            }
-            
-            // check if we should check for max recipients
-            if (maxRcpt > 0) {
-                int rcptCount = 0;
-            
-                // check if the key exists
-                rcptCount = getRcptCount(session);
-                
-                rcptCount++;
-        
-                // check if the max recipients has reached
-                if (rcptCount > maxRcpt) {
-                    maxRcptReached = true;
-                    responseString = "452 "+DSNStatus.getStatus(DSNStatus.NETWORK,DSNStatus.DELIVERY_TOO_MANY_REC)+" Requested action not taken: max recipients reached";
-                    session.writeResponse(responseString);
-                    getLogger().error(responseString);
-                }
-                
-                // put the recipient cound in session hashtable
-                session.getState().put(RCPTCOUNT,Integer.toString(rcptCount));
-            }
-            
-            // check if we should use tarpit
-            if (tarpitRcptCount > 0) {
-                int rcptCount = 0;
-                rcptCount = getRcptCount(session);
-                rcptCount++;
-                
-                if (rcptCount > tarpitRcptCount) {
-                    useTarpit = true;                   
+                StringTokenizer optionTokenizer = new StringTokenizer(
+                        rcptOptionString, " ");
+                while (optionTokenizer.hasMoreElements()) {
+                    String rcptOption = optionTokenizer.nextToken();
+                    int equalIndex = rcptOption.indexOf('=');
+                    String rcptOptionName = rcptOption;
+                    String rcptOptionValue = "";
+                    if (equalIndex > 0) {
+                        rcptOptionName = rcptOption.substring(0, equalIndex)
+                                .toUpperCase(Locale.US);
+                        rcptOptionValue = rcptOption.substring(equalIndex + 1);
+                    }
+                    // Unexpected option attached to the RCPT command
+                    if (getLogger().isDebugEnabled()) {
+                        StringBuffer debugBuffer = new StringBuffer(128)
+                                .append(
+                                        "RCPT command had unrecognized/unexpected option ")
+                                .append(rcptOptionName).append(" with value ")
+                                .append(rcptOptionValue).append(
+                                        getContext(session, recipientAddress,
+                                                recipient));
+                        getLogger().debug(debugBuffer.toString());
+                    }
                 }
-                
-                // put the recipient cound in session hashtable
-                session.getState().put(RCPTCOUNT,Integer.toString(rcptCount));
-                 
-            }
-            
-            if (maxRcptReached == false) {
-                rcptColl.add(recipientAddress);
-                session.getState().put(SMTPSession.RCPT_LIST, rcptColl);
-                responseBuffer.append("250 "+DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.ADDRESS_VALID)+" Recipient <")
-                              .append(recipient)
-                              .append("> OK");
-                responseString = session.clearResponseBuffer();
-                
-                if (useTarpit == true) {
-                    try {
-                        sleep(tarpitSleepTime);
-                    } catch (InterruptedException e) { }
-                }
-                session.writeResponse(responseString);
+                optionTokenizer = null;
             }
         }
+        return false;
     }
 
-
-    private String getContext(SMTPSession session, MailAddress recipientAddress, String recipient){
+    private String getContext(SMTPSession session,
+            MailAddress recipientAddress, String recipient) {
         StringBuffer sb = new StringBuffer(128);
-        if(null!=recipientAddress) {
-            sb.append(" [to:" + (recipientAddress).toInternetAddress().getAddress() + "]");
-        } else if(null!=recipient) {
+        if (null != recipientAddress) {
+            sb
+                    .append(" [to:"
+                            + (recipientAddress).toInternetAddress()
+                                    .getAddress() + "]");
+        } else if (null != recipient) {
             sb.append(" [to:" + recipient + "]");
         }
-        if (null!=session.getState().get(SMTPSession.SENDER)) {
-            sb.append(" [from:" + ((MailAddress)session.getState().get(SMTPSession.SENDER)).toInternetAddress().getAddress() + "]");
+        if (null != session.getState().get(SMTPSession.SENDER)) {
+            sb
+                    .append(" [from:"
+                            + ((MailAddress) session.getState().get(
+                                    SMTPSession.SENDER)).toInternetAddress()
+                                    .getAddress() + "]");
         }
         return sb.toString();
-    } 
-    
-    
-    private int getRcptCount(SMTPSession session) {
-        int startCount = 0;
-        
-        // check if the key exists
-        if (session.getState().get(RCPTCOUNT) != null) {
-            Integer rcptCountInteger = Integer.valueOf(session.getState().get(RCPTCOUNT).toString());
-            return rcptCountInteger.intValue();
-        } else {
-            return startCount;
+    }
+
+    public void finalizeCommand(SMTPSession session) {
+        String responseString = null;
+        StringBuffer responseBuffer = session.getResponseBuffer();
+
+        Collection rcptColl = (Collection) session.getState().get(
+                SMTPSession.RCPT_LIST);
+        if (rcptColl == null) {
+            rcptColl = new ArrayList();
         }
-    }
-    
-    
-    public void sleep(float timeInMillis) throws InterruptedException {
-        Thread.sleep( (long) timeInMillis );
+        MailAddress recipientAddress = (MailAddress) session.getState().get(
+                SMTPSession.CURRENT_RCPT);
+
+        rcptColl.add(recipientAddress);
+        session.getState().put(SMTPSession.RCPT_LIST, rcptColl);
+        responseBuffer.append(
+                "250 "
+                        + DSNStatus.getStatus(DSNStatus.SUCCESS,
+                                DSNStatus.ADDRESS_VALID) + " Recipient <")
+                .append(recipientAddress).append("> OK");
+        responseString = session.clearResponseBuffer();
+        session.writeResponse(responseString);
     }
 }
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPHandler.java	(revision 417037)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPHandler.java	(working copy)
@@ -20,6 +20,10 @@
 import org.apache.avalon.framework.container.ContainerUtil;
 import org.apache.james.Constants;
 import org.apache.james.core.AbstractJamesHandler;
+import org.apache.james.smtpserver.filter.EhloFilterHandler;
+import org.apache.james.smtpserver.filter.HeloFilterHandler;
+import org.apache.james.smtpserver.filter.MailFilterHandler;
+import org.apache.james.smtpserver.filter.RcptFilterHandler;
 import org.apache.james.util.CRLFTerminatedReader;
 import org.apache.james.util.watchdog.Watchdog;
 import org.apache.mailet.Mail;
@@ -267,13 +271,90 @@
           } 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;
-                  }
-              }
+                  if (commandHandlers.get(i) instanceof CommandHandler) {
+                        ((CommandHandler) commandHandlers.get(i))
+                                .onCommand(this);
+                    } else {
+                        boolean m = false;
+                        boolean match = ((ExtendableCommandHandler) commandHandlers
+                                .get(i)).onCommand(this);
+
+                        if (match == false) {
+                            if (curCommandName.equals("EHLO")) {
+                                int fCount = handlerChain
+                                        .getEhloFilterHandlers().size();
+
+                                for (int i2 = 0; i2 < fCount; i2++) {
+                                    // call the filter
+                                    m = ((EhloFilterHandler) handlerChain
+                                            .getEhloFilterHandlers().get(i2))
+                                            .onEhloCommand(this);
+
+                                    // break the loop if it matched
+                                    if (m == true)
+                                        break;
+                                }
+                            } else if (curCommandName.equals("HELO")) {
+                                int fCount = handlerChain
+                                        .getEhloFilterHandlers().size();
+
+                                for (int i2 = 0; i2 < fCount; i2++) {
+                                    // call the filter
+                                    m = ((HeloFilterHandler) handlerChain
+                                            .getHeloFilterHandlers().get(i2))
+                                            .onHeloCommand(this);
+
+                                    // break the loop if it matched
+                                    if (m == true)
+                                        break;
+                                }
+
+                            } else if (curCommandName.equals("MAIL")) {
+                                int fCount = handlerChain
+                                        .getMailFilterHandlers().size();
+
+                                for (int i2 = 0; i2 < fCount; i2++) {
+                                    // call the filter
+                                    m = ((MailFilterHandler) handlerChain
+                                            .getMailFilterHandlers().get(i2))
+                                            .onMailCommand(this);
+
+                                    // break the loop if it matched
+                                    if (m == true)
+                                        break;
+                                }
+
+                            } else if (curCommandName.equals("RCPT")) {
+
+                                int fCount = handlerChain
+                                        .getRcptFilterHandlers().size();
+
+                                for (int i2 = 0; i2 < fCount; i2++) {
+                                    // call the filter
+                                    m = ((RcptFilterHandler) handlerChain
+                                            .getRcptFilterHandlers().get(i2))
+                                            .onRcptCommand(this);
+
+                                    // break the loop if it matched
+                                    if (m == true)
+                                        break;
+                                }
+                            } else if (curCommandName.equals("DATA")) {
+                                // TODO: implement this
+                            }
+                            // if not matched before finalize the handler
+                            if (m == false)
+                                ((ExtendableCommandHandler) commandHandlers
+                                        .get(i)).finalizeCommand(this);
+                        }
+
+                    }
+                    theWatchdog.reset();
+                    //if the response is received, stop processing of command handlers
+                    if (mode != COMMAND_MODE) {
+                        break;
+                    }
+                }
 
           }
 
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPHandlerChain.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPHandlerChain.java	(revision 416301)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPHandlerChain.java	(working copy)
@@ -30,6 +30,11 @@
 import org.apache.avalon.framework.service.ServiceException;
 import org.apache.avalon.framework.service.ServiceManager;
 import org.apache.avalon.framework.service.Serviceable;
+import org.apache.james.smtpserver.filter.DataFilterHandler;
+import org.apache.james.smtpserver.filter.EhloFilterHandler;
+import org.apache.james.smtpserver.filter.HeloFilterHandler;
+import org.apache.james.smtpserver.filter.MailFilterHandler;
+import org.apache.james.smtpserver.filter.RcptFilterHandler;
 
 import java.util.ArrayList;
 import java.util.Enumeration;
@@ -46,6 +51,11 @@
 public class SMTPHandlerChain extends AbstractLogEnabled implements Configurable, Serviceable, Contextualizable, Initializable {
 
     private HashMap commandHandlerMap = new HashMap();
+    private ArrayList ehloFilterHandlers = new ArrayList();
+    private ArrayList heloFilterHandlers = new ArrayList();
+    private ArrayList mailFilterHandlers = new ArrayList();
+    private ArrayList rcptFilterHandlers = new ArrayList();
+    private ArrayList dataFilterHandlers = new ArrayList();
     private ArrayList messageHandlers = new ArrayList();
     private ArrayList connectHandlers = new ArrayList();
 
@@ -137,6 +147,17 @@
                                 }
 
                             }
+                            
+                            //if it is a command handler add it to the map with key as command name
+                            if(handler instanceof ExtendableCommandHandler) {
+                                String commandName = children[i].getAttribute("command");
+                                commandName = commandName.toUpperCase(Locale.US);
+                                addToMap(commandName, (ExtendableCommandHandler)handler);
+                                if (getLogger().isInfoEnabled()) {
+                                    getLogger().info("Added Commandhandler: " + className);
+                                }
+
+                            }
 
                             //if it is a message handler add it to list of message handlers
                             if(handler instanceof MessageHandler) {
@@ -145,6 +166,46 @@
                                     getLogger().info("Added MessageHandler: " + className);
                                 }
                             }
+                            
+                            if(handler instanceof EhloFilterHandler) {
+                                ehloFilterHandlers.add((EhloFilterHandler)handler);
+                                if (getLogger().isInfoEnabled()) {
+                                    getLogger().info("Added EhloFilterHandler: " + className);
+                                }
+                                
+                            }
+                            
+                            if(handler instanceof HeloFilterHandler) {
+                                heloFilterHandlers.add((HeloFilterHandler)handler);
+                                if (getLogger().isInfoEnabled()) {
+                                    getLogger().info("Added HeloFilterHandler: " + className);
+                                }
+                                
+                            }
+                            
+                            if(handler instanceof MailFilterHandler) {
+                                mailFilterHandlers.add((MailFilterHandler)handler);
+                                if (getLogger().isInfoEnabled()) {
+                                    getLogger().info("Added MailFilterHandler: " + className);
+                                }
+                                
+                            }
+                            
+                            if(handler instanceof RcptFilterHandler) {
+                                rcptFilterHandlers.add((RcptFilterHandler)handler);
+                                if (getLogger().isInfoEnabled()) {
+                                    getLogger().info("Added RcptFilterHandler: " + className);
+                                }
+                                
+                            }
+                            
+                            if(handler instanceof DataFilterHandler) {
+                                dataFilterHandlers.add((DataFilterHandler)handler);
+                                if (getLogger().isInfoEnabled()) {
+                                    getLogger().info("Added DataFilterHandler: " + className);
+                                }
+                                
+                            }
 
                         } catch (ClassNotFoundException ex) {
                            if (getLogger().isErrorEnabled()) {
@@ -239,6 +300,15 @@
         }
         handlers.add(cmdHandler);
     }
+    
+    private void addToMap(String commandName, ExtendableCommandHandler 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
@@ -278,5 +348,25 @@
     List getConnectHandlers() {
         return connectHandlers;
     }
+    
+    List getEhloFilterHandlers() {
+        return ehloFilterHandlers;
+    }
+    
+    List getHeloFilterHandlers() {
+        return heloFilterHandlers;
+    }
+    
+    List getMailFilterHandlers() {
+        return mailFilterHandlers;
+    }
+    
+    List getRcptFilterHandlers() {
+        return rcptFilterHandlers;
+    }
+    
+    List getDataFilterHandlers() {
+        return dataFilterHandlers;
+    }
 
 }
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPSession.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPSession.java	(revision 416301)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/SMTPSession.java	(working copy)
@@ -35,8 +35,10 @@
     // Keys used to store/lookup data in the internal state hash map
     public final static String MESG_FAILED = "MESG_FAILED";   // Message failed flag
     public final static String SENDER = "SENDER_ADDRESS";     // Sender's email address
+    public final static String CURRENT_RCPT = "CURRENT_RCPT"; // Current recipient
     public final static String RCPT_LIST = "RCPT_LIST";   // The message recipients
     public final static String CURRENT_HELO_MODE = "CURRENT_HELO_MODE"; // HELO or EHLO
+    public final static String RCPTCOUNT = "RCPT_COUNT"; //  recipient count
 
     /**
      * Writes response string to the client
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/DataFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/DataFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/DataFilterHandler.java	(revision 0)
@@ -0,0 +1,29 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+import org.apache.james.smtpserver.SMTPSession;
+
+/**
+ * Data filter handlers must implement this interface
+ */
+public interface DataFilterHandler {
+    
+    // run the filter
+    public boolean onDataCommand(SMTPSession session);
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/EhloFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/EhloFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/EhloFilterHandler.java	(revision 0)
@@ -0,0 +1,30 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+import org.apache.james.smtpserver.SMTPSession;
+
+
+/**
+ * Ehlo filter handlers must implement this interface
+ */
+public interface EhloFilterHandler {
+    
+    // run the filter
+    public boolean onEhloCommand(SMTPSession session);
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/HeloFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/HeloFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/HeloFilterHandler.java	(revision 0)
@@ -0,0 +1,30 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+import org.apache.james.smtpserver.SMTPSession;
+
+
+/**
+ * Helo filter handlers must implement this interface
+ */
+public interface HeloFilterHandler {
+    
+    // run the filter
+    public boolean onHeloCommand(SMTPSession session);
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/MailFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/MailFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/MailFilterHandler.java	(revision 0)
@@ -0,0 +1,30 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+import org.apache.james.smtpserver.SMTPSession;
+
+
+/**
+ * Mail filter handlers must implement this interface
+ */
+public interface MailFilterHandler {
+    
+    // run the filter
+    public boolean onMailCommand(SMTPSession session);
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/MaxRcptFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/MaxRcptFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/MaxRcptFilterHandler.java	(revision 0)
@@ -0,0 +1,99 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+import java.util.Collection;
+
+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.logger.AbstractLogEnabled;
+import org.apache.james.smtpserver.SMTPSession;
+import org.apache.james.util.mail.dsn.DSNStatus;
+
+/**
+ * Handles RCPT command
+ */
+public class MaxRcptFilterHandler extends AbstractLogEnabled implements
+        RcptFilterHandler, Configurable {
+
+    private int maxRcpt = 0;
+
+    /**
+     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+     */
+    public void configure(Configuration handlerConfiguration)
+            throws ConfigurationException {
+        Configuration configuration = handlerConfiguration.getChild("maxRcpt",
+                false);
+        if (configuration != null) {
+            setMaxRcpt(configuration.getValueAsInteger(0));
+        } else {
+            throw new ConfigurationException(
+                    "Please set the maxRcpt configuration value");
+        }
+    }
+
+    /**
+     * Set the max rcpt for wich should be accepted
+     *  
+     * @param maxRcpt The max rcpt count
+     */
+    public void setMaxRcpt(int maxRcpt) {
+        this.maxRcpt = maxRcpt;
+    }
+
+    private int getRcptCount(SMTPSession session) {
+        int startCount = 0;
+
+        // check if the key exists
+        if (session.getState().get(SMTPSession.RCPT_LIST) != null) {
+            return ((Collection) session.getState().get(SMTPSession.RCPT_LIST))
+                    .size();
+        } else {
+            return startCount;
+        }
+    }
+
+    public void sleep(float timeInMillis) throws InterruptedException {
+        Thread.sleep((long) timeInMillis);
+    }
+
+    public boolean onRcptCommand(SMTPSession session) {
+        String responseString = null;
+        int rcptCount = 0;
+
+        // check if the key exists
+        rcptCount = getRcptCount(session);
+
+        rcptCount++;
+        
+        // check if the max recipients has reached
+        if (rcptCount > maxRcpt) {
+            responseString = "452 "
+                    + DSNStatus.getStatus(DSNStatus.NETWORK,
+                            DSNStatus.DELIVERY_TOO_MANY_REC)
+                    + " Requested action not taken: max recipients reached";
+            session.writeResponse(responseString);
+            getLogger().error(responseString);
+            return true;
+        }
+        return false;
+
+    }
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/RcptFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/RcptFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/RcptFilterHandler.java	(revision 0)
@@ -0,0 +1,30 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+import org.apache.james.smtpserver.SMTPSession;
+
+
+/**
+ * Rcpt filter handlers must implement this interface
+ */
+public interface RcptFilterHandler {
+    
+    // run the filter
+    public boolean onRcptCommand(SMTPSession session);
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ResolvableEhloHeloFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ResolvableEhloHeloFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ResolvableEhloHeloFilterHandler.java	(revision 0)
@@ -0,0 +1,115 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+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.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.james.services.DNSServer;
+import org.apache.james.smtpserver.SMTPSession;
+import org.apache.james.util.mail.dsn.DSNStatus;
+
+import java.net.UnknownHostException;
+
+/**
+ * Handles EHLO command
+ */
+public class ResolvableEhloHeloFilterHandler extends AbstractLogEnabled
+        implements EhloFilterHandler, HeloFilterHandler, Configurable,
+        Serviceable {
+
+    private boolean checkAuthNetworks = false;
+
+    private DNSServer dnsServer = null;
+
+    /**
+     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+     */
+    public void configure(Configuration handlerConfiguration)
+            throws ConfigurationException {
+        Configuration configRelay = handlerConfiguration.getChild(
+                "checkAuthNetworks", false);
+        if (configRelay != null) {
+            setCheckAuthNetworks(configRelay.getValueAsBoolean(false));
+        }
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
+     */
+    public void service(ServiceManager serviceMan) throws ServiceException {
+        setDnsServer((DNSServer) serviceMan.lookup(DNSServer.ROLE));
+    }
+
+    /**
+     * Set to true if AuthNetworks should be included in the EHLO check
+     * 
+     * @param checkAuthNetworks
+     *            Set to true to enable
+     */
+    public void setCheckAuthNetworks(boolean checkAuthNetworks) {
+        this.checkAuthNetworks = checkAuthNetworks;
+    }
+
+    /**
+     * Set the DNSServer
+     * 
+     * @param dnsServer
+     *            The DNSServer
+     */
+    public void setDnsServer(DNSServer dnsServer) {
+        this.dnsServer = dnsServer;
+    }
+
+    public boolean onHeloCommand(SMTPSession session) {
+        return onEhloCommand(session);
+    }
+
+    public boolean onEhloCommand(SMTPSession session) {
+        String argument = session.getCommandArgument();
+        String responseString = null;
+
+        /**
+         * don't check if the ip address is allowed to relay. Only check if it
+         * is set in the config. ed.
+         */
+        if (!session.isRelayingAllowed() || checkAuthNetworks) {
+            // try to resolv the provided helo. If it can not resolved do not
+            // accept it.
+            try {
+                dnsServer.getByName(argument);
+            } catch (UnknownHostException e) {
+                responseString = "501 "
+                        + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                                DSNStatus.DELIVERY_INVALID_ARG)
+                        + " Provided EHLO/HELO " + argument
+                        + " can not resolved";
+                session.writeResponse(responseString);
+                getLogger().info(responseString);
+
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ReverseEqualsEhloHeloFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ReverseEqualsEhloHeloFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ReverseEqualsEhloHeloFilterHandler.java	(revision 0)
@@ -0,0 +1,128 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+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.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.james.services.DNSServer;
+import org.apache.james.smtpserver.SMTPSession;
+import org.apache.james.util.mail.dsn.DSNStatus;
+
+import java.net.UnknownHostException;
+
+/**
+ * Handles EHLO command
+ */
+public class ReverseEqualsEhloHeloFilterHandler extends AbstractLogEnabled
+        implements EhloFilterHandler, HeloFilterHandler, Configurable,
+        Serviceable {
+
+    private boolean checkAuthNetworks = false;
+
+    private DNSServer dnsServer = null;
+
+    /**
+     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+     */
+    public void configure(Configuration handlerConfiguration)
+            throws ConfigurationException {
+        Configuration configRelay = handlerConfiguration.getChild(
+                "checkAuthNetworks", false);
+        if (configRelay != null) {
+            setCheckAuthNetworks(configRelay.getValueAsBoolean(false));
+        }
+    }
+
+    /**
+     * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
+     */
+    public void service(ServiceManager serviceMan) throws ServiceException {
+        setDnsServer((DNSServer) serviceMan.lookup(DNSServer.ROLE));
+    }
+
+    /**
+     * Set to true if AuthNetworks should be included in the EHLO check
+     * 
+     * @param checkAuthNetworks
+     *            Set to true to enable
+     */
+    public void setCheckAuthNetworks(boolean checkAuthNetworks) {
+        this.checkAuthNetworks = checkAuthNetworks;
+    }
+
+    /**
+     * Set the DNSServer
+     * 
+     * @param dnsServer
+     *            The DNSServer
+     */
+    public void setDnsServer(DNSServer dnsServer) {
+        this.dnsServer = dnsServer;
+    }
+
+    public boolean onHeloCommand(SMTPSession session) {
+        return onEhloCommand(session);
+    }
+
+    public boolean onEhloCommand(SMTPSession session) {
+        String argument = session.getCommandArgument();
+        String responseString = null;
+
+        /**
+         * don't check if the ip address is allowed to relay. Only check if it
+         * is set in the config. ed.
+         */
+        if (!session.isRelayingAllowed() || checkAuthNetworks) {
+            try {
+                // get reverse entry
+                String reverse = dnsServer.getByName(
+                        session.getRemoteIPAddress()).getHostName();
+
+                if (!argument.equals(reverse)) {
+                    responseString = "501 "
+                            + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                                    DSNStatus.DELIVERY_INVALID_ARG)
+                            + " Provided EHLO " + argument
+                            + " not equal reverse of "
+                            + session.getRemoteIPAddress();
+
+                    session.writeResponse(responseString);
+                    getLogger().info(responseString);
+                    return true;
+                }
+            } catch (UnknownHostException e) {
+                responseString = "501 "
+                        + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                                DSNStatus.DELIVERY_INVALID_ARG)
+                        + " Ipaddress " + session.getRemoteIPAddress()
+                        + " can not resolved";
+
+                session.writeResponse(responseString);
+                getLogger().info(responseString);
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/TarpitFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/TarpitFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/TarpitFilterHandler.java	(revision 0)
@@ -0,0 +1,112 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+import java.util.Collection;
+
+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.logger.AbstractLogEnabled;
+import org.apache.james.smtpserver.SMTPSession;
+
+/**
+ * Handles RCPT command
+ */
+public class TarpitFilterHandler extends AbstractLogEnabled implements
+        RcptFilterHandler, Configurable {
+
+    private int tarpitRcptCount = 0;
+
+    private long tarpitSleepTime = 5000;
+
+    /**
+     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+     */
+    public void configure(Configuration handlerConfiguration)
+            throws ConfigurationException {
+
+        Configuration configTarpitRcptCount = handlerConfiguration.getChild(
+                "tarpitRcptCount", false);
+        if (configTarpitRcptCount != null) {
+            setTarpitRcptCount(configTarpitRcptCount.getValueAsInteger(0));
+        }
+        
+        if (tarpitRcptCount == 0) throw new ConfigurationException("Please set the tarpitRcptCount bigger values as 0");
+
+        Configuration configTarpitSleepTime = handlerConfiguration.getChild(
+                "tarpitSleepTime", false);
+        if (configTarpitSleepTime != null) {
+            setTarpitSleepTime(configTarpitSleepTime.getValueAsLong(5000));
+        }
+        
+        if (tarpitSleepTime == 0) throw new ConfigurationException("Please set the tarpitSleepTimeto a bigger values as 0" );
+
+    }
+
+    /**
+     * Set the tarpit count after which the tarpit sleep time will be activated
+     * 
+     * @param tarpitRcptCount
+     */
+    public void setTarpitRcptCount(int tarpitRcptCount) {
+        this.tarpitRcptCount = tarpitRcptCount;
+    }
+
+    /**
+     * Set the tarpit sleep time
+     * 
+     * @param tarpitSleepTime
+     *            Time in milliseconds
+     */
+    public void setTarpitSleepTime(long tarpitSleepTime) {
+        this.tarpitSleepTime = tarpitSleepTime;
+    }
+
+    private int getRcptCount(SMTPSession session) {
+        int startCount = 0;
+
+        // check if the key exists
+        if (session.getState().get(SMTPSession.RCPT_LIST) != null) {
+            return ((Collection) session.getState().get(SMTPSession.RCPT_LIST))
+                    .size();
+        } else {
+            return startCount;
+        }
+    }
+
+    public void sleep(float timeInMillis) throws InterruptedException {
+        Thread.sleep((long) timeInMillis);
+    }
+
+    public boolean onRcptCommand(SMTPSession session) {
+        
+            int rcptCount = 0;
+            rcptCount = getRcptCount(session);
+            rcptCount++;
+
+            if (rcptCount > tarpitRcptCount) {
+                try {
+                    sleep(tarpitSleepTime);
+                } catch (InterruptedException e) {
+                }
+            }
+        // return false anyway cause we just want to slowdown the connection
+        return false;
+    }
+}
Index: /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ValidSenderDomainFilterHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ValidSenderDomainFilterHandler.java	(revision 0)
+++ /home/maurer/stuff/workspace/james-trunk2/src/java/org/apache/james/smtpserver/filter/ValidSenderDomainFilterHandler.java	(revision 0)
@@ -0,0 +1,108 @@
+/***********************************************************************
+ * 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.smtpserver.filter;
+
+import java.util.Collection;
+
+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.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.james.services.DNSServer;
+import org.apache.james.smtpserver.SMTPSession;
+import org.apache.james.util.mail.dsn.DSNStatus;
+import org.apache.mailet.MailAddress;
+
+/**
+  * Handles MAIL command
+  */
+public class ValidSenderDomainFilterHandler
+    extends AbstractLogEnabled
+    implements MailFilterHandler,Configurable, Serviceable {
+    
+    private boolean checkAuthClients = false;
+    
+    private DNSServer dnsServer = null;
+    
+    /**
+     * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
+     */
+    public void configure(Configuration handlerConfiguration) throws ConfigurationException {
+        
+        Configuration configRelay = handlerConfiguration.getChild("checkAuthClients",false);
+        if(configRelay != null) {
+            setCheckAuthClients(configRelay.getValueAsBoolean(false));
+        }
+    }
+    
+    /**
+     * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
+     */
+    public void service(ServiceManager serviceMan) throws ServiceException {
+        setDnsServer((DNSServer) serviceMan.lookup(DNSServer.ROLE));
+    }
+    
+    /**
+     * Set the DnsServer
+     * 
+     * @param dnsServer The DnsServer
+     */
+    public void setDnsServer(DNSServer dnsServer) {
+        this.dnsServer = dnsServer;
+    }
+    
+    /**
+     * Enable checking of authorized clients
+     * 
+     * @param checkAuthClients Set to true to enable
+     */
+    public void setCheckAuthClients(boolean checkAuthClients) {
+        this.checkAuthClients = checkAuthClients;
+    }
+    
+
+    public boolean onMailCommand(SMTPSession session) {
+        
+       String responseString = null;
+        MailAddress senderAddress = (MailAddress) session.getState().get(SMTPSession.SENDER);
+        
+        /**
+         * don't check if the ip address is allowed to relay. Only check if it is set in the config. 
+         */
+        if (checkAuthClients || !session.isRelayingAllowed()) {
+
+            // Maybe we should build a static method in org.apache.james.dnsserver.DNSServer ?
+            Collection records;
+        
+            
+            // try to resolv the provided domain in the senderaddress. If it can not resolved do not accept it.
+            records = dnsServer.findMXRecords(senderAddress.getHost());
+            if (records == null || records.size() == 0) {
+                responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.ADDRESS_SYNTAX_SENDER)+ " sender " + senderAddress + " contains a domain with no valid MX records";
+                session.writeResponse(responseString);
+                getLogger().info(responseString);
+                return true;
+            }
+
+        }
+        return false;
+    }
+}
