# Small patch to Cyrus IMAP 2.1.16 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. # # Apparently Mozilla Thunderbird has the same problem. # diff -ur cyrus-imapd-2.1.16-DIST/imap/imapd.c cyrus-imapd-2.1.16/imap/imapd.c --- cyrus-imapd-2.1.16-DIST/imap/imapd.c 2003-09-24 15:16:02.000000000 +0100 +++ cyrus-imapd-2.1.16/imap/imapd.c 2005-04-04 10:26:46.399575348 +0100 @@ -2991,6 +2991,10 @@ index_fetch(imapd_mailbox, sequence, usinguid, &fetchargs, &fetchedsomething); + /* 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 (fetchedsomething || usinguid) { prot_printf(imapd_out, "%s OK %s\r\n", tag, error_message(IMAP_OK_COMPLETED)); @@ -3108,7 +3112,8 @@ index_fetch(imapd_mailbox, msgno, 0, &fetchargs, &fetchedsomething); - index_check(imapd_mailbox, 0, 0); + /* Vanilla index_check() can generate illegal EXPUNGE events */ + index_check_existing(imapd_mailbox, 0, 1); if (fetchedsomething) { prot_printf(imapd_out, "%s OK %s\r\n", tag, @@ -3245,7 +3250,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 -ur cyrus-imapd-2.1.16-DIST/imap/imapd.h cyrus-imapd-2.1.16/imap/imapd.h --- cyrus-imapd-2.1.16-DIST/imap/imapd.h 2003-02-13 20:15:25.000000000 +0000 +++ cyrus-imapd-2.1.16/imap/imapd.h 2005-04-04 11:10:13.482298858 +0100 @@ -240,6 +240,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 -ur cyrus-imapd-2.1.16-DIST/imap/index.c cyrus-imapd-2.1.16/imap/index.c --- cyrus-imapd-2.1.16-DIST/imap/index.c 2003-08-14 17:20:32.000000000 +0100 +++ cyrus-imapd-2.1.16/imap/index.c 2005-04-04 10:28:20.764246213 +0100 @@ -422,6 +422,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; + + /* Bail out if the mailbox was rotated under our feet */ + if ((index_len > 0) && + ((stat(FNAME_INDEX+1, &sbuf) != 0) || + (sbuf.st_ino != mailbox->index_ino) || + (index_ino != mailbox->index_ino))) + 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 * @@ -455,6 +494,7 @@ char *saveseenuids, *save; int savealloced; unsigned start, newallseen, inrange, usecomma; + mailbox_notifyproc_t *updatenotifier; if (!keepingseen || !seendb) return; if (imapd_exists == 0) { @@ -728,6 +768,9 @@ free(newseenuids); seenuids = saveseenuids; + + updatenotifier = mailbox_get_updatenotifier(); + if (updatenotifier) updatenotifier(mailbox); } diff -ur cyrus-imapd-2.1.16-DIST/imap/mailbox.c cyrus-imapd-2.1.16/imap/mailbox.c --- cyrus-imapd-2.1.16-DIST/imap/mailbox.c 2003-11-04 21:43:00.000000000 +0000 +++ cyrus-imapd-2.1.16/imap/mailbox.c 2005-04-04 10:28:46.831392889 +0100 @@ -143,6 +143,14 @@ } /* + * Get the updatenotifier function + */ +mailbox_notifyproc_t *mailbox_get_updatenotifier(void) +{ + return updatenotifier; +} + +/* * Create connection to acappush */ int mailbox_initialize(void) diff -ur cyrus-imapd-2.1.16-DIST/imap/mailbox.h cyrus-imapd-2.1.16/imap/mailbox.h --- cyrus-imapd-2.1.16-DIST/imap/mailbox.h 2003-03-31 21:15:05.000000000 +0100 +++ cyrus-imapd-2.1.16/imap/mailbox.h 2005-04-04 10:24:00.889693737 +0100 @@ -218,6 +218,8 @@ extern void mailbox_set_updatenotifier(mailbox_notifyproc_t *notifyproc); +extern mailbox_notifyproc_t *mailbox_get_updatenotifier(void); + extern int mailbox_initialize(void); extern char *mailbox_message_fname(struct mailbox *mailbox,