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 no...@apache.org on 2011/05/30 20:01:06 UTC

svn commit: r1129279 - in /james/imap/trunk: api/src/main/java/org/apache/james/imap/api/message/request/ api/src/main/java/org/apache/james/imap/api/process/ message/src/main/java/org/apache/james/imap/decode/ message/src/main/java/org/apache/james/im...

Author: norman
Date: Mon May 30 18:01:06 2011
New Revision: 1129279

URL: http://svn.apache.org/viewvc?rev=1129279&view=rev
Log:
Add support for SEARCHRES. See IMAP-309

Added:
    james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SearchResUtil.java
Modified:
    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/decode/ImapRequestLineReader.java
    james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java
    james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java
    james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/FetchCommandParser.java
    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/decode/parser/StoreCommandParser.java
    james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserAndParenthesesTest.java
    james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserCharsetTest.java
    james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserNotTest.java
    james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserOrTest.java
    james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserQuotedCharsetTest.java
    james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeySequenceSetTest.java
    james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeyTest.java
    james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserTopLevelAndTest.java
    james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
    james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java

Modified: 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=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchResultOption.java (original)
+++ james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/request/SearchResultOption.java Mon May 30 18:01:06 2011
@@ -19,7 +19,7 @@
 package org.apache.james.imap.api.message.request;
 
 /**
- * Represent ESEARCH result options. See RFC4731
+ * Represent ESEARCH result options. See RFC4731 and RFC5182
  *
  */
 public enum SearchResultOption {
@@ -41,5 +41,12 @@ public enum SearchResultOption {
     /**
      * Return the count of matched messages
      */
-    COUNT
+    COUNT,
+    
+    /**
+     * Save the last ESEARCH returned sequence-set's. 
+     * 
+     * See RFC5182 2.4. Interaction with ESEARCH Extension
+     */
+    SAVE
 }

Added: james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SearchResUtil.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SearchResUtil.java?rev=1129279&view=auto
==============================================================================
--- james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SearchResUtil.java (added)
+++ james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SearchResUtil.java Mon May 30 18:01:06 2011
@@ -0,0 +1,68 @@
+/****************************************************************
+ * 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.process;
+
+import java.util.Arrays;
+
+import org.apache.james.imap.api.message.IdRange;
+
+/**
+ * Utility class which is used to support the SEARCHRES extension
+ *
+ */
+public class SearchResUtil {
+    
+    private final static String SEARCHRES_SAVED_SET = "SEARCHRES_SAVED_SET";
+    
+    /**
+     * Return the saved sequence-set which you can refer to with $. This method will
+     * return a IdRange[0] If no sequence-set is saved
+     * 
+     * @param session
+     * @return sequenceSet
+     */
+    public static IdRange[] getSavedSequenceSet(ImapSession session) {
+        Object obj = session.getAttribute(SEARCHRES_SAVED_SET);
+        if (obj != null) {
+            return (IdRange[]) obj;
+        } else {
+            return new IdRange[0];
+        }
+    }
+    
+    /**
+     * Save the given sequence-set which you can refer to later with $.
+     * 
+     * @param session
+     * @param ranges
+     */
+    public static void saveSequenceSet(ImapSession session, IdRange[] ranges) {
+        session.setAttribute(SEARCHRES_SAVED_SET, IdRange.mergeRanges(Arrays.asList(ranges)).toArray(new IdRange[0]));
+    }
+    
+    /**
+     * Reset the saved sequence-set
+     * 
+     * @param session
+     */
+    public static void resetSavedSequenceSet(ImapSession session) {
+        session.setAttribute(SEARCHRES_SAVED_SET, null);
+    }
+}

Modified: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java (original)
+++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/ImapRequestLineReader.java Mon May 30 18:01:06 2011
@@ -42,6 +42,8 @@ import org.apache.james.imap.api.ImapCon
 import org.apache.james.imap.api.display.HumanReadableText;
 import org.apache.james.imap.api.message.IdRange;
 import org.apache.james.imap.api.message.request.DayMonthYear;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.api.process.SearchResUtil;
 
 /**
  * Wraps the client input reader with a bunch of convenience methods, allowing
@@ -574,10 +576,25 @@ public abstract class ImapRequestLineRea
     }
 
     /**
-     * Reads a "message set" argument, and parses into an IdSet. Currently only
-     * supports a single range of values.
+     * Reads a "message set" argument, and parses into an IdSet.
      */
     public IdRange[] parseIdRange() throws DecodingException {
+        return parseIdRange(null);
+    }
+
+    /**
+     * Reads a "message set" argument, and parses into an IdSet. This also support the use of $ as sequence-set as stated in SEARCHRES RFC5182 
+     */
+    public IdRange[] parseIdRange(ImapSession session) throws DecodingException {
+        if (session != null) {
+            char c = nextWordChar();
+            // Special handling for SEARCHRES extension. See RFC5182
+            if (c == '$') {
+                consume();
+                return SearchResUtil.getSavedSequenceSet(session);
+            }
+        }
+        
         CharacterValidator validator = new MessageSetCharValidator();
         // Don't fail to parse id ranges which are enclosed by "(..)"
         // See IMAP-283
@@ -607,6 +624,7 @@ public abstract class ImapRequestLineRea
         return (IdRange[]) merged.toArray(new IdRange[merged.size()]);
     }
 
+    
     /**
      * Parse a range which use a ":" as delimiter
      * 

Modified: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java (original)
+++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/CopyCommandParser.java Mon May 30 18:01:06 2011
@@ -46,7 +46,7 @@ public class CopyCommandParser extends A
      * boolean, org.apache.james.imap.api.process.ImapSession)
      */
     protected ImapMessage decode(ImapCommand command, ImapRequestLineReader request, String tag, boolean useUids, ImapSession session) throws DecodingException {
-        IdRange[] idSet = request.parseIdRange();
+        IdRange[] idSet = request.parseIdRange(session);
         String mailboxName = request.mailbox();
         request.eol();
         final ImapMessage result = new CopyRequest(command, idSet, mailboxName, useUids, tag);

Modified: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java (original)
+++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExpungeCommandParser.java Mon May 30 18:01:06 2011
@@ -48,7 +48,7 @@ public class ExpungeCommandParser extend
     protected ImapMessage decode(ImapCommand command, ImapRequestLineReader request, String tag, boolean useUids, ImapSession session) throws DecodingException {
         IdRange[] uidSet = null;
         if (useUids) {
-            uidSet = request.parseIdRange();
+            uidSet = request.parseIdRange(session);
         }
         request.eol();
 

Modified: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/FetchCommandParser.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/FetchCommandParser.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/FetchCommandParser.java (original)
+++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/FetchCommandParser.java Mon May 30 18:01:06 2011
@@ -227,7 +227,7 @@ public class FetchCommandParser extends 
      * boolean, org.apache.james.imap.api.process.ImapSession)
      */
     protected ImapMessage decode(ImapCommand command, ImapRequestLineReader request, String tag, boolean useUids, ImapSession session) throws DecodingException {
-        IdRange[] idSet = request.parseIdRange();
+        IdRange[] idSet = request.parseIdRange(session);
         FetchData fetch = fetchRequest(request);
         request.eol();
 

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=1129279&r1=1129278&r2=1129279&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 Mon May 30 18:01:06 2011
@@ -68,21 +68,23 @@ public class SearchCommandParser extends
      * @param isFirstToken
      *            true when this is the first token read, false otherwise
      */
-    protected SearchKey searchKey(ImapRequestLineReader request, Charset charset, boolean isFirstToken) throws DecodingException, IllegalCharsetNameException, UnsupportedCharsetException {
+    protected SearchKey searchKey(ImapSession session, ImapRequestLineReader request, Charset charset, boolean isFirstToken) throws DecodingException, IllegalCharsetNameException, UnsupportedCharsetException {
         final char next = request.nextChar();
-        if (next >= '0' && next <= '9' || next == '*') {
-            return sequenceSet(request);
+        
+        if (next >= '0' && next <= '9' || next == '*' || next == '$') {
+            return sequenceSet(session, request);
         } else if (next == '(') {
-            return paren(request, charset);
+            return paren(session, request, charset);
         } else {
             final int cap = consumeAndCap(request);
             switch (cap) {
+            
             case 'A':
                 return a(request);
             case 'B':
                 return b(request, charset);
             case 'C':
-                return c(request, isFirstToken, charset);
+                return c(session, request, isFirstToken, charset);
             case 'D':
                 return d(request);
             case 'E':
@@ -104,9 +106,9 @@ public class SearchCommandParser extends
             case 'M':
                 throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
             case 'N':
-                return n(request, charset);
+                return n(session, request, charset);
             case 'O':
-                return o(request, charset);
+                return o(session, request, charset);
             case 'P':
                 throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
             case 'Q':
@@ -129,21 +131,21 @@ public class SearchCommandParser extends
         }
     }
 
-    private SearchKey paren(ImapRequestLineReader request, Charset charset) throws DecodingException {
+    private SearchKey paren(ImapSession session, ImapRequestLineReader request, Charset charset) throws DecodingException {
         request.consume();
         List<SearchKey> keys = new ArrayList<SearchKey>();
-        addUntilParen(request, keys, charset);
+        addUntilParen(session, request, keys, charset);
         return SearchKey.buildAnd(keys);
     }
 
-    private void addUntilParen(ImapRequestLineReader request, List<SearchKey> keys, Charset charset) throws DecodingException {
+    private void addUntilParen(ImapSession session, ImapRequestLineReader request, List<SearchKey> keys, Charset charset) throws DecodingException {
         final char next = request.nextWordChar();
         if (next == ')') {
             request.consume();
         } else {
-            final SearchKey key = searchKey(request, null, false);
+            final SearchKey key = searchKey(session, request, null, false);
             keys.add(key);
-            addUntilParen(request, keys, charset);
+            addUntilParen(session, request, keys, charset);
         }
     }
 
@@ -165,19 +167,19 @@ public class SearchCommandParser extends
         return result;
     }
 
-    private SearchKey c(ImapRequestLineReader request, final boolean isFirstToken, final Charset charset) throws DecodingException, IllegalCharsetNameException, UnsupportedCharsetException {
+    private SearchKey c(ImapSession session, ImapRequestLineReader request, final boolean isFirstToken, final Charset charset) throws DecodingException, IllegalCharsetNameException, UnsupportedCharsetException {
         final int next = consumeAndCap(request);
         switch (next) {
         case 'C':
             return cc(request, charset);
         case 'H':
-            return charset(request, isFirstToken);
+            return charset(session, request, isFirstToken);
         default:
             throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
         }
     }
 
-    private SearchKey charset(ImapRequestLineReader request, final boolean isFirstToken) throws DecodingException, IllegalCharsetNameException, UnsupportedCharsetException {
+    private SearchKey charset(ImapSession session, ImapRequestLineReader request, final boolean isFirstToken) throws DecodingException, IllegalCharsetNameException, UnsupportedCharsetException {
         final SearchKey result;
         nextIsA(request);
         nextIsR(request);
@@ -191,7 +193,7 @@ public class SearchCommandParser extends
         final String value = request.astring();
         final Charset charset = Charset.forName(value);
         request.nextWordChar();
-        result = searchKey(request, charset, false);
+        result = searchKey(session, request, charset, false);
         return result;
     }
 
@@ -301,7 +303,7 @@ public class SearchCommandParser extends
         }
     }
 
-    private SearchKey o(ImapRequestLineReader request, Charset charset) throws DecodingException {
+    private SearchKey o(ImapSession session, ImapRequestLineReader request, Charset charset) throws DecodingException {
         final int next = consumeAndCap(request);
         switch (next) {
         case 'L':
@@ -309,7 +311,7 @@ public class SearchCommandParser extends
         case 'N':
             return on(request);
         case 'R':
-            return or(request, charset);
+            return or(session, request, charset);
         default:
             throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
         }
@@ -326,13 +328,13 @@ public class SearchCommandParser extends
         }
     }
     
-    private SearchKey n(ImapRequestLineReader request, Charset charset) throws DecodingException {
+    private SearchKey n(ImapSession session, ImapRequestLineReader request, Charset charset) throws DecodingException {
         final int next = consumeAndCap(request);
         switch (next) {
         case 'E':
             return _new(request);
         case 'O':
-            return not(request, charset);
+            return not(session, request, charset);
         default:
             throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
         }
@@ -526,21 +528,21 @@ public class SearchCommandParser extends
         return result;
     }
 
-    private SearchKey or(ImapRequestLineReader request, Charset charset) throws DecodingException {
+    private SearchKey or(ImapSession session, ImapRequestLineReader request, Charset charset) throws DecodingException {
         final SearchKey result;
         nextIsSpace(request);
-        final SearchKey firstKey = searchKey(request, charset, false);
+        final SearchKey firstKey = searchKey(session, request, charset, false);
         nextIsSpace(request);
-        final SearchKey secondKey = searchKey(request, charset, false);
+        final SearchKey secondKey = searchKey(session, request, charset, false);
         result = SearchKey.buildOr(firstKey, secondKey);
         return result;
     }
 
-    private SearchKey not(ImapRequestLineReader request, Charset charset) throws DecodingException {
+    private SearchKey not(ImapSession session, ImapRequestLineReader request, Charset charset) throws DecodingException {
         final SearchKey result;
         nextIsT(request);
         nextIsSpace(request);
-        final SearchKey nextKey = searchKey(request, charset, false);
+        final SearchKey nextKey = searchKey(session, request, charset, false);
         result = SearchKey.buildNot(nextKey);
         return result;
     }
@@ -707,8 +709,8 @@ public class SearchCommandParser extends
         return result;
     }
 
-    private SearchKey sequenceSet(ImapRequestLineReader request) throws DecodingException {
-        final IdRange[] range = request.parseIdRange();
+    private SearchKey sequenceSet(ImapSession session, ImapRequestLineReader request) throws DecodingException {
+        final IdRange[] range = request.parseIdRange(session);
         final SearchKey result = SearchKey.buildSequenceSet(range);
         return result;
     }
@@ -850,6 +852,11 @@ public class SearchCommandParser extends
         nextIs(request, 'L', 'l');
     }
 
+
+    private void nextIsV(ImapRequestLineReader request) throws DecodingException {
+        nextIs(request, 'V', 'v');
+    }
+
     private void nextIs(ImapRequestLineReader request, final char upper, final char lower) throws DecodingException {
         final char next = request.consume();
         if (next != upper && next != lower) {
@@ -857,16 +864,16 @@ public class SearchCommandParser extends
         }
     }
 
-    public SearchKey decode(ImapRequestLineReader request) throws DecodingException, IllegalCharsetNameException, UnsupportedCharsetException {
+    public SearchKey decode(ImapSession session, ImapRequestLineReader request) throws DecodingException, IllegalCharsetNameException, UnsupportedCharsetException {
         request.nextWordChar();
-        final SearchKey firstKey = searchKey(request, null, true);
+        final SearchKey firstKey = searchKey(session, request, null, true);
         final SearchKey result;
         if (request.nextChar() == ' ') {
             List<SearchKey> keys = new ArrayList<SearchKey>();
             keys.add(firstKey);
             while (request.nextChar() == ' ') {
                 request.nextWordChar();
-                final SearchKey key = searchKey(request, null, false);
+                final SearchKey key = searchKey(session, request, null, false);
                 keys.add(key);
             }
             result = SearchKey.buildAnd(keys);
@@ -935,6 +942,13 @@ public class SearchCommandParser extends
                     throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
                 }
                 break;
+            // Check for SAVE options which is part of the SEARCHRES extension
+            case 'S':
+                nextIsA(reader);
+                nextIsV(reader);
+                nextIsE(reader);
+                options.add(SearchResultOption.SAVE);
+                break;
             default:
                 throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key");
             }
@@ -987,7 +1001,7 @@ public class SearchCommandParser extends
             }
             
             // Parse the search term from the request
-            final SearchKey key = decode(request);
+            final SearchKey key = decode(session, request);
             
             final SearchKey finalKey;
             if (recent != null) {

Modified: james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java (original)
+++ james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java Mon May 30 18:01:06 2011
@@ -49,7 +49,7 @@ public class StoreCommandParser extends 
      * boolean, org.apache.james.imap.api.process.ImapSession)
      */
     protected ImapMessage decode(ImapCommand command, ImapRequestLineReader request, String tag, boolean useUids, ImapSession session) throws DecodingException {
-        final IdRange[] idSet = request.parseIdRange();
+        final IdRange[] idSet = request.parseIdRange(session);
         final Boolean sign;
         boolean silent = false;
 

Modified: james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserAndParenthesesTest.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserAndParenthesesTest.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserAndParenthesesTest.java (original)
+++ james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserAndParenthesesTest.java Mon May 30 18:01:06 2011
@@ -196,7 +196,7 @@ public class SearchCommandParserAndParen
                 new ByteArrayInputStream(input.getBytes("US-ASCII")),
                 new ByteArrayOutputStream());
 
-        final SearchKey result = parser.decode(reader);
+        final SearchKey result = parser.decode(null, reader);
         assertEquals(in.key, result);
     }
 

Modified: james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserCharsetTest.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserCharsetTest.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserCharsetTest.java (original)
+++ james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserCharsetTest.java Mon May 30 18:01:06 2011
@@ -186,7 +186,7 @@ public class SearchCommandParserCharsetT
                 new ByteArrayInputStream(NioUtils.add(NioUtils.add(CHARSET,
                         term), BYTES_UTF8_NON_ASCII_SEARCH_TERM)),
                 new ByteArrayOutputStream());
-        final SearchKey searchKey = parser.searchKey(reader, null, true);
+        final SearchKey searchKey = parser.searchKey(null, reader, null, true);
         assertEquals(key, searchKey);
     }
 
@@ -196,7 +196,7 @@ public class SearchCommandParserCharsetT
                 new ByteArrayInputStream(input.getBytes(charset)),
                 new ByteArrayOutputStream());
 
-        final SearchKey searchKey = parser.searchKey(reader, null, isFirst);
+        final SearchKey searchKey = parser.searchKey(null, reader, null, isFirst);
         assertEquals(key, searchKey);
     }
 

Modified: james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserNotTest.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserNotTest.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserNotTest.java (original)
+++ james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserNotTest.java Mon May 30 18:01:06 2011
@@ -120,6 +120,6 @@ public class SearchCommandParserNotTest 
                 new ByteArrayInputStream(input.getBytes("US-ASCII")),
                 new ByteArrayOutputStream());
 
-        assertEquals(key, parser.searchKey(reader, null, false));
+        assertEquals(key, parser.searchKey(null, reader, null, false));
     }
 }

Modified: james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserOrTest.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserOrTest.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserOrTest.java (original)
+++ james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserOrTest.java Mon May 30 18:01:06 2011
@@ -180,7 +180,7 @@ public class SearchCommandParserOrTest {
                 new ByteArrayInputStream(input.getBytes("US-ASCII")),
                 new ByteArrayOutputStream());
 
-        assertEquals(key, parser.searchKey(reader, null, false));
+        assertEquals(key, parser.searchKey(null, reader, null, false));
     }
 
     public class Input {

Modified: james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserQuotedCharsetTest.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserQuotedCharsetTest.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserQuotedCharsetTest.java (original)
+++ james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserQuotedCharsetTest.java Mon May 30 18:01:06 2011
@@ -164,7 +164,7 @@ public class SearchCommandParserQuotedCh
                         .getBytes("US-ASCII")),
                         BYTES_QUOTED_UTF8_LENGTHY_NON_ASCII_SEARCH_TERM)),
                 new ByteArrayOutputStream());
