Author: norman
Date: Sun Jan 30 12:38:15 2011
New Revision: 1065257
URL: http://svn.apache.org/viewvc?rev=1065257&view=rev
Log:
Add better support for UIDPLUS. See IMAP-252. Thanks to Wojtek Strzalka for the
patch which was applied with one change to remove dependency on commons-lang
Modified:
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/IdRange.java
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.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/StatusResponseEncoder.java
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/AbstractTestImapResponseComposer.java
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ImapResponseComposerImplTest.java
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AppendProcessor.java
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/CopyProcessor.java
Modified:
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/IdRange.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/IdRange.java?rev=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/IdRange.java
(original)
+++
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/IdRange.java
Sun Jan 30 12:38:15 2011
@@ -113,6 +113,13 @@ public class IdRange {
return retValue;
}
+ public String getFormattedString() {
+ if(this._lowVal == this._highVal)
+ return Long.toString(this._lowVal);
+ else
+ return this._lowVal+":"+this._highVal;
+ }
+
/**
* Utility method which will copy the given {@link List} and try to merge
the
* {@link IdRange} in the copy before return it.
Modified:
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.java?rev=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.java
(original)
+++
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/message/response/StatusResponse.java
Sun Jan 30 12:38:15 2011
@@ -19,6 +19,7 @@
package org.apache.james.imap.api.message.response;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -26,6 +27,7 @@ import javax.mail.Flags;
import org.apache.james.imap.api.ImapCommand;
import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.api.message.IdRange;
import org.apache.james.imap.api.message.MessageFlags;
/**
@@ -127,6 +129,33 @@ public interface StatusResponse extends
private static final ResponseCode TRYCREATE = new ResponseCode(
"TRYCREATE");
+ /** RFC4315 <code>APPENDUID</code> response code */
+ public static final ResponseCode appendUid(long uidValidity, IdRange[]
uids) {
+ String uidParam = formatRanges(uids);
+ return new ResponseCode("APPENDUID", Arrays.asList(uidParam),
uidValidity, false);
+ }
+
+ /** RFC4315 <code>COPYUID</code> response code */
+ public static final ResponseCode copyUid(long uidValidity, IdRange[]
sourceRanges, IdRange[] targetRanges) {
+ String source = formatRanges(sourceRanges);
+ String target = formatRanges(targetRanges);
+
+ return new ResponseCode("COPYUID", Arrays.asList(new String[] {
source, target }), uidValidity, false);
+ }
+
+ private static String formatRanges(IdRange[] ranges) {
+ if (ranges == null || ranges.length == 0)
+ return "*";
+ StringBuilder rangeBuilder = new StringBuilder();
+ for (int i = 0; i < ranges.length; i++) {
+ rangeBuilder.append(ranges[i].getFormattedString());
+ if (i + 1 < ranges.length) {
+ rangeBuilder.append(",");
+ }
+ }
+ return rangeBuilder.toString();
+ }
+
/**
* Creates a RFC2060 <code>ALERT</code> response code.
*
@@ -251,24 +280,27 @@ public interface StatusResponse extends
private final Collection<String> parameters;
private final long number;
+
+ private final boolean useParens;
@SuppressWarnings ("unchecked")
private ResponseCode(final String code) {
- this(code, Collections.EMPTY_LIST, 0);
+ this(code, Collections.EMPTY_LIST, 0, true);
}
@SuppressWarnings ("unchecked")
private ResponseCode(final String code, final long number) {
- this(code, Collections.EMPTY_LIST, number);
+ this(code, Collections.EMPTY_LIST, number, true);
}
private ResponseCode(final String code, final Collection<String>
parameters) {
- this(code, parameters, 0);
+ this(code, parameters, 0, true);
}
private ResponseCode(final String code, final Collection<String>
parameters,
- final long number) {
+ final long number, final boolean useParens) {
super();
+ this.useParens = useParens;
this.code = code;
this.parameters = parameters;
this.number = number;
@@ -287,6 +319,10 @@ public interface StatusResponse extends
return number;
}
+ public final boolean useParens() {
+ return useParens;
+ }
+
/**
* Gets parameters for this code.
*
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=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/ImapResponseComposer.java
Sun Jan 30 12:38:15 2011
@@ -201,7 +201,7 @@ public interface ImapResponseComposer {
public abstract void statusResponse(String tag, ImapCommand command,
String type, String responseCode, Collection<String> parameters,
- long number, String text) throws IOException;
+ boolean useParens, long number, String text) throws IOException;
public abstract void statusResponse(Long messages, Long recent,
Long uidNext, Long uidValidity, Long unseen, String mailboxName)
Modified:
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/StatusResponseEncoder.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/StatusResponseEncoder.java?rev=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/StatusResponseEncoder.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/StatusResponseEncoder.java
Sun Jan 30 12:38:15 2011
@@ -57,14 +57,17 @@ public class StatusResponseEncoder exten
final String text = asString(textKey, session);
final Collection<String> parameters;
final long number;
+ final boolean useParens;
if (responseCode == null) {
parameters = null;
number = 0;
+ useParens = false;
} else {
parameters = responseCode.getParameters();
number = responseCode.getNumber();
+ useParens = responseCode.useParens();
}
- composer.statusResponse(tag, command, type, code, parameters, number,
+ composer.statusResponse(tag, command, type, code, parameters,
useParens, number,
text);
}
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=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/encode/base/ImapResponseComposerImpl.java
Sun Jan 30 12:38:15 2011
@@ -267,7 +267,7 @@ public class ImapResponseComposerImpl im
* java.lang.String, Collection, long, java.lang.String)
*/
public void statusResponse(String tag, ImapCommand command, String type,
- String responseCode, Collection<String> parameters, long number,
String text)
+ String responseCode, Collection<String> parameters, boolean
useParens, long number, String text)
throws IOException {
if (tag == null) {
untagged();
@@ -278,16 +278,18 @@ public class ImapResponseComposerImpl im
if (responseCode != null) {
openSquareBracket();
message(responseCode);
+ if (number > 0) {
+ message(number);
+ }
if (parameters != null && !parameters.isEmpty()) {
- openParen();
+ if(useParens)
+ openParen();
for (Iterator<String> it = parameters.iterator();
it.hasNext();) {
final String parameter = it.next();
message(parameter);
}
- closeParen();
- }
- if (number > 0) {
- message(number);
+ if(useParens)
+ closeParen();
}
closeSquareBracket();
}
Modified:
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/AbstractTestImapResponseComposer.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/AbstractTestImapResponseComposer.java?rev=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/AbstractTestImapResponseComposer.java
(original)
+++
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/AbstractTestImapResponseComposer.java
Sun Jan 30 12:38:15 2011
@@ -155,11 +155,11 @@ public abstract class AbstractTestImapRe
@Test
public void testShouldEncodeUnparameterisedStatus() throws Exception {
checkStatusResponseEncode("A1 NO [ALERT] APPEND failed\r\n", "A1",
- command("APPEND"), "NO", "ALERT", new ArrayList<String>(), 0,
+ command("APPEND"), "NO", "ALERT", new ArrayList<String>(),
true, 0,
"failed");
checkStatusResponseEncode("A1 BAD [TRYCREATE] SELECT whatever\r\n",
"A1", command("SELECT"), "BAD", "TRYCREATE",
- new ArrayList<String>(), 0, "whatever");
+ new ArrayList<String>(), true, 0, "whatever");
}
@Test
@@ -170,15 +170,31 @@ public abstract class AbstractTestImapRe
parameters.add("THREE");
checkStatusResponseEncode(
"A1 NO [BADCHARSET (ONE TWO THREE)] APPEND failed\r\n", "A1",
- command("APPEND"), "NO", "BADCHARSET", parameters, 0,
"failed");
+ command("APPEND"), "NO", "BADCHARSET", parameters, true, 0,
"failed");
}
@Test
public void testShouldEncodeNumberParameterStatus() throws Exception {
checkStatusResponseEncode("A1 NO [UIDNEXT 10] APPEND failed\r\n", "A1",
- command("APPEND"), "NO", "UIDNEXT", null, 10, "failed");
+ command("APPEND"), "NO", "UIDNEXT", null, true, 10, "failed");
}
+ @Test
+ public void testShouldEncodeNumberAndListParameterStatus() throws
Exception {
+ Collection<String> parameters = new ArrayList<String>();
+ parameters.add("1:2");
+ parameters.add("3:4");
+
+ checkStatusResponseEncode("A1 OK [COPYUID 10 1:2 3:4] COPY
completed\r\n", "A1",
+ command("COPY"), "OK", "COPYUID", parameters, false, 10,
"completed");
+
+ parameters.clear();
+ parameters.add("3");
+
+ checkStatusResponseEncode("A1 OK [APPENDUID 10 3] APPEND
completed\r\n", "A1",
+ command("APPEND"), "OK", "APPENDUID", parameters, false, 10,
"completed");
+ }
+
private void checkFlagsEncode(String expected, Flags flags)
throws Exception {
StringBuffer buffer = new StringBuffer();
@@ -243,14 +259,14 @@ public abstract class AbstractTestImapRe
protected abstract byte[] encodeStatusResponse(String tag,
ImapCommand command, String type, String responseCode,
- Collection<String> parameters, int number, String text) throws
Exception;
+ Collection<String> parameters, boolean useParens, int number,
String text) throws Exception;
private void checkStatusResponseEncode(String expected, String tag,
ImapCommand command, String type, String responseCode,
- Collection<String> parameters, int number, String text) throws
Exception {
+ Collection<String> parameters, boolean useParens, int number,
String text) throws Exception {
StringBuffer buffer = new StringBuffer();
byte[] output = encodeStatusResponse(tag, command, type, responseCode,
- parameters, number, text);
+ parameters, useParens, number, text);
for (int i = 0; i < output.length; i++) {
buffer.append((char) output[i]);
}
Modified:
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ImapResponseComposerImplTest.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ImapResponseComposerImplTest.java?rev=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ImapResponseComposerImplTest.java
(original)
+++
james/imap/trunk/message/src/test/java/org/apache/james/imap/encode/base/ImapResponseComposerImplTest.java
Sun Jan 30 12:38:15 2011
@@ -71,10 +71,10 @@ public class ImapResponseComposerImplTes
}
protected byte[] encodeStatusResponse(String tag, ImapCommand command,
- String type, String responseCode, Collection<String> parameters,
- int number, String text) throws Exception {
+ String type, String responseCode, Collection<String> parameters,
+ boolean useParens, int number, String text) throws Exception {
composer.statusResponse(tag, command, type, responseCode, parameters,
- number, text);
+ useParens, number, text);
return writer.getBytes();
}
Modified:
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java?rev=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
(original)
+++
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractMailboxProcessor.java
Sun Jan 30 12:38:15 2011
@@ -31,6 +31,7 @@ import org.apache.james.imap.api.message
import org.apache.james.imap.api.message.response.ImapResponseMessage;
import org.apache.james.imap.api.message.response.StatusResponse;
import org.apache.james.imap.api.message.response.StatusResponseFactory;
+import org.apache.james.imap.api.message.response.StatusResponse.ResponseCode;
import org.apache.james.imap.api.process.ImapProcessor;
import org.apache.james.imap.api.process.ImapSession;
import org.apache.james.imap.api.process.SelectedMailbox;
@@ -241,6 +242,13 @@ abstract public class AbstractMailboxPro
HumanReadableText.COMPLETED);
responder.respond(response);
}
+
+ protected void okComplete(final ImapCommand command, final String tag,
+ final ResponseCode code, final ImapProcessor.Responder
responder) {
+ final StatusResponse response = factory.taggedOk(tag, command,
+ HumanReadableText.COMPLETED, code);
+ responder.respond(response);
+ }
protected void no(final ImapCommand command, final String tag,
final ImapProcessor.Responder responder,
Modified:
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AppendProcessor.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AppendProcessor.java?rev=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AppendProcessor.java
(original)
+++
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AppendProcessor.java
Sun Jan 30 12:38:15 2011
@@ -29,8 +29,10 @@ import org.apache.commons.logging.Log;
import org.apache.james.imap.api.ImapCommand;
import org.apache.james.imap.api.ImapSessionUtils;
import org.apache.james.imap.api.display.HumanReadableText;
+import org.apache.james.imap.api.message.IdRange;
import org.apache.james.imap.api.message.response.StatusResponse;
import org.apache.james.imap.api.message.response.StatusResponseFactory;
+import org.apache.james.imap.api.message.response.StatusResponse.ResponseCode;
import org.apache.james.imap.api.process.ImapProcessor;
import org.apache.james.imap.api.process.ImapSession;
import org.apache.james.imap.api.process.SelectedMailbox;
@@ -41,6 +43,7 @@ import org.apache.james.mailbox.MailboxN
import org.apache.james.mailbox.MailboxPath;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.MessageManager.MetaData.FetchGroup;
public class AppendProcessor extends AbstractMailboxProcessor<AppendRequest> {
@@ -69,7 +72,7 @@ public class AppendProcessor extends Abs
command, mailbox, responder, mailboxPath);
} catch (MailboxNotFoundException e) {
// consume message on exception
- cosume(messageIn);
+ consume(messageIn);
// Indicates that the mailbox does not exist
// So TRY CREATE
@@ -77,7 +80,7 @@ public class AppendProcessor extends Abs
} catch (MailboxException e) {
// consume message on exception
- cosume(messageIn);
+ consume(messageIn);
// Some other issue
no(command, tag, responder,
HumanReadableText.GENERIC_FAILURE_DURING_PROCESSING);
@@ -86,7 +89,7 @@ public class AppendProcessor extends Abs
}
- private void cosume(InputStream in) {
+ private void consume(InputStream in) {
try {
while(in.read() != -1);
} catch (IOException e1) {
@@ -121,6 +124,7 @@ public class AppendProcessor extends Abs
try {
final MailboxSession mailboxSession =
ImapSessionUtils.getMailboxSession(session);
final SelectedMailbox selectedMailbox = session.getSelected();
+ final MailboxManager mailboxManager = getMailboxManager();
final boolean isSelectedMailbox = selectedMailbox != null
&& selectedMailbox.getPath().equals(mailboxPath);
final long uid = mailbox.appendMessage(message, datetime,
mailboxSession,
@@ -128,8 +132,14 @@ public class AppendProcessor extends Abs
if (isSelectedMailbox) {
selectedMailbox.addRecent(uid);
}
+
+ // get folder UIDVALIDITY
+ Long uidValidity = mailboxManager.getMailbox(mailboxPath,
mailboxSession).getMetaData(false, mailboxSession,
FetchGroup.NO_UNSEEN).getUidValidity();
+
unsolicitedResponses(session, responder, false);
- okComplete(command, tag, responder);
+
+ // in case of MULTIAPPEND support we will push more then one UID
here
+ okComplete(command, tag, ResponseCode.appendUid(uidValidity, new
IdRange[] { new IdRange(uid) }), responder);
} catch (MailboxNotFoundException e) {
// Indicates that the mailbox does not exist
// So TRY CREATE
Modified:
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/CopyProcessor.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/CopyProcessor.java?rev=1065257&r1=1065256&r2=1065257&view=diff
==============================================================================
---
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/CopyProcessor.java
(original)
+++
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/CopyProcessor.java
Sun Jan 30 12:38:15 2011
@@ -19,10 +19,15 @@
package org.apache.james.imap.processor;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.james.imap.api.ImapCommand;
import org.apache.james.imap.api.ImapSessionUtils;
import org.apache.james.imap.api.display.HumanReadableText;
import org.apache.james.imap.api.message.IdRange;
+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.message.response.StatusResponse.ResponseCode;
import org.apache.james.imap.api.message.response.StatusResponseFactory;
import org.apache.james.imap.api.process.ImapProcessor;
@@ -35,6 +40,7 @@ import org.apache.james.mailbox.MailboxM
import org.apache.james.mailbox.MailboxPath;
import org.apache.james.mailbox.MailboxSession;
import org.apache.james.mailbox.MessageRange;
+import org.apache.james.mailbox.MessageManager.MetaData.FetchGroup;
public class CopyProcessor extends AbstractMailboxProcessor<CopyRequest> {
@@ -62,15 +68,23 @@ public class CopyProcessor extends Abstr
no(command, tag, responder,
HumanReadableText.FAILURE_NO_SUCH_MAILBOX,
ResponseCode.tryCreate());
} else {
+ List<IdRange> resultRanges=new ArrayList<IdRange>();
for (int i = 0; i < idSet.length; i++) {
-
MessageRange messageSet = messageRange(currentMailbox,
idSet[i], useUids);
- mailboxManager.copyMessages(messageSet,
currentMailbox.getPath(),
- targetMailbox, mailboxSession);
+ List<MessageRange> copiedUids =
mailboxManager.copyMessages(messageSet, currentMailbox.getPath(),
targetMailbox, mailboxSession);
+
+ for (MessageRange mr : copiedUids) {
+ resultRanges.add(new IdRange(mr.getUidFrom(),
mr.getUidTo()));
+ }
}
+ IdRange[] resultUids =
IdRange.mergeRanges(resultRanges).toArray(new IdRange[0]);
+
+ // get folder UIDVALIDITY
+ Long uidValidity = mailboxManager.getMailbox(targetMailbox,
mailboxSession).getMetaData(false, mailboxSession,
FetchGroup.NO_UNSEEN).getUidValidity();
+
unsolicitedResponses(session, responder, useUids);
- okComplete(command, tag, responder);
+ okComplete(command, tag, ResponseCode.copyUid(uidValidity,
idSet, resultUids), responder);
}
} catch (MessageRangeException e) {
taggedBad(command, tag, responder,
HumanReadableText.INVALID_MESSAGESET);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]