Author: norman
Date: Sun May 29 18:42:23 2011
New Revision: 1128932

URL: http://svn.apache.org/viewvc?rev=1128932&view=rev
Log:
Add support for the ESEARCH extension. See IMAP-308 and rfc4731

Added:
    
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchOperation.java
    
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchResultOption.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ESearchResponseEncoder.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ESearchResponse.java
Modified:
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SearchRequest.java
    
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
    
james/imap/trunk/processor/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java

Added: 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchOperation.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchOperation.java?rev=1128932&view=auto
==============================================================================
--- 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchOperation.java
 (added)
+++ 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchOperation.java
 Sun May 29 18:42:23 2011
@@ -0,0 +1,43 @@
+
+/****************************************************************
+ * 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.imap.api.message.request;
+
+import java.util.List;
+
+public final class SearchOperation {
+
+    private final SearchKey key;
+    private final List<SearchResultOption> options;
+
+    public SearchOperation(SearchKey key, List<SearchResultOption> options) {
+        this.key = key;
+        this.options = options;
+    }
+    
+    public SearchKey getSearchKey() {
+        return key;
+    }
+    public List<SearchResultOption> getResultOptions() {
+        return options;
+    }
+    
+ 
+    
+}

Added: 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchResultOption.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchResultOption.java?rev=1128932&view=auto
==============================================================================
--- 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchResultOption.java
 (added)
+++ 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchResultOption.java
 Sun May 29 18:42:23 2011
@@ -0,0 +1,45 @@
+/****************************************************************
+ * 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.imap.api.message.request;
+
+/**
+ * Represent ESEARCH result options. See RFC4731
+ *
+ */
+public enum SearchResultOption {
+    /**
+     * Return all matched message uids formatted as sequence-set
+     */
+    ALL,
+    
+    /**
+     * Return the minimum uid matched 
+     */
+    MIN,
+    
+    /**
+     * Return the maximum uid matched
+     */
+    MAX,
+    
+    /**
+     * Return the count of matched messages
+     */
+    COUNT
+}

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java?rev=1128932&r1=1128931&r2=1128932&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java
 Sun May 29 18:42:23 2011
@@ -22,6 +22,7 @@ import java.nio.charset.Charset;
 import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -35,6 +36,8 @@ import org.apache.james.imap.api.display
 import org.apache.james.imap.api.message.IdRange;
 import org.apache.james.imap.api.message.request.DayMonthYear;
 import org.apache.james.imap.api.message.request.SearchKey;
+import org.apache.james.imap.api.message.request.SearchOperation;
+import org.apache.james.imap.api.message.request.SearchResultOption;
 import org.apache.james.imap.api.message.response.StatusResponse;
 import org.apache.james.imap.api.message.response.StatusResponseFactory;
 import org.apache.james.imap.api.message.response.StatusResponse.ResponseCode;
@@ -109,6 +112,8 @@ public class SearchCommandParser extends
             case 'Q':
                 throw new 
DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
             case 'R':
+                nextIsE(request);
+                nextIsC(request);
                 return recent(request);
             case 'S':
                 return s(request, charset);
@@ -144,10 +149,14 @@ public class SearchCommandParser extends
 
     private int consumeAndCap(ImapRequestLineReader request) throws 
DecodingException {
         final char next = request.consume();
+        return cap(next);
+    }
+
+    private int cap(char next) {
         final int cap = next > 'Z' ? next ^ 32 : next;
         return cap;
     }
-
+    
     private SearchKey cc(ImapRequestLineReader request, final Charset charset) 
throws DecodingException {
         final SearchKey result;
         nextIsSpace(request);
@@ -545,8 +554,8 @@ public class SearchCommandParser extends
 
     private SearchKey recent(ImapRequestLineReader request) throws 
DecodingException {
         final SearchKey result;
-        nextIsE(request);
-        nextIsC(request);
+        //nextIsE(request);
+        //nextIsC(request);
         nextIsE(request);
         nextIsN(request);
         nextIsT(request);
@@ -887,6 +896,54 @@ public class SearchCommandParser extends
         }
     }
 
