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