Here's a rather nasty little bug in 2.3.15:

  . FETCH 1:2 fast
  * 1 FETCH (FLAGS (\Recent \Deleted \Seen) ...
  * 2 FETCH (FLAGS (\Recent \Seen) ...
  . OK Completed (0.000 sec)

  . SCAN "" a "hello world"
  . OK Completed (0.000 secs 1 calls)

  . EXPUNGE
  * 2 EXPUNGE      <--- Whoops, didn't mean that one.
  * 1 EXISTS
  * 1 RECENT
  . OK Completed

The correct message is expunged, imapd just reports the wrong message back to the client. Probably PINE or ALPINE given that this is an undocumented extension invented by the UW people.

The root cause appears to be index_operatemailbox().

This restores static state in index.c and the global imapd_exists in imapd.c based on its mailbox argument, including:

    index_base = mailbox->index_base;
    index_len = mailbox->index_len;

Unfortunately index.c works on the assumption that index_base is a private mmaped array (index_dirty = 1, set immediately by index_check()),
so that it can compare the current cyrus.index with the previous version
each time that index_check() is called.

If index_base is just a copy of mailbox->index_base, then index_check() remaps both arrays (at least on Linux). You end up comparing two identical arrays, but with (mailbox->exists < imapd_exists), which means that index_check() is going to generate some untagged EXPUNGE responses.

I attach a nasty patch to fix the SCAN extension by simply saving and then restoring all of the globals involved. index_operatemailbox() is called from two other functions in imapd.c: catenate_url() and cmd_urlfetch().

--
David Carter                             Email: david.car...@ucs.cam.ac.uk
University Computing Service,            Phone: (01223) 334502
New Museums Site, Pembroke Street,       Fax:   (01223) 334679
Cambridge UK. CB2 3QH.
diff -udNr cyrus-imapd-2.3.15/imap/imapd.c cyrus-imapd/imap/imapd.c
--- cyrus-imapd-2.3.15/imap/imapd.c	2009-07-29 16:51:21.000000000 +0100
+++ cyrus-imapd/imap/imapd.c	2009-10-05 17:27:47.000000000 +0100
@@ -5925,6 +5925,12 @@
 		   struct auth_state *auth_state, int (*proc)(),
 		   void *rock, int force);
 
+    if (listargs->scan && imapd_mailbox) {
+	/* SCAN will mess with the globals in index.c,
+	   so reset them for our currently mailbox */
+	index_save_globals();
+    }
+
     if (listargs->opts & LIST_REMOTE) {
 	if (!config_getswitch(IMAPOPT_PROXYD_DISABLE_MAILBOX_REFERRALS)) {
 	    supports_referrals = !disable_referrals;
@@ -6039,7 +6045,7 @@
     if (listargs->scan && imapd_mailbox) {
 	/* SCAN will mess with the globals in index.c,
 	   so reset them for our currently mailbox */
-	index_operatemailbox(imapd_mailbox);
+	index_restore_globals();
     }
 
     imapd_check(!(listargs->opts & (LIST_LSUB | LIST_SUBSCRIBED)) ?
diff -udNr cyrus-imapd-2.3.15/imap/index.c cyrus-imapd/imap/index.c
--- cyrus-imapd-2.3.15/imap/index.c	2009-09-09 02:22:38.000000000 +0100
+++ cyrus-imapd/imap/index.c	2009-10-05 17:27:47.000000000 +0100
@@ -99,6 +99,19 @@
 static unsigned long start_offset;
 static unsigned long record_size;
 
+/* Backup copy */
+static const char *index_base_saved;
+static unsigned long index_len_saved;
+static unsigned long index_dirty_saved;
+static const char *cache_base_saved;
+static unsigned long cache_len_saved;
+static unsigned long cache_end_saved;
+static unsigned long cache_dirty_saved;
+static ino_t index_ino_saved;
+static unsigned long start_offset_saved;
+static unsigned long record_size_saved;
+static int imapd_exists_saved;
+
 static unsigned lastnotrecent;	/* Msgno of last non-\Recent message */
 
 static time_t *flagreport;	/* Array for each msgno of last_updated when
@@ -242,10 +255,47 @@
 
     index_ino = mailbox->index_ino;
     start_offset = mailbox->start_offset;
-    record_size = mailbox->record_size;
+    record_size  = mailbox->record_size;
     imapd_exists = mailbox->exists;
 }
 
+void index_save_globals()
+{
+    index_dirty_saved = index_dirty;
+    cache_dirty_saved = cache_dirty;
+
+    index_base_saved = index_base;
+    index_len_saved  = index_len;
+
+    cache_base_saved = cache_base;
+    cache_len_saved  = cache_len;
+    cache_end_saved  = cache_end;
+
+    index_ino_saved    = index_ino;
+    start_offset_saved = start_offset;
+    record_size_saved  = record_size;
+    imapd_exists_saved = imapd_exists;
+}
+
+void index_restore_globals()
+{
+    index_dirty = index_dirty_saved;
+    cache_dirty = cache_dirty_saved;
+
+    index_base = index_base_saved;
+    index_len  = index_len_saved;
+
+    cache_base = cache_base_saved;
+    cache_len  = cache_len_saved;
+    cache_end  = cache_end_saved;
+
+    index_ino    = index_ino_saved;
+    start_offset = start_offset_saved;
+    record_size  = record_size_saved;
+    imapd_exists = imapd_exists_saved;
+}
+
+
 /*
  * Check for and report updates
  *

Reply via email to