Author: niklas
Date: Wed Dec 15 16:00:25 2010
New Revision: 1049622

URL: http://svn.apache.org/viewvc?rev=1049622&view=rev
Log:
Added initial support for IDLE (IMAP-239).

Added:
    
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java
    
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
Modified:
    
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java
    
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java
    
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.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/ImapParserFactory.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/ImapResponseWriter.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/main/ChannelImapResponseWriter.java
    
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java
    
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java
    
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java
    
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java

Added: 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java?rev=1049622&view=auto
==============================================================================
--- 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java
 (added)
+++ 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ContinuationReader.java
 Wed Dec 15 16:00:25 2010
@@ -0,0 +1,27 @@
+/****************************************************************
+ * 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;
+
+import java.io.IOException;
+
+public interface ContinuationReader {
+
+    public String readContinuation() throws IOException;
+    
+}

Modified: 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java 
(original)
+++ 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapConstants.java 
Wed Dec 15 16:00:25 2010
@@ -31,6 +31,8 @@ public interface ImapConstants {
 
     public static final String UNTAGGED = "*";
 
+    public static final String CONTINUATION = "+";
+    
     public static final String SP = " ";
 
     public static final String NIL = "NIL";
@@ -105,6 +107,8 @@ public interface ImapConstants {
 
     public static final String SUPPORTS_STARTTLS = "STARTTLS";
 
+    public static final String SUPPORTS_IDLE = "IDLE";
+    
     public static final char HIERARCHY_DELIMITER_CHAR = '.';
 
     public static final char NAMESPACE_PREFIX_CHAR = '#';
@@ -183,6 +187,8 @@ public interface ImapConstants {
 
     public static final String NOOP_COMMAND_NAME = "NOOP";
 
+    public static final String IDLE_COMMAND_NAME = "IDLE";
+    
     public static final String LSUB_COMMAND_NAME = "LSUB";
 
     public static final String LOGOUT_COMMAND_NAME = "LOGOUT";

Modified: 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java
 (original)
+++ 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/ImapMessageFactory.java
 Wed Dec 15 16:00:25 2010
@@ -68,6 +68,9 @@ public interface ImapMessageFactory {
     public ImapMessage createNoopMessage(final ImapCommand command,
             final String tag);
 
+    public ImapMessage createIdleMessage(final ImapCommand command,
+            final ContinuationReader reader, final String tag);
+    
     public ImapMessage createCloseMessage(final ImapCommand command,
             final String tag);
 

Modified: 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
 (original)
+++ 
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.java
 Wed Dec 15 16:00:25 2010
@@ -196,6 +196,9 @@ public class HumanReadableText {
     public static final HumanReadableText BYE_UNKNOWN_COMMAND = new 
HumanReadableText(
             "org.apache.james.imap.BYE_UNKNOWN_COMMAND", "Unknown command.");
 
+    public static final HumanReadableText IDLING = new HumanReadableText(
+            "org.apache.james.imap.IDLING", "Idling");
+    
     private final String defaultValue;
 
     private final String key;

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=1049622&r1=1049621&r2=1049622&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
 Wed Dec 15 16:00:25 2010
@@ -19,8 +19,10 @@
 
 package org.apache.james.imap.decode;
 
+import java.io.IOException;
 import java.io.InputStream;
 
+import org.apache.james.imap.api.ContinuationReader;
 import org.apache.james.imap.api.display.HumanReadableText;
 
 /**
@@ -30,7 +32,7 @@ import org.apache.james.imap.api.display
  * 
  * @version $Revision: 109034 $
  */
-public abstract class ImapRequestLineReader {
+public abstract class ImapRequestLineReader implements ContinuationReader {
     
 
     protected boolean nextSeen = false;
@@ -154,4 +156,22 @@ public abstract class ImapRequestLineRea
         }
         consume();
     }
+    
+    public String readContinuation() throws IOException {
+        // Consume the '\n' from the previous line.
+        consume();
+        
+        StringBuilder sb = new StringBuilder();
+        char next = nextChar();
+        while (next != '\r') {
+            sb.append(next);
+            consume();
+            next = nextChar();
+        }
+        consume();
+
+        // NOTE: This code leaves the '\n' as next char. This seems to be what 
is expected by the code which parses commands.
+        
+        return sb.toString();
+    }
 }