-        final SearchKey searchKey = parser.searchKey(reader, null, true);
+        final SearchKey searchKey = parser.searchKey(null, reader, null, true);
         assertEquals(key, searchKey);
     }
 
@@ -176,7 +176,7 @@ public class SearchCommandParserQuotedCh
                         .getBytes("US-ASCII")),
                         BYTES_QUOTED_UTF8_NON_ASCII_SEARCH_TERM)),
                 new ByteArrayOutputStream());
-        final SearchKey searchKey = parser.searchKey(reader, null, true);
+        final SearchKey searchKey = parser.searchKey(null, reader, null, true);
         assertEquals(key, searchKey);
     }
 
@@ -287,7 +287,7 @@ public class SearchCommandParserQuotedCh
                 new ByteArrayInputStream(add(add(CHARSET, term),
                         BYTES_UTF8_NON_ASCII_SEARCH_TERM)),
                 new ByteArrayOutputStream());
-        final SearchKey searchKey = parser.searchKey(reader, null, true);
+        final SearchKey searchKey = parser.searchKey(null, reader, null, true);
         assertEquals(key, searchKey);
     }
 
@@ -297,7 +297,7 @@ public class SearchCommandParserQuotedCh
                 new ByteArrayInputStream(input.getBytes(charset)),
                 new ByteArrayOutputStream());
 
