Hello all,
I made a stab at adding a message size limit to the James Server. I've 
included diffs and new classes in this message. The new functionality 
works at the SMTPHandler level, so it will restrict the size of messages 
for relaying as well as for local delivery. The max message size is 
optionally configured in the conf file in KiloBytes.

I've done some limited testing running it on Win2K with telnet, Outlook 
Express, and Netscape mail clients connecting, and it seems to work 
well. I've also done a little bit of testing with relaying, and it works 
there, although if the relay is through another james server, you get no 
notification of the failure. Testing with out Netscape Messaging Server, 
however, generated an appropriate bounce message, once the message had 
been relayed.

Anyway, without further ado, here's the code. I welcome any comments on 
the approach or the code.

Matt Pangaro
Loki Technologies
http://www.lokitech.com

P.S. I hope this formatting doesn't get too messed up. I was told that the list won't 
accept attachments, so I've put everything inline.

Index: james.conf.xml
===================================================================
RCS file: /products/cvs/master/james/conf/james.conf.xml,v
retrieving revision 1.3
diff -r1.3 james.conf.xml
160a161,164
>                     <!-- This sets the maximum allowed message size for the 
>smtphandler in KBytes.
>                         The value defaults to 0, which means no limit.
>                     <maxmessagesize> 2000 </maxmessagesize>
>                     -->


Index: SMTPServer.java
===================================================================
RCS file: /products/cvs/master/james/src/org/apache/james/smtpserver/SMTPServer.java,v
retrieving revision 1.16
diff -r1.16 SMTPServer.java
24c24
<  * @version 1.0.0, 24/04/1999
---
>  * @version 1.1.0, 06/02/2001
25a26
>  * @author  Matthew Pangaro <[EMAIL PROTECTED]>
34,35c35,36
<  
<     
---
>     private String handlerStartMesg = "Executing handler";
> 
51c52<  threadPool = ThreadManager.getWorkerPool("whateverNameYouFancy");
---
>         threadPool = ThreadManager.getWorkerPool("whateverNameYouFancy");
61a63,67
>         //get the configured max message size so we can log it
>         long limit = 
>conf.getChild("smtphandler").getChild("maxmessagesize").getValueAsLong(0);
>         if (limit > 0) {
>             handlerStartMesg += " with message size limit : " + limit + " KBytes";
>         }
76c82
<             logger.debug("Executing handler.");
---
>             logger.debug(handlerStartMesg);


Index: SMTPHandler.java
===================================================================
RCS file: /products/cvs/master/james/src/org/apache/james/smtpserver/SMTPHandler.java,v
retrieving revision 1.28
diff -r1.28 SMTPHandler.java
36c36,37
<  * @version 0.9
---
>  * @author Matthew Pangaro <[EMAIL PROTECTED]>
>  * @version 0.9.1
47a49
>     public final static String MESG_FAILED = "MESG_FAILED";
74a77
>     private long maxmessagesize;
78c81,83
<  timeout = conf.getChild("connectiontimeout").getValueAsLong(120000);
---
>         timeout = conf.getChild("connectiontimeout").getValueAsLong(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;
167c172,174
<         logger.info("Command received: " + command);
---
>         if (state.get(MESG_FAILED) == null) {
>             logger.info("Command received: " + command);
>         }
208c215,216
<                 out.println("250 " + state.get(SERVER_NAME) + " Hello " + argument + 
" (" + state.get(REMOTE_NAME) + " [" + state.get(REMOTE_IP) + "])");
---
>                 out.println("250-" + state.get(SERVER_NAME) + " Hello " + argument + 
>" (" + state.get(REMOTE_NAME) + " [" + state.get(REMOTE_IP) + "])");
>                 out.println("250 SIZE " + maxmessagesize);
300a309,312
>                     // if the message size limit has been set, we'll wrap msgIn with 
>a SizeLimitedInputStream
>                     if (maxmessagesize > 0) {
>                         msgIn = new SizeLimitedInputStream(msgIn, maxmessagesize);
>                     }
332a345,346
>                     //call mail.getSize() to force the message to be loaded. Need to 
>do this to limit the size
>                     mail.getSize();
335,337c349,367
<                     out.println("451 Error processing message: " + me.getMessage());
<                     logger.error("Error processing message: "
<      + me.getMessage());
---
>                     //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) {
>                         logger.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());
>                         logger.error("Error processing message: " + me.getMessage());
>                     }
349c379,381
<             out.println("500 " + state.get(SERVER_NAME) + " Syntax error, command 
unrecognized: " + command);
---
>             if (state.get(MESG_FAILED) == null) {
>                 out.println("500 " + state.get(SERVER_NAME) + " Syntax error, 
>command unrecognized: " + command);
>             }


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 <[EMAIL PROTECTED]>
 */
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();
        }
    }
}


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 <[EMAIL PROTECTED]>
 * @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.");
    }
}



------------------------------------------------------------
To subscribe:        [EMAIL PROTECTED]
To unsubscribe:      [EMAIL PROTECTED]
Archives:  <http://www.mail-archive.com/james%40list.working-dogs.com/>
Problems?:           [EMAIL PROTECTED]

Reply via email to