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 da...@apache.org on 2002/11/26 15:53:49 UTC

cvs commit: jakarta-james/proposals/imap2/test/org/apache/james/test FileProtocolSessionBuilder.java InvalidServerResponseException.java ProtocolSession.java AbstractProtocolTest.java JamesTask.java SimpleFileProtocolTest.java

darrell     2002/11/26 06:53:49

  Modified:    proposals/imap2 build-test.xml build.xml
               proposals/imap2/java/org/apache/james/imapserver
                        ImapConstants.java ImapHandler.java
                        ImapRequestLineReader.java ImapSession.java
                        JamesImapHost.java
               proposals/imap2/java/org/apache/james/imapserver/commands
                        CapabilityCommand.java CommandParser.java
                        ImapCommandFactory.java LoginCommand.java
                        StatusCommand.java
               proposals/imap2/test/org/apache/james/imapserver
                        Capability.test CommandParserTest.java
                        IMAPTest.java ImapHostTest.java ImapStoreTest.java
                        InitialMail.java TestAuthenticated.java
                        TestNonAuthenticated.java TestSelected.java
               proposals/imap2/test/org/apache/james/remotemanager
                        TestRemoteManager.java UserManagementTest.java
               proposals/imap2/test/org/apache/james/smtpserver
                        TestSMTP.java
               proposals/imap2/test/org/apache/james/test
                        AbstractProtocolTest.java JamesTask.java
                        SimpleFileProtocolTest.java
  Added:       proposals/imap2/java/org/apache/james/imapserver
                        ImapRequestHandler.java ImapSessionImpl.java
               proposals/imap2/test/org/apache/james/imapserver Status.test
                        StringArgs.test
               proposals/imap2/test/org/apache/james/remotemanager
                        InitialImapUsersTest.java InitialUsers.test
               proposals/imap2/test/org/apache/james/test
                        FileProtocolSessionBuilder.java
                        InvalidServerResponseException.java
                        ProtocolSession.java
  Removed:     proposals/imap2/test/org/apache/james/imapserver
                        InitialUsers.java
  Log:
  IMAP Proposal updates.
  
  * Implemented rfc2088 - Non synchronised literals
    - Now correctly handle both {3}\nXXX and {3+}XXX stringliterals.
  
  * Separated most imap-specific code out of ImapHandler and into ImapRequestHandler.
    ImapHandler is now a relatively generic copy of the POP3Handler, with the
    ImapRequestHandler having a standard "process( Reader, Writer, Session)" type interface.
    Hopefully, the patterns used in this proposal will prove useful in refactoring some of
    the other protocol servers.
  
  * implemented the STATUS command.
  
  * Modified testing framework so that protocol tests can be run directly against
    the ImapRequestHandler (or other generic request handler), without sending
    requests over the wire. This is very useful for rapid development and debugging,
    as it eliminates the deploy/start-phoenix cycle, and allows the command processing
    code to be easily debugged. (Over-the-wire testing still works, using the same
    protocol definition files).
  
  * Separated the actual protocol simulation functionality from the JUnit tests,
    and moved the generation of a ProtocolSession from a file into a separate builder.
    This will allow different mechanisms for defining protocol sessions (eg javascript),
    and different means for execution, eg JUnit, Ant task, executable, JetSpeed?
  
  Revision  Changes    Path
  1.3       +16 -6     jakarta-james/proposals/imap2/build-test.xml
  
  Index: build-test.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/build-test.xml,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- build-test.xml	25 Nov 2002 01:11:44 -0000	1.2
  +++ build-test.xml	26 Nov 2002 14:53:47 -0000	1.3
  @@ -58,16 +58,18 @@
       <property name="build.classes" value="${build.dir}/classes"/>
       <property name="build.test.classes" value="${build.dir}/test/classes"/>
   
  +    <property name="xerces.jar" value="${lib.dir}/xerces-1.4.3.jar"/>
  +
       <path id="test.class.path">
           <pathelement location="${build.classes}"/>
  +        <pathelement location="${xerces.jar}"/>
  +        <pathelement path="${java.class.path}"/>
           <fileset dir="${lib.dir}">
  -            <include name="junit-3.7.jar"/>
  -            <include name="mail_1_2.jar"/>
  -            <include name="activation.jar"/>
  -            <include name="jakarta-oro-2.0.1.jar"/>
  +            <include name="*.jar"/>
  +            <exclude name="xerces.jar"/>
           </fileset>
           <fileset dir="${phoenix.dir}/lib">
  -            <include name="avalon-framework-4.1.3.jar"/>
  +            <include name="*.jar"/>
           </fileset>
           <fileset dir="${phoenix.dir}/bin/lib">
               <include name="phoenix-engine.jar"/>
  @@ -141,10 +143,13 @@
                   <pathelement location="${build.test.classes}"/>
                   <path refid="test.class.path"/>
               </classpath>
  +            <sysproperty key="runTestsLocal" value="true"/>
               <formatter type="plain" usefile="false"/>
               <test name="org.apache.james.imapserver.ImapHostTest"/>
               <test name="org.apache.james.imapserver.CommandParserTest"/>
               <test name="org.apache.james.imapserver.ImapStoreTest"/>
  +            <test name="org.apache.james.imapserver.TestNonAuthenticated"/>
  +            <test name="org.apache.james.imapserver.TestAuthenticated"/>
           </junit>
       </target>
   
  @@ -161,8 +166,9 @@
                   <pathelement location="${build.test.classes}"/>
                   <path refid="test.class.path"/>
               </classpath>
  +            <sysproperty key="runTestsLocal" value="false"/>
               <formatter type="plain" usefile="false"/>
  -            <test name="org.apache.james.imapserver.InitialUsers"/>
  +            <test name="org.apache.james.remotemanager.InitialImapUsersTest"/>
               <test name="org.apache.james.imapserver.InitialMail"/>
           </junit>
       </target>
  @@ -174,6 +180,7 @@
                   <pathelement location="${build.test.classes}"/>
                   <path refid="test.class.path"/>
               </classpath>
  +            <sysproperty key="runTestsLocal" value="false"/>
               <formatter type="plain" usefile="false"/>
               <test name="org.apache.james.imapserver.TestNonAuthenticated"/>
           </junit>
  @@ -186,6 +193,7 @@
                   <pathelement location="${build.test.classes}"/>
                   <path refid="test.class.path"/>
               </classpath>
  +            <sysproperty key="runTestsLocal" value="false"/>
               <formatter type="plain" usefile="false"/>
               <test name="org.apache.james.imapserver.TestAuthenticated"/>
           </junit>
  @@ -198,6 +206,7 @@
                   <pathelement location="${build.test.classes}"/>
                   <path refid="test.class.path"/>
               </classpath>
  +            <sysproperty key="runTestsLocal" value="false"/>
               <formatter type="plain" usefile="false"/>
               <test name="org.apache.james.imapserver.TestSelected"/>
           </junit>
  @@ -209,6 +218,7 @@
                   <pathelement location="${build.test.classes}"/>
                   <path refid="test.class.path"/>
               </classpath>
  +            <sysproperty key="runTestsLocall" value="false"/>
               <formatter type="plain" usefile="false"/>
               <test name="org.apache.james.remotemanager.TestRemoteManager"/>
           </junit>
  
  
  
  1.2       +2 -2      jakarta-james/proposals/imap2/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/build.xml,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- build.xml	22 Nov 2002 02:09:50 -0000	1.1
  +++ build.xml	26 Nov 2002 14:53:47 -0000	1.2
  @@ -218,7 +218,7 @@
                                     compile
          ===================================================================
     -->
  -    <target name="compile" depends="prepare,prepare-jdbc3">
  +    <target name="compile" depends="prepare,prepare-jdbc3" description="Compiles the source.">
           <!-- First compile the main James tree, leaving out any files that
                overlap with the IMAP proposal. -->
           <echo message="compiling James"/>
  
  
  
  1.2       +1 -0      jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapConstants.java
  
  Index: ImapConstants.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapConstants.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ImapConstants.java	22 Nov 2002 02:09:50 -0000	1.1
  +++ ImapConstants.java	26 Nov 2002 14:53:47 -0000	1.2
  @@ -18,6 +18,7 @@
   
       String SP = " ";
       String VERSION = "IMAP4rev1";
  +    String CAPABILITIES = "LITERAL+";
   
       String USER_NAMESPACE = "#mail";
   
  
  
  
  1.3       +12 -149   jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapHandler.java
  
  Index: ImapHandler.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapHandler.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- ImapHandler.java	25 Nov 2002 01:11:44 -0000	1.2
  +++ ImapHandler.java	26 Nov 2002 14:53:47 -0000	1.3
  @@ -12,6 +12,7 @@
   import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.logger.AbstractLogEnabled;
   import org.apache.avalon.framework.logger.Logger;
  +import org.apache.avalon.framework.logger.LogEnabled;
   import org.apache.james.Constants;
   import org.apache.james.imapserver.commands.ImapCommand;
   import org.apache.james.imapserver.commands.ImapCommandFactory;
  @@ -30,6 +31,8 @@
   import java.io.InputStreamReader;
   import java.io.OutputStream;
   import java.io.PrintWriter;
  +import java.io.Writer;
  +import java.io.Reader;
   import java.net.Socket;
   
   /**
  @@ -46,11 +49,8 @@
   {
   
       private String softwaretype = "JAMES IMAP4rev1 Server " + Constants.SOFTWARE_VERSION;
  -    private ImapResponse untaggedResponse;
  -    private ImapRequestLineReader request;
  -    private CommandParser parser = new CommandParser();
  +    private ImapRequestHandler requestHandler = new ImapRequestHandler();
       private ImapSession session;
  -    private ImapCommandFactory imapCommands = new ImapCommandFactory();
   
       /**
        * The per-service configuration data that applies to all handlers
  @@ -97,7 +97,6 @@
        * The watchdog target that idles out this handler.
        */
       private WatchdogTarget theWatchdogTarget = new IMAPWatchdogTarget();
  -    private static final String REQUEST_SYNTAX = "Protocol Error: Was expecting <tag SPACE command [arguments]>";
   
       /**
        * Set the configuration data for the handler.
  @@ -209,7 +208,7 @@
           try {
               outs = new BufferedOutputStream( socket.getOutputStream(), 1024 );
               out = new InternetPrintWriter( outs, true );
  -            untaggedResponse = new ImapResponse( out );
  +            ImapResponse untaggedResponse = new ImapResponse( out );
   
               // Write welcome message
               StringBuffer responseBuffer =
  @@ -220,11 +219,14 @@
                       .append( " ready" );
               untaggedResponse.okResponse( null, responseBuffer.toString() );
   
  -            request = new ImapRequestLineReader( in );
  -            session = new ImapSessionImpl();
  +            session = new ImapSessionImpl( theConfigData.getImapHost(),
  +                                           theConfigData.getUsersRepository(),
  +                                           this,
  +                                           socket.getInetAddress().getHostName(),
  +                                           socket.getInetAddress().getHostAddress());
   
               theWatchdog.start();
  -            while ( parseCommand() ) {
  +            while ( requestHandler.handleRequest( in, out, session ) ) {
                   theWatchdog.reset();
               }
               theWatchdog.stop();
  @@ -265,7 +267,7 @@
       /**
        * Resets the handler data to a basic state.
        */
  -    private void resetHandler()
  +    void resetHandler()
       {
   
           if ( theWatchdog != null ) {
  @@ -364,63 +366,6 @@
       }
   
       /**
  -     * This method parses POP3 commands read off the wire in handleConnection.
  -     * Actual processing of the command (possibly including additional back and
  -     * forth communication with the client) is delegated to one of a number of
  -     * command specific handler methods.  The primary purpose of this method is
  -     * to parse the raw command string to determine exactly which handler should
  -     * be called.  It returns true if expecting additional commands, false otherwise.
  -     *
  -     * @return whether additional commands are expected.
  -     */
  -    private boolean parseCommand() throws ProtocolException
  -    {
  -        try {
  -            request.nextChar();
  -        }
  -        catch ( ProtocolException e ) {
  -            return false;
  -        }
  -        ImapResponse response = new ImapResponse( out );
  -        String tag = null;
  -        String commandName = null;
  -
  -        try {
  -            tag = parser.tag( request );
  -        }
  -        catch ( ProtocolException e ) {
  -            response.badResponse( REQUEST_SYNTAX );
  -            return true;
  -        }
  -
  -        System.out.println( "Got <tag>: " + tag );
  -        response.setTag( tag );
  -        try {
  -            commandName = parser.atom( request );
  -        }
  -        catch ( ProtocolException e ) {
  -            response.commandError( REQUEST_SYNTAX );
  -            return true;
  -        }
  -
  -        System.out.println( "Got <command>: " + commandName );
  -        ImapCommand command = imapCommands.getCommand( commandName );
  -        if ( command == null )
  -        {
  -            response.commandError( "Invalid command.");
  -            return true;
  -        }
  -
  -        if ( !command.validForState( session.getState() ) ) {
  -            response.commandFailed( command, "Command not valid in this state" );
  -            return true;
  -        }
  -        
  -        command.process( request, response, session );
  -        return true;
  -    }
  -
  -    /**
        * This method logs at a "DEBUG" level the response string that
        * was sent to the POP3 client.  The method is provided largely
        * as syntactic sugar to neaten up the code base.  It is declared
  @@ -480,87 +425,5 @@
   
       }
   
  -    private final class ImapSessionImpl implements ImapSession
  -    {
  -        private ImapSessionState state = ImapSessionState.NON_AUTHENTICATED;
  -        private User user = null;
  -        private ImapMailbox selectedMailbox = null;
  -        // TODO: Use a session-specific wrapper for user's view of mailbox
  -        // this wrapper would provide access control and track if the mailbox
  -        // is opened read-only.
  -        private boolean selectedIsReadOnly = false;
  -
  -        public ImapHost getHost()
  -        {
  -            return theConfigData.getImapHost();
  -        }
  -
  -        public void unsolicitedResponses( ImapResponse request )
  -        {
  -        }
  -
  -        public void closeConnection()
  -        {
  -            resetHandler();
  -        }
  -
  -        public UsersRepository getUsers()
  -        {
  -            return theConfigData.getUsersRepository();
  -        }
  -
  -        public Logger getSecurityLogger()
  -        {
  -            return getLogger();
  -        }
  -
  -        public String getClientHostname()
  -        {
  -            return socket.getInetAddress().getHostName();
  -        }
  -
  -        public String getClientIP()
  -        {
  -            return socket.getInetAddress().getHostAddress();
  -        }
  -
  -        public void setAuthenticated( User user )
  -        {
  -            this.state = ImapSessionState.AUTHENTICATED;
  -            this.user = user;
  -        }
  -
  -        public User getUser()
  -        {
  -            return this.user;
  -        }
  -
  -        public void deselect()
  -        {
  -            this.state = ImapSessionState.AUTHENTICATED;
  -        }
  -
  -        public void setSelected( ImapMailbox mailbox, boolean readOnly )
  -        {
  -            this.state = ImapSessionState.SELECTED;
  -            this.selectedMailbox = mailbox;
  -            this.selectedIsReadOnly = readOnly;
  -        }
  -
  -        public ImapMailbox getSelected()
  -        {
  -            return this.selectedMailbox;
  -        }
  -
  -        public boolean selectedIsReadOnly()
  -        {
  -            return this.selectedIsReadOnly;
  -        }
  -
  -        public ImapSessionState getState()
  -        {
  -            return this.state;
  -        }
  -    }
   }
   
  
  
  
  1.2       +35 -11    jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapRequestLineReader.java
  
  Index: ImapRequestLineReader.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapRequestLineReader.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ImapRequestLineReader.java	25 Nov 2002 01:11:44 -0000	1.1
  +++ ImapRequestLineReader.java	26 Nov 2002 14:53:47 -0000	1.2
  @@ -11,6 +11,8 @@
   import java.io.BufferedReader;
   import java.io.IOException;
   import java.io.Reader;
  +import java.io.Writer;
  +import java.io.BufferedWriter;
   import java.util.StringTokenizer;
   
   /**
  @@ -24,13 +26,15 @@
   public class ImapRequestLineReader
   {
       private Reader reader;
  +    private Writer writer;
   
       private boolean nextSeen = false;
       private char nextChar; // unknown
   
  -    ImapRequestLineReader( Reader reader )
  +    ImapRequestLineReader( Reader reader, Writer writer )
       {
           this.reader = reader;
  +        this.writer = writer;
       }
   
       /**
  @@ -50,8 +54,6 @@
           }
   
           if ( next == '\r' || next == '\n' ) {
  -            // Move to the next line, and throw exception.
  -            eol();
               throw new ProtocolException( "Missing argument." );
           }
   
  @@ -83,15 +85,16 @@
   
               nextSeen = true;
               nextChar = ( char ) next;
  +//            System.out.println( "Read '" + nextChar + "'" );
           }
           return nextChar;
       }
   
       /**
  -     * Moves the request line reader to the next line, by consuming any
  -     * trailing whitespace, and CRLF.
  +     * Moves the request line reader to end of the line, checking that no non-space
  +     * character are found.
        * @throws ProtocolException If more non-space tokens are found in this line,
  -     *                           or the end-of-file is reached. All extra tokens are consumed regardless.
  +     *                           or the end-of-file is reached.
        */
       public void eol() throws ProtocolException
       {
  @@ -109,11 +112,6 @@
               next = nextChar();
           }
   
  -        // Need to consume until the end-of-line, regardless.
  -        while ( consume() != '\n' ) {
  -            // keep on consuming
  -        }
  -
           // Check if we found extra characters.
           if ( next != '\n' ) {
               throw new ProtocolException( "Expected end-of-line, found more characters.");
  @@ -151,5 +149,31 @@
           catch ( IOException e ) {
               throw new ProtocolException( "Error reading from stream." );
           }
  +    }
  +
  +    /**
  +     * Sends a server command continuation request '+' back to the client,
  +     * requesting more data to be sent.
  +     */
  +    public void commandContinuationRequest()
  +            throws ProtocolException
  +    {
  +        try {
  +            writer.write( "+\n" );
  +        }
  +        catch ( IOException e ) {
  +            throw new ProtocolException("Unexpected exception in sending command continuation request.");
  +        }
  +    }
  +
  +    public void consumeLine()
  +            throws ProtocolException
  +    {
  +        char next = nextChar();
  +        while ( next != '\n' ) {
  +            consume();
  +            next = nextChar();
  +        }
  +        consume();
       }
   }
  
  
  
  1.2       +1 -7      jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapSession.java
  
  Index: ImapSession.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapSession.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ImapSession.java	22 Nov 2002 02:09:50 -0000	1.1
  +++ ImapSession.java	26 Nov 2002 14:53:47 -0000	1.2
  @@ -51,12 +51,6 @@
       UsersRepository getUsers();
   
       /**
  -     * Provides a security logger for auditing logins.
  -     * @return The security logger.
  -     */
  -    Logger getSecurityLogger();
  -
  -    /**
        * @return The hostname of the connected client.
        */
       String getClientHostname();
  
  
  
  1.2       +3 -3      jakarta-james/proposals/imap2/java/org/apache/james/imapserver/JamesImapHost.java
  
  Index: JamesImapHost.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/JamesImapHost.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JamesImapHost.java	22 Nov 2002 02:09:50 -0000	1.1
  +++ JamesImapHost.java	26 Nov 2002 14:53:47 -0000	1.2
  @@ -197,8 +197,8 @@
                                        boolean subscribedOnly )
               throws MailboxException
       {
  -        System.out.println( "Listing for user: '" + user.getUserName() + "'" +
  -                            " pattern:'" + mailboxPattern + "'" );
  +//        System.out.println( "Listing for user: '" + user.getUserName() + "'" +
  +//                            " pattern:'" + mailboxPattern + "'" );
   
           ArrayList mailboxes = new ArrayList();
           String qualifiedPattern = getQualifiedMailboxName( user, mailboxPattern );
  
  
  
  1.1                  jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapRequestHandler.java
  
  Index: ImapRequestHandler.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.imapserver;
  
  import org.apache.james.imapserver.commands.ImapCommandFactory;
  import org.apache.james.imapserver.commands.CommandParser;
  import org.apache.james.imapserver.commands.ImapCommand;
  
  import java.io.Reader;
  import java.io.PrintWriter;
  
  /**
   *
   * @author  Darrell DeBoer <da...@apache.org>
   *
   * @version $Revision: 1.1 $
   */
  public final class ImapRequestHandler
  {
      private ImapCommandFactory imapCommands = new ImapCommandFactory();
      private CommandParser parser = new CommandParser();
      private static final String REQUEST_SYNTAX = "Protocol Error: Was expecting <tag SPACE command [arguments]>";
  
      /**
       * This method parses POP3 commands read off the wire in handleConnection.
       * Actual processing of the command (possibly including additional back and
       * forth communication with the client) is delegated to one of a number of
       * command specific handler methods.  The primary purpose of this method is
       * to parse the raw command string to determine exactly which handler should
       * be called.  It returns true if expecting additional commands, false otherwise.
       *
       * @return whether additional commands are expected.
       */
      public boolean handleRequest( Reader reader,
                                    PrintWriter writer,
                                    ImapSession session )
              throws ProtocolException
      {
          ImapRequestLineReader request = new ImapRequestLineReader( reader, writer );
          try {
              request.nextChar();
          }
          catch ( ProtocolException e ) {
              return false;
          }
  
          ImapResponse response = new ImapResponse( writer );
  
          doProcessRequest( request, response, session );
  
          // Consume the rest of the line, throwing away any extras. This allows us
          // to clean up after a protocol error.
          request.consumeLine();
  
          return true;
      }
  
      private void doProcessRequest( ImapRequestLineReader request,
                                     ImapResponse response,
                                     ImapSession session)
      {
          String tag = null;
          String commandName = null;
  
          try {
              tag = parser.tag( request );
          }
          catch ( ProtocolException e ) {
              response.badResponse( REQUEST_SYNTAX );
              return;
          }
  
  //        System.out.println( "Got <tag>: " + tag );
          response.setTag( tag );
          try {
              commandName = parser.atom( request );
          }
          catch ( ProtocolException e ) {
              response.commandError( REQUEST_SYNTAX );
              return;
          }
  
  //        System.out.println( "Got <command>: " + commandName );
          ImapCommand command = imapCommands.getCommand( commandName );
          if ( command == null )
          {
              response.commandError( "Invalid command.");
              return;
          }
  
          if ( !command.validForState( session.getState() ) ) {
              response.commandFailed( command, "Command not valid in this state" );
              return;
          }
  
          command.process( request, response, session );
      }
  
  
  }
  
  
  
  1.1                  jakarta-james/proposals/imap2/java/org/apache/james/imapserver/ImapSessionImpl.java
  
  Index: ImapSessionImpl.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.imapserver;
  
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.james.services.User;
  import org.apache.james.services.UsersRepository;
  import org.apache.james.imapserver.store.ImapMailbox;
  
  /**
   *
   * @author  Darrell DeBoer <da...@apache.org>
   *
   * @version $Revision: 1.1 $
   */
  public final class ImapSessionImpl implements ImapSession
  {
      private ImapSessionState state = ImapSessionState.NON_AUTHENTICATED;
      private User user = null;
      private ImapMailbox selectedMailbox = null;
      // TODO: Use a session-specific wrapper for user's view of mailbox
      // this wrapper would provide access control and track if the mailbox
      // is opened read-only.
      private boolean selectedIsReadOnly = false;
  
      private String clientHostName;
      private String clientAddress;
  
      // TODO these shouldn't be in here - they can be provided directly to command components.
      private ImapHandler handler;
      private ImapHost imapHost;
      private UsersRepository users;
  
      public ImapSessionImpl( ImapHost imapHost,
                              UsersRepository users,
                              ImapHandler handler,
                              String clientHostName,
                              String clientAddress )
      {
          this.imapHost = imapHost;
          this.users = users;
          this.handler = handler;
          this.clientHostName = clientHostName;
          this.clientAddress = clientAddress;
      }
  
      public ImapHost getHost()
      {
          return imapHost;
      }
  
      public void unsolicitedResponses( ImapResponse request )
      {
      }
  
      public void closeConnection()
      {
          handler.resetHandler();
      }
  
      public UsersRepository getUsers()
      {
          return users;
      }
  
      public String getClientHostname()
      {
          return clientHostName;
      }
  
      public String getClientIP()
      {
          return clientAddress;
      }
  
      public void setAuthenticated( User user )
      {
          this.state = ImapSessionState.AUTHENTICATED;
          this.user = user;
      }
  
      public User getUser()
      {
          return this.user;
      }
  
      public void deselect()
      {
          this.state = ImapSessionState.AUTHENTICATED;
      }
  
      public void setSelected( ImapMailbox mailbox, boolean readOnly )
      {
          this.state = ImapSessionState.SELECTED;
          this.selectedMailbox = mailbox;
          this.selectedIsReadOnly = readOnly;
      }
  
      public ImapMailbox getSelected()
      {
          return this.selectedMailbox;
      }
  
      public boolean selectedIsReadOnly()
      {
          return this.selectedIsReadOnly;
      }
  
      public ImapSessionState getState()
      {
          return this.state;
      }
  }
  
  
  
  1.3       +2 -6      jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/CapabilityCommand.java
  
  Index: CapabilityCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/CapabilityCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- CapabilityCommand.java	25 Nov 2002 01:11:44 -0000	1.2
  +++ CapabilityCommand.java	26 Nov 2002 14:53:48 -0000	1.3
  @@ -24,7 +24,7 @@
       public static final String NAME = "CAPABILITY";
       public static final String ARGS = null;
   
  -    public static final String CAPABILITY_RESPONSE = NAME + SP + VERSION;
  +    public static final String CAPABILITY_RESPONSE = NAME + SP + VERSION + SP + CAPABILITIES;
   
       /** @see CommandTemplate#doProcess */
       protected void doProcess( ImapRequestLineReader request,
  @@ -32,14 +32,10 @@
                                 ImapSession session )
               throws ProtocolException
       {
  -        System.out.println( "About to do parser.endLine()" );
           parser.endLine( request );
  -        System.out.println( "Completed parser.endLine()" );
           response.untaggedResponse( CAPABILITY_RESPONSE );
  -        System.out.println( "Sent untagged response." );
           session.unsolicitedResponses( response );
           response.commandComplete( this );
  -        System.out.println( "Sent capability response." );
       }
   
       /** @see ImapCommand#getName */
  
  
  
  1.2       +50 -4     jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/CommandParser.java
  
  Index: CommandParser.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/CommandParser.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CommandParser.java	25 Nov 2002 01:11:44 -0000	1.1
  +++ CommandParser.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -9,6 +9,7 @@
   
   import org.apache.james.imapserver.ProtocolException;
   import org.apache.james.imapserver.ImapRequestLineReader;
  +import org.apache.james.imapserver.ImapConstants;
   import org.apache.james.imapserver.store.MessageFlags;
   import org.apache.james.util.Assert;
   
  @@ -83,6 +84,27 @@
       }
   
       /**
  +     * Reads a "mailbox" argument from the request. Not implemented *exactly* as per spec,
  +     * since a quoted or literal "inbox" still yeilds "INBOX"
  +     * (ie still case-insensitive if quoted or literal). I think this makes sense.
  +     *
  +     * mailbox         ::= "INBOX" / astring
  +     *              ;; INBOX is case-insensitive.  All case variants of
  +     *              ;; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX
  +     *              ;; not as an astring.
  +     */
  +    public String mailbox( ImapRequestLineReader request ) throws ProtocolException
  +    {
  +        String mailbox = astring( request );
  +        if ( mailbox.equalsIgnoreCase( ImapConstants.INBOX_NAME ) ) {
  +            return ImapConstants.INBOX_NAME;
  +        }
  +        else {
  +            return mailbox;
  +        }
  +    }
  +
  +    /**
        * Reads a "date-time" argument from the request.
        */
       public Date dateTime( ImapRequestLineReader request ) throws ProtocolException
  @@ -171,15 +193,29 @@
   
           StringBuffer digits = new StringBuffer();
           char next = request.nextChar();
  -        while ( next != '}' )
  +        while ( next != '}' && next != '+' )
           {
               digits.append( next );
               request.consume();
               next = request.nextChar();
           }
  +
  +        // If the number is *not* suffixed with a '+', we *are* using a synchronized literal,
  +        // and we need to send command continuation request before reading data.
  +        boolean synchronizedLiteral = true;
  +        // '+' indicates a non-synchronized literal (no command continuation request)
  +        if ( next == '+' ) {
  +            synchronizedLiteral = false;
  +            consumeChar(request, '+' );
  +        }
  +
           // Consume the '}' and the newline
           consumeChar( request, '}' );
  -        endLine( request );
  +        consumeChar( request, '\n' );
  +
  +        if ( synchronizedLiteral ) {
  +            request.commandContinuationRequest();
  +        }
   
           int size = Integer.parseInt( digits.toString() );
           char[] buffer = new char[size];
  @@ -196,7 +232,9 @@
               throws ProtocolException
       {
           char consumed = request.consume();
  -        Assert.isTrue( Assert.ON && consumed == expected );
  +        if ( consumed != expected ) {
  +            throw new ProtocolException( "Expected:'" + expected + "' found:'" + consumed + "'" );
  +        }
       }
   
       /**
  @@ -311,6 +349,14 @@
            * @return <code>true</code> if chr is valid, <code>false</code> if not.
            */
           boolean isValid( char chr );
  +    }
  +
  +    protected class NoopCharValidator implements CharacterValidator
  +    {
  +        public boolean isValid( char chr )
  +        {
  +            return true;
  +        }
       }
   
       protected class ATOM_CHARValidator implements CharacterValidator
  
  
  
  1.2       +2 -2      jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/ImapCommandFactory.java
  
  Index: ImapCommandFactory.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/ImapCommandFactory.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ImapCommandFactory.java	22 Nov 2002 02:09:51 -0000	1.1
  +++ ImapCommandFactory.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -53,7 +53,7 @@
   //        _imapCommands.put( "UNSUBSCRIBE", UnsubscribeCommand.class );
           _imapCommands.put( ListCommand.NAME, ListCommand.class );
           _imapCommands.put( LsubCommand.NAME, LsubCommand.class );
  -//        _imapCommands.put( "STATUS", StatusCommand.class );
  +        _imapCommands.put( StatusCommand.NAME, StatusCommand.class );
   //        _imapCommands.put( "APPEND", AppendCommand.class );
   //        // RFC2342 NAMESPACE
   //        _imapCommands.put( "NAMESPACE", NamespaceCommand.class );
  
  
  
  1.3       +1 -8      jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/LoginCommand.java
  
  Index: LoginCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/LoginCommand.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- LoginCommand.java	25 Nov 2002 01:11:44 -0000	1.2
  +++ LoginCommand.java	26 Nov 2002 14:53:48 -0000	1.3
  @@ -40,16 +40,9 @@
               session.setAuthenticated( user );
               response.commandComplete( this );
   
  -            // Log the login.
  -            session.getSecurityLogger().info( "Login successful for " + user.getUserName() +
  -                                              " from  " + session.getClientHostname() +
  -                                              "(" + session.getClientIP() + ")" );
           }
           else {
               response.commandFailed( this, "Invalid login/password" );
  -            session.getSecurityLogger().error( "Login failed for " + userid +
  -                                               " from " + session.getClientHostname() +
  -                                               "(" + session.getClientIP() + ")" );
           }
       }
   
  
  
  
  1.2       +45 -2     jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/StatusCommand.java
  
  Index: StatusCommand.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/java/org/apache/james/imapserver/commands/StatusCommand.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- StatusCommand.java	25 Nov 2002 01:11:44 -0000	1.1
  +++ StatusCommand.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -84,6 +84,11 @@
               buffer.append( mailbox.getUnseenCount() );
               buffer.append( SP );
           }
  +        if ( buffer.charAt( buffer.length() - 1 ) == ' ' ) {
  +            buffer.setLength( buffer.length() - 1 );
  +        }
  +        buffer.append(')');
  +        response.commandResponse( this, buffer.toString());
   
           session.unsolicitedResponses( response );
           response.commandComplete( this );
  @@ -104,9 +109,47 @@
       private class StatusCommandParser extends CommandParser
       {
           StatusDataItems statusDataItems( ImapRequestLineReader request )
  +                throws ProtocolException
           {
  -            // TODO: implement.
  -            return new StatusDataItems();
  +            StatusDataItems items = new StatusDataItems();
  +
  +            request.nextWordChar();
  +            consumeChar( request, '(' );
  +            CharacterValidator validator = new NoopCharValidator();
  +            String nextWord = consumeWord( request, validator );
  +            while ( ! nextWord.endsWith(")" ) ) {
  +                addItem( nextWord, items );
  +                nextWord = consumeWord( request, validator );
  +            }
  +            // Got the closing ")", may be attached to a word.
  +            if ( nextWord.length() > 1 ) {
  +                addItem( nextWord.substring(0, nextWord.length() - 1 ), items );
  +            }
  +
  +            return items;
  +        }
  +
  +        private void addItem( String nextWord, StatusDataItems items )
  +                throws ProtocolException
  +        {
  +            if ( nextWord.equals( MESSAGES ) ) {
  +                items.messages = true;
  +            }
  +            else if ( nextWord.equals( RECENT ) ) {
  +                items.recent = true;
  +            }
  +            else if ( nextWord.equals( UIDNEXT ) ) {
  +                items.uidNext = true;
  +            }
  +            else if ( nextWord.equals( UIDVALIDITY ) ) {
  +                items.uidValidity = true;
  +            }
  +            else if ( nextWord.equals( UNSEEN ) ) {
  +                items.unseen = true;
  +            }
  +            else {
  +                throw new ProtocolException( "Unknown status item: '" + nextWord + "'" );
  +            }
           }
       }
   
  
  
  
  1.3       +1 -1      jakarta-james/proposals/imap2/test/org/apache/james/imapserver/Capability.test
  
  Index: Capability.test
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/Capability.test,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Capability.test	25 Nov 2002 01:11:45 -0000	1.2
  +++ Capability.test	26 Nov 2002 14:53:48 -0000	1.3
  @@ -1,5 +1,5 @@
   C: abcd CAPABILITY
  -S: \* CAPABILITY IMAP4rev1
  +S: \* CAPABILITY IMAP4rev1 LITERAL+
   S: abcd OK CAPABILITY completed
   
   C: abcd CAPABILITY extra stuff
  
  
  
  1.2       +64 -10    jakarta-james/proposals/imap2/test/org/apache/james/imapserver/CommandParserTest.java
  
  Index: CommandParserTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/CommandParserTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- CommandParserTest.java	25 Nov 2002 01:11:45 -0000	1.1
  +++ CommandParserTest.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -11,8 +11,9 @@
   
   import junit.framework.TestCase;
   
  -import java.io.StringReader;
   import java.io.BufferedReader;
  +import java.io.StringReader;
  +import java.io.StringWriter;
   
   /**
    * Tests for the {@link ImapRequestLineReader}.
  @@ -25,20 +26,49 @@
           extends TestCase
   {
       private CommandParser parser = new CommandParser();
  +    private StringWriter writer = new StringWriter();
   
       public CommandParserTest( String s )
       {
           super( s );
       }
   
  -    public void testTag() throws Exception
  +    /**
  +     * Tests handling of the "atom" argument type.
  +     * TODO: check special characters.
  +     * @throws Exception
  +     */
  +    public void testAtom() throws Exception
       {
  -        String testRequest = "a01 a.not.her not+ok";
  +        String testRequest = "a01 a.not.her one\ntwo ";
           ImapRequestLineReader request = getRequest( testRequest );
   
  -        assertEquals( "a01", parser.tag( request ) );
  -        assertEquals( "a.not.her", parser.tag( request ) );
  +        assertEquals( "a01", parser.atom( request ) );
  +        assertEquals( "a.not.her", parser.atom( request ) );
  +        assertEquals( "one", parser.atom( request ) );
  +        request.eol();
  +        request.consumeLine();
  +        assertEquals( "two", parser.atom( request ) );
  +
  +        // Must have \n or " " after atom.
  +        testRequest = "a01";
  +        request = getRequest( testRequest );
  +        try {
  +            String test = parser.atom( request );
  +            fail( "shouldn't get here" );
  +        }
  +        catch ( ProtocolException e ) {}
  +    }
   
  +    /**
  +     * Test handling of the "tag" argument type.
  +     */
  +    public void testTag() throws Exception
  +    {
  +        String testRequest = "this-is-ok this+is+not+ok";
  +        ImapRequestLineReader request = getRequest( testRequest );
  +
  +        assertEquals( "this-is-ok", parser.tag( request ));
           try {
               String test = parser.tag( request );
               fail( "Tags may not contain the '+' character." );
  @@ -68,20 +98,27 @@
        */
       public void testLiteral() throws Exception
       {
  -        String test = "{24}\nThese \tare 24\ncharacters";
  +        // Synchronized literal.
  +        String test = "{24+}\nA \tsynchronized \nliteral {26}\nAn \tunsynchronized\nliteral";
           ImapRequestLineReader request = getRequest(test );
   
  -        assertEquals( "These \tare 24\ncharacters", parser.astring( request ) );
  +        assertEquals( "A \tsynchronized \nliteral", parser.astring( request ) );
  +        // Make sure we didn't get a command continuation response
  +        assertEquals( "", writer.getBuffer().toString() );
  +
  +        assertEquals( "An \tunsynchronized\nliteral", parser.astring( request ) );
  +        // Make sure we got a command continuation response
  +        assertEquals( "+\n", writer.getBuffer().toString() );
  +
       }
   
       /**
        * Test handling of astring arguments. More detailed tests for atom,
        * quoted and literal should be in specific argument tests.
  -     * TODO: add literal
        */
       public void testAstring() throws Exception
       {
  -        String testRequest = "atom at.om \"quoted\" \"\" {6}\n\"here\"";
  +        String testRequest = "atom at.om \"quoted\" \"\" {6+}\n\"here\"";
           ImapRequestLineReader request = getRequest( testRequest );
   
           assertEquals( "atom", parser.astring( request ) );
  @@ -91,10 +128,27 @@
           assertEquals( "\"here\"", parser.astring( request ));
       }
   
  +    /**
  +     * Tests for reading "mailbox" arguments. This is simply an "astring", where the
  +     * special name "INBOX" is treated case insensitive.
  +     */
  +    public void testMailbox() throws Exception
  +    {
  +        String testRequest = "mailboxName \"quotedName\" {11+}\nliteralName iNbOx ";
  +        ImapRequestLineReader request = getRequest( testRequest );
  +
  +        assertEquals( "mailboxName", parser.mailbox( request ) );
  +        assertEquals( "quotedName", parser.mailbox( request ));
  +        assertEquals( "literalName", parser.mailbox( request ));
  +        assertEquals( "INBOX", parser.mailbox( request ));
  +    }
  +
       private ImapRequestLineReader getRequest( String testRequest )
       {
           BufferedReader reader = new BufferedReader( new StringReader( testRequest ) );
  -        ImapRequestLineReader request = new ImapRequestLineReader( reader );
  +        // Clear the writer.
  +        writer.getBuffer().setLength(0);
  +        ImapRequestLineReader request = new ImapRequestLineReader( reader, writer );
           return request;
       }
   }
  
  
  
  1.2       +8 -8      jakarta-james/proposals/imap2/test/org/apache/james/imapserver/IMAPTest.java
  
  Index: IMAPTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/IMAPTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- IMAPTest.java	22 Nov 2002 02:09:52 -0000	1.1
  +++ IMAPTest.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -7,16 +7,16 @@
    */
   package org.apache.james.imapserver;
   
  -import javax.mail.internet.InternetAddress;
   
   public interface IMAPTest
   {
  -    public int PORT = 143;
  -    public String HOST = "localhost";
  +    int PORT = 143;
  +    String HOST = "localhost";
   
  -    public String USER = "imapuser";
  -    public String PASSWORD = "password";
  -    public String FROM_ADDRESS = "sender@localhost";
  -    public String TO_ADDRESS = USER + "@" + HOST;
  -    
  +    String USER = "imapuser";
  +    String PASSWORD = "password";
  +    String FROM_ADDRESS = "sender@localhost";
  +    String TO_ADDRESS = USER + "@" + HOST;
  +
  +    int TIMEOUT = 30000;
   }
  
  
  
  1.2       +3 -6      jakarta-james/proposals/imap2/test/org/apache/james/imapserver/ImapHostTest.java
  
  Index: ImapHostTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/ImapHostTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ImapHostTest.java	22 Nov 2002 02:09:52 -0000	1.1
  +++ ImapHostTest.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -7,16 +7,13 @@
    */
   package org.apache.james.imapserver;
   
  -import org.apache.james.imapserver.store.ImapStore;
  -import org.apache.james.imapserver.store.InMemoryStore;
   import org.apache.james.imapserver.store.ImapMailbox;
  +import org.apache.james.imapserver.store.InMemoryStore;
   import org.apache.james.imapserver.store.MailboxException;
  -import org.apache.james.imapserver.ImapConstants;
   import org.apache.james.services.User;
   import org.apache.james.userrepository.DefaultUser;
  -import junit.framework.TestCase;
   
  -import java.util.Collection;
  +import junit.framework.TestCase;
   
   /**
    * A test for implementations of the {@link ImapHost} interface.
  
  
  
  1.2       +2 -2      jakarta-james/proposals/imap2/test/org/apache/james/imapserver/ImapStoreTest.java
  
  Index: ImapStoreTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/ImapStoreTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- ImapStoreTest.java	22 Nov 2002 02:09:52 -0000	1.1
  +++ ImapStoreTest.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -7,9 +7,9 @@
    */
   package org.apache.james.imapserver;
   
  +import org.apache.james.imapserver.store.ImapMailbox;
   import org.apache.james.imapserver.store.ImapStore;
   import org.apache.james.imapserver.store.InMemoryStore;
  -import org.apache.james.imapserver.store.ImapMailbox;
   import org.apache.james.imapserver.store.MailboxException;
   
   import junit.framework.TestCase;
  
  
  
  1.2       +2 -2      jakarta-james/proposals/imap2/test/org/apache/james/imapserver/InitialMail.java
  
  Index: InitialMail.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/InitialMail.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- InitialMail.java	22 Nov 2002 02:09:52 -0000	1.1
  +++ InitialMail.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -9,11 +9,11 @@
   
   import junit.framework.TestCase;
   
  -import javax.mail.internet.InternetAddress;
  -import javax.mail.internet.MimeMessage;
   import javax.mail.Message;
   import javax.mail.Session;
   import javax.mail.Transport;
  +import javax.mail.internet.InternetAddress;
  +import javax.mail.internet.MimeMessage;
   import java.util.Properties;
   
   public final class InitialMail extends TestCase
  
  
  
  1.2       +8 -18     jakarta-james/proposals/imap2/test/org/apache/james/imapserver/TestAuthenticated.java
  
  Index: TestAuthenticated.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/TestAuthenticated.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestAuthenticated.java	22 Nov 2002 02:09:52 -0000	1.1
  +++ TestAuthenticated.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -7,40 +7,30 @@
    */
   package org.apache.james.imapserver;
   
  -import junit.framework.TestCase;
  +import org.apache.james.test.SimpleFileProtocolTest;
  +
   import junit.framework.Test;
   import junit.framework.TestSuite;
   
  -import java.net.Socket;
  -import java.io.*;
  -import java.util.List;
  -import java.util.Iterator;
  -import java.util.ArrayList;
  -import java.util.Date;
  -
  -import org.apache.james.test.SimpleFileProtocolTest;
  -import org.apache.james.remotemanager.UserManagementTest;
  -
   public class TestAuthenticated
           extends SimpleFileProtocolTest implements IMAPTest
   {
       public TestAuthenticated( String name )
       {
           super( name );
  -        _port = 143;
       }
   
       public void setUp() throws Exception
       {
           super.setUp();
  -        addTestFile( "Welcome.test", _preElements );
  +        addTestFile( "Welcome.test", preElements );
           addLogin( USER, PASSWORD );
       }
   
       protected void addLogin( String username, String password )
       {
  -        _testElements.add( new ClientRequest( "a001 LOGIN " + username + " " + password ) );
  -        _testElements.add( new ServerResponse( "a001 OK LOGIN completed" ));
  +        testElements.CL( "a001 LOGIN " + username + " " + password );
  +        testElements.SL( "a001 OK LOGIN completed" );
       }
   
       public static Test suite() throws Exception
  @@ -57,10 +47,10 @@
           suite.addTest( new TestAuthenticated( "SelectEmpty" ) );
           suite.addTest( new TestAuthenticated( "ListNamespace" ) );
           suite.addTest( new TestAuthenticated( "ListMailboxes" ) );
  +        suite.addTest( new TestAuthenticated( "Status" ) );
  +//        suite.addTest( new TestAuthenticated( "StringArgs" ) );
   
  -//        suite.addTest( new TestAuthenticated( "Subscribe" ) );
  -//        suite.addTest( new TestAuthenticated( "Subscribe2" ) );
  -
  +        // Run delete last, because many of the tests depend on created mailboxes.
           suite.addTest( new TestAuthenticated( "Delete" ) );
   
           return suite;
  
  
  
  1.2       +4 -15     jakarta-james/proposals/imap2/test/org/apache/james/imapserver/TestNonAuthenticated.java
  
  Index: TestNonAuthenticated.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/TestNonAuthenticated.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestNonAuthenticated.java	22 Nov 2002 02:09:52 -0000	1.1
  +++ TestNonAuthenticated.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -7,20 +7,10 @@
    */
   package org.apache.james.imapserver;
   
  -import junit.framework.TestCase;
  -import junit.framework.TestResult;
  -import junit.framework.TestSuite;
  -import junit.framework.Test;
  -
  -import java.net.Socket;
  -import java.io.*;
  -import java.util.List;
  -import java.util.Iterator;
  -import java.util.ArrayList;
  -import java.util.Date;
  -
   import org.apache.james.test.SimpleFileProtocolTest;
  -import org.apache.james.remotemanager.UserManagementTest;
  +
  +import junit.framework.Test;
  +import junit.framework.TestSuite;
   
   public class TestNonAuthenticated
           extends SimpleFileProtocolTest
  @@ -28,13 +18,12 @@
       public TestNonAuthenticated( String name )
       {
           super( name );
  -        _port = 143;
       }
   
       public void setUp() throws Exception
       {
           super.setUp();
  -        addTestFile( "Welcome.test", _preElements );
  +        addTestFile( "Welcome.test", preElements );
       }
   
       public static Test suite() throws Exception
  
  
  
  1.2       +1 -1      jakarta-james/proposals/imap2/test/org/apache/james/imapserver/TestSelected.java
  
  Index: TestSelected.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/imapserver/TestSelected.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestSelected.java	22 Nov 2002 02:09:52 -0000	1.1
  +++ TestSelected.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -21,7 +21,7 @@
       public void setUp() throws Exception
       {
           super.setUp();
  -        addTestFile( "SelectInbox.test" );
  +        addTestFile( "SelectInbox.test", preElements );
       }
   
       public static Test suite() throws Exception
  
  
  
  1.1                  jakarta-james/proposals/imap2/test/org/apache/james/imapserver/Status.test
  
  Index: Status.test
  ===================================================================
  # Tests for the STATUS command
  C: a001 STATUS test (MESSAGES)
  S: \* STATUS test \(MESSAGES \d+\)
  S: a001 OK STATUS completed
  
  C: a001 STATUS test (  MESSAGES  )
  S: \* STATUS test \(MESSAGES \d+\)
  S: a001 OK STATUS completed
  
  C: a001 STATUS test (MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN)
  S: \* STATUS test \(MESSAGES \d+ RECENT \d+ UIDNEXT \d+ UIDVALIDITY \d+ UNSEEN \d+\)
  S: a001 OK STATUS completed
  
  C: a001 STATUS test (UNSEEN RECENT )
  S: \* STATUS test \(RECENT \d+ UNSEEN \d+\)
  S: a001 OK STATUS completed
  
  
  
  
  
  1.1                  jakarta-james/proposals/imap2/test/org/apache/james/imapserver/StringArgs.test
  
  Index: StringArgs.test
  ===================================================================
  # The following tests check the parsing of string arguments of various formats.
  # The STATUS command is used for testing all types of string arguments.
  
  # The <mailbox> argument of the STATUS command is of type "mailbox", which
  # may be either (case-insensitive) "INBOX" or an "astring". "astring", in turn,
  # may be an "atom", a "quoted" string, or a "literal" ( format "{xxx[+]}\nXXXX" )
  
  # INBOX special case
  C: a001 STATUS INBOX (MESSAGES)
  S: \* STATUS INBOX \(MESSAGES \d+\)
  S: a001 OK STATUS completed
  
  # Case-insensitive inbox
  C: a001 STATUS InBoX (MESSAGES)
  S: \* STATUS INBOX \(MESSAGES \d+\)
  S: a001 OK STATUS completed
  
  # atom
  C: a001 STATUS test (MESSAGES)
  S: \* STATUS test \(MESSAGES \d+\)
  S: a001 OK STATUS completed
  
  # quoted
  C: a001 STATUS "test" (MESSAGES)
  S: \* STATUS test \(MESSAGES \d+\)
  S: a001 OK STATUS completed
  
  # non-synchronized literal
  C: a001 STATUS {4}
  S: +
  C: test (MESSAGES)
  S: \* STATUS test \(MESSAGES \d+\)
  S: a001 OK STATUS completed
  
  # synchronized literal
  C: a001 STATUS {4+}
  C: test (MESSAGES)
  S: \* STATUS test \(MESSAGES \d+\)
  S: a001 OK STATUS completed
  
  
  
  
  
  1.2       +5 -13     jakarta-james/proposals/imap2/test/org/apache/james/remotemanager/TestRemoteManager.java
  
  Index: TestRemoteManager.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/remotemanager/TestRemoteManager.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestRemoteManager.java	22 Nov 2002 02:09:54 -0000	1.1
  +++ TestRemoteManager.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -1,18 +1,10 @@
   package org.apache.james.remotemanager;
   
  -import junit.framework.TestCase;
  +import org.apache.james.test.SimpleFileProtocolTest;
  +
   import junit.framework.Test;
   import junit.framework.TestSuite;
   
  -import java.net.Socket;
  -import java.io.*;
  -import java.util.List;
  -import java.util.Iterator;
  -import java.util.ArrayList;
  -import java.util.Date;
  -
  -import org.apache.james.test.SimpleFileProtocolTest;
  -
   public class TestRemoteManager
           extends SimpleFileProtocolTest
   {
  @@ -20,9 +12,9 @@
       public TestRemoteManager( String testFileName ) throws Exception
       {
           super( testFileName );
  -        _port = 4555;
  -        addTestFile( "RemoteManagerLogin.test", _preElements );
  -        addTestFile( "RemoteManagerLogout.test", _postElements );
  +        port = 4555;
  +        addTestFile( "RemoteManagerLogin.test", preElements );
  +        addTestFile( "RemoteManagerLogout.test", postElements );
       }
   
       public static Test suite() throws Exception
  
  
  
  1.2       +11 -10    jakarta-james/proposals/imap2/test/org/apache/james/remotemanager/UserManagementTest.java
  
  Index: UserManagementTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/remotemanager/UserManagementTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- UserManagementTest.java	22 Nov 2002 02:09:54 -0000	1.1
  +++ UserManagementTest.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -1,12 +1,14 @@
   package org.apache.james.remotemanager;
   
   import org.apache.james.test.AbstractProtocolTest;
  +import org.apache.james.test.FileProtocolSessionBuilder;
   
   public class UserManagementTest
           extends AbstractProtocolTest
   {
       private String _userName;
       private String _password;
  +    private FileProtocolSessionBuilder builder = new FileProtocolSessionBuilder();
   
       public UserManagementTest( String action, String userName )
       {
  @@ -16,7 +18,6 @@
       public UserManagementTest( String action, String userName, String password )
       {
           super( action );
  -        _port = 4555;
           _userName = userName;
           _password = password;
       }
  @@ -24,8 +25,8 @@
       public void setUp() throws Exception
       {
           super.setUp();
  -        addTestFile( "RemoteManagerLogin.test", _preElements );
  -        addTestFile( "RemoteManagerLogout.test", _postElements );
  +        builder.addTestFile( "RemoteManagerLogin.test", preElements );
  +        builder.addTestFile( "RemoteManagerLogout.test", postElements );
       }
   
       public void addUser() throws Exception
  @@ -36,12 +37,12 @@
       protected void addUser( String userName, String password )
               throws Exception
       {
  -        CL( "adduser " + userName + " " + password );
  -        SL( "User " + userName + " added" );
  -        executeTests();
  +        testElements.CL( "adduser " + userName + " " + password );
  +        testElements.SL( "User " + userName + " added", "Generated test." );
  +        runSessions();
       }
   
  -    /*protected void addExistingUser( String userName, String password )  
  +    /*protected void addExistingUser( String userName, String password )
           throws Exception{
           CL( "adduser " + userName + " " + password );
           SL( "user " + userName + " already exist" );
  @@ -55,8 +56,8 @@
   
       protected void deleteUser( String userName ) throws Exception
       {
  -        CL( "deluser " + userName );
  -        SL( "User " + userName + " deleted" );
  -        executeTests();
  +        testElements.CL( "deluser " + userName );
  +        testElements.SL( "User " + userName + " deleted" );
  +        runSessions();
       }
   }
  
  
  
  1.1                  jakarta-james/proposals/imap2/test/org/apache/james/remotemanager/InitialImapUsersTest.java
  
  Index: InitialImapUsersTest.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.remotemanager;
  
  import junit.framework.Test;
  import junit.framework.TestSuite;
  
  public final class InitialImapUsersTest
          extends TestRemoteManager
  {
      public InitialImapUsersTest( String s ) throws Exception
      {
          super( s );
      }
  
      public static Test suite() throws Exception
      {
          TestSuite suite = new TestSuite();
          suite.addTest( new InitialImapUsersTest( "InitialUsers" ) );
          return suite;
      }
  }
  
  
  
  1.1                  jakarta-james/proposals/imap2/test/org/apache/james/remotemanager/InitialUsers.test
  
  Index: InitialUsers.test
  ===================================================================
  C: adduser imapuser password
  S: User imapuser added
  
  
  1.2       +2 -12     jakarta-james/proposals/imap2/test/org/apache/james/smtpserver/TestSMTP.java
  
  Index: TestSMTP.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/smtpserver/TestSMTP.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TestSMTP.java	22 Nov 2002 02:09:54 -0000	1.1
  +++ TestSMTP.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -1,18 +1,10 @@
   package org.apache.james.smtpserver;
   
  -import junit.framework.TestCase;
  +import org.apache.james.test.SimpleFileProtocolTest;
  +
   import junit.framework.Test;
   import junit.framework.TestSuite;
   
  -import java.net.Socket;
  -import java.io.*;
  -import java.util.List;
  -import java.util.Iterator;
  -import java.util.ArrayList;
  -import java.util.Date;
  -
  -import org.apache.james.test.SimpleFileProtocolTest;
  -
   
   public class TestSMTP
           extends SimpleFileProtocolTest
  @@ -20,8 +12,6 @@
       public TestSMTP( String name )
       {
           super( name );
  -        _port = 25;
  -        _timeout = 0;
       }
   
       public static Test suite() throws Exception
  
  
  
  1.2       +127 -246  jakarta-james/proposals/imap2/test/org/apache/james/test/AbstractProtocolTest.java
  
  Index: AbstractProtocolTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/test/AbstractProtocolTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- AbstractProtocolTest.java	22 Nov 2002 02:09:54 -0000	1.1
  +++ AbstractProtocolTest.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -1,12 +1,29 @@
   package org.apache.james.test;
   
  -import org.apache.oro.text.perl.Perl5Util;
  +import org.apache.james.imapserver.IMAPTest;
  +import org.apache.james.imapserver.ImapHandler;
  +import org.apache.james.imapserver.ImapHost;
  +import org.apache.james.imapserver.ImapRequestHandler;
  +import org.apache.james.imapserver.ImapSession;
  +import org.apache.james.imapserver.ImapSessionImpl;
  +import org.apache.james.imapserver.JamesImapHost;
  +import org.apache.james.imapserver.store.MailboxException;
  +import org.apache.james.services.User;
  +import org.apache.james.services.UsersRepository;
  +import org.apache.james.userrepository.AbstractUsersRepository;
  +import org.apache.james.userrepository.DefaultUser;
   
   import junit.framework.TestCase;
   
  -import java.io.*;
  -import java.util.*;
  +import java.io.BufferedReader;
  +import java.io.InputStreamReader;
  +import java.io.PipedReader;
  +import java.io.PipedWriter;
  +import java.io.PrintWriter;
   import java.net.Socket;
  +import java.util.HashMap;
  +import java.util.Iterator;
  +import java.util.Map;
   
   /**
    * Abstract Protocol Test is the root of all of the James Imap Server test
  @@ -19,26 +36,19 @@
    * @author Unattributed Original Authors
    * @author Andrew C. Oliver
    */
  -public abstract class AbstractProtocolTest extends TestCase
  +public abstract class AbstractProtocolTest
  +        extends TestCase implements IMAPTest
   {
  -    private Socket _socket;
  -    private PrintWriter _out;
  -    private BufferedReader _in;
  -    protected String _host = "127.0.0.1";
  -
  -    protected int _port;
  -    protected int _timeout = 0;
  -
  -    protected List _preElements = new ArrayList();
  -    protected List _testElements = new ArrayList();
  -    protected List _postElements = new ArrayList();
  -
  -    private static final Perl5Util perl = new Perl5Util();
  -    private static final String CLIENT_TAG = "C: ";
  -    private static final String SERVER_TAG = "S: ";
  -    private static final String OPEN_UNORDERED_BLOCK_TAG = "SUB {";
  -    private static final String CLOSE_UNORDERED_BLOCK_TAG = "}";
  -    private static final String COMMENT_TAG = "#";
  +    protected ProtocolSession preElements = new ProtocolSession();
  +    protected ProtocolSession testElements;
  +    protected ProtocolSession postElements = new ProtocolSession();
  +
  +    protected String host = HOST;
  +    protected int port = PORT;
  +    protected int timeout = TIMEOUT;
  +
  +    private static UsersRepository users;
  +    private static ImapHost imapHost;
   
       public AbstractProtocolTest( String s )
       {
  @@ -49,270 +59,141 @@
       public void setUp() throws Exception
       {
           super.setUp();
  -        _testElements.clear();
  +        testElements = new ProtocolSession();
   
  -        _socket = new Socket( _host, _port );
  -        _socket.setSoTimeout( _timeout );
  -        _out = new PrintWriter( _socket.getOutputStream(), true );
  -        _in = new BufferedReader( new InputStreamReader( _socket.getInputStream() ) );
  -    }
  -
  -    // comment in TestCase
  -    protected void tearDown() throws Exception
  -    {
  -        _out.close();
  -        _in.close();
  -        _socket.close();
  -        super.tearDown();
  -    }
  -
  -    // comment in TestCase
  -    protected void executeTests() throws Exception
  -    {
  -        executeTest( _preElements );
  -        executeTest( _testElements );
  -        executeTest( _postElements );
       }
   
       /**
  -     * executes the test case as specified in the file.  Commands in
  -     * CL: elements are sent to the server, and the SL: lines are verified
  -     * against those returning from the server.  The order is important
  -     * unless in a "SUB:" block in which case the order is not important and
  -     * the test will pass if any line in the SUB: block matches.
  +     * Uses a system property to determine whether to run tests locally, or against
  +     * a remote server.
        */
  -    protected void executeTest( List protocolLines ) throws Exception
  +    protected void runSessions() throws Exception
       {
  -        for ( Iterator iter = protocolLines.iterator(); iter.hasNext(); ) {
  -            Object obj = iter.next();
  -            if ( obj instanceof ProtocolElement ) {
  -                ProtocolElement test = ( ProtocolElement ) obj;
  -                test.testProtocol( _out, _in );
  -            }
  +        String runLocal = System.getProperty( "runTestsLocal", "true" );
  +        boolean local = Boolean.valueOf( runLocal ).booleanValue();
  +        if ( local ) {
  +            runLocalProtocolSessions();
  +        }
  +        else {
  +            runSocketProtocolSessions();
           }
       }
   
       /**
  -     * adds a new Client request line to the test elements
  +     * Runs the pre,test and post protocol sessions against a running instance of James,
  +     * by communicating via a socket connection. After a request is sent, the server response
  +     * is parsed to determine if the actual response matches that expected.
        */
  -    protected void CL( String clientLine )
  +    private void runSocketProtocolSessions()
  +            throws Exception
       {
  -        _testElements.add( new ClientRequest( clientLine ) );
  -    }
  +        Socket socket = new Socket( host, port );
  +        socket.setSoTimeout( timeout );
   
  -    /**
  -     * adds a new Server Response line to the test elements
  -     */
  -    protected void SL( String serverLine )
  -    {
  -        _testElements.add( new ServerResponse( serverLine ) );
  -    }
  +        PrintWriter out = new PrintWriter( socket.getOutputStream(), true );
  +        BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream() ) );
  +        try {
  +             preElements.runSession( in, out );
  +             testElements.runSession( in, out );
  +             postElements.runSession( in, out );
  +         }
  +         catch ( InvalidServerResponseException e ) {
  +             fail( e.getMessage() );
  +         }
  +
  +        out.close();
  +        in.close();
  +        socket.close();
  +     }
   
       /**
  -     * This Line is sent to the server (everything after "CL: ") in expectation
  -     * that the server will respond.
  +     * Runs the pre,test and post protocol sessions against a local copy of the ImapServer.
  +     * This does not require that James be running, and is useful for rapid development and
  +     * debugging.
  +     *
  +     * Instead of sending requests to a socket, requests are written to a PipedWriter,
  +     * which then provides a Reader which can be given to the ImapRequestHandler.
  +     * Likewise, server responses are writter to a PipedWriter, and the associate reader
  +     * is parsed to ensure that the responses match those expected.
        */
  -    protected class ClientRequest implements ProtocolElement
  +    private void runLocalProtocolSessions() throws Exception
       {
  -        private String _msg;
  +        // Read the client requests into a piped reader.
  +        PipedReader clientPipeReader = new PipedReader();
  +        PipedWriter clientPipeWriter = new PipedWriter( clientPipeReader );
  +        PrintWriter clientOut = new PrintWriter( clientPipeWriter );
  +        preElements.writeClient( clientOut );
  +        testElements.writeClient( clientOut );
  +        postElements.writeClient( clientOut );
   
  -        public ClientRequest( String msg )
  -        {
  -            _msg = msg;
  -        }
  +        clientPipeWriter.close();
   
  -        /**
  -         * Sends the request to the server
  -         */
  -        public void testProtocol( PrintWriter out, BufferedReader in ) throws Exception
  -        {
  -            out.println( _msg );
  -        }
  +        BufferedReader clientIn = new BufferedReader( clientPipeReader );
   
  -        /**
  -         * This should NOT be called, CL is not blockable!  Runtime exception
  -         * will be thrown.  Implemented because of "ProtocolElement"
  -         */
  -        public void testProtocolBlock( PrintWriter out, BufferedReader in, List list )
  -                throws Exception
  -        {
  -            //out.println( _msg );
  -            throw new RuntimeException( "Syntax error in test case, CL is not " +
  -                                        "able to be used in a SUB: block" );
  -        }
  -    }
  +        PipedReader serverPipeReader = new PipedReader();
  +        PipedWriter serverPipeWriter = new PipedWriter( serverPipeReader );
  +        PrintWriter serverOut = new PrintWriter( serverPipeWriter );
   
  -    protected class ServerResponse implements ProtocolElement
  -    {
  -        private String expectedLine;
  -        protected String location;
  +        serverOut.println( "* OK IMAP4rev1 Server XXX ready" );
   
  -        public ServerResponse( String expectedPattern, String location )
  -        {
  -            this.expectedLine = expectedPattern;
  -            this.location = location;
  -        }
  +        ImapSession session = getImapSession();
  +        ImapRequestHandler requestHandler = new ImapRequestHandler();
  +        while( requestHandler.handleRequest( clientIn, serverOut, session ) ) {};
   
  -        public ServerResponse( String expectedPattern )
  -        {
  -            this( expectedPattern, "" );
  +        BufferedReader serverIn = new BufferedReader( serverPipeReader );
  +        try {
  +            preElements.testResponse(  serverIn );
  +            testElements.testResponse(  serverIn );
  +            postElements.testResponse(  serverIn );
           }
  -
  -        public void testProtocol( PrintWriter out, BufferedReader in ) throws Exception
  -        {
  -            String testLine = readLine( in );
  -            if ( ! match( expectedLine, testLine ) ) {
  -                String errMsg = "\nLocation: " + location +
  -                        "\nExcpected: " + expectedLine +
  -                        "\nActual   : " + testLine;
  -                fail( errMsg );
  -            }
  +        catch ( InvalidServerResponseException e ) {
  +            fail( e.getMessage() );
           }
  +    }
   
  -        protected boolean match( String expected, String actual )
  -        {
  -            String pattern = "m/" + expected + "/";
  -            return perl.match( pattern, actual );
  -        }
  +    // TODO setup the session properly.
  +    private ImapSession getImapSession() throws MailboxException
  +    {
  +        setUpEnvironment();
  +        ImapSession session = new ImapSessionImpl( imapHost, users, new ImapHandler(), null, null );
  +        return session;
  +    }
   
  -        /**
  -         * Grabs a line from the server and throws an error message if it
  -         * doesn't work out
  -         * @param in BufferedReader for getting the server response
  -         * @return String of the line from the server
  -         */
  -        protected String readLine( BufferedReader in ) throws Exception
  -        {
  -            try {
  -                return in.readLine();
  -            }
  -            catch ( InterruptedIOException e ) {
  -                String errMsg = "\nLocation: " + location +
  -                        "\nExpected: " + expectedLine +
  -                        "\nReason: Server Timeout.";
  -                fail( errMsg );
  -                return "";
  -            }
  +    private void setUpEnvironment() throws MailboxException
  +    {
  +        if ( users == null || imapHost == null ) {
  +            users = new DummyUsersRepository();
  +            DefaultUser user = new DefaultUser( USER, "SHA" );
  +            user.setPassword( PASSWORD );
  +            users.addUser( user );
  +
  +            imapHost = new JamesImapHost();
  +            imapHost.createPrivateMailAccount( user );
           }
       }
   
  -    private class UnorderedBlockResponse extends ServerResponse
  +    private class DummyUsersRepository extends AbstractUsersRepository
       {
  -        private List expectedLines = new ArrayList();
  +        private Map users = new HashMap();
   
  -        public UnorderedBlockResponse( List expectedLines, String location )
  +        protected Iterator listAllUsers()
           {
  -            super( "<Unordered Block>", location );
  -            this.expectedLines = expectedLines;
  +            return users.values().iterator();
           }
   
  -        public void testProtocol( PrintWriter out, BufferedReader in ) throws Exception
  +        protected void doAddUser( User user )
           {
  -            List testLines = new ArrayList( expectedLines );
  -            while ( testLines.size() > 0 )
  -            {
  -                String actualLine = readLine( in );
  -                boolean foundMatch = false;
  -
  -                for ( int i = 0; i < testLines.size(); i++ )
  -                {
  -                    String expected = (String)testLines.get( i );
  -                    if ( match( expected, actualLine ))
  -                    {
  -                        foundMatch = true;
  -                        testLines.remove( expected );
  -                        break;
  -                    }
  -                }
  -
  -                if (! foundMatch )
  -                {
  -                    StringBuffer errMsg = new StringBuffer()
  -                        .append( "\nLocation: " )
  -                        .append( location )
  -                        .append( "\nExpected one of: " );
  -                    Iterator iter = expectedLines.iterator();
  -                    while ( iter.hasNext() ) {
  -                        errMsg.append( "\n    " );
  -                        errMsg.append( iter.next() );
  -                    }
  -                    errMsg.append("\nActual: " )
  -                          .append( actualLine );
  -
  -                    fail( errMsg.toString() );
  -                }
  -            }
  +            users.put( user.getUserName(), user );
           }
  -    }
  -
   
  -    protected interface ProtocolElement
  -    {
  -        void testProtocol( PrintWriter out, BufferedReader in ) throws Exception;
  -    }
  -
  -    protected void addTestFile( String fileName ) throws Exception
  -    {
  -        addTestFile( fileName, _testElements );
  -    }
  -
  -    protected void addTestFile( String fileName, List protocolLines ) throws Exception
  -    {
  -        // Need to find local resource.
  -        InputStream is = this.getClass().getResourceAsStream( fileName );
  -        if ( is == null ) {
  -            throw new Exception( "Test Resource '" + fileName + "' not found." );
  +        protected void doRemoveUser( User user )
  +        {
  +            users.remove( user.getUserName());
           }
   
  -        addProtocolLinesFromStream( is, protocolLines, fileName );
  -    }
  -
  -    private void addProtocolLinesFromStream( InputStream is, List protocolElements, String fileName )
  -            throws Exception
  -    {
  -        BufferedReader reader = new BufferedReader( new InputStreamReader( is ) );
  -        String next;
  -        int lineNumber = 1;
  -        while ( ( next = reader.readLine() ) != null ) {
  -            String location = fileName + ":" + lineNumber;
  -            if ( next.startsWith( CLIENT_TAG ) ) {
  -                String clientMsg = next.substring( 3 );
  -                protocolElements.add( new ClientRequest( clientMsg ) );
  -            }
  -            else if ( next.startsWith( SERVER_TAG ) ) {
  -                String serverMsg = next.substring( 3 );
  -                protocolElements.add( new ServerResponse( serverMsg, location ) );
  -            }
  -            else if ( next.startsWith( OPEN_UNORDERED_BLOCK_TAG ) ) {
  -                List unorderedLines = new ArrayList( 5 );
  -                next = reader.readLine();
  -
  -                while ( !next.startsWith( CLOSE_UNORDERED_BLOCK_TAG ) ) {
  -                    if (! next.startsWith( SERVER_TAG ) ) {
  -                        throw new Exception( "Only 'S: ' lines are permitted inside a 'SUB {' block.");
  -                    }
  -                    String serverMsg = next.substring( 3 );
  -                    unorderedLines.add( serverMsg );
  -                    next = reader.readLine();
  -                    lineNumber++;
  -                }
  -
  -                UnorderedBlockResponse blockResponse =
  -                        new UnorderedBlockResponse( unorderedLines, location );
  -                protocolElements.add( blockResponse );
  -            }
  -            else if ( next.startsWith( COMMENT_TAG )
  -                    || next.trim().length() == 0 ) {
  -                // ignore these lines.
  -            }
  -            else {
  -                String prefix = next;
  -                if ( next.length() > 3 ) {
  -                    prefix = next.substring( 0, 3 );
  -                }
  -                throw new Exception( "Invalid line prefix: " + prefix );
  -            }
  -            lineNumber++;
  +        protected void doUpdateUser( User user )
  +        {
  +            users.put( user.getUserName(), user );
           }
       }
   }
  
  
  
  1.2       +6 -7      jakarta-james/proposals/imap2/test/org/apache/james/test/JamesTask.java
  
  Index: JamesTask.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/test/JamesTask.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- JamesTask.java	22 Nov 2002 02:09:54 -0000	1.1
  +++ JamesTask.java	26 Nov 2002 14:53:48 -0000	1.2
  @@ -7,16 +7,15 @@
    */
   package org.apache.james.test;
   
  -import org.apache.tools.ant.BuildException;
  +import org.apache.avalon.framework.CascadingRuntimeException;
  +import org.apache.avalon.framework.parameters.Parameterizable;
  +import org.apache.avalon.framework.parameters.Parameters;
  +import org.apache.avalon.phoenix.components.embeddor.SingleAppEmbeddor;
   import org.apache.tools.ant.AntClassLoader;
  +import org.apache.tools.ant.BuildException;
  +import org.apache.tools.ant.types.CommandlineJava;
   import org.apache.tools.ant.types.Path;
   import org.apache.tools.ant.types.Reference;
  -import org.apache.tools.ant.types.CommandlineJava;
  -import org.apache.avalon.framework.parameters.Parameters;
  -import org.apache.avalon.framework.parameters.Parameterizable;
  -import org.apache.avalon.framework.ExceptionUtil;
  -import org.apache.avalon.framework.CascadingRuntimeException;
  -import org.apache.avalon.phoenix.components.embeddor.SingleAppEmbeddor;
   
   /**
    * An attempt at a task which can launch James from Ant, and shut it down again.
  
  
  
  1.2       +23 -8     jakarta-james/proposals/imap2/test/org/apache/james/test/SimpleFileProtocolTest.java
  
  Index: SimpleFileProtocolTest.java
  ===================================================================
  RCS file: /home/cvs/jakarta-james/proposals/imap2/test/org/apache/james/test/SimpleFileProtocolTest.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- SimpleFileProtocolTest.java	22 Nov 2002 02:09:54 -0000	1.1
  +++ SimpleFileProtocolTest.java	26 Nov 2002 14:53:49 -0000	1.2
  @@ -1,24 +1,39 @@
   package org.apache.james.test;
   
  +import java.io.InputStream;
  +
  +/**
  + * A Protocol test which reads the test protocol session from a file. The
  + * file read is taken as "<test-name>.test", where <test-name> is the value
  + * passed into the constructor.
  + */
   public class SimpleFileProtocolTest
           extends AbstractProtocolTest
   {
  +    private FileProtocolSessionBuilder builder =
  +            new FileProtocolSessionBuilder();
  +
       public SimpleFileProtocolTest( String fileName )
       {
           super( fileName );
       }
   
  -    public SimpleFileProtocolTest( String fileName, String host, int port )
  +    protected void runTest() throws Throwable
       {
  -        super( fileName );
  -        _host = host;
  -        _port = port;
  +        String fileName = getName() + ".test";
  +        addTestFile( fileName, testElements );
  +
  +        runSessions();
       }
   
  -    protected void runTest() throws Throwable
  +    protected void addTestFile( String fileName, ProtocolSession session) throws Exception
       {
  -        String testFileName = getName() + ".test";
  -        addTestFile( testFileName );
  -        executeTests();
  +        // Need to find local resource.
  +        InputStream is = this.getClass().getResourceAsStream( fileName );
  +        if ( is == null ) {
  +            throw new Exception( "Test Resource '" + fileName + "' not found." );
  +        }
  +
  +        builder.addProtocolLinesFromStream( is, session, fileName );
       }
   }
  
  
  
  1.1                  jakarta-james/proposals/imap2/test/org/apache/james/test/FileProtocolSessionBuilder.java
  
  Index: FileProtocolSessionBuilder.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.test;
  
  import java.io.BufferedReader;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.util.ArrayList;
  import java.util.List;
  
  /**
   *
   * @author  Darrell DeBoer <da...@apache.org>
   *
   * @version $Revision: 1.1 $
   */
  public class FileProtocolSessionBuilder
  {
      private static final String CLIENT_TAG = "C: ";
      private static final String SERVER_TAG = "S: ";
      private static final String OPEN_UNORDERED_BLOCK_TAG = "SUB {";
      private static final String CLOSE_UNORDERED_BLOCK_TAG = "}";
      private static final String COMMENT_TAG = "#";
  
      public ProtocolSession buildProtocolSession( String fileName )
              throws Exception
      {
          ProtocolSession session = new ProtocolSession();
          addTestFile( fileName, session );
          return session;
      }
  
      public void addTestFile( String fileName, ProtocolSession session )
              throws Exception
      {
          // Need to find local resource.
          InputStream is = this.getClass().getResourceAsStream( fileName );
          if ( is == null ) {
              throw new Exception( "Test Resource '" + fileName + "' not found." );
          }
  
          addProtocolLinesFromStream( is, session, fileName );
      }
  
      public void addProtocolLinesFromStream( InputStream is,
                                               ProtocolSession session,
                                               String fileName )
              throws Exception
      {
          BufferedReader reader = new BufferedReader( new InputStreamReader( is ) );
          String next;
          int lineNumber = 1;
          while ( ( next = reader.readLine() ) != null ) {
              String location = fileName + ":" + lineNumber;
              if ( next.startsWith( CLIENT_TAG ) ) {
                  String clientMsg = next.substring( 3 );
                  session.CL( clientMsg );
              }
              else if ( next.startsWith( SERVER_TAG ) ) {
                  String serverMsg = next.substring( 3 );
                  session.SL( serverMsg, location );
              }
              else if ( next.startsWith( OPEN_UNORDERED_BLOCK_TAG ) ) {
                  List unorderedLines = new ArrayList( 5 );
                  next = reader.readLine();
  
                  while ( !next.startsWith( CLOSE_UNORDERED_BLOCK_TAG ) ) {
                      if (! next.startsWith( SERVER_TAG ) ) {
                          throw new Exception( "Only 'S: ' lines are permitted inside a 'SUB {' block.");
                      }
                      String serverMsg = next.substring( 3 );
                      unorderedLines.add( serverMsg );
                      next = reader.readLine();
                      lineNumber++;
                  }
  
                  session.SUB( unorderedLines, location );
              }
              else if ( next.startsWith( COMMENT_TAG )
                      || next.trim().length() == 0 ) {
                  // ignore these lines.
              }
              else {
                  String prefix = next;
                  if ( next.length() > 3 ) {
                      prefix = next.substring( 0, 3 );
                  }
                  throw new Exception( "Invalid line prefix: " + prefix );
              }
              lineNumber++;
          }
      }
  
  }
  
  
  
  1.1                  jakarta-james/proposals/imap2/test/org/apache/james/test/InvalidServerResponseException.java
  
  Index: InvalidServerResponseException.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.test;
  
  /**
   *
   * @author  Darrell DeBoer <da...@apache.org>
   *
   * @version $Revision: 1.1 $
   */
  public class InvalidServerResponseException extends Exception
  {
      public InvalidServerResponseException( String message )
      {
          super( message );
      }
  }
  
  
  
  1.1                  jakarta-james/proposals/imap2/test/org/apache/james/test/ProtocolSession.java
  
  Index: ProtocolSession.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.test;
  
  import org.apache.oro.text.perl.Perl5Util;
  
  import java.io.BufferedReader;
  import java.io.InterruptedIOException;
  import java.io.PrintWriter;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  /**
   * A protocol session which can be run against a reader and writer, which checks
   * the server response against the expected values.
   * TODO extract the FileProtocolSession from this generic one, so we can build
   * protocol sessions from files with different formats.
   * @author  Darrell DeBoer <da...@apache.org>
   *
   * @version $Revision: 1.1 $
   */
  public class ProtocolSession
  {
      protected List _testElements = new ArrayList();
      private static final Perl5Util perl = new Perl5Util();
  
      // comment in TestCase
      public void runSession( BufferedReader in, PrintWriter out ) throws Exception
      {
          for ( Iterator iter = _testElements.iterator(); iter.hasNext(); ) {
              Object obj = iter.next();
              if ( obj instanceof ProtocolElement ) {
                  ProtocolElement test = ( ProtocolElement ) obj;
                  test.testProtocol( out, in );
              }
          }
      }
  
      /**
       * Write an entire client session to the specified PrintWriter. Server
       * responses are ignored, but may be collected for later testing with
       * {@link #testResponse}.
       */
      public void writeClient( PrintWriter out ) throws Exception
      {
          Iterator iterator = _testElements.iterator();
          while ( iterator.hasNext() ) {
              ProtocolElement element = (ProtocolElement) iterator.next();
              if ( element instanceof ClientRequest ) {
                  element.testProtocol( out, null );
              }
          }
      }
  
      public void testResponse( BufferedReader in ) throws Exception
      {
          Iterator iterator = _testElements.iterator();
          while ( iterator.hasNext() ) {
              ProtocolElement element = (ProtocolElement) iterator.next();
              if ( element instanceof ServerResponse ) {
                  element.testProtocol( null, in );
              }
          }
      }
  
      /**
       * adds a new Client request line to the test elements
       */
      public void CL( String clientLine )
      {
          _testElements.add( new ClientRequest( clientLine ) );
      }
  
      /**
       * adds a new Server Response line to the test elements
       */
      public void SL( String serverLine, String location )
      {
          _testElements.add( new ServerResponse( serverLine, location ) );
      }
  
      /**
       * adds a new Server Response line to the test elements
       */
      public void SL( String serverLine )
      {
          _testElements.add( new ServerResponse( serverLine, "Location unknown.") );
      }
  
      /**
       * adds a new Server Unordered Block to the test elements.
       */
      public void SUB( List serverLines, String location )
      {
          _testElements.add( new UnorderedBlockResponse( serverLines, location ) );
      }
  
      /**
       * Adds a ProtocolElement to the test elements.
       */
      public void addProtocolElement( ProtocolElement element )
      {
          _testElements.add( element );
      }
  
      /**
       * This Line is sent to the server (everything after "CL: ") in expectation
       * that the server will respond.
       */
      private class ClientRequest implements ProtocolElement
      {
          private String _msg;
  
          public ClientRequest( String msg )
          {
              _msg = msg;
          }
  
          /**
           * Sends the request to the server
           */
          public void testProtocol( PrintWriter out, BufferedReader in ) throws Exception
          {
              out.println( _msg );
          }
      }
  
      private class ServerResponse implements ProtocolElement
      {
          private String expectedLine;
          protected String location;
  
          public ServerResponse( String expectedPattern, String location )
          {
              this.expectedLine = expectedPattern;
              this.location = location;
          }
  
          public ServerResponse( String expectedPattern )
          {
              this( expectedPattern, "" );
          }
  
          public void testProtocol( PrintWriter out, BufferedReader in ) throws Exception
          {
              String testLine = readLine( in );
              if ( ! match( expectedLine, testLine ) ) {
                  String errMsg = "\nLocation: " + location +
                          "\nExcpected: " + expectedLine +
                          "\nActual   : " + testLine;
                  throw new InvalidServerResponseException( errMsg );
              }
          }
  
          protected boolean match( String expected, String actual )
          {
              String pattern = "m/" + expected + "/";
              return perl.match( pattern, actual );
          }
  
          /**
           * Grabs a line from the server and throws an error message if it
           * doesn't work out
           * @param in BufferedReader for getting the server response
           * @return String of the line from the server
           */
          protected String readLine( BufferedReader in ) throws Exception
          {
              try {
                  return in.readLine();
              }
              catch ( InterruptedIOException e ) {
                  String errMsg = "\nLocation: " + location +
                          "\nExpected: " + expectedLine +
                          "\nReason: Server Timeout.";
                  throw new InvalidServerResponseException( errMsg );
              }
          }
      }
  
      private class UnorderedBlockResponse extends ServerResponse
      {
          private List expectedLines = new ArrayList();
  
          public UnorderedBlockResponse( List expectedLines, String location )
          {
              super( "<Unordered Block>", location );
              this.expectedLines = expectedLines;
          }
  
          public void testProtocol( PrintWriter out, BufferedReader in )
                  throws Exception
          {
              List testLines = new ArrayList( expectedLines );
              while ( testLines.size() > 0 )
              {
                  String actualLine = readLine( in );
                  boolean foundMatch = false;
  
                  for ( int i = 0; i < testLines.size(); i++ )
                  {
                      String expected = (String)testLines.get( i );
                      if ( match( expected, actualLine ))
                      {
                          foundMatch = true;
                          testLines.remove( expected );
                          break;
                      }
                  }
  
                  if (! foundMatch )
                  {
                      StringBuffer errMsg = new StringBuffer()
                          .append( "\nLocation: " )
                          .append( location )
                          .append( "\nExpected one of: " );
                      Iterator iter = expectedLines.iterator();
                      while ( iter.hasNext() ) {
                          errMsg.append( "\n    " );
                          errMsg.append( iter.next() );
                      }
                      errMsg.append("\nActual: " )
                            .append( actualLine );
  
                      throw new InvalidServerResponseException( errMsg.toString() );
                  }
              }
          }
      }
  
      interface ProtocolElement
      {
          void testProtocol( PrintWriter out, BufferedReader in ) throws Exception;
      }
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>