Index: SMTPHandler.java
===================================================================
RCS file: /home/cvspublic/jakarta-james/src/java/org/apache/james/smtpserver/SMTPHandler.java,v
retrieving revision 1.17
diff -u -r1.17 SMTPHandler.java
--- SMTPHandler.java	17 Apr 2002 03:19:32 -0000	1.17
+++ SMTPHandler.java	3 Jun 2002 15:54:43 -0000
@@ -7,18 +7,20 @@
  */
 package org.apache.james.smtpserver;
 
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
 import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
 import org.apache.avalon.cornerstone.services.scheduler.PeriodicTimeTrigger;
 import org.apache.avalon.cornerstone.services.scheduler.Target;
 import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler;
+import org.apache.avalon.framework.activity.Disposable;
 import org.apache.avalon.framework.component.ComponentException;
 import org.apache.avalon.framework.component.ComponentManager;
 import org.apache.avalon.framework.component.Composable;
 import org.apache.avalon.framework.configuration.Configurable;
 import org.apache.avalon.framework.configuration.Configuration;
 import org.apache.avalon.framework.configuration.ConfigurationException;
-import org.apache.james.BaseConnectionHandler;
 import org.apache.james.Constants;
+import org.apache.james.core.AbstractServer;
 import org.apache.james.core.MailHeaders;
 import org.apache.james.core.MailImpl;
 import org.apache.james.services.MailServer;
@@ -41,15 +43,15 @@
  * @author Jason Borden <jborden@javasense.com>
  * @author Matthew Pangaro <mattp@lokitech.com>
  * @author Danny Angus <danny@thought.co.uk>
+ * @author Andrei Ivanov <myfam@surfeu.fi>
  *
-
  * This is $Revision: 1.17 $
  * Committed on $Date: 2002/04/17 03:19:32 $ by: $Author: serge $
 
  */
 public class SMTPHandler
