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 rd...@apache.org on 2008/07/16 23:34:17 UTC

svn commit: r677437 [1/3] - in /james/server/trunk: experimental-seda-imap-function/src/main/java/org/apache/james/experimental/imapserver/encode/writer/ experimental-seda-imap-function/src/test/java/org/apache/james/test/functional/imap/ experimental-...

Author: rdonkin
Date: Wed Jul 16 14:34:15 2008
New Revision: 677437

URL: http://svn.apache.org/viewvc?rev=677437&view=rev
Log:
Switch to using Mime4j for BODYSTRUCTURE parsing. Remove incompatible tests for old IMAP implementation. Still need to test recursive MIME.

Added:
    james/server/trunk/experimental-seda-imap-function/src/test/java/org/apache/james/test/functional/imap/AbstractTestFetchBodyStructure.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/AddressImpl.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/ContentBodyElement.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeBuilder.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeImpl.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/FetchProcessor.java
      - copied, changed from r659754, james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/FetchProcessor.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/FetchResponseBuilder.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/HeaderBodyElement.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/MimeDescriptorStructure.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/MimePathImpl.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/PartialFetchBodyElement.java
      - copied, changed from r659754, james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/PartialFetchBodyElement.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/PartialWritableByteChannel.java
      - copied, changed from r659754, james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/PartialWritableByteChannel.java
    james/server/trunk/imap-mailbox-processor-function/src/test/java/org/apache/james/imapserver/processor/imap4rev1/fetch/
    james/server/trunk/imap-mailbox-processor-function/src/test/java/org/apache/james/imapserver/processor/imap4rev1/fetch/PartialFetchBodyElementTest.java
      - copied, changed from r659754, james/server/trunk/imap-mailbox-processor-function/src/test/java/org/apache/james/imapserver/processor/imap4rev1/PartialFetchBodyElementTest.java
    james/server/trunk/imap-mailbox-processor-function/src/test/java/org/apache/james/imapserver/processor/imap4rev1/fetch/PartialWritableByteChannelTest.java
      - copied, changed from r659754, james/server/trunk/imap-mailbox-processor-function/src/test/java/org/apache/james/imapserver/processor/imap4rev1/PartialWritableByteChannelTest.java
    james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/store/
    james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/store/MailboxException.java
      - copied unchanged from r659754, james/server/trunk/imapmailbox-library/src/main/java/org/apache/james/imapserver/store/MailboxException.java
    james/server/trunk/mailbox-library/src/main/java/org/apache/james/mailboxmanager/Headers.java
    james/server/trunk/mailet-function/   (with props)
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/experimental/imapserver/ExperimentalFetchBodyStructureTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/mailboxmanager/torque/TorqueMailboxTestCase.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/MimeDescriptorImpl.java
Removed:
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/FetchProcessor.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/PartialFetchBodyElement.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/PartialWritableByteChannel.java
    james/server/trunk/imap-mailbox-processor-function/src/test/java/org/apache/james/imapserver/processor/imap4rev1/PartialFetchBodyElementTest.java
    james/server/trunk/imap-mailbox-processor-function/src/test/java/org/apache/james/imapserver/processor/imap4rev1/PartialWritableByteChannelTest.java
    james/server/trunk/imapmailbox-library/build.xml
    james/server/trunk/imapmailbox-library/src/main/java/org/apache/james/imapserver/store/ImapMessageAttributes.java
    james/server/trunk/imapmailbox-library/src/main/java/org/apache/james/imapserver/store/MailboxException.java
    james/server/trunk/imapmailbox-library/src/main/java/org/apache/james/imapserver/store/SimpleMessageAttributes.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/AbstractSessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/BodyFetchSessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/CopySessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/CreateSessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/DeleteSessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/ExpungeSessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/RenameSessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/SessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/StatusSessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/UidFlagSizeFetchSessionTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/imapserver/handler/session/UidStoreSessionTest.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMimeMessage.java
Modified:
    james/server/trunk/experimental-seda-imap-function/src/main/java/org/apache/james/experimental/imapserver/encode/writer/ChannelImapResponseWriter.java
    james/server/trunk/experimental-seda-imap-function/src/test/resources/org/apache/james/test/functional/imap/scripts/FetchSimpleBodyStructure.test
    james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/ImapConstants.java
    james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imap/message/response/imap4rev1/FetchResponse.java
    james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseComposer.java
    james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseWriter.java
    james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/base/ImapResponseComposerImpl.java
    james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoder.java
    james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/base/ByteImapResponseWriter.java
    james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderEnvelopeTest.java
    james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderTest.java
    james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/legacy/MockImapResponseWriter.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/base/SelectedMailboxSessionImpl.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/Imap4Rev1ProcessorFactory.java
    james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/StoreProcessor.java
    james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/FetchCommand.java
    james/server/trunk/mailbox-library/src/main/java/org/apache/james/mailboxmanager/MessageResult.java
    james/server/trunk/mailbox-library/src/main/java/org/apache/james/mailboxmanager/impl/FetchGroupImpl.java
    james/server/trunk/mailbox-library/src/main/java/org/apache/james/mailboxmanager/impl/MessageResultImpl.java
    james/server/trunk/mailbox-library/src/main/java/org/apache/james/mailboxmanager/util/MessageResultUtils.java
    james/server/trunk/mailbox-library/src/test/java/org/apache/james/mailboxmanager/MessageResultImplIncludedResultsTest.java
    james/server/trunk/mailbox-library/src/test/java/org/apache/james/mailboxmanager/MessageResultUtilsIsIncludedTest.java
    james/server/trunk/phoenix-deployment/src/test/org/apache/james/mailboxmanager/torque/TorqueMailboxTest.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/MessageRowUtils.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/PartContentBuilder.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailbox.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueMailboxManager.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueResultIterator.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/om/BaseMessageRow.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/om/MessageHeader.java
    james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/om/MessageRow.java

