Index: /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/smtpserver/EhloCmdHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/smtpserver/EhloCmdHandler.java	(revision 407601)
+++ /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/smtpserver/EhloCmdHandler.java	(working copy)
@@ -31,9 +31,10 @@
 import java.util.ArrayList;
 
 /**
-  * Handles EHLO command
-  */
-public class EhloCmdHandler extends AbstractLogEnabled implements CommandHandler,Configurable,  Serviceable {
+ * Handles EHLO command
+ */
+public class EhloCmdHandler extends AbstractLogEnabled implements
+        CommandHandler, Configurable, Serviceable {
 
     /**
      * The name of the command handled by the command handler
@@ -44,26 +45,37 @@
      * set checkResolvableEhlo to false as default value
      */
     private boolean checkResolvableEhlo = false;
-    
+
+    private boolean checkReverseEqualEhlo = 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));
+    public void configure(Configuration handlerConfiguration)
+            throws ConfigurationException {
+        Configuration configuration = handlerConfiguration.getChild(
+                "checkResolvableEhlo", false);
+        if (configuration != null) {
+            setCheckResolvableEhlo(configuration.getValueAsBoolean(false));
+        }
+
+        Configuration config = handlerConfiguration.getChild(
+                "checkReverseEqualEhlo", false);
+        if (config != null) {
+            setCheckReverseEqualEhlo(config.getValueAsBoolean(false));
         }
-        
-        Configuration configRelay = handlerConfiguration.getChild("checkAuthNetworks",false);
-        if(configRelay != null) {
+
+        Configuration configRelay = handlerConfiguration.getChild(
+                "checkAuthNetworks", false);
+        if (configRelay != null) {
             setCheckAuthNetworks(configRelay.getValueAsBoolean(false));
         }
     }
-    
+
     /**
      * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
      */
@@ -70,11 +82,12 @@
     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
+     * @param checkResolvableEhlo
+     *            Set to true for enable check
      */
     public void setCheckResolvableEhlo(boolean checkResolvableEhlo) {
         this.checkResolvableEhlo = checkResolvableEhlo;
@@ -79,11 +92,21 @@
     public void setCheckResolvableEhlo(boolean checkResolvableEhlo) {
         this.checkResolvableEhlo = checkResolvableEhlo;
     }
-    
+
+    /**
+     * Set to true to enable check for reverse equal EHLO
+     * 
+     * @param checkReverseEqualEhlo Set to true for enable check
+     */
+    public void setCheckReverseEqualEhlo(boolean checkReverseEqualEhlo) {
+        this.checkReverseEqualEhlo = checkReverseEqualEhlo;
+    }
+
     /**
      * Set to true if AuthNetworks should be included in the EHLO check
      * 
-     * @param checkAuthNetworks Set to true to enable
+     * @param checkAuthNetworks
+     *            Set to true to enable
      */
     public void setCheckAuthNetworks(boolean checkAuthNetworks) {
         this.checkAuthNetworks = checkAuthNetworks;
@@ -88,11 +111,12 @@
     public void setCheckAuthNetworks(boolean checkAuthNetworks) {
         this.checkAuthNetworks = checkAuthNetworks;
     }
-    
+
     /**
      * Set the DNSServer
      * 
-     * @param dnsServer The DNSServer
+     * @param dnsServer
+     *            The DNSServer
      */
     public void setDnsServer(DNSServer dnsServer) {
         this.dnsServer = dnsServer;
@@ -100,9 +124,9 @@
 
     /*
      * processes EHLO command
-     *
+     * 
      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
-    **/
+     */
     public void onCommand(SMTPSession session) {
         doEHLO(session, session.getCommandArgument());
     }
@@ -108,12 +132,14 @@
     }
 
     /**
-     * Handler method called upon receipt of a EHLO 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
+     * Handler method called upon receipt of a EHLO 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 doEHLO(SMTPSession session, String argument) {
         String responseString = null;
@@ -119,17 +145,18 @@
         String responseString = null;
         StringBuffer responseBuffer = session.getResponseBuffer();
         boolean badEhlo = false;
-        
-        // check for resolvable EHLO if its set in config
-        if (checkResolvableEhlo) {
-            
-            /**
-             * 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) {
+
+        /**
+         * 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 to resolv the provided helo. If it can not resolved do
+                // not accept it.
                 try {
                     dnsServer.getByName(argument);
                 } catch (UnknownHostException e) {
@@ -134,7 +161,37 @@
                     dnsServer.getByName(argument);
                 } catch (UnknownHostException e) {
                     badEhlo = true;
-                    responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Provided EHLO " + argument + " can not resolved";
+                    responseString = "501 "
+                            + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                                    DSNStatus.DELIVERY_INVALID_ARG)
+                            + " Provided EHLO " + argument
+                            + " can not resolved";
+                    session.writeResponse(responseString);
+                    getLogger().info(responseString);
+                }
+            } else if (checkReverseEqualEhlo) {
+                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 "
+                                + reverse;
+                        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);
                 }
@@ -140,11 +197,14 @@
                 }
             }
         }
-        
+
         if (argument == null) {
-            responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Domain address required: " + COMMAND_NAME;
+            responseString = "501 "
+                    + DSNStatus.getStatus(DSNStatus.PERMANENT,
+                            DSNStatus.DELIVERY_INVALID_ARG)
+                    + " Domain address required: " + COMMAND_NAME;
             session.writeResponse(responseString);
-        } else if (!badEhlo){
+        } else if (!badEhlo) {
             session.resetState();
             session.getState().put(SMTPSession.CURRENT_HELO_MODE, COMMAND_NAME);
 
@@ -150,17 +210,14 @@
 
             ArrayList esmtpextensions = new ArrayList();
 
-            esmtpextensions.add(new StringBuffer(session.getConfigurationData().getHelloName())
-                .append(" Hello ")
-                .append(argument)
-                .append(" (")
-                .append(session.getRemoteHost())
-                .append(" [")
-                .append(session.getRemoteIPAddress())
-                .append("])").toString());
+            esmtpextensions.add(new StringBuffer(session.getConfigurationData()
+                    .getHelloName()).append(" Hello ").append(argument).append(
+                    " (").append(session.getRemoteHost()).append(" [").append(
+                    session.getRemoteIPAddress()).append("])").toString());
 
             // Extension defined in RFC 1870
-            long maxMessageSize = session.getConfigurationData().getMaxMessageSize();
+            long maxMessageSize = session.getConfigurationData()
+                    .getMaxMessageSize();
             if (maxMessageSize > 0) {
                 esmtpextensions.add("SIZE " + maxMessageSize);
             }
@@ -172,9 +229,8 @@
 
             esmtpextensions.add("PIPELINING");
             esmtpextensions.add("ENHANCEDSTATUSCODES");
-            // see http://issues.apache.org/jira/browse/JAMES-419 
-            //esmtpextensions.add("8BITMIME");
-
+            // see http://issues.apache.org/jira/browse/JAMES-419
+            // esmtpextensions.add("8BITMIME");
 
             // Iterator i = esmtpextensions.iterator();
             for (int i = 0; i < esmtpextensions.size(); i++) {
Index: /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/smtpserver/HeloCmdHandler.java
===================================================================
--- /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/smtpserver/HeloCmdHandler.java	(revision 407601)
+++ /home/maurer/stuff/workspace/james-dev/src/java/org/apache/james/smtpserver/HeloCmdHandler.java	(working copy)
@@ -17,7 +17,6 @@
 
 package org.apache.james.smtpserver;
 
-
 import java.net.UnknownHostException;
 import org.apache.avalon.framework.configuration.Configurable;
 import org.apache.avalon.framework.configuration.Configuration;
@@ -27,140 +26,180 @@
 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 CommandHandler,Configurable, Serviceable {
+	/**
+	 * The name of the command handled by the command handler
+	 */
+	private final static String COMMAND_NAME = "HELO";
+
+	/**
+	 * set checkValidHelo to false as default value
+	 */
+	private boolean checkResolvableHelo = false;
+
+	private boolean checkReverseEqualHelo = 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(
+				"checkReverseEqualHelo", false);
+		if (config != null) {
+			setCheckReverseEqualHelo(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 checkReverseEqualHelo Set to true for enable check
+	 */
+	public void setCheckReverseEqualHelo(boolean checkReverseEqualHelo) {
+		this.checkResolvableHelo = checkReverseEqualHelo;
+	}
+
+	/**
+	 * 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;
+	}
 
-    /**
-     * The name of the command handled by the command handler
-     */
-    private final static String COMMAND_NAME = "HELO";
+	/*
+	 * process HELO command
+	 *
+	 * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
+	 **/
+	public void onCommand(SMTPSession session) {
+		doHELO(session, session.getCommandArgument());
+	}
 
-    /**
-     * set checkValidHelo to false as default value
-     */
-    private boolean checkResolvableHelo = 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 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 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;
-    }
+	/**
+	 * 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) {
+		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) {
 
-       
-    /*
-     * process HELO command
-     *
-     * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
-    **/
-    public void onCommand(SMTPSession session) {
-        doHELO(session, session.getCommandArgument());
-    }
+			// check for resolvable HELO if its set in config
+			if (checkResolvableHelo) {
 
-    /**
-     * 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) {
-        String responseString = null;
-        boolean badHelo = false;
-                
-        
-        // check for resolvable HELO if its set in config
-        if (checkResolvableHelo) {
-            
-            /**
-             * 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) {
+					badHelo = true;
+					responseString = "501 Provided HELO " + argument
+							+ " can not resolved";
+					session.writeResponse(responseString);
+					getLogger().info(responseString);
+				}
 
-                // 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 (checkReverseEqualHelo) {
+			try {
+				// get reverse entry
+				String reverse = dnsServer.getByName(
+						session.getRemoteIPAddress()).getHostName();
 
-            }
-        }
-        
-        if (argument == null) {
-            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);
-        }
-    }
+				if (!argument.equals(reverse)) {
+					badHelo = true;
+					responseString = "501 "
+							+ DSNStatus.getStatus(DSNStatus.PERMANENT,
+									DSNStatus.DELIVERY_INVALID_ARG)
+							+ " Provided HELO " + argument
+							+ " not equal reverse of " + reverse;
+					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);
+			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);
+		}
+	}
 }
Index: /home/maurer/stuff/workspace/james-dev/src/conf/james-config.xml
===================================================================
--- /home/maurer/stuff/workspace/james-dev/src/conf/james-config.xml	(revision 407606)
+++ /home/maurer/stuff/workspace/james-dev/src/conf/james-config.xml	(working copy)
@@ -727,6 +727,12 @@
                 <checkResolvableHelo> false </checkResolvableHelo>
                 -->
                 
+                <!-- If is set to true helo is only accepted if it is equal the reverse of the -->
+                <!-- connecting client -->
+                <!--
+                <checkReverseEqualHelo> false </checkReverseEqualHelo>
+                -->
+                
                 <!-- If is set to true sender domain will be checked also for clients that -->
                 <!-- are allowed to relay. Default is false. -->
                 <!--
@@ -739,6 +745,12 @@
                 <checkResolvableEhlo> false </checkResolvableEhlo>
                 -->
                 
+                <!-- If is set to true ehlo is only accepted if it is equal the reverse of the -->
+                <!-- connecting client -->
+                <!--
+                <checkReverseEqualEhlo> false </checkReverseEqualEhlo>
+                -->
+                
                 <!-- If is set to true sender domain will be checked also for clients that -->
                 <!-- are allowed to relay. Default is false. -->
                 <!--
