Author: norman Date: Sat Jul 16 19:28:53 2011 New Revision: 1147479 URL: http://svn.apache.org/viewvc?rev=1147479&view=rev Log: Handle the "CONDSTORE enabling commands" as stated in CONDSTORE RFC. This say we MUST include MODSEQ infos in any untagges FETCH Responses after a "CONDSTORE enabling command" was issued and the selected mailbox does store the mod sequences in a permanent way. See IMAP-305
Modified: james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.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/AbstractSelectionProcessor.java james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/EnableProcessor.java james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StatusProcessor.java james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StoreProcessor.java james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java Modified: james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java URL: http://svn.apache.org/viewvc/james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java?rev=1147479&r1=1147478&r2=1147479&view=diff ============================================================================== --- james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java (original) +++ james/imap/trunk/api/src/main/java/org/apache/james/imap/api/process/SelectedMailbox.java Sat Jul 16 19:28:53 2011 @@ -197,11 +197,4 @@ public interface SelectedMailbox { public void resetNewApplicableFlags(); - /** - * Return true if the selected mailbox was selected with the condstore option - * - * @return condstore - */ - public boolean getCondstore(); - } \ No newline at end of file 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=1147479&r1=1147478&r2=1147479&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 Sat Jul 16 19:28:53 2011 @@ -58,6 +58,7 @@ import org.apache.james.mailbox.MessageR import org.apache.james.mailbox.MessageResult; import org.apache.james.mailbox.SearchQuery; import org.apache.james.mailbox.MessageManager.MetaData; +import org.apache.james.mailbox.MessageManager.MetaData.FetchGroup; import org.apache.james.mailbox.MessageRange.Type; import org.apache.james.mailbox.SearchQuery.NumericRange; @@ -231,6 +232,8 @@ abstract public class AbstractMailboxPro throw new MailboxException("No message found with uid " + uid); boolean qresyncEnabled = EnableProcessor.getEnabledCapabilities(session).contains(ImapConstants.SUPPORTS_QRESYNC); + boolean condstoreEnabled = EnableProcessor.getEnabledCapabilities(session).contains(ImapConstants.SUPPORTS_CONDSTORE); + final Flags flags = mr.getFlags(); final Long uidOut; if (useUid || qresyncEnabled) { @@ -245,9 +248,9 @@ abstract public class AbstractMailboxPro } final FetchResponse response; - // Check if we also need to return the MODSEQ in the response. This is true if the mailbox was selected with the CONSTORE option or - // if QRESYNC was enabled - if (selected.getCondstore() || qresyncEnabled) { + // Check if we also need to return the MODSEQ in the response. This is true if CONDSTORE or + // if QRESYNC was enabled, and the mailbox supports the permant storage of mod-sequences + if ((condstoreEnabled || qresyncEnabled) && mailbox.getMetaData(false, mailboxSession, FetchGroup.NO_COUNT).isModSeqPermanent()) { response = new FetchResponse(msn, flags, uidOut, mr.getModSeq(), null, null, null, null, null, null); } else { response = new FetchResponse(msn, flags, uidOut, null, null, null, null, null, null, null); @@ -256,6 +259,24 @@ abstract public class AbstractMailboxPro } } + protected void condstoreEnablingCommand(ImapSession session, Responder responder, MetaData metaData, boolean sendHighestModSeq) { + Set<String> enabled = EnableProcessor.getEnabledCapabilities(session); + if (!enabled.contains(ImapConstants.SUPPORTS_CONDSTORE)) { + if (sendHighestModSeq) { + if (metaData.isModSeqPermanent()) { + + final long highestModSeq = metaData.getHighestModSeq(); + + StatusResponse untaggedOk = getStatusResponseFactory().untaggedOk(HumanReadableText.HIGHEST_MOD_SEQ, ResponseCode.highestModSeq(highestModSeq)); + responder.respond(untaggedOk); + } + } + enabled.add(ImapConstants.SUPPORTS_CONDSTORE); + + + } + } + private MessageManager getMailbox(final ImapSession session, final SelectedMailbox selected) throws MailboxException { final MailboxManager mailboxManager = getMailboxManager(); final MessageManager mailbox = mailboxManager.getMailbox(selected.getPath(), ImapSessionUtils.getMailboxSession(session)); 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=1147479&r1=1147478&r2=1147479&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 Sat Jul 16 19:28:53 2011 @@ -131,7 +131,9 @@ abstract class AbstractSelectionProcesso return; } - final MessageManager.MetaData metaData = selectMailbox(fullMailboxPath, session, request.getCondstore()); + + + final MessageManager.MetaData metaData = selectMailbox(fullMailboxPath, session); final SelectedMailbox selected = session.getSelected(); flags(responder, selected); @@ -143,9 +145,13 @@ abstract class AbstractSelectionProcesso highestModSeq(responder, metaData, selected); uidNext(responder, metaData); + if (request.getCondstore()) { + condstoreEnablingCommand(session, responder, metaData, false); + } + // Now do the QRESYNC processing if necessary // - // If the mailbox does nto store the mod-sequence in a permanent way its needed to not process the QRESYNC paramters + // If the mailbox does not store the mod-sequence in a permanent way its needed to not process the QRESYNC paramters // The same is true if none are given ;) if (metaData.isModSeqPermanent() && lastKnownUidValidity != null) { if (lastKnownUidValidity == metaData.getUidValidity()) { @@ -320,6 +326,7 @@ abstract class AbstractSelectionProcesso } + private void highestModSeq(Responder responder, MetaData metaData, SelectedMailbox selected) { final StatusResponse untaggedOk; if (metaData.isModSeqPermanent()) { @@ -382,7 +389,7 @@ abstract class AbstractSelectionProcesso responder.respond(existsResponse); } - private MessageManager.MetaData selectMailbox(MailboxPath mailboxPath, ImapSession session, boolean condstore) throws MailboxException { + private MessageManager.MetaData selectMailbox(MailboxPath mailboxPath, ImapSession session) throws MailboxException { final MailboxManager mailboxManager = getMailboxManager(); final MailboxSession mailboxSession = ImapSessionUtils.getMailboxSession(session); final MessageManager mailbox = mailboxManager.getMailbox(mailboxPath, mailboxSession); @@ -399,10 +406,7 @@ abstract class AbstractSelectionProcesso if (currentMailbox != null) { getStatusResponseFactory().untaggedOk(HumanReadableText.QRESYNC_CLOSED, ResponseCode.closed()); } - if (condstore == false) { - condstore = EnableProcessor.getEnabledCapabilities(session).contains(ImapConstants.SUPPORTS_CONDSTORE); - } - sessionMailbox = createNewSelectedMailbox(mailbox, mailboxSession, session, mailboxPath, condstore); + sessionMailbox = createNewSelectedMailbox(mailbox, mailboxSession, session, mailboxPath); } else { // TODO: Check if we need to handle CONDSTORE there too @@ -413,7 +417,7 @@ abstract class AbstractSelectionProcesso return metaData; } - private SelectedMailbox createNewSelectedMailbox(final MessageManager mailbox, final MailboxSession mailboxSession, ImapSession session, MailboxPath path, boolean condstore) throws MailboxException { + private SelectedMailbox createNewSelectedMailbox(final MessageManager mailbox, final MailboxSession mailboxSession, ImapSession session, MailboxPath path) throws MailboxException { Iterator<MessageResult> messages = mailbox.getMessages(MessageRange.all(), FetchGroupImpl.MINIMAL, mailboxSession); Flags applicableFlags = new Flags(flags); @@ -428,7 +432,7 @@ abstract class AbstractSelectionProcesso // \RECENT is not a applicable flag in imap so remove it from the list applicableFlags.remove(Flags.Flag.RECENT); - final SelectedMailbox sessionMailbox = new SelectedMailboxImpl(getMailboxManager(), uids.iterator(),applicableFlags, session, path, condstore); + final SelectedMailbox sessionMailbox = new SelectedMailboxImpl(getMailboxManager(), uids.iterator(),applicableFlags, session, path); session.selected(sessionMailbox); return sessionMailbox; } Modified: james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/EnableProcessor.java URL: http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/EnableProcessor.java?rev=1147479&r1=1147478&r2=1147479&view=diff ============================================================================== --- james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/EnableProcessor.java (original) +++ james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/EnableProcessor.java Sat Jul 16 19:28:53 2011 @@ -23,11 +23,13 @@ import static org.apache.james.imap.api. import java.util.ArrayList; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.james.imap.api.ImapCommand; 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.StatusResponseFactory; import org.apache.james.imap.api.process.ImapProcessor; import org.apache.james.imap.api.process.ImapSession; @@ -38,12 +40,12 @@ import org.apache.james.mailbox.MailboxM public class EnableProcessor extends AbstractMailboxProcessor<EnableRequest> implements CapabilityImplementingProcessor { - private final List<PermitEnableCapabilityProcessor> capabilities = new ArrayList<PermitEnableCapabilityProcessor>(); + private final static List<PermitEnableCapabilityProcessor> capabilities = new ArrayList<PermitEnableCapabilityProcessor>(); public final static String ENABLED_CAPABILITIES = "ENABLED_CAPABILITIES"; public EnableProcessor(final ImapProcessor next, final MailboxManager mailboxManager, final StatusResponseFactory factory, final List<PermitEnableCapabilityProcessor> capabilities) { this(next, mailboxManager, factory); - this.capabilities.addAll(capabilities); + EnableProcessor.capabilities.addAll(capabilities); } @@ -60,22 +62,7 @@ public class EnableProcessor extends Abs try { List<String> caps = request.getCapabilities(); - Set<String> enabledCaps = new HashSet<String>(); - for (int i = 0; i < caps.size(); i++) { - String cap = caps.get(i); - // Check if the CAPABILITY is supported at all - if (CapabilityProcessor.getSupportedCapabilities(session).contains(cap)) { - for (int a = 0; a < capabilities.size(); a++) { - PermitEnableCapabilityProcessor enableProcessor = capabilities.get(a); - if (enableProcessor.getPermitEnableCapabilities(session).contains(cap)) { - enableProcessor.enable(request, responder, session, cap); - enabledCaps.add(cap); - } - } - } - } - getEnabledCapabilities(session).addAll(enabledCaps); - + Set<String> enabledCaps = enable(request, responder, session, caps.iterator()); responder.respond(new EnableResponse(enabledCaps)); unsolicitedResponses(session, responder, false); @@ -85,6 +72,25 @@ public class EnableProcessor extends Abs } } + public static Set<String> enable(ImapRequest request, Responder responder, ImapSession session, Iterator<String> caps) throws EnableException { + Set<String> enabledCaps = new HashSet<String>(); + while(caps.hasNext()) { + String cap = caps.next(); + // Check if the CAPABILITY is supported at all + if (CapabilityProcessor.getSupportedCapabilities(session).contains(cap)) { + for (int a = 0; a < capabilities.size(); a++) { + PermitEnableCapabilityProcessor enableProcessor = capabilities.get(a); + if (enableProcessor.getPermitEnableCapabilities(session).contains(cap)) { + enableProcessor.enable(request, responder, session, cap); + enabledCaps.add(cap); + } + } + } + } + getEnabledCapabilities(session).addAll(enabledCaps); + return enabledCaps; + } + /** * Add a {@link PermitEnableCapabilityProcessor} which can be enabled * Modified: james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java URL: http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java?rev=1147479&r1=1147478&r2=1147479&view=diff ============================================================================== --- james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java (original) +++ james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/SearchProcessor.java Sat Jul 16 19:28:53 2011 @@ -53,6 +53,7 @@ import org.apache.james.mailbox.MailboxM import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MessageManager; import org.apache.james.mailbox.MessageManager.MetaData; +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; @@ -118,6 +119,10 @@ public class SearchProcessor extends Abs if (session.getAttribute(SEARCH_MODSEQ) != null) { MetaData metaData = mailbox.getMetaData(false, msession , MessageManager.MetaData.FetchGroup.NO_COUNT); highestModSeq = findHighestModSeq(msession, mailbox, MessageRange.toRanges(uids), metaData.getHighestModSeq()); + + // Enable CONDSTORE as this is a CONDSTORE enabling command + condstoreEnablingCommand(session, responder, metaData, true); + } else { highestModSeq = null; } Modified: james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StatusProcessor.java URL: http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StatusProcessor.java?rev=1147479&r1=1147478&r2=1147479&view=diff ============================================================================== --- james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StatusProcessor.java (original) +++ james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/StatusProcessor.java Sat Jul 16 19:28:53 2011 @@ -20,6 +20,7 @@ package org.apache.james.imap.processor; import org.apache.james.imap.api.ImapCommand; +import org.apache.james.imap.api.ImapConstants; import org.apache.james.imap.api.ImapSessionUtils; import org.apache.james.imap.api.display.HumanReadableText; import org.apache.james.imap.api.message.StatusDataItems; @@ -78,6 +79,11 @@ public class StatusProcessor extends Abs final Long uidValidity = uidValidity(statusDataItems, metaData); final Long unseen = unseen(statusDataItems, metaData); final Long highestModSeq = highestModSeq(statusDataItems, metaData); + + // Enable CONDSTORE as this is a CONDSTORE enabling command + if (highestModSeq != null) { + EnableProcessor.getEnabledCapabilities(session).add(ImapConstants.SUPPORTS_CONDSTORE); + } final MailboxStatusResponse response = new MailboxStatusResponse(messages, recent, uidNext, highestModSeq, uidValidity, unseen, request.getMailboxName()); responder.respond(response); unsolicitedResponses(session, responder, false); 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=1147479&r1=1147478&r2=1147479&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 Sat Jul 16 19:28:53 2011 @@ -292,25 +292,32 @@ public class StoreProcessor extends Abst resultFlags.add(Flags.Flag.RECENT); } - + session.getLog().debug("CONDSTORE=" +enabled.contains(ImapConstants.SUPPORTS_CONDSTORE)); + final FetchResponse response; // For more informations related to the FETCH response see // // RFC4551 3.2. STORE and UID STORE Commands if (silent && (unchangedSince != -1 || qresyncEnabled || condstoreEnabled)) { // We need to return an FETCH response which contains the mod-sequence of the message even if FLAGS.SILENT was used - response = new FetchResponse(msn, null, resultUid, modSeqs.get(resultUid), null, null, null, null, null, null); + response = new FetchResponse(msn, null, resultUid, modSeqs.get(uid), null, null, null, null, null, null); } else if (!silent && (unchangedSince != -1 || qresyncEnabled || condstoreEnabled)){ // // Use a FETCH response which contains the mod-sequence and the flags - response = new FetchResponse(msn, resultFlags, resultUid, modSeqs.get(resultUid), null, null, null, null, null, null); + response = new FetchResponse(msn, resultFlags, resultUid, modSeqs.get(uid), null, null, null, null, null, null); } else { // Use a FETCH response which only contains the flags as no CONDSTORE was used response = new FetchResponse(msn, resultFlags, resultUid, null, null, null, null, null, null, null); } responder.respond(response); + } + if (unchangedSince != -1) { + // Enable CONDSTORE as this is a CONDSTORE enabling command + condstoreEnablingCommand(session, responder, mailbox.getMetaData(false, mailboxSession, FetchGroup.NO_COUNT), true); + } } + } } Modified: james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java URL: http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java?rev=1147479&r1=1147478&r2=1147479&view=diff ============================================================================== --- james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java (original) +++ james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java Sat Jul 16 19:28:53 2011 @@ -47,10 +47,8 @@ public class SelectedMailboxImpl impleme private final Set<Long> recentUids; private boolean recentUidRemoved; - - private final boolean condstore; - - public SelectedMailboxImpl(final MailboxManager mailboxManager, final Iterator<Long> uids, final Flags applicableFlags, final ImapSession session, final MailboxPath path, final boolean condstore) throws MailboxException { + + public SelectedMailboxImpl(final MailboxManager mailboxManager, final Iterator<Long> uids, final Flags applicableFlags, final ImapSession session, final MailboxPath path) throws MailboxException { recentUids = new TreeSet<Long>(); recentUidRemoved = false; MailboxSession mailboxSession = ImapSessionUtils.getMailboxSession(session); @@ -60,7 +58,6 @@ public class SelectedMailboxImpl impleme mailboxManager.addListener(path, events, mailboxSession); converter = new UidToMsnConverter(session, uids); mailboxManager.addListener(path, converter, mailboxSession); - this.condstore = condstore; } /** @@ -287,9 +284,4 @@ public class SelectedMailboxImpl impleme public void resetNewApplicableFlags() { events.resetNewApplicableFlags(); } - - @Override - public boolean getCondstore() { - return condstore; - } } Modified: james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java URL: http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java?rev=1147479&r1=1147478&r2=1147479&view=diff ============================================================================== --- james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java (original) +++ james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/fetch/FetchProcessor.java Sat Jul 16 19:28:53 2011 @@ -44,6 +44,7 @@ import org.apache.james.mailbox.MailboxM import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MessageManager; import org.apache.james.mailbox.MessageManager.MessageCallback; +import org.apache.james.mailbox.MessageManager.MetaData; import org.apache.james.mailbox.MessageRange; import org.apache.james.mailbox.MessageRangeException; import org.apache.james.mailbox.MessageResult; @@ -95,6 +96,13 @@ public class FetchProcessor extends Abst return; } final MailboxSession mailboxSession = ImapSessionUtils.getMailboxSession(session); + + MetaData metaData = mailbox.getMetaData(false, mailboxSession, org.apache.james.mailbox.MessageManager.MetaData.FetchGroup.NO_COUNT); + if (fetch.getChangedSince() != -1 || fetch.isModSeq()) { + // Enable CONDSTORE as this is a CONDSTORE enabling command + condstoreEnablingCommand(session, responder, metaData, true); + } + List<MessageRange> ranges = new ArrayList<MessageRange>(); for (int i = 0; i < idSet.length; i++) { @@ -109,7 +117,7 @@ public class FetchProcessor extends Abst if (vanished ) { // TODO: From the QRESYNC RFC it seems ok to send the VANISHED responses after the FETCH Responses. // If we do so we could prolly save one mailbox access which should give use some more speed up - respondVanished(mailboxSession, mailbox, ranges, changedSince, mailbox.getMetaData(false, mailboxSession, org.apache.james.mailbox.MessageManager.MetaData.FetchGroup.NO_COUNT), responder); + respondVanished(mailboxSession, mailbox, ranges, changedSince, metaData, responder); } // if QRESYNC is enable its necessary to also return the UID in all cases if (EnableProcessor.getEnabledCapabilities(session).contains(ImapConstants.SUPPORTS_QRESYNC)) { --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org