pgoldstein    2003/03/25 23:43:44

  Modified:    src/java/org/apache/james/core MailHeaders.java
               src/java/org/apache/james/nntpserver NNTPHandler.java
               src/java/org/apache/james/nntpserver/repository
                        NNTPArticle.java NNTPArticleImpl.java
                        NNTPRepository.java NNTPRepositoryImpl.java
  Added:       src/java/org/apache/james/util DotStuffingInputStream.java
  Removed:     src/java/org/apache/james/smtpserver SMTPInputStream.java
               src/java/org/apache/james/nntpserver/repository
                        NNTPLineReader.java NNTPLineReaderImpl.java
  Log:
  Committing NNTP changes to resolve encoding issue.
  Changes do not check incoming header for character
  set, but instead treat the article as a raw block of
  bytes.  Checked in for Noel Bergman.
  
  Revision  Changes    Path
  1.2       +86 -0     
jakarta-james/src/java/org/apache/james/util/DotStuffingInputStream.java
  
  
  
  
  1.10      +15 -21    jakarta-james/src/java/org/apache/james/core/MailHeaders.java
  
  Index: MailHeaders.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/src/java/org/apache/james/core/MailHeaders.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- MailHeaders.java  8 Mar 2003 21:14:01 -0000       1.9
  +++ MailHeaders.java  26 Mar 2003 07:43:44 -0000      1.10
  @@ -58,6 +58,8 @@
   
   package org.apache.james.core;
   
  +import javax.mail.MessagingException;
  +import javax.mail.internet.InternetHeaders;
   import java.io.ByteArrayOutputStream;
   import java.io.InputStream;
   import java.io.OutputStream;
  @@ -65,15 +67,13 @@
   import java.io.Serializable;
   import java.util.Enumeration;
   
  -import javax.mail.MessagingException;
  -import javax.mail.internet.InternetHeaders;
  -
   import org.apache.mailet.RFC2822Headers;
   
   /**
    * This interface defines a container for mail headers. Each header must use
    * MIME format: <pre>name: value</pre>.
    *
  + * @author Federico Barbieri <[EMAIL PROTECTED]>
    */
   public class MailHeaders extends InternetHeaders implements Serializable, Cloneable 
{
   