Modified: james/server/trunk/experimental-seda-imap-function/src/main/java/org/apache/james/experimental/imapserver/encode/writer/ChannelImapResponseWriter.java
URL: http://svn.apache.org/viewvc/james/server/trunk/experimental-seda-imap-function/src/main/java/org/apache/james/experimental/imapserver/encode/writer/ChannelImapResponseWriter.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/experimental-seda-imap-function/src/main/java/org/apache/james/experimental/imapserver/encode/writer/ChannelImapResponseWriter.java (original)
+++ james/server/trunk/experimental-seda-imap-function/src/main/java/org/apache/james/experimental/imapserver/encode/writer/ChannelImapResponseWriter.java Wed Jul 16 14:34:15 2008
@@ -35,6 +35,7 @@
  */
 public class ChannelImapResponseWriter extends AbstractLogEnabled implements ImapConstants, ImapResponseWriter {
     
+    private static final int LOWER_CASE_OFFSET = 'a' - 'A';
     private static final int DEFAULT_BUFFER_SIZE = 128;
     
     private final Charset usAscii;
@@ -205,10 +206,13 @@
     public void literal(Literal literal) throws IOException {
         space();
         write(BYTES_OPEN_BRACE);
-        writeASCII(Long.toString(literal.size()));
+        final long size = literal.size();
+        writeASCII(Long.toString(size));
         write(BYTES_CLOSE_BRACE);
         write(BYTES_LINE_END);
-        literal.writeTo(out);
+        if (size>0) {
+            literal.writeTo(out);
+        }
     }
 
     public void closeSquareBracket() throws IOException {
@@ -218,4 +222,36 @@
     public void openSquareBracket() throws IOException {
         openBracket(BYTES_OPEN_SQUARE_BRACKET);
     }
+    
+    public void upperCaseAscii(String message) throws IOException {
+        upperCaseAscii(message, false);
+    }
+    
+    private void upperCaseAscii(String message, boolean quote) throws IOException {
+        space();
+        final int length = message.length();
+        buffer.clear();
+        if (quote) {
+            buffer.put(BYTE_DQUOTE);
+        }
+        for (int i=0;i<length;i++) {
+            writeIfFull();
+            final char next = message.charAt(i);
+            if (next >= 'a' && next <= 'z') {
+                buffer.put((byte)(next - LOWER_CASE_OFFSET));
+            } else {
+                buffer.put((byte)(next));
+            }
+        }
+        writeIfFull();
+        if (quote) {
+            buffer.put(BYTE_DQUOTE);
+        }
+        buffer.flip();
+        write(buffer);
+    }
+
+    public void quoteUpperCaseAscii(String message) throws IOException {
+        upperCaseAscii(message, true);   
+    }
 }

Added: james/server/trunk/experimental-seda-imap-function/src/test/java/org/apache/james/test/functional/imap/AbstractTestFetchBodyStructure.java
URL: http://svn.apache.org/viewvc/james/server/trunk/experimental-seda-imap-function/src/test/java/org/apache/james/test/functional/imap/AbstractTestFetchBodyStructure.java?rev=677437&view=auto
==============================================================================
--- james/server/trunk/experimental-seda-imap-function/src/test/java/org/apache/james/test/functional/imap/AbstractTestFetchBodyStructure.java (added)
+++ james/server/trunk/experimental-seda-imap-function/src/test/java/org/apache/james/test/functional/imap/AbstractTestFetchBodyStructure.java Wed Jul 16 14:34:15 2008
@@ -0,0 +1,41 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you 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.test.functional.imap;
+
+import java.util.Locale;
+
+public abstract class AbstractTestFetchBodyStructure extends AbstractTestSelectedStateBase {
+
+    public AbstractTestFetchBodyStructure(HostSystem system) {
+        super(system);
+    }
+
+    public void testFetchFetchSimpleBodyStructureUS() throws Exception {
+        scriptTest("FetchSimpleBodyStructure", Locale.US);
+    }
+    
+    public void testFetchFetchSimpleBodyStructureKOREA() throws Exception {
+        scriptTest("FetchSimpleBodyStructure", Locale.KOREA);
+    }
+    
+    public void testFetchFetchSimpleBodyStructureITALY() throws Exception {
+        scriptTest("FetchSimpleBodyStructure", Locale.ITALY);
+    }
+}

Modified: james/server/trunk/experimental-seda-imap-function/src/test/resources/org/apache/james/test/functional/imap/scripts/FetchSimpleBodyStructure.test
URL: http://svn.apache.org/viewvc/james/server/trunk/experimental-seda-imap-function/src/test/resources/org/apache/james/test/functional/imap/scripts/FetchSimpleBodyStructure.test?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/experimental-seda-imap-function/src/test/resources/org/apache/james/test/functional/imap/scripts/FetchSimpleBodyStructure.test (original)
+++ james/server/trunk/experimental-seda-imap-function/src/test/resources/org/apache/james/test/functional/imap/scripts/FetchSimpleBodyStructure.test Wed Jul 16 14:34:15 2008
@@ -122,57 +122,89 @@
 S: Rhubarb!\)
 S: A11 OK FETCH completed\.
 C: A12 FETCH 1 (BODY[2])