+    private List<SearchResultOption> parseOptions(ImapRequestLineReader 
reader) throws DecodingException {
+        List<SearchResultOption> options = new ArrayList<SearchResultOption>();
+        nextIs(reader, '(', '(');
+        reader.nextWordChar();
+        
+        int cap = consumeAndCap(reader);
+
+        while (cap != ')') {
+            switch (cap) {
+            case 'A':
+                nextIsL(reader);
+                nextIsL(reader);
+                options.add(SearchResultOption.ALL);
+
+            case 'C':
+                nextIsO(reader);
+                nextIsU(reader);
+                nextIsN(reader);
+                nextIsT(reader);
+                options.add(SearchResultOption.COUNT);
+                break;
+            case 'M':
+                final int c = consumeAndCap(reader);
+                switch (c) {
+                case 'A':
+                    nextIsX(reader);
+                    options.add(SearchResultOption.MAX);
+                    break;
+                case 'I':
+                    nextIsM(reader);
+                    options.add(SearchResultOption.MIN);
+                    break;
+                default:
+                    throw new 
DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
+                }
+            default:
+                throw new 
DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
+            }
+            reader.nextWordChar();
+            cap = consumeAndCap(reader);
+        }
+        // if the options are empty then we parsed RETURN () which is a 
shortcut for ALL.
+        // See http://www.faqs.org/rfcs/rfc4731.html 3.1
+        if (options.isEmpty()) {
+            options.add(SearchResultOption.ALL);
+        }
+        return options;
+    }
     /*
      * (non-Javadoc)
      * 
@@ -898,10 +955,45 @@ public class SearchCommandParser extends
      */
     protected ImapMessage decode(ImapCommand command, ImapRequestLineReader 
request, String tag, boolean useUids, ImapSession session) throws 
DecodingException {
         try {
+            SearchKey recent = null;
+            List<SearchResultOption> options = null;
+            int c = cap(request.nextWordChar());
+            if (c == 'R') {
+                // if we found a R its either RECENT or RETURN so consume it
+                request.consume();
+                
+                nextIsE(request);
+                c = consumeAndCap(request);
+
+                switch (c) {
+                case 'C':
+                    recent = recent(request);
+                    break;
+                case 'T': 
+                    nextIsU(request);
+                    nextIsR(request);
+                    nextIsN(request);
+                    options = parseOptions(request);
+                default:
+                    throw new 
DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
+                }
+            }
+            
             // Parse the search term from the request
             final SearchKey key = decode(request);
-
-            final ImapMessage result = new SearchRequest(command, key, 
useUids, tag);
+            
+            final SearchKey finalKey;
+            if (recent != null) {
+                finalKey = SearchKey.buildAnd(Arrays.asList(recent, key));
+            } else {
+                finalKey = key;
+            }
+            
+            if (options == null) {
+                options = new ArrayList<SearchResultOption>();
+            }
+            
+            final ImapMessage result = new SearchRequest(command, new 
SearchOperation(finalKey, options), useUids, tag);
             return result;
         } catch (IllegalCharsetNameException e) {
             session.getLog().debug("Unable to decode request", e);
@@ -911,4 +1003,5 @@ public class SearchCommandParser extends
             return unsupportedCharset(tag, command);
         }
     }
+
 }

Added: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ESearchResponseEncoder.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ESearchResponseEncoder.java?rev=1128932&view=auto
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ESearchResponseEncoder.java
 (added)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ESearchResponseEncoder.java
 Sun May 29 18:42:23 2011
