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/03/22 12:12:33 UTC

svn commit: r639977 - in /james/server/trunk/imap-codec-library/src: main/java/org/apache/james/imapserver/codec/decode/ main/java/org/apache/james/imapserver/codec/decode/base/ test/java/org/apache/james/imapserver/codec/decode/imap4rev1/

Author: rdonkin
Date: Sat Mar 22 04:12:32 2008
New Revision: 639977

URL: http://svn.apache.org/viewvc?rev=639977&view=rev
Log:
Quoted string SEARCH CHARSET implementation

Added:
    james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/imap4rev1/SearchCommandParserQuotedCharsetTest.java
Modified:
    james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/ImapRequestLineReader.java
    james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/base/AbstractImapCommandParser.java

Modified: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/ImapRequestLineReader.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/ImapRequestLineReader.java?rev=639977&r1=639976&r2=639977&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/ImapRequestLineReader.java (original)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/ImapRequestLineReader.java Sat Mar 22 04:12:32 2008
@@ -73,7 +73,9 @@
     /**
      * Reads the next character in the current line. This method will continue to return
      * the same character until the {@link #consume()} method is called.
-     * @return The next character.
+     * @return The next character 
+     * TODO: character encoding is variable and cannot be determine at the token level;
+     * this char is not accurate reported; should be an octet
      * @throws ProtocolException If the end-of-stream is reached.
      */
     public char nextChar() throws ProtocolException

Modified: james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/base/AbstractImapCommandParser.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/base/AbstractImapCommandParser.java?rev=639977&r1=639976&r2=639977&view=diff
==============================================================================
--- james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/base/AbstractImapCommandParser.java (original)
+++ james/server/trunk/imap-codec-library/src/main/java/org/apache/james/imapserver/codec/decode/base/AbstractImapCommandParser.java Sat Mar 22 04:12:32 2008
@@ -20,8 +20,11 @@
 package org.apache.james.imapserver.codec.decode.base;
 
 import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
 import java.nio.charset.CharacterCodingException;
 import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.MalformedInputException;
 import java.nio.charset.UnmappableCharacterException;
@@ -52,6 +55,8 @@
  */
 public abstract class AbstractImapCommandParser extends AbstractLogEnabled implements ImapCommandParser, MessagingImapCommandParser
 {
+    private static final int QUOTED_BUFFER_INITIAL_CAPACITY = 64;
+
     private static final Charset US_ASCII = Charset.forName("US-ASCII");
     
     private ImapCommand command;
@@ -161,7 +166,7 @@
         char next = request.nextWordChar();
         switch ( next ) {
             case '"':
-                return consumeQuoted( request );
+                return consumeQuoted( request, charset );
             case '{':
                 return consumeLiteral( request, charset );
             default:
@@ -346,23 +351,27 @@
             final byte[] bytes = new byte[size];
             request.read( bytes );
             final ByteBuffer buffer = ByteBuffer.wrap(bytes);
-            try {
-                
-                final String result = charset.newDecoder()
-                    .onMalformedInput(CodingErrorAction.REPORT)
-                    .onUnmappableCharacter(CodingErrorAction.REPORT)
-                    .decode(buffer).toString();
-                return result;
-                
-            } catch (IllegalStateException e) {
-                throw new ProtocolException ("Bad character encoding", e);
-            } catch (MalformedInputException e) {
-                throw new ProtocolException ("Bad character encoding", e);
-            } catch (UnmappableCharacterException e) {
-                throw new ProtocolException ("Bad character encoding", e);
-            } catch (CharacterCodingException e) {
-                throw new ProtocolException ("Bad character encoding", e);
-            }
+            return decode(charset, buffer);
+        }
+    }
+
+    private String decode(final Charset charset, final ByteBuffer buffer) throws ProtocolException {
+        try {
+            
+            final String result = charset.newDecoder()
+                .onMalformedInput(CodingErrorAction.REPORT)
+                .onUnmappableCharacter(CodingErrorAction.REPORT)
+                .decode(buffer).toString();
+            return result;
+            
+        } catch (IllegalStateException e) {
+            throw new ProtocolException ("Bad character encoding", e);
+        } catch (MalformedInputException e) {
+            throw new ProtocolException ("Bad character encoding", e);
+        } catch (UnmappableCharacterException e) {
+            throw new ProtocolException ("Bad character encoding", e);
+        } catch (CharacterCodingException e) {
+            throw new ProtocolException ("Bad character encoding", e);
         }
     }
 