-    extends BaseConnectionHandler
-    implements ConnectionHandler, Composable, Configurable, Target {
+    extends AbstractLogEnabled
+    implements ConnectionHandler, Composable, Configurable, Disposable, Target {
 
     public final static String SERVER_NAME = "SERVER_NAME";
     public final static String SERVER_TYPE = "SERVER_TYPE";
@@ -66,15 +68,15 @@
     public final static char[] SMTPTerminator = {'\r','\n','.','\r','\n'};
 
     private Socket socket;
-    private DataInputStream in;
-    private PrintWriter out;
 
     private String remoteHost;
     private String remoteHostGiven;
     private String remoteIP;
     private String messageID;
     private String smtpID;
-
+    
+    private int timeout;
+    private String helloName;   
     private boolean authRequired = false;
     private boolean verifyIdentity = false;
 
@@ -84,41 +86,74 @@
 
     private String softwaretype = "JAMES SMTP Server "
                                    + Constants.SOFTWARE_VERSION;
-    private static long count = 0;
-    private long connNumber = count++;
+    
+    private static long connCount = 0;
     private HashMap state       = new HashMap();
     private Random random       = new Random();
     private long maxmessagesize = 0;
     private int lengthReset = 20000;
-
-    public void configure ( Configuration configuration )
+    
+    public boolean disposed = false;    
+    private final String STOP_SCHED;
+    
+    /** Creates a new instance of SMTPHandler */
+    public SMTPHandler() {    
+        STOP_SCHED = SMTPHandler.class + Long.toString(connCount++);    
+    }
+  
+    public void configure ( Configuration conf )
            throws ConfigurationException {
-        super.configure(configuration);
-        authRequired
-           = configuration.getChild("authRequired").getValueAsBoolean(false);
-        verifyIdentity
-           = configuration.getChild("verifyIdentity").getValueAsBoolean(false);
+        timeout = conf.getAttributeAsInteger(SMTPServer.TIMEOUT_NAME);    
+        helloName = conf.getAttribute(SMTPServer.HELLO_NAME);    
+    
+        authRequired = conf.getAttributeAsBoolean(SMTPServer.AUTHREQ_NAME);
+        verifyIdentity = conf.getAttributeAsBoolean(SMTPServer.VERIFID_NAME);
         // get the message size limit from the conf file and multiply
         // by 1024, to put it in bytes
-        maxmessagesize =
-            configuration.getChild( "maxmessagesize" ).getValueAsLong( 0 ) * 1024;
-        getLogger().debug("Max message size is: " + maxmessagesize);
+        maxmessagesize = conf.getAttributeAsLong(SMTPServer.MSGSIZE_NAME);
         //how many bytes to read before updating the timer that data is being transfered
-        lengthReset = configuration.getChild("lengthReset").getValueAsInteger(20000);
+        lengthReset = conf.getAttributeAsInteger(SMTPServer.LENRES_NAME);    
     }
 
     public void compose( final ComponentManager componentManager )
         throws ComponentException {
-        mailServer = (MailServer)componentManager.lookup(
-                                 "org.apache.james.services.MailServer");
-        scheduler = (TimeScheduler)componentManager.lookup(
-            "org.apache.avalon.cornerstone.services.scheduler.TimeScheduler");
-        UsersStore usersStore = (UsersStore)componentManager.lookup(
-            "org.apache.james.services.UsersStore" );
+        mailServer = (MailServer)componentManager.lookup(MailServer.ROLE);
+        scheduler = (TimeScheduler)componentManager.lookup(TimeScheduler.ROLE);
+        UsersStore usersStore 
+                        = (UsersStore)componentManager.lookup(UsersStore.ROLE);
         users = usersStore.getRepository("LocalUsers");
     }
 
     /**
+      * The dispose operation is called at the end of a components lifecycle.
+      * This method will be called after Startable.stop() method (if implemented
+      * by component). Components use this method to release and destroy any
+      * resources that the Component owns.
+      */
+    public void dispose() {
+        try {
+            this.socket.close(); // socket itself is closed inside cornerstone as well
+        } catch ( IOException ioe ) {
+            getLogger().error("Exception disposing connection handler: " 
+                                                            + ioe.getMessage());
+        }
+        this.socket = null;
+        
+        try {
+            this.scheduler.removeTrigger(STOP_SCHED);
+        } catch ( NoSuchElementException ignore ) {}      
+        this.scheduler = null;
+
+        this.users = null;
+        this.mailServer = null;
+    
+        this.state.clear();
+        this.state = null;        
+    
+        disposed = true;  
+    }
+  
+    /**
      * Handle a connection.
      * This handler is responsible for processing connections as they occur.
      *
@@ -130,11 +165,7 @@
         throws IOException {
         try {
             this.socket = connection;
-            final InputStream bufferedInput =
-                new BufferedInputStream( socket.getInputStream(), 1024 );
-            in = new DataInputStream( bufferedInput );
-            out = new InternetPrintWriter(socket.getOutputStream(), true);
-
+            
             remoteHost = socket.getInetAddress ().getHostName ();
             remoteIP = socket.getInetAddress ().getHostAddress ();
             smtpID = Math.abs(random.nextInt() % 1024) + "";
@@ -150,6 +181,13 @@
                          + remoteIP + ")");
 
         try {
+          
+            InputStream socketIn = socket.getInputStream();
+            BufferedReader in 
+                  = new BufferedReader(new InputStreamReader(socketIn), 1024);
+            PrintWriter out = new InternetPrintWriter(
+                                              socket.getOutputStream(), true);                           
+          
             // Initially greet the connector
             // Format is:  Sat,  24 Jan 1998 13:16:09 -0500
 
@@ -160,10 +198,13 @@
                         + softwaretype + ") ready "
                         + RFC822DateFormat.toString(new Date()));
 
-            while  (parseCommand(in.readLine())) {
+            while  ( parseCommand(in.readLine(), out, in, socketIn) ) {
                 scheduler.resetTrigger(this.toString());
             }
-            socket.close();
+            in.close();
+            socketIn.close();
+            out.close();
+            socket.close();            
             scheduler.removeTrigger(this.toString());
         } catch (SocketException se) {
             getLogger().debug("Socket to " + remoteHost
@@ -189,13 +230,12 @@
     public void targetTriggered( final String triggerName ) {
         getLogger().error("Connection timeout on socket");
         try {
-            out.println("Connection timeout. Closing connection");
             socket.close();
         } catch (IOException e) {
         }
     }
 
- private void resetState() {
+    private void resetState() {
         String user = (String) state.get(AUTH);
 
         state.clear();
@@ -212,13 +252,14 @@
     }
 
 
-    private boolean parseCommand(String command)
+    private boolean parseCommand(String command, PrintWriter out, 
+                                  BufferedReader in, InputStream socketIn)
         throws Exception {
         String argument  = null;
         String argument1 = null;
         if (command == null) return false;
         if (state.get(MESG_FAILED) == null) {
-            getLogger().info("Command received: " + command);
+            getLogger().debug("Command received: " + command);
         }
         command = command.trim();
         if (command.indexOf(" ")>0){
@@ -231,29 +272,30 @@
         }
 
         if (command.equalsIgnoreCase("HELO"))
-            doHELO(command,argument,argument1);
+            doHELO(command,argument,argument1,out);
         else if (command.equalsIgnoreCase("EHLO"))
-            doEHLO(command,argument,argument1);
+            doEHLO(command,argument,argument1,out);
         else if (command.equalsIgnoreCase("AUTH"))
-            doAUTH(command,argument,argument1);
+            doAUTH(command,argument,argument1,out,in);
         else if (command.equalsIgnoreCase("MAIL"))
-            doMAIL(command,argument,argument1);
+            doMAIL(command,argument,argument1,out);
         else if (command.equalsIgnoreCase("RCPT"))
-            doRCPT(command,argument,argument1);
+            doRCPT(command,argument,argument1,out);
         else if (command.equalsIgnoreCase("NOOP"))
-            doNOOP(command,argument,argument1);
+            doNOOP(command,argument,argument1,out);
         else if (command.equalsIgnoreCase("RSET"))
-            doRSET(command,argument,argument1);
+            doRSET(command,argument,argument1,out);
         else if (command.equalsIgnoreCase("DATA"))
-            doDATA(command,argument,argument1);
+            doDATA(command,argument,argument1,out,socketIn);
         else if (command.equalsIgnoreCase("QUIT"))
-            doQUIT(command,argument,argument1);
+            doQUIT(command,argument,argument1,out);
         else
-            doUnknownCmd(command,argument,argument1);
+            doUnknownCmd(command,argument,argument1,out);
         return (command.equalsIgnoreCase("QUIT") == false);
     }
 
-    private void doHELO(String command,String argument,String argument1) {
+    private void doHELO(String command, String argument, 
+                                          String argument1, PrintWriter out) {
         if (state.containsKey(CURRENT_HELO_MODE)) {
             out.println("250 " + state.get(SERVER_NAME)
                         + " Duplicate HELO");
@@ -277,7 +319,8 @@
         }
     }
 
-    private void doEHLO(String command,String argument,String argument1) {
+    private void doEHLO(String command, String argument, 
+                                          String argument1, PrintWriter out) {
         if (state.containsKey(CURRENT_HELO_MODE)) {
             out.println("250 " + state.get(SERVER_NAME)
                         + " Duplicate EHLO");
@@ -308,7 +351,8 @@
 
     }
 
-    private void doAUTH(String command,String argument,String argument1)
+    private void doAUTH(String command, String argument, String argument1, 
+                                          PrintWriter out, BufferedReader in)
             throws Exception {
         if (state.containsKey(AUTH)) {
             out.println("503 User has previously authenticated."
@@ -333,7 +377,7 @@
             if (users.test(user, pass)) {
                 state.put(AUTH, user);
                 out.println("235 Authentication Successful");
-                getLogger().info("AUTH method PLAIN succeeded");
+                getLogger().debug("AUTH method PLAIN succeeded");
             } else {
                 out.println("535 Authentication Failed");
                 getLogger().error("AUTH method PLAIN failed");
@@ -354,7 +398,7 @@
             if (users.test(user, pass)) {
                 state.put(AUTH, user);
                 out.println("235 Authentication Successful");
-                getLogger().info("AUTH method LOGIN succeeded");
+                getLogger().debug("AUTH method LOGIN succeeded");
             } else {
                 out.println("535 Authentication Failed");
                 getLogger().error("AUTH method LOGIN failed");
@@ -368,7 +412,8 @@
         }
     }
 
-    private void doMAIL(String command,String argument,String argument1) {
+    private void doMAIL(String command, String argument, 
+                                            String argument1, PrintWriter out) {
         if (state.containsKey(SENDER)) {
             out.println("503 Sender already specified");
         } else if (argument == null || !argument.equalsIgnoreCase("FROM")
@@ -430,7 +475,8 @@
         }
     }
 
-    private void doRCPT(String command,String argument,String argument1) {
+    private void doRCPT(String command, String argument, 
+                                            String argument1, PrintWriter out) {
         if (!state.containsKey(SENDER)) {
             out.println("503 Need MAIL before RCPT");
         } else if (argument == null || !argument.equalsIgnoreCase("TO")
@@ -510,15 +556,18 @@
             out.println("250 Recipient <" + recipient + "> OK");
         }
     }
-    private void doNOOP(String command,String argument,String argument1) {
+    private void doNOOP(String command, String argument, 
+                                          String argument1, PrintWriter out) {
         out.println("250 OK");
     }
-    private void doRSET(String command,String argument,String argument1) {
+    private void doRSET(String command, String argument, 
+                                          String argument1, PrintWriter out) {
         resetState();
         out.println("250 OK");
     }
 
-    private void doDATA(String command,String argument,String argument1) {
+    private void doDATA(String command, String argument, String argument1, 
+                                      PrintWriter out, InputStream socketIn) {
         if (!state.containsKey(SENDER)) {
             out.println("503 No sender specified");
         } else if (!state.containsKey(RCPT_VECTOR)) {
@@ -527,7 +576,8 @@
             out.println("354 Ok Send data ending with <CRLF>.<CRLF>");
             try {
                 //Setup the input stream to notify the scheduler periodically
-                InputStream msgIn = new SchedulerNotifyInputStream(in, scheduler, this.toString(), 20000);
+                InputStream msgIn = new SchedulerNotifyInputStream(socketIn, 
+                                            scheduler, this.toString(), 20000);
                 // parse headers
                 msgIn = new CharTerminatedInputStream(msgIn, SMTPTerminator);
                 // if the message size limit has been set, we'll
@@ -647,13 +697,14 @@
         }
     }
 
-    private void doQUIT(String command,String argument,String argument1) {
+    private void doQUIT(String command, String argument, 
+                                          String argument1, PrintWriter out) {
         out.println("221 " + state.get(SERVER_NAME)
                     + " Service closing transmission channel");
     }
 
-    private void doUnknownCmd(String command,String argument,
-                              String argument1) {
+    private void doUnknownCmd(String command, String argument,
+                              String argument1, PrintWriter out) {
         if (state.get(MESG_FAILED) == null) {
             out.println("500 " + state.get(SERVER_NAME)
                         + " Syntax error, command unrecognized: " + command);