-        final SearchKey searchKey = parser.searchKey(reader, null, isFirst);
+        final SearchKey searchKey = parser.searchKey(null, reader, null, isFirst);
         assertEquals(key, searchKey);
     }
 

Modified: james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeySequenceSetTest.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeySequenceSetTest.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeySequenceSetTest.java (original)
+++ james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeySequenceSetTest.java Mon May 30 18:01:06 2011
@@ -107,7 +107,7 @@ public class SearchCommandParserSearchKe
                 new ByteArrayInputStream(input.getBytes("US-ASCII")),
                 new ByteArrayOutputStream());
 
-        final SearchKey searchKey = parser.searchKey(reader, null, false);
+        final SearchKey searchKey = parser.searchKey(null, reader, null, false);
         assertEquals(key, searchKey);
     }
 }

Modified: james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeyTest.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeyTest.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeyTest.java (original)
+++ james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserSearchKeyTest.java Mon May 30 18:01:06 2011
@@ -386,7 +386,7 @@ public class SearchCommandParserSearchKe
                 new ByteArrayInputStream(input.getBytes("US-ASCII")),
                 new ByteArrayOutputStream());
 
-        assertEquals(key, parser.searchKey(reader, null, false));
+        assertEquals(key, parser.searchKey(null, reader, null, false));
     }
 
     @Test
