Blob Blame History Raw
# Small patch to Cyrus IMAP 2.2.4 which modifies \Seen state handling to
# make it compatible with Outlook Express. OE makes two connections to a
# given mailfolder: one generates indexes while the other fetches messages.
# Unfortunately it gets confused if \Seen updates caused by the message
# stream aren't immediately flushed and picked up by the index stream.
#
# This patch is a 2.2.4 port from the patch found here:
# http://www-uxsup.csx.cam.ac.uk/~dpc22/cyrus/patches/2.1.16/OutLookExpress-seenstate.patch
#
diff -Naur cyrus-imapd-2.2.4.orig/imap/imapd.c cyrus-imapd-2.2.4/imap/imapd.c
--- cyrus-imapd-2.2.4.orig/imap/imapd.c	Thu May  6 20:46:21 2004
+++ cyrus-imapd-2.2.4/imap/imapd.c	Fri May 21 02:10:25 2004
@@ -3063,6 +3063,10 @@
     snprintf(mytime, sizeof(mytime), "%2.3f", 
 	     (clock() - start) / (double) CLOCKS_PER_SEC);
 
+    /* Checkpoint \Seen immediately after each FETCH completes. Checks for
+     * changes from other processes at the same time */
+    index_check_existing(imapd_mailbox, usinguid, 1);
+
     if (r) {
 	prot_printf(imapd_out, "%s NO %s (%s sec)\r\n", tag,
 		    error_message(r), mytime);
@@ -3184,7 +3188,7 @@
 
     index_fetch(imapd_mailbox, msgno, 0, &fetchargs, &fetchedsomething);
 
-    index_check(imapd_mailbox, 0, 0);
+    index_check_existing(imapd_mailbox, 0, 1);
 
     if (fetchedsomething) {
 	prot_printf(imapd_out, "%s OK %s\r\n", tag,
@@ -3321,7 +3325,9 @@
 		    flag, nflags);
 
     if (usinguid) {
-	index_check(imapd_mailbox, 1, 0);
+	index_check(imapd_mailbox, 1, 1);   /* Check \Seen too */
+    } else {
+        index_check_existing(imapd_mailbox, 0, 1);
     }
 
     if (r) {
diff -Naur cyrus-imapd-2.2.4.orig/imap/imapd.h cyrus-imapd-2.2.4/imap/imapd.h
--- cyrus-imapd-2.2.4.orig/imap/imapd.h	Wed Oct 22 20:50:07 2003
+++ cyrus-imapd-2.2.4/imap/imapd.h	Fri May 21 02:06:02 2004
@@ -233,6 +233,8 @@
 extern void index_operatemailbox(struct mailbox *mailbox);
 extern void index_check(struct mailbox *mailbox, int usinguid,
 			   int checkseen);
+extern void
+index_check_existing(struct mailbox *mailbox, int usinguid, int checkseen);
 extern void index_checkseen(struct mailbox *mailbox, int quiet,
 			       int usinguid, int oldexists);
 
diff -Naur cyrus-imapd-2.2.4.orig/imap/index.c cyrus-imapd-2.2.4/imap/index.c
--- cyrus-imapd-2.2.4.orig/imap/index.c	Wed Apr 21 19:40:48 2004
+++ cyrus-imapd-2.2.4/imap/index.c	Fri May 21 02:06:02 2004
@@ -425,6 +425,45 @@
     }
 }
 
+/* Nasty hack to report system + user flags updates without checking for
+ * new mail or expunge (relies on index atomic rewrite+rename for expunge).
+ *
+ * Needed to keep Outlook Express happy without breaking IMAP concurrent
+ * access regime which (quite correctly) prohibits unsolicited EXPUNGE and
+ * EXIST responses for non-UID versions of FETCH and STORE. Otherwise you
+ * can end up with hilarous situations such as:
+ *
+ *   . FETCH 2 fast
+ *   * EXPUNGE 1          <-- from concurrent session.
+ *   . FETCH (data relating to previous message _3_, if it exists)
+ *
+ */
+
+void
+index_check_existing(struct mailbox *mailbox, int usinguid, int checkseen)
+{
+    int msgno, i;
+    bit32 user_flags[MAX_USER_FLAGS/32];
+
+    if (imapd_exists == -1)
+        return;
+
+    if (checkseen)
+        index_checkseen(mailbox, 0, usinguid, imapd_exists);
+
+    for (msgno = 1; msgno <= imapd_exists; msgno++) {
+	if (flagreport[msgno] < LAST_UPDATED(msgno)) {
+	    for (i = 0; i < VECTOR_SIZE(user_flags); i++) {
+		user_flags[i] = USER_FLAGS(msgno, i);
+	    }
+	    index_fetchflags(mailbox, msgno, SYSTEM_FLAGS(msgno), user_flags,
+			     LAST_UPDATED(msgno));
+	    if (usinguid) prot_printf(imapd_out, " UID %u", UID(msgno));
+	    prot_printf(imapd_out, ")\r\n");
+	}
+    }
+}
+
 /*
  * Checkpoint the user's \Seen state
  *