@@ -0,0 +1,81 @@
+/****************************************************************
+ * 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.imap.encode;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.api.message.IdRange;
+import org.apache.james.imap.api.message.request.SearchResultOption;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.encode.base.AbstractChainedImapEncoder;
+import org.apache.james.imap.message.response.ESearchResponse;
+
+/**
+ * Encoders IMAP4rev1 <code>ESEARCH</code> responses.
+ */
+public class ESearchResponseEncoder extends AbstractChainedImapEncoder {
+
+    public ESearchResponseEncoder(ImapEncoder next) {
+        super(next);
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.encode.base.AbstractChainedImapEncoder#doEncode(org.apache.james.imap.api.ImapMessage,
 org.apache.james.imap.encode.ImapResponseComposer, 
org.apache.james.imap.api.process.ImapSession)
+     */
+    protected void doEncode(ImapMessage acceptableMessage, 
ImapResponseComposer composer, ImapSession session) throws IOException {
+        ESearchResponse response = (ESearchResponse) acceptableMessage;
+        String tag = response.getTag();
+        long min = response.getMinUid();
+        long max = response.getMaxUid();
+        long count = response.getCount();
+        IdRange[] all = response.getAll();
+        boolean useUid = response.getUseUid();
+        List<SearchResultOption> options = response.getSearchResultOptions();
+        
+        
composer.untagged().message("ESEARCH").openParen().message("TAG").quote(tag).closeParen();
+        if (useUid) {
+            composer.message("UID");
+        }
+        if (min > -1 && options.contains(SearchResultOption.MIN)) {
+            composer.message(SearchResultOption.MIN.name()).message(min);
+        }
+        if (max > -1 && options.contains(SearchResultOption.MAX)) {
+            composer.message(SearchResultOption.MAX.name()).message(max);
+        }
+        if (options.contains(SearchResultOption.COUNT)) {
+            composer.message(SearchResultOption.COUNT.name()).message(count);
+        }
+        if (all != null && all.length > 0 && 
options.contains(SearchResultOption.ALL)) {
+            composer.message(SearchResultOption.ALL.name());
+            composer.sequenceSet(all);
+        }
+        composer.end();
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.encode.base.AbstractChainedImapEncoder#isAcceptable(org.apache.james.imap.api.ImapMessage)
+     */
+    protected boolean isAcceptable(ImapMessage message) {
+        return (message instanceof ESearchResponse);
+    }
+}

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java?rev=1128932&r1=1128931&r2=1128932&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
 Sun May 29 18:42:23 2011
@@ -26,6 +26,7 @@ import java.util.List;
 import javax.mail.Flags;
 
 import org.apache.james.imap.api.ImapCommand;
+import org.apache.james.imap.api.message.IdRange;
 import org.apache.james.imap.message.response.Literal;
 
 public interface ImapResponseComposer {
@@ -237,6 +238,8 @@ public interface ImapResponseComposer {
 
     public ImapResponseComposer message(final long number) throws IOException;
 
+    public ImapResponseComposer sequenceSet(final IdRange[] ranges) throws 
IOException;
+
     /**
      * Write a CRLF and flush the composer which will write the content of it 
to the socket
      * 

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java?rev=1128932&r1=1128931&r2=1128932&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
 Sun May 29 18:42:23 2011
@@ -31,6 +31,7 @@ import javax.mail.Flags;
 import org.apache.commons.io.output.ByteArrayOutputStream;
 import org.apache.james.imap.api.ImapCommand;
 import org.apache.james.imap.api.ImapConstants;
+import org.apache.james.imap.api.message.IdRange;
 import org.apache.james.imap.encode.ImapResponseComposer;
 import org.apache.james.imap.encode.ImapResponseWriter;
 import org.apache.james.imap.message.response.Literal;
@@ -829,4 +830,20 @@ public class ImapResponseComposerImpl im
         }
     }
 
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.encode.ImapResponseComposer#sequenceSet(org.apache.james.imap.api.message.IdRange[])
+     */
+    public ImapResponseComposer sequenceSet(IdRange[] ranges) throws 
IOException {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0 ; i< ranges.length; i++) {
+            IdRange range = ranges[i];
+            sb.append(range.getFormattedString());
+            if (i + 1 < ranges.length) {
+                sb.append(",");
+            }
+        }
+        return message(sb.toString());
+    }
+
 }

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java?rev=1128932&r1=1128931&r2=1128932&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/main/DefaultImapEncoderFactory.java
 Sun May 29 18:42:23 2011
@@ -23,6 +23,7 @@ import org.apache.james.imap.api.display
 import org.apache.james.imap.encode.AuthenticateResponseEncoder;
 import org.apache.james.imap.encode.CapabilityResponseEncoder;
 import org.apache.james.imap.encode.ContinuationResponseEncoder;
+import org.apache.james.imap.encode.ESearchResponseEncoder;
 import org.apache.james.imap.encode.ExistsResponseEncoder;
 import org.apache.james.imap.encode.ExpungeResponseEncoder;
 import org.apache.james.imap.encode.FetchResponseEncoder;
@@ -71,8 +72,8 @@ public class DefaultImapEncoderFactory i
         final CapabilityResponseEncoder capabilityResponseEncoder = new 
CapabilityResponseEncoder(flagsResponseEncoder);
         final ContinuationResponseEncoder continuationResponseEncoder = new 
ContinuationResponseEncoder(capabilityResponseEncoder, localizer);
         final AuthenticateResponseEncoder authResponseEncoder = new 
AuthenticateResponseEncoder(continuationResponseEncoder);
-
-        return authResponseEncoder;
+        final ESearchResponseEncoder esearchResponseEncoder = new 
ESearchResponseEncoder(authResponseEncoder);
+        return esearchResponseEncoder;
     }
 
     private final Localizer localizer;

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SearchRequest.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SearchRequest.java?rev=1128932&r1=1128931&r2=1128932&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SearchRequest.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SearchRequest.java
 Sun May 29 18:42:23 2011