@@ -740,7 +740,7 @@ public class SearchCommandParserSearchKe
                 new ByteArrayOutputStream());
 
         try {
-            parser.searchKey(reader, null, false);
+            parser.searchKey(null, reader, null, false);
             fail("Expected protocol exception to be throw since input is invalid");
         } catch (DecodingException e) {
             // expected

Modified: james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserTopLevelAndTest.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserTopLevelAndTest.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserTopLevelAndTest.java (original)
+++ james/imap/trunk/message/src/test/java/org/apache/james/imap/decode/parser/SearchCommandParserTopLevelAndTest.java Mon May 30 18:01:06 2011
@@ -198,6 +198,6 @@ public class SearchCommandParserTopLevel
                 new ByteArrayInputStream(input.getBytes("US-ASCII")),
                 new ByteArrayOutputStream());
 
-        assertEquals(input, key, parser.decode(reader));
+        assertEquals(input, key, parser.decode(null, reader));
     }
 }

Modified: james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
URL: http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java?rev=1129279&r1=1129278&r2=1129279&view=diff
==============================================================================
--- james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java (original)
+++ james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java Mon May 30 18:01:06 2011
@@ -33,6 +33,7 @@ import org.apache.james.imap.api.message
 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.SearchResUtil;
 import org.apache.james.imap.api.process.SelectedMailbox;
 import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest;
 import org.apache.james.imap.message.response.ExistsResponse;
