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/02/09 18:41:55 UTC
svn commit: r620163 - in /james/server/trunk:
core-library/src/main/java/org/apache/james/mailboxmanager/
core-library/src/main/java/org/apache/james/mailboxmanager/impl/
core-library/src/test/java/org/apache/james/mailboxmanager/
imap-api/src/main/jav...
Author: rdonkin
Date: Sat Feb 9 09:41:53 2008
New Revision: 620163
URL: http://svn.apache.org/viewvc?rev=620163&view=rev
Log:
Decode fetch body commands in the codec.
Added:
james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoder.java
james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoderTest.java
Modified:
james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResult.java
james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResultUtils.java
james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/FetchGroupImpl.java
james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/MessageResultImpl.java
james/server/trunk/core-library/src/test/java/org/apache/james/mailboxmanager/MessageResultImplIncludedResultsTest.java
james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/ImapConstants.java
james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/message/BodyFetchElement.java
james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/imap4rev1/FetchCommandParser.java
james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/FetchProcessor.java
james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/FetchCommand.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/OrFetchGroup.java
james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueResultIterator.java
Modified: james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResult.java
URL: http://svn.apache.org/viewvc/james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResult.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResult.java (original)
+++ james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResult.java Sat Feb 9 09:41:53 2008
@@ -86,23 +86,21 @@
public static final int BODY_CONTENT = 0x400;
/**
- * Contents to be retu
- * @return
+ * Contents to be fetched.
+ * Composed bitwise.
+ *
+ * @return bitwise descripion
+ * @see #MINIMAL
+ * @see #MIME_MESSAGE
+ * @see #KEY
+ * @see #SIZE
+ * @see #INTERNAL_DATE
+ * @see #FLAGS
+ * @see #HEADERS
+ * @see #FULL_CONTENT
+ * @see #BODY_CONTENT
*/
public int content();
-
- /**
- * Mime parts to be included in the results.
- * @return array of mime parts numbered from one,
- * or null
- */
- public int[] mimeParts();
-
- /**
- * Mime headers to be included in the results.
- * @return array of mime headers numbered from one
- */
- public int[] mimeHeaders();
}
/**
@@ -154,9 +152,21 @@
Iterator iterateHeaders() throws MailboxManagerException;
/**
+ * Iterates the MIME headers for the given
+ * part in a multipart message.
+ * @param path describing the part's position within
+ * a multipart message
+ * @return <code>Header</code> <code>Iterator</code>,
+ * or null when {@link FetchGroup#mimeHeaders()} does not
+ * include the index and when the mime part cannot be found
+ * @throws MailboxManagerException
+ */
+ Iterator iterateHeaders(MimePath path) throws MailboxManagerException;
+
+ /**
* A header.
*/
- public interface Header extends Content{
+ public interface Header extends Content {
/**
* Gets the name of this header.
@@ -180,16 +190,37 @@
* or or null if {@link FetchGroup#FULL_CONTENT} has not been included in the
* results
*/
- Content getFullMessage() throws MailboxManagerException;
+ Content getFullContent() throws MailboxManagerException;
+
/**
+ * Gets the full content of the given mime part.
+ * @param path describes the part
+ * @return <code>Content</code>,
+ * or null when {@link FetchGroup#mimeBodies()} did not been include
+ * the given index and when the mime part cannot be found
+ * @throws MailboxManagerException
+ */
+ Content getFullContent(MimePath path) throws MailboxManagerException;
+
+ /**
* Gets the body of the message excluding headers.
* The message data should have normalised line endings (CRLF).
* @return <code>Content</code>,
* or or null if {@link FetchGroup#FULL_CONTENT} has not been included in the
* results
*/
- Content getMessageBody() throws MailboxManagerException;
+ Content getBody() throws MailboxManagerException;
+
+ /**
+ * Gets the body of the given mime part.
+ * @param path describes the part
+ * @return <code>Content</code>,
+ * or null when {@link FetchGroup#mimeBodies()} did not been include
+ * the given index and when the mime part cannot be found
+ * @throws MailboxManagerException
+ */
+ Content getBody(MimePath path) throws MailboxManagerException;
/**
* IMAP needs to know the size of the content before it starts to write it out.
@@ -217,5 +248,17 @@
* @throws MessagingException
*/
public long size();
+ }
+
+ /**
+ * Describes a path within a multipart MIME message.
+ */
+ public interface MimePath {
+
+ /**
+ * Gets the positions of each part in the path.
+ * @return part positions describing the path
+ */
+ public int[] getPositions();
}
}
Modified: james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResultUtils.java
URL: http://svn.apache.org/viewvc/james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResultUtils.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResultUtils.java (original)
+++ james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/MessageResultUtils.java Sat Feb 9 09:41:53 2008
@@ -20,6 +20,7 @@
package org.apache.james.mailboxmanager;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.List;
@@ -66,6 +67,56 @@
results.add(header);
break;
}
+ }
+ }
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Gets header lines whose header names matches (ignoring case)
+ * any of those given.
+ * @param names header names to be matched, not null
+ * @param iterator {@link MessageResult.Header} <code>Iterator</code>
+ * @return <code>List</code> of <code>MessageResult.Header</code>'s,
+ * in their natural order
+ * @throws MessagingException
+ */
+ public static List getMatching(final Collection names, final Iterator iterator) throws MessagingException {
+ final List results = new ArrayList(names.size());
+ if (iterator != null) {
+ while(iterator.hasNext()) {
+ MessageResult.Header header = (MessageResult.Header) iterator.next();
+ final String headerName = header.getName();
+ if (headerName != null) {
+ if (names.contains(headerName)) {
+ results.add(header);
+ }
+ }
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Gets header lines whose header names matches (ignoring case)
+ * any of those given.
+ * @param names header names to be matched, not null
+ * @param iterator {@link MessageResult.Header} <code>Iterator</code>
+ * @return <code>List</code> of <code>MessageResult.Header</code>'s,
+ * in their natural order
+ * @throws MessagingException
+ */
+ public static List getNotMatching(final Collection names, final Iterator iterator) throws MessagingException {
+ final List results = new ArrayList(names.size());
+ if (iterator != null) {
+ while(iterator.hasNext()) {
+ MessageResult.Header header = (MessageResult.Header) iterator.next();
+ final String headerName = header.getName();
+ if (headerName != null) {
+ if (!names.contains(headerName)) {
+ results.add(header);
}
}
}
Modified: james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/FetchGroupImpl.java
URL: http://svn.apache.org/viewvc/james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/FetchGroupImpl.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/FetchGroupImpl.java (original)
+++ james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/FetchGroupImpl.java Sat Feb 9 09:41:53 2008
@@ -74,7 +74,7 @@
return mimeHeaders;
}
- public int[] mimeParts() {
+ public int[] mimeBodies() {
return mimeParts;
}
Modified: james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/MessageResultImpl.java
URL: http://svn.apache.org/viewvc/james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/MessageResultImpl.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/MessageResultImpl.java (original)
+++ james/server/trunk/core-library/src/main/java/org/apache/james/mailboxmanager/impl/MessageResultImpl.java Sat Feb 9 09:41:53 2008
@@ -44,10 +44,10 @@
private Date internalDate;
private String key;
private List headers;
- private Content messageBody;
- private Content fullMessage;
+ private Content body;
+ private Content fullContent;
private int includedResults = FetchGroup.MINIMAL;
-
+
public MessageResultImpl(long uid) {
setUid(uid);
}
@@ -81,10 +81,10 @@
setHeaders(IteratorUtils.toList(result.iterateHeaders()));
}
if (MessageResultUtils.isFullContentIncluded(result)) {
- setFullMessage(result.getFullMessage());
+ setFullContent(result.getFullContent());
}
if (MessageResultUtils.isBodyContentIncluded(result)) {
- setMessageBody(result.getMessageBody());
+ setBody(result.getBody());
}
}
@@ -188,23 +188,23 @@
}
}
- public final Content getFullMessage() {
- return fullMessage;
+ public final Content getFullContent() {
+ return fullContent;
}
- public final void setFullMessage(Content fullMessage) {
- this.fullMessage = fullMessage;
+ public final void setFullContent(Content fullMessage) {
+ this.fullContent = fullMessage;
if (fullMessage != null) {
includedResults |= FetchGroup.FULL_CONTENT;
}
}
- public final Content getMessageBody() {
- return messageBody;
+ public final Content getBody() {
+ return body;
}
- public final void setMessageBody(Content messageBody) {
- this.messageBody = messageBody;
+ public final void setBody(Content messageBody) {
+ this.body = messageBody;
if (messageBody != null) {
includedResults |= FetchGroup.BODY_CONTENT;
}
@@ -230,6 +230,18 @@
+ " )";
return retValue;
+ }
+
+ public Content getBody(MimePath path) throws MailboxManagerException {
+ throw new MailboxManagerException("Unsupported operation");
+ }
+
+ public Content getFullContent(MimePath path) throws MailboxManagerException {
+ throw new MailboxManagerException("Unsupported operation");
+ }
+
+ public Iterator iterateHeaders(MimePath path) throws MailboxManagerException {
+ throw new MailboxManagerException("Unsupported operation");
}
Modified: james/server/trunk/core-library/src/test/java/org/apache/james/mailboxmanager/MessageResultImplIncludedResultsTest.java
URL: http://svn.apache.org/viewvc/james/server/trunk/core-library/src/test/java/org/apache/james/mailboxmanager/MessageResultImplIncludedResultsTest.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/core-library/src/test/java/org/apache/james/mailboxmanager/MessageResultImplIncludedResultsTest.java (original)
+++ james/server/trunk/core-library/src/test/java/org/apache/james/mailboxmanager/MessageResultImplIncludedResultsTest.java Sat Feb 9 09:41:53 2008
@@ -104,18 +104,18 @@
}
public void testShouldIncludedResultsWhenFullMessageSet() throws Exception {
- result.setFullMessage(null);
+ result.setFullContent(null);
assertEquals(FetchGroup.MINIMAL, result.getIncludedResults().content());
- result.setFullMessage(content);
+ result.setFullContent(content);
assertEquals(FetchGroup.FULL_CONTENT, result.getIncludedResults().content());
result = new MessageResultImpl(this.result);
assertEquals(FetchGroup.FULL_CONTENT, result.getIncludedResults().content());
}
public void testShouldIncludedResultsWhenMessageBodySet() throws Exception {
- result.setMessageBody(null);
+ result.setBody(null);
assertEquals(FetchGroup.MINIMAL, result.getIncludedResults().content());
- result.setMessageBody(content);
+ result.setBody(content);
assertEquals(FetchGroup.BODY_CONTENT, result.getIncludedResults().content());
result = new MessageResultImpl(this.result);
assertEquals(FetchGroup.BODY_CONTENT, result.getIncludedResults().content());
@@ -129,11 +129,11 @@
result.setUid(99);
assertEquals(FetchGroup.FLAGS, result.getIncludedResults().content());
assertTrue(MessageResultUtils.isFlagsIncluded(result));
- result.setMessageBody(content);
+ result.setBody(content);
assertEquals(FetchGroup.FLAGS | FetchGroup.BODY_CONTENT, result.getIncludedResults().content());
assertTrue(MessageResultUtils.isFlagsIncluded(result));
assertTrue(MessageResultUtils.isBodyContentIncluded(result));
- result.setFullMessage(content);
+ result.setFullContent(content);
assertEquals(FetchGroup.FLAGS |
FetchGroup.BODY_CONTENT | FetchGroup.FULL_CONTENT, result.getIncludedResults().content());
assertTrue(MessageResultUtils.isFlagsIncluded(result));
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=620163&r1=620162&r2=620163&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 Sat Feb 9 09:41:53 2008
@@ -108,4 +108,11 @@
public static final String NAME_ATTRIBUTE_NOSELECT = "\\Noselect";
public static final String NAME_ATTRIBUTE_MARKED = "\\Marked";
public static final String NAME_ATTRIBUTE_UNMARKED = "\\Unmarked";
+
+ public static final String PS_TEXT = "TEXT";
+ public static final String PS_HEADER = "HEADER";
+ public static final String PS_MIME = "MIME";
+ 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";
}
Modified: james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/message/BodyFetchElement.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/message/BodyFetchElement.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/message/BodyFetchElement.java (original)
+++ james/server/trunk/imap-api/src/main/java/org/apache/james/api/imap/message/BodyFetchElement.java Sat Feb 9 09:41:53 2008
@@ -18,23 +18,80 @@
****************************************************************/
package org.apache.james.api.imap.message;
+import java.util.Collection;
+
+import org.apache.james.api.imap.ImapConstants;
+
public class BodyFetchElement
{
- private String name;
- private String sectionIdentifier;
- public BodyFetchElement( String name, String sectionIdentifier)
- {
- this.name = name;
- this.sectionIdentifier = sectionIdentifier;
+ public static final int TEXT = 0;
+ public static final int MIME = 1;
+ public static final int HEADER = 2;
+ public static final int HEADER_FIELDS = 3;
+ public static final int HEADER_NOT_FIELDS = 4;
+ public static final int CONTENT = 5;
+
+ private static final BodyFetchElement rfc822 = new BodyFetchElement(ImapConstants.FETCH_RFC822, CONTENT, null, null);
+ private static final BodyFetchElement rfc822Header = new BodyFetchElement(ImapConstants.FETCH_RFC822_HEADER, HEADER, null, null);
+ private static final BodyFetchElement rfc822Text = new BodyFetchElement(ImapConstants.FETCH_RFC822_TEXT, TEXT, null, null);
+
+ public static final BodyFetchElement createRFC822() {
+ return rfc822;
+ }
+
+ public static final BodyFetchElement createRFC822Header() {
+ return rfc822Header;
}
+
+ public static final BodyFetchElement createRFC822Text() {
+ return rfc822Text;
+ }
+
+
+ private final String name;
+ private final int sectionType;
+ private final int[] path;
+ private final Collection fieldNames;
- public String getParameters()
+ public BodyFetchElement( final String name, final int sectionType,
+ final int[] path, final Collection fieldNames)
{
- return this.sectionIdentifier;
+ this.name = name;
+ this.sectionType = sectionType;
+ this.fieldNames = fieldNames;
+ this.path = path;
}
-
+
public String getResponseName() {
return this.name;
+ }
+
+ /**
+ * Gets field names.
+ * @return <code>String</code> collection, when {@link #HEADER_FIELDS}
+ * or {@link #HEADER_NOT_FIELDS}
+ * or null otherwise
+ */
+ public final Collection getFieldNames() {
+ return fieldNames;
+ }
+
+ /**
+ * Gets the MIME path.
+ * @return the path,
+ * or null if the section is the base message
+ */
+ public final int[] getPath() {
+ return path;
+ }
+
+ /**
+ * Gets the type of section.
+ * @return {@link #HEADER_FIELDS}, {@link #TEXT}, {@link #CONTENT}, {@link #HEADER},
+ * {@link #MIME} or {@link #HEADER_NOT_FIELDS}
+ */
+ public final int getSectionType() {
+ return sectionType;
}
}
Added: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoder.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoder.java?rev=620163&view=auto
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoder.java (added)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoder.java Sat Feb 9 09:41:53 2008
@@ -0,0 +1,461 @@
+/****************************************************************
+ * 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.codec.decode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.james.api.imap.ProtocolException;
+
+
+public class FetchPartPathDecoder {
+
+ public static final int TEXT = 0;
+ public static final int MIME = 1;
+ public static final int HEADER = 2;
+ public static final int HEADER_FIELDS = 3;
+ public static final int HEADER_NOT_FIELDS = 4;
+ public static final int CONTENT = 5;
+ /** Going to need to make one array copy so might as well ensure plenty of space */
+ private static final int ARRAY_INCREMENT = 20;
+ /** Embedded RFC882 mesages are rare so start size one array */
+ private static final int ARRAY_INITIAL_SIZE = 1;
+
+ private int sectionType;
+ private int[] path;
+ private int partial;
+ private int used;
+ private List names;
+
+ public FetchPartPathDecoder() {}
+
+ public int decode(final CharSequence sectionSpecification) throws ProtocolException {
+ init();
+ sectionType = decode(0, sectionSpecification);
+ prunePath();
+ return sectionType;
+ }
+
+ private void prunePath() {
+ if (path != null) {
+ final int length = path.length;
+ if (used < length) {
+ final int[] newPath = new int[used];
+ System.arraycopy(path, 0, newPath, 0, used);
+ path = newPath;
+ }
+ }
+ }
+
+ private int decode(final int at, final CharSequence sectionSpecification) throws ProtocolException {
+ final int result;
+ final int length = sectionSpecification.length();
+ if (at<length)
+ {
+ final char next = sectionSpecification.charAt(at);
+ switch (next) {
+ case '.':
+ separator();
+ result = decode(at + 1, sectionSpecification);
+ break;
+
+ case '0':
+ result = digit(at, sectionSpecification, 0);
+ break;
+
+ case '1':
+ result = digit(at, sectionSpecification, 1);
+ break;
+
+ case '2':
+ result = digit(at, sectionSpecification, 2);
+ break;
+
+ case '3':
+ result = digit(at, sectionSpecification, 3);
+ break;
+
+ case '4':
+ result = digit(at, sectionSpecification, 4);
+ break;
+
+ case '5':
+ result = digit(at, sectionSpecification, 5);
+ break;
+
+ case '6':
+ result = digit(at, sectionSpecification, 6);
+ break;
+
+ case '7':
+ result = digit(at, sectionSpecification, 7);
+ break;
+
+ case '8':
+ result = digit(at, sectionSpecification, 8);
+ break;
+
+ case '9':
+ result = digit(at, sectionSpecification, 9);
+ break;
+
+ case 't':
+ case 'T':
+ result = text(at, sectionSpecification);
+ break;
+
+ case 'h':
+ case 'H':
+ result = header(at, sectionSpecification);
+ break;
+
+ case 'm':
+ case 'M':
+ result = mime(at, sectionSpecification);
+ break;
+
+ default:
+ throw new ProtocolException("Did not expect '" + next + "' here in body specification.");
+ }
+ } else {
+ storePartial();
+ result = CONTENT;
+ }
+ return result;
+ }
+
+
+ private int mime(int at, CharSequence sectionSpecification) throws ProtocolException {
+ if (sectionSpecification.length() == at+4) {
+ mustBeI(sectionSpecification, at+1);
+ mustBeM(sectionSpecification, at+2);
+ mustBeE(sectionSpecification, at+3);
+ storePartial();
+ } else {
+ throw new ProtocolException("Unknown body specification");
+ }
+ return MIME;
+ }
+
+ private void mustBeI(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char i = sectionSpecification.charAt(position);
+ if (!(i == 'i'|| i == 'I')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeM(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'm' || next == 'M')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeN(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'n' || next == 'N')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeO(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'o' || next == 'O')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeE(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'e' || next == 'E')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeA(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'a' || next == 'A')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeD(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'd' || next == 'D')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeR(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'r' || next == 'R')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeX(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'x' || next == 'X')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeT(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 't' || next == 'T')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeF(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'f' || next == 'F')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeL(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 'l' || next == 'L')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeS(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == 's' || next == 'S')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeDot(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == '.')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private void mustBeOpenParen(CharSequence sectionSpecification, int position) throws ProtocolException {
+ final char next = sectionSpecification.charAt(position);
+ if (!(next == '(')) {
+ throw new ProtocolException("Unknown body specification");
+ }
+ }
+
+ private int header(int at, CharSequence sectionSpecification) throws ProtocolException {
+ final int result;
+ final int length = sectionSpecification.length();
+ if (length > at+5) {
+ mustBeE(sectionSpecification, at+1);
+ mustBeA(sectionSpecification, at+2);
+ mustBeD(sectionSpecification, at+3);
+ mustBeE(sectionSpecification, at+4);
+ mustBeR(sectionSpecification, at+5);
+ storePartial();
+ if (length == at+6) {
+ result = HEADER;
+ } else {
+ result = headerFields(at+6, sectionSpecification);
+ }
+ } else {
+ throw new ProtocolException("Unknown body specification");
+ }
+ return result;
+ }
+
+ private int headerFields(int at, CharSequence sectionSpecification) throws ProtocolException {
+ final int result;
+ final int length = sectionSpecification.length();
+ if (length > at + 7) {
+ mustBeDot(sectionSpecification, at);
+ mustBeF(sectionSpecification, at + 1);
+ mustBeI(sectionSpecification, at + 2);
+ mustBeE(sectionSpecification, at + 3);
+ mustBeL(sectionSpecification, at + 4);
+ mustBeD(sectionSpecification, at + 5);
+ mustBeS(sectionSpecification, at + 6);
+ final char next = sectionSpecification.charAt(at + 7);
+ final int namesStartAt;
+ switch (next) {
+ case ' ':
+ result = HEADER_FIELDS;
+ namesStartAt = skipSpaces(at + 7, sectionSpecification);
+ break;
+ case '.':
+ if (length > at + 10) {
+ mustBeN(sectionSpecification, at + 8);
+ mustBeO(sectionSpecification, at + 9);
+ mustBeT(sectionSpecification, at + 10);
+ result = HEADER_NOT_FIELDS;
+ namesStartAt = skipSpaces(at + 11, sectionSpecification);
+ } else {
+ throw new ProtocolException("Unknown body specification");
+ }
+ break;
+ default:
+ throw new ProtocolException("Unknown body specification");
+ }
+ mustBeOpenParen(sectionSpecification, namesStartAt);
+ readHeaderNames(namesStartAt + 1, sectionSpecification);
+
+ } else {
+ throw new ProtocolException("Unknown body specification");
+ }
+ return result;
+ }
+
+ private void readHeaderNames(final int at, final CharSequence sectionSpecification) throws ProtocolException {
+ names = new ArrayList();
+ final int firstWordStart = skipSpaces(at, sectionSpecification);
+ readHeaderNames(firstWordStart, firstWordStart, sectionSpecification);
+ }
+
+ private void readHeaderNames(final int at, final int lastWordStart, final CharSequence sectionSpecification) throws ProtocolException {
+ if (at < sectionSpecification.length()) {
+ final char next = sectionSpecification.charAt(at);
+ switch (next) {
+ case ' ':
+ readName(lastWordStart, at, sectionSpecification);
+ final int nextWord = skipSpaces(at, sectionSpecification);
+ readHeaderNames(nextWord, nextWord, sectionSpecification);
+ break;
+ case ')':
+ readName(lastWordStart, at, sectionSpecification);
+ break;
+ default:
+ readHeaderNames(at + 1, lastWordStart, sectionSpecification);
+ }
+ } else {
+ throw new ProtocolException("Closing parenthesis missing.");
+ }
+ }
+
+ private void readName(final int wordStart, final int wordFinish, final CharSequence sectionSpecification) {
+ if (wordStart <= wordFinish) {
+ final CharSequence word = sectionSpecification.subSequence(wordStart, wordFinish);
+ final String name = word.toString();
+ names.add(name);
+ }
+ }
+
+ private int skipSpaces(final int at, final CharSequence sectionSpecification) {
+ final int result;
+ if (at < sectionSpecification.length()) {
+ final char next = sectionSpecification.charAt(at);
+ if (next == ' ') {
+ result = skipSpaces(at+1, sectionSpecification);
+ } else {
+ result = at;
+ }
+ } else {
+ result = at;
+ }
+ return result;
+ }
+
+ private int text(int at, CharSequence sectionSpecification) throws ProtocolException {
+ if (sectionSpecification.length() == at+4) {
+ mustBeE(sectionSpecification, at+1);
+ mustBeX(sectionSpecification, at+2);
+ mustBeT(sectionSpecification, at+3);
+ storePartial();
+ } else {
+ throw new ProtocolException("Unknown body specification");
+ }
+ return TEXT;
+ }
+
+ private int digit(final int at, final CharSequence sectionSpecification, int digit) throws ProtocolException {
+ final int result;
+ digit(digit);
+ result = decode(at + 1, sectionSpecification);
+ return result;
+ }
+
+ private void init() {
+ sectionType = CONTENT;
+ resetPartial();
+ path = null;
+ used = 0;
+ names = null;
+ }
+
+ private void resetPartial() {
+ partial = 0;
+ }
+
+ private void separator() {
+ storePartial();
+ }
+
+ private void storePartial() {
+ if (partial > 0) {
+ ensureSpaceForOneInPath();
+ path[used++] = partial;
+ resetPartial();
+ }
+ }
+
+ private void ensureSpaceForOneInPath() {
+ if (path == null) {
+ path = new int[ARRAY_INITIAL_SIZE];
+ } else {
+ final int length = path.length;
+ if (used >= length) {
+ int[] newPath = new int[length + ARRAY_INCREMENT];
+ System.arraycopy(path, 0, newPath, 0, length);
+ path = newPath;
+ }
+ }
+ }
+
+ private void digit(int digit) {
+ partial = (partial * 10) + digit;
+ }
+
+ /**
+ * Gets the decoded path.
+ * @return the path
+ */
+ public final int[] getPath() {
+ return path;
+ }
+
+ /**
+ * Gets the
+ * @return {@link #TEXT}, {@link #MIME}, {@link #HEADER}, {@link #HEADER_FIELDS},
+ * {@link #HEADER_NOT_FIELDS} or {@link #CONTENT}
+ */
+ public final int getSpecifier() {
+ return sectionType;
+ }
+
+ /**
+ * Gets field names.
+ * @return <code>List</code> of <code>String</code> names when
+ * {@link #HEADER_FIELDS} or {@link #HEADER_NOT_FIELDS},
+ * null otherwise
+ */
+ public final List getNames() {
+ return names;
+ }
+
+
+}
Modified: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/imap4rev1/FetchCommandParser.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/imap4rev1/FetchCommandParser.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/imap4rev1/FetchCommandParser.java (original)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/imap4rev1/FetchCommandParser.java Sat Feb 9 09:41:53 2008
@@ -18,6 +18,8 @@
****************************************************************/
package org.apache.james.imapserver.codec.decode.imap4rev1;
+import java.util.List;
+
import org.apache.james.api.imap.ImapCommand;
import org.apache.james.api.imap.ImapMessage;
import org.apache.james.api.imap.ProtocolException;
@@ -26,6 +28,7 @@
import org.apache.james.api.imap.message.BodyFetchElement;
import org.apache.james.api.imap.message.FetchData;
import org.apache.james.api.imap.message.IdRange;
+import org.apache.james.imapserver.codec.decode.FetchPartPathDecoder;
import org.apache.james.imapserver.codec.decode.ImapRequestLineReader;
import org.apache.james.imapserver.codec.decode.InitialisableCommandFactory;
@@ -114,11 +117,11 @@
} else if ("UID".equalsIgnoreCase(name)) {
fetch.setUid(true);
} else if ("RFC822".equalsIgnoreCase(name)) {
- fetch.add(new BodyFetchElement("RFC822", ""), false);
+ fetch.add(BodyFetchElement.createRFC822(), false);
} else if ("RFC822.HEADER".equalsIgnoreCase(name)) {
- fetch.add(new BodyFetchElement("RFC822.HEADER", "HEADER"), true);
+ fetch.add(BodyFetchElement.createRFC822Header(), true);
} else if ("RFC822.TEXT".equalsIgnoreCase(name)) {
- fetch.add(new BodyFetchElement("RFC822.TEXT", "TEXT"), false);
+ fetch.add(BodyFetchElement.createRFC822Text(), false);
} else {
throw new ProtocolException( "Invalid fetch attribute: " + name );
}
@@ -126,19 +129,68 @@
else {
consumeChar( command, '[' );
-
String parameter = readWord(command, "]");
consumeChar( command, ']');
- 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 + "[]" );
- }
+
+ final BodyFetchElement bodyFetchElement = createBodyElement(parameter);
+ final boolean isPeek = isPeek(name);
+ fetch.add(bodyFetchElement, isPeek);
}
}
+
+ private boolean isPeek(String name) throws ProtocolException {
+ final boolean isPeek;
+ if ( "BODY".equalsIgnoreCase( name ) ) {
+ isPeek = false;
+ } else if ( "BODY.PEEK".equalsIgnoreCase( name ) ) {
+ isPeek = true;
+ } else {
+ throw new ProtocolException( "Invalid fetch attibute: " + name + "[]" );
+ }
+ return isPeek;
+ }
+
+ private BodyFetchElement createBodyElement(String parameter) throws ProtocolException {
+ final String responseName = "BODY[" + parameter + "]";
+ FetchPartPathDecoder decoder = new FetchPartPathDecoder();
+ decoder.decode(parameter);
+ final int sectionType = getSectionType(decoder);
+
+ final List names = decoder.getNames();
+ final int[] path = decoder.getPath();
+ final BodyFetchElement bodyFetchElement
+ = new BodyFetchElement(responseName, sectionType, path, names);
+ return bodyFetchElement;
+ }
+
+ private int getSectionType(FetchPartPathDecoder decoder) throws ProtocolException {
+ final int specifier = decoder.getSpecifier();
+ final int sectionType;
+ switch (specifier) {
+ case FetchPartPathDecoder.CONTENT:
+ sectionType = BodyFetchElement.CONTENT;
+ break;
+ case FetchPartPathDecoder.HEADER:
+ sectionType = BodyFetchElement.HEADER;
+ break;
+ case FetchPartPathDecoder.HEADER_FIELDS:
+ sectionType = BodyFetchElement.HEADER_FIELDS;
+ break;
+ case FetchPartPathDecoder.HEADER_NOT_FIELDS:
+ sectionType = BodyFetchElement.HEADER_NOT_FIELDS;
+ break;
+ case FetchPartPathDecoder.MIME:
+ sectionType = BodyFetchElement.MIME;
+ break;
+ case FetchPartPathDecoder.TEXT:
+ sectionType = BodyFetchElement.TEXT;
+ break;
+ default:
+ throw new ProtocolException("Section type is unsupported.");
+ }
+ return sectionType;
+ }
private String readWord(ImapRequestLineReader request, String terminator) throws ProtocolException {
StringBuffer buf = new StringBuffer();
Added: james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoderTest.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoderTest.java?rev=620163&view=auto
==============================================================================
--- james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoderTest.java (added)
+++ james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/FetchPartPathDecoderTest.java Sat Feb 9 09:41:53 2008
@@ -0,0 +1,201 @@
+/****************************************************************
+ * 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.codec.decode;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.james.api.imap.ProtocolException;
+
+import junit.framework.TestCase;
+
+public class FetchPartPathDecoderTest extends TestCase {
+
+ FetchPartPathDecoder decoder;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ decoder = new FetchPartPathDecoder();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testShouldDetectText() throws Exception {
+ assertEquals(FetchPartPathDecoder.TEXT, decoder.decode("TEXT"));
+ assertEquals(FetchPartPathDecoder.TEXT, decoder.decode("3.TEXT"));
+ assertEquals(FetchPartPathDecoder.TEXT, decoder.decode("3.1.TEXT"));
+ assertEquals(FetchPartPathDecoder.TEXT, decoder.decode("3.2.5.7.8.TEXT"));
+ }
+
+ public void testShouldDetectHeader() throws Exception {
+ assertEquals(FetchPartPathDecoder.HEADER, decoder.decode("HEADER"));
+ assertEquals(FetchPartPathDecoder.HEADER, decoder.decode("4.HEADER"));
+ assertEquals(FetchPartPathDecoder.HEADER, decoder.decode("10.1.HEADER"));
+ assertEquals(FetchPartPathDecoder.HEADER, decoder.decode("8.3.5.11.HEADER"));
+ }
+
+ public void testShouldDetectHeaderFields() throws Exception {
+ assertEquals(FetchPartPathDecoder.HEADER_FIELDS, decoder.decode("HEADER.FIELDS ()"));
+ assertEquals(FetchPartPathDecoder.HEADER_FIELDS, decoder.decode("4.HEADER.FIELDS ()"));
+ assertEquals(FetchPartPathDecoder.HEADER_FIELDS, decoder.decode("10.1.HEADER.FIELDS ()"));
+ assertEquals(FetchPartPathDecoder.HEADER_FIELDS, decoder.decode("8.3.5.11.HEADER.FIELDS ()"));
+ }
+
+ public void testShouldDetectHeaderFieldsNot() throws Exception {
+ assertEquals(FetchPartPathDecoder.HEADER_NOT_FIELDS, decoder.decode("HEADER.FIELDS.NOT ()"));
+ assertEquals(FetchPartPathDecoder.HEADER_NOT_FIELDS, decoder.decode("4.HEADER.FIELDS.NOT ()"));
+ assertEquals(FetchPartPathDecoder.HEADER_NOT_FIELDS, decoder.decode("10.1.HEADER.FIELDS.NOT ()"));
+ assertEquals(FetchPartPathDecoder.HEADER_NOT_FIELDS, decoder.decode("8.3.5.11.HEADER.FIELDS.NOT ()"));
+ }
+
+ public void testShouldDetectMime() throws Exception {
+ assertEquals(FetchPartPathDecoder.MIME, decoder.decode("MIME"));
+ assertEquals(FetchPartPathDecoder.MIME, decoder.decode("6.MIME"));
+ assertEquals(FetchPartPathDecoder.MIME, decoder.decode("2.88.MIME"));
+ assertEquals(FetchPartPathDecoder.MIME, decoder.decode("32.3.15.11.MIME"));
+ }
+
+ public void testShouldDetectContent() throws Exception {
+ assertEquals(FetchPartPathDecoder.CONTENT, decoder.decode("34"));
+ assertEquals(FetchPartPathDecoder.CONTENT, decoder.decode("6"));
+ assertEquals(FetchPartPathDecoder.CONTENT, decoder.decode("9.88"));
+ assertEquals(FetchPartPathDecoder.CONTENT, decoder.decode("17.3.15.11"));
+ }
+
+ public void testShouldIgnoreCase() throws Exception {
+ assertEquals(FetchPartPathDecoder.MIME, decoder.decode("6.MIME"));
+ assertEquals(FetchPartPathDecoder.MIME, decoder.decode("6.mime"));
+ assertEquals(FetchPartPathDecoder.MIME, decoder.decode("6.miME"));
+ assertEquals(FetchPartPathDecoder.MIME, decoder.decode("6.MIme"));
+ assertEquals(FetchPartPathDecoder.HEADER, decoder.decode("6.HEADER"));
+ assertEquals(FetchPartPathDecoder.HEADER, decoder.decode("6.header"));
+ assertEquals(FetchPartPathDecoder.HEADER, decoder.decode("6.HEadER"));
+ assertEquals(FetchPartPathDecoder.HEADER, decoder.decode("6.heADEr"));
+ assertEquals(FetchPartPathDecoder.TEXT, decoder.decode("6.TEXT"));
+ assertEquals(FetchPartPathDecoder.TEXT, decoder.decode("6.text"));
+ assertEquals(FetchPartPathDecoder.TEXT, decoder.decode("6.TExt"));
+ assertEquals(FetchPartPathDecoder.TEXT, decoder.decode("6.teXT"));
+ }
+
+ public void testMimimalPath() throws Exception {
+ int[] values = {6};
+ checkEndingPermutations(values);
+ }
+
+ public void testLongPath() throws Exception {
+ int[] values = {3, 11, 345, 231, 11, 3, 1, 1, 1, 3, 8, 8};
+ checkEndingPermutations(values);
+ }
+
+ public void testShouldThrowProtocolExceptionWhenSpecifierBogus() throws Exception {
+ try {
+ decoder.decode("1.34.BOGUS");
+ fail("Expected protocol exception to be thrown");
+ } catch (ProtocolException e) {
+ // expected
+ }
+ }
+
+ public void testShouldThrowProtocolExceptionWhenPathBogus() throws Exception {
+ try {
+ decoder.decode("1.34.BOGUS.44.34234.324");
+ fail("Expected protocol exception to be thrown");
+ } catch (ProtocolException e) {
+ // expected
+ }
+ }
+
+ public void testShouldReadShortFieldNames() throws Exception {
+ String[] names = {"A", "B", "C", "D", "E", "F"};
+ checkReadNames("1.8.HEADER.FIELDS", names);
+ }
+
+ public void testShouldReadShortFieldNotNames() throws Exception {
+ String[] names = {"A", "B", "C", "D", "E", "F"};
+ checkReadNames("1.8.9.HEADER.FIELDS.NOT", names);
+ }
+
+
+ public void testShouldReadOneFieldNames() throws Exception {
+ String[] names = {"AFieldName"};
+ checkReadNames("1.8.HEADER.FIELDS", names);
+ }
+
+ public void testShouldReadOneFieldNotNames() throws Exception {
+ String[] names = {"AFieldName"};
+ checkReadNames("1.8.9.HEADER.FIELDS.NOT", names);
+ }
+
+ public void testShouldReadManyFieldNames() throws Exception {
+ String[] names = {"ONE", "TWO", "THREE", "FOUR", "FIVE", "345345"};
+ checkReadNames("1.8.HEADER.FIELDS", names);
+ }
+
+ public void testShouldReadManyFieldNotNames() throws Exception {
+ String[] names = {"ONE", "TWO", "THREE", "FOUR", "FIVE", "345345"};
+ checkReadNames("1.8.HEADER.FIELDS.NOT", names);
+ }
+
+ private void checkReadNames(String base, String[] names) throws Exception {
+ base = base + " (";
+ for (int i=0;i<names.length;i++) {
+ base = base + ' ' + names[i];
+ }
+ base = base + ')';
+ decoder.decode(base);
+ Collection results = decoder.getNames();
+ assertNotNull(results);
+ Iterator it = results.iterator();
+ for (int i=0;i<names.length;i++) {
+ assertEquals(names[i], it.next());
+ }
+ }
+
+ private void checkEndingPermutations(int[] values) throws Exception {
+ String base = "";
+ boolean first = true;
+ for (int i=0;i<values.length; i++) {
+ if (first) {
+ first = false;
+ } else {
+ base = base + ".";
+ }
+ base = base + values[i];
+ }
+ checkPath(values, base);
+ checkPath(values, base + ".TEXT");
+ checkPath(values, base + ".HEADER");
+ checkPath(values, base + ".MIME");
+ checkPath(values, base + ".HEADER.FIELDS.NOT ()");
+ checkPath(values, base + ".HEADER.FIELDS ()");
+ }
+
+ private void checkPath(int[] expected, String encoded) throws Exception {
+ decoder.decode(encoded);
+ final int[] path = decoder.getPath();
+ assertNotNull(path);
+ assertEquals(expected.length, path.length);
+ for (int i=0;i<expected.length; i++) {
+ assertEquals(expected[i], path[i]);
+ }
+ }
+}
Modified: james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/FetchProcessor.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/FetchProcessor.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/FetchProcessor.java (original)
+++ james/server/trunk/imap-mailbox-processor-function/src/main/java/org/apache/james/imapserver/processor/imap4rev1/FetchProcessor.java Sat Feb 9 09:41:53 2008
@@ -131,7 +131,7 @@
}
}
- private FetchGroup getFetchGroup(FetchData fetch) {
+ private FetchGroup getFetchGroup(FetchData fetch) throws ProtocolException {
int result = FetchGroup.MINIMAL;
if (fetch.isFlags() || fetch.isSetSeen()) {
result |= FetchGroup.FLAGS;
@@ -155,24 +155,27 @@
return new FetchGroupImpl(result);
}
- private int fetchForBodyElements(final Collection bodyElements) {
+ private int fetchForBodyElements(final Collection bodyElements) throws ProtocolException {
int result = 0;
if (bodyElements != null) {
for (final Iterator it = bodyElements.iterator(); it.hasNext();) {
final BodyFetchElement element = (BodyFetchElement) it.next();
- final String section = element.getParameters();
- if ("HEADER".equalsIgnoreCase(section)) {
- result |= FetchGroup.HEADERS;
- } else if (section.startsWith("HEADER.FIELDS.NOT ")) {
- result |= FetchGroup.HEADERS;
- } else if (section.startsWith("HEADER.FIELDS ")) {
- result |= FetchGroup.HEADERS;
- } else if (section.equalsIgnoreCase("TEXT")) {
- ;
- result |= FetchGroup.BODY_CONTENT;
- } else if (section.length() == 0) {
- result |= FetchGroup.FULL_CONTENT;
+ final int sectionType = element.getSectionType();
+ switch(sectionType) {
+ case BodyFetchElement.CONTENT:
+ result = result | MessageResult.FetchGroup.FULL_CONTENT;
+ break;
+ case BodyFetchElement.HEADER:
+ case BodyFetchElement.HEADER_NOT_FIELDS:
+ case BodyFetchElement.HEADER_FIELDS:
+ case BodyFetchElement.MIME:
+ result = result | MessageResult.FetchGroup.HEADERS;
+ break;
+ case BodyFetchElement.TEXT:
+ result = result | MessageResult.FetchGroup.BODY_CONTENT;
+ break;
}
+
}
}
return result;
@@ -238,9 +241,7 @@
result.getFlags().add(Flags.Flag.SEEN);
ensureFlagsResponse = true;
}
-
-
// FLAGS response
if (fetch.isFlags() || ensureFlagsResponse) {
setFlags(result.getFlags());
@@ -252,8 +253,6 @@
.getInternalDate());
}
- // TODO: RFC822.HEADER
-
// RFC822.SIZE response
if (fetch.isSize()) {
setSize(result.getSize());
@@ -292,10 +291,7 @@
this.elements = new ArrayList();
for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
BodyFetchElement fetchElement = (BodyFetchElement) iterator.next();
- final String sectionSpecifier = fetchElement.getParameters();
- final String responseName = fetchElement.getResponseName();
- final FetchResponse.BodyElement element
- = bodyFetch(result, sectionSpecifier, responseName);
+ final FetchResponse.BodyElement element = bodyFetch(result, fetchElement);
if (element != null) {
this.elements.add(element);
}
@@ -465,88 +461,123 @@
}
private FetchResponse.BodyElement bodyFetch(final MessageResult messageResult,
- String sectionSpecifier, String name) throws MessagingException {
+ BodyFetchElement fetchElement) throws MessagingException, ProtocolException {
+
final FetchResponse.BodyElement result;
- // TODO: section specifier should be fully parsed during parsing phase
- if (sectionSpecifier.length() == 0) {
- final MessageResult.Content fullMessage = messageResult.getFullMessage();
- result = new ContentBodyElement(name, fullMessage);
-
- } else if (sectionSpecifier.equalsIgnoreCase("HEADER")) {
- final Iterator headers = messageResult.iterateHeaders();
- List lines = MessageResultUtils.getAll(headers);
- result = new HeaderBodyElement(name, lines);
-
- } else if (sectionSpecifier.startsWith("HEADER.FIELDS.NOT ")) {
- String[] excludeNames = extractHeaderList(sectionSpecifier,
- "HEADER.FIELDS.NOT ".length());
- final Iterator headers = messageResult.iterateHeaders();
- List lines = MessageResultUtils.getNotMatching(excludeNames, headers);
- result = new HeaderBodyElement(name, lines);
-
- } else if (sectionSpecifier.startsWith("HEADER.FIELDS ")) {
- String[] includeNames = extractHeaderList(sectionSpecifier,
- "HEADER.FIELDS ".length());
- final Iterator headers = messageResult.iterateHeaders();
- List lines = MessageResultUtils.getMatching(includeNames, headers);
- result = new HeaderBodyElement(name, lines);
-
- } else if (sectionSpecifier.equalsIgnoreCase("MIME")) {
- // TODO implement
- throw new MailboxManagerException("MIME not yet implemented.");
-
- } else if (sectionSpecifier.equalsIgnoreCase("TEXT")) {
- final MessageResult.Content messageBody = messageResult.getMessageBody();
- result = new ContentBodyElement(name, messageBody);
+ final String name = fetchElement.getResponseName();
+ final int specifier = fetchElement.getSectionType();
+ final int[] path = fetchElement.getPath();
+ final Collection names = fetchElement.getFieldNames();
+ final boolean isBase = (path == null || path.length == 0);
+ switch (specifier) {
+ case BodyFetchElement.CONTENT:
+ result = content(messageResult, name, path, isBase);
+ break;
+
+ case BodyFetchElement.HEADER_FIELDS:
+ result = fields(messageResult, name, path, names, isBase);
+ break;
+
+ case BodyFetchElement.HEADER_NOT_FIELDS:
+ result = fieldsNot(messageResult, name, path, names, isBase);
+ break;
+
+ case BodyFetchElement.MIME:
+ case BodyFetchElement.HEADER:
+ result = headers(messageResult, name, path, isBase);
+ break;
+
+ case BodyFetchElement.TEXT:
+ result = text(messageResult, name, path, isBase);
+ break;
+
+ default:
+ result = null;
+ break;
+ }
+
+ return result;
+ }
+
+ private FetchResponse.BodyElement text(final MessageResult messageResult, String name, final int[] path, final boolean isBase) throws MailboxManagerException {
+ final FetchResponse.BodyElement result;
+ final MessageResult.Content body;
+ if (isBase) {
+ body = messageResult.getBody();
} 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 MailboxManagerException("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 MailboxManagerException(
- "Mime parts not yet implemented for fetch.");
+ MessageResult.MimePath mimePath = new MimePathImpl(path);
+ body = messageResult.getBody(mimePath);
}
+ result = new ContentBodyElement(name, body);
return result;
+ }
+ private FetchResponse.BodyElement headers(final MessageResult messageResult, String name, final int[] path, final boolean isBase) throws MailboxManagerException, MessagingException {
+ final FetchResponse.BodyElement result;
+ final Iterator headers = getHeaders(messageResult, path, isBase);
+ List lines = MessageResultUtils.getAll(headers);
+ result = new HeaderBodyElement(name, lines);
+ return result;
}
- // 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;
+ private FetchResponse.BodyElement fieldsNot(final MessageResult messageResult, String name,
+ final int[] path, Collection names, final boolean isBase) throws MailboxManagerException, MessagingException {
+ final FetchResponse.BodyElement result;
+
+ final Iterator headers = getHeaders(messageResult, path, isBase);
+
+ List lines = MessageResultUtils.getNotMatching(names, headers);
+ result = new HeaderBodyElement(name, lines);
+ return result;
+ }
+
+ private FetchResponse.BodyElement fields(final MessageResult messageResult, String name,
+ final int[] path, Collection names, final boolean isBase) throws MailboxManagerException, MessagingException {
+ final FetchResponse.BodyElement result;
+ final Iterator headers = getHeaders(messageResult, path, isBase);
+ List lines = MessageResultUtils.getMatching(names, headers);
+ result = new HeaderBodyElement(name, lines);
+ return result;
+ }
+
+ private Iterator getHeaders(final MessageResult messageResult, final int[] path, final boolean isBase) throws MailboxManagerException {
+ final Iterator headers;
+ if (isBase) {
+ headers = messageResult.iterateHeaders();
+ } else {
+ MessageResult.MimePath mimePath = new MimePathImpl(path);
+ headers = messageResult.iterateHeaders(mimePath);
}
- String sub = value.substring(startPos);
- strings.add(sub);
+ return headers;
+ }
- return (String[]) strings.toArray(new String[0]);
+ private FetchResponse.BodyElement content(final MessageResult messageResult, String name, final int[] path, final boolean isBase) throws MailboxManagerException {
+ final FetchResponse.BodyElement result;
+ final MessageResult.Content full;
+ if (isBase) {
+ full = messageResult.getFullContent();
+ } else {
+ MessageResult.MimePath mimePath = new MimePathImpl(path);
+ full = messageResult.getFullContent(mimePath);
+ }
+ result = new ContentBodyElement(name, full);
+ return result;
}
+ }
+
+ private static final class MimePathImpl implements MessageResult.MimePath {
+ private final int[] positions;
+
+ public MimePathImpl(final int[] positions) {
+ super();
+ this.positions = positions;
+ }
+
+ public int[] getPositions() {
+ return positions;
+ }
+
}
private static final class EnvelopeImpl implements FetchResponse.Envelope {
Modified: james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/FetchCommand.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/FetchCommand.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/FetchCommand.java (original)
+++ james/server/trunk/imapserver-function/src/main/java/org/apache/james/imapserver/commands/FetchCommand.java Sat Feb 9 09:41:53 2008
@@ -248,7 +248,7 @@
throws ProtocolException, MessagingException
{
if ( sectionSpecifier.length() == 0 ) {
- final Content fullMessage = result.getFullMessage();
+ final Content fullMessage = result.getFullContent();
addLiteralContent(fullMessage, response);
}
else if ( sectionSpecifier.equalsIgnoreCase( "HEADER" ) ) {
@@ -273,7 +273,7 @@
throw new ProtocolException( "MIME not yet implemented." );
}
else if ( sectionSpecifier.equalsIgnoreCase( "TEXT" ) ) {
- final Content messageBody = result.getMessageBody();
+ final Content messageBody = result.getBody();
addLiteralContent(messageBody, response);
}
else {
Modified: james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/MessageRowUtils.java
URL: http://svn.apache.org/viewvc/james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/MessageRowUtils.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/MessageRowUtils.java (original)
+++ james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/MessageRowUtils.java Sat Feb 9 09:41:53 2008
@@ -283,11 +283,11 @@
result -= FetchGroup.HEADERS;
}
if ((result & FetchGroup.BODY_CONTENT) > 0) {
- messageResult.setMessageBody(createBodyContent(messageRow));
+ messageResult.setBody(createBodyContent(messageRow));
result -= FetchGroup.BODY_CONTENT;
}
if ((result & FetchGroup.FULL_CONTENT) > 0) {
- messageResult.setFullMessage(createFullContent(messageRow, messageResult.getHeaders()));
+ messageResult.setFullContent(createFullContent(messageRow, messageResult.getHeaders()));
result -= FetchGroup.FULL_CONTENT;
}
if (result != 0) {
Modified: james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/OrFetchGroup.java
URL: http://svn.apache.org/viewvc/james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/OrFetchGroup.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/OrFetchGroup.java (original)
+++ james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/OrFetchGroup.java Sat Feb 9 09:41:53 2008
@@ -20,11 +20,13 @@
package org.apache.james.mailboxmanager.torque;
import org.apache.james.mailboxmanager.MessageResult.FetchGroup;
+import org.apache.james.mailboxmanager.MessageResult.MimePath;
/**
* Wraps a fetch group and ORs content.
*/
public final class OrFetchGroup implements FetchGroup {
+
private final FetchGroup delegate;
private final int or;
@@ -39,15 +41,8 @@
return or | delegate.content();
}
- public int[] mimeHeaders() {
- return delegate.mimeHeaders();
- }
-
- public int[] mimeParts() {
- return delegate.mimeParts();
- }
-
public String toString() {
return "Fetch " + or + " OR " + delegate;
}
+
}
Modified: james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueResultIterator.java
URL: http://svn.apache.org/viewvc/james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueResultIterator.java?rev=620163&r1=620162&r2=620163&view=diff
==============================================================================
--- james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueResultIterator.java (original)
+++ james/server/trunk/torque-mailboxmanager-function/src/main/java/org/apache/james/mailboxmanager/torque/TorqueResultIterator.java Sat Feb 9 09:41:53 2008
@@ -116,7 +116,7 @@
throw exception;
}
- public Content getFullMessage() throws MailboxManagerException{
+ public Content getFullContent() throws MailboxManagerException{
throw exception;
}
@@ -132,7 +132,7 @@
return null;
}
- public Content getMessageBody() throws MailboxManagerException {
+ public Content getBody() throws MailboxManagerException {
throw exception;
}
@@ -165,6 +165,18 @@
// Java 1.5 return (int) Math.signum(uid - that.getUid());
long diff = uid - that.getUid();
return (int) diff == 0 ? 0 : diff > 0 ? 1 : -1;
+ }
+
+ public Content getBody(MimePath path) throws MailboxManagerException {
+ throw exception;
+ }
+
+ public Content getFullContent(MimePath path) throws MailboxManagerException {
+ throw exception;
+ }
+
+ public Iterator iterateHeaders(MimePath path) throws MailboxManagerException {
+ throw exception;
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org