You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ch...@apache.org on 2001/05/11 11:47:21 UTC

cvs commit: jakarta-james/src/org/apache/james/testing NNTPClient.java POP3Hammering.java

charlesb    01/05/11 02:47:21

  Added:       src/java/org/apache/james/smtpserver
                        MessageSizeException.java SMTPHandler.java
                        SMTPServer.java SMTPServer.xinfo
                        SizeLimitedInputStream.java
                        SizeLimitedSMTPHandler.java
               src/java/org/apache/james/testing NNTPClient.java
                        POP3Hammering.java
  Removed:     src/org/apache/james/smtpserver MessageSizeException.java
                        SMTPHandler.java SMTPServer.java SMTPServer.xinfo
                        SizeLimitedInputStream.java
                        SizeLimitedSMTPHandler.java
               src/org/apache/james/testing NNTPClient.java
                        POP3Hammering.java
  Log:
  Moving from src/org to src/java/org
  
  Revision  Changes    Path
  1.1                  jakarta-james/src/java/org/apache/james/smtpserver/MessageSizeException.java
  
  Index: MessageSizeException.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.smtpserver;
  
  import java.io.*;
  
  /**
    * This exceptions is used to indicate when a new MimeMessage has exceeded
    * the maximum message size for the server, as configured in the conf file.
    * @author Matthew Pangaro <ma...@lokitech.com>
    * @version 0.5.1
    */
  public class MessageSizeException extends IOException {
  
      /** Default constructor that sets the message indicating message
          size error.
      */
      public MessageSizeException() {
          super("Message size exceeds fixed maximum message size.");
      }
  }
  
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/smtpserver/SMTPHandler.java
  
  Index: SMTPHandler.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.smtpserver;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.mail.*;
  import javax.mail.internet.*;
  import org.apache.avalon.framework.activity.Initializable;
  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.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.logger.AbstractLoggable;
  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.james.*;
  import org.apache.james.core.*;
  import org.apache.james.services.MailServer;
  import org.apache.james.util.*;
  import org.apache.mailet.*;
  
  /**
   * This handles an individual incoming message.  It handles regular SMTP
   * commands, and when it receives a message, adds it to the spool.
   * @author Serge Knystautas <se...@lokitech.com>
   * @author Federico Barbieri <sc...@systemy.it>
   * @version 0.9
   */
  public class SMTPHandler
      extends BaseConnectionHandler
      implements ConnectionHandler, Composable, Configurable, Target  {
  
      public final static String SERVER_NAME = "SERVER_NAME";
      public final static String SERVER_TYPE = "SERVER_TYPE";
      public final static String REMOTE_NAME = "REMOTE_NAME";
      public final static String REMOTE_IP = "REMOTE_IP";
      public final static String NAME_GIVEN = "NAME_GIVEN";
      public final static String CURRENT_HELO_MODE = "CURRENT_HELO_MODE";
      public final static String SENDER = "SENDER_ADDRESS";
      public final static String RCPT_VECTOR = "RCPT_VECTOR";
      public final static String SMTP_ID = "SMTP_ID";
      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 Configuration conf;
      private TimeScheduler scheduler;
      private MailServer mailServer;
  
      private String softwaretype = "JAMES SMTP Server " + Constants.SOFTWARE_VERSION;
      private static long count;
      private Hashtable state     = new Hashtable();
      private Random random       = new Random();
  
      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");
      }
  
      /**
       * Handle a connection.
       * This handler is responsible for processing connections as they occur.
       *
       * @param connection the connection
       * @exception IOException if an error reading from socket occurs
       * @exception ProtocolException if an error handling connection occurs
       */
      public void handleConnection( Socket connection )
          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) + "";
              state.clear();
              state.put(SERVER_NAME, this.helloName );
              state.put(SERVER_TYPE, this.softwaretype );
              state.put(REMOTE_NAME, remoteHost);
              state.put(REMOTE_IP, remoteIP);
              state.put(SMTP_ID, smtpID);
          } catch (Exception e) {
              getLogger().error("Cannot open connection from " + remoteHost + " (" + remoteIP + "): " + e.getMessage(), e );
              throw new RuntimeException("Cannot open connection from " + remoteHost + " (" + remoteIP + "): " + e.getMessage());
          }
  
          getLogger().info("Connection from " + remoteHost + " (" + remoteIP + ")");
  
          try {
              // Initially greet the connector
              // Format is:  Sat,  24 Jan 1998 13:16:09 -0500
  
              final PeriodicTimeTrigger trigger = new PeriodicTimeTrigger( timeout, -1 );
              scheduler.addTrigger( this.toString(), trigger, this );
              out.println("220 " + this.helloName + " SMTP Server (" + softwaretype + ") ready " + RFC822DateFormat.toString(new Date()));
  
              while  (parseCommand(in.readLine())) {
                  scheduler.resetTrigger(this.toString());
              }
              socket.close();
              scheduler.removeTrigger(this.toString());
          } catch (SocketException se) {
              getLogger().debug("Socket to " + remoteHost + " closed remotely.", se );
          } catch ( InterruptedIOException iioe ) {
              getLogger().debug( "Socket to " + remoteHost + " timeout.", iioe );
          } catch ( IOException ioe ) {
              getLogger().debug( "Exception handling socket to " + remoteHost + ":"
                                 + ioe.getMessage(), ioe );
          } catch (Exception e) {
              getLogger().debug( "Exception opening socket: " + e.getMessage(), e );
          } finally {
              try {
                  socket.close();
              } catch (IOException e) {
                  getLogger().error("Exception closing socket: " + e.getMessage());
              }
          }
      }
  
      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() {
          state.clear();
          state.put(SERVER_NAME, this.helloName );
          state.put(SERVER_TYPE, this.softwaretype );
          state.put(REMOTE_NAME, remoteHost);
          state.put(REMOTE_IP, remoteIP);
          state.put(SMTP_ID, smtpID);
      }
  
      private boolean parseCommand(String command)
          throws Exception {
  
          if (command == null) return false;
          getLogger().info("Command received: " + command);
          StringTokenizer commandLine = new StringTokenizer(command.trim(), " :");
          int arguments = commandLine.countTokens();
          if (arguments == 0) {
              return true;
          } else if(arguments > 0) {
              command = commandLine.nextToken();
          }
          String argument = (String) null;
          if(arguments > 1) {
              argument = commandLine.nextToken();
          }
          String argument1 = (String) null;
          if(arguments > 2) {
              argument1 = commandLine.nextToken();
          }
  
          if (command.equalsIgnoreCase("HELO"))
              doHELO(command,argument,argument1);
          else if (command.equalsIgnoreCase("EHLO"))
              doEHLO(command,argument,argument1);
          else if (command.equalsIgnoreCase("MAIL"))
              doMAIL(command,argument,argument1);
          else if (command.equalsIgnoreCase("RCPT"))
              doRCPT(command,argument,argument1);
          else if (command.equalsIgnoreCase("NOOP"))
              doNOOP(command,argument,argument1);
          else if (command.equalsIgnoreCase("RSET"))
              doRSET(command,argument,argument1);
          else if (command.equalsIgnoreCase("DATA"))
              doDATA(command,argument,argument1);
          else if (command.equalsIgnoreCase("QUIT"))
              doQUIT(command,argument,argument1);
          else
              doUnknownCmd(command,argument,argument1);
          return (command.equalsIgnoreCase("QUIT") == false);
      }
  
      private void doHELO(String command,String argument,String argument1) {
          if (state.containsKey(CURRENT_HELO_MODE)) {
              out.println("250 " + state.get(SERVER_NAME) + " Duplicate HELO/EHLO");
          } else if (argument == null) {
              out.println("501 domain address required: " + command);
          } else {
              state.put(CURRENT_HELO_MODE, command);
              state.put(NAME_GIVEN, argument);
              out.println("250 " + state.get(SERVER_NAME) + " Hello " + argument +
                          " (" + state.get(REMOTE_NAME) +
                          " [" + state.get(REMOTE_IP) + "])");
          }
      }
      private void doEHLO(String command,String argument,String argument1) {
          doHELO(command,argument,argument1);
      }
      private void doMAIL(String command,String argument,String argument1) {
          if (state.containsKey(SENDER)) {
              out.println("503 Sender already specified");
          } else if (argument == null || !argument.equalsIgnoreCase("FROM")
                     || argument1 == null) {
              out.println("501 Usage: MAIL FROM:<sender>");
          } else {
              String sender = argument1.trim();
              if (!sender.startsWith("<") || !sender.endsWith(">")) {
                  out.println("501 Syntax error in parameters or arguments");
                  getLogger().error("Error parsing sender address: " + sender
                                    + ": did not start and end with < >");
                  return;
              }
              MailAddress senderAddress = null;
              //Remove < and >
              sender = sender.substring(1, sender.length() - 1);
              try {
                  senderAddress = new MailAddress(sender);
              } catch (Exception pe) {
                  out.println("501 Syntax error in parameters or arguments");
                  getLogger().error("Error parsing sender address: " + sender
                                    + ": " + pe.getMessage());
                  return;
              }
              state.put(SENDER, senderAddress);
              out.println("250 Sender <" + sender + "> OK");
          }
      }
  
      private void doRCPT(String command,String argument,String argument1) {
          if (!state.containsKey(SENDER)) {
              out.println("503 Need MAIL before RCPT");
          } else if (argument == null || !argument.equalsIgnoreCase("TO") || argument1 == null) {
              out.println("501 Usage: RCPT TO:<recipient>");
          } else {
              Collection rcptColl = (Collection) state.get(RCPT_VECTOR);
              if (rcptColl == null) {
                  rcptColl = new Vector();
              }
              String recipient = argument1.trim();
              if (!recipient.startsWith("<") || !recipient.endsWith(">")) {
                  out.println("Syntax error in parameters or arguments");
                  getLogger().error("Error parsing recipient address: "
                                    + recipient
                                    + ": did not start and end with < >");
                  return;
              }
              MailAddress recipientAddress = null;
              //Remove < and >
              recipient = recipient.substring(1, recipient.length() - 1);
              try {
                  recipientAddress = new MailAddress(recipient);
              } catch (Exception pe) {
                  out.println("501 Syntax error in parameters or arguments");
                  getLogger().error("Error parsing recipient address: "
                                    + recipient + ": " + pe.getMessage());
                  return;
              }
              rcptColl.add(recipientAddress);
              state.put(RCPT_VECTOR, rcptColl);
              out.println("250 Recipient <" + recipient + "> OK");
          }
      }
      private void doNOOP(String command,String argument,String argument1) {
          out.println("250 OK");
      }
      private void doRSET(String command,String argument,String argument1) {
          resetState();
          out.println("250 OK");
      }
  
      private void doDATA(String command,String argument,String argument1) {
          if (!state.containsKey(SENDER)) {
              out.println("503 No sender specified");
          } else if (!state.containsKey(RCPT_VECTOR)) {
              out.println("503 No recipients specified");
          } else {
              out.println("354 Ok Send data ending with <CRLF>.<CRLF>");
              try {
                  // parse headers
                  InputStream msgIn = new CharTerminatedInputStream(in, SMTPTerminator);
                  MailHeaders headers = new MailHeaders(msgIn);
                  // if headers do not contains minimum REQUIRED headers fields add them
                  if (!headers.isSet("Date")) {
                      headers.setHeader("Date", RFC822DateFormat.toString (new Date ()));
                  }
                  /*
                    We no longer add To as this in practice is not set (from what I've seen)
                    if (!headers.isSet("To")) {
                    headers.setHeader("To", );
                    }
                  */
                  if (!headers.isSet("From")) {
                      headers.setHeader("From", state.get(SENDER).toString());
                  }
  
                  String received = "from " + state.get(REMOTE_NAME) + " ([" + state.get(REMOTE_IP)
                      + "])\r\n          by " + this.helloName + " ("
                      + softwaretype + ") with SMTP ID " + state.get(SMTP_ID);
                  if (((Collection)state.get(RCPT_VECTOR)).size () == 1) {
                      //Only indicate a recipient if they're the only recipient
                      //(prevents email address harvesting and large headers in bulk email)
                      received += "\r\n          for <"
                          + ((Vector)state.get(RCPT_VECTOR)).elementAt(0).toString() + ">";
                  }
                  received += ";\r\n          " + RFC822DateFormat.toString (new Date ());
                  headers.addHeader ("Received", received);
  
                  // headers.setReceivedStamp("Unknown", (String) helloName.elementAt(0));
                  ByteArrayInputStream headersIn = new ByteArrayInputStream(headers.toByteArray());
                  MailImpl mail = new MailImpl(mailServer.getId(), (MailAddress)state.get(SENDER),
                                               (Vector)state.get(RCPT_VECTOR),
                                               new SequenceInputStream(headersIn, msgIn));
                  mail.setRemoteHost((String)state.get(REMOTE_NAME));
                  mail.setRemoteAddr((String)state.get(REMOTE_IP));
                  mailServer.sendMail(mail);
              } catch (MessagingException me) {
                  out.println("451 Error processing message: " + me.getMessage());
                  getLogger().error("Error processing message: "
                                    + me.getMessage());
                  return;
              }
              getLogger().info("Mail sent to Mail Server");
              resetState();
              out.println("250 Message received");
          }
      }
      private void doQUIT(String command,String argument,String argument1) {
          out.println("221 " + state.get(SERVER_NAME) + " Service closing transmission channel");
      }
  
      private void doUnknownCmd(String command,String argument,String argument1) {
          out.println("500 " + state.get(SERVER_NAME) + " Syntax error, command unrecognized: " +
                      command);
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/smtpserver/SMTPServer.java
  
  Index: SMTPServer.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.smtpserver;
  
  import java.net.InetAddress;
  import java.net.UnknownHostException;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.cornerstone.services.connection.AbstractService;
  import org.apache.avalon.cornerstone.services.connection.ConnectionHandlerFactory;
  import org.apache.avalon.cornerstone.services.connection.DefaultHandlerFactory;
  
  /**
   *
   * @version 1.1.0, 06/02/2001
   * @author  Federico Barbieri <sc...@pop.systemy.it>
   * @author  Matthew Pangaro <ma...@lokitech.com>
   * @author  <a href="mailto:donaldp@apache.org">Peter Donald</a>
   */
  public class SMTPServer 
      extends AbstractService {
  
      protected ConnectionHandlerFactory createFactory()
      {
          return new DefaultHandlerFactory( SMTPHandler.class );
      }
  
      public void configure( final Configuration configuration )
          throws ConfigurationException {
  
          m_port = configuration.getChild( "port" ).getValueAsInteger( 25 );
  
          try 
          { 
              final String bindAddress = configuration.getChild( "bind" ).getValue( null );
              if( null != bindAddress )
              {
                  m_bindTo = InetAddress.getByName( bindAddress ); 
              }
          }
          catch( final UnknownHostException unhe ) 
          {
              throw new ConfigurationException( "Malformed bind parameter", unhe );
          }
  
          final String useTLS = configuration.getChild("useTLS").getValue( "" );
          if( useTLS.equals( "TRUE" ) ) m_serverSocketType = "ssl";
   
         super.configure( configuration.getChild( "handler" ) );
      }
  
      public void initialize() throws Exception {
          getLogger().info("SMTPServer init...");
          super.initialize();
          getLogger().info("SMTPServer ...init end");
          System.out.println("Started SMTP Server "+m_connectionName);
      }
  }
      
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/smtpserver/SMTPServer.xinfo
  
  Index: SMTPServer.xinfo
  ===================================================================
  <?xml version="1.0"?>
  
  <blockinfo>
    <services>
      <service name="org.apache.avalon.framework.component.Component" version="1.0"/>
    </services>
  
    <dependencies>
      <dependency>
        <role>org.apache.james.services.MailStore</role>
        <service name="org.apache.james.services.MailStore" version="1.0"/>
      </dependency>
      <dependency>
        <role>org.apache.james.services.UsersStore</role>
        <service name="org.apache.james.services.UsersStore" version="1.0"/>
      </dependency>
      <dependency>
        <role>org.apache.avalon.cornerstone.services.connection.ConnectionManager</role>
        <service name="org.apache.avalon.cornerstone.services.connection.ConnectionManager" 
                 version="1.0"/>
      </dependency>
      <dependency>
        <role>org.apache.avalon.cornerstone.services.sockets.SocketManager</role>
        <service name="org.apache.avalon.cornerstone.services.sockets.SocketManager" version="1.0"/>
      </dependency>
      <dependency>
        <role>org.apache.avalon.cornerstone.services.scheduler.TimeScheduler</role>
        <service name="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler" version="1.0"/>
      </dependency> 
      <dependency>
        <role>org.apache.james.services.MailServer</role>
        <service name="org.apache.james.services.MailServer" version="1.0"/>
      </dependency> 
    </dependencies>  
  </blockinfo>
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/smtpserver/SizeLimitedInputStream.java
  
  Index: SizeLimitedInputStream.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.smtpserver;
  
  import java.io.*;
  import org.apache.james.smtpserver.*;
  
  /** This class wraps an underlying input stream, limiting the allowable size
    * of an incoming MimeMessage. The size limit is configured in the conf file,
    * and when the limit is reached, a MessageSizeException is thrown.
    * @author Matthew Pangaro <ma...@lokitech.com>
    */
  public class SizeLimitedInputStream extends InputStream {
      /** Maximum number of bytes to read.
       */
      private long maxmessagesize = 0;
      /** Running total of bytes read from wrapped stream.
       */
      private long bytesread = 0;
  
      /** InputStream that will be wrapped.
       */
      private InputStream in = null;
  
      /** Constructor for the stream. Wraps an underlying stream.
       * @param in InputStream to use as basis for new Stream.
       * @param maxmessagesize Message size limit, in Kilobytes
       */
      public SizeLimitedInputStream(InputStream in, long maxmessagesize) {
          this.in = in;
          this.maxmessagesize = maxmessagesize;
      }
  
      /** Overrides the read method of InputStream to call the read() method of the
       * wrapped input stream.
       * @throws IOException Throws a MessageSizeException, which is a sub-type of IOException.
       * @return Returns the int character value of the byte read.
       */
      public int read() throws IOException {
          if (maxmessagesize > 0 && bytesread <= maxmessagesize) {
              bytesread++;
              return in.read();
          } else {
              throw new MessageSizeException();
          }
      }
  }
  
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/smtpserver/SizeLimitedSMTPHandler.java
  
  Index: SizeLimitedSMTPHandler.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.smtpserver;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  import javax.mail.*;
  import javax.mail.internet.*;
  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.avalon.framework.context.Context;
  import org.apache.avalon.framework.context.ContextException;
  import org.apache.avalon.framework.context.Contextualizable;
  import org.apache.avalon.framework.logger.AbstractLoggable;
  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.james.*;
  import org.apache.james.core.*;
  import org.apache.james.services.MailServer;
  import org.apache.james.util.*;
  import org.apache.mailet.*;
  
  /**
   * This handles an individual incoming message.  It handles regular SMTP
   * commands, and when it receives a message, adds it to the spool.
   * @author Serge Knystautas <se...@lokitech.com>
   * @author Federico Barbieri <sc...@systemy.it>
    * @author Matthew Pangaro <ma...@lokitech.com>
   * @version 0.9.1
   */
  public class SizeLimitedSMTPHandler
      extends BaseConnectionHandler
      implements ConnectionHandler, Composable, Configurable, Target {
  
      public final static String SERVER_NAME = "SERVER_NAME";
      public final static String SERVER_TYPE = "SERVER_TYPE";
      public final static String REMOTE_NAME = "REMOTE_NAME";
      public final static String REMOTE_IP = "REMOTE_IP";
      public final static String NAME_GIVEN = "NAME_GIVEN";
      public final static String CURRENT_HELO_MODE = "CURRENT_HELO_MODE";
      public final static String SENDER = "SENDER_ADDRESS";
      public final static String MESG_FAILED = "MESG_FAILED";
      public final static String RCPT_VECTOR = "RCPT_VECTOR";
      public final static String SMTP_ID = "SMTP_ID";
      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 Configuration conf;
      private Context context;
      private TimeScheduler scheduler;
      private MailServer mailServer;
  
      private String softwaretype = "JAMES SMTP Server " + Constants.SOFTWARE_VERSION;
      private static long count;
  
      private Hashtable state     = new Hashtable();
      private Random random       = new Random();
      private long maxmessagesize;
  
      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");
      }
  
      public void configure(Configuration conf) throws ConfigurationException {
          this.conf = conf;
          timeout = conf.getChild( "connectiontimeout" ).getValueAsInteger( 120000 );
          // get the message size limit from the conf file and multiply
          //by 1024, to put it in bytes
          maxmessagesize =
              conf.getChild( "maxmessagesize" ).getValueAsLong( 0 ) * 1024;
      }
  
      /**
       * Handle a connection.
       * This handler is responsible for processing connections as they occur.
       *
       * @param connection the connection
       * @exception IOException if an error reading from socket occurs
       * @exception ProtocolException if an error handling connection occurs
       */
      public void handleConnection( Socket connection )
          throws IOException {
  
          try {
              this.socket = socket;
              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) + "";
              state.clear();
              state.put(SERVER_NAME, this.helloName );
              state.put(SERVER_TYPE, this.softwaretype );
              state.put(REMOTE_NAME, remoteHost);
              state.put(REMOTE_IP, remoteIP);
              state.put(SMTP_ID, smtpID);
          } catch (Exception e) {
              final String message =
                  "Cannot open connection from " + remoteHost + " (" + remoteIP + "): " +
                  e.getMessage();
              getLogger().error( message, e );
              throw new RuntimeException( message );
          }
  
          getLogger().info( "Connection from " + remoteHost + " (" + remoteIP + ")" );
  
          try {
              // Initially greet the connector
              // Format is:  Sat,  24 Jan 1998 13:16:09 -0500
  
              final PeriodicTimeTrigger trigger = new PeriodicTimeTrigger( timeout, -1 );
              scheduler.addTrigger( this.toString(), trigger, this );
              out.println("220 " + this.helloName + " SMTP Server (" + softwaretype + ") ready " + RFC822DateFormat.toString(new Date()));
  
              while  (parseCommand(in.readLine())) {
                  scheduler.resetTrigger(this.toString());
              }
              socket.close();
              scheduler.removeTrigger(this.toString());
          } catch ( final SocketException se ) {
              getLogger().debug( "Socket to " + remoteHost + " closed remotely.", se );
          } catch ( final InterruptedIOException iioe ) {
              getLogger().debug( "Socket to " + remoteHost + " timeout.", iioe );
          } catch ( final IOException ioe ) {
              getLogger().debug("Exception handling socket to " + remoteHost + ":"
                                + ioe.getMessage(), ioe );
          } catch ( final Exception e ) {
              getLogger().debug( "Exception opening socket: " + e.getMessage(), e );
          } finally {
              try {
                  socket.close();
              } catch ( final IOException ioe ) {
                  getLogger().error( "Exception closing socket: " + ioe.getMessage(), ioe );
              }
          }
      }
  
      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 boolean parseCommand(String command)
          throws Exception {
  
          if (command == null) return false;
          if (state.get(MESG_FAILED) == null) {
              getLogger().info("Command received: " + command);
          }
          StringTokenizer commandLine = new StringTokenizer(command.trim(), " :");
          int arguments = commandLine.countTokens();
          if (arguments == 0) {
              return true;
          } else if(arguments > 0) {
              command = commandLine.nextToken();
          }
          String argument = (String) null;
          if(arguments > 1) {
              argument = commandLine.nextToken();
          }
          String argument1 = (String) null;
          if(arguments > 2) {
              argument1 = commandLine.nextToken();
          }
          // HELO Command
          if (command.equalsIgnoreCase("HELO")) {
              if (state.containsKey(CURRENT_HELO_MODE)) {
                  out.println("250 " + state.get(SERVER_NAME) + " Duplicate HELO/EHLO");
                  return true;
              } else if (argument == null) {
                  out.println("501 domain address required: " + commandLine);
                  return true;
              } else {
                  state.put(CURRENT_HELO_MODE, command);
                  state.put(NAME_GIVEN, argument);
                  out.println("250 " + state.get(SERVER_NAME) + " Hello " + argument + " (" + state.get(REMOTE_NAME) + " [" + state.get(REMOTE_IP) + "])");
                  return true;
              }
              // EHLO Command
          } else if (command.equalsIgnoreCase("EHLO")) {
              if (state.containsKey(CURRENT_HELO_MODE)) {
                  out.println("250 " + state.get(SERVER_NAME) + " Duplicate HELO/EHLO");
                  return true;
              } else if (argument == null) {
                  out.println("501 domain address required: " + commandLine);
                  return true;
              } else {
                  state.put(CURRENT_HELO_MODE, command);
                  state.put(NAME_GIVEN, argument);
                  out.println("250 " + state.get(SERVER_NAME) + " Hello " + argument + " (" + state.get(REMOTE_NAME) + " [" + state.get(REMOTE_IP) + "])");
                  out.println("250 SIZE " + maxmessagesize);
                  return true;
              }
              // MAIL Command
          } else if (command.equalsIgnoreCase("MAIL")) {
              if (state.containsKey(SENDER)) {
                  out.println("503 Sender already specified");
                  return true;
              } else if (argument == null || !argument.equalsIgnoreCase("FROM") || argument1 == null) {
                  out.println("501 Usage: MAIL FROM:<sender>");
                  return true;
              } else {
                  String sender = argument1.trim();
                  if (!sender.startsWith("<") || !sender.endsWith(">")) {
                      out.println("501 Syntax error in parameters or arguments");
                      getLogger().error("Error parsing sender address: " + sender
                                        + ": did not start and end with < >");
                      return true;
                  }
                  MailAddress senderAddress = null;
                  //Remove < and >
                  sender = sender.substring(1, sender.length() - 1);
                  try {
                      senderAddress = new MailAddress(sender);
                  } catch (Exception pe) {
                      out.println("501 Syntax error in parameters or arguments");
                      getLogger().error("Error parsing sender address: " + sender
                                        + ": " + pe.getMessage());
                      return true;
                  }
                  state.put(SENDER, senderAddress);
                  out.println("250 Sender <" + sender + "> OK");
                  return true;
              }
              // RCPT Command
          } else if (command.equalsIgnoreCase("RCPT")) {
              if (!state.containsKey(SENDER)) {
                  out.println("503 Need MAIL before RCPT");
                  return true;
              } else if (argument == null || !argument.equalsIgnoreCase("TO") || argument1 == null) {
                  out.println("501 Usage: RCPT TO:<recipient>");
                  return true;
              } else {
                  Collection rcptColl = (Collection) state.get(RCPT_VECTOR);
                  if (rcptColl == null) {
                      rcptColl = new Vector();
                  }
                  String recipient = argument1.trim();
                  if (!recipient.startsWith("<") || !recipient.endsWith(">")) {
                      out.println("Syntax error in parameters or arguments");
                      getLogger().error("Error parsing recipient address: "
                                        + recipient
                                        + ": did not start and end with < >");
                      return true;
                  }
                  MailAddress recipientAddress = null;
                  //Remove < and >
                  recipient = recipient.substring(1, recipient.length() - 1);
                  try {
                      recipientAddress = new MailAddress(recipient);
                  } catch (Exception pe) {
                      out.println("501 Syntax error in parameters or arguments");
                      getLogger().error("Error parsing recipient address: "
                                        + recipient + ": " + pe.getMessage());
                      return true;
                  }
                  rcptColl.add(recipientAddress);
                  state.put(RCPT_VECTOR, rcptColl);
                  out.println("250 Recipient <" + recipient + "> OK");
                  return true;
              }
              // NOOP Command
          } else if (command.equalsIgnoreCase("NOOP")) {
              out.println("250 OK");
              return true;
              // DATA Command
          } else if (command.equalsIgnoreCase("RSET")) {
              resetState();
              out.println("250 OK");
              return true;
              // DATA Command
          } else if (command.equalsIgnoreCase("DATA")) {
              if (!state.containsKey(SENDER)) {
                  out.println("503 No sender specified");
                  return true;
              } else if (!state.containsKey(RCPT_VECTOR)) {
                  out.println("503 No recipients specified");
                  return true;
              } else {
                  out.println("354 Ok Send data ending with <CRLF>.<CRLF>");
                  try {
                      // parse headers
                      InputStream msgIn = new CharTerminatedInputStream(in, SMTPTerminator);
                      // if the message size limit has been set, we'll
                      //wrap msgIn with a SizeLimitedInputStream
                      if (maxmessagesize > 0) {
                          msgIn =
                              new SizeLimitedInputStream(msgIn, maxmessagesize);
                      }
                      MailHeaders headers = new MailHeaders(msgIn);
                      // if headers do not contains minimum REQUIRED headers fields add them
                      if (!headers.isSet("Date")) {
                          headers.setHeader("Date", RFC822DateFormat.toString (new Date ()));
                      }
                      /*
                        We no longer add To as this in practice is not set (from what I've seen)
                        if (!headers.isSet("To")) {
                        headers.setHeader("To", );
                        }
                      */
                      if (!headers.isSet("From")) {
                          headers.setHeader("From", state.get(SENDER).toString());
                      }
  
                      String received = "from " + state.get(REMOTE_NAME) + " ([" + state.get(REMOTE_IP)
                          + "])\r\n          by " + this.helloName + " ("
                          + softwaretype + ") with SMTP ID " + state.get(SMTP_ID);
                      if (((Collection)state.get(RCPT_VECTOR)).size () == 1) {
                          //Only indicate a recipient if they're the only recipient
                          //(prevents email address harvesting and large headers in bulk email)
                          received += "\r\n          for <"
                              + ((Vector)state.get(RCPT_VECTOR)).elementAt(0).toString() + ">";
                      }
                      received += ";\r\n          " + RFC822DateFormat.toString (new Date ());
                      headers.addHeader ("Received", received);
  
                      // headers.setReceivedStamp("Unknown", (String) helloName.elementAt(0));
                      ByteArrayInputStream headersIn = new ByteArrayInputStream(headers.toByteArray());
                      MailImpl mail = new MailImpl(mailServer.getId(), (MailAddress)state.get(SENDER), (Vector)state.get(RCPT_VECTOR), new SequenceInputStream(headersIn, msgIn));
                      //call mail.getSize() to force the message to be
                      //loaded. Need to do this to limit the size
                      mail.getSize();
                      mail.setRemoteHost((String)state.get(REMOTE_NAME));
                      mail.setRemoteAddr((String)state.get(REMOTE_IP));
                      mailServer.sendMail(mail);
                  } catch (MessagingException me) {
                      //Grab any exception attached to this one.
                      Exception e = me.getNextException();
  
                      //If there was an attached exception, and it's a
                      //MessageSizeException
                      if (e != null && e instanceof MessageSizeException) {
                          getLogger().error("552 Error processing message: "
                                            + e.getMessage());
                          //Add an item to the state to suppress
                          //logging of extra lines of data
                          //  that are sent after the size limit has
                          //been hit.
                          state.put(MESG_FAILED, Boolean.TRUE);
  
                          //then let the client know that the size
                          //limit has been hit.
                          out.println("552 Error processing message: "
                                      + e.getMessage());
                      } else {
                          out.println("451 Error processing message: "
                                      + me.getMessage());
                          getLogger().error("Error processing message: " +
                                            me.getMessage());
                      }
                      return true;
                  }
                  getLogger().info("Mail sent to Mail Server");
                  resetState();
                  out.println("250 Message received");
                  return true;
              }
          } else if (command.equalsIgnoreCase("QUIT")) {
              out.println("221 " + state.get(SERVER_NAME) + " Service closing transmission channel");
              return false;
          } else {
              if (state.get(MESG_FAILED) == null) {
                  out.println("500 " + state.get(SERVER_NAME) + " Syntax error, command unrecognized: " + command);
              }
              return true;
          }
      }
  
      private void resetState() {
          state.clear();
          state.put(SERVER_NAME, this.helloName );
          state.put(SERVER_TYPE, this.softwaretype );
          state.put(REMOTE_NAME, remoteHost);
          state.put(REMOTE_IP, remoteIP);
          state.put(SMTP_ID, smtpID);
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/testing/NNTPClient.java
  
  Index: NNTPClient.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.testing;
  
  import java.util.*;
  import javax.mail.*;
  import javax.mail.internet.*;
  import sun.net.nntp.*;
  import org.apache.avalon.excalibur.io.IOUtil;
  import java.io.*;
  
  /**
   * @author Harmeet <hb...@apache.org>
   */
  public class NNTPClient {
      public static void main(String[] args) throws Exception {
          String server = args[0];
          String group = args[1];
          NntpClient nntp = new NntpClient(server);
          NewsgroupInfo info = nntp.getGroup(group);
          System.out.println("newsgroup: "+group+", "+info.firstArticle+", "+
                             info.lastArticle);
          File f = new File(group);
          f.mkdirs();
          for ( int i = 0 ; i < 10 ; i++ ) {
              int articleId = i+info.firstArticle;
              if ( articleId > info.lastArticle )
                  break;
              IOUtil.copy(nntp.getArticle(articleId),
                          new FileOutputStream(new File(f,articleId+"")));
          }
      }
  }
  
  
  
  1.1                  jakarta-james/src/java/org/apache/james/testing/POP3Hammering.java
  
  Index: POP3Hammering.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE file.
   */
  package org.apache.james.testing;
  
  import java.util.*;
  import javax.mail.*;
  import javax.mail.internet.*;
  
  /**
   * Program that can be run multiple times to recreate the
   * "stuck file" issue in Windows.
   *
   * @author Prasanna Uppaladadium <pr...@vayusphere.com>
   */
  public class POP3Hammering {
  
      private String mailHost;
      private String user;
      private String password;
      private Properties prop = new Properties();
  
      private static final String body = "Test message number: ";
  
      private int iter;
  
      public POP3Hammering(String host, String user, String password) {
          this.mailHost = host;
          this.user = user;
          this.password = password;
          iter = 0;
          prop.put("java.smtp.host", mailHost);
      }
  
      void sendMail() {
          try {
              Session session = Session.getDefaultInstance(prop, null);
              // Transport transport = session.getTransport("smtp");
              MimeMessage msg = new MimeMessage(session);
              msg.setFrom(new InternetAddress(user + "@localhost"));
              msg.addRecipient(Message.RecipientType.TO, new InternetAddress(user + "@localhost"));
              msg.setContent(body + ++iter, "text/plain");
              Transport.send(msg);
              // transport.close();
              System.out.println("Sent message : " + msg.getContent() +
                      " from: " + msg.getFrom()[0] + " To: " +
                      msg.getAllRecipients()[0]);
          } catch (Throwable e) {
              e.printStackTrace();
              System.exit(0);
          }
      }
  
      void receiveMail(boolean delete) {
          try {
              Session session = Session.getDefaultInstance(prop, null);
              Store store = session.getStore("pop3");
              store.connect(mailHost, user, password);
  
              Folder folder = store.getFolder("INBOX");
  
              if(folder == null || !folder.exists()) {
                  System.out.println("This folder does not exist.");
                  return;
              }
  
              folder.open(Folder.READ_WRITE);
  
              Message[] msgs = folder.getMessages();
              System.out.println("Received " + msgs.length + " messages for " + user);
              Message msg = msgs[0];
              System.out.println("From: " + msg.getFrom()[0].toString());
              System.out.println("To: " + msg.getRecipients(Message.RecipientType.TO)[0]);
              System.out.println("-------------------");
              System.out.println(msg.getContent().toString());
  
              if(delete) {
                  msg.setFlag(Flags.Flag.DELETED, true);
                  System.out.println("Deleted.");
              }
              folder.close(true);
              store.close();
          } catch (MessagingException e) {
              e.printStackTrace();
          } catch (Throwable e) {
              e.printStackTrace();
          }
      }
  
      public static void main(String[] args) throws Throwable {
          POP3Hammering tester = new POP3Hammering(args[0], args[1], args[2]);
          tester.sendMail();
          tester.sendMail();
  
          tester.receiveMail(true);
          tester.receiveMail(true);
      }
  }
  
  
  

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