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 jo...@apache.org on 2006/10/09 19:15:42 UTC

svn commit: r454432 [4/14] - in /james/server/sandbox/imap-integration: ./ lib/ src/java/ src/java/org/apache/james/imapserver/ src/java/org/apache/james/imapserver/commands/ src/java/org/apache/james/imapserver/debug/ src/java/org/apache/james/imapser...

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ListCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ListCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ListCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ListCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,365 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.mailboxmanager.ListResult;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.impl.ListResultImpl;
+
+/**
+ * Handles processeing for the LIST imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class ListCommand extends AuthenticatedStateCommand
+{
+    public static final String NAME = "LIST";
+    public static final String ARGS = "<reference-name> <mailbox-name-with-wildcards>";
+
+    private ListCommandParser parser = new ListCommandParser();
+
+    /** @see CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session )
+            throws ProtocolException, MailboxException
+    {
+        String referenceName = parser.mailbox( request );
+        String mailboxPattern = parser.listMailbox( request );
+        parser.endLine( request );
+
+        // Should the #user.userName section be removed from names returned?
+        boolean removeUserPrefix;
+
+        ListResult[] listResults;
+        
+        String personalNamespace = USER_NAMESPACE + HIERARCHY_DELIMITER_CHAR +
+        session.getUser().getUserName();
+        
+        if ( mailboxPattern.length() == 0 ) {
+            // An empty mailboxPattern signifies a request for the hierarchy delimiter
+            // and root name of the referenceName argument
+
+            String referenceRoot;
+            if ( referenceName.startsWith( NAMESPACE_PREFIX ) )
+            {
+                // A qualified reference name - get the first element,
+                // and don't remove the user prefix
+                removeUserPrefix = false;
+                int firstDelimiter = referenceName.indexOf( HIERARCHY_DELIMITER_CHAR );
+                if ( firstDelimiter == -1 ) {
+                    referenceRoot = referenceName;
+                }
+                else {
+                    referenceRoot = referenceName.substring(0, firstDelimiter );
+                }
+            }
+            else {
+                // A relative reference name - need to remove user prefix from results.
+                referenceRoot = "";
+                removeUserPrefix = true;
+                
+            }
+
+            // Get the mailbox for the reference name.
+            listResults = new ListResult[1];
+            listResults[0]=new ListResultImpl(referenceRoot,HIERARCHY_DELIMITER);
+        }
+        else {
+
+            // If the mailboxPattern is fully qualified, ignore the
+            // reference name.
+            if ( mailboxPattern.charAt( 0 ) == NAMESPACE_PREFIX_CHAR ) {
+                referenceName="";
+            }
+
+            // If the search pattern is relative, need to remove user prefix from results.
+            removeUserPrefix = ( (referenceName+mailboxPattern).charAt(0) != NAMESPACE_PREFIX_CHAR );
+
+            if (removeUserPrefix) {
+                referenceName=personalNamespace+"."+referenceName;
+            }
+            
+            listResults = doList( session, referenceName, mailboxPattern );
+        }
+
+
+        int prefixLength = personalNamespace.length();
+
+       for (int i = 0; i < listResults.length; i++) {
+            StringBuffer message = new StringBuffer( "(" );
+            String[] attrs=listResults[i].getAttributes();
+            for (int j = 0; j < attrs.length; j++) {
+                if (j > 0) {
+                    message.append(' ');
+                }
+                message.append( attrs[j] );
+            }
+            message.append( ") \"" );
+            message.append( listResults[i].getHierarchyDelimiter() );
+            message.append( "\" " );
+
+            String mailboxName = listResults[i].getName();
+            if ( removeUserPrefix ) {
+                if ( mailboxName.length() <= prefixLength ) {
+                    mailboxName = "";
+                }
+                else {
+                    mailboxName = mailboxName.substring( prefixLength + 1 );
+                }
+            }
+
+            // TODO: need to check if the mailbox name needs quoting.
+            if ( mailboxName.length() == 0 ) {
+                message.append("\"\"");
+            }
+            else {
+                message.append( mailboxName );
+            }
+
+            response.commandResponse( this, message.toString() );
+        }
+
+        session.unsolicitedResponses( response, false );
+        response.commandComplete( this );
+    }
+
+    protected ListResult[] doList( ImapSession session, String base, String pattern ) throws MailboxException {
+        return doList(  session,  base,  pattern, false);
+    }
+    
+    
+    protected ListResult[] doList( ImapSession session, String base, String pattern, boolean subscribed ) throws MailboxException
+    {
+        try {
+            return session.getMailboxManager().list(base,pattern,false);
+        } catch (MailboxManagerException e) {
+            throw new MailboxException(e);  
+        }
+    }
+
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+
+    private class ListCommandParser extends CommandParser
+    {
+        /**
+         * Reads an argument of type "list_mailbox" from the request, which is
+         * the second argument for a LIST or LSUB command. Valid values are a "string"
+         * argument, an "atom" with wildcard characters.
+         * @return An argument of type "list_mailbox"
+         */
+        public String listMailbox( ImapRequestLineReader request ) throws ProtocolException
+        {
+            char next = request.nextWordChar();
+            switch ( next ) {
+                case '"':
+                    return consumeQuoted( request );
+                case '{':
+                    return consumeLiteral( request );
+                default:
+                    return consumeWord( request, new ListCharValidator() );
+            }
+        }
+
+        private class ListCharValidator extends ATOM_CHARValidator
+        {
+            public boolean isValid( char chr )
+            {
+                if ( isListWildcard( chr ) ) {
+                    return true;
+                }
+                return super.isValid( chr );
+            }
+        }
+    }
+}
+
+/*
+6.3..8.  LIST Command
+
+   Arguments:  reference name
+               mailbox name with possible wildcards
+
+   Responses:  untagged responses: LIST
+
+   Result:     OK - list completed
+               NO - list failure: can't list that reference or name
+               BAD - command unknown or arguments invalid
+
+      The LIST command returns a subset of names from the complete set
+      of all names available to the client.  Zero or more untagged LIST
+      replies are returned, containing the name attributes, hierarchy
+      delimiter, and name; see the description of the LIST reply for
+      more detail.
+
+      The LIST command SHOULD return its data quickly, without undue
+      delay.  For example, it SHOULD NOT go to excess trouble to
+      calculate \Marked or \Unmarked status or perform other processing;
+      if each name requires 1 second of processing, then a list of 1200
+      names would take 20 minutes!
+
+      An empty ("" string) reference name argument indicates that the
+      mailbox name is interpreted as by SELECT. The returned mailbox
+      names MUST match the supplied mailbox name pattern.  A non-empty
+      reference name argument is the name of a mailbox or a level of
+      mailbox hierarchy, and indicates a context in which the mailbox
+      name is interpreted in an implementation-defined manner.
+
+      An empty ("" string) mailbox name argument is a special request to
+      return the hierarchy delimiter and the root name of the name given
+      in the reference.  The value returned as the root MAY be null if
+      the reference is non-rooted or is null.  In all cases, the
+      hierarchy delimiter is returned.  This permits a client to get the
+      hierarchy delimiter even when no mailboxes by that name currently
+      exist.
+
+      The reference and mailbox name arguments are interpreted, in an
+      implementation-dependent fashion, into a canonical form that
+      represents an unambiguous left-to-right hierarchy.  The returned
+      mailbox names will be in the interpreted form.
+
+      Any part of the reference argument that is included in the
+      interpreted form SHOULD prefix the interpreted form.  It SHOULD
+      also be in the same form as the reference name argument.  This
+      rule permits the client to determine if the returned mailbox name
+      is in the context of the reference argument, or if something about
+      the mailbox argument overrode the reference argument.  Without
+      this rule, the client would have to have knowledge of the server's
+      naming semantics including what characters are "breakouts" that
+      override a naming context.
+
+      For example, here are some examples of how references and mailbox
+      names might be interpreted on a UNIX-based server:
+
+               Reference     Mailbox Name  Interpretation
+               ------------  ------------  --------------
+               ~smith/Mail/  foo.*         ~smith/Mail/foo.*
+               archive/      %             archive/%
+               #news.        comp.mail.*   #news.comp.mail.*
+               ~smith/Mail/  /usr/doc/foo  /usr/doc/foo
+               archive/      ~fred/Mail/*  ~fred/Mail/*
+
+      The first three examples demonstrate interpretations in the
+      context of the reference argument.  Note that "~smith/Mail" SHOULD
+      NOT be transformed into something like "/u2/users/smith/Mail", or
+      it would be impossible for the client to determine that the
+      interpretation was in the context of the reference.
+
+      The character "*" is a wildcard, and matches zero or more
+      characters at this position.  The character "%" is similar to "*",
+      but it does not match a hierarchy delimiter.  If the "%" wildcard
+      is the last character of a mailbox name argument, matching levels
+      of hierarchy are also returned.  If these levels of hierarchy are
+      not also selectable mailboxes, they are returned with the
+      \Noselect mailbox name attribute (see the description of the LIST
+      response for more details).
+
+      Server implementations are permitted to "hide" otherwise
+      accessible mailboxes from the wildcard characters, by preventing
+      certain characters or names from matching a wildcard in certain
+      situations.  For example, a UNIX-based server might restrict the
+      interpretation of "*" so that an initial "/" character does not
+      match.
+
+      The special name INBOX is included in the output from LIST, if
+      INBOX is supported by this server for this user and if the
+      uppercase string "INBOX" matches the interpreted reference and
+      mailbox name arguments with wildcards as described above.  The
+      criteria for omitting INBOX is whether SELECT INBOX will return
+      failure; it is not relevant whether the user's real INBOX resides
+      on this or some other server.
+
+   Example:    C: A101 LIST "" ""
+               S: * LIST (\Noselect) "/" ""
+               S: A101 OK LIST Completed
+               C: A102 LIST #news.comp.mail.misc ""
+               S: * LIST (\Noselect) "." #news.
+               S: A102 OK LIST Completed
+               C: A103 LIST /usr/staff/jones ""
+               S: * LIST (\Noselect) "/" /
+               S: A103 OK LIST Completed
+               C: A202 LIST ~/Mail/ %
+               S: * LIST (\Noselect) "/" ~/Mail/foo
+               S: * LIST () "/" ~/Mail/meetings
+               S: A202 OK LIST completed
+
+7.2.2.  LIST Response
+
+   Contents:   name attributes
+               hierarchy delimiter
+               name
+
+      The LIST response occurs as a result of a LIST command.  It
+      returns a single name that matches the LIST specification.  There
+      can be multiple LIST responses for a single LIST command.
+
+      Four name attributes are defined:
+
+      \Noinferiors   It is not possible for any child levels of
+                     hierarchy to exist under this name; no child levels
+                     exist now and none can be created in the future.
+
+      \Noselect      It is not possible to use this name as a selectable
+                     mailbox.
+
+      \Marked        The mailbox has been marked "interesting" by the
+                     server; the mailbox probably contains messages that
+                     have been added since the last time the mailbox was
+                     selected.
+
+      \Unmarked      The mailbox does not contain any additional
+                     messages since the last time the mailbox was
+                     selected.
+
+      If it is not feasible for the server to determine whether the
+      mailbox is "interesting" or not, or if the name is a \Noselect
+      name, the server SHOULD NOT send either \Marked or \Unmarked.
+
+      The hierarchy delimiter is a character used to delimit levels of
+      hierarchy in a mailbox name.  A client can use it to create child
+      mailboxes, and to search higher or lower levels of naming
+      hierarchy.  All children of a top-level hierarchy node MUST use
+      the same separator character.  A NIL hierarchy delimiter means
+      that no hierarchy exists; the name is a "flat" name.
+
+      The name represents an unambiguous left-to-right hierarchy, and
+      MUST be valid for use as a reference in LIST and LSUB commands.
+      Unless \Noselect is indicated, the name MUST also be valid as an
+            argument for commands, such as SELECT, that accept mailbox
+      names.
+
+   Example:    S: * LIST (\Noselect) "/" ~/Mail/foo
+*/

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LoginCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LoginCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LoginCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LoginCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,90 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.services.User;
+
+
+/**
+ * Handles processeing for the LOGIN imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class LoginCommand extends NonAuthenticatedStateCommand
+{
+    public static final String NAME = "LOGIN";
+    public static final String ARGS = "<userid> <password>";
+
+    /** @see CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session )
+            throws ProtocolException
+    {
+        String userid = parser.astring( request );
+        String password = parser.astring( request );
+        parser.endLine( request );
+
+        if ( session.getUsers().test( userid, password ) ) {
+            User user = session.getUsers().getUserByName( userid );
+            session.setAuthenticated( user );
+            response.commandComplete( this );
+
+        }
+        else {
+            response.commandFailed( this, "Invalid login/password" );
+        }
+    }
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+}
+
+/*
+6.2.2.  LOGIN Command
+
+   Arguments:  user name
+               password
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - login completed, now in authenticated state
+               NO - login failure: user name or password rejected
+               BAD - command unknown or arguments invalid
+
+      The LOGIN command identifies the client to the server and carries
+      the plaintext password authenticating this user.
+
+   Example:    C: a001 LOGIN SMITH SESAME
+               S: a001 OK LOGIN completed
+*/

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LogoutCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LogoutCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LogoutCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LogoutCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,82 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+
+/**
+ * Handles processeing for the LOGOUT imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class LogoutCommand extends CommandTemplate
+{
+    public static final String NAME = "LOGOUT";
+    public static final String ARGS = null;
+    public static final String BYE_MESSAGE = VERSION + SP + "Server logging out";
+
+    /** @see CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session ) throws ProtocolException
+    {
+        parser.endLine( request );
+
+        response.byeResponse( BYE_MESSAGE );
+        response.commandComplete( this );
+        session.closeConnection();
+    }
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+}
+
+/*
+6.1.3.  LOGOUT Command
+
+   Arguments:  none
+
+   Responses:  REQUIRED untagged response: BYE
+
+   Result:     OK - logout completed
+               BAD - command unknown or arguments invalid
+
+      The LOGOUT command informs the server that the client is done with
+      the connection.  The server MUST send a BYE untagged response
+      before the (tagged) OK response, and then close the network
+      connection.
+
+   Example:    C: A023 LOGOUT
+               S: * BYE IMAP4rev1 Server logging out
+               S: A023 OK LOGOUT completed
+               (Server and client then close the connection)
+*/

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LsubCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LsubCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LsubCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/LsubCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,44 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.mailboxmanager.ListResult;
+
+/**
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class LsubCommand extends ListCommand
+{
+    public static final String NAME = "LSUB";
+
+    protected ListResult[] doList( ImapSession session, String base, String pattern )  throws MailboxException
+    {
+        return doList(session,base,pattern,true);
+    }
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/MsnRange.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/MsnRange.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/MsnRange.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/MsnRange.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,50 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+/**
+ * Represents a range of Message Sequence Numbers.
+ */
+public class MsnRange {
+
+    private int _lowVal;
+    private int _highVal;
+
+    public MsnRange(int singleVal) {
+        _lowVal = singleVal;
+        _highVal = singleVal;
+    }
+
+    public MsnRange(int lowVal, int highVal) {
+        _lowVal = lowVal;
+        _highVal = highVal;
+    }
+
+    public int getLowVal() {
+        return _lowVal;
+    }
+
+    public int getHighVal() {
+        return _highVal;
+    }
+
+    public boolean includes(int msn) {
+        return _lowVal <= msn && msn <= _highVal;
+    }
+
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/NonAuthenticatedStateCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/NonAuthenticatedStateCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/NonAuthenticatedStateCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/NonAuthenticatedStateCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,39 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapSessionState;
+
+/**
+ * A base class for ImapCommands only valid in the NON_AUTHENTICATED state.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+abstract class NonAuthenticatedStateCommand extends CommandTemplate
+{
+
+    /**
+     * Ensure that state is {@link ImapSessionState#NON_AUTHENTICATED}.
+     */
+    public boolean validForState( ImapSessionState state )
+    {
+        return ( state == ImapSessionState.NON_AUTHENTICATED );
+    }
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/NoopCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/NoopCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/NoopCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/NoopCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,88 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.store.MailboxException;
+
+/**
+ * Handles processeing for the NOOP imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class NoopCommand extends CommandTemplate
+{
+    public static final String NAME = "NOOP";
+    public static final String ARGS = null;
+
+    /** @see org.apache.james.imapserver.commands.CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session ) throws ProtocolException, MailboxException
+    {
+        parser.endLine( request );
+        session.unsolicitedResponses( response, false );
+        response.commandComplete( this );
+    }
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+}
+
+/*
+6.1.2.  NOOP Command
+
+   Arguments:  none
+
+   Responses:  no specific responses for this command (but see below)
+
+   Result:     OK - noop completed
+               BAD - command unknown or arguments invalid
+
+      The NOOP command always succeeds.  It does nothing.
+
+      Since any command can return a status update as untagged data, the
+      NOOP command can be used as a periodic poll for new messages or
+      message status updates during a period of inactivity.  The NOOP
+      command can also be used to reset any inactivity autologout timer
+      on the server.
+
+   Example:    C: a002 NOOP
+               S: a002 OK NOOP completed
+                  . . .
+               C: a047 NOOP
+               S: * 22 EXPUNGE
+               S: * 23 EXISTS
+               S: * 3 RECENT
+               S: * 14 FETCH (FLAGS (\Seen \Deleted))
+               S: a047 OK NOOP completed
+*/

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/RenameCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/RenameCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/RenameCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/RenameCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,139 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.AuthorizationException;
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+
+/**
+ * Handles processeing for the RENAME imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class RenameCommand extends AuthenticatedStateCommand
+{
+    public static final String NAME = "RENAME";
+    public static final String ARGS = "existing-mailbox-name SPACE new-mailbox-name";
+
+    /** @see CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session )
+            throws ProtocolException, MailboxException, AuthorizationException
+    {
+        String existingName = parser.mailbox( request );
+        String newName = parser.mailbox( request );
+        parser.endLine( request );
+
+        try {
+            existingName=session.buildFullName(existingName);
+            newName=session.buildFullName(newName);
+            session.getMailboxManager().renameMailbox( existingName, newName );
+        } catch (MailboxManagerException e) {
+           throw new MailboxException(e);
+        }
+
+        session.unsolicitedResponses( response , false );
+        response.commandComplete( this );
+    }
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+
+}
+
+/*
+6.3.5.  RENAME Command
+
+   Arguments:  existing mailbox name
+               new mailbox name
+
+   Responses:  no specific responses for this command
+
+   Result:     OK - rename completed
+               NO - rename failure: can't rename mailbox with that name,
+                    can't rename to mailbox with that name
+               BAD - command unknown or arguments invalid
+
+      The RENAME command changes the name of a mailbox.  A tagged OK
+      response is returned only if the mailbox has been renamed.  It is
+      an error to attempt to rename from a mailbox name that does not
+      exist or to a mailbox name that already exists.  Any error in
+      renaming will return a tagged NO response.
+
+      If the name has inferior hierarchical names, then the inferior
+      hierarchical names MUST also be renamed.  For example, a rename of
+      "foo" to "zap" will rename "foo/bar" (assuming "/" is the
+      hierarchy delimiter character) to "zap/bar".
+
+      The value of the highest-used unique identifier of the old mailbox
+      name MUST be preserved so that a new mailbox created with the same
+      name will not reuse the identifiers of the former incarnation,
+      UNLESS the new incarnation has a different unique identifier
+      validity value.  See the description of the UID command for more
+      detail.
+
+      Renaming INBOX is permitted, and has special behavior.  It moves
+      all messages in INBOX to a new mailbox with the given name,
+      leaving INBOX empty.  If the server implementation supports
+      inferior hierarchical names of INBOX, these are unaffected by a
+      rename of INBOX.
+
+   Examples:   C: A682 LIST "" *
+               S: * LIST () "/" blurdybloop
+               S: * LIST (\Noselect) "/" foo
+               S: * LIST () "/" foo/bar
+               S: A682 OK LIST completed
+               C: A683 RENAME blurdybloop sarasoop
+               S: A683 OK RENAME completed
+               C: A684 RENAME foo zowie
+               S: A684 OK RENAME Completed
+               C: A685 LIST "" *
+               S: * LIST () "/" sarasoop
+               S: * LIST (\Noselect) "/" zowie
+               S: * LIST () "/" zowie/bar
+               S: A685 OK LIST completed
+
+               C: Z432 LIST "" *
+               S: * LIST () "." INBOX
+               S: * LIST () "." INBOX.bar
+               S: Z432 OK LIST completed
+               C: Z433 RENAME INBOX old-mail
+               S: Z433 OK RENAME completed
+               C: Z434 LIST "" *
+               S: * LIST () "." INBOX
+               S: * LIST () "." INBOX.bar
+               S: * LIST () "." old-mail
+               S: Z434 OK LIST completed
+*/

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SearchCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SearchCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SearchCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SearchCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,316 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import javax.mail.Message;
+import javax.mail.search.SearchTerm;
+
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+
+/**
+ * Handles processeing for the SEARCH imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class SearchCommand extends SelectedStateCommand implements UidEnabledCommand
+{
+    public static final String NAME = "SEARCH";
+    public static final String ARGS = "<search term>";
+
+    private SearchCommandParser parser = new SearchCommandParser();
+
+    /** @see CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session )
+            throws ProtocolException, MailboxException
+    {
+        doProcess( request, response, session, false );
+    }
+
+    public void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session,
+                              boolean useUids )
+            throws ProtocolException, MailboxException
+    {
+        // Parse the search term from the request
+        SearchTerm searchTerm = parser.searchTerm( request );
+        parser.endLine( request );
+
+        ImapMailboxSession mailbox = session.getSelected().getMailbox();
+        final int result;
+        if (useUids) {
+            result= MessageResult.UID;
+        } else {
+            result= MessageResult.MSN;
+        }
+        MessageResult[] messageResults;
+        try {
+            messageResults = mailbox.search(GeneralMessageSetImpl.all(),searchTerm, result);
+        } catch (MailboxManagerException e) {
+          throw new MailboxException(e);
+        }
+        StringBuffer idList = new StringBuffer();
+        for (int i = 0; i < messageResults.length; i++) {
+            if ( i > 0 ) {
+                idList.append( SP );
+            }
+            if ( useUids ) {
+                idList.append( messageResults[i].getUid());
+            } else {
+                idList.append( messageResults[i].getMsn());
+            }
+        }
+        
+        response.commandResponse( this, idList.toString() );
+        boolean omitExpunged = (!useUids);
+        session.unsolicitedResponses( response, omitExpunged, useUids );
+        response.commandComplete( this );
+    }
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+
+    private class SearchCommandParser extends CommandParser
+    {
+        /**
+         * Parses the request argument into a valid search term.
+         * Not yet implemented - all searches will return everything for now.
+         * TODO implement search
+         */
+        public SearchTerm searchTerm( ImapRequestLineReader request )
+                throws ProtocolException
+        {
+            // Dummy implementation
+            // Consume to the end of the line.
+            char next = request.nextChar();
+            while ( next != '\n' ) {
+                request.consume();
+                next = request.nextChar();
+            }
+
+            // Return a search term that matches everything.
+            return new SearchTerm()
+            {
+                private static final long serialVersionUID = 5290284637903768771L;
+
+                public boolean match( Message message )
+                {
+                    return true;
+                }
+            };
+        }
+
+    }
+}
+/*
+6.4.4.  SEARCH Command
+
+   Arguments:  OPTIONAL [CHARSET] specification
+               searching criteria (one or more)
+
+   Responses:  REQUIRED untagged response: SEARCH
+
+   Result:     OK - search completed
+               NO - search error: can't search that [CHARSET] or
+                    criteria
+               BAD - command unknown or arguments invalid
+
+      The SEARCH command searches the mailbox for messages that match
+      the given searching criteria.  Searching criteria consist of one
+      or more search keys.  The untagged SEARCH response from the server
+      contains a listing of message sequence numbers corresponding to
+      those messages that match the searching criteria.
+
+      When multiple keys are specified, the result is the intersection
+      (AND function) of all the messages that match those keys.  For
+      example, the criteria DELETED FROM "SMITH" SINCE 1-Feb-1994 refers
+      to all deleted messages from Smith that were placed in the mailbox
+      since February 1, 1994.  A search key can also be a parenthesized
+      list of one or more search keys (e.g. for use with the OR and NOT
+      keys).
+
+      Server implementations MAY exclude [MIME-IMB] body parts with
+      terminal content media types other than TEXT and MESSAGE from
+      consideration in SEARCH matching.
+
+      The OPTIONAL [CHARSET] specification consists of the word
+      "CHARSET" followed by a registered [CHARSET].  It indicates the
+      [CHARSET] of the strings that appear in the search criteria.
+      [MIME-IMB] content transfer encodings, and [MIME-HDRS] strings in
+      [RFC-822]/[MIME-IMB] headers, MUST be decoded before comparing
+      text in a [CHARSET] other than US-ASCII.  US-ASCII MUST be
+      supported; other [CHARSET]s MAY be supported.  If the server does
+      not support the specified [CHARSET], it MUST return a tagged NO
+      response (not a BAD).
+
+      In all search keys that use strings, a message matches the key if
+      the string is a substring of the field.  The matching is case-
+      insensitive.
+
+      The defined search keys are as follows.  Refer to the Formal
+      Syntax section for the precise syntactic definitions of the
+      arguments.
+
+      <message set>  Messages with message sequence numbers
+                     corresponding to the specified message sequence
+                     number set
+
+      ALL            All messages in the mailbox; the default initial
+                     key for ANDing.
+
+      ANSWERED       Messages with the \Answered flag set.
+
+      BCC <string>   Messages that contain the specified string in the
+                     envelope structure's BCC field.
+
+      BEFORE <date>  Messages whose internal date is earlier than the
+                     specified date.
+
+      BODY <string>  Messages that contain the specified string in the
+                     body of the message.
+
+      CC <string>    Messages that contain the specified string in the
+                     envelope structure's CC field.
+
+      DELETED        Messages with the \Deleted flag set.
+
+      DRAFT          Messages with the \Draft flag set.
+
+      FLAGGED        Messages with the \Flagged flag set.
+
+      FROM <string>  Messages that contain the specified string in the
+                     envelope structure's FROM field.
+
+      HEADER <field-name> <string>
+                     Messages that have a header with the specified
+                     field-name (as defined in [RFC-822]) and that
+                     contains the specified string in the [RFC-822]
+                     field-body.
+
+      KEYWORD <flag> Messages with the specified keyword set.
+
+      LARGER <n>     Messages with an [RFC-822] size larger than the
+                     specified number of octets.
+
+      NEW            Messages that have the \Recent flag set but not the
+                     \Seen flag.  This is functionally equivalent to
+                     "(RECENT UNSEEN)".
+
+      NOT <search-key>
+                     Messages that do not match the specified search
+                     key.
+
+      OLD            Messages that do not have the \Recent flag set.
+                     This is functionally equivalent to "NOT RECENT" (as
+                     opposed to "NOT NEW").
+
+      ON <date>      Messages whose internal date is within the
+                     specified date.
+
+      OR <search-key1> <search-key2>
+                     Messages that match either search key.
+
+      RECENT         Messages that have the \Recent flag set.
+
+      SEEN           Messages that have the \Seen flag set.
+
+      SENTBEFORE <date>
+                     Messages whose [RFC-822] Date: header is earlier
+                     than the specified date.
+
+      SENTON <date>  Messages whose [RFC-822] Date: header is within the
+                     specified date.
+
+      SENTSINCE <date>
+                     Messages whose [RFC-822] Date: header is within or
+                     later than the specified date.
+
+      SINCE <date>   Messages whose internal date is within or later
+                     than the specified date.
+
+      SMALLER <n>    Messages with an [RFC-822] size smaller than the
+                     specified number of octets.
+
+      SUBJECT <string>
+                     Messages that contain the specified string in the
+                     envelope structure's SUBJECT field.
+
+      TEXT <string>  Messages that contain the specified string in the
+                     header or body of the message.
+
+      TO <string>    Messages that contain the specified string in the
+                     envelope structure's TO field.
+
+      UID <message set>
+                     Messages with unique identifiers corresponding to
+                     the specified unique identifier set.
+
+      UNANSWERED     Messages that do not have the \Answered flag set.
+
+      UNDELETED      Messages that do not have the \Deleted flag set.
+
+      UNDRAFT        Messages that do not have the \Draft flag set.
+
+      UNFLAGGED      Messages that do not have the \Flagged flag set.
+
+      UNKEYWORD <flag>
+                     Messages that do not have the specified keyword
+                     set.
+
+      UNSEEN         Messages that do not have the \Seen flag set.
+
+   Example:    C: A282 SEARCH FLAGGED SINCE 1-Feb-1994 NOT FROM "Smith"
+               S: * SEARCH 2 84 882
+               S: A282 OK SEARCH completed
+
+
+
+7.2.5.  SEARCH Response
+
+   Contents:   zero or more numbers
+
+      The SEARCH response occurs as a result of a SEARCH or UID SEARCH
+      command.  The number(s) refer to those messages that match the
+      search criteria.  For SEARCH, these are message sequence numbers;
+      for UID SEARCH, these are unique identifiers.  Each number is
+      delimited by a space.
+
+   Example:    S: * SEARCH 2 3 6
+
+*/

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SelectCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SelectCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SelectCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SelectCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,189 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+
+/**
+ * Handles processeing for the SELECT imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class SelectCommand extends AuthenticatedStateCommand
+{
+    public static final String NAME = "SELECT";
+    public static final String ARGS = "mailbox";
+
+    /** @see org.apache.james.imapserver.commands.CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session )
+            throws ProtocolException, MailboxException
+    {
+        String mailboxName = parser.mailbox( request );
+        parser.endLine( request );
+
+        session.deselect();
+
+        final boolean isExamine = ( this instanceof ExamineCommand );
+
+        try {
+            mailboxName=session.buildFullName(mailboxName);
+            selectMailbox(mailboxName, session, isExamine);
+            ImapMailboxSession mailbox = session.getSelected().getMailbox();
+            response.flagsResponse(mailbox.getPermanentFlags());
+            final boolean resetRecent = !isExamine;
+            response.recentResponse(mailbox.getRecentCount(resetRecent));
+            response
+                    .okResponse("UIDVALIDITY " + mailbox.getUidValidity(), null);
+
+            MessageResult firstUnseen = mailbox.getFirstUnseen(MessageResult.MSN);
+                   
+            response.existsResponse(mailbox.getMessageCount());
+
+            if (firstUnseen != null) {
+                response.okResponse("UNSEEN " + firstUnseen.getMsn(), "Message "
+                        + firstUnseen.getMsn() + " is the first unseen");
+            } else {
+                response.okResponse(null, "No messages unseen");
+            }
+            response.permanentFlagsResponse(mailbox.getPermanentFlags());
+
+            if (!mailbox.isWriteable()) {
+                response.commandComplete(this, "READ-ONLY");
+            } else {
+                response.commandComplete(this, "READ-WRITE");
+            }
+        } catch (MailboxManagerException e) {
+            throw new MailboxException(e);
+        }
+    }
+
+    private boolean selectMailbox(String mailboxName, ImapSession session, boolean readOnly) throws MailboxException, MailboxManagerException {
+        ImapMailboxSession mailbox = session.getMailboxManager().getGenericImapMailboxSession(mailboxName);
+
+        if ( !mailbox.isSelectable() ) {
+            throw new MailboxException( "Nonselectable mailbox." );
+        }
+
+        session.setSelected( mailbox, readOnly );
+        return readOnly;
+    }
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+}
+
+/*
+6.3.1.  SELECT Command
+
+   Arguments:  mailbox name
+
+   Responses:  REQUIRED untagged responses: FLAGS, EXISTS, RECENT
+               OPTIONAL OK untagged responses: UNSEEN, PERMANENTFLAGS
+
+   Result:     OK - select completed, now in selected state
+               NO - select failure, now in authenticated state: no
+                    such mailbox, can't access mailbox
+               BAD - command unknown or arguments invalid
+
+   The SELECT command selects a mailbox so that messages in the
+   mailbox can be accessed.  Before returning an OK to the client,
+   the server MUST send the following untagged data to the client:
+
+      FLAGS       Defined flags in the mailbox.  See the description
+                  of the FLAGS response for more detail.
+
+      <n> EXISTS  The number of messages in the mailbox.  See the
+                  description of the EXISTS response for more detail.
+
+      <n> RECENT  The number of messages with the \Recent flag set.
+                  See the description of the RECENT response for more
+                  detail.
+
+      OK [UIDVALIDITY <n>]
+                  The unique identifier validity value.  See the
+                  description of the UID command for more detail.
+
+   to define the initial state of the mailbox at the client.
+
+   The server SHOULD also send an UNSEEN response code in an OK
+   untagged response, indicating the message sequence number of the
+   first unseen message in the mailbox.
+
+   If the client can not change the permanent state of one or more of
+   the flags listed in the FLAGS untagged response, the server SHOULD
+   send a PERMANENTFLAGS response code in an OK untagged response,
+   listing the flags that the client can change permanently.
+
+   Only one mailbox can be selected at a time in a connection;
+   simultaneous access to multiple mailboxes requires multiple
+   connections.  The SELECT command automatically deselects any
+   currently selected mailbox before attempting the new selection.
+   Consequently, if a mailbox is selected and a SELECT command that
+   fails is attempted, no mailbox is selected.
+
+
+
+
+Crispin                     Standards Track                    [Page 23]
+
+RFC 2060                       IMAP4rev1                   December 1996
+
+
+   If the client is permitted to modify the mailbox, the server
+   SHOULD prefix the text of the tagged OK response with the
+         "[READ-WRITE]" response code.
+
+      If the client is not permitted to modify the mailbox but is
+      permitted read access, the mailbox is selected as read-only, and
+      the server MUST prefix the text of the tagged OK response to
+      SELECT with the "[READ-ONLY]" response code.  Read-only access
+      through SELECT differs from the EXAMINE command in that certain
+      read-only mailboxes MAY permit the change of permanent state on a
+      per-user (as opposed to global) basis.  Netnews messages marked in
+      a server-based .newsrc file are an example of such per-user
+      permanent state that can be modified with read-only mailboxes.
+
+   Example:    C: A142 SELECT INBOX
+               S: * 172 EXISTS
+               S: * 1 RECENT
+               S: * OK [UNSEEN 12] Message 12 is first unseen
+               S: * OK [UIDVALIDITY 3857529045] UIDs valid
+               S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+               S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+               S: A142 OK [READ-WRITE] SELECT completed
+*/

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SelectedStateCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SelectedStateCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SelectedStateCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/SelectedStateCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,49 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapSessionState;
+
+/**
+ * A base class for ImapCommands only valid in the SELECTED state.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+abstract class SelectedStateCommand extends CommandTemplate
+{
+    /**
+     * Subclasses of this command are only valid in the
+     * {@link ImapSessionState#SELECTED} state.
+     */
+    public boolean validForState( ImapSessionState state )
+    {
+        return ( state == ImapSessionState.SELECTED );
+    }
+
+    protected boolean includes(IdRange[] idSet, long id) {
+        for (int i = 0; i < idSet.length; i++) {
+            IdRange idRange = idSet[i];
+            if (idRange.includes(id)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/StatusCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/StatusCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/StatusCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/StatusCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,241 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+
+/**
+ * Handles processeing for the STATUS imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class StatusCommand extends AuthenticatedStateCommand
+{
+    public static final String NAME = "STATUS";
+    public static final String ARGS = "<mailbox> ( <status-data-item>+ )";
+
+    private static final String MESSAGES = "MESSAGES";
+    private static final String RECENT = "RECENT";
+    private static final String UIDNEXT = "UIDNEXT";
+    private static final String UIDVALIDITY = "UIDVALIDITY";
+    private static final String UNSEEN = "UNSEEN";
+
+    private StatusCommandParser parser = new StatusCommandParser();
+
+    /** @see CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session )
+            throws ProtocolException, MailboxException
+    {
+        String mailboxName = parser.mailbox( request );
+        StatusDataItems statusDataItems = parser.statusDataItems( request );
+        parser.endLine( request );
+
+        ImapMailboxSession mailbox = session.getSelected().getMailbox();
+
+        StringBuffer buffer = new StringBuffer( mailboxName );
+        buffer.append( SP );
+        buffer.append( "(" );
+        try {
+            if (statusDataItems.messages) {
+                buffer.append(MESSAGES);
+                buffer.append(SP);
+
+                buffer.append(mailbox.getMessageCount());
+
+                buffer.append(SP);
+            }
+
+            if (statusDataItems.recent) {
+                buffer.append(RECENT);
+                buffer.append(SP);
+                buffer.append(mailbox.getRecentCount(false));
+                buffer.append(SP);
+            }
+
+            if (statusDataItems.uidNext) {
+                buffer.append(UIDNEXT);
+                buffer.append(SP);
+                buffer.append(mailbox.getUidNext());
+                buffer.append(SP);
+            }
+
+            if (statusDataItems.uidValidity) {
+                buffer.append(UIDVALIDITY);
+                buffer.append(SP);
+                buffer.append(mailbox.getUidValidity());
+                buffer.append(SP);
+            }
+
+            if (statusDataItems.unseen) {
+                buffer.append(UNSEEN);
+                buffer.append(SP);
+                buffer.append(mailbox.getUnseenCount());
+                buffer.append(SP);
+            }
+        } catch (MailboxManagerException e) {
+            throw new MailboxException(e);
+        }
+        if ( buffer.charAt( buffer.length() - 1 ) == ' ' ) {
+            buffer.setLength( buffer.length() - 1 );
+        }
+        buffer.append(')');
+        response.commandResponse( this, buffer.toString());
+
+        session.unsolicitedResponses( response, false );
+        response.commandComplete( this );
+    }
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+
+    private class StatusCommandParser extends CommandParser
+    {
+        StatusDataItems statusDataItems( ImapRequestLineReader request )
+                throws ProtocolException
+        {
+            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 + "'" );
+            }
+        }
+    }
+
+    private class StatusDataItems
+    {
+        boolean messages;
+        boolean recent;
+        boolean uidNext;
+        boolean uidValidity;
+        boolean unseen;
+    }
+}
+/*
+6.3.10. STATUS Command
+
+   Arguments:  mailbox name
+               status data item names
+
+   Responses:  untagged responses: STATUS
+
+   Result:     OK - status completed
+               NO - status failure: no status for that name
+               BAD - command unknown or arguments invalid
+
+      The STATUS command requests the status of the indicated mailbox.
+      It does not change the currently selected mailbox, nor does it
+      affect the state of any messages in the queried mailbox (in
+      particular, STATUS MUST NOT cause messages to lose the \Recent
+      flag).
+
+      The STATUS command provides an alternative to opening a second
+      IMAP4rev1 connection and doing an EXAMINE command on a mailbox to
+      query that mailbox's status without deselecting the current
+      mailbox in the first IMAP4rev1 connection.
+
+      Unlike the LIST command, the STATUS command is not guaranteed to
+      be fast in its response.  In some implementations, the server is
+      obliged to open the mailbox read-only internally to obtain certain
+      status information.  Also unlike the LIST command, the STATUS
+      command does not accept wildcards.
+
+      The currently defined status data items that can be requested are:
+
+      MESSAGES       The number of messages in the mailbox.
+
+      RECENT         The number of messages with the \Recent flag set.
+
+      UIDNEXT        The next UID value that will be assigned to a new
+                     message in the mailbox.  It is guaranteed that this
+                     value will not change unless new messages are added
+                     to the mailbox; and that it will change when new
+                     messages are added even if those new messages are
+                     subsequently expunged.
+
+
+
+Crispin                     Standards Track                    [Page 33]
+
+RFC 2060                       IMAP4rev1                   December 1996
+
+
+      UIDVALIDITY    The unique identifier validity value of the
+                     mailbox.
+
+      UNSEEN         The number of messages which do not have the \Seen
+                     flag set.
+
+
+      Example:    C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
+                  S: * STATUS blurdybloop (MESSAGES 231 UIDNEXT 44292)
+                  S: A042 OK STATUS completed
+
+*/

Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/StoreCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/StoreCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/StoreCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/StoreCommand.java Mon Oct  9 10:15:30 2006
@@ -0,0 +1,234 @@
+/***********************************************************************
+ * Copyright (c) 2000-2004 The Apache Software Foundation.             *
+ * All rights reserved.                                                *
+ * ------------------------------------------------------------------- *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you *
+ * may not use this file except in compliance with the License. You    *
+ * may obtain a copy of the License at:                                *
+ *                                                                     *
+ *     http://www.apache.org/licenses/LICENSE-2.0                      *
+ *                                                                     *
+ * Unless required by applicable law or agreed to in writing, software *
+ * distributed under the License is distributed on an "AS IS" BASIS,   *
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or     *
+ * implied.  See the License for the specific language governing       *
+ * permissions and limitations under the License.                      *
+ ***********************************************************************/
+
+package org.apache.james.imapserver.commands;
+
+import javax.mail.Flags;
+
+import org.apache.james.imapserver.ImapRequestLineReader;
+import org.apache.james.imapserver.ImapResponse;
+import org.apache.james.imapserver.ImapSession;
+import org.apache.james.imapserver.ProtocolException;
+import org.apache.james.imapserver.store.MailboxException;
+import org.apache.james.mailboxmanager.GeneralMessageSet;
+import org.apache.james.mailboxmanager.MailboxListener;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+
+/**
+ * Handles processeing for the STORE imap command.
+ *
+ * @author  Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class StoreCommand extends SelectedStateCommand implements UidEnabledCommand
+{
+    public static final String NAME = "STORE";
+    public static final String ARGS = "<Message-set> ['+'|'-']FLAG[.SILENT] <flag-list>";
+
+    private final StoreCommandParser parser = new StoreCommandParser();
+
+    /** @see CommandTemplate#doProcess */
+    protected void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session )
+            throws ProtocolException, MailboxException
+    {
+        doProcess( request, response, session , false );
+    }
+
+    public void doProcess( ImapRequestLineReader request,
+                              ImapResponse response,
+                              ImapSession session,
+                              boolean useUids )
+            throws ProtocolException, MailboxException
+    {
+        IdRange[] idSet = parser.parseIdRange( request );
+        StoreDirective directive = parser.storeDirective( request );
+        Flags flags = parser.flagList( request );
+        parser.endLine( request );
+
+        ImapMailboxSession mailbox = session.getSelected().getMailbox();
+        MailboxListener silentListener = null;
+
+        final boolean replace;
+        final boolean value;
+        if (directive.getSign() < 0) {
+            value=false;
+            replace=false;
+        }
+        else if (directive.getSign() > 0) {
+            value=true;
+            replace=false;
+        }
+        else {
+            replace=true;
+            value=true;
+        }
+        try {
+            if (directive.isSilent()) {
+                silentListener = session.getSelected().getMailbox();
+            }
+            for (int i = 0; i < idSet.length; i++) {
+                final GeneralMessageSet messageSet = GeneralMessageSetImpl
+                        .range(idSet[i].getLowVal(), idSet[i].getHighVal(),
+                                useUids);
+
+                mailbox.setFlags(flags, value, replace, messageSet,
+                        silentListener);
+            }
+        } catch (MailboxManagerException e) {
+            throw new MailboxException(e);
+        }
+        boolean omitExpunged = (!useUids);
+        session.unsolicitedResponses( response, omitExpunged , useUids);
+        response.commandComplete( this );
+    }
+
+
+    /** @see ImapCommand#getName */
+    public String getName()
+    {
+        return NAME;
+    }
+
+    /** @see CommandTemplate#getArgSyntax */
+    public String getArgSyntax()
+    {
+        return ARGS;
+    }
+
+    private class StoreCommandParser extends CommandParser
+    {
+        StoreDirective storeDirective( ImapRequestLineReader request ) throws ProtocolException
+        {
+            int sign = 0;
+            boolean silent = false;
+
+            char next = request.nextWordChar();
+            if ( next == '+' ) {
+                sign = 1;
+                request.consume();
+            }
+            else if ( next == '-' ) {
+                sign = -1;
+                request.consume();
+            }
+            else {
+                sign = 0;
+            }
+
+            String directive = consumeWord( request, new NoopCharValidator() );
+            if ( "FLAGS".equalsIgnoreCase( directive ) ) {
+                silent = false;
+            }
+            else if ( "FLAGS.SILENT".equalsIgnoreCase( directive ) ) {
+                silent = true;
+            }
+            else {
+                throw new ProtocolException( "Invalid Store Directive: '" + directive + "'" );
+            }
+            return new StoreDirective( sign, silent );
+        }
+    }
+
+    private class StoreDirective
+    {
+        private int sign;
+        private boolean silent;
+
+        public StoreDirective( int sign, boolean silent )
+        {
+            this.sign = sign;
+            this.silent = silent;
+        }
+
+        public int getSign()
+        {
+            return sign;
+        }
+
+        public boolean isSilent()
+        {
+            return silent;
+        }
+    }
+}
+/*
+6.4.6.  STORE Command
+
+   Arguments:  message set
+               message data item name
+               value for message data item
+
+   Responses:  untagged responses: FETCH
+
+   Result:     OK - store completed
+               NO - store error: can't store that data
+               BAD - command unknown or arguments invalid
+
+      The STORE command alters data associated with a message in the
+      mailbox.  Normally, STORE will return the updated value of the
+      data with an untagged FETCH response.  A suffix of ".SILENT" in
+      the data item name prevents the untagged FETCH, and the server
+      SHOULD assume that the client has determined the updated value
+      itself or does not care about the updated value.
+
+         Note: regardless of whether or not the ".SILENT" suffix was
+         used, the server SHOULD send an untagged FETCH response if a
+         change to a message's flags from an external source is
+         observed.  The intent is that the status of the flags is
+         determinate without a race condition.
+
+      The currently defined data items that can be stored are:
+
+      FLAGS <flag list>
+                     Replace the flags for the message with the
+                     argument.  The new value of the flags are returned
+                     as if a FETCH of those flags was done.
+
+      FLAGS.SILENT <flag list>
+                     Equivalent to FLAGS, but without returning a new
+                     value.
+
+      +FLAGS <flag list>
+                     Add the argument to the flags for the message.  The
+                     new value of the flags are returned as if a FETCH
+                     of those flags was done.
+
+      +FLAGS.SILENT <flag list>
+                     Equivalent to +FLAGS, but without returning a new
+                     value.
+
+      -FLAGS <flag list>
+                     Remove the argument from the flags for the message.
+                     The new value of the flags are returned as if a
+                     FETCH of those flags was done.
+
+      -FLAGS.SILENT <flag list>
+                     Equivalent to -FLAGS, but without returning a new
+                     value.
+
+   Example:    C: A003 STORE 2:4 +FLAGS (\Deleted)
+               S: * 2 FETCH FLAGS (\Deleted \Seen)
+               S: * 3 FETCH FLAGS (\Deleted)
+               S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
+               S: A003 OK STORE completed
+
+*/



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