Author: norman
Date: Tue Jul 12 18:21:42 2011
New Revision: 1145703
URL: http://svn.apache.org/viewvc?rev=1145703&view=rev
Log:
Start to work on CONDSTORE extension. Still work in progress. See IMAP-305
Added:
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java
Modified:
james/imap/trunk/api/src/main/java/org/apache/james/imap/api/display/HumanReadableText.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/decode/parser/ExamineCommandParser.java
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SelectRequest.java
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/StoreRequest.java
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StoreProcessor.java
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=1145703&r1=1145702&r2=1145703&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
Tue Jul 12 18:21:42 2011
@@ -39,6 +39,9 @@ public class HumanReadableText {
}
public static final HumanReadableText UIDNEXT = new
HumanReadableText("org.apache.james.imap.UIDNEXT", "Predicted next UID");
+
+ public static final HumanReadableText HIGHEST_MOD_SEQ = new
HumanReadableText("org.apache.james.imap.HIGHEST_MOD_SEQ", "");
+ public static final HumanReadableText NO_MOD_SEQ = new
HumanReadableText("org.apache.james.imap.NO_MOD_SEQ", "Sorry, this mailbox
format doesn't support modsequences");
public static final HumanReadableText UID_VALIDITY = new
HumanReadableText("org.apache.james.imap.UID_VALIDITY", "UIDs valid");
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=1145703&r1=1145702&r2=1145703&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
Tue Jul 12 18:21:42 2011
@@ -253,6 +253,28 @@ public interface StatusResponse extends
return new ResponseCode("UIDNEXT", uid);
}
+
+ /**
+ * Create a RFC4551 <code>HIGESTMODSEQ</code> response code
+ *
+ * @param modSeq positive non-zero long
+ * @return <code>ResponseCode</code>
+ */
+ public static ResponseCode highestModSeq(long modSeq) {
+ return new ResponseCode("HIGESTMODSEQ", modSeq);
+ }
+
+ /**
+ * Create a RFC4551 <code>NOMODSEQ</code> response code
+ *
+ * @return <code>ResponseCode</code>
+ */
+ public static ResponseCode noModSeq() {
+ return new ResponseCode("NOMODSEQ");
+ }
+
+
+
/**
* Creates an extension response code. Names that do not begin with 'X'
* will have 'X' prepended
Added:
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java?rev=1145703&view=auto
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java
(added)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/AbstractSelectionCommandParser.java
Tue Jul 12 18:21:42 2011
@@ -0,0 +1,82 @@
+/****************************************************************
+ * 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.james.imap.api.ImapCommand;
+import org.apache.james.imap.api.ImapMessage;
+import org.apache.james.imap.api.process.ImapSession;
+import org.apache.james.imap.decode.DecodingException;
+import org.apache.james.imap.decode.ImapRequestLineReader;
+import org.apache.james.imap.decode.ImapRequestLineReader.CharacterValidator;
+import org.apache.james.imap.decode.base.AbstractImapCommandParser;
+import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest;
+
+public abstract class AbstractSelectionCommandParser extends
AbstractImapCommandParser{
+
+ public AbstractSelectionCommandParser(ImapCommand command) {
+ super(command);
+ }
+
+
+
+ private final static byte[] UNCHANGEDSINCE = "(UNCHANGEDSINCE)".getBytes();
+
+ private int cap(char next) {
+ final int cap = next > 'Z' ? next ^ 32 : next;
+ return cap;
+ }
+
+ /*
+ * (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.james.imap.api.process.ImapSession)
+ */
+ protected ImapMessage decode(ImapCommand command, ImapRequestLineReader
request, String tag, ImapSession session) throws DecodingException {
+ final String mailboxName = request.mailbox();
+ boolean condstore = false;
+
+ char c = Character.UNASSIGNED;
+ try {
+ c = request.nextWordChar();
+ } catch (DecodingException e) {
+
+ }
+ if (c == '(') {
+ request.consumeWord(new CharacterValidator() {
+ int pos = 0;
+ @Override
+ public boolean isValid(char chr) {
+ return cap(chr) == UNCHANGEDSINCE[pos++];
+ }
+ });
+ condstore = true;
+
+ }
+
+ request.eol();
+ final ImapMessage result = createRequest(command, mailboxName,
condstore, tag);
+ return result;
+ }
+
+ protected abstract AbstractMailboxSelectionRequest
createRequest(ImapCommand command, String mailboxName, boolean condstore,
String tag);
+}
Modified:
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/ExamineCommandParser.java
Tue Jul 12 18:21:42 2011
@@ -20,36 +20,22 @@ package org.apache.james.imap.decode.par
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.api.process.ImapSession;
-import org.apache.james.imap.decode.ImapRequestLineReader;
-import org.apache.james.imap.decode.DecodingException;
-import org.apache.james.imap.decode.base.AbstractImapCommandParser;
+import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest;
import org.apache.james.imap.message.request.ExamineRequest;
/**
* Parse EXAMINE commands
*/
-public class ExamineCommandParser extends AbstractImapCommandParser {
+public class ExamineCommandParser extends AbstractSelectionCommandParser {
public ExamineCommandParser() {
super(ImapCommand.authenticatedStateCommand(ImapConstants.EXAMINE_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.james.imap.api.process.ImapSession)
- */
- protected ImapMessage decode(ImapCommand command, ImapRequestLineReader
request, String tag, ImapSession session) throws DecodingException {
- final String mailboxName = request.mailbox();
- request.eol();
- final ImapMessage result = new ExamineRequest(command, mailboxName,
tag);
- return result;
+ @Override
+ protected AbstractMailboxSelectionRequest createRequest(ImapCommand
command, String mailboxName, boolean condstore, String tag) {
+ return new ExamineRequest(command, mailboxName, condstore, tag);
}
+
}
Modified:
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/SelectCommandParser.java
Tue Jul 12 18:21:42 2011
@@ -20,36 +20,22 @@ package org.apache.james.imap.decode.par
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.api.process.ImapSession;
-import org.apache.james.imap.decode.ImapRequestLineReader;
-import org.apache.james.imap.decode.DecodingException;
-import org.apache.james.imap.decode.base.AbstractImapCommandParser;
+import org.apache.james.imap.message.request.AbstractMailboxSelectionRequest;
import org.apache.james.imap.message.request.SelectRequest;
/**
* Parse SELECT commands
*/
-public class SelectCommandParser extends AbstractImapCommandParser {
+public class SelectCommandParser extends AbstractSelectionCommandParser {
public SelectCommandParser() {
super(ImapCommand.authenticatedStateCommand(ImapConstants.SELECT_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.james.imap.api.process.ImapSession)
- */
- protected ImapMessage decode(ImapCommand command, ImapRequestLineReader
request, String tag, ImapSession session) throws DecodingException {
- final String mailboxName = request.mailbox();
- request.eol();
- final ImapMessage result = new SelectRequest(command, mailboxName,
tag);
- return result;
+ @Override
+ protected AbstractMailboxSelectionRequest createRequest(ImapCommand
command, String mailboxName, boolean condstore, String tag) {
+ return new SelectRequest(command, mailboxName, condstore, tag);
}
+
}
Modified:
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/decode/parser/StoreCommandParser.java
Tue Jul 12 18:21:42 2011
@@ -28,6 +28,7 @@ import org.apache.james.imap.api.message
import org.apache.james.imap.api.process.ImapSession;
import org.apache.james.imap.decode.ImapRequestLineReader;
import org.apache.james.imap.decode.DecodingException;
+import org.apache.james.imap.decode.ImapRequestLineReader.CharacterValidator;
import org.apache.james.imap.message.request.StoreRequest;
/**
@@ -35,10 +36,18 @@ import org.apache.james.imap.message.req
*/
public class StoreCommandParser extends AbstractUidCommandParser {
+ private final static byte[] UNCHANGEDSINCE = "UNCHANGEDSINCE".getBytes();
+
public StoreCommandParser() {
super(ImapCommand.selectedStateCommand(ImapConstants.STORE_COMMAND_NAME));
}
+ private int cap(char next) {
+ final int cap = next > 'Z' ? next ^ 32 : next;
+ return cap;
+ }
+
+
/*
* (non-Javadoc)
*
@@ -52,8 +61,24 @@ public class StoreCommandParser extends
final IdRange[] idSet = request.parseIdRange(session);
final Boolean sign;
boolean silent = false;
-
+ long unchangedSince = -1;
char next = request.nextWordChar();
+ if (next == '(') {
+ // Seems like we have a CONDSTORE parameter
+ request.consume();
+
+ request.consumeWord(new CharacterValidator() {
+ private int pos = 0;
+ public boolean isValid(char chr) {
+ return cap(chr) == UNCHANGEDSINCE[pos++];
+ }
+ });
+ request.consumeChar(' ');
+ unchangedSince = request.number();
+ request.consumeChar(')');
+ next = request.nextWordChar();
+ }
+
if (next == '+') {
sign = Boolean.TRUE;
request.consume();
@@ -92,7 +117,7 @@ public class StoreCommandParser extends
}
request.eol();
- final ImapMessage result = new StoreRequest(command, idSet, silent,
flags, useUids, tag, sign);
+ final ImapMessage result = new StoreRequest(command, idSet, silent,
flags, useUids, tag, sign, unchangedSince);
return result;
}
}
Modified:
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/AbstractMailboxSelectionRequest.java
Tue Jul 12 18:21:42 2011
@@ -27,10 +27,12 @@ import org.apache.james.imap.api.message
*/
public abstract class AbstractMailboxSelectionRequest extends
AbstractImapRequest {
private final String mailboxName;
+ private final boolean condstore;
- public AbstractMailboxSelectionRequest(final ImapCommand command, final
String mailboxName, final String tag) {
+ public AbstractMailboxSelectionRequest(final ImapCommand command, final
String mailboxName, boolean condstore, final String tag) {
super(tag, command);
this.mailboxName = mailboxName;
+ this.condstore = condstore;
}
/**
@@ -41,5 +43,9 @@ public abstract class AbstractMailboxSel
public final String getMailboxName() {
return mailboxName;
}
+
+ public final boolean getCondstore() {
+ return condstore;
+ }
}
Modified:
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/ExamineRequest.java
Tue Jul 12 18:21:42 2011
@@ -21,8 +21,8 @@ package org.apache.james.imap.message.re
import org.apache.james.imap.api.ImapCommand;
public class ExamineRequest extends AbstractMailboxSelectionRequest {
- public ExamineRequest(final ImapCommand command, final String mailboxName,
final String tag) {
- super(command, mailboxName, tag);
+ public ExamineRequest(final ImapCommand command, final String mailboxName,
final boolean condstore, final String tag) {
+ super(command, mailboxName, condstore, tag);
}
}
Modified:
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SelectRequest.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SelectRequest.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SelectRequest.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/SelectRequest.java
Tue Jul 12 18:21:42 2011
@@ -22,7 +22,7 @@ import org.apache.james.imap.api.ImapCom
public class SelectRequest extends AbstractMailboxSelectionRequest {
- public SelectRequest(final ImapCommand command, final String mailboxName,
final String tag) {
- super(command, mailboxName, tag);
+ public SelectRequest(final ImapCommand command, final String mailboxName,
boolean condstore, final String tag) {
+ super(command, mailboxName, condstore, tag);
}
}
Modified:
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/StoreRequest.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/StoreRequest.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/StoreRequest.java
(original)
+++
james/imap/trunk/message/src/main/java/org/apache/james/imap/message/request/StoreRequest.java
Tue Jul 12 18:21:42 2011
@@ -37,7 +37,9 @@ public class StoreRequest extends Abstra
private final boolean signedPlus;
- public StoreRequest(final ImapCommand command, final IdRange[] idSet,
final boolean silent, final Flags flags, final boolean useUids, final String
tag, final Boolean sign) {
+ private long unchangedSince;
+
+ public StoreRequest(final ImapCommand command, final IdRange[] idSet,
final boolean silent, final Flags flags, final boolean useUids, final String
tag, final Boolean sign, final long unchangedSince) {
super(tag, command);
this.idSet = idSet;
this.silent = silent;
@@ -53,6 +55,7 @@ public class StoreRequest extends Abstra
signedMinus = true;
signedPlus = false;
}
+ this.unchangedSince = unchangedSince;
}
/**
@@ -95,6 +98,10 @@ public class StoreRequest extends Abstra
public final boolean isUseUids() {
return useUids;
}
+
+ public final long getUnchangedSince() {
+ return unchangedSince;
+ }
public String toString() {
final StringBuffer buffer = new StringBuffer(100);
Modified:
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
(original)
+++
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
Tue Jul 12 18:21:42 2011
@@ -109,10 +109,22 @@ abstract class AbstractSelectionProcesso
uidValidity(responder, metaData);
unseen(responder, metaData, selected);
permanentFlags(responder, metaData, selected);
+ higestModSeq(responder, metaData, selected);
uidNext(responder, metaData);
taggedOk(responder, tag, command, metaData);
}
+ private void higestModSeq(Responder responder, MetaData metaData,
SelectedMailbox selected) {
+ final StatusResponse untaggedOk;
+ if (metaData.isModSeqPermanent()) {
+ final long highestModSeq = metaData.getHighestModSeq();
+ untaggedOk =
statusResponseFactory.untaggedOk(HumanReadableText.HIGHEST_MOD_SEQ,
ResponseCode.highestModSeq(highestModSeq));
+ } else {
+ untaggedOk =
statusResponseFactory.untaggedOk(HumanReadableText.NO_MOD_SEQ,
ResponseCode.noModSeq());
+ }
+ responder.respond(untaggedOk);
+ }
+
private void uidNext(final Responder responder, final
MessageManager.MetaData metaData) throws MailboxException {
final long uid = metaData.getUidNext();
final StatusResponse untaggedOk =
statusResponseFactory.untaggedOk(HumanReadableText.UIDNEXT,
ResponseCode.uidNext(uid));
Modified:
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StoreProcessor.java
URL:
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StoreProcessor.java?rev=1145703&r1=1145702&r2=1145703&view=diff
==============================================================================
---
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StoreProcessor.java
(original)
+++
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StoreProcessor.java
Tue Jul 12 18:21:42 2011
@@ -19,6 +19,9 @@
package org.apache.james.imap.processor;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import javax.mail.Flags;
@@ -27,12 +30,14 @@ import org.apache.james.imap.api.ImapCom
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.process.ImapProcessor;
import org.apache.james.imap.api.process.ImapSession;
import org.apache.james.imap.api.process.SelectedMailbox;
import org.apache.james.imap.message.request.StoreRequest;
import org.apache.james.imap.message.response.FetchResponse;
+import org.apache.james.imap.processor.base.FetchGroupImpl;
import org.apache.james.mailbox.MailboxException;
import org.apache.james.mailbox.MailboxManager;
import org.apache.james.mailbox.MailboxSession;
@@ -40,6 +45,7 @@ import org.apache.james.mailbox.MessageM
import org.apache.james.mailbox.MessageManager.MetaData.FetchGroup;
import org.apache.james.mailbox.MessageRange;
import org.apache.james.mailbox.MessageRangeException;
+import org.apache.james.mailbox.MessageResult;
public class StoreProcessor extends AbstractMailboxProcessor<StoreRequest> {
@@ -49,74 +55,60 @@ public class StoreProcessor extends Abst
protected void doProcess(StoreRequest request, ImapSession session, String
tag, ImapCommand command, Responder responder) {
final IdRange[] idSet = request.getIdSet();
- final Flags flags = request.getFlags();
final boolean useUids = request.isUseUids();
- final boolean silent = request.isSilent();
- final boolean isSignedPlus = request.isSignedPlus();
- final boolean isSignedMinus = request.isSignedMinus();
+ final long unchangedSince = request.getUnchangedSince();
- final boolean replace;
- final boolean value;
- if (isSignedMinus) {
- value = false;
- replace = false;
- } else if (isSignedPlus) {
- value = true;
- replace = false;
- } else {
- replace = true;
- value = true;
- }
try {
final MessageManager mailbox = getSelectedMailbox(session);
+ final MailboxSession mailboxSession =
ImapSessionUtils.getMailboxSession(session);
+
+ if (unchangedSince != -1 &&
mailbox.isModSeqPermanent(mailboxSession) == false ) {
+ // Check if the mailbox did not support modsequences. If so
return a tagged bad response.
+ // See RFC4551 3.1.2. NOMODSEQ Response Code
+ taggedBad(command, tag, responder,
HumanReadableText.NO_MOD_SEQ);
+ return;
+ }
+ List<Long> failedUids = new ArrayList<Long>();
+
for (int i = 0; i < idSet.length; i++) {
final SelectedMailbox selected = session.getSelected();
MessageRange messageSet = messageRange(selected, idSet[i],
useUids);
if (messageSet != null) {
- final MailboxSession mailboxSession =
ImapSessionUtils.getMailboxSession(session);
- final Map<Long, Flags> flagsByUid =
mailbox.setFlags(flags, value, replace, messageSet, mailboxSession);
- // As the STORE command is allowed to create a new
"flag/keyword", we need to send a FLAGS and PERMANENTFLAGS response before the
FETCH response
- // if some new flag/keyword was used
- // See IMAP-303
- if (selected.hasNewApplicableFlags()) {
- flags(responder, selected);
- permanentFlags(responder, mailbox.getMetaData(false,
mailboxSession, FetchGroup.NO_COUNT), selected);
- selected.resetNewApplicableFlags();
- }
- if (!silent) {
-
- for (Map.Entry<Long, Flags> entry :
flagsByUid.entrySet()) {
- final long uid = entry.getKey();
- final int msn = selected.msn(uid);
-
- if (msn == SelectedMailbox.NO_SUCH_MESSAGE)
- throw new MailboxException("No message found
with uid " + uid);
-
- final Flags resultFlags = entry.getValue();
- final Long resultUid;
- if (useUids) {
- resultUid = uid;
+ if (unchangedSince != -1) {
+ List<Long> uids = new ArrayList<Long>();
+
+ Iterator<MessageResult> results =
mailbox.getMessages(messageSet, FetchGroupImpl.MINIMAL, mailboxSession);
+ while(results.hasNext()) {
+ MessageResult r = results.next();
+ long uid = r.getUid();
+ if (r.getModSeq() <= unchangedSince) {
+ uids.add(uid);
} else {
- resultUid = null;
- }
-
-
- if (selected.isRecent(uid)) {
- resultFlags.add(Flags.Flag.RECENT);
+ failedUids.add(uid);
}
-
- final FetchResponse response = new
FetchResponse(msn, resultFlags, resultUid, null, null, null, null, null, null);
- responder.respond(response);
}
+ List<MessageRange> mRanges =
MessageRange.toRanges(uids);
+ for (int a = 0 ; a < mRanges.size(); a++) {
+ setFlags(request, mailboxSession, mailbox,
mRanges.get(a), selected, tag, command, responder);
+ }
+ } else {
+ setFlags(request, mailboxSession, mailbox, messageSet,
selected, tag, command, responder);
}
+
}
}
final boolean omitExpunged = (!useUids);
unsolicitedResponses(session, responder, omitExpunged, useUids);
- okComplete(command, tag, responder);
+ if (failedUids.isEmpty()) {
+ okComplete(command, tag, responder);
+ } else {
+ // TODO: Fix me!
+ final StatusResponse response =
getStatusResponseFactory().taggedOk(tag, command, HumanReadableText.COMPLETED);
+ responder.respond(response);
+ }
} catch (MessageRangeException e) {
session.getLog().debug("Store failed", e);
taggedBad(command, tag, responder,
HumanReadableText.INVALID_MESSAGESET);
@@ -125,4 +117,63 @@ public class StoreProcessor extends Abst
no(command, tag, responder, HumanReadableText.SAVE_FAILED);
}
}
+
+ private void setFlags(StoreRequest request, MailboxSession mailboxSession,
MessageManager mailbox, MessageRange messageSet, SelectedMailbox selected,
String tag, ImapCommand command, Responder responder) throws MailboxException {
+
+ final Flags flags = request.getFlags();
+ final boolean useUids = request.isUseUids();
+ final boolean silent = request.isSilent();
+ final boolean isSignedPlus = request.isSignedPlus();
+ final boolean isSignedMinus = request.isSignedMinus();
+
+ final boolean replace;
+ final boolean value;
+ if (isSignedMinus) {
+ value = false;
+ replace = false;
+ } else if (isSignedPlus) {
+ value = true;
+ replace = false;
+ } else {
+ replace = true;
+ value = true;
+ }
+
+ final Map<Long, Flags> flagsByUid = mailbox.setFlags(flags, value,
replace, messageSet, mailboxSession);
+ // As the STORE command is allowed to create a new "flag/keyword", we
need to send a FLAGS and PERMANENTFLAGS response before the FETCH response
+ // if some new flag/keyword was used
+ // See IMAP-303
+ if (selected.hasNewApplicableFlags()) {
+ flags(responder, selected);
+ permanentFlags(responder, mailbox.getMetaData(false,
mailboxSession, FetchGroup.NO_COUNT), selected);
+ selected.resetNewApplicableFlags();
+ }
+
+ if (!silent) {
+
+ for (Map.Entry<Long, Flags> entry : flagsByUid.entrySet()) {
+ final long uid = entry.getKey();
+ final int msn = selected.msn(uid);
+
+ if (msn == SelectedMailbox.NO_SUCH_MESSAGE)
+ throw new MailboxException("No message found with uid " +
uid);
+
+ final Flags resultFlags = entry.getValue();
+ final Long resultUid;
+ if (useUids) {
+ resultUid = uid;
+ } else {
+ resultUid = null;
+ }
+
+
+ if (selected.isRecent(uid)) {
+ resultFlags.add(Flags.Flag.RECENT);
+ }
+
+ final FetchResponse response = new FetchResponse(msn,
resultFlags, resultUid, null, null, null, null, null, null);
+ responder.respond(response);
+ }
+ }
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]