@@ -84,6 +85,11 @@ abstract class AbstractSelectionProcesso
             final MailboxPath fullMailboxPath = buildFullPath(session, mailboxName);
             final MessageManager.MetaData metaData = selectMailbox(fullMailboxPath, session);
             respond(tag, command, session, metaData, responder);
+            
+            // Reset the saved sequence-set after successful SELECT / EXAMINE
+            // See RFC 5812 2.1. Normative Description of the SEARCHRES Extension
+            SearchResUtil.resetSavedSequenceSet(session);
+            
         } catch (MailboxNotFoundException e) {
             session.getLog().debug("Select failed", e);
             responder.respond(statusResponseFactory.taggedNo(tag, command, HumanReadableText.FAILURE_NO_SUCH_MAILBOX));

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=1129279&r1=1129278&r2=1129279&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 Mon May 30 18:01:06 2011
@@ -42,6 +42,7 @@ import org.apache.james.imap.api.message
 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.SearchResUtil;
 import org.apache.james.imap.api.process.SelectedMailbox;
 import org.apache.james.imap.message.request.SearchRequest;
 import org.apache.james.imap.message.response.ESearchResponse;
@@ -73,10 +74,13 @@ public class SearchProcessor extends Abs
      * org.apache.james.imap.api.process.ImapProcessor.Responder)
      */
     protected void doProcess(SearchRequest request, ImapSession session, String tag, ImapCommand command, Responder responder) {
+        final SearchOperation operation = request.getSearchOperation();
+        final SearchKey searchKey = operation.getSearchKey();
+        final boolean useUids = request.isUseUids();
+        List<SearchResultOption> resultOptions = operation.getResultOptions();
+
         try {
-            final SearchOperation operation = request.getSearchOperation();
-            final SearchKey searchKey = operation.getSearchKey();
-            final boolean useUids = request.isUseUids();
+
             final MessageManager mailbox = getSelectedMailbox(session);
 
             final SearchQuery query = toQuery(searchKey, session);
@@ -84,20 +88,11 @@ public class SearchProcessor extends Abs
             final Collection<Long> results = findIds(useUids, session, mailbox, query);
             final long[] ids = toArray(results);
 
-            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]);
@@ -108,10 +103,53 @@ public class SearchProcessor extends Abs
                     MessageRange range = ranges.get(i);
                     idRanges[i] = new IdRange(range.getUidFrom(), range.getUidTo());
                 }