Added: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java?rev=1049622&view=auto
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java
 (added)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/IdleCommandParser.java
 Wed Dec 15 16:00:25 2010
@@ -0,0 +1,51 @@
+/****************************************************************
+ * 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.decode.parser;
+
+import org.apache.commons.logging.Log;
+import org.apache.james.imap.api.ImapCommand;
+import org.apache.james.imap.api.ImapConstants;
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.decode.ImapRequestLineReader;
+import org.apache.james.imap.decode.DecodingException;
+import org.apache.james.imap.decode.base.AbstractImapCommandParser;
+
+/**
+ *
+ * Parses IDLE commands
+ *
+ */
+public class IdleCommandParser extends AbstractImapCommandParser {
+
+    public IdleCommandParser() {
+        
super(ImapCommand.selectedStateCommand(ImapConstants.IDLE_COMMAND_NAME));
+    }
+
+    /*
+     * (non-Javadoc)
+     * @see 
org.apache.james.imap.decode.base.AbstractImapCommandParser#decode(org.apache.james.imap.api.ImapCommand,
 org.apache.james.imap.decode.ImapRequestLineReader, java.lang.String, 
org.apache.commons.logging.Log)
+     */
+    protected ImapMessage decode(ImapCommand command,
+            ImapRequestLineReader request, String tag, Log logger) throws 
DecodingException {
+        endLine(request);
+        final ImapMessage result = 
getMessageFactory().createIdleMessage(command, request, tag);
+        return result;
+    }
+
+}

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ImapParserFactory.java
 Wed Dec 15 16:00:25 2010
@@ -104,7 +104,7 @@ public class ImapParserFactory implement
         // _imapCommands.put( "MYRIGHTS", MyRightsCommand.class );
 
         // Commands only valid in SELECTED state.
-        // CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, and UID
+        // CHECK, CLOSE, EXPUNGE, SEARCH, FETCH, STORE, COPY, UID and IDLE
         _imapCommands.put(ImapConstants.CHECK_COMMAND_NAME,
                 CheckCommandParser.class);
         _imapCommands.put(ImapConstants.CLOSE_COMMAND_NAME,
@@ -121,6 +121,8 @@ public class ImapParserFactory implement
                 StoreCommandParser.class);
         _imapCommands.put(ImapConstants.UID_COMMAND_NAME,
                 UidCommandParser.class);
+        _imapCommands.put(ImapConstants.IDLE_COMMAND_NAME,
+                IdleCommandParser.class);
         _imapCommands.put(ImapConstants.STARTTLS, StartTLSCommandParser.class);
     }
 

Added: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java?rev=1049622&view=auto
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java
 (added)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ContinuationResponseEncoder.java
 Wed Dec 15 16:00:25 2010
@@ -0,0 +1,60 @@
+/****************************************************************
+ * 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.ArrayList;
+import java.util.Locale;
+
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.api.display.Locales;
+import org.apache.james.imap.api.display.Localizer;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.encode.base.AbstractChainedImapEncoder;
+import org.apache.james.imap.message.response.ContinuationResponse;
+
+public class ContinuationResponseEncoder extends AbstractChainedImapEncoder {
+
+    private final Localizer localizer;
+    
+    public ContinuationResponseEncoder(ImapEncoder next, final Localizer 
localizer) {
+        super(next);
+        this.localizer = localizer;
+    }
+
+    protected void doEncode(ImapMessage acceptableMessage,
+            ImapResponseComposer composer, ImapSession session) throws 
IOException {
+        
+        ContinuationResponse response = (ContinuationResponse) 
acceptableMessage;
+        final String message = response.getData() != null ? response.getData() 
: asString(response.getTextKey(), session);
+        composer.continuationResponse(message);
+    }
+
+    private String asString(HumanReadableText text, ImapSession session) {
+        // TODO: calculate locales
+        return localizer.localize(text, new Locales(new ArrayList<Locale>(), 
null));
+    }
+
+    protected boolean isAcceptable(ImapMessage message) {
+        return (message instanceof ContinuationResponse);
+    }
+
+}

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=1049622&r1=1049621&r2=1049622&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
 Wed Dec 15 16:00:25 2010
@@ -293,4 +293,13 @@ public interface ImapResponseComposer {
      * @throws IOException 
      */
     public ImapResponseComposer capabilities(List<String> capabilities) throws 