  @@ -99,30 +99,24 @@
           super(in);
       }
   
  -// TODO: Overloading error.  This is extremely dangerous, as the overloaded call
  -//       does not behave like an overridden call.  Specifically, the choice of
  -//       which method to invoke is made at compile time, not at runtime.
  -//       Potentially very, very bad if the behaviors diverge.
  -
       /**
  -     * Write the headers to an PrintStream
  +     * Write the headers to an output stream
        *
        * @param writer the stream to which to write the headers
        */
  -    public void writeTo(PrintStream writer) {
  +    public void writeTo(OutputStream out) {
  +        PrintStream pout;
  +        if (out instanceof PrintStream) {
  +            pout = (PrintStream)out;
  +        } else {
  +            pout = new PrintStream(out);
  +        }
           for (Enumeration e = super.getAllHeaderLines(); e.hasMoreElements(); ) {
  -            writer.println((String) e.nextElement());
  +            pout.print((String) e.nextElement());
  +            pout.print("\r\n");
           }
  -        writer.println("");
  -    }
  -
  -    /**
  -     * Write the headers to an output stream
  -     *
  -     * @param out the stream to which to write the headers
  -     */
  -    public void writeTo(OutputStream out) {
  -        writeTo(new PrintStream(out));
  +        // Print trailing CRLF
  +        pout.print("\r\n");
       }
   
       /**
  
  
  
  1.38      +265 -120  
jakarta-james/src/java/org/apache/james/nntpserver/NNTPHandler.java
  
  Index: NNTPHandler.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-james/src/java/org/apache/james/nntpserver/NNTPHandler.java,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -r1.37 -r1.38
  --- NNTPHandler.java  8 Mar 2003 21:14:04 -0000       1.37
  +++ NNTPHandler.java  26 Mar 2003 07:43:44 -0000      1.38
  @@ -58,13 +58,20 @@
   
   package org.apache.james.nntpserver;
   
  +import java.io.BufferedInputStream;
  +import java.io.BufferedOutputStream;
   import java.io.BufferedReader;
   import java.io.BufferedWriter;
  +import java.io.ByteArrayInputStream;
   import java.io.IOException;
  +import java.io.InputStream;
   import java.io.InputStreamReader;
  +import java.io.OutputStream;
   import java.io.OutputStreamWriter;
   import java.io.PrintWriter;
  +import java.io.SequenceInputStream;
   import java.net.Socket;
  +import java.text.DateFormat;
   import java.text.ParseException;
   import java.util.ArrayList;
   import java.util.Calendar;
  @@ -73,20 +80,28 @@
   import java.util.List;
   import java.util.Locale;
   import java.util.StringTokenizer;
  +import javax.mail.MessagingException;
   
   import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
   import org.apache.avalon.excalibur.pool.Poolable;
   import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
  +import org.apache.avalon.framework.logger.Logger;
  +import org.apache.james.core.MailHeaders;
   import org.apache.james.nntpserver.repository.NNTPArticle;
   import org.apache.james.nntpserver.repository.NNTPGroup;
  -import org.apache.james.nntpserver.repository.NNTPLineReaderImpl;
  +import org.apache.james.nntpserver.repository.NNTPRepository;
  +import org.apache.james.util.CharTerminatedInputStream;
  +import org.apache.james.util.DotStuffingInputStream;
  +import org.apache.james.util.ExtraDotOutputStream;
   import org.apache.james.util.InternetPrintWriter;
   import org.apache.james.util.watchdog.Watchdog;
   import org.apache.james.util.watchdog.WatchdogTarget;
  -import org.apache.mailet.dates.RFC2980DateFormat;
  +
   import org.apache.mailet.dates.RFC977DateFormat;
  +import org.apache.mailet.dates.RFC2980DateFormat;
   import org.apache.mailet.dates.SimplifiedDateFormat;
  +import org.apache.mailet.UsersRepository;
   
   /**
    * The NNTP protocol is defined by RFC 977.
  @@ -94,7 +109,6 @@
    * URL: http://www.ietf.org/internet-drafts/draft-ietf-nntpext-base-15.txt
    *
    * Common NNTP extensions are in RFC 2980.
  - *
    */
   public class NNTPHandler
       extends AbstractLogEnabled
  @@ -176,6 +190,11 @@
       private final static String COMMAND_QUIT = "QUIT";
   
       /**
  +     * The text string for the NNTP SLAVE command.
  +     */
  +    private final static String COMMAND_SLAVE = "SLAVE";
  +
  +    /**
        * The text string for the NNTP DATE command.
        */
       private final static String COMMAND_DATE = "DATE";
  @@ -226,6 +245,11 @@
       private final static String COMMAND_AUTHINFO = "AUTHINFO";
   
       /**
  +     * The text string for the NNTP PAT command.
  +     */
  +    private final static String COMMAND_PAT = "PAT";
  +
  +    /**
        * The text string for the NNTP MODE READER parameter.
        */
       private final static String MODE_TYPE_READER = "READER";
  @@ -246,22 +270,47 @@
       private final static String AUTHINFO_PARAM_PASS = "PASS";
   
       /**
  -     * The thread executing this handler
  +     * The character array that indicates termination of an NNTP message
  +     */
  +    private final static char[] NNTPTerminator = { '\r', '\n', '.', '\r', '\n' };
  +
  +    /**
  +     * The thread executing this handler 
        */
       private Thread handlerThread;
   
       /**
  +     * The remote host name obtained by lookup on the socket.
  +     */
  +    private String remoteHost;
  +
  +    /**
  +     * The remote IP address of the socket.
  +     */
  +    private String remoteIP;
  +
  +    /**
        * The TCP/IP socket over which the POP3 interaction
        * is occurring
        */
       private Socket socket;
   
       /**
  +     * The incoming stream of bytes coming from the socket.
  +     */
  +    private InputStream in;
  +
  +    /**
        * The reader associated with incoming characters.
        */
       private BufferedReader reader;
   
       /**
  +     * The socket's output stream
  +     */
  +    private OutputStream outs;
  +
  +    /**
        * The writer to which outgoing messages are written.
        */
       private PrintWriter writer;
  @@ -366,16 +415,31 @@
        * @see 
org.apache.avalon.cornerstone.services.connection.ConnectionHandler#handleConnection(Socket)
        */
       public void handleConnection( Socket connection ) throws IOException {
  -
           try {
               this.socket = connection;
               synchronized (this) {
                   handlerThread = Thread.currentThread();
               }
  -            reader = new BufferedReader(new 
InputStreamReader(socket.getInputStream(), "ASCII"), 1024);
  -            writer = new InternetPrintWriter(new BufferedWriter(new 
OutputStreamWriter(socket.getOutputStream()), 1024), true);
  +            remoteIP = socket.getInetAddress().getHostAddress();
  +            remoteHost = socket.getInetAddress().getHostName();
  +            in = new BufferedInputStream(socket.getInputStream(), 1024);
  +            // An ASCII encoding can be used because all transmissions other
  +            // that those in the message body command are guaranteed
  +            // to be ASCII
  +            reader = new BufferedReader(new InputStreamReader(in, "ASCII"), 512);
  +            outs = new BufferedOutputStream(socket.getOutputStream(), 1024);
  +            writer = new InternetPrintWriter(outs, true);
           } catch (Exception e) {
  -            getLogger().error( "Cannot open connection from: " + e.getMessage(), e 
);
  +            StringBuffer exceptionBuffer = 
  +                new StringBuffer(256)
  +                    .append("Cannot open connection from ")
  +                    .append(remoteHost)
  +                    .append(" (")
  +                    .append(remoteIP)
  +                    .append("): ")
  +                    .append(e.getMessage());
  +            String exceptionString = exceptionBuffer.toString();
  +            getLogger().error(exceptionString, e );
           }
   
           try {
  @@ -383,16 +447,16 @@
               if ( theConfigData.getNNTPRepository().isReadOnly() ) {
                   StringBuffer respBuffer =
                       new StringBuffer(128)
  -                    .append("201 ")
  -                    .append(theConfigData.getHelloName())
  -                    .append(" NNTP Service Ready, posting prohibited");
  +                        .append("201 ")
  +                        .append(theConfigData.getHelloName())
  +                        .append(" NNTP Service Ready, posting prohibited");
                   writeLoggedFlushedResponse(respBuffer.toString());
               } else {
                   StringBuffer respBuffer =
                       new StringBuffer(128)
  -                    .append("200 ")
  -                    .append(theConfigData.getHelloName())
  -                    .append(" NNTP Service Ready, posting permitted");
  +                            .append("200 ")
  +                            .append(theConfigData.getHelloName())
  +                            .append(" NNTP Service Ready, posting permitted");
                   writeLoggedFlushedResponse(respBuffer.toString());
               }
   
  @@ -402,17 +466,16 @@
               }
               theWatchdog.stop();
   
  -            getLogger().debug("Connection closed");
  +            getLogger().info("Connection closed");
           } catch (Exception e) {
  -            // if the connection has been idled out, the
  +            // If the connection has been idled out, the
               // socket will be closed and null.  Do NOT
               // log the exception or attempt to send the
               // closing connection message
               if (socket != null) {
                   try {
                       doQUIT(null);
  -                } catch(Throwable t) { }
  -
  +                } catch (Throwable t) {}
                   getLogger().error( "Exception during connection:" + e.getMessage(), 
e );
               }
           } finally {
  @@ -444,11 +507,16 @@
               reader = null;
           }
   
  +        in = null;
  +
           if (writer != null) {
               writer.close();
               writer = null;
           }
  +        outs = null;
   
  +        remoteHost = null;
  +        remoteIP = null;
           try {
               if (socket != null) {
                   socket.close();
  @@ -505,14 +573,20 @@
           }
           command = command.toUpperCase(Locale.US);
   
  +        boolean returnValue = true;
           if (!isAuthorized(command) ) {
               writeLoggedFlushedResponse("502 User is not authenticated");
               getLogger().debug("Command not allowed.");
  -            return true;
  +            return returnValue;
           }
  -        if ((command.equals(COMMAND_MODE)) && (argument != null) &&
  -            argument.toUpperCase(Locale.US).equals(MODE_TYPE_READER)) {
  -            doMODEREADER(argument);
  +        if ((command.equals(COMMAND_MODE)) && (argument != null)) {
  +            if (argument.toUpperCase(Locale.US).equals(MODE_TYPE_READER)) {
  +                doMODEREADER(argument);
  +            } else if (argument.toUpperCase(Locale.US).equals(MODE_TYPE_STREAM)) {
  +                doMODESTREAM(argument);
  +            } else {
  +                writeLoggedFlushedResponse("500 Command not understood");
  +            }
           } else if ( command.equals(COMMAND_LIST)) {
               doLIST(argument);
           } else if ( command.equals(COMMAND_GROUP) ) {
  @@ -535,6 +609,7 @@
               doIHAVE(argument);
           } else if ( command.equals(COMMAND_QUIT) ) {
               doQUIT(argument);
  +            returnValue = false;
           } else if ( command.equals(COMMAND_DATE) ) {
               doDATE(argument);
           } else if ( command.equals(COMMAND_HELP) ) {
  @@ -555,12 +630,14 @@
               doXHDR(argument);
           } else if ( command.equals(COMMAND_AUTHINFO) ) {
               doAUTHINFO(argument);
  -        } else if ( command.equals("PAT") ) {
  +        } else if ( command.equals(COMMAND_SLAVE) ) {
  +            doSLAVE(argument);
  +        } else if ( command.equals(COMMAND_PAT) ) {
               doPAT(argument);
           } else {
               doUnknownCommand(command, argument);
           }
  -        return (command.equals(COMMAND_QUIT) == false);
  +        return returnValue;
       }
   
       /**
  @@ -573,10 +650,10 @@
           if (getLogger().isDebugEnabled()) {
               StringBuffer logBuffer =
                   new StringBuffer(128)
  -                .append("Received unknown command ")
  -                .append(command)
  -                .append(" with argument ")
  -                .append(argument);
  +                    .append("Received unknown command ")
  +                    .append(command)
  +                    .append(" with argument ")
  +                    .append(argument);
               getLogger().debug(logBuffer.toString());
           }
           writeLoggedFlushedResponse("500 Unknown command");
  @@ -603,9 +680,7 @@
               writeLoggedFlushedResponse("501 Syntax error");
               return;
           }
  -
           command = command.toUpperCase(Locale.US);
  -
           if ( command.equals(AUTHINFO_PARAM_USER) ) {
               // Reject re-authentication
               if ( isAlreadyAuthenticated ) {
  @@ -656,12 +731,14 @@
        * an argument.
        *
        * @param argument the argument passed in with the NEWNEWS command.
  -     *                 Should be NEWNEWS newsgroups date time [GMT] [<distribution>]
        *                 see RFC 977 #3.8, RFC 2980 #4.5.
  +     *                 Should be a wildmat followed by a date.
        */
       private void doNEWNEWS(String argument) {
  +        // see section 11.4
   
           String wildmat = "*";
  +
           if (argument != null) {
               int spaceIndex = argument.indexOf(" ");
               if (spaceIndex >= 0) {
  @@ -688,16 +765,13 @@
           }
   
           writeLoggedFlushedResponse("230 list of new articles by message-id 
follows");
  -
  -        Iterator groups = 
theConfigData.getNNTPRepository().getMatchedGroups(wildmat);
  -        while (groups.hasNext() ) {
  -            Iterator articles = 
((NNTPGroup)(groups.next())).getArticlesSince(theDate);
  -            while ( articles.hasNext() ) {
  +        Iterator groupIter = 
theConfigData.getNNTPRepository().getMatchedGroups(wildmat);
  +        while ( groupIter.hasNext() ) {
  +            Iterator articleIter = 
((NNTPGroup)(groupIter.next())).getArticlesSince(theDate);
  +            while (articleIter.hasNext()) {
                   StringBuffer iterBuffer =
                       new StringBuffer(64)
  -                    .append("<")
  -                    .append(((NNTPArticle)articles.next()).getUniqueID())
  -                    .append(">");
  +                        .append(((NNTPArticle)articleIter.next()).getUniqueID());
                   writeLoggedResponse(iterBuffer.toString());
               }
           }
  @@ -708,18 +782,18 @@
        * Lists the groups added since the date passed in as
        * an argument.
        *
  -     * @param argument the argument passed in with the NEWNEWS command.
  +     * @param argument the argument passed in with the NEWGROUPS command.
        *                 Should be a date.
        */
       private void doNEWGROUPS(String argument) {
           // see section 11.3
  -        // both draft-ietf-nntpext-base-15.txt and rfc977 have only group names
  -        // in response lines, but INN sends
  +        // both draft-ietf-nntpext-base-15.txt and rfc977 have only group names 
  +        // in response lines, but INN sends 
           // '<group name> <last article> <first article> <posting allowed>'
           // NOTE: following INN over either document.
           //
           // TODO: Check this.  Audit at 
http://www.academ.com/pipermail/ietf-nntp/2001-July/002185.html
  -        // doesn't mention the supposed discrepancy.  Consider changing code to
  +        // doesn't mention the supposed discrepancy.  Consider changing code to 
           // be in line with spec.
           Date theDate = null;
           try {
  @@ -735,13 +809,13 @@
               NNTPGroup currentGroup = (NNTPGroup)iter.next();
               StringBuffer iterBuffer =
                   new StringBuffer(128)
  -                .append(currentGroup.getName())
  -                .append(" ")
  -                .append(currentGroup.getLastArticleNumber())
  -                .append(" ")
  -                .append(currentGroup.getFirstArticleNumber())
  -                .append(" ")
  -                .append((currentGroup.isPostAllowed()?"y":"n"));
  +                    .append(currentGroup.getName())
  +                    .append(" ")
  +                    .append(currentGroup.getLastArticleNumber())
  +                    .append(" ")
  +                    .append(currentGroup.getFirstArticleNumber())
  +                    .append(" ")
  +                    .append((currentGroup.isPostAllowed()?"y":"n"));
               writeLoggedResponse(iterBuffer.toString());
           }
           writeLoggedFlushedResponse(".");
  @@ -758,6 +832,16 @@
       }
   
       /**
  +     * Acknowledges a SLAVE command.  No special preference is given
  +     * to slave connections.
  +     *
  +     * @param argument the argument passed in with the SLAVE command.
  +     */
  +    private void doSLAVE(String argument) {
  +        writeLoggedFlushedResponse("202 slave status noted");
  +    }
  +
  +    /**
        * Returns the current date according to the news server.
        *
        * @param argument the argument passed in with the DATE command
  @@ -765,7 +849,7 @@
       private void doDATE(String argument) {
           Date dt = new Date(System.currentTimeMillis()-UTC_OFFSET);
           String dtStr = DF_RFC2980.format(new Date(dt.getTime() - UTC_OFFSET));
  -        writeLoggedFlushedResponse("111 "+dtStr);
  +        writeLoggedFlushedResponse("111 " + dtStr);
       }
   
       /**
  @@ -783,7 +867,6 @@
        * @param argument the argument passed in with the LIST command.
        */
       private void doLIST(String argument) {
  -
           // see section 9.4.1
           String wildmat = "*";
           boolean isListNewsgroups = false;
  @@ -857,7 +940,12 @@
               writeLoggedFlushedResponse("435 article not wanted - do not send it");
           } else {
               writeLoggedFlushedResponse("335 send article to be transferred. End 
with <CR-LF>.<CR-LF>");
  -            createArticle();
  +            try {
  +                createArticle();
  +            } catch (RuntimeException e) {
  +                writeLoggedFlushedResponse("436 transfer failed - try again later");
  +                throw e;
  +            }
               writeLoggedFlushedResponse("235 article received ok");
           }
       }
  @@ -897,8 +985,8 @@
               } else {
                   StringBuffer respBuffer =
                       new StringBuffer(64)
  -                    .append("223 0 ")
  -                    .append(param);
  +                            .append("223 0 ")
  +                            .append(param);
                   writeLoggedFlushedResponse(respBuffer.toString());
               }
           } else {
  @@ -930,10 +1018,10 @@
                       }
                       StringBuffer respBuffer =
                           new StringBuffer(128)
  -                        .append("223 ")
  -                        .append(article.getArticleNumber())
  -                        .append(" ")
  -                        .append(articleID);
  +                                .append("223 ")
  +                                .append(article.getArticleNumber())
  +                                .append(" ")
  +                                .append(articleID);
                       writeLoggedFlushedResponse(respBuffer.toString());
                   }
               }
  @@ -960,8 +1048,8 @@
               } else {
                   StringBuffer respBuffer =
                       new StringBuffer(64)
  -                    .append("222 0 ")
  -                    .append(param);
  +                            .append("222 0 ")
  +                            .append(param);
                   writeLoggedFlushedResponse(respBuffer.toString());
               }
           } else {
  @@ -993,16 +1081,17 @@
                       }
                       StringBuffer respBuffer =
                           new StringBuffer(128)
  -                        .append("222 ")
  -                        .append(article.getArticleNumber())
  -                        .append(" ")
  -                        .append(articleID);
  +                                .append("222 ")
  +                                .append(article.getArticleNumber())
  +                                .append(" ")
  +                                .append(articleID);
                       writeLoggedFlushedResponse(respBuffer.toString());
                   }
               }
           }
           if (article != null) {
  -            article.writeBody(writer);
  +            writer.flush();
  +            article.writeBody(new ExtraDotOutputStream(outs));
               writeLoggedFlushedResponse(".");
           }
       }
  @@ -1027,8 +1116,8 @@
               } else {
                   StringBuffer respBuffer =
                       new StringBuffer(64)
  -                    .append("221 0 ")
  -                    .append(param);
  +                            .append("221 0 ")
  +                            .append(param);
                   writeLoggedFlushedResponse(respBuffer.toString());
               }
           } else {
  @@ -1060,16 +1149,17 @@
                       }
                       StringBuffer respBuffer =
                           new StringBuffer(128)
  -                        .append("221 ")
  -                        .append(article.getArticleNumber())
  -                        .append(" ")
  -                        .append(articleID);
  +                                .append("221 ")
  +                                .append(article.getArticleNumber())
  +                                .append(" ")
  +                                .append(articleID);
                       writeLoggedFlushedResponse(respBuffer.toString());
                   }
               }
           }
           if (article != null) {
  -            article.writeHead(writer);
  +            writer.flush();
  +            article.writeHead(new ExtraDotOutputStream(outs));
               writeLoggedFlushedResponse(".");
           }
       }
  @@ -1094,8 +1184,8 @@
               } else {
                   StringBuffer respBuffer =
                       new StringBuffer(64)
  -                    .append("220 0 ")
  -                    .append(param);
  +                            .append("220 0 ")
  +                            .append(param);
                   writeLoggedResponse(respBuffer.toString());
               }
           } else {
  @@ -1127,16 +1217,17 @@
                       }
                       StringBuffer respBuffer =
                           new StringBuffer(128)
  -                        .append("220 ")
  -                        .append(article.getArticleNumber())
  -                        .append(" ")
  -                        .append(articleID);
  +                                .append("220 ")
  +                                .append(article.getArticleNumber())
  +                                .append(" ")
  +                                .append(articleID);
                       writeLoggedFlushedResponse(respBuffer.toString());
                   }
               }
           }
           if (article != null) {
  -            article.writeArticle(writer);
  +            writer.flush();
  +            article.writeArticle(new ExtraDotOutputStream(outs));
               writeLoggedFlushedResponse(".");
           }
       }
  @@ -1161,10 +1252,10 @@
               NNTPArticle article = group.getArticle(currentArticleNumber);
               StringBuffer respBuffer =
                   new StringBuffer(64)
  -                .append("223 ")
  -                .append(article.getArticleNumber())
  -                .append(" ")
  -                .append(article.getUniqueID());
  +                        .append("223 ")
  +                        .append(article.getArticleNumber())
  +                        .append(" ")
  +                        .append(article.getUniqueID());
               writeLoggedFlushedResponse(respBuffer.toString());
           }
       }
  @@ -1190,10 +1281,10 @@
               NNTPArticle article = group.getArticle(currentArticleNumber);
               StringBuffer respBuffer =
                   new StringBuffer(64)
  -                .append("223 ")
  -                .append(article.getArticleNumber())
  -                .append(" ")
  -                .append(article.getUniqueID());
  +                        .append("223 ")
  +                        .append(article.getArticleNumber())
  +                        .append(" ")
  +                        .append(article.getUniqueID());
               writeLoggedFlushedResponse(respBuffer.toString());
           }
       }
  @@ -1215,9 +1306,9 @@
           } else {
               group = newGroup;
               // if the number of articles in group == 0
  -            // then the server may return this information in 3 ways,
  +            // then the server may return this information in 3 ways, 
               // The clients must honor all those 3 ways.
  -            // our response is:
  +            // our response is: 
               // highWaterMark == lowWaterMark and number of articles == 0
               int articleCount = group.getNumberOfArticles();
               int lowWaterMark = group.getFirstArticleNumber();
  @@ -1233,15 +1324,15 @@
               }
               StringBuffer respBuffer =
                   new StringBuffer(128)
  -                .append("211 ")
  -                .append(articleCount)
  -                .append(" ")
  -                .append(lowWaterMark)
  -                .append(" ")
  -                .append(highWaterMark)
  -                .append(" ")
  -                .append(group.getName())
  -                .append(" group selected");
  +                        .append("211 ")
  +                        .append(articleCount)
  +                        .append(" ")
  +                        .append(lowWaterMark)
  +                        .append(" ")
  +                        .append(highWaterMark)
  +                        .append(" ")
  +                        .append(group.getName())
  +                        .append(" group selected");
               writeLoggedFlushedResponse(respBuffer.toString());
           }
       }
  @@ -1269,7 +1360,17 @@
       private void doMODEREADER(String argument) {
           // 7.2
           writeLoggedFlushedResponse(theConfigData.getNNTPRepository().isReadOnly()
  -                                   ? "201 Posting Not Permitted" : "200 Posting 
Permitted");
  +                       ? "201 Posting Not Permitted" : "200 Posting Permitted");
  +    }
  +
  +    /**
  +     * Informs the server that the client is a news server.
  +     *
  +     * @param argument the argument passed in with the MODE STREAM command
  +     */
  +    private void doMODESTREAM(String argument) {
  +        // 7.2
  +        writeLoggedFlushedResponse("500 Command not understood");
       }
   
       /**
  @@ -1340,7 +1441,7 @@
       }
   
       /**
  -     * Get the values of the headers for the selected newsgroup,
  +     * Get the values of the headers for the selected newsgroup, 
        * with an optional range modifier.
        *
        * @param argument the argument passed in with the XHDR command.
  @@ -1350,7 +1451,7 @@
       }
   
       /**
  -     * Get the values of the headers for the selected newsgroup,
  +     * Get the values of the headers for the selected newsgroup, 
        * with an optional range modifier.
        *
        * @param argument the argument passed in with the HDR command.
  @@ -1390,9 +1491,9 @@
                   }
                   StringBuffer hdrBuffer =
                       new StringBuffer(128)
  -                    .append(article[i].getArticleNumber())
  -                    .append(" ")
  -                    .append(val);
  +                            .append(article[i].getArticleNumber())
  +                            .append(" ")
  +                            .append(val);
                   writeLoggedResponse(hdrBuffer.toString());
               }
               writeLoggedFlushedResponse(".");
  @@ -1431,9 +1532,9 @@
           } else {
               writeLoggedResponse("224 Overview information follows");
               for ( int i = 0 ; i < article.length ; i++ ) {
  -                article[i].writeOverview(writer);
  +                article[i].writeOverview(outs);
                   if (i % 100 == 0) {
  -                    // Reset the watchdog ever hundred headers or so
  +                    // Reset the watchdog every hundred headers or so
                       // to ensure the connection doesn't timeout for slow
                       // clients
                       theWatchdog.reset();
  @@ -1447,7 +1548,51 @@
        * Handles the transaction for getting the article data.
        */
       private void createArticle() {
  -        theConfigData.getNNTPRepository().createArticle(new 
NNTPLineReaderImpl(reader));
  +        try {
  +            InputStream msgIn = new CharTerminatedInputStream(in, NNTPTerminator);
  +            // Removes the dot stuffing
  +            msgIn = new DotStuffingInputStream(msgIn);
  +            MailHeaders headers = new MailHeaders(msgIn);
  +            processMessageHeaders(headers);
  +            processMessage(headers, msgIn);
  +        } catch (MessagingException me) {
  +            throw new NNTPException("MessagingException encountered when loading 
article.");
  +        }
  +    }
  +
  +    /**
  +     * Processes the NNTP message headers coming in off the wire.
  +     *
  +     * @param headers the headers of the message being read
  +     */
  +    private MailHeaders processMessageHeaders(MailHeaders headers)
  +        throws MessagingException {
  +        return headers;
  +    }
  +
  +    /**
  +     * Processes the NNTP message coming in off the wire.  Reads the
  +     * content and delivers to the spool.
  +     *
  +     * @param headers the headers of the message being read
  +     * @param msgIn the stream containing the message content
  +     */
  +    private void processMessage(MailHeaders headers, InputStream bodyIn)
  +        throws MessagingException {
  +        InputStream messageIn = null;
  +        try {
  +            messageIn = new SequenceInputStream(new 
ByteArrayInputStream(headers.toByteArray()), bodyIn);
  +            theConfigData.getNNTPRepository().createArticle(messageIn);
  +        } finally {
  +            if (messageIn != null) {
  +                try {
  +                    messageIn.close();
  +                } catch (IOException ioe) {
  +                    // Ignore exception on close.
  +                }
  +                messageIn = null;
  +            }
  +        }
       }
   
       /**
  @@ -1473,9 +1618,9 @@
           try {
               StringBuffer dateStringBuffer =
                   new StringBuffer(64)
  -                .append(date)
  -                .append(" ")
  -                .append(time);
  +                    .append(date)
  +                    .append(" ")
  +                    .append(time);
               Date dt = DF_RFC977.parse(dateStringBuffer.toString());
               if ( utc ) {
                   dt = new Date(dt.getTime()+UTC_OFFSET);
  @@ -1484,12 +1629,12 @@
           } catch ( ParseException pe ) {
               StringBuffer exceptionBuffer =
                   new StringBuffer(128)
  -                .append("Date extraction failed: ")
  -                .append(date)
  -                .append(",")
  -                .append(time)
  -                .append(",")
  -                .append(utc);
  +                    .append("Date extraction failed: ")
  +                    .append(date)
  +                    .append(",")
  +                    .append(time)
  +                    .append(",")
  +                    .append(utc);
               throw new NNTPException(exceptionBuffer.toString());
           }
       }
  @@ -1592,10 +1737,10 @@
           } else {
               return false;
           }
  -    }
  +   }
   
       /**
  -     * This method logs at a "DEBUG" level the response string that
  +     * This method logs at a "DEBUG" level the response string that 
        * was sent to the SMTP client.  The method is provided largely
        * as syntactic sugar to neaten up the code base.  It is declared
        * private and final to encourage compiler inlining.
  @@ -1622,7 +1767,7 @@
       }
   
       /**
  -     * Write a response string.  The response is also logged.
  +     * Write a response string.  The response is also logged. 
        * Used for multi-line responses.
        *
        * @param responseString the response string sent to the client
  
  
  
  1.8       +10 -11    
jakarta-james/src/java/org/apache/james/nntpserver/repository/NNTPArticle.java
  
  Index: NNTPArticle.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-james/src/java/org/apache/james/nntpserver/repository/NNTPArticle.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- NNTPArticle.java  8 Mar 2003 21:14:04 -0000       1.7
  +++ NNTPArticle.java  26 Mar 2003 07:43:44 -0000      1.8
  @@ -58,11 +58,10 @@
   
   package org.apache.james.nntpserver.repository;
   
  -import java.io.PrintWriter;
  +import java.io.OutputStream;
   
  -/**
  +/** 
    * Contract exposed by a NewsGroup Article
  - *
    */
   public interface NNTPArticle {
   
  @@ -90,30 +89,30 @@
       /**
        * Writes the whole article to a writer.
        *
  -     * @param wrt the PrintWriter to which the article is written.
  +     * @param wrt the OutputStream to which the article is written.
        */
  -    void writeArticle(PrintWriter wrt);
  +    void writeArticle(OutputStream wrt);
   
       /**
        * Writes the article headers to a writer.
        *
  -     * @param wrt the PrintWriter to which the article is written.
  +     * @param wrt the OutputStream to which the article is written.
        */
  -    void writeHead(PrintWriter wrt);
  +    void writeHead(OutputStream wrt);
   
       /**
        * Writes the article body to a writer.
        *
  -     * @param wrt the PrintWriter to which the article is written.
  +     * @param wrt the OutputStream to which the article is written.
        */
  -    void writeBody(PrintWriter wrt);
  +    void writeBody(OutputStream wrt);
   
       /**
        * Writes the article overview to a writer.
        *
  -     * @param wrt the PrintWriter to which the article is written.
  +     * @param wrt the OutputStream to which the article is written.
        */
  -    void writeOverview(PrintWriter wrt);
  +    void writeOverview(OutputStream wrt);
   
       /**
        * Gets the header with the specified headerName.  Returns null
  
  
  
  1.20      +81 -60    
jakarta-james/src/java/org/apache/james/nntpserver/repository/NNTPArticleImpl.java
  
  Index: NNTPArticleImpl.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-james/src/java/org/apache/james/nntpserver/repository/NNTPArticleImpl.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- NNTPArticleImpl.java      8 Mar 2003 21:14:04 -0000       1.19
  +++ NNTPArticleImpl.java      26 Mar 2003 07:43:44 -0000      1.20
  @@ -58,22 +58,20 @@
   
   package org.apache.james.nntpserver.repository;
   
  +import org.apache.james.core.MailHeaders;
   import org.apache.james.nntpserver.NNTPException;
   import org.apache.avalon.excalibur.io.IOUtil;
   
   import javax.mail.internet.InternetHeaders;
  -
   import java.io.BufferedReader;
   import java.io.File;
   import java.io.FileInputStream;
   import java.io.FileReader;
   import java.io.IOException;
  -import java.io.PrintWriter;
  -
  +import java.io.OutputStream;
   
  -/**
  +/** 
    * Please see NNTPArticle for comments
  - *
    */
   class NNTPArticleImpl implements NNTPArticle {
   
  @@ -122,87 +120,99 @@
               InternetHeaders headers = new InternetHeaders(fin);
               String[] idheader = headers.getHeader("Message-Id");
               return ( idheader.length > 0 ) ? idheader[0] : null;
  -        } catch(Exception ex) { 
  -            throw new NNTPException(ex); 
  +        } catch(Exception ex) {
  +            throw new NNTPException(ex);
           } finally {
               IOUtil.shutdownStream(fin);
           }
       }
   
       /**
  -     * @see 
org.apache.james.nntpserver.repository.NNTPArticle#writeArticle(PrintWriter)
  +     * @see 
org.apache.james.nntpserver.repository.NNTPArticle#writeArticle(OutputStream)
        */
  -    public void writeArticle(PrintWriter prt) {
  -        BufferedReader reader = null;
  +    public void writeArticle(OutputStream out) {
  +        FileInputStream fileStream = null;
           try {
  -            reader = new BufferedReader(new FileReader(articleFile));
  -            String line = null;
  -            while ( ( line = reader.readLine() ) != null ) {
  -                // add extra dot if line starts with '.'
  -                // '.' indicates end of article.
  -                if ( line.startsWith(".") )
  -                    prt.print(".");
  -                prt.println(line);
  +            fileStream = new FileInputStream(articleFile);
  +            byte[] readBuffer = new byte[1024];
  +            int read = 0;
  +            while ((read = fileStream.read(readBuffer)) > 0) {
  +                out.write(readBuffer, 0, read);
               }
  -        } catch(IOException ex) {
  +        } catch(IOException ex) { 
               throw new NNTPException(ex);
           } finally {
  -            try {
  -                if (reader != null) {
  -                    reader.close();
  +            if (fileStream != null) {
  +                try {
  +                    fileStream.close();
  +                } catch (IOException ioe) {
  +                    // Ignored
                   }
  -            } catch (IOException ioe) {
  -                throw new NNTPException(ioe);
               }
           }
       }
   
       /**
  -     * @see 
org.apache.james.nntpserver.repository.NNTPArticle#writeHead(PrintWriter)
  +     * @see 
org.apache.james.nntpserver.repository.NNTPArticle#writeHead(OutputStream)
        */
  -    public void writeHead(PrintWriter prt) {
  +    public void writeHead(OutputStream out) {
  +        FileInputStream fileStream = null;
           try {
  -            BufferedReader reader = new BufferedReader(new FileReader(articleFile));
  -            String line = null;
  -            while ( ( line = reader.readLine() ) != null ) {
  -                if ( line.trim().length() == 0 )
  -                    break;
  -                if ( line.startsWith(".") )
  -                    prt.print(".");
  -                prt.println(line);
  +            fileStream = new FileInputStream(articleFile);
  +            MailHeaders headers = new MailHeaders(fileStream);
  +            byte[] headerBuffer = headers.toByteArray();
  +            int headerBufferLength = headerBuffer.length;
  +            // Write the headers excluding the final CRLF pair
  +            if (headerBufferLength > 2) {
  +                out.write(headerBuffer, 0, (headerBufferLength - 2));
               }
  -            reader.close();
  -        } catch(IOException ex) { throw new NNTPException(ex); }
  +        } catch(Exception ex) { 
  +            throw new NNTPException(ex);
  +        } finally {
  +            if (fileStream != null) {
  +                try {
  +                    fileStream.close();
  +                } catch (IOException ioe) {
  +                    // Ignored
  +                }
  +            }
  +        }
       }
   
       /**
  -     * @see 
org.apache.james.nntpserver.repository.NNTPArticle#writeBody(PrintWriter)
  +     * @see 
org.apache.james.nntpserver.repository.NNTPArticle#writeBody(OutputStream)
        */
  -    public void writeBody(PrintWriter prt) {
  +    public void writeBody(OutputStream out) {
  +        FileInputStream fileStream = null;
           try {
  -            BufferedReader reader = new BufferedReader(new FileReader(articleFile));
  -            String line = null;
  -            boolean startWriting = false;
  -            while ( ( line = reader.readLine() ) != null ) {
  -                if ( startWriting ) {
  -                    if ( line.startsWith(".") )
  -                        prt.print(".");
  -                    prt.println(line);
  -                } else
  -                    startWriting = ( line.trim().length() == 0 );
  +            fileStream = new FileInputStream(articleFile);
  +            MailHeaders headers = new MailHeaders(fileStream);
  +            byte[] readBuffer = new byte[1024];
  +            int read = 0;
  +            while ((read = fileStream.read(readBuffer)) > 0) {
  +                out.write(readBuffer, 0, read);
  +            }
  +        } catch(Exception ex) {
  +            throw new NNTPException(ex);
  +        } finally {
  +            if (fileStream != null) {
  +                try {
  +                    fileStream.close();
  +                } catch (IOException ioe) {
  +                    // Ignored
  +                }
               }
  -            reader.close();
  -        } catch(IOException ex) { throw new NNTPException(ex); }
  +        }
       }
   
       /**
  -     * @see 
org.apache.james.nntpserver.repository.NNTPArticle#writeOverview(PrintWriter)
  +     * @see 
org.apache.james.nntpserver.repository.NNTPArticle#writeOverview(OutputStream)
        */
  -    public void writeOverview(PrintWriter prt) {
  +    public void writeOverview(OutputStream out) {
  +        FileInputStream fileStream = null;
           try {
  -            FileInputStream fin = new FileInputStream(articleFile);
  -            InternetHeaders hdr = new InternetHeaders(fin);
  -            fin.close();
  +            fileStream = new FileInputStream(articleFile);
  +            InternetHeaders hdr = new InternetHeaders(fileStream);
               String subject = hdr.getHeader("Subject",null);
               String author = hdr.getHeader("From",null);
               String date = hdr.getHeader("Date",null);
  @@ -212,16 +222,27 @@
               // TODO: Address the line count issue.
               long lineCount = -1;
               StringBuffer line=new StringBuffer(256)
  -                .append(getArticleNumber())      .append("\t")
  +                .append(getArticleNumber())    .append("\t")
                   .append(cleanHeader(subject))    .append("\t")
                   .append(cleanHeader(author))     .append("\t")
                   .append(cleanHeader(date))       .append("\t")
                   .append(cleanHeader(msgId))      .append("\t")
                   .append(cleanHeader(references)) .append("\t")
                   .append(byteCount)               .append("\t")
  -                .append(lineCount);
  -            prt.println(line.toString());
  -        } catch(Exception ex) { throw new NNTPException(ex); }
  +                .append(lineCount).append("\r\n");
  +            String lineString = line.toString();
  +            out.write(lineString.getBytes("ASCII"));
  +        } catch(Exception ex) {
  +            throw new NNTPException(ex);
  +        } finally {
  +            if (fileStream != null) {
  +                try {
  +                    fileStream.close();
  +                } catch (IOException ioe) {
  +                    // Ignored
  +                }
  +            }
  +        }
       }
   
       /**
  @@ -252,7 +273,7 @@
           StringBuffer sb = new StringBuffer(field);
           for( int i=0 ; i<sb.length() ; i++ ) {
               char c = sb.charAt(i);
  -            if( (c=='\n') || (c=='\t') || (c=='\r') ) {
  +            if( (c=='\n') || (c=='\t') || (c=='\r')) {
                   sb.setCharAt(i, ' ');
               }
           }
  
  
  
  1.9       +4 -3      
jakarta-james/src/java/org/apache/james/nntpserver/repository/NNTPRepository.java
  
  Index: NNTPRepository.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-james/src/java/org/apache/james/nntpserver/repository/NNTPRepository.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- NNTPRepository.java       8 Mar 2003 21:14:05 -0000       1.8
  +++ NNTPRepository.java       26 Mar 2003 07:43:44 -0000      1.9
  @@ -58,12 +58,12 @@
   
   package org.apache.james.nntpserver.repository;
   
  +import java.io.InputStream;
   import java.util.Date;
   import java.util.Iterator;
   
   /**
    * Abstraction of entire NNTP Repository.
  - *
    */
   public interface NNTPRepository {
   
  @@ -87,10 +87,11 @@
   
       /**
        * Creates an article in the repository from the data in the reader.
  +     * TODO: Change this to be more OO and pass in a MimeMessage
        *
  -     * @param reader the reader that serves as a source for the article data
  +     * @param in the InputStream that serves as a source for the message data.
        */
  -    void createArticle(NNTPLineReader reader);
  +    void createArticle(InputStream in);
   
       /**
        * Gets all groups that match the wildmat string
  
  
  
  1.16      +90 -49    
jakarta-james/src/java/org/apache/james/nntpserver/repository/NNTPRepositoryImpl.java
  
  Index: NNTPRepositoryImpl.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-james/src/java/org/apache/james/nntpserver/repository/NNTPRepositoryImpl.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- NNTPRepositoryImpl.java   8 Mar 2003 21:14:05 -0000       1.15
  +++ NNTPRepositoryImpl.java   26 Mar 2003 07:43:44 -0000      1.16
  @@ -64,6 +64,7 @@
   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.container.ContainerUtil;
   import org.apache.avalon.framework.context.Context;
   import org.apache.avalon.framework.context.ContextException;
   import org.apache.avalon.framework.context.Contextualizable;
  @@ -76,6 +77,7 @@
   
   import java.io.File;
   import java.io.FileOutputStream;
  +import java.io.InputStream;
   import java.io.IOException;
   import java.io.PrintStream;
   import java.util.ArrayList;
  @@ -83,14 +85,14 @@
   import java.util.HashMap;
   import java.util.Iterator;
   import java.util.List;
  +import java.util.Set;
   
   /**
    * NNTP Repository implementation.
  - *
    */
  -public class NNTPRepositoryImpl extends AbstractLogEnabled
  -    implements NNTPRepository, Contextualizable, Configurable, Initializable
  -{
  +public class NNTPRepositoryImpl extends AbstractLogEnabled 
  +    implements NNTPRepository, Contextualizable, Configurable, Initializable {
  +
       /**
        * The context employed by this repository
        */
  @@ -127,9 +129,9 @@
       private ArticleIDRepository articleIDRepo;
   
       /**
  -     * The list of groups stored in this repository
  +     * A map to allow lookup of valid newsgroup names
        */
  -    private String[] addGroups = null;
  +    private HashMap groupNameMap = null;
   
       /**
        * The root path as a String.
  @@ -185,22 +187,41 @@
       public void configure( Configuration aConfiguration ) throws 
ConfigurationException {
           configuration = aConfiguration;
           readOnly = configuration.getChild("readOnly").getValueAsBoolean(false);
  +        articleIDDomainSuffix = configuration.getChild("articleIDDomainSuffix")
  +            .getValue("foo.bar.sho.boo");
  +        rootPathString = configuration.getChild("rootPath").getValue(null);
  +        if (rootPathString == null) {
  +            throw new ConfigurationException("Root path URL is required.");
  +        }
  +        tempPathString = configuration.getChild("tempPath").getValue(null);
  +        if (tempPathString == null) {
  +            throw new ConfigurationException("Temp path URL is required.");
  +        }
  +        articleIdPathString = 
configuration.getChild("articleIDPath").getValue(null);
  +        if (articleIdPathString == null) {
  +            throw new ConfigurationException("Article ID path URL is required.");
  +        }
  +        if (getLogger().isDebugEnabled()) {
  +            if (readOnly) {
  +                getLogger().debug("NNTP repository is read only.");
  +            } else {
  +                getLogger().debug("NNTP repository is writeable.");
  +            }
  +            getLogger().debug("NNTP repository root path URL is " + rootPathString);
  +            getLogger().debug("NNTP repository temp path URL is " + tempPathString);
  +            getLogger().debug("NNTP repository article ID path URL is " + 
articleIdPathString);
  +        }
           Configuration newsgroupConfiguration = configuration.getChild("newsgroups");
  -        List addGroupsList = new ArrayList();
  -        if ( configuration != null ) {
  +        groupNameMap = new HashMap();
  +        if ( newsgroupConfiguration != null ) {
               Configuration[] children = 
newsgroupConfiguration.getChildren("newsgroup");
               if ( children != null ) {
                   for ( int i = 0 ; i < children.length ; i++ ) {
  -                    addGroupsList.add(children[i].getValue());
  +                    String groupName = children[i].getValue();
  +                    groupNameMap.put(groupName, groupName);
                   }
               }
           }
  -        articleIDDomainSuffix = configuration.getChild("articleIDDomainSuffix")
  -            .getValue("foo.bar.sho.boo");
  -        addGroups = (String[])addGroupsList.toArray(new String[0]);
  -        rootPathString = configuration.getChild("rootPath").getValue();
  -        tempPathString = configuration.getChild("tempPath").getValue();
  -        articleIdPathString = configuration.getChild("articleIDPath").getValue();
           getLogger().debug("Repository configuration done");
       }
   
  @@ -209,6 +230,7 @@
        */
       public void initialize() throws Exception {
   
  +        getLogger().debug("Starting initialize");
           File articleIDPath = null;
   
           try {
  @@ -245,15 +267,18 @@
               throw new ConfigurationException(errorBuffer.toString());
           }
   
  -        for ( int i = 0 ; i < addGroups.length ; i++ ) {
  -            File groupFile = new File(rootPath,addGroups[i]);
  +        Set groups = groupNameMap.keySet();
  +        Iterator groupIterator = groups.iterator();
  +        while( groupIterator.hasNext() ) {
  +            String groupName = (String)groupIterator.next();
  +            File groupFile = new File(rootPath,groupName);
               if ( groupFile.exists() == false ) {
                   groupFile.mkdirs();
               } else if (!(groupFile.isDirectory())) {
                   StringBuffer errorBuffer =
                       new StringBuffer(128)
                           .append("A file exists in the NNTP root directory with the 
same name as a newsgroup.  File ")
  -                        .append(addGroups[i])
  +                        .append(groupName)
                           .append("in directory ")
                           .append(rootPathString)
                           .append(" is not a directory.");
  @@ -285,14 +310,27 @@
        * @see org.apache.james.nntpserver.repository.NNTPRepository#getGroup(String)
        */
       public NNTPGroup getGroup(String groupName) {
  +        if (groupNameMap.get(groupName) == null) {
  +            if (getLogger().isDebugEnabled()) {
  +                getLogger().debug(groupName + " is not a newsgroup hosted on this 
server.");
  +            }
  +            return null;
  +        }
           File groupFile = new File(rootPath,groupName);
           NNTPGroup groupToReturn = null;
           synchronized(this) {
               groupToReturn = (NNTPGroup)repositoryGroups.get(groupName);
               if ((groupToReturn == null) && groupFile.exists() && 
groupFile.isDirectory() ) {
  -                groupToReturn = new NNTPGroupImpl(groupFile);
  -                ((NNTPGroupImpl)groupToReturn).enableLogging(getLogger());
  -                repositoryGroups.put(groupName, groupToReturn);
  +                try {
  +                    groupToReturn = new NNTPGroupImpl(groupFile);
  +                    ContainerUtil.enableLogging(groupToReturn, getLogger());
  +                    ContainerUtil.contextualize(groupToReturn, context);
  +                    ContainerUtil.initialize(groupToReturn);
  +                    repositoryGroups.put(groupName, groupToReturn);
  +                } catch (Exception e) {
  +                    getLogger().error("Couldn't create group object.", e);
  +                    groupToReturn = null;
  +                }
               }
           }
           return groupToReturn;
  @@ -308,34 +346,43 @@
               ex.printStackTrace();
               return null;
           }
  -//         int idx = id.indexOf('@');
  -//         String name = id.substring(0,idx);
  -//         String groupname = id.substring(idx+1);
  -//         NNTPGroup group = getGroup(groupname);
  -//         return ( group == null ) ? null : group.getArticleFromID(name);
       }
   
       /**
  -     * @see 
org.apache.james.nntpserver.repository.NNTPRepository#createArticle(NNTPLineReader)
  +     * @see 
org.apache.james.nntpserver.repository.NNTPRepository#createArticle(InputStream)
        */
  -    public void createArticle(NNTPLineReader reader) {
  +    public void createArticle(InputStream in) {
           StringBuffer fileBuffer =
               new StringBuffer(32)
                       .append(System.currentTimeMillis())
                       .append(".")
                       .append(Math.random());
           File f = new File(tempPath, fileBuffer.toString());
  +        FileOutputStream fout = null;
           try {
  -            FileOutputStream fout = new FileOutputStream(f);
  -            PrintStream prt = new PrintStream(fout,true);
  -            String line;
  -            while ( ( line = reader.readLine() ) != null ) {
  -                prt.println(line);
  +            fout = new FileOutputStream(f);
  +            byte[] readBuffer = new byte[1024];
  +            int bytesRead = 0;
  +            while ( ( bytesRead = in.read(readBuffer, 0, 1024) ) > 0 ) {
  +                fout.write(readBuffer, 0, bytesRead);
  +            }
  +            fout.flush();
  +            fout.close();
  +            fout = null;
  +            boolean renamed = f.renameTo(new 
File(spool.getSpoolPath(),f.getName()));
  +            if (!renamed) {
  +                throw new IOException("Could not create article on the spool.");
               }
  -            prt.close();
  -            f.renameTo(new File(spool.getSpoolPath(),f.getName()));
           } catch(IOException ex) {
               throw new NNTPException("create article failed",ex);
  +        } finally {
  +            if (fout != null) {
  +                try {
  +                    fout.close();
  +                } catch (IOException ioe) {
  +                    // Ignored
  +                }
  +            }
           }
       }
   
  @@ -343,6 +390,7 @@
        * @see 
org.apache.james.nntpserver.repository.NNTPRepository#getMatchedGroups(String)
        */
       public Iterator getMatchedGroups(String wildmat) {
  +        // TODO: Add filter for valid group names
           File[] f = rootPath.listFiles(new AndFileFilter
               (new DirectoryFileFilter(),new GlobFilenameFilter(wildmat)));
           return getGroups(f);
  @@ -370,6 +418,7 @@
        * @see 
org.apache.james.nntpserver.repository.NNTPRepository#getGroupsSince(Date)
        */
       public Iterator getGroupsSince(Date dt) {
  +        // TODO: Add filter for valid group names
           File[] f = rootPath.listFiles(new AndFileFilter
               (new DirectoryFileFilter(),new DateSinceFileFilter(dt.getTime())));
           return getGroups(f);
  @@ -428,7 +477,7 @@
        *
        * TODO: This method doesn't properly implement the Avalon lifecycle.
        */
  -    private NNTPSpooler createSpooler()
  +    private NNTPSpooler createSpooler() 
               throws ConfigurationException {
           String className = "org.apache.james.nntpserver.repository.NNTPSpooler";
           Configuration spoolerConfiguration = configuration.getChild("spool");
  @@ -440,19 +489,11 @@
           }
           try {
               Object obj = 
getClass().getClassLoader().loadClass(className).newInstance();
  -            // TODO: Need to support compose
  -            if ( obj instanceof LogEnabled ) {
  -                ((LogEnabled)obj).enableLogging( getLogger() );
  -            }
  -            if (obj instanceof Contextualizable) {
  -                ((Contextualizable)obj).contextualize(context);
  -            }
  -            if ( obj instanceof Configurable ) {
  -                
((Configurable)obj).configure(spoolerConfiguration.getChild("configuration"));
  -            }
  -            if ( obj instanceof Initializable ) {
  -                ((Initializable)obj).initialize();
  -            }
  +            // TODO: Need to support service
  +            ContainerUtil.enableLogging(obj, getLogger());
  +            ContainerUtil.contextualize(obj, context);
  +            ContainerUtil.configure(obj, 
spoolerConfiguration.getChild("configuration"));
  +            ContainerUtil.initialize(obj);
               return (NNTPSpooler)obj;
           } catch(ClassCastException cce) {
               StringBuffer errorBuffer =
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to