-S: \* 1 FETCH \(BODY\[2\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[2\] \{0\}
+S: \)
 S: A12 OK FETCH completed\.
 C: A13 FETCH 1 (BODY[3])
-S: \* 1 FETCH \(BODY\[3\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[3\] \{0\}
+S: \)
 S: A13 OK FETCH completed\.
 C: A14 FETCH 1 (BODY[3.HEADER])
-S: \* 1 FETCH \(BODY\[3\.HEADER\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[3\.HEADER\] \{0\}
+S: \)
 S: A14 OK FETCH completed\.
 C: A15 FETCH 1 (BODY[3.TEXT])
-S: \* 1 FETCH \(BODY\[3\.TEXT\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[3\.TEXT\] \{0\}
+S: \)
 S: A15 OK FETCH completed\.
 C: A16 FETCH 1 (BODY[3.1])
-S: \* 1 FETCH \(BODY\[3\.1\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[3\.1\] \{0\}
+S: \)
 S: A16 OK FETCH completed\.
 C: A17 FETCH 1 (BODY[3.2])
-S: \* 1 FETCH \(BODY\[3\.2\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[3\.2\] \{0\}
+S: \)
 S: A17 OK FETCH completed\.
 C: A18 FETCH 1 (BODY[4])
-S: \* 1 FETCH \(BODY\[4\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\] \{0\}
+S: \)
 S: A18 OK FETCH completed\.
 C: A19 FETCH 1 (BODY[4.1])
-S: \* 1 FETCH \(BODY\[4\.1\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.1\] \{0\}
+S: \)
 S: A19 OK FETCH completed\.
 C: A20 FETCH 1 (BODY[4.1.MIME])
-S: \* 1 FETCH \(BODY\[4\.1\.MIME\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.1\.MIME\] \{0\}
+S: \)
 S: A20 OK FETCH completed\.
 C: A21 FETCH 1 (BODY[4.2])
-S: \* 1 FETCH \(BODY\[4\.2\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.2\] \{0\}
+S: \)
 S: A21 OK FETCH completed\.
 C: A22 FETCH 1 (BODY[4.2.HEADER])
-S: \* 1 FETCH \(BODY\[4\.2\.HEADER\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.2\.HEADER\] \{0\}
+S: \)
 S: A22 OK FETCH completed\.
 C: A23 FETCH 1 (BODY[4.2.TEXT])
-S: \* 1 FETCH \(BODY\[4\.2\.TEXT\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.2\.TEXT\] \{0\}
+S: \)
 S: A23 OK FETCH completed\.
 C: A24 FETCH 1 (BODY[4.2.1])
-S: \* 1 FETCH \(BODY\[4\.2\.1\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.2\.1\] \{0\}
+S: \)
 S: A24 OK FETCH completed\.
 C: A25 FETCH 1 (BODY[4.2.2])
-S: \* 1 FETCH \(BODY\[4\.2\.2\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.2\.2\] \{0\}
+S: \)
 S: A25 OK FETCH completed\.
 C: A26 FETCH 1 (BODY[4.2.2.1])
-S: \* 1 FETCH \(BODY\[4\.2\.2\.1\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.2\.2\.1\] \{0\}
+S: \)
 S: A26 OK FETCH completed\.
 C: A27 FETCH 1 (BODY[4.2.2.2])
-S: \* 1 FETCH \(BODY\[4\.2\.2\.2\] NIL\)
+# See http://markmail.org/message/2jconrj7scvdi5dj
+S: \* 1 FETCH \(BODY\[4\.2\.2\.2\] \{0\}
+S: \)
 S: A27 OK FETCH completed\.
 C: A28 FETCH 1:* (BODY BODYSTRUCTURE)
-S: \* 1 FETCH \(BODY \("text" "plain" \("charset" "us-ascii"\) NIL NIL "7bit" 8 0\) BODYSTRUCTURE \("text" "plain" \("charset" "us-ascii"\) NIL NIL "7bit" 8 0 NIL NIL NIL\)\)
-S: \* 2 FETCH \(BODY \("text" "plain" \("charset" "ISO-8859-1"\) NIL NIL "7bit" 192 6\) BODYSTRUCTURE \("text" "plain" \("charset" "ISO-8859-1"\) NIL NIL "7bit" 192 6 NIL \("inline" NIL\) NIL\)\)
-S: \* 3 FETCH \(BODY \("application" "xhtml\+xml" \("e" "mc\*mc"\) "<477345345@example\.org>" "Homage to 70's TV" "7bit" 183\) BODYSTRUCTURE \("application" "xhtml\+xml" \("e" "mc\*mc"\) "<477345345@example\.org>" "Homage to 70's TV" "7bit" 183 "Q2hlY2sgSW50ZWdyaXR5IQ==" \("inline" \("foo" "bar" "one" "1" "param" "value"\)\) \("en" "en-US" "en-CA"\)\)\)
+S: \* 1 FETCH \(BODY \("TEXT" "PLAIN" \("charset" "us-ascii"\) NIL NIL "7BIT" 8 0\) BODYSTRUCTURE \("TEXT" "PLAIN" \("charset" "us-ascii"\) NIL NIL "7BIT" 8 0 NIL NIL NIL NIL\)\)
+S: \* 2 FETCH \(BODY \("TEXT" "PLAIN" \("charset" "iso-8859-1"\) NIL NIL "7BIT" 192 6\) BODYSTRUCTURE \("TEXT" "PLAIN" \("charset" "iso-8859-1"\) NIL NIL "7BIT" 192 6 NIL \("inline" NIL\) NIL NIL\)\)
+S: \* 3 FETCH \(BODY \("APPLICATION" "XHTML\+XML" \("e" "mc\*mc"\) "<477345345@example\.org>" "Homage to 70's TV" "7BIT" 183\) BODYSTRUCTURE \("APPLICATION" "XHTML\+XML" \("e" "mc\*mc"\) "<477345345@example\.org>" "Homage to 70's TV" "7BIT" 183 "Q2hlY2sgSW50ZWdyaXR5IQ==" \("inline" \("param" "value" "one" "1" "foo" "bar"\)\) \("en" "en-US" "en-CA"\) "http://www.example.org/rhubard.html"\)\)
 S: A28 OK FETCH completed\.
 C: A29 DELETE testmailbox
 S: A29 OK DELETE completed\.

Modified: james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/ImapConstants.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/ImapConstants.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/ImapConstants.java (original)
+++ james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/ImapConstants.java Wed Jul 16 14:34:15 2008
@@ -34,6 +34,12 @@
     public static final String NIL = "NIL";
     public static final String UID = "UID";
     
+    public static final String MIME_HEADER_CONTENT_LOCATION = "Content-Location";
+    public static final String MIME_HEADER_CONTENT_MD5 = "Content-MD5";
+    public static final String MIME_HEADER_CONTENT_LANGUAGE = "Content-Language";
+    
+    public static final String[] EMPTY_STRING_ARRAY = {};
+    
     public static final byte BYTE_OPENING_PARENTHESIS = 0x28;
     public static final byte[] BYTES_OPENING_PARENTHESIS = {BYTE_OPENING_PARENTHESIS};
     public static final byte BYTE_CLOSING_PARENTHESIS = 0x29;
@@ -73,6 +79,12 @@
     final String NAMESPACE_PREFIX = String.valueOf( NAMESPACE_PREFIX_CHAR );
 
     String INBOX_NAME = "INBOX";
+    public String MIME_TYPE_TEXT = "TEXT";
+    public String MIME_TYPE_MULTIPART = "MULTIPART";
+    public String MIME_SUBTYPE_PLAIN = "PLAIN";
+    public String MIME_TYPE_MESSAGE = "MESSAGE";
+    public String MIME_SUBTYPE_RFC822 = "RFC822";
+    
     public static final char BACK_SLASH = '\\';
     public static final String STATUS_UNSEEN = "UNSEEN";
     public static final String STATUS_UIDVALIDITY = "UIDVALIDITY";
@@ -120,4 +132,6 @@
     public static final String FETCH_RFC822 = "RFC822";
     public static final String FETCH_RFC822_HEADER = "RFC822.HEADER";
     public static final String FETCH_RFC822_TEXT = "RFC822.TEXT";
+    public static final String FETCH_BODY_STRUCTURE = "BODYSTRUCTURE";
+    public static final String FETCH_BODY = "BODY";
 }

Modified: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imap/message/response/imap4rev1/FetchResponse.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imap/message/response/imap4rev1/FetchResponse.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imap/message/response/imap4rev1/FetchResponse.java (original)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imap/message/response/imap4rev1/FetchResponse.java Wed Jul 16 14:34:15 2008
@@ -21,7 +21,9 @@
 import java.io.IOException;
 import java.nio.channels.WritableByteChannel;
 import java.util.Date;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import javax.mail.Flags;
 
@@ -34,13 +36,14 @@
     private final Long uid;
     private final Date internalDate;
     private final Integer size;
-    private final StringBuffer misc;
     private final List elements;
     private final Envelope envelope;
+    private final Structure body;
+    private final Structure bodystructure;
     
     public FetchResponse(final int messageNumber, final Flags flags, final Long uid,
             final Date internalDate, final Integer size, final Envelope envelope,
-            StringBuffer misc, List elements) {
+            final Structure body, final Structure bodystructure, List elements) {
         super();
         this.messageNumber = messageNumber;
         this.flags = flags;
@@ -48,11 +51,30 @@
         this.internalDate = internalDate;
         this.size = size;
         this.envelope = envelope;
-        this.misc = misc;
         this.elements = elements;
+        this.body = body;
+        this.bodystructure = bodystructure;
+    }
+    
+    /**
+     * Gets the structure of this message.
+     * @return <code>Structure</code>,
+     * or null if the <code>FETCH</code> did not include <code>BODY</code>
+     */
+    public Structure getBody() {
+        return body;
     }
 
     /**
+     * Gets the structure of this message.
+     * @return <code>Structure</code>,
+     * or null if the <code>FETCH</code> did not include <code>BODYSTRUCTURE</code>
+     */
+    public Structure getBodyStructure() {
+        return bodystructure;
+    }
+    
+    /**
      * Gets the number of the message whose details 
      * have been fetched.
      * @return message number
@@ -114,13 +136,123 @@
     public final List getElements() {
         return elements;
     }
-
+    
     /**
-     * TODO: replace
-     * @return the misc
+     * Describes the message structure.
      */
-    public final StringBuffer getMisc() {
-        return misc;
+    public interface Structure {
+        /**
+         * Gets the MIME media type.
+         * @return media type, 
+         * or null if default
+         */
+        public String getMediaType();
+        
+        /**
+         * Gets the MIME content subtype
+         * @return subtype 
+         * of null if default
+         */
+        public String getSubType();
+        
+        /**
+         * Gets body type parameters. 
+         * @return parameters, 
+         * or null
+         */
+        public String[] getParameters();
+        
+        /**
+         * Gets <code>Content-ID</code>.
+         * @return MIME content ID,
+         * possibly null
+         */
+        public String getId();
+        
+        /**
+         * Gets <code>Content-Description</code>.
+         * @return MIME <code>Content-Description</code>,
+         * possibly null
+         */
+        public String getDescription();
+        
+        /**
+         * Gets content transfer encoding.
+         * @return MIME <code>Content-Transfer-Encoding</code>,
+         * possibly null
+         */
+        public String getEncoding();
+        
+        /**
+         * Gets the size of message body the in octets.
+         * @return number of octets in the message.
+         */
+        public long getOctets();
+        
+        /**
+         * Gets the number of lines fo transfer encoding 
+         * for a <code>TEXT</code> type.
+         * @return number of lines when <code>TEXT</code>,
+         * -1 otherwise
+         */
+        public long getLines();
+        
+        /**
+         * Gets <code>Content-MD5</code>.
+         * @return Content-MD5
+         * or null if <code>BODY</code> FETCH or not present
+         */
+        public String getMD5();
+        
+        /**
+         * Gets header field-value from <code>Content-Disposition</code>.
+         * @return map of field value <code>String</code> 
+         * indexed by field name <code>String</code>
+         * or null if <code>BODY</code> FETCH or not present
+         */
+        public Map getDispositionParams();
+        
+        /**
+         * Gets header field-value from <code>Content-Disposition</code>.
+         * @return disposition 
+         * or null if <code>BODY</code> FETCH or not present
+         */
+        public String getDisposition();
+        
+        /**
+         * Gets MIME <code>Content-Language</code>'s.
+         * @return List of <code>Content-Language</code> name <code>String</code>'s
+         * possibly null or null when <code>BODY</code> FETCH
+         */
+        public List getLanguages();
+        
+        /**
+         * Gets <code>Content-Location</code>.
+         * @return Content-Location possibly null;
+         * or null when <code>BODY</code> FETCH
+         */
+        public String getLocation();
+        
+        /**
+         * Iterates parts of a composite media type.
+         * @return <code>Structure</code> <code>Iterator</code>
+         * when composite type, null otherwise
+         */
+        public Iterator parts();
+        
+        /**
+         * Gets the envelope of an embedded mail.
+         * @return <code>Envelope</code> when <code>message/rfc822</code>
+         * otherwise null
+         */
+        public Envelope getEnvelope();
+        
+        /**
+         * Gets the envelope of an embedded mail.
+         * @return <code>Structure</code> when when <code>message/rfc822</code>
+         * otherwise null
+         */
+        public Structure getBody();
     }
     
     /**

Modified: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseComposer.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseComposer.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseComposer.java (original)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseComposer.java Wed Jul 16 14:34:15 2008
@@ -161,7 +161,7 @@
     public abstract void expungeResponse(int msn) throws IOException;
     
     public abstract void searchResponse(long[] ids) throws IOException;
-
+    
     /**
      * Starts a FETCH response by writing the opening
      * star-FETCH-number-paren sequence.
@@ -258,7 +258,7 @@
 
     public abstract void commandName(final String name) throws IOException;
 
-    public abstract void message(final String message) throws IOException;
+    public ImapResponseComposer message(final String message) throws IOException;
 
     public abstract void message(final long number) throws IOException;
 
@@ -275,5 +275,61 @@
     public void quote(String message) throws IOException;
 
     public void literal(Literal literal) throws IOException;
-
+    
+    public ImapResponseComposer openParen() throws IOException;
+    public ImapResponseComposer closeParen() throws IOException;
+    
+    /**
+     * Appends the given message after conversion to upper case.
+     * The message may be assumed to be ASCII encoded.
+     * Conversion of characters MUST NOT be performed according 
+     * to the current locale but as per ASCII.
+     * @param message ASCII encoded, not null
+     * @return self, not null
+     * @throws IOException
+     */
+    public ImapResponseComposer upperCaseAscii(final String message) throws IOException;
+    
+    /**
+     * Appends the given message after conversion to upper case.
+     * The message may be assumed to be ASCII encoded.
+     * Conversion of characters MUST NOT be performed according 
+     * to the current locale but as per ASCII.
+     * @param message ASCII encoded, not null
+     * @return self, not null
+     * @throws IOException
+     */
+    public ImapResponseComposer quoteUpperCaseAscii(final String message) throws IOException;
+    
+    /**
+     * Appends the given message after appropriate quoting (when not null)
+     * or <code>NIL</code> (when null).
+     * @param message possibly null
+     * @return self, not null
+     * @throws IOException
+     */
+    public ImapResponseComposer nillableQuote(String message) throws IOException;
+    
+    /**
+     * Composes a sequence of nillables quotes.
+     * When messages are null, a single <code>NIL</code> is appended.
+     * Otherwise, each element is appended in sequence as per {@link #nillableQuote(String)}.
+     * @param quotes messages, possibly null
+     * @return self, not null
+     * @throws IOException
+     */
+    public ImapResponseComposer nillableQuotes(String[] quotes) throws IOException;
+    
+    /**
+     * Composes a nillable composition.
+     * When the master quote is null, <code>NIL</code> is appended.
+     * Otherwise, a parenthesized list is created starting with the master quote.
+     * When the quotes are null, <code>NIL</code> is appended only.
+     * Otherwise, each element is appended in sequence as per {@link #nillableQuote(String)}
+     * @param quote master, possibly null
+     * @param quotes quotes, possibly null
+     * @return self, not null
+     * @throws IOException
+     */
+    public ImapResponseComposer nillableComposition(String masterQuote, String[] quotes) throws IOException;
 }
\ No newline at end of file

Modified: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseWriter.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseWriter.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseWriter.java (original)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/ImapResponseWriter.java Wed Jul 16 14:34:15 2008
@@ -109,4 +109,25 @@
      * @throws IOException
      */
     void literal(Literal literal) throws IOException;
+
+    /**
+     * Writes given message converted to upper case.
+     * The message may be assumed to be ASCII encoded.
+     * Conversion of characters MUST NOT be performed according 
+     * to the current locale but as per ASCII.
+     * @param message ASCII encoded, not null
+     * @throws IOException
+     */
+    void upperCaseAscii(String message) throws IOException;
+
+    /**
+     * Writes given message converted to upper case.
+     * The message may be assumed to be ASCII encoded.
+     * Conversion of characters MUST NOT be performed according 
+     * to the current locale but as per ASCII.
+     * The message is surrounded by quotes.
+     * @param message ASCII encoded, not null
+     * @throws IOException 
+     */
+    void quoteUpperCaseAscii(String message) throws IOException;
 }

Modified: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/base/ImapResponseComposerImpl.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/base/ImapResponseComposerImpl.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/base/ImapResponseComposerImpl.java (original)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/base/ImapResponseComposerImpl.java Wed Jul 16 14:34:15 2008
@@ -39,7 +39,7 @@
  * client.
  */
 public class ImapResponseComposerImpl extends AbstractLogEnabled implements
-        ImapConstants, ImapResponseWriter, ImapResponseComposer {
+        ImapConstants, ImapResponseComposer {
 
     public static final String ENVELOPE = "ENVELOPE";
     
@@ -287,13 +287,14 @@
      * @throws IOException 
      * @see org.apache.james.imapserver.codec.encode.ImapResponseComposer#message(java.lang.String)
      */
-    public void message(final String message) throws IOException {
+    public ImapResponseComposer message(final String message) throws IOException {
         if (message != null) {
             // TODO: consider message normalisation
             // TODO: CR/NFs in message must be replaced
             // TODO: probably best done in the writer
             writer.message(message);
         }
+        return this;
     }
 
     /**
@@ -438,13 +439,14 @@
         writer.quote(message);
     }
 
-    public void closeParen() throws IOException {
+    public ImapResponseComposer closeParen() throws IOException {
         writer.closeParen();
-        
+        return this;
     }
 
-    public void openParen() throws IOException {
+    public ImapResponseComposer openParen() throws IOException {
         writer.openParen();
+        return this;
     }
 
     public void searchResponse(long[] ids) throws IOException {
@@ -539,12 +541,13 @@
         nillableQuote(subject);
     }
 
-    public void nillableQuote(String message) throws IOException {
+    public ImapResponseComposer nillableQuote(String message) throws IOException {
         if (message == null) {
             nil();
         } else {
             quote(message);
         }
+        return this;
     }
 
     public void skipNextSpace() throws IOException {
@@ -558,4 +561,48 @@
     public void openSquareBracket() throws IOException {
         writer.openSquareBracket();
     }
+
+    public ImapResponseComposer nillableComposition(String masterQuote, String[] quotes) throws IOException {
+        if (masterQuote == null) {
+            nil();
+        }  else {
+            openParen();
+            quote(masterQuote);
+            nillableQuotes(quotes);
+            closeParen();
+        }
+        return this;
+    }
+
+    public ImapResponseComposer nillableQuotes(String[] quotes) throws IOException {
+        if (quotes == null) {
+            nil();
+        } else {
+            openParen();
+            for (int i = 0; i < quotes.length; i++) {
+                final String string = quotes[i];
+                nillableQuote(string);
+            }
+            closeParen();
+        }
+        return this;
+    }
+
+    public ImapResponseComposer upperCaseAscii(String message) throws IOException {
+        if (message == null) {
+            nil();
+        } else {
+            writer.upperCaseAscii(message);
+        }
+        return this;
+    }
+
+    public ImapResponseComposer quoteUpperCaseAscii(String message) throws IOException {
+        if (message == null) {
+            nil();
+        } else {
+            writer.quoteUpperCaseAscii(message);
+        }
+        return this;
+    }
 }

Modified: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoder.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoder.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoder.java (original)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoder.java Wed Jul 16 14:34:15 2008
@@ -20,15 +20,19 @@
 package org.apache.james.imapserver.codec.encode.imap4rev1;
 
 import java.io.IOException;
+import java.util.Collection;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import javax.mail.Flags;
 
+import org.apache.avalon.framework.logger.Logger;
 import org.apache.james.api.imap.ImapConstants;
 import org.apache.james.api.imap.ImapMessage;
 import org.apache.james.imap.message.response.imap4rev1.FetchResponse;
+import org.apache.james.imap.message.response.imap4rev1.FetchResponse.Structure;
 import org.apache.james.imapserver.codec.encode.EncoderUtils;
 import org.apache.james.imapserver.codec.encode.ImapEncoder;
 import org.apache.james.imapserver.codec.encode.ImapResponseComposer;
@@ -36,6 +40,8 @@
 
 public class FetchResponseEncoder extends AbstractChainedImapEncoder {
 
+    private static final String[] EMPTY_STRING_ARRAY={};
+    
     public FetchResponseEncoder(final ImapEncoder next) {
         super(next);
     }
@@ -53,28 +59,190 @@
             encodeInternalDate(composer, fetchResponse);
             encodeSize(composer, fetchResponse);
             encodeEnvelope(composer, fetchResponse);
-            encode(composer, fetchResponse.getMisc());
+            encodeBody(composer, fetchResponse.getBody());
+            encodeBodyStructure(composer, fetchResponse.getBodyStructure());
             encodeUid(composer, fetchResponse);
             encodeBodyElements(composer, fetchResponse.getElements());
             composer.closeFetchResponse();
         }
     }
     
+    private void encodeBody(ImapResponseComposer composer, Structure body) throws IOException {
+        if (body != null) {
+            composer.message(ImapConstants.FETCH_BODY);
+            encodeStructure(composer, body, false);
+        }
+    }
+
+    private void encodeBodyStructure(ImapResponseComposer composer, Structure bodyStructure) throws IOException {
+        if (bodyStructure != null) {
+            composer.message(ImapConstants.FETCH_BODY_STRUCTURE);
+            encodeStructure(composer, bodyStructure, true);
+        }
+    }
+    
+    private void encodeStructure(final ImapResponseComposer composer, 
+            final Structure structure, final boolean includeExtensions) throws IOException {
+        
+        final String mediaType;
+        final String subType;
+        final String rawMediaType = structure.getMediaType();
+        if (rawMediaType == null) {
+            mediaType = ImapConstants.MIME_TYPE_TEXT;
+            subType = ImapConstants.MIME_SUBTYPE_PLAIN;
+        } else {
+            mediaType = rawMediaType;
+            subType = structure.getSubType();
+        }
+        encodeStructure(composer, structure, includeExtensions, mediaType, subType);
+    }
+
+    private void encodeStructure(final ImapResponseComposer composer, final Structure structure, 
+            final boolean includeExtensions, final String mediaType, final String subType) throws IOException {
+        if (ImapConstants.MIME_TYPE_MULTIPART.equalsIgnoreCase(mediaType)) {
+            
+            encodeMultipart(composer, structure, subType, includeExtensions);
+            
+        } else {
+            if (ImapConstants.MIME_TYPE_MESSAGE.equalsIgnoreCase(mediaType) 
+                    && ImapConstants.MIME_SUBTYPE_RFC822.equalsIgnoreCase(subType)) {
+
+                encodeRfc822Message(composer, structure, mediaType, subType, includeExtensions);
+            } else {
+                encodeBasic(composer, structure, includeExtensions, mediaType, subType);
+            }
+        }
+    }
+
+    private void encodeBasic(final ImapResponseComposer composer, final Structure structure, final boolean includeExtensions, final String mediaType, final String subType) throws IOException {
+        if (ImapConstants.MIME_TYPE_TEXT.equalsIgnoreCase(mediaType)) {
+            
+            final long lines = structure.getLines();
+            
+            encodeBodyFields(composer, structure, mediaType, subType);
+            composer.message(lines);                
+        } else {
+            encodeBodyFields(composer, structure, mediaType, subType);
+        }
+        if (includeExtensions) {
+            encodeOnePartBodyExtensions(composer, structure);
+        }   
+        composer.closeParen();
+    }
+
+    private void encodeOnePartBodyExtensions(final ImapResponseComposer composer, final Structure structure) throws IOException {
+        final String md5 = structure.getMD5();
+        final String[] languages = languages(structure);
+        final String location = structure.getLocation();
+        composer.nillableQuote(md5);
+        bodyFldDsp(structure, composer).nillableQuotes(languages).nillableQuote(location);
+    }
+
+    private ImapResponseComposer bodyFldDsp(final Structure structure, final ImapResponseComposer composer) throws IOException {
+        final String disposition = structure.getDisposition();
+        if (disposition == null) {
+            composer.nil();
+        } else {
+            composer.openParen();
+            composer.quote(disposition);
+            final Map params = structure.getDispositionParams();
+            bodyFldParam(params, composer);
+            composer.closeParen();
+        }
+        return composer;
+    }
+    
+    private void bodyFldParam(final Map params, final ImapResponseComposer composer) throws IOException {
+        if (params == null || params.isEmpty()) {
+            composer.nil();
+        } else {
+            composer.openParen();
+            final Collection names = params.keySet();
+            for (Iterator iter = names.iterator(); iter.hasNext();) {
+                final String name = (String) iter.next();
+                final String value = (String) params.get(name);
+                if (value == null) {
+                    final Logger logger = getLogger();
+                    logger.warn("Disposition parameter name has no value.");
+                    if (logger.isDebugEnabled()) {
+                        logger.debug("Disposition parameter " + name + " has no matching value");
+                    }
+                } else {
+                    composer.quote(name);
+                    composer.quote(value);
+                }
+            }
+            composer.closeParen();
+        }
+    }
+
+    private void encodeBodyFields(final ImapResponseComposer composer, final Structure structure, final String mediaType, final String subType) throws IOException {
+        final String[] bodyParams = structure.getParameters();
+        final String id = structure.getId();
+        final String description = structure.getDescription();
+        final String encoding = structure.getEncoding();
+        final long octets = structure.getOctets();
+        composer.openParen().quoteUpperCaseAscii(mediaType).quoteUpperCaseAscii(subType).nillableQuotes(bodyParams)
+                .nillableQuote(id).nillableQuote(description).quoteUpperCaseAscii(encoding).message(octets);
+    }
+
+    private void encodeMultipart(ImapResponseComposer composer, Structure structure, 
+            final String subType, final boolean includeExtensions) throws IOException {
+        composer.openParen();
+        
+        for (Iterator it = structure.parts(); it.hasNext();) {
+            final Structure part = (Structure) it.next();
+            encodeStructure(composer, part, includeExtensions);
+        }
+        
+        if (includeExtensions) {
+            final String[] languages = languages(structure);
+            composer.nillableQuotes(structure.getParameters());
+            bodyFldDsp(structure, composer).nillableQuotes(languages).nillableQuote(structure.getLocation());
+        }
+        composer.upperCaseAscii(subType).closeParen();
+    }
+
+    private String[] languages(Structure structure) {
+        final List languageList = structure.getLanguages();
+        final String[] languages;
+        if (languageList == null) {
+            languages = null;
+        } else {
+            languages = (String[]) languageList.toArray(EMPTY_STRING_ARRAY);
+        }
+        return languages;
+    }
+
+    private void encodeRfc822Message(ImapResponseComposer composer, Structure structure, 
+            final String mediaType, final String subType, final boolean includeExtensions) throws IOException {
+        final long lines = structure.getLines();
+        final FetchResponse.Envelope envelope = structure.getEnvelope();
+        final FetchResponse.Structure embeddedStructure = structure.getBody();
+        
+        encodeBodyFields(composer, structure, mediaType, subType);
+        encodeEnvelope(composer, envelope);
+        encodeStructure(composer, embeddedStructure, includeExtensions);
+        composer.message(lines);
+        
+        if (includeExtensions) {
+            encodeOnePartBodyExtensions(composer, structure);
+        }
+        composer.closeParen();
+    }
+    
+
     private void encodeBodyElements(final ImapResponseComposer composer, final List elements) throws IOException {
         if (elements != null) {
             for (final Iterator it = elements.iterator();it.hasNext();) {
                 FetchResponse.BodyElement element = (FetchResponse.BodyElement) it.next();
-                composer.message(element.getName());
+                final String name = element.getName();
+                composer.message(name);
                 composer.literal(element);
             }
         }
     }
 
-    private void encode(ImapResponseComposer composer, StringBuffer buffer) throws IOException {
-        if (buffer != null && buffer.length() > 0) {
-            composer.message(buffer.substring(1));
-        }
-    }
 
     private void encodeSize(ImapResponseComposer composer, final FetchResponse fetchResponse) throws IOException {
         final Integer size = fetchResponse.getSize();
@@ -111,6 +279,10 @@
 
     private void encodeEnvelope(final ImapResponseComposer composer, final FetchResponse fetchResponse) throws IOException {
         final FetchResponse.Envelope envelope = fetchResponse.getEnvelope();
+        encodeEnvelope(composer, envelope);
+    }
+
+    private void encodeEnvelope(final ImapResponseComposer composer, final FetchResponse.Envelope envelope) throws IOException {
         if (envelope != null) {
             final String date = envelope.getDate();
             final String subject = envelope.getSubject();

Modified: james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/base/ByteImapResponseWriter.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/base/ByteImapResponseWriter.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/base/ByteImapResponseWriter.java (original)
+++ james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/base/ByteImapResponseWriter.java Wed Jul 16 14:34:15 2008
@@ -36,6 +36,8 @@
  */
 public class ByteImapResponseWriter extends AbstractLogEnabled implements ImapConstants, ImapResponseWriter {
     
+    private static final int LOWER_CASE_OFFSET = 'a' - 'A';
+    
     private PrintWriter writer;
     private ByteArrayOutputStream out;
     private boolean skipNextSpace;
@@ -182,4 +184,28 @@
     public void openSquareBracket() throws IOException {
         openBracket(OPENING_SQUARE_BRACKET);
     }
+
+    public void upperCaseAscii(String message) throws IOException {
+        upperCaseAscii(message, false);
+    }
+
+    private void upperCaseAscii(String message, boolean quote) {
+        space();
+        if (quote) writer.print(DQUOTE);
+        // message is ASCII
+        final int length = message.length();
+        for (int i=0;i<length;i++) {
+            final char next = message.charAt(i);
+            if (next >= 'a' && next <= 'z') {
+                writer.print(next + LOWER_CASE_OFFSET);
+            } else {
+                writer.print(next);
+            }
+        }
+        if (quote) writer.print(DQUOTE);
+    }
+
+    public void quoteUpperCaseAscii(String message) {
+        upperCaseAscii(message, true);
+    }
 }

Modified: james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderEnvelopeTest.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderEnvelopeTest.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderEnvelopeTest.java (original)
+++ james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderEnvelopeTest.java Wed Jul 16 14:34:15 2008
@@ -77,7 +77,7 @@
     
         
         message = new FetchResponse(MSN, null, null, null, null, 
-                (FetchResponse.Envelope) envelope.proxy(), null, null);
+                (FetchResponse.Envelope) envelope.proxy(), null, null, null);
         mockComposer = mock(ImapResponseComposer.class);
         composer = (ImapResponseComposer) mockComposer.proxy();
         mockNextEncoder = mock(ImapEncoder.class);

Modified: james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderTest.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderTest.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderTest.java (original)
+++ james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/FetchResponseEncoderTest.java Wed Jul 16 14:34:15 2008
@@ -57,11 +57,11 @@
     }
     
     public void testShouldAcceptFetchResponse() throws Exception {
-        assertTrue(encoder.isAcceptable(new FetchResponse(11, null, null, null, null, null, null, null)));
+        assertTrue(encoder.isAcceptable(new FetchResponse(11, null, null, null, null, null, null, null, null)));
     }
     
     public void testShouldEncodeFlagsResponse() throws Exception {
-        FetchResponse message = new FetchResponse(100, flags, null, null, null, null, null, null);
+        FetchResponse message = new FetchResponse(100, flags, null, null, null, null, null, null, null);
         mockComposer.expects(once()).method("openFetchResponse").with(eq(100L));
         mockComposer.expects(once()).method("flags").with(eq(flags));
         mockComposer.expects(once()).method("closeFetchResponse");
@@ -69,7 +69,7 @@
     }
     
     public void testShouldEncodeUidResponse() throws Exception {
-        FetchResponse message = new FetchResponse(100, null, new Long(72), null, null, null, null, null);
+        FetchResponse message = new FetchResponse(100, null, new Long(72), null, null, null, null, null, null);
         mockComposer.expects(once()).method("openFetchResponse").with(eq(100L));
         mockComposer.expects(once()).method("message").with(eq("UID"));
         mockComposer.expects(once()).method("message").with(eq(72L));
@@ -78,7 +78,7 @@
     }
     
     public void testShouldEncodeAllResponse() throws Exception {
-        FetchResponse message = new FetchResponse(100, flags, new Long(72), null, null, null, null, null);
+        FetchResponse message = new FetchResponse(100, flags, new Long(72), null, null, null, null, null, null);
         mockComposer.expects(once()).method("openFetchResponse").with(eq(100L));
         mockComposer.expects(once()).method("flags").with(eq(flags));
         mockComposer.expects(once()).method("message").with(eq("UID"));

Modified: james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/legacy/MockImapResponseWriter.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/legacy/MockImapResponseWriter.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/legacy/MockImapResponseWriter.java (original)
+++ james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/encode/imap4rev1/legacy/MockImapResponseWriter.java Wed Jul 16 14:34:15 2008
@@ -367,8 +367,6 @@
                 return false;
             return true;
         }
-        
-        
     }
 
     public void skipNextSpace() throws IOException {
@@ -381,5 +379,46 @@
     public void openSquareBracket() throws IOException {
         operations.add(new BracketOperation(true, true));
     }
+
+    public void upperCaseAscii(String message) throws IOException {
+        operations.add(new UpperCaseASCIIOperation(message, false));
+    }
     
+    public static final class UpperCaseASCIIOperation {
+        public final String message;
+        public final boolean quote;
+        public UpperCaseASCIIOperation(String message, boolean quote) {
+            this.message = message;
+            this.quote = quote;
+        }
+
+        public int hashCode() {
+            final int PRIME = 31;
+            int result = 1;
+            result = PRIME * result + ((message == null) ? 0 : message.hashCode());
+            return result;
+        }
+        
+        public boolean equals(Object obj) {
+            if (this == obj)
+                return true;
+            if (obj == null)
+                return false;
+            if (getClass() != obj.getClass())
+                return false;
+            final UpperCaseASCIIOperation other = (UpperCaseASCIIOperation) obj;
+            if (message == null) {
+                if (other.message != null)
+                    return false;
+            } else if (!message.equals(other.message))
+                return false;
+            return true;
+        }
+        
+        
+    }
+
+    public void quoteUpperCaseAscii(String message) throws IOException {
+        operations.add(new UpperCaseASCIIOperation(message, true));
+    }    
 }

Modified: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/base/SelectedMailboxSessionImpl.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/base/SelectedMailboxSessionImpl.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/base/SelectedMailboxSessionImpl.java (original)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/base/SelectedMailboxSessionImpl.java Wed Jul 16 14:34:15 2008
@@ -160,7 +160,7 @@
             } else {
                 uidOut = null;
             }
-            FetchResponse response = new FetchResponse(msn, flags, uidOut, null, null, null, null, null);
+            FetchResponse response = new FetchResponse(msn, flags, uidOut, null, null, null, null, null, null);
             responses.add(response);
         }
     }

Modified: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/Imap4Rev1ProcessorFactory.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/Imap4Rev1ProcessorFactory.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/Imap4Rev1ProcessorFactory.java (original)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/Imap4Rev1ProcessorFactory.java Wed Jul 16 14:34:15 2008
@@ -21,6 +21,7 @@
 
 import org.apache.james.api.imap.message.response.imap4rev1.StatusResponseFactory;
 import org.apache.james.api.imap.process.ImapProcessor;
+import org.apache.james.imapserver.processor.imap4rev1.fetch.FetchProcessor;
 import org.apache.james.mailboxmanager.manager.MailboxManagerProvider;
 import org.apache.james.services.UsersRepository;
 

Modified: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/StoreProcessor.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/StoreProcessor.java?rev=677437&r1=677436&r2=677437&view=diff
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/StoreProcessor.java (original)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/StoreProcessor.java Wed Jul 16 14:34:15 2008
@@ -112,7 +112,7 @@
                             resultFlags.add(Flags.Flag.RECENT);
                         }
                         final FetchResponse response 
