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