+                
+                boolean esearch = false;
+                for (int i = 0; i < resultOptions.size(); i++) {
+                    if (SearchResultOption.SAVE != resultOptions.get(i)) {
+                        esearch = true;
+                        break;
+                    }
+                }
+                
+                if (esearch) {
+                    long min = -1;
+                    long max = -1;
+                    long count = ids.length;
+
+                    if (ids.length > 0) {
+                        min = ids[0];
+                        max = ids[ids.length -1];
+                    } 
+                   
+                    
+                    // Save the sequence-set for later usage. This is part of SEARCHRES 
+                    if (resultOptions.contains(SearchResultOption.SAVE)) {
+                        if (resultOptions.contains(SearchResultOption.ALL) || resultOptions.contains(SearchResultOption.COUNT)) {
+                            // if the options contain ALL or COUNT we need to save the complete sequence-set
+                            SearchResUtil.saveSequenceSet(session, idRanges);
+                        } else {
+                            List<IdRange> savedRanges = new ArrayList<IdRange>();
+                            if (resultOptions.contains(SearchResultOption.MIN)) {
+                                // Store the MIN
+                                savedRanges.add(new IdRange(min));  
+                            } 
+                            if (resultOptions.contains(SearchResultOption.MAX)) {
+                                // Store the MAX
+                                savedRanges.add(new IdRange(max));
+                            }
+                            SearchResUtil.saveSequenceSet(session, savedRanges.toArray(new IdRange[0]));
+                        }
+                    }
+                    response = new ESearchResponse(min, max, count, idRanges, tag, useUids, resultOptions);
+                } else {
+                    // Just save the returned sequence-set as this is not SEARCHRES + ESEARCH
+                    SearchResUtil.saveSequenceSet(session, idRanges);
+                    response = new SearchResponse(ids);
 
-                response = new ESearchResponse(min, max, count, idRanges, tag, useUids, resultOptions);
-
+                }
             }
+
             responder.respond(response);
 
             boolean omitExpunged = (!useUids);
@@ -123,6 +161,13 @@ public class SearchProcessor extends Abs
         } catch (MailboxException e) {
             session.getLog().debug("Search failed", e);
             no(command, tag, responder, HumanReadableText.SEARCH_FAILED);
+            
+            if (resultOptions.contains(SearchResultOption.SAVE)) {
+                // Reset the saved sequence-set on a BAD response if the SAVE option was used.
+                //
+                // See RFC5182 2.1.Normative Description of the SEARCHRES Extension
+                SearchResUtil.resetSavedSequenceSet(session);
+            }
         }
     }
 
@@ -316,6 +361,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", "ESEARCH");
+        return Arrays.asList("WITHIN", "ESEARCH", "SEARCHRES");
     }
 }



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