-                            = new FetchResponse(msn, resultFlags, resultUid, null, null, null, null, null);
+                            = new FetchResponse(msn, resultFlags, resultUid, null, null, null, null, null, null);
                         responder.respond(response);
                     }
                 }

Added: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/AddressImpl.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/AddressImpl.java?rev=677437&view=auto
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/AddressImpl.java (added)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/AddressImpl.java Wed Jul 16 14:34:15 2008
@@ -0,0 +1,56 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you 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.processor.imap4rev1.fetch;
+
+import org.apache.james.imap.message.response.imap4rev1.FetchResponse;
+
+final class AddressImpl implements FetchResponse.Envelope.Address {
+    private final String atDomainList;
+    private final String hostName;
+    private final String mailboxName;
+    private final String personalName;
+
+    public AddressImpl(final String atDomainList, final String hostName, final String mailboxName, final String personalName) {
+        super();
+        this.atDomainList = atDomainList;
+        this.hostName = hostName;
+        this.mailboxName = mailboxName;
+        this.personalName = personalName;
+    }
+
+    public String getAtDomainList() {
+        return atDomainList;
+    }
+
+    public String getHostName() {
+        return hostName;
+    }
+
+    public String getMailboxName() {
+        return mailboxName;
+    }
+
+    public String getPersonalName() {
+        return personalName;
+    }
+}
\ No newline at end of file