@@ -19,22 +19,22 @@
 package org.apache.james.imap.message.request;
 
 import org.apache.james.imap.api.ImapCommand;
-import org.apache.james.imap.api.message.request.SearchKey;
+import org.apache.james.imap.api.message.request.SearchOperation;
 
 public class SearchRequest extends AbstractImapRequest {
 
-    private final SearchKey searchKey;
+    private final SearchOperation operation;
 
     private final boolean useUids;
 
-    public SearchRequest(final ImapCommand command, final SearchKey SearchKey, 
final boolean useUids, final String tag) {
+    public SearchRequest(final ImapCommand command, final SearchOperation 
operation, final boolean useUids, final String tag) {
         super(tag, command);
-        this.searchKey = SearchKey;
+        this.operation = operation;
         this.useUids = useUids;
     }
 
-    public final SearchKey getSearchKey() {
-        return searchKey;
+    public final SearchOperation getSearchOperation() {
+        return operation;
     }
 
     public final boolean isUseUids() {

Added: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ESearchResponse.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ESearchResponse.java?rev=1128932&view=auto
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ESearchResponse.java
 (added)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ESearchResponse.java
 Sun May 29 18:42:23 2011
@@ -0,0 +1,77 @@
+/****************************************************************
+ * 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.imap.message.response;
+
+import java.util.List;
+
+import org.apache.james.imap.api.message.IdRange;
+import org.apache.james.imap.api.message.request.SearchResultOption;
+import org.apache.james.imap.api.message.response.ImapResponseMessage;
+
+public class ESearchResponse implements ImapResponseMessage{
+
+    private final long minUid;
+    private final long maxUid;
+    private final long count;
+    private final IdRange[] all;
+    private final String tag;
+    private boolean useUid;
+    private List<SearchResultOption> options;
+
+    public ESearchResponse(final long minUid, final long maxUid, final long 
count, final IdRange[] all, String tag, final boolean useUid, final 
List<SearchResultOption> options) {
+        super();
+        this.options = options;
+        this.minUid = minUid;
+        this.maxUid = maxUid;
+        this.count = count;
+        this.all = all;
+        this.tag = tag;
+        this.useUid = useUid;
+    }
+    
+    public final long getCount() {
+        return count;
+    }
+    
+    public final long getMinUid() {
+        return minUid;
+    }
+    
+    public final long getMaxUid() {
+        return maxUid;
+    }
+    
+    public IdRange[] getAll() {
+        return all;
+    }
+    
+    public String getTag() {
+        return tag;
+    }
+    
+    public boolean getUseUid() {
+        return useUid;
+    }
+    
+    public List<SearchResultOption> getSearchResultOptions() {
+        return options;
+    }
+    
+}

Modified: 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java?rev=1128932&r1=1128931&r2=1128932&view=diff
==============================================================================
--- 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
 (original)
+++ 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java
 Sun May 29 18:42:23 2011
@@ -36,11 +36,15 @@ import org.apache.james.imap.api.display
 import org.apache.james.imap.api.message.IdRange;
 import org.apache.james.imap.api.message.request.DayMonthYear;
 import org.apache.james.imap.api.message.request.SearchKey;
+import org.apache.james.imap.api.message.request.SearchOperation;
+import org.apache.james.imap.api.message.request.SearchResultOption;
+import org.apache.james.imap.api.message.response.ImapResponseMessage;
 import org.apache.james.imap.api.message.response.StatusResponseFactory;
 import org.apache.james.imap.api.process.ImapProcessor;
 import org.apache.james.imap.api.process.ImapSession;
 import org.apache.james.imap.api.process.SelectedMailbox;
 import org.apache.james.imap.message.request.SearchRequest;
+import org.apache.james.imap.message.response.ESearchResponse;
 import org.apache.james.imap.message.response.SearchResponse;
 import org.apache.james.mailbox.MailboxException;
 import org.apache.james.mailbox.MailboxManager;
@@ -70,7 +74,8 @@ public class SearchProcessor extends Abs
      */
     protected void doProcess(SearchRequest request, ImapSession session, 
String tag, ImapCommand command, Responder responder) {
         try {
-            final SearchKey searchKey = request.getSearchKey();
+            final SearchOperation operation = request.getSearchOperation();
+            final SearchKey searchKey = operation.getSearchKey();
             final boolean useUids = request.isUseUids();
             final MessageManager mailbox = getSelectedMailbox(session);
 
@@ -79,8 +84,36 @@ public class SearchProcessor extends Abs
             final Collection<Long> results = findIds(useUids, session, 
mailbox, query);
             final long[] ids = toArray(results);
 
-            final SearchResponse response = new SearchResponse(ids);
+            List<SearchResultOption> resultOptions = 
operation.getResultOptions();
+            final ImapResponseMessage response;
+            if (resultOptions == null || resultOptions.isEmpty()) {
+                response = new SearchResponse(ids);
+            } else {
+                long min = -1;
+                long max = -1;
+                long count = ids.length;
+                IdRange[] idRanges;
+
+                if (ids.length > 0) {
+                    min = ids[0];
+                    max = ids[ids.length -1];
+                } 
+                List<Long> idList = new ArrayList<Long>(ids.length);
+                for ( int i = 0; i < ids.length; i++) {
+                    idList.add(ids[i]);
+                }
+                List<MessageRange> ranges = MessageRange.toRanges(idList);
+                idRanges = new IdRange[ranges.size()];
+                for (int i = 0 ; i <ranges.size(); i++) {
+                    MessageRange range = ranges.get(i);
+                    idRanges[i] = new IdRange(range.getUidFrom(), 
range.getUidTo());
+                }
+
+                response = new ESearchResponse(min, max, count, idRanges, tag, 
useUids, resultOptions);
+
+            }
             responder.respond(response);
+
             boolean omitExpunged = (!useUids);
             unsolicitedResponses(session, responder, omitExpunged, useUids);
             okComplete(command, tag, responder);
@@ -283,6 +316,6 @@ public class SearchProcessor extends Abs
      * @see 
org.apache.james.imap.processor.CapabilityImplementingProcessor#getImplementedCapabilities(org.apache.james.imap.api.process.ImapSession)
      */
     public List<String> getImplementedCapabilities(ImapSession session) {
-        return Arrays.asList("WITHIN");
+        return Arrays.asList("WITHIN", "SEARCHRES");
     }
 }

Modified: 
james/imap/trunk/processor/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java?rev=1128932&r1=1128931&r2=1128932&view=diff
==============================================================================
--- 
james/imap/trunk/processor/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java
 (original)
+++ 
james/imap/trunk/processor/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java
 Sun May 29 18:42:23 2011
@@ -37,6 +37,8 @@ import org.apache.james.imap.api.display
 import org.apache.james.imap.api.message.IdRange;
 import org.apache.james.imap.api.message.request.DayMonthYear;
 import org.apache.james.imap.api.message.request.SearchKey;
+import org.apache.james.imap.api.message.request.SearchOperation;
+import org.apache.james.imap.api.message.request.SearchResultOption;
 import org.apache.james.imap.api.message.response.StatusResponse;
 import org.apache.james.imap.api.message.response.StatusResponseFactory;
 import org.apache.james.imap.api.process.ImapProcessor;
@@ -494,7 +496,7 @@ public class SearchProcessorTest {
             allowing(selectedMailbox).hasNewApplicableFlags(); 
will(returnValue(false));
           
         }});
-        SearchRequest message = new SearchRequest(command, key, false, TAG);
+        SearchRequest message = new SearchRequest(command, new 
SearchOperation(key, new ArrayList<SearchResultOption>()), false, TAG);
         processor.doProcess(message, session, TAG, command, responder);
     }
 



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to