IOException;
+    
+    /**
+     * Writes a continuation response.
+     * 
+     * @param message
+     *            message for display, not null
+     */
+    public abstract void continuationResponse(String message) throws 
IOException;
+
 }
\ No newline at end of file

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseWriter.java
 Wed Dec 15 16:00:25 2010
@@ -47,6 +47,14 @@ public interface ImapResponseWriter {
     void tag(String tag) throws IOException;
 
     /**
+     * Starts a continuation response.
+     * 
+     * @param message
+     *            the message, not null
+     */
+    void continuation(String message) throws IOException;
+    
+    /**
      * Writes a command name.
      * 
      * @param commandName

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=1049622&r1=1049621&r2=1049622&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
 Wed Dec 15 16:00:25 2010
@@ -90,6 +90,15 @@ public class ImapResponseComposerImpl im
 
     /**
      * @throws IOException
+     * @see 
org.apache.james.imap.encode.ImapResponseComposer#continuationResponse(String)
+     */
+    public void continuationResponse(String message) throws IOException {
+        writer.continuation(message);
+        end();
+    }
+    
+    /**
+     * @throws IOException
      * @see 
org.apache.james.imap.encode.ImapResponseComposer#flagsResponse(javax.mail.Flags)
      */
     public void flagsResponse(Flags flags) throws IOException {

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=1049622&r1=1049621&r2=1049622&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
 Wed Dec 15 16:00:25 2010
@@ -21,6 +21,7 @@ package org.apache.james.imap.encode.mai
 
 import org.apache.james.imap.api.display.Localizer;
 import org.apache.james.imap.encode.CapabilityResponseEncoder;
+import org.apache.james.imap.encode.ContinuationResponseEncoder;
 import org.apache.james.imap.encode.ExistsResponseEncoder;
 import org.apache.james.imap.encode.ExpungeResponseEncoder;
 import org.apache.james.imap.encode.FetchResponseEncoder;
@@ -73,7 +74,9 @@ public class DefaultImapEncoderFactory i
                 listResponseEncoder);
         final CapabilityResponseEncoder capabilityResponseEncoder = new 
CapabilityResponseEncoder(
                 flagsResponseEncoder);
-        return capabilityResponseEncoder;
+        final ContinuationResponseEncoder continuationResponseEncoder = new 
ContinuationResponseEncoder(
+                capabilityResponseEncoder, localizer);
+        return continuationResponseEncoder;
     }
 
     private final Localizer localizer;

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/main/ChannelImapResponseWriter.java
 Wed Dec 15 16:00:25 2010
@@ -253,4 +253,8 @@ public class ChannelImapResponseWriter i
     public void quoteUpperCaseAscii(String message) throws IOException {
         upperCaseAscii(message, true);
     }
+    
+    public void continuation(String message) throws IOException {
+        writeASCII(CONTINUATION + SP + message);
+    }
 }

Modified: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java
 (original)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/BaseImap4Rev1MessageFactory.java
 Wed Dec 15 16:00:25 2010
@@ -23,6 +23,7 @@ import java.util.Date;
 
 import javax.mail.Flags;
 
+import org.apache.james.imap.api.ContinuationReader;
 import org.apache.james.imap.api.ImapMessageFactory;
 import org.apache.james.imap.api.ImapCommand;
 import org.apache.james.imap.api.ImapMessage;