Added: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/ContentBodyElement.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/ContentBodyElement.java?rev=677437&view=auto
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/ContentBodyElement.java (added)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/ContentBodyElement.java Wed Jul 16 14:34:15 2008
@@ -0,0 +1,62 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you 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.processor.imap4rev1.fetch;
+
+import java.io.IOException;
+import java.nio.channels.WritableByteChannel;
+
+import org.apache.james.imap.message.response.imap4rev1.FetchResponse.BodyElement;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.MessageResult.Content;
+
+final class ContentBodyElement implements BodyElement {
+    private final String name;
+    private final MessageResult.Content content;
+    
+    public ContentBodyElement(final String name, final Content content) {
+        super();
+        this.name = name;
+        this.content = content;
+    }
+
+    /**
+     * @see org.apache.james.imap.message.response.imap4rev1.FetchResponse.BodyElement#getName()
+     */
+    public String getName() {
+        return name;
+    }
+    
+    /**
+     * @see org.apache.james.imap.message.response.imap4rev1.FetchResponse.BodyElement#size()
+     */
+    public long size() {
+        return content.size();
+    }
+    
+    /**
+     * @see org.apache.james.imap.message.response.imap4rev1.FetchResponse.BodyElement#writeTo(WritableByteChannel)
+     */
+    public void writeTo(WritableByteChannel channel) throws IOException {
+        content.writeTo(channel);
+    }
+}
\ No newline at end of file