@@ -398,31 +407,28 @@
     /**
      * Reads a quoted string value from the request.
      */
-    protected String consumeQuoted( ImapRequestLineReader request )
+    protected String consumeQuoted( ImapRequestLineReader request)
+            throws ProtocolException
+    { 
+        return consumeQuoted(request, null);
+    }
+    
+    /**
+     * Reads a quoted string value from the request.
+     */
+    protected String consumeQuoted( ImapRequestLineReader request, Charset charset )
             throws ProtocolException
     {
-        // The 1st character must be '"'
-        consumeChar(request, '"' );
-
-        StringBuffer quoted = new StringBuffer();
-        char next = request.nextChar();
-        while( next != '"' ) {
-            if ( next == '\\' ) {
-                request.consume();
-                next = request.nextChar();
-                if ( ! isQuotedSpecial( next ) ) {
-                    throw new ProtocolException( "Invalid escaped character in quote: '" +
-                                                 next + "'" );
-                }
-            }
-            quoted.append( next );
-            request.consume();
-            next = request.nextChar();
+        if (charset == null) {
+            return consumeQuoted(request, US_ASCII);
+        } else {
+            // The 1st character must be '"'
+            consumeChar(request, '"' );
+            final QuotedStringDecoder decoder = new QuotedStringDecoder(charset);
+            final String result = decoder.decode(request);
+            consumeChar( request, '"' );
+            return result;
         }
-
-        consumeChar( request, '"' );
-
-        return quoted.toString();
     }
 
     /**
@@ -643,4 +649,105 @@
         }
     }
 
+    /**
+     * Decodes contents of a quoted string.
+     * Charset aware.
+     * One shot, not thread safe.
+     */
+    private static class QuotedStringDecoder {
+        /** Decoder suitable for charset */
+        private final CharsetDecoder decoder;
+        
+        /** byte buffer will be filled then flushed to character buffer */
+        private final ByteBuffer buffer;
+        /** character buffer may be dynamically resized */
+        CharBuffer charBuffer;
+        
+        public QuotedStringDecoder(Charset charset) {
+            decoder = charset.newDecoder();
+            buffer = ByteBuffer.allocate(QUOTED_BUFFER_INITIAL_CAPACITY);
+            charBuffer = CharBuffer.allocate(QUOTED_BUFFER_INITIAL_CAPACITY);
+        }
+        
+        public String decode(ImapRequestLineReader request) throws ProtocolException {
+            try {
+                decoder.reset();
+                char next = request.nextChar();
+                while( next != '"' ) {
+                    // fill up byte buffer before decoding
+                    if (!buffer.hasRemaining()) {
+                        decodeByteBufferToCharacterBuffer(false);
+                    }
+                    if ( next == '\\' ) {
+                        request.consume();
+                        next = request.nextChar();
+                        if ( ! isQuotedSpecial( next ) ) {
+                            throw new ProtocolException( "Invalid escaped character in quote: '" +
+                                    next + "'" );
+                        }
+                    }
+                    // TODO: nextChar does not report accurate chars so safe to cast to byte
+                    buffer.put( (byte) next );
+                    request.consume();
+                    next = request.nextChar();
+                }
+                completeDecoding();
+                final String result = charBuffer.toString();
+                return result;
+
+            } catch (IllegalStateException e) {
+                throw new ProtocolException ("Bad character encoding", e);
+            }
+        }
+
+        private void completeDecoding() throws ProtocolException {
+            decodeByteBufferToCharacterBuffer(true);
+            flush();
+            charBuffer.flip();
+        }
+
+        private void flush() throws ProtocolException {
+            final CoderResult coderResult = decoder.flush(charBuffer);
+            if (coderResult.isOverflow()) {
+                upsizeCharBuffer();
+                flush();
+            } else if (coderResult.isError()) {
+                throw new ProtocolException("Bad character encoding");
+            }
+        }
+
+        /**
+         * Decodes contents of the byte buffer to the character buffer.
+         * The character buffer will be replaced by a larger one if required.
+         * @param endOfInput is the input ended
+         */
+        private CoderResult decodeByteBufferToCharacterBuffer(final boolean endOfInput) throws ProtocolException {
+            buffer.flip();
+            return decodeMoreBytesToCharacterBuffer(endOfInput);
+        }
+
+        private CoderResult decodeMoreBytesToCharacterBuffer(final boolean endOfInput) throws ProtocolException {
+            final CoderResult coderResult = decoder.decode(buffer, charBuffer, endOfInput);
+            if (coderResult.isOverflow()) {
+                upsizeCharBuffer();
+                return decodeMoreBytesToCharacterBuffer(endOfInput);
+            } else if (coderResult.isError()) {
+                throw new ProtocolException("Bad character encoding");
+            } else if (coderResult.isUnderflow()) {
+                buffer.clear();
+            }
+            return coderResult;
+        }
+
+        /**
+         * Increases the size of the character buffer.
+         */
+        private void upsizeCharBuffer() {
+            final int oldCapacity = charBuffer.capacity();
+            CharBuffer oldBuffer = charBuffer;
+            charBuffer = CharBuffer.allocate(oldCapacity + QUOTED_BUFFER_INITIAL_CAPACITY);
+            oldBuffer.flip();
+            charBuffer.put(oldBuffer);
+        }
+    }
 }