@@ -85,6 +86,14 @@ public class BaseImap4Rev1MessageFactory
 
     /*
      * (non-Javadoc)
+     * @see 
org.apache.james.imap.api.ImapMessageFactory#createNoopMessage(org.apache.james.imap.api.ImapCommand,
 java.lang.String)
+     */
+    public ImapMessage createIdleMessage(ImapCommand command, 
ContinuationReader reader, String tag) {
+        return new IdleRequest(command, reader, tag);
+    }
+    
+    /*
+     * (non-Javadoc)
      * @see 
org.apache.james.imap.api.ImapMessageFactory#createCloseMessage(org.apache.james.imap.api.ImapCommand,
 java.lang.String)
      */
     public ImapMessage createCloseMessage(ImapCommand command, String tag) {

Added: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java?rev=1049622&view=auto
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java
 (added)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/IdleRequest.java
 Wed Dec 15 16:00:25 2010
@@ -0,0 +1,36 @@
+/****************************************************************
+ * 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.request;
+
+import org.apache.james.imap.api.ContinuationReader;
+import org.apache.james.imap.api.ImapCommand;
+
+public class IdleRequest extends AbstractImapRequest {
+    
+    private final ContinuationReader reader;
+
+    public IdleRequest(ImapCommand command, ContinuationReader reader, String 
tag) {
+        super(tag, command);
+        this.reader = reader;
+    }
+    
+    public ContinuationReader getContinuationReader() {
+        return reader;
+    }
+}

Added: 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java?rev=1049622&view=auto
==============================================================================
--- 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java
 (added)
+++ 
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/response/ContinuationResponse.java
 Wed Dec 15 16:00:25 2010
@@ -0,0 +1,50 @@
+/****************************************************************
+ * 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 org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.api.message.response.ImapResponseMessage;
+
+public class ContinuationResponse implements ImapResponseMessage {
+
+    private final String data;
+
+    private final HumanReadableText textKey;
+
+    public ContinuationResponse(final String data) {
+        super();
+        this.data = data;
+        this.textKey = null;
+    }
+
+    public ContinuationResponse(final HumanReadableText textKey) {
+        super();
+        this.data = null;
+        this.textKey = textKey;
+    }
+    
+    public String getData() {
+        return data;
+    }
+    
+    public HumanReadableText getTextKey() {
+        return textKey;
+    }
+}

Modified: 
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java
 (original)
+++ 
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/MockImapResponseWriter.java
 Wed Dec 15 16:00:25 2010
@@ -279,6 +279,17 @@ public class MockImapResponseWriter impl
 
     }
 
+    public static class ContinuationOperation {
+        public boolean equals(Object obj) {
+            return obj instanceof ContinuationOperation;
+        }
+
+        public int hashCode() {
+            return 3;
+        }
+
+    }
+    
     public void closeParen() {
         operations.add(new BracketOperation(false, false));
     }
@@ -442,4 +453,8 @@ public class MockImapResponseWriter impl
 
     public void space() {
     }
+    
+    public void continuation(String message) {
+        operations.add(new ContinuationOperation());
+    }
 }

Modified: 
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java
 (original)
+++ 
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ByteImapResponseWriter.java
 Wed Dec 15 16:00:25 2010
@@ -204,4 +204,8 @@ public class ByteImapResponseWriter impl
     public void quoteUpperCaseAscii(String message) {
         upperCaseAscii(message, true);
     }
+    
+    public void continuation(String message) throws IOException {
+        writer.print(CONTINUATION + SP + message);
+    }
 }

Modified: 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java?rev=1049622&r1=1049621&r2=1049622&view=diff
==============================================================================
--- 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
 (original)
+++ 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/DefaultProcessorChain.java
 Wed Dec 15 16:00:25 2010
@@ -84,8 +84,10 @@ public class DefaultProcessorChain {
                 appendProcessor, mailboxManager, statusResponseFactory);
         final NoopProcessor noopProcessor = new NoopProcessor(storeProcessor,
                 mailboxManager, statusResponseFactory);
+        final IdleProcessor idleProcessor = new IdleProcessor(noopProcessor,
+                mailboxManager, statusResponseFactory);
         final StatusProcessor statusProcessor = new StatusProcessor(
-                noopProcessor, mailboxManager, statusResponseFactory);
+                idleProcessor, mailboxManager, statusResponseFactory);
         final LSubProcessor lsubProcessor = new LSubProcessor(statusProcessor,
                 mailboxManager, subscriptionManager, statusResponseFactory);
         final ListProcessor listProcessor = new ListProcessor(lsubProcessor,
@@ -97,6 +99,7 @@ public class DefaultProcessorChain {
         final NamespaceProcessor namespaceProcessor = new NamespaceProcessor(
                 selectProcessor, mailboxManager, statusResponseFactory);
         
+        capabilityProcessor.addProcessor(idleProcessor);
         capabilityProcessor.addProcessor(namespaceProcessor);
         
         final ImapProcessor fetchProcessor = new 
FetchProcessor(namespaceProcessor,

Added: 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java?rev=1049622&view=auto
==============================================================================
--- 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
 (added)
+++ 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/IdleProcessor.java
 Wed Dec 15 16:00:25 2010
@@ -0,0 +1,134 @@
+/****************************************************************
+ * 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.processor;
+
+import static org.apache.james.imap.api.ImapConstants.SUPPORTS_IDLE;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.james.imap.api.ContinuationReader;
+import org.apache.james.imap.api.ImapCommand;
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.api.message.request.ImapRequest;
+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;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.message.request.IdleRequest;
+import org.apache.james.imap.message.response.ContinuationResponse;
+import org.apache.james.imap.processor.base.ImapSessionUtils;
+import org.apache.james.mailbox.MailboxException;
+import org.apache.james.mailbox.MailboxListener;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+
+public class IdleProcessor extends AbstractMailboxProcessor implements 
CapabilityImplementingProcessor {
+
+    private final StatusResponseFactory factory;
+    
+    public IdleProcessor(final ImapProcessor next, final MailboxManager 
mailboxManager,
+            final StatusResponseFactory factory) {
+        super(next, mailboxManager, factory);
+        
+        this.factory = factory;
+    }
+
+    protected boolean isAcceptable(ImapMessage message) {
+        return (message instanceof IdleRequest);
+    }
+
+    protected void doProcess(ImapRequest message, ImapSession session,
+            String tag, ImapCommand command, Responder responder) {
+
+        try {
+            IdleRequest request = (IdleRequest) message;
+            ContinuationReader reader = request.getContinuationReader();
+        
+            responder.respond(new 
ContinuationResponse(HumanReadableText.IDLING));
+            unsolicitedResponses(session, responder, false);
+
+            MailboxManager mailboxManager = getMailboxManager();
+            MailboxSession mailboxSession = 
ImapSessionUtils.getMailboxSession(session);
+            AtomicBoolean closed = new AtomicBoolean(false);
+            
+            String line = null;
+            try {
+                mailboxManager.addListener(session.getSelected().getPath(), 
+                        new IdleMailboxListener(closed, session, responder), 
mailboxSession);
+            
+                line = reader.readContinuation();
+            } finally {
+                synchronized (session) {
+                    closed.set(true);
+                }
+            }
+            if (!"DONE".equals(line.toUpperCase())) {
+                StatusResponse response = factory.taggedBad(tag, command,
+                        HumanReadableText.INVALID_COMMAND);
+                responder.respond(response);
+            } else {
+                okComplete(command, tag, responder);
+            }
+        } catch (IOException e) {
+            // TODO: What should we do here?
+            no(command, tag, responder, 
HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING);
+        } catch (MailboxException e) {
+            // TODO: What should we do here?
+            no(command, tag, responder, 
HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING);
+        }
+    }
+
+    public List<String> getImplementedCapabilities(ImapSession session) {
+        return Arrays.asList(SUPPORTS_IDLE);
+    }
+    
+    private class IdleMailboxListener implements MailboxListener {
+        
+        private final AtomicBoolean closed;
+        private final ImapSession session;
+        private final Responder responder;
+        
+        public IdleMailboxListener(AtomicBoolean closed, ImapSession session, 
Responder responder) {
+            this.closed = closed;
+            this.session = session;
+            this.responder = responder;
+        }
+
+        public void event(Event event) {
+            synchronized (session) {
+                if (isClosed()) {
+                    return;
+                }
+                if (event instanceof Added || event instanceof Expunged || 
event instanceof FlagsUpdated) {
+                    unsolicitedResponses(session, responder, false);
+                }
+            }
+        }
+
+        public boolean isClosed() {
+            return closed.get();
+        }
+        
+    }
+}



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

Reply via email to