Added: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeBuilder.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeBuilder.java?rev=677437&view=auto
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeBuilder.java (added)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeBuilder.java Wed Jul 16 14:34:15 2008
@@ -0,0 +1,195 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you 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.processor.imap4rev1.fetch;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.mail.MessagingException;
+
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.james.imap.message.response.imap4rev1.FetchResponse;
+import org.apache.james.mailboxmanager.Headers;
+import org.apache.james.mailboxmanager.MailboxManagerException;
+import org.apache.james.mailboxmanager.MessageResult;
+import org.apache.james.mailboxmanager.util.MessageResultUtils;
+import org.apache.james.mime4j.field.address.Address;
+import org.apache.james.mime4j.field.address.AddressList;
+import org.apache.james.mime4j.field.address.DomainList;
+import org.apache.james.mime4j.field.address.Group;
+import org.apache.james.mime4j.field.address.MailboxList;
+import org.apache.james.mime4j.field.address.NamedMailbox;
+import org.apache.james.mime4j.field.address.parser.ParseException;
+import org.apache.mailet.RFC2822Headers;
+
+final class EnvelopeBuilder {
+    private final Logger logger;
+    
+    public EnvelopeBuilder(final Logger logger) {
+        super();
+        this.logger = logger;
+    }
+   
+    public FetchResponse.Envelope buildEnvelope(final Headers headers) throws MessagingException, ParseException {
+        final String date = headerValue(headers, RFC2822Headers.DATE);
+        final String subject = headerValue(headers, RFC2822Headers.SUBJECT);
+        final FetchResponse.Envelope.Address[] fromAddresses 
+                    = buildAddresses(headers, RFC2822Headers.FROM);
+        final FetchResponse.Envelope.Address[] senderAddresses
+                    = buildAddresses(headers, RFC2822Headers.SENDER, fromAddresses);
+        final FetchResponse.Envelope.Address[] replyToAddresses
+                    = buildAddresses(headers, RFC2822Headers.REPLY_TO, fromAddresses);
+        final FetchResponse.Envelope.Address[] toAddresses 
+                    = buildAddresses(headers, RFC2822Headers.TO);
+        final FetchResponse.Envelope.Address[] ccAddresses 
+                    = buildAddresses(headers, RFC2822Headers.CC);
+        final FetchResponse.Envelope.Address[] bccAddresses 
+                    = buildAddresses(headers, RFC2822Headers.BCC);
+        final String inReplyTo = headerValue(headers, RFC2822Headers.IN_REPLY_TO);
+        final String messageId = headerValue(headers, RFC2822Headers.MESSAGE_ID);
+        final FetchResponse.Envelope envelope = new EnvelopeImpl(date, subject, fromAddresses, senderAddresses, 
+                replyToAddresses, toAddresses, ccAddresses, bccAddresses, inReplyTo, messageId);
+        return envelope;
+    }
+    
+    private String headerValue(final Headers message, final String headerName) throws MessagingException, MailboxManagerException {
+        final MessageResult.Header header 
+            = MessageResultUtils.getMatching(headerName, message.headers());
+        final String result;
+        if (header == null) {
+            result = null;
+        } else {
+            final String value = header.getValue();
+            if (value == null || "".equals(value)) {
+                result = null;
+            } else {
+                result = value;
+            }
+        }
+        return result;
+    }
+
+    private FetchResponse.Envelope.Address[] buildAddresses(final Headers message, final String headerName, 
+            final FetchResponse.Envelope.Address[] defaults) throws ParseException, MessagingException {
+        final FetchResponse.Envelope.Address[] results;
+        final FetchResponse.Envelope.Address[] addresses = buildAddresses(message, headerName);
+        if (addresses == null) {
+            results = defaults;
+        } else {
+            results = addresses;
+        }
+        return results;
+    }
+    
+    private FetchResponse.Envelope.Address[] buildAddresses(final Headers message, final String headerName) 
+                throws ParseException, MessagingException {
+        final MessageResult.Header header = MessageResultUtils.getMatching(headerName, message.headers());
+        final FetchResponse.Envelope.Address[] results;
+        if (header == null) {
+            results = null;
+        } else {
+            final String value = header.getValue();
+            if ("".equals(value.trim())) {
+                results  = null;
+            } else {
+                final AddressList addressList = AddressList.parse(value);
+                final int size = addressList.size();
+                final List addresses = new ArrayList(size);
+                for (int i=0;i<size;i++) {
+                    final Address address = addressList.get(i);
+                    if (address instanceof Group) {
+                        final Group group = (Group) address;
+                        addAddresses(group, addresses);
+
+                    } else if (address instanceof org.apache.james.mime4j.field.address.Mailbox) {
+                        final org.apache.james.mime4j.field.address.Mailbox mailbox 
+                            = (org.apache.james.mime4j.field.address.Mailbox) address;
+                        final FetchResponse.Envelope.Address mailboxAddress = buildMailboxAddress(mailbox);
+                        addresses.add(mailboxAddress);
+
+                    } else {
+                        logger.warn("Unknown address type");
+                    }
+                }
+
+                results = (FetchResponse.Envelope.Address[]) 
+                addresses.toArray(FetchResponse.Envelope.Address.EMPTY);
+            }
+        }
+        return results;
+    }
+    
+    private FetchResponse.Envelope.Address buildMailboxAddress(final org.apache.james.mime4j.field.address.Mailbox mailbox) {
+        final String name;
+        if (mailbox instanceof NamedMailbox) {
+            final NamedMailbox namedMailbox = (NamedMailbox) mailbox;
+            name = namedMailbox.getName();
+        } else {
+            name = null;
+        }
+        final String domain = mailbox.getDomain();
+        final DomainList route = mailbox.getRoute();
+        final String atDomainList;
+        if (route == null) {
+            atDomainList = null;
+        } else {
+            atDomainList = route.toRouteString();
+        }
+        final String localPart = mailbox.getLocalPart();
+        final FetchResponse.Envelope.Address result = buildMailboxAddress(name, atDomainList, localPart, domain);
+        return result;
+    }
+    
+    private void addAddresses(final Group group, final List addresses) {
+        final String groupName = group.getName();
+        final FetchResponse.Envelope.Address start = startGroup(groupName);
+        addresses.add(start);
+        final MailboxList mailboxList = group.getMailboxes();
+        for (int i=0;i<mailboxList.size();i++) {
+            final org.apache.james.mime4j.field.address.Mailbox mailbox = mailboxList.get(i);
+            final FetchResponse.Envelope.Address address = buildMailboxAddress(mailbox);
+            addresses.add(address);
+        }
+        final FetchResponse.Envelope.Address end = endGroup();
+        addresses.add(end);
+    }
+    
+    private FetchResponse.Envelope.Address startGroup(String groupName) {
+        final FetchResponse.Envelope.Address result 
+        = new AddressImpl(null, null, groupName, null);
+        return result;
+    }
+    
+    private FetchResponse.Envelope.Address endGroup() {
+        final FetchResponse.Envelope.Address result 
+        = new AddressImpl(null, null, null, null);
+        return result;
+    }
+                
+    private FetchResponse.Envelope.Address buildMailboxAddress(String name, String atDomainList, 
+                                                        String mailbox, String domain) {
+        final FetchResponse.Envelope.Address result 
+            = new AddressImpl(atDomainList, domain, mailbox, name);
+        return result;
+    }
+}
\ No newline at end of file