Added: james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/imap4rev1/SearchCommandParserQuotedCharsetTest.java
URL: http://svn.apache.org/viewvc/james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/imap4rev1/SearchCommandParserQuotedCharsetTest.java?rev=639977&view=auto
==============================================================================
--- james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/imap4rev1/SearchCommandParserQuotedCharsetTest.java (added)
+++ james/server/trunk/imap-codec-library/src/test/java/org/apache/james/imapserver/codec/decode/imap4rev1/SearchCommandParserQuotedCharsetTest.java Sat Mar 22 04:12:32 2008
@@ -0,0 +1,215 @@
+/****************************************************************
+ * 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.imap4rev1;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.Charset;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.james.api.imap.ImapCommand;
+import org.apache.james.api.imap.ImapMessage;
+import org.apache.james.api.imap.ProtocolException;
+import org.apache.james.api.imap.display.HumanReadableTextKey;
+import org.apache.james.api.imap.imap4rev1.Imap4Rev1CommandFactory;
+import org.apache.james.api.imap.imap4rev1.Imap4Rev1MessageFactory;
+import org.apache.james.api.imap.message.request.SearchKey;
+import org.apache.james.api.imap.message.response.imap4rev1.StatusResponse;
+import org.apache.james.api.imap.message.response.imap4rev1.StatusResponseFactory;
+import org.apache.james.imapserver.codec.decode.ImapRequestLineReader;
+import org.jmock.Mock;
+import org.jmock.MockObjectTestCase;
+
+public class SearchCommandParserQuotedCharsetTest extends MockObjectTestCase {
+
+    private static final Charset UTF8 = Charset.forName("UTF-8");
+    private static final Charset ASCII = Charset.forName("US-ASCII");
+    private static final String TAG = "A1";
+    private static final String ASCII_SEARCH_TERM = "A Search Term";
+    private static final String NON_ASCII_SEARCH_TERM = "\u043A\u0430\u043A \u0414\u0435\u043B\u0430?";
+    private static final String LENGTHY_NON_ASCII_SEARCH_TERM = NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM +
+        NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM + NON_ASCII_SEARCH_TERM;
+    private static final byte[] BYTES_LENGTHY_NON_ASCII_SEARCH_TERM = LENGTHY_NON_ASCII_SEARCH_TERM.getBytes(UTF8); 
+    private static final byte[] BYTES_NON_ASCII_SEARCH_TERM = NON_ASCII_SEARCH_TERM.getBytes(UTF8); 
+    private static final byte[] BYTES_QUOTED_UTF8_LENGTHY_NON_ASCII_SEARCH_TERM = add(add(" \"".getBytes(ASCII), BYTES_LENGTHY_NON_ASCII_SEARCH_TERM), "\"".getBytes(ASCII));
+    private static final byte[] BYTES_QUOTED_UTF8_NON_ASCII_SEARCH_TERM = add(add(" \"".getBytes(ASCII), BYTES_NON_ASCII_SEARCH_TERM), "\"".getBytes(ASCII));
+    private static final byte[] BYTES_UTF8_NON_ASCII_SEARCH_TERM = add(" {16}\r\n".getBytes(ASCII), BYTES_NON_ASCII_SEARCH_TERM);
+    private static final byte[] CHARSET = "CHARSET UTF-8 ".getBytes(ASCII);
+    
+    private static final byte[] add(byte[] one, byte[] two) {
+        byte[] results = new byte[one.length + two.length];
+        System.arraycopy(one, 0, results, 0, one.length);
+        System.arraycopy(two, 0, results, one.length, two.length);
+        return results;
+    }
+    
+    SearchCommandParser parser;
+    Mock mockStatusResponseFactory;
+    Mock mockCommandFactory;
+    Mock mockMessageFactory;
+    Mock mockCommand;
+    Mock mockMessage;
+    ImapCommand command;
+    ImapMessage message;
+
+    protected void setUp() throws Exception {
+        super.setUp();
+        parser = new SearchCommandParser();
+        mockCommandFactory = mock(Imap4Rev1CommandFactory.class);
+        mockCommandFactory.expects(once()).method("getSearch");
+        mockMessageFactory = mock(Imap4Rev1MessageFactory.class);
+        mockCommand = mock(ImapCommand.class);
+        command = (ImapCommand) mockCommand.proxy();
+        mockMessage = mock(ImapMessage.class);
+        mockStatusResponseFactory = mock(StatusResponseFactory.class);
+        message = (ImapMessage) mockMessage.proxy();
+        parser.init((Imap4Rev1CommandFactory) mockCommandFactory.proxy());
+        parser.setMessageFactory((Imap4Rev1MessageFactory) mockMessageFactory.proxy());
+        parser.setStatusResponseFactory((StatusResponseFactory) mockStatusResponseFactory.proxy());
+        parser.enableLogging(new MockLogger());
+    }
+
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+    
+    
+    public void testShouldDecoderLengthyQuotedCharset() throws Exception {
+        SearchKey key = SearchKey.buildBcc(LENGTHY_NON_ASCII_SEARCH_TERM);
+        ImapRequestLineReader reader = new ImapRequestLineReader(new ByteArrayInputStream(
+                    add(
+                            add(CHARSET, "BCC".getBytes("US-ASCII")), BYTES_QUOTED_UTF8_LENGTHY_NON_ASCII_SEARCH_TERM)), 
+                new ByteArrayOutputStream());
+        final SearchKey searchKey = parser.searchKey(reader, null, true);
+        assertEquals(key, searchKey);
+    }
+    
+    public void testShouldDecoderQuotedCharset() throws Exception {
+        SearchKey key = SearchKey.buildBcc(NON_ASCII_SEARCH_TERM);
+        ImapRequestLineReader reader = new ImapRequestLineReader(new ByteArrayInputStream(add(add(CHARSET, "BCC".getBytes("US-ASCII")), BYTES_QUOTED_UTF8_NON_ASCII_SEARCH_TERM)), 
+                new ByteArrayOutputStream());
+        final SearchKey searchKey = parser.searchKey(reader, null, true);
+        assertEquals(key, searchKey);
+    }
+    
+    public void testBadCharset() throws Exception {
+        Collection charsetNames = new HashSet();
+        for (final Iterator it = Charset.availableCharsets().values().iterator(); it.hasNext();) {
+            final Charset charset = (Charset) it.next();
+            final Set aliases = charset.aliases();
+            charsetNames.addAll(aliases);
+        }
+        mockStatusResponseFactory.expects(once()).method("taggedNo").with(eq(TAG), same(command), eq(HumanReadableTextKey.BAD_CHARSET), eq(StatusResponse.ResponseCode.badCharset(charsetNames)));
+        ImapRequestLineReader reader = new ImapRequestLineReader(new ByteArrayInputStream("CHARSET BOGUS ".getBytes("US-ASCII")), 
+                new ByteArrayOutputStream());
+        parser.decode(command, reader, TAG, false);
+    }
+    
+    
+    
+    public void testShouldThrowProtocolExceptionWhenBytesAreNotEncodedByCharset() throws Exception {
+        try {
+            ImapRequestLineReader reader = new ImapRequestLineReader(new ByteArrayInputStream(add("CHARSET US-ASCII BCC ".getBytes("US-ASCII"), BYTES_NON_ASCII_SEARCH_TERM)), 
+                    new ByteArrayOutputStream());
+            parser.decode(command, reader, TAG, false);
+            fail("A protocol exception should be thrown when charset is incompatible with input");
+        } catch (ProtocolException e) {
+            //expected
+        }
+    }
+    
+    public void testBCCShouldConvertCharset() throws Exception {
+        SearchKey key = SearchKey.buildBcc(NON_ASCII_SEARCH_TERM);
+        checkUTF8Valid("BCC".getBytes("US-ASCII"), key);
+    }
+    
+    public void testBODYShouldConvertCharset() throws Exception {
+        SearchKey key = SearchKey.buildBody(NON_ASCII_SEARCH_TERM);
+        checkUTF8Valid("BODY".getBytes("US-ASCII"), key);
+    }
+    
+    public void testCCShouldConvertCharset() throws Exception {
+        SearchKey key = SearchKey.buildCc(NON_ASCII_SEARCH_TERM);
+        checkUTF8Valid("CC".getBytes("US-ASCII"), key);   
+    }
+    
+    public void testFROMShouldConvertCharset() throws Exception {
+        SearchKey key = SearchKey.buildFrom(NON_ASCII_SEARCH_TERM);
+        checkUTF8Valid("FROM".getBytes("US-ASCII"), key);
+    }
+    
+    public void testHEADERShouldConvertCharset() throws Exception {
+        SearchKey key = SearchKey.buildHeader("whatever", NON_ASCII_SEARCH_TERM);
+        checkUTF8Valid("HEADER whatever".getBytes("US-ASCII"), key);
+    }
+    
+    public void testSUBJECTShouldConvertCharset() throws Exception {
+        SearchKey key = SearchKey.buildSubject(NON_ASCII_SEARCH_TERM);
+        checkUTF8Valid("SUBJECT".getBytes("US-ASCII"), key);
+    }
+    
+    public void testTEXTShouldConvertCharset() throws Exception {
+        SearchKey key = SearchKey.buildText(NON_ASCII_SEARCH_TERM);
+        checkUTF8Valid("TEXT".getBytes("US-ASCII"), key);
+    }
+    
+    public void testTOShouldConvertCharset() throws Exception {
+        SearchKey key = SearchKey.buildTo(NON_ASCII_SEARCH_TERM);
+        checkUTF8Valid("TO".getBytes("US-ASCII"), key);
+    }
+    
+    public void testASCIICharset() throws Exception {
+        SearchKey key = SearchKey.buildBcc(ASCII_SEARCH_TERM);
+        checkValid("CHARSET US-ASCII BCC \"" + ASCII_SEARCH_TERM + "\"", key, true, "US-ASCII");
+    }
+    
+    public void testSimpleUTF8Charset() throws Exception {
+        SearchKey key = SearchKey.buildBcc(ASCII_SEARCH_TERM);
+        checkValid("CHARSET UTF-8 BCC \"" + ASCII_SEARCH_TERM + "\"", key, true, "US-ASCII");
+    }
+    
+    private void checkUTF8Valid(byte[] term, final SearchKey key) throws Exception {
+        ImapRequestLineReader reader = new ImapRequestLineReader(new ByteArrayInputStream(add(add(CHARSET, term), BYTES_UTF8_NON_ASCII_SEARCH_TERM)), 
+                new ByteArrayOutputStream());
+        final SearchKey searchKey = parser.searchKey(reader, null, true);
+        assertEquals(key, searchKey);
+    }
+    
+    private void checkValid(String input, final SearchKey key, boolean isFirst, String charset) throws Exception {
+        ImapRequestLineReader reader = new ImapRequestLineReader(new ByteArrayInputStream(input.getBytes(charset)), 
+                new ByteArrayOutputStream());
+
+        final SearchKey searchKey = parser.searchKey(reader, null, isFirst);
+        assertEquals(key, searchKey);
+    }
+    
+}



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