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 [3/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/CopyCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/CopyCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/CopyCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/CopyCommand.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,96 @@
+/***********************************************************************
+ * 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.GeneralMessageSet;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+
+/**
+ * Handles processeing for the COPY imap command.
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class CopyCommand extends SelectedStateCommand implements UidEnabledCommand
+{
+ public static final String NAME = "COPY";
+ public static final String ARGS = "<message-set> <mailbox>";
+
+ /** @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 );
+ String mailboxName = parser.mailbox( request );
+ parser.endLine( request );
+
+ ImapMailboxSession currentMailbox = session.getSelected().getMailbox();
+
+
+ try {
+ mailboxName=session.buildFullName(mailboxName);
+ if (!session.getMailboxManager().existsMailbox(mailboxName)) {
+ MailboxException e=new MailboxException("Mailbox does not exists");
+ e.setResponseCode( "TRYCREATE" );
+ throw e;
+ }
+ for (int i = 0; i < idSet.length; i++) {
+ GeneralMessageSet messageSet=GeneralMessageSetImpl.range(idSet[i].getLowVal(),idSet[i].getHighVal(),useUids);
+ session.getMailboxManager().copyMessages(currentMailbox,messageSet,mailboxName);
+ }
+ } catch (MailboxManagerException e) {
+ throw new MailboxException(e);
+ }
+
+
+
+ session.unsolicitedResponses( response, useUids);
+ response.commandComplete( this );
+ }
+
+ /** @see ImapCommand#getName */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /** @see CommandTemplate#getArgSyntax */
+ public String getArgSyntax()
+ {
+ return ARGS;
+ }
+}
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/CreateCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/CreateCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/CreateCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/CreateCommand.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,123 @@
+/***********************************************************************
+ * 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 CREATE imap command.
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class CreateCommand extends AuthenticatedStateCommand
+{
+ public static final String NAME = "CREATE";
+ public static final String ARGS = "<mailbox>";
+
+ /** @see CommandTemplate#doProcess */
+ protected void doProcess( ImapRequestLineReader request,
+ ImapResponse response,
+ ImapSession session )
+ throws ProtocolException, MailboxException, AuthorizationException
+ {
+ String mailboxName = parser.mailbox( request );
+ parser.endLine( request );
+
+
+ try {
+
+ mailboxName=session.buildFullName(mailboxName);
+ session.getMailboxManager().createMailbox(mailboxName );
+ } 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.3. CREATE Command
+
+ Arguments: mailbox name
+
+ Responses: no specific responses for this command
+
+ Result: OK - create completed
+ NO - create failure: can't create mailbox with that name
+ BAD - command unknown or arguments invalid
+
+ The CREATE command creates a mailbox with the given name. An OK
+ response is returned only if a new mailbox with that name has been
+ created. It is an error to attempt to create INBOX or a mailbox
+ with a name that refers to an extant mailbox. Any error in
+ creation will return a tagged NO response.
+
+ If the mailbox name is suffixed with the server's hierarchy
+ separator character (as returned from the server by a LIST
+ command), this is a declaration that the client intends to create
+ mailbox names under this name in the hierarchy. Server
+ implementations that do not require this declaration MUST ignore
+ it.
+
+ If the server's hierarchy separator character appears elsewhere in
+ the name, the server SHOULD create any superior hierarchical names
+ that are needed for the CREATE command to complete successfully.
+ In other words, an attempt to create "foo/bar/zap" on a server in
+ which "/" is the hierarchy separator character SHOULD create foo/
+ and foo/bar/ if they do not already exist.
+
+ If a new mailbox is created with the same name as a mailbox which
+ was deleted, its unique identifiers MUST be greater than any
+ unique identifiers used in the previous incarnation of the mailbox
+ UNLESS the new incarnation has a different unique identifier
+ validity value. See the description of the UID command for more
+ detail.
+
+ Example: C: A003 CREATE owatagusiam/
+ S: A003 OK CREATE completed
+ C: A004 CREATE owatagusiam/blurdybloop
+ S: A004 OK CREATE completed
+
+ Note: the interpretation of this example depends on whether "/"
+ was returned as the hierarchy separator from LIST. If "/" is the
+ hierarchy separator, a new level of hierarchy named "owatagusiam"
+ with a member called "blurdybloop" is created. Otherwise, two
+ mailboxes at the same hierarchy level are created.
+*/
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/DeleteCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/DeleteCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/DeleteCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/DeleteCommand.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,151 @@
+/***********************************************************************
+ * 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;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+
+/**
+ * Handles processeing for the DELETE imap command.
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class DeleteCommand extends AuthenticatedStateCommand
+{
+ public static final String NAME = "DELETE";
+ public static final String ARGS = "<mailbox>";
+
+ /** @see CommandTemplate#doProcess */
+ protected void doProcess( ImapRequestLineReader request,
+ ImapResponse response,
+ ImapSession session )
+ throws ProtocolException, MailboxException, AuthorizationException
+ {
+
+ String mailboxName = parser.mailbox( request );
+ parser.endLine( request );
+
+ try {
+ mailboxName = session.buildFullName(mailboxName);
+ if (session.getSelected() != null) {
+ if (session.getSelected().getMailbox().getName().equals(
+ mailboxName)) {
+ session.deselect();
+ }
+ }
+ session.getMailboxManager().deleteMailbox(mailboxName);
+ } 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.4. DELETE Command
+
+ Arguments: mailbox name
+
+ Responses: no specific responses for this command
+
+ Result: OK - delete completed
+ NO - delete failure: can't delete mailbox with that name
+ BAD - command unknown or arguments invalid
+
+ The DELETE command permanently removes the mailbox with the given
+ name. A tagged OK response is returned only if the mailbox has
+ been deleted. It is an error to attempt to delete INBOX or a
+ mailbox name that does not exist.
+
+ The DELETE command MUST NOT remove inferior hierarchical names.
+ For example, if a mailbox "foo" has an inferior "foo.bar"
+ (assuming "." is the hierarchy delimiter character), removing
+ "foo" MUST NOT remove "foo.bar". It is an error to attempt to
+ delete a name that has inferior hierarchical names and also has
+ the \Noselect mailbox name attribute (see the description of the
+ LIST response for more details).
+
+ It is permitted to delete a name that has inferior hierarchical
+ names and does not have the \Noselect mailbox name attribute. In
+ this case, all messages in that mailbox are removed, and the name
+ will acquire the \Noselect mailbox name attribute.
+
+ The value of the highest-used unique identifier of the deleted
+ mailbox 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.
+
+
+ Examples: C: A682 LIST "" *
+ S: * LIST () "/" blurdybloop
+ S: * LIST (\Noselect) "/" foo
+ S: * LIST () "/" foo/bar
+ S: A682 OK LIST completed
+ C: A683 DELETE blurdybloop
+ S: A683 OK DELETE completed
+ C: A684 DELETE foo
+ S: A684 NO Name "foo" has inferior hierarchical names
+ C: A685 DELETE foo/bar
+ S: A685 OK DELETE Completed
+ C: A686 LIST "" *
+ S: * LIST (\Noselect) "/" foo
+ S: A686 OK LIST completed
+ C: A687 DELETE foo
+ S: A687 OK DELETE Completed
+
+
+ C: A82 LIST "" *
+ S: * LIST () "." blurdybloop
+ S: * LIST () "." foo
+ S: * LIST () "." foo.bar
+ S: A82 OK LIST completed
+ C: A83 DELETE blurdybloop
+ S: A83 OK DELETE completed
+ C: A84 DELETE foo
+ S: A84 OK DELETE Completed
+ C: A85 LIST "" *
+ S: * LIST () "." foo.bar
+ S: A85 OK LIST completed
+ C: A86 LIST "" %
+ S: * LIST (\Noselect) "." foo
+ S: A86 OK LIST completed
+*/
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ExamineCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ExamineCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ExamineCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ExamineCommand.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,34 @@
+/***********************************************************************
+ * 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;
+
+/**
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class ExamineCommand extends SelectCommand
+{
+ public static final String NAME = "EXAMINE";
+
+ public String getName()
+ {
+ return NAME;
+ }
+}
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ExpungeCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ExpungeCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ExpungeCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ExpungeCommand.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,105 @@
+/***********************************************************************
+ * 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.GeneralMessageSet;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.impl.GeneralMessageSetImpl;
+import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
+
+/**
+ * Handles processeing for the EXPUNGE imap command.
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class ExpungeCommand extends SelectedStateCommand
+{
+ public static final String NAME = "EXPUNGE";
+ public static final String ARGS = null;
+
+ /** @see CommandTemplate#doProcess */
+ protected void doProcess( ImapRequestLineReader request,
+ ImapResponse response,
+ ImapSession session )
+ throws ProtocolException, MailboxException
+ {
+ parser.endLine( request );
+
+ ImapMailboxSession mailbox = session.getSelected().getMailbox();
+ if (!mailbox.isWriteable()) {
+ response.commandFailed( this, "Mailbox selected read only." );
+ }
+
+ try {
+ mailbox.expunge(GeneralMessageSetImpl.all(),GeneralMessageSet.TYPE_NONE);
+ } 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.4.3. EXPUNGE Command
+
+ Arguments: none
+
+ Responses: untagged responses: EXPUNGE
+
+ Result: OK - expunge completed
+ NO - expunge failure: can't expunge (e.g. permission
+ denied)
+ BAD - command unknown or arguments invalid
+
+ The EXPUNGE command permanently removes from the currently
+ selected mailbox all messages that have the \Deleted flag set.
+ Before returning an OK to the client, an untagged EXPUNGE response
+ is sent for each message that is removed.
+
+ Example: C: A202 EXPUNGE
+ S: * 3 EXPUNGE
+ S: * 3 EXPUNGE
+ S: * 5 EXPUNGE
+ S: * 8 EXPUNGE
+ S: A202 OK EXPUNGE completed
+
+ Note: in this example, messages 3, 4, 7, and 11 had the
+ \Deleted flag set. See the description of the EXPUNGE
+ response for further explanation.
+*/
+
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/FetchCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/FetchCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/FetchCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/FetchCommand.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,946 @@
+/***********************************************************************
+ * 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 java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.mail.Flags;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.core.MimeMessageWrapper;
+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.imapserver.store.MessageFlags;
+import org.apache.james.imapserver.store.SimpleMessageAttributes;
+import org.apache.james.mailboxmanager.GeneralMessageSet;
+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;
+import org.apache.mailet.dates.RFC822DateFormat;
+
+import com.sun.mail.util.CRLFOutputStream;
+
+/**
+ * Handles processeing for the FETCH imap command.
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+class FetchCommand extends SelectedStateCommand implements UidEnabledCommand
+{
+ public static final String NAME = "FETCH";
+ public static final String ARGS = "<message-set> <fetch-profile>";
+
+ private FetchCommandParser parser = new FetchCommandParser();
+
+ /** @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 );
+ FetchRequest fetch = parser.fetchRequest( request );
+ parser.endLine( request );
+
+ if (useUids) {
+ fetch.uid = true;
+ }
+
+ // TODO only fetch needed results
+ int resultToFetch = MessageResult.FLAGS | MessageResult.MIME_MESSAGE
+ | MessageResult.INTERNAL_DATE | MessageResult.MSN
+ | MessageResult.SIZE;
+ ImapMailboxSession mailbox = session.getSelected().getMailbox();
+ for (int i = 0; i < idSet.length; i++) {
+ GeneralMessageSet messageSet=GeneralMessageSetImpl.range(idSet[i].getLowVal(),idSet[i].getHighVal(),useUids);
+ MessageResult[] result;
+ try {
+ result = mailbox.getMessages(messageSet,resultToFetch);
+ } catch (MailboxManagerException e) {
+ throw new MailboxException(e);
+ }
+ for (int j = 0; j < result.length; j++) {
+ String msgData = outputMessage( fetch, result[j], mailbox, useUids );
+ response.fetchResponse( result[j].getMsn(), msgData );
+
+ }
+ }
+
+ boolean omitExpunged = (!useUids);
+ session.unsolicitedResponses( response, omitExpunged , useUids);
+ response.commandComplete( this );
+ }
+
+ private String outputMessage(FetchRequest fetch, MessageResult result,
+ ImapMailboxSession mailbox, boolean useUids)
+ throws MailboxException, ProtocolException {
+ // Check if this fetch will cause the "SEEN" flag to be set on this
+ // message
+ // If so, update the flags, and ensure that a flags response is included
+ // in the response.
+ try {
+ boolean ensureFlagsResponse = false;
+ if (fetch.isSetSeen()
+ && !result.getFlags().contains(Flags.Flag.SEEN)) {
+ mailbox.setFlags(new Flags(Flags.Flag.SEEN), true, false,
+ GeneralMessageSetImpl.oneUid(result.getUid()), null);
+ result.getFlags().add(Flags.Flag.SEEN);
+ ensureFlagsResponse = true;
+ }
+
+ StringBuffer response = new StringBuffer();
+
+ // FLAGS response
+ if (fetch.flags || ensureFlagsResponse) {
+ response.append(" FLAGS ");
+ response.append(MessageFlags.format(result.getFlags()));
+ }
+
+ // INTERNALDATE response
+ if (fetch.internalDate) {
+ response.append(" INTERNALDATE \"");
+ // TODO format properly
+ response.append(RFC822DateFormat.toString(result
+ .getInternalDate())); // not right format
+ response.append("\"");
+
+ }
+
+ // RFC822.SIZE response
+ if (fetch.size) {
+ response.append(" RFC822.SIZE ");
+ response.append(result.getSize());
+ }
+
+ SimpleMessageAttributes attrs = new SimpleMessageAttributes(result
+ .getMimeMessage());
+
+ // ENVELOPE response
+ if (fetch.envelope) {
+ response.append(" ENVELOPE ");
+ response.append(attrs.getEnvelope());
+ }
+
+ // BODY response
+ if (fetch.body) {
+ response.append(" BODY ");
+ response.append(attrs.getBodyStructure(false));
+ }
+
+ // BODYSTRUCTURE response
+ if (fetch.bodyStructure) {
+ response.append(" BODYSTRUCTURE ");
+ response.append(attrs.getBodyStructure(true));
+ }
+
+ // UID response
+ if (fetch.uid) {
+ response.append(" UID ");
+ response.append(result.getUid());
+ }
+
+ // BODY part responses.
+ Collection elements = fetch.getBodyElements();
+ for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
+ BodyFetchElement fetchElement = (BodyFetchElement) iterator
+ .next();
+ response.append(SP);
+ response.append(fetchElement.getResponseName());
+ response.append(SP);
+
+ // Various mechanisms for returning message body.
+ String sectionSpecifier = fetchElement.getParameters();
+
+ MimeMessage mimeMessage = result.getMimeMessage();
+ try {
+ handleBodyFetch(mimeMessage, sectionSpecifier, response);
+ } catch (MessagingException e) {
+ // TODO chain exceptions
+ throw new MailboxException(e.getMessage());
+ }
+ }
+
+ if (response.length() > 0) {
+ // Remove the leading " ".
+ return response.substring(1);
+ } else {
+ return "";
+ }
+ } catch (MailboxManagerException mme) {
+ throw new MailboxException(mme);
+ } catch (MessagingException me) {
+ throw new MailboxException(me);
+ }
+ }
+
+
+ private void handleBodyFetch( MimeMessage mimeMessage,
+ String sectionSpecifier,
+ StringBuffer response )
+ throws ProtocolException, MessagingException
+ {
+ if ( sectionSpecifier.length() == 0 ) {
+ // TODO - need to use an InputStream from the response here.
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ try {
+ mimeMessage.writeTo(new CRLFOutputStream(bout));
+ }
+ catch ( IOException e ) {
+ throw new ProtocolException( "Error reading message source" );
+ }
+ byte[] bytes = bout.toByteArray();
+ addLiteral( bytes, response );
+ // TODO JD maybe we've to add CRLF here
+
+ }
+ else if ( sectionSpecifier.equalsIgnoreCase( "HEADER" ) ) {
+ Enumeration enum = mimeMessage.getAllHeaderLines();
+ addHeaders( enum, response );
+ }
+ else if ( sectionSpecifier.startsWith( "HEADER.FIELDS.NOT " ) ) {
+ String[] excludeNames = extractHeaderList( sectionSpecifier, "HEADER.FIELDS.NOT ".length() );
+ Enumeration enum = mimeMessage.getNonMatchingHeaderLines( excludeNames );
+ addHeaders( enum, response );
+ }
+ else if ( sectionSpecifier.startsWith( "HEADER.FIELDS " ) ) {
+ String[] includeNames = extractHeaderList( sectionSpecifier, "HEADER.FIELDS ".length() );
+ Enumeration enum = mimeMessage.getMatchingHeaderLines( includeNames );
+ addHeaders( enum, response );
+ }
+ else if ( sectionSpecifier.equalsIgnoreCase( "MIME" ) ) {
+ // TODO implement
+ throw new ProtocolException( "MIME not yet implemented." );
+ }
+ else if ( sectionSpecifier.equalsIgnoreCase( "TEXT" ) ) {
+ // TODO - need to use an InputStream from the response here.
+ // TODO - this is a hack. To get just the body content, I'm using a null
+ // input stream to take the headers. Need to have a way of ignoring headers.
+ ByteArrayOutputStream headerOut = new ByteArrayOutputStream();
+ ByteArrayOutputStream bodyOut = new ByteArrayOutputStream();
+ try {
+ // TODO James Trunk : Is this okay?
+ MimeMessageWrapper mmw=new MimeMessageWrapper(mimeMessage);
+
+ mmw.writeTo(headerOut, bodyOut );
+ byte[] bytes = bodyOut.toByteArray();
+
+ addLiteral( bytes, response );
+
+ }
+ catch ( IOException e ) {
+ throw new ProtocolException( "Error reading message source" );
+ }
+ }
+ else {
+ // Should be a part specifier followed by a section specifier.
+ // See if there's a leading part specifier.
+ // If so, get the number, get the part, and call this recursively.
+ int dotPos = sectionSpecifier.indexOf( '.' );
+ if ( dotPos == -1 ) {
+ throw new ProtocolException( "Malformed fetch attribute: " + sectionSpecifier );
+ }
+ int partNumber = Integer.parseInt( sectionSpecifier.substring( 0, dotPos ) );
+ String partSectionSpecifier = sectionSpecifier.substring( dotPos + 1 );
+
+ // TODO - get the MimePart of the mimeMessage, and call this method
+ // with the new partSectionSpecifier.
+// MimeMessage part;
+// handleBodyFetch( part, partSectionSpecifier, response );
+ throw new ProtocolException( "Mime parts not yet implemented for fetch." );
+ }
+
+ }
+
+ private void addLiteral( byte[] bytes, StringBuffer response )
+ {
+ response.append('{' );
+ response.append( bytes.length ); // TODO JD addLiteral: why was it bytes.length +1 here?
+ response.append( '}' );
+ response.append( "\r\n" );
+
+ for ( int i = 0; i < bytes.length; i++ ) {
+ byte b = bytes[i];
+ response.append((char)b);
+ }
+ }
+
+ // TODO should do this at parse time.
+ private String[] extractHeaderList( String headerList, int prefixLen )
+ {
+ // Remove the trailing and leading ')('
+ String tmp = headerList.substring( prefixLen + 1, headerList.length() - 1 );
+ String[] headerNames = split( tmp, " " );
+ return headerNames;
+ }
+
+ private String[] split(String value, String delimiter) {
+ ArrayList strings = new ArrayList();
+ int startPos = 0;
+ int delimPos;
+ while ( (delimPos = value.indexOf(delimiter, startPos) ) != -1) {
+ String sub = value.substring(startPos, delimPos);
+ strings.add(sub);
+ startPos = delimPos + 1;
+ }
+ String sub = value.substring(startPos);
+ strings.add(sub);
+
+ return (String[]) strings.toArray(new String[0]);
+ }
+
+ private void addHeaders( Enumeration enum, StringBuffer response )
+ {
+ List lines = new ArrayList();
+ int count = 0;
+ while (enum.hasMoreElements()) {
+ String line = (String)enum.nextElement();
+ count += line.length() + 2;
+ lines.add(line);
+ }
+ response.append( '{' );
+ response.append( count + 2 );
+ response.append( '}' );
+ response.append("\r\n");
+
+ Iterator lit = lines.iterator();
+ while (lit.hasNext()) {
+ String line = (String)lit.next();
+ response.append( line );
+ response.append( "\r\n" );
+ }
+ response.append("\r\n");
+ }
+
+ /** @see ImapCommand#getName */
+ public String getName()
+ {
+ return NAME;
+ }
+
+ /** @see CommandTemplate#getArgSyntax */
+ public String getArgSyntax()
+ {
+ return ARGS;
+ }
+
+ private class FetchCommandParser extends CommandParser
+ {
+
+
+ public FetchRequest fetchRequest( ImapRequestLineReader request )
+ throws ProtocolException
+ {
+ FetchRequest fetch = new FetchRequest();
+
+ char next = nextNonSpaceChar( request );
+ consumeChar( request, '(' );
+
+ next = nextNonSpaceChar( request );
+ while ( next != ')' ) {
+ addNextElement( request, fetch );
+ next = nextNonSpaceChar( request );
+ }
+
+ consumeChar(request, ')');
+
+ return fetch;
+ }
+
+ private void addNextElement( ImapRequestLineReader command, FetchRequest fetch)
+ throws ProtocolException
+ {
+ char next = nextCharInLine( command );
+ StringBuffer element = new StringBuffer();
+ while ( next != ' ' && next != '[' && next != ')' ) {
+ element.append(next);
+ command.consume();
+ next = nextCharInLine( command );
+ }
+ String name = element.toString();
+ // Simple elements with no '[]' parameters.
+ if ( next == ' ' || next == ')' ) {
+ if ( "FAST".equalsIgnoreCase( name ) ) {
+ fetch.flags = true;
+ fetch.internalDate = true;
+ fetch.size = true;
+ } else if ("FULL".equalsIgnoreCase(name)) {
+ fetch.flags = true;
+ fetch.internalDate = true;
+ fetch.size = true;
+ fetch.envelope = true;
+ fetch.body = true;
+ } else if ("ALL".equalsIgnoreCase(name)) {
+ fetch.flags = true;
+ fetch.internalDate = true;
+ fetch.size = true;
+ fetch.envelope = true;
+ } else if ("FLAGS".equalsIgnoreCase(name)) {
+ fetch.flags = true;
+ } else if ("RFC822.SIZE".equalsIgnoreCase(name)) {
+ fetch.size = true;
+ } else if ("ENVELOPE".equalsIgnoreCase(name)) {
+ fetch.envelope = true;
+ } else if ("INTERNALDATE".equalsIgnoreCase(name)) {
+ fetch.internalDate = true;
+ } else if ("BODY".equalsIgnoreCase(name)) {
+ fetch.body = true;
+ } else if ("BODYSTRUCTURE".equalsIgnoreCase(name)) {
+ fetch.bodyStructure = true;
+ } else if ("UID".equalsIgnoreCase(name)) {
+ fetch.uid = true;
+ } else if ("RFC822".equalsIgnoreCase(name)) {
+ fetch.add(new BodyFetchElement("RFC822", ""), false);
+ } else if ("RFC822.HEADER".equalsIgnoreCase(name)) {
+ fetch.add(new BodyFetchElement("RFC822.HEADER", "HEADER"), true);
+ } else if ("RFC822.TEXT".equalsIgnoreCase(name)) {
+ fetch.add(new BodyFetchElement("RFC822.TEXT", "TEXT"), false);
+ } else {
+ throw new ProtocolException( "Invalid fetch attribute: " + name );
+ }
+ }
+ else {
+ consumeChar( command, '[' );
+
+ StringBuffer sectionIdentifier = new StringBuffer();
+ next = nextCharInLine( command );
+ while ( next != ']' ) {
+ sectionIdentifier.append( next );
+ command.consume();
+ next = nextCharInLine(command);
+ }
+ consumeChar( command, ']' );
+
+ String parameter = sectionIdentifier.toString();
+
+ if ( "BODY".equalsIgnoreCase( name ) ) {
+ fetch.add(new BodyFetchElement("BODY[" + parameter + "]", parameter), false);
+ } else if ( "BODY.PEEK".equalsIgnoreCase( name ) ) {
+ fetch.add(new BodyFetchElement("BODY[" + parameter + "]", parameter), true);
+ } else {
+ throw new ProtocolException( "Invalid fetch attibute: " + name + "[]" );
+ }
+ }
+ }
+
+ private char nextCharInLine( ImapRequestLineReader request )
+ throws ProtocolException
+ {
+ char next = request.nextChar();
+ if ( next == '\r' || next == '\n' ) {
+ throw new ProtocolException( "Unexpected end of line." );
+ }
+ return next;
+ }
+
+ private char nextNonSpaceChar( ImapRequestLineReader request )
+ throws ProtocolException
+ {
+ char next = request.nextChar();
+ while ( next == ' ' ) {
+ request.consume();
+ next = request.nextChar();
+ }
+ return next;
+ }
+
+ }
+
+ private static class FetchRequest
+ {
+ boolean flags;
+ boolean uid;
+ boolean internalDate;
+ boolean size;
+ boolean envelope;
+ boolean body;
+ boolean bodyStructure;
+
+ private boolean setSeen = false;
+
+ private Set bodyElements = new HashSet();
+
+ public Collection getBodyElements() {
+ return bodyElements;
+ }
+
+ public boolean isSetSeen() {
+ return setSeen;
+ }
+
+ public void add( BodyFetchElement element, boolean peek )
+ {
+ if (!peek) {
+ setSeen = true;
+ }
+ bodyElements.add(element);
+ }
+ }
+
+ private class BodyFetchElement
+ {
+ private String name;
+ private String sectionIdentifier;
+
+ public BodyFetchElement( String name, String sectionIdentifier)
+ {
+ this.name = name;
+ this.sectionIdentifier = sectionIdentifier;
+ }
+
+ public String getParameters()
+ {
+ return this.sectionIdentifier;
+ }
+
+ public String getResponseName() {
+ return this.name;
+ }
+ }
+
+}
+/*
+6.4.5. FETCH Command
+
+ Arguments: message set
+ message data item names
+
+ Responses: untagged responses: FETCH
+
+ Result: OK - fetch completed
+ NO - fetch error: can't fetch that data
+ BAD - command unknown or arguments invalid
+
+ The FETCH command retrieves data associated with a message in the
+ mailbox. The data items to be fetched can be either a single atom
+ or a parenthesized list.
+
+ The currently defined data items that can be fetched are:
+
+ ALL Macro equivalent to: (FLAGS INTERNALDATE
+ RFC822.SIZE ENVELOPE)
+
+ BODY Non-extensible form of BODYSTRUCTURE.
+
+ BODY[<section>]<<partial>>
+ The text of a particular body section. The section
+ specification is a set of zero or more part
+ specifiers delimited by periods. A part specifier
+ is either a part number or one of the following:
+ HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, and
+ TEXT. An empty section specification refers to the
+ entire message, including the header.
+
+ Every message has at least one part number.
+ Non-[MIME-IMB] messages, and non-multipart
+ [MIME-IMB] messages with no encapsulated message,
+ only have a part 1.
+
+ Multipart messages are assigned consecutive part
+ numbers, as they occur in the message. If a
+ particular part is of type message or multipart,
+ its parts MUST be indicated by a period followed by
+ the part number within that nested multipart part.
+
+ A part of type MESSAGE/RFC822 also has nested part
+ numbers, referring to parts of the MESSAGE part's
+ body.
+
+ The HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, and
+ TEXT part specifiers can be the sole part specifier
+ or can be prefixed by one or more numeric part
+ specifiers, provided that the numeric part
+ specifier refers to a part of type MESSAGE/RFC822.
+ The MIME part specifier MUST be prefixed by one or
+ more numeric part specifiers.
+
+ The HEADER, HEADER.FIELDS, and HEADER.FIELDS.NOT
+ part specifiers refer to the [RFC-822] header of
+ the message or of an encapsulated [MIME-IMT]
+ MESSAGE/RFC822 message. HEADER.FIELDS and
+ HEADER.FIELDS.NOT are followed by a list of
+ field-name (as defined in [RFC-822]) names, and
+ return a subset of the header. The subset returned
+ by HEADER.FIELDS contains only those header fields
+ with a field-name that matches one of the names in
+ the list; similarly, the subset returned by
+ HEADER.FIELDS.NOT contains only the header fields
+ with a non-matching field-name. The field-matching
+ is case-insensitive but otherwise exact. In all
+ cases, the delimiting blank line between the header
+ and the body is always included.
+
+ The MIME part specifier refers to the [MIME-IMB]
+ header for this part.
+
+ The TEXT part specifier refers to the text body of
+ the message, omitting the [RFC-822] header.
+
+
+ Here is an example of a complex message
+ with some of its part specifiers:
+
+ HEADER ([RFC-822] header of the message)
+ TEXT MULTIPART/MIXED
+ 1 TEXT/PLAIN
+ 2 APPLICATION/OCTET-STREAM
+ 3 MESSAGE/RFC822
+ 3.HEADER ([RFC-822] header of the message)
+ 3.TEXT ([RFC-822] text body of the message)
+ 3.1 TEXT/PLAIN
+ 3.2 APPLICATION/OCTET-STREAM
+ 4 MULTIPART/MIXED
+ 4.1 IMAGE/GIF
+ 4.1.MIME ([MIME-IMB] header for the IMAGE/GIF)
+ 4.2 MESSAGE/RFC822
+ 4.2.HEADER ([RFC-822] header of the message)
+ 4.2.TEXT ([RFC-822] text body of the message)
+ 4.2.1 TEXT/PLAIN
+ 4.2.2 MULTIPART/ALTERNATIVE
+ 4.2.2.1 TEXT/PLAIN
+ 4.2.2.2 TEXT/RICHTEXT
+
+
+ It is possible to fetch a substring of the
+ designated text. This is done by appending an open
+ angle bracket ("<"), the octet position of the
+ first desired octet, a period, the maximum number
+ of octets desired, and a close angle bracket (">")
+ to the part specifier. If the starting octet is
+ beyond the end of the text, an empty string is
+ returned.
+
+ Any partial fetch that attempts to read beyond the
+ end of the text is truncated as appropriate. A
+ partial fetch that starts at octet 0 is returned as
+ a partial fetch, even if this truncation happened.
+
+ Note: this means that BODY[]<0.2048> of a
+ 1500-octet message will return BODY[]<0>
+ with a literal of size 1500, not BODY[].
+
+ Note: a substring fetch of a
+ HEADER.FIELDS or HEADER.FIELDS.NOT part
+ specifier is calculated after subsetting
+ the header.
+
+
+ The \Seen flag is implicitly set; if this causes
+ the flags to change they SHOULD be included as part
+ of the FETCH responses.
+
+ BODY.PEEK[<section>]<<partial>>
+ An alternate form of BODY[<section>] that does not
+ implicitly set the \Seen flag.
+
+ BODYSTRUCTURE The [MIME-IMB] body structure of the message. This
+ is computed by the server by parsing the [MIME-IMB]
+ header fields in the [RFC-822] header and
+ [MIME-IMB] headers.
+
+ ENVELOPE The envelope structure of the message. This is
+ computed by the server by parsing the [RFC-822]
+ header into the component parts, defaulting various
+ fields as necessary.
+
+ FAST Macro equivalent to: (FLAGS INTERNALDATE
+ RFC822.SIZE)
+
+ FLAGS The flags that are set for this message.
+
+ FULL Macro equivalent to: (FLAGS INTERNALDATE
+ RFC822.SIZE ENVELOPE BODY)
+
+ INTERNALDATE The internal date of the message.
+
+ RFC822 Functionally equivalent to BODY[], differing in the
+ syntax of the resulting untagged FETCH data (RFC822
+ is returned).
+
+ RFC822.HEADER Functionally equivalent to BODY.PEEK[HEADER],
+ differing in the syntax of the resulting untagged
+ FETCH data (RFC822.HEADER is returned).
+
+ RFC822.SIZE The [RFC-822] size of the message.
+
+ RFC822.TEXT Functionally equivalent to BODY[TEXT], differing in
+ the syntax of the resulting untagged FETCH data
+ (RFC822.TEXT is returned).
+
+ UID The unique identifier for the message.
+
+ Example: C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
+ S: * 2 FETCH ....
+ S: * 3 FETCH ....
+ S: * 4 FETCH ....
+ S: A654 OK FETCH completed
+
+
+7.4.2. FETCH Response
+
+ Contents: message data
+
+ The FETCH response returns data about a message to the client.
+ The data are pairs of data item names and their values in
+ parentheses. This response occurs as the result of a FETCH or
+ STORE command, as well as by unilateral server decision (e.g. flag
+ updates).
+
+ The current data items are:
+
+ BODY A form of BODYSTRUCTURE without extension data.
+
+ BODY[<section>]<<origin_octet>>
+ A string expressing the body contents of the
+ specified section. The string SHOULD be
+ interpreted by the client according to the content
+ transfer encoding, body type, and subtype.
+
+ If the origin octet is specified, this string is a
+ substring of the entire body contents, starting at
+ that origin octet. This means that BODY[]<0> MAY
+ be truncated, but BODY[] is NEVER truncated.
+
+ 8-bit textual data is permitted if a [CHARSET]
+ identifier is part of the body parameter
+ parenthesized list for this section. Note that
+ headers (part specifiers HEADER or MIME, or the
+ header portion of a MESSAGE/RFC822 part), MUST be
+ 7-bit; 8-bit characters are not permitted in
+ headers. Note also that the blank line at the end
+ of the header is always included in header data.
+
+ Non-textual data such as binary data MUST be
+ transfer encoded into a textual form such as BASE64
+ prior to being sent to the client. To derive the
+ original binary data, the client MUST decode the
+ transfer encoded string.
+
+ BODYSTRUCTURE A parenthesized list that describes the [MIME-IMB]
+ body structure of a message. This is computed by
+ the server by parsing the [MIME-IMB] header fields,
+ defaulting various fields as necessary.
+
+ For example, a simple text message of 48 lines and
+ 2279 octets can have a body structure of: ("TEXT"
+ "PLAIN" ("CHARSET" "US-ASCII") NIL NIL "7BIT" 2279
+ 48)
+
+ Multiple parts are indicated by parenthesis
+ nesting. Instead of a body type as the first
+ element of the parenthesized list there is a nested
+ body. The second element of the parenthesized list
+ is the multipart subtype (mixed, digest, parallel,
+ alternative, etc.).
+
+ For example, a two part message consisting of a
+ text and a BASE645-encoded text attachment can have
+ a body structure of: (("TEXT" "PLAIN" ("CHARSET"
+ "US-ASCII") NIL NIL "7BIT" 1152 23)("TEXT" "PLAIN"
+ ("CHARSET" "US-ASCII" "NAME" "cc.diff")
+ "<96...@cac.washington.edu>"
+ "Compiler diff" "BASE64" 4554 73) "MIXED"))
+
+ Extension data follows the multipart subtype.
+ Extension data is never returned with the BODY
+ fetch, but can be returned with a BODYSTRUCTURE
+ fetch. Extension data, if present, MUST be in the
+ defined order.
+
+ The extension data of a multipart body part are in
+ the following order:
+
+ body parameter parenthesized list
+ A parenthesized list of attribute/value pairs
+ [e.g. ("foo" "bar" "baz" "rag") where "bar" is
+ the value of "foo" and "rag" is the value of
+ "baz"] as defined in [MIME-IMB].
+
+ body disposition
+ A parenthesized list, consisting of a
+ disposition type string followed by a
+ parenthesized list of disposition
+ attribute/value pairs. The disposition type and
+ attribute names will be defined in a future
+ standards-track revision to [DISPOSITION].
+
+ body language
+ A string or parenthesized list giving the body
+ language value as defined in [LANGUAGE-TAGS].
+
+ Any following extension data are not yet defined in
+ this version of the protocol. Such extension data
+ can consist of zero or more NILs, strings, numbers,
+ or potentially nested parenthesized lists of such
+ data. Client implementations that do a
+ BODYSTRUCTURE fetch MUST be prepared to accept such
+ extension data. Server implementations MUST NOT
+ send such extension data until it has been defined
+ by a revision of this protocol.
+
+ The basic fields of a non-multipart body part are
+ in the following order:
+
+ body type
+ A string giving the content media type name as
+ defined in [MIME-IMB].
+
+ body subtype
+ A string giving the content subtype name as
+ defined in [MIME-IMB].
+
+ body parameter parenthesized list
+ A parenthesized list of attribute/value pairs
+ [e.g. ("foo" "bar" "baz" "rag") where "bar" is
+ the value of "foo" and "rag" is the value of
+ "baz"] as defined in [MIME-IMB].
+
+ body id
+ A string giving the content id as defined in
+ [MIME-IMB].
+
+ body description
+ A string giving the content description as
+ defined in [MIME-IMB].
+
+ body encoding
+ A string giving the content transfer encoding as
+ defined in [MIME-IMB].
+
+ body size
+ A number giving the size of the body in octets.
+ Note that this size is the size in its transfer
+ encoding and not the resulting size after any
+ decoding.
+
+ A body type of type MESSAGE and subtype RFC822
+ contains, immediately after the basic fields, the
+ envelope structure, body structure, and size in
+ text lines of the encapsulated message.
+
+ A body type of type TEXT contains, immediately
+ after the basic fields, the size of the body in
+ text lines. Note that this size is the size in its
+ content transfer encoding and not the resulting
+ size after any decoding.
+
+ Extension data follows the basic fields and the
+ type-specific fields listed above. Extension data
+ is never returned with the BODY fetch, but can be
+ returned with a BODYSTRUCTURE fetch. Extension
+ data, if present, MUST be in the defined order.
+
+ The extension data of a non-multipart body part are
+ in the following order:
+
+ body MD5
+ A string giving the body MD5 value as defined in
+ [MD5].
+
+ body disposition
+ A parenthesized list with the same content and
+ function as the body disposition for a multipart
+ body part.
+
+ body language
+ A string or parenthesized list giving the body
+ language value as defined in [LANGUAGE-TAGS].
+
+ Any following extension data are not yet defined in
+ this version of the protocol, and would be as
+ described above under multipart extension data.
+
+ ENVELOPE A parenthesized list that describes the envelope
+ structure of a message. This is computed by the
+ server by parsing the [RFC-822] header into the
+ component parts, defaulting various fields as
+ necessary.
+
+ The fields of the envelope structure are in the
+ following order: date, subject, from, sender,
+ reply-to, to, cc, bcc, in-reply-to, and message-id.
+ The date, subject, in-reply-to, and message-id
+ fields are strings. The from, sender, reply-to,
+ to, cc, and bcc fields are parenthesized lists of
+ address structures.
+
+ An address structure is a parenthesized list that
+ describes an electronic mail address. The fields
+ of an address structure are in the following order:
+ personal name, [SMTP] at-domain-list (source
+ route), mailbox name, and host name.
+
+ [RFC-822] group syntax is indicated by a special
+ form of address structure in which the host name
+ field is NIL. If the mailbox name field is also
+ NIL, this is an end of group marker (semi-colon in
+ RFC 822 syntax). If the mailbox name field is
+ non-NIL, this is a start of group marker, and the
+ mailbox name field holds the group name phrase.
+
+ Any field of an envelope or address structure that
+ is not applicable is presented as NIL. Note that
+ the server MUST default the reply-to and sender
+ fields from the from field; a client is not
+ expected to know to do this.
+
+ FLAGS A parenthesized list of flags that are set for this
+ message.
+
+ INTERNALDATE A string representing the internal date of the
+ message.
+
+ RFC822 Equivalent to BODY[].
+
+ RFC822.HEADER Equivalent to BODY.PEEK[HEADER].
+
+ RFC822.SIZE A number expressing the [RFC-822] size of the
+ message.
+
+ RFC822.TEXT Equivalent to BODY[TEXT].
+
+ UID A number expressing the unique identifier of the
+ message.
+
+
+ Example: S: * 23 FETCH (FLAGS (\Seen) RFC822.SIZE 44827)
+
+*/
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/IdRange.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/IdRange.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/IdRange.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/IdRange.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 UID values.
+ */
+public class IdRange {
+
+ private long _lowVal;
+ private long _highVal;
+
+ public IdRange(long singleVal) {
+ _lowVal = singleVal;
+ _highVal = singleVal;
+ }
+
+ public IdRange(long lowVal, long highVal) {
+ _lowVal = lowVal;
+ _highVal = highVal;
+ }
+
+ public long getLowVal() {
+ return _lowVal;
+ }
+
+ public long getHighVal() {
+ return _highVal;
+ }
+
+ public boolean includes(long uid) {
+ return _lowVal <= uid && uid <= _highVal;
+ }
+
+}
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/IdSet.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/IdSet.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/IdSet.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/IdSet.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,29 @@
+/***********************************************************************
+ * 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;
+
+/**
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+public interface IdSet
+{
+ boolean includes( long value );
+}
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ImapCommand.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ImapCommand.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ImapCommand.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ImapCommand.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,58 @@
+/***********************************************************************
+ * 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.ImapSessionState;
+
+/**
+ * Represents a processor for a particular Imap command. Implementations of this
+ * interface should encpasulate all command specific processing.
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+public interface ImapCommand
+{
+ /**
+ * @return the name of the command, as specified in rfc2060.
+ */
+ String getName();
+
+ /**
+ * Specifies if this command is valid for the given session state.
+ * @param state The current {@link org.apache.james.imapserver.ImapSessionState state} of the {@link org.apache.james.imapserver.ImapSession}
+ * @return <code>true</code> if the command is valid in this state.
+ */
+ boolean validForState( ImapSessionState state );
+
+ /**
+ * Performs all processing of the current Imap request. Reads command
+ * arguments from the request, performs processing, and writes responses
+ * back to the request object, which are sent to the client.
+ * @param request The current client request
+ * @param response The current server response
+ * @param session The current session
+ */
+ void process( ImapRequestLineReader request,
+ ImapResponse response,
+ ImapSession session );
+}
Added: james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ImapCommandFactory.java
URL: http://svn.apache.org/viewvc/james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ImapCommandFactory.java?view=auto&rev=454432
==============================================================================
--- james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ImapCommandFactory.java (added)
+++ james/server/sandbox/imap-integration/src/java/org/apache/james/imapserver/commands/ImapCommandFactory.java Mon Oct 9 10:15:30 2006
@@ -0,0 +1,121 @@
+/***********************************************************************
+ * 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 java.util.HashMap;
+import java.util.Map;
+
+import org.apache.avalon.framework.CascadingRuntimeException;
+import org.apache.avalon.framework.logger.AbstractLogEnabled;
+import org.apache.avalon.framework.logger.LogEnabled;
+
+/**
+ * A factory for ImapCommand instances, provided based on the command name.
+ * Command instances are created on demand, when first accessed.
+ *
+ * @author Darrell DeBoer <da...@apache.org>
+ *
+ * @version $Revision: 109034 $
+ */
+public class ImapCommandFactory
+ extends AbstractLogEnabled
+{
+ private Map _imapCommands;
+
+ public ImapCommandFactory()
+ {
+ _imapCommands = new HashMap();
+
+ // Commands valid in any state
+ // CAPABILITY, NOOP, and LOGOUT
+ _imapCommands.put( CapabilityCommand.NAME, CapabilityCommand.class );
+ _imapCommands.put( NoopCommand.NAME, NoopCommand.class );
+ _imapCommands.put( LogoutCommand.NAME, LogoutCommand.class );
+
+ // Commands valid in NON_AUTHENTICATED state.
+ // AUTHENTICATE and LOGIN
+ _imapCommands.put( AuthenticateCommand.NAME, AuthenticateCommand.class );
+ _imapCommands.put( LoginCommand.NAME, LoginCommand.class );
+
+ // Commands valid in AUTHENTICATED or SELECTED state.
+ // RFC2060: SELECT, EXAMINE, CREATE, DELETE, RENAME, SUBSCRIBE, UNSUBSCRIBE, LIST, LSUB, STATUS, and APPEND
+ _imapCommands.put( SelectCommand.NAME, SelectCommand.class );
+ _imapCommands.put( ExamineCommand.NAME, ExamineCommand.class );
+ _imapCommands.put( CreateCommand.NAME, CreateCommand.class );
+ _imapCommands.put( DeleteCommand.NAME, DeleteCommand.class );
+ _imapCommands.put( RenameCommand.NAME, RenameCommand.class );
+ _imapCommands.put( SubscribeCommand.NAME, SubscribeCommand.class );
+ _imapCommands.put( UnsubscribeCommand.NAME, UnsubscribeCommand.class );
+ _imapCommands.put( ListCommand.NAME, ListCommand.class );
+ _imapCommands.put( LsubCommand.NAME, LsubCommand.class );
+ _imapCommands.put( StatusCommand.NAME, StatusCommand.class );
+ _imapCommands.put( AppendCommand.NAME, AppendCommand.class );
+
+// // RFC2342 NAMESPACE
+// _imapCommands.put( "NAMESPACE", NamespaceCommand.class );
+
+ // RFC2086 GETACL, SETACL, DELETEACL, LISTRIGHTS, MYRIGHTS
+// _imapCommands.put( "GETACL", GetAclCommand.class );
+// _imapCommands.put( "SETACL", SetAclCommand.class );
+// _imapCommands.put( "DELETEACL", DeleteAclCommand.class );
+// _imapCommands.put( "LISTRIGHTS", ListRightsCommand.class );
+// _imapCommands.put( "MYRIGHTS", MyRightsCommand.class );
+
+
+ // Commands only valid in SELECTED state.
+ // CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, and UID
+ _imapCommands.put( CheckCommand.NAME, CheckCommand.class );
+ _imapCommands.put( CloseCommand.NAME, CloseCommand.class );
+ _imapCommands.put( ExpungeCommand.NAME, ExpungeCommand.class );
+ _imapCommands.put( CopyCommand.NAME, CopyCommand.class );
+ _imapCommands.put( SearchCommand.NAME, SearchCommand.class );
+ _imapCommands.put( FetchCommand.NAME, FetchCommand.class );
+ _imapCommands.put( StoreCommand.NAME, StoreCommand.class );
+ _imapCommands.put( UidCommand.NAME, UidCommand.class );
+ }
+
+ public ImapCommand getCommand( String commandName )
+ {
+ Class cmdClass = ( Class ) _imapCommands.get( commandName.toUpperCase() );
+
+ if ( cmdClass == null ) {
+ return null;
+ }
+ else {
+ return createCommand( cmdClass );
+ }
+ }
+
+ private ImapCommand createCommand( Class commandClass )
+ {
+ try {
+ ImapCommand cmd = ( ImapCommand ) commandClass.newInstance();
+ if ( cmd instanceof LogEnabled ) {
+ ( ( LogEnabled ) cmd ).enableLogging( getLogger() );
+ }
+ if ( cmd instanceof UidCommand ) {
+ ( ( UidCommand) cmd ).setCommandFactory( this );
+ }
+ return cmd;
+ }
+ catch ( Exception e ) {
+ throw new CascadingRuntimeException( "Could not create command instance: " + commandClass.getName(), e );
+ }
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org