Added: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeImpl.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeImpl.java?rev=677437&view=auto
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeImpl.java (added)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/fetch/EnvelopeImpl.java Wed Jul 16 14:34:15 2008
@@ -0,0 +1,96 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you 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.processor.imap4rev1.fetch;
+
+import org.apache.james.imap.message.response.imap4rev1.FetchResponse;
+
+final class EnvelopeImpl implements FetchResponse.Envelope {
+
+    private final Address[] bcc;
+    private final Address[] cc;
+    private final String date;
+    private final Address[] from;
+    private final String inReplyTo;
+    private final String messageId;
+    private final Address[] replyTo;
+    private final Address[] sender;
+    private final String subject;                  
+    private final Address[] to;
+    
+    public EnvelopeImpl(final String date, final String subject, final Address[] from, 
+            final Address[] sender, final Address[] replyTo, final Address[] to, 
+            final Address[] cc, final Address[] bcc, final String inReplyTo, 
+            final String messageId) {
+        super();
+        this.bcc = bcc;
+        this.cc = cc;
+        this.date = date;
+        this.from = from;
+        this.inReplyTo = inReplyTo;
+        this.messageId = messageId;
+        this.replyTo = replyTo;
+        this.sender = sender;
+        this.subject = subject;
+        this.to = to;
+    }
+
+    public Address[] getBcc() {
+        return bcc;
+    }
+
+    public Address[] getCc() {
+        return cc;
+    }
+
+    public String getDate() {
+        return date;
+    }
+
+    public Address[] getFrom() {
+        return from;
+    }
+
+    public String getInReplyTo() {
+        return inReplyTo;
+    }
+
+    public String getMessageId() {
+        return messageId;
+    }
+
+    public Address[] getReplyTo() {
+        return replyTo;
+    }
+
+    public Address[] getSender() {
+        return sender;
+    }
+
+    public String getSubject() {
+        return subject;
+    }
+
+    public Address[] getTo() {
+        return to;
+    }
+}
\ No newline at end of file



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