changeset 2322:aae574ed7f4c HEAD

Broke mailbox_sync() into iterator.
author Timo Sirainen <tss@iki.fi>
date Mon, 12 Jul 2004 14:35:50 +0300
parents d803ba0206f0
children ec1dac19cb06
files src/imap/Makefile.am src/imap/client.h src/imap/cmd-idle.c src/imap/cmd-select.c src/imap/cmd-status.c src/imap/cmd-store.c src/imap/commands-util.c src/imap/imap-fetch.c src/imap/imap-sync.c src/imap/imap-sync.h src/imap/mail-storage-callbacks.c src/lib-imap/imap-util.c src/lib-imap/imap-util.h src/lib-storage/index/index-mailbox-check.c src/lib-storage/index/index-status.c src/lib-storage/index/index-storage.h src/lib-storage/index/index-sync.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/maildir/maildir-storage.h src/lib-storage/index/maildir/maildir-sync.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/index/mbox/mbox-storage.h src/lib-storage/index/mbox/mbox-sync.c src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/lib-storage/proxy-mailbox.c src/pop3/client.c src/pop3/mail-storage-callbacks.c
diffstat 29 files changed, 510 insertions(+), 457 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/Makefile.am	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/Makefile.am	Mon Jul 12 14:35:50 2004 +0300
@@ -68,6 +68,7 @@
 	imap-messageset.c \
 	imap-search.c \
 	imap-sort.c \
+	imap-sync.c \
 	imap-thread.c \
 	mail-storage-callbacks.c \
 	main.c \
@@ -84,5 +85,6 @@
 	imap-messageset.h \
 	imap-search.h \
 	imap-sort.h \
+	imap-sync.h \
 	imap-thread.h \
 	namespace.h
--- a/src/imap/client.h	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/client.h	Mon Jul 12 14:35:50 2004 +0300
@@ -25,6 +25,7 @@
 	struct mailbox *mailbox;
         struct mailbox_keywords keywords;
 	unsigned int select_counter; /* increased when mailbox is changed */
+	uint32_t messages_count, recent_count;
 
 	time_t last_input;
 	unsigned int bad_counter;
--- a/src/imap/cmd-idle.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/cmd-idle.c	Mon Jul 12 14:35:50 2004 +0300
@@ -5,6 +5,7 @@
 #include "istream.h"
 #include "ostream.h"
 #include "commands.h"
+#include "imap-sync.h"
 
 #include <stdlib.h>
 
@@ -19,7 +20,7 @@
 
 	o_stream_cork(client->output);
 
-	if (client->idle_expunge) {
+	if (client->idle_expunge != 0) {
 		client_send_line(client,
 			t_strdup_printf("* %u EXPUNGE", client->idle_expunge));
 	}
@@ -28,12 +29,8 @@
 	client->io = io_add(i_stream_get_fd(client->input),
 			    IO_READ, _client_input, client);
 
-	if (client->mailbox != NULL) {
-		mailbox_auto_sync(client->mailbox, mailbox_check_interval != 0 ?
-				  MAILBOX_SYNC_FLAG_NO_EXPUNGES :
-				  MAILBOX_SYNC_AUTO_STOP,
-				  mailbox_check_interval);
-	}
+	if (client->mailbox != NULL)
+		mailbox_notify_changes(client->mailbox, 0, NULL, NULL);
 
 	client_sync_full(client);
 	if (done_ok)
@@ -78,21 +75,28 @@
 static void idle_timeout(void *context)
 {
 	struct client *client = context;
-	struct mailbox_status status;
+
+	/* outlook workaround - it hasn't sent anything for a long time and
+	   we're about to disconnect unless it does something. send a fake
+	   EXISTS to see if it responds. it's expunged later. */
 
 	timeout_remove(client->idle_to);
 	client->idle_to = NULL;
 
-	if (mailbox_get_status(client->mailbox, STATUS_MESSAGES, &status) < 0) {
+	client->idle_expunge = client->messages_count+1;
+	client_send_line(client,
+			 t_strdup_printf("* %u EXISTS", client->idle_expunge));
+	mailbox_notify_changes(client->mailbox, 0, NULL, NULL);
+}
+
+static void idle_callback(struct mailbox *box, void *context)
+{
+	struct client *client = context;
+
+	if (imap_sync(client, box, 0) < 0) {
 		client_send_untagged_storage_error(client,
 			mailbox_get_storage(client->mailbox));
-		idle_finish(client, TRUE);
-	} else {
-                client->idle_expunge = status.messages+1;
-		client_send_line(client,
-			t_strdup_printf("* %u EXISTS", client->idle_expunge));
-
-		mailbox_auto_sync(client->mailbox, MAILBOX_SYNC_AUTO_STOP, 0);
+		mailbox_notify_changes(client->mailbox, 0, NULL, NULL);
 	}
 }
 
@@ -113,9 +117,10 @@
 	if (interval == 0)
 		interval = DEFAULT_IDLE_CHECK_INTERVAL;
 
-	if (client->mailbox != NULL)
-		mailbox_auto_sync(client->mailbox, 0, interval);
-
+	if (client->mailbox != NULL) {
+		mailbox_notify_changes(client->mailbox, interval,
+				       idle_callback, client);
+	}
 	client_send_line(client, "+ idling");
 
 	io_remove(client->io);
--- a/src/imap/cmd-select.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/cmd-select.c	Mon Jul 12 14:35:50 2004 +0300
@@ -2,6 +2,7 @@
 
 #include "common.h"
 #include "commands.h"
+#include "imap-sync.h"
 
 int _cmd_select_full(struct client *client, int readonly)
 {
@@ -34,6 +35,12 @@
 		return TRUE;
 	}
 
+	if (imap_sync(client, box, 0) < 0) {
+		client_send_storage_error(client, storage);
+		mailbox_close(box);
+		return TRUE;
+	}
+
 	if (mailbox_get_status(box, STATUS_MESSAGES | STATUS_RECENT |
 			       STATUS_FIRST_UNSEEN_SEQ | STATUS_UIDVALIDITY |
 			       STATUS_UIDNEXT | STATUS_KEYWORDS,
@@ -45,6 +52,8 @@
 
 	client_save_keywords(&client->keywords,
 			     status.keywords, status.keywords_count);
+	client->messages_count = status.messages;
+	client->recent_count = status.recent;
 
 	/* set client's mailbox only after getting status to make sure
 	   we're not sending any expunge/exists replies too early to client */
@@ -81,12 +90,6 @@
 	client_send_tagline(client, mailbox_is_readonly(box) ?
 			    "OK [READ-ONLY] Select completed." :
 			    "OK [READ-WRITE] Select completed.");
-
-	if (mailbox_check_interval != 0) {
-		mailbox_auto_sync(box, MAILBOX_SYNC_FLAG_NO_EXPUNGES,
-				  mailbox_check_interval);
-	}
-
 	return TRUE;
 }
 
--- a/src/imap/cmd-status.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/cmd-status.c	Mon Jul 12 14:35:50 2004 +0300
@@ -4,6 +4,7 @@
 #include "str.h"
 #include "imap-quote.h"
 #include "commands.h"
+#include "imap-sync.h"
 
 /* Returns status items, or -1 if error */
 static enum mailbox_status_items
@@ -64,7 +65,10 @@
 			return FALSE;
 	}
 
-	failed = mailbox_get_status(box, items, status) < 0;
+	if (imap_sync(client, box, 0) < 0)
+		failed = TRUE;
+	else
+		failed = mailbox_get_status(box, items, status) < 0;
 
 	if (box != client->mailbox)
 		mailbox_close(box);
--- a/src/imap/cmd-store.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/cmd-store.c	Mon Jul 12 14:35:50 2004 +0300
@@ -1,6 +1,7 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "common.h"
+#include "str.h"
 #include "commands.h"
 #include "imap-search.h"
 #include "imap-util.h"
@@ -37,19 +38,21 @@
 static int mail_send_flags(struct client *client, struct mail *mail)
 {
 	const struct mail_full_flags *flags;
-	const char *str;
+	string_t *str;
 
 	flags = mail->get_flags(mail);
 	if (flags == NULL)
 		return FALSE;
 
 	t_push();
-	str = imap_write_flags(flags);
-	str = t_strdup_printf(client->cmd_uid ?
-			      "* %u FETCH (FLAGS (%s) UID %u)" :
-			      "* %u FETCH (FLAGS (%s))",
-			      mail->seq, str, mail->uid);
-	client_send_line(client, str);
+	str = t_str_new(128);
+	str_printfa(str, "* %u FETCH (FLAGS (", mail->seq);
+	imap_write_flags(str, flags);
+	if (client->cmd_uid)
+		str_printfa(str, ") UID %u)", mail->uid);
+	else
+		str_append(str, "))");
+	client_send_line(client, str_c(str));
 	t_pop();
 
 	return TRUE;
--- a/src/imap/commands-util.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/commands-util.c	Mon Jul 12 14:35:50 2004 +0300
@@ -7,6 +7,7 @@
 #include "imap-util.h"
 #include "mail-storage.h"
 #include "imap-parser.h"
+#include "imap-sync.h"
 #include "namespace.h"
 
 /* Maximum length for mailbox name, including it's path. This isn't fully
@@ -116,7 +117,7 @@
 	if (client->mailbox == NULL)
 		return;
 
-	if (mailbox_sync(client->mailbox, 0) < 0) {
+	if (imap_sync(client, client->mailbox, 0) < 0) {
 		client_send_untagged_storage_error(client,
 			mailbox_get_storage(client->mailbox));
 	}
@@ -127,7 +128,7 @@
 	if (client->mailbox == NULL)
 		return;
 
-	if (mailbox_sync(client->mailbox, MAILBOX_SYNC_FLAG_FAST) < 0) {
+	if (imap_sync(client, client->mailbox, MAILBOX_SYNC_FLAG_FAST) < 0) {
 		client_send_untagged_storage_error(client,
 			mailbox_get_storage(client->mailbox));
 	}
@@ -138,8 +139,8 @@
 	if (client->mailbox == NULL)
 		return;
 
-	if (mailbox_sync(client->mailbox, MAILBOX_SYNC_FLAG_FAST |
-			 MAILBOX_SYNC_FLAG_NO_EXPUNGES) < 0) {
+	if (imap_sync(client, client->mailbox, MAILBOX_SYNC_FLAG_FAST |
+		      MAILBOX_SYNC_FLAG_NO_EXPUNGES) < 0) {
 		client_send_untagged_storage_error(client,
 			mailbox_get_storage(client->mailbox));
 	}
--- a/src/imap/imap-fetch.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/imap-fetch.c	Mon Jul 12 14:35:50 2004 +0300
@@ -58,7 +58,9 @@
 		flags = &full_flags;
 	}
 
-	str_printfa(ctx->str, "FLAGS (%s) ", imap_write_flags(flags));
+	str_append(ctx->str, "FLAGS (");
+	imap_write_flags(ctx->str, flags);
+	str_append(ctx->str, ") ");
 	return TRUE;
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imap/imap-sync.c	Mon Jul 12 14:35:50 2004 +0300
@@ -0,0 +1,88 @@
+/* Copyright (C) 2002 Timo Sirainen */
+
+#include "common.h"
+#include "str.h"
+#include "imap-util.h"
+#include "mail-storage.h"
+#include "imap-sync.h"
+
+int imap_sync(struct client *client, struct mailbox *box,
+	      enum mailbox_sync_flags flags)
+{
+        struct mailbox_transaction_context *t;
+	struct mailbox_sync_context *ctx;
+        struct mailbox_sync_rec sync_rec;
+	struct mailbox_status status;
+	struct mail *mail;
+        const struct mail_full_flags *mail_flags;
+	string_t *str;
+	uint32_t seq;
+
+	if (client->mailbox != box) {
+		/* mailbox isn't selected - we only wish to sync the mailbox
+		   without sending anything to client */
+		ctx = mailbox_sync_init(box, flags);
+		while (mailbox_sync_next(ctx, &sync_rec) > 0)
+			;
+		return mailbox_sync_deinit(ctx, &status);
+	}
+
+	t_push();
+	str = t_str_new(256);
+
+	t = mailbox_transaction_begin(box, FALSE);
+	ctx = mailbox_sync_init(box, flags);
+	while (mailbox_sync_next(ctx, &sync_rec) > 0) {
+		switch (sync_rec.type) {
+		case MAILBOX_SYNC_TYPE_FLAGS:
+			for (seq = sync_rec.seq1; seq <= sync_rec.seq2; seq++) {
+				mail = mailbox_fetch(t, seq, MAIL_FETCH_FLAGS);
+
+				mail_flags = mail->get_flags(mail);
+				if (mail_flags == NULL)
+					continue;
+
+				str_truncate(str, 0);
+				str_printfa(str, "* %u FETCH (FLAGS (", seq);
+				imap_write_flags(str, mail_flags);
+				str_append(str, "))");
+				client_send_line(client, str_c(str));
+			}
+			break;
+		case MAILBOX_SYNC_TYPE_EXPUNGE:
+			for (seq = sync_rec.seq2; seq >= sync_rec.seq1; seq--) {
+				str_truncate(str, 0);
+				str_printfa(str, "* %u EXPUNGE", seq);
+				client_send_line(client, str_c(str));
+			}
+			break;
+		}
+	}
+
+	if (mailbox_sync_deinit(ctx, &status) < 0) {
+		mailbox_transaction_rollback(t);
+		t_pop();
+		return -1;
+	}
+
+	mailbox_transaction_commit(t);
+
+	if (status.messages != client->messages_count) {
+                client->messages_count = status.messages;
+		str_truncate(str, 0);
+		str_printfa(str, "* %u EXISTS", status.messages);
+		client_send_line(client, str_c(str));
+	}
+	if (status.recent != client->recent_count) {
+                client->recent_count = status.recent;
+		str_truncate(str, 0);
+		str_printfa(str, "* %u RECENT", status.recent);
+		client_send_line(client, str_c(str));
+	}
+
+	/*FIXME:client_save_keywords(&client->keywords, keywords, keywords_count);
+	client_send_mailbox_flags(client, mailbox, keywords, keywords_count);*/
+
+	t_pop();
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/imap/imap-sync.h	Mon Jul 12 14:35:50 2004 +0300
@@ -0,0 +1,7 @@
+#ifndef __IMAP_SYNC_H
+#define __IMAP_SYNC_H
+
+int imap_sync(struct client *client, struct mailbox *box,
+	      enum mailbox_sync_flags flags);
+
+#endif
--- a/src/imap/mail-storage-callbacks.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/imap/mail-storage-callbacks.c	Mon Jul 12 14:35:50 2004 +0300
@@ -33,79 +33,8 @@
 	o_stream_flush(client->output);
 }
 
-static void expunge(struct mailbox *mailbox, unsigned int seq, void *context)
-{
-	struct client *client = context;
-	char str[MAX_INT_STRLEN+20];
-
-	if (client->mailbox != mailbox)
-		return;
-
-	i_snprintf(str, sizeof(str), "* %u EXPUNGE", seq);
-	client_send_line(client, str);
-}
-
-static void update_flags(struct mailbox *mailbox, unsigned int seq,
-			 const struct mail_full_flags *flags, void *context)
-{
-	struct client *client = context;
-	const char *str;
-
-	if (client->mailbox != mailbox)
-		return;
-
-	t_push();
-	str = imap_write_flags(flags);
-	str = t_strdup_printf("* %u FETCH (FLAGS (%s))", seq, str);
-	client_send_line(client, str);
-	t_pop();
-}
-
-static void message_count_changed(struct mailbox *mailbox, unsigned int count,
-				  void *context)
-{
-	struct client *client = context;
-	char str[MAX_INT_STRLEN+20];
-
-	if (client->mailbox != mailbox)
-		return;
-
-	i_snprintf(str, sizeof(str), "* %u EXISTS", count);
-	client_send_line(client, str);
-}
-
-static void recent_count_changed(struct mailbox *mailbox, unsigned int count,
-				 void *context)
-{
-	struct client *client = context;
-	char str[MAX_INT_STRLEN+20];
-
-	if (client->mailbox != mailbox)
-		return;
-
-	i_snprintf(str, sizeof(str), "* %u RECENT", count);
-	client_send_line(client, str);
-}
-
-static void new_keywords(struct mailbox *mailbox, const char *keywords[],
-			 unsigned int keywords_count, void *context)
-{
-	struct client *client = context;
-
-	if (client->mailbox != mailbox)
-		return;
-
-	client_save_keywords(&client->keywords, keywords, keywords_count);
-	client_send_mailbox_flags(client, mailbox, keywords, keywords_count);
-}
-
 struct mail_storage_callbacks mail_storage_callbacks = {
 	alert_no_diskspace,
 	notify_ok,
-	notify_no,
-	expunge,
-	update_flags,
-	message_count_changed,
-	recent_count_changed,
-	new_keywords
+	notify_no
 };
--- a/src/lib-imap/imap-util.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-imap/imap-util.c	Mon Jul 12 14:35:50 2004 +0300
@@ -5,38 +5,33 @@
 #include "mail-types.h"
 #include "imap-util.h"
 
-const char *imap_write_flags(const struct mail_full_flags *flags)
+void imap_write_flags(string_t *dest, const struct mail_full_flags *flags)
 {
-	string_t *str;
-	const char *sysflags;
 	unsigned int i;
-
-	if (flags == 0)
-		return "";
-
-	sysflags = t_strconcat(
-		(flags->flags & MAIL_ANSWERED) ? " \\Answered" : "",
-		(flags->flags & MAIL_FLAGGED) ? " \\Flagged" : "",
-		(flags->flags & MAIL_DELETED) ? " \\Deleted" : "",
-		(flags->flags & MAIL_SEEN) ? " \\Seen" : "",
-		(flags->flags & MAIL_DRAFT) ? " \\Draft" : "",
-		(flags->flags & MAIL_RECENT)  ? " \\Recent" : "",
-		NULL);
+	size_t size;
 
-	if (*sysflags != '\0')
-		sysflags++;
-
-	if (flags->keywords_count == 0)
-		return sysflags;
+	size = str_len(dest);
+	if ((flags->flags & MAIL_ANSWERED) != 0)
+		str_append(dest, "\\Answered ");
+	if ((flags->flags & MAIL_FLAGGED) != 0)
+		str_append(dest, "\\Flagged ");
+	if ((flags->flags & MAIL_DELETED) != 0)
+		str_append(dest, "\\Deleted ");
+	if ((flags->flags & MAIL_SEEN) != 0)
+		str_append(dest, "\\Seen ");
+	if ((flags->flags & MAIL_DRAFT) != 0)
+		str_append(dest, "\\Draft ");
+	if ((flags->flags & MAIL_RECENT) != 0)
+		str_append(dest, "\\Recent ");
 
-	/* we have keywords too */
-	str = t_str_new(256);
-	str_append(str, sysflags);
+	if (flags->keywords_count > 0) {
+		/* we have keywords too */
+		for (i = 0; i < flags->keywords_count; i++) {
+			str_append(dest, flags->keywords[i]);
+			str_append_c(dest, ' ');
+		}
+	}
 
-	for (i = 0; i < flags->keywords_count; i++) {
-		if (str_len(str) > 0)
-			str_append_c(str, ' ');
-		str_append(str, flags->keywords[i]);
-	}
-	return str_c(str);
+	if (str_len(dest) != size)
+		str_truncate(dest, str_len(dest)-1);
 }
--- a/src/lib-imap/imap-util.h	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-imap/imap-util.h	Mon Jul 12 14:35:50 2004 +0300
@@ -4,6 +4,6 @@
 struct mail_full_flags;
 
 /* Return flags as a space separated string. */
-const char *imap_write_flags(const struct mail_full_flags *flags);
+void imap_write_flags(string_t *dest, const struct mail_full_flags *flags);
 
 #endif
--- a/src/lib-storage/index/index-mailbox-check.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/index-mailbox-check.c	Mon Jul 12 14:35:50 2004 +0300
@@ -9,31 +9,46 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
+struct index_notify_file {
+	struct index_notify_file *next;
+
+	char *path;
+	time_t last_stamp;
+};
+
+struct index_notify_io {
+	struct index_notify_io *next;
+	struct io *io;
+	int fd;
+};
+
 static void check_timeout(void *context)
 {
 	struct index_mailbox *ibox = context;
-	struct index_autosync_file *file;
+	struct index_notify_file *file;
 	struct stat st;
-	int sync;
+	time_t last_check;
+	int notify;
 
 	/* check changes only when we can also notify of new mail */
-	if ((unsigned int) (ioloop_time - ibox->sync_last_check) <
-	    ibox->min_newmail_notify_interval)
+	last_check = I_MAX(ibox->sync_last_check, ibox->notify_last_check);
+	if ((unsigned int)(ioloop_time - last_check) <
+	    ibox->min_notify_interval)
 		return;
 
-	ibox->sync_last_check = ioloop_time;
+	ibox->notify_last_check = ioloop_time;
 
-	sync = ibox->autosync_pending;
-	for (file = ibox->autosync_files; file != NULL; file = file->next) {
+	notify = ibox->notify_pending;
+	for (file = ibox->notify_files; file != NULL; file = file->next) {
 		if (stat(file->path, &st) == 0 &&
 		    file->last_stamp != st.st_mtime)
 			file->last_stamp = st.st_mtime;
 	}
 
-	if (sync) {
-		ibox->box.sync(&ibox->box, ibox->autosync_flags);
-		ibox->sync_last_notify = ioloop_time;
-		ibox->autosync_pending = FALSE;
+	if (notify) {
+		ibox->notify_last_sent = ioloop_time;
+		ibox->notify_pending = FALSE;
+		ibox->notify_callback(&ibox->box, ibox->notify_context);
 	}
 }
 
@@ -41,24 +56,24 @@
 {
 	struct index_mailbox *ibox = context;
 
-	ibox->sync_last_check = ioloop_time;
-	if ((unsigned int) (ioloop_time - ibox->sync_last_notify) >=
-	    ibox->min_newmail_notify_interval) {
-		ibox->box.sync(&ibox->box, ibox->autosync_flags);
-		ibox->sync_last_notify = ioloop_time;
-                ibox->autosync_pending = FALSE;
+	ibox->notify_last_check = ioloop_time;
+	if ((unsigned int)(ioloop_time - ibox->notify_last_sent) >=
+	    ibox->min_notify_interval) {
+		ibox->notify_last_sent = ioloop_time;
+                ibox->notify_pending = FALSE;
+		ibox->notify_callback(&ibox->box, ibox->notify_context);
 	} else {
-		ibox->autosync_pending = TRUE;
+		ibox->notify_pending = TRUE;
 	}
 }
 
 void index_mailbox_check_add(struct index_mailbox *ibox,
 			     const char *path, int dir)
 {
-	struct index_autosync_file *file;
+	struct index_notify_file *file;
 	struct stat st;
 	struct io *io;
-	struct index_autosync_io *aio;
+	struct index_notify_io *aio;
 	int fd;
 
 	fd = open(path, O_RDONLY);
@@ -66,56 +81,56 @@
 		io = io_add(fd, dir ? IO_DIR_NOTIFY : IO_FILE_NOTIFY,
 			    notify_callback, ibox);
 		if (io != NULL) {
-			aio = i_new(struct index_autosync_io, 1);
+			aio = i_new(struct index_notify_io, 1);
 			aio->io = io;
 			aio->fd = fd;
-			aio->next = ibox->autosync_ios;
-			ibox->autosync_ios = aio;
+			aio->next = ibox->notify_ios;
+			ibox->notify_ios = aio;
 		}
 	}
 
-	file = i_new(struct index_autosync_file, 1);
+	file = i_new(struct index_notify_file, 1);
 	file->path = i_strdup(path);
 	if (fd < 0)
 		file->last_stamp = stat(path, &st) < 0 ? 0 : st.st_mtime;
 	else
 		file->last_stamp = fstat(fd, &st) < 0 ? 0 : st.st_mtime;
 
-	file->next = ibox->autosync_files;
-        ibox->autosync_files = file;
+	file->next = ibox->notify_files;
+        ibox->notify_files = file;
 
-	if (ibox->autosync_to == NULL)
-		ibox->autosync_to = timeout_add(1000, check_timeout, ibox);
+	if (ibox->notify_to == NULL)
+		ibox->notify_to = timeout_add(1000, check_timeout, ibox);
 }
 
 void index_mailbox_check_remove_all(struct index_mailbox *ibox)
 {
-	struct index_autosync_file *file;
-	struct index_autosync_io *aio;
+	struct index_notify_file *file;
+	struct index_notify_io *aio;
 
 	/* reset notify stamp */
-	ibox->sync_last_notify = 0;
+	ibox->notify_last_sent = 0;
 
-	while (ibox->autosync_files != NULL) {
-		file = ibox->autosync_files;
-		ibox->autosync_files = file->next;
+	while (ibox->notify_files != NULL) {
+		file = ibox->notify_files;
+		ibox->notify_files = file->next;
 
                 i_free(file->path);
 		i_free(file);
 	}
 
-	while (ibox->autosync_ios != NULL) {
-		aio = ibox->autosync_ios;
-		ibox->autosync_ios = aio->next;
+	while (ibox->notify_ios != NULL) {
+		aio = ibox->notify_ios;
+		ibox->notify_ios = aio->next;
 
 		io_remove(aio->io);
 		if (close(aio->fd) < 0)
-			i_error("close(autosync_io) failed: %m");
+			i_error("close(notify_io) failed: %m");
 		i_free(aio);
 	}
 
-	if (ibox->autosync_to != NULL) {
-		timeout_remove(ibox->autosync_to);
-		ibox->autosync_to = NULL;
+	if (ibox->notify_to != NULL) {
+		timeout_remove(ibox->notify_to);
+		ibox->notify_to = NULL;
 	}
 }
--- a/src/lib-storage/index/index-status.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/index-status.c	Mon Jul 12 14:35:50 2004 +0300
@@ -3,10 +3,6 @@
 #include "lib.h"
 #include "index-storage.h"
 
-#define STATUS_MESSAGE_COUNTS \
-	(STATUS_MESSAGES | STATUS_RECENT | STATUS_UIDNEXT | \
-	 STATUS_UIDVALIDITY | STATUS_UNSEEN | STATUS_FIRST_UNSEEN_SEQ)
-
 /*static void
 get_keywords(struct mail_keywords *mcf, struct mailbox_status *status)
 {
@@ -21,44 +17,47 @@
 		status->keywords[i] = t_strdup(flags[i]);
 }*/
 
-int index_storage_get_status(struct mailbox *box,
-			     enum mailbox_status_items items,
-			     struct mailbox_status *status)
+int index_storage_get_status_locked(struct index_mailbox *ibox,
+				    enum mailbox_status_items items,
+				    struct mailbox_status *status_r)
 {
-	struct index_mailbox *ibox = (struct index_mailbox *) box;
 	const struct mail_index_header *hdr;
 
-	memset(status, 0, sizeof(struct mailbox_status));
-
-	if ((items & STATUS_MESSAGE_COUNTS) != 0) {
-		/* sync mailbox to update message counts */
-		if (mailbox_sync(box, 0) < 0)
-			return -1;
-	}
+	memset(status_r, 0, sizeof(struct mailbox_status));
 
 	/* we can get most of the status items without any trouble */
 	if (mail_index_get_header(ibox->view, &hdr) < 0)
 		return -1;
-	if ((items & STATUS_MESSAGE_COUNTS) != 0) {
-		status->messages = hdr->messages_count;
-		status->recent = ibox->synced_recent_count;
-		status->unseen = hdr->messages_count - hdr->seen_messages_count;
-		status->uidvalidity = hdr->uid_validity;
-		status->uidnext = hdr->next_uid;
-	}
-	//FIXME:status->diskspace_full = ibox->nodiskspace;
+
+	status_r->messages = hdr->messages_count;
+	status_r->recent = ibox->synced_recent_count;
+	status_r->unseen =
+		hdr->messages_count - hdr->seen_messages_count;
+	status_r->uidvalidity = hdr->uid_validity;
+	status_r->uidnext = hdr->next_uid;
+	//FIXME:status_r->diskspace_full = ibox->nodiskspace;
 
 	if (items & STATUS_FIRST_UNSEEN_SEQ) {
 		if (mail_index_lookup_first(ibox->view, 0, MAIL_SEEN,
-					    &status->first_unseen_seq) < 0) {
+					    &status_r->first_unseen_seq) < 0) {
 			mail_storage_set_index_error(ibox);
 			return -1;
 		}
 	}
 
 	/*FIXME:if (items & STATUS_KEYWORDS)
-		get_keywords(ibox, status);*/
-
-	mail_index_view_unlock(ibox->view);
+		get_keywords(ibox, status_r);*/
 	return 0;
 }
+
+int index_storage_get_status(struct mailbox *box,
+			     enum mailbox_status_items items,
+			     struct mailbox_status *status)
+{
+	struct index_mailbox *ibox = (struct index_mailbox *)box;
+	int ret;
+
+	ret = index_storage_get_status_locked(ibox, items, status);
+	mail_index_view_unlock(ibox->view);
+	return ret;
+}
--- a/src/lib-storage/index/index-storage.h	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/index-storage.h	Mon Jul 12 14:35:50 2004 +0300
@@ -22,19 +22,6 @@
 	MAILBOX_LOCK_NOTIFY_MAILBOX_OVERRIDE
 };
 
-struct index_autosync_file {
-	struct index_autosync_file *next;
-
-	char *path;
-	time_t last_stamp;
-};
-
-struct index_autosync_io {
-	struct index_autosync_io *next;
-	struct io *io;
-	int fd;
-};
-
 struct index_storage {
 	struct mail_storage storage;
 
@@ -63,12 +50,13 @@
 	void (*mail_deinit)(struct index_mail *mail);
 	int (*is_recent)(struct index_mailbox *ibox, uint32_t uid);
 
-	struct timeout *autosync_to;
-	struct index_autosync_file *autosync_files;
-        struct index_autosync_io *autosync_ios;
-	enum mailbox_sync_flags autosync_flags;
-	time_t sync_last_check, sync_last_notify;
-	unsigned int min_newmail_notify_interval;
+	struct timeout *notify_to;
+	struct index_notify_file *notify_files;
+        struct index_notify_io *notify_ios;
+	time_t notify_last_check, notify_last_sent;
+	unsigned int min_notify_interval;
+	mailbox_notify_callback_t *notify_callback;
+	void *notify_context;
 
 	time_t next_lock_notify; /* temporary */
 	enum mailbox_lock_notify_type last_notify_type;
@@ -78,7 +66,8 @@
 
 	buffer_t *recent_flags;
 	uint32_t recent_flags_start_seq, recent_flags_count;
-	unsigned int synced_recent_count;
+	uint32_t synced_recent_count;
+	time_t sync_last_check;
 
 	/* mbox: */
 	int mbox_fd;
@@ -106,7 +95,7 @@
 	unsigned int recent_flags_synced:1;
 	unsigned int sent_diskspace_warning:1;
 	unsigned int sent_readonly_flags_warning:1;
-	unsigned int autosync_pending:1;
+	unsigned int notify_pending:1;
 	unsigned int mail_read_mmaped:1;
 	unsigned int syncing_commit:1;
 };
@@ -164,6 +153,14 @@
 			     const char *path, int dir);
 void index_mailbox_check_remove_all(struct index_mailbox *ibox);
 
+struct mailbox_sync_context *
+index_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags,
+			int failed);
+int index_mailbox_sync_next(struct mailbox_sync_context *ctx,
+			    struct mailbox_sync_rec *sync_rec_r);
+int index_mailbox_sync_deinit(struct mailbox_sync_context *ctx,
+			      struct mailbox_status *status_r);
+
 int index_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
 
 void index_storage_set_callbacks(struct mail_storage *storage,
@@ -174,6 +171,9 @@
 int index_storage_get_status(struct mailbox *box,
 			     enum mailbox_status_items items,
 			     struct mailbox_status *status);
+int index_storage_get_status_locked(struct index_mailbox *ibox,
+				    enum mailbox_status_items items,
+				    struct mailbox_status *status_r);
 
 struct mail *
 index_storage_fetch(struct mailbox_transaction_context *t, uint32_t seq,
--- a/src/lib-storage/index/index-sync.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/index-sync.c	Mon Jul 12 14:35:50 2004 +0300
@@ -4,6 +4,17 @@
 #include "buffer.h"
 #include "index-storage.h"
 
+struct index_mailbox_sync_context {
+	struct mailbox_sync_context ctx;
+	struct index_mailbox *ibox;
+	struct mail_index_view_sync_ctx *sync_ctx;
+	uint32_t messages_count;
+
+	const uint32_t *expunges;
+	size_t expunges_count;
+	int failed;
+};
+
 void index_mailbox_set_recent(struct index_mailbox *ibox, uint32_t seq)
 {
 	unsigned char *p;
@@ -97,124 +108,142 @@
 	return 0;
 }
 
-int index_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+struct mailbox_sync_context *
+index_mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags,
+			int failed)
 {
 	struct index_mailbox *ibox = (struct index_mailbox *)box;
-	struct mail_index_view_sync_ctx *ctx;
-        struct mail_full_flags full_flags;
-	const struct mail_index_record *rec;
-	struct mail_index_sync_rec sync;
-	struct mail_storage_callbacks *sc;
-	const uint32_t *expunges;
-	size_t i, expunges_count;
-	void *sc_context;
+        struct index_mailbox_sync_context *ctx;
 	enum mail_index_sync_type sync_mask;
-	uint32_t seq, seq1, seq2;
-	uint32_t messages_count, last_messages_count;
-	int ret;
+
+	ctx = i_new(struct index_mailbox_sync_context, 1);
+	ctx->ctx.box = box;
+	ctx->ibox = ibox;
+
+	if (failed) {
+		ctx->failed = TRUE;
+		return &ctx->ctx;
+	}
+
+	ctx->messages_count = mail_index_view_get_message_count(ibox->view);
 
 	sync_mask = MAIL_INDEX_SYNC_MASK_ALL;
 	if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0)
 		sync_mask &= ~MAIL_INDEX_SYNC_TYPE_EXPUNGE;
 
-	if (mail_index_view_sync_begin(ibox->view, sync_mask, &ctx) < 0) {
-                mail_storage_set_index_error(ibox);
-		return -1;
+	if (mail_index_view_sync_begin(ibox->view, sync_mask,
+				       &ctx->sync_ctx) < 0) {
+		mail_storage_set_index_error(ibox);
+		ctx->failed = TRUE;
+		return &ctx->ctx;
 	}
 
-	last_messages_count = mail_index_view_get_message_count(ibox->view);
-
 	if (!ibox->recent_flags_synced) {
 		ibox->recent_flags_synced = TRUE;
-                index_mailbox_update_recent(ibox, 1, last_messages_count);
+                index_mailbox_update_recent(ibox, 1, ctx->messages_count);
 	}
 
-	if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0) {
-		expunges_count = 0;
-		expunges = NULL;
-	} else {
-		expunges =
-			mail_index_view_sync_get_expunges(ctx, &expunges_count);
+	if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) == 0) {
+		ctx->expunges =
+			mail_index_view_sync_get_expunges(ctx->sync_ctx,
+							  &ctx->expunges_count);
 	}
+	return &ctx->ctx;
+}
 
-	sc = ibox->storage->callbacks;
-	sc_context = ibox->storage->callback_context;
+int index_mailbox_sync_next(struct mailbox_sync_context *_ctx,
+			    struct mailbox_sync_rec *sync_rec_r)
+{
+	struct index_mailbox_sync_context *ctx =
+		(struct index_mailbox_sync_context *)_ctx;
+	struct mail_index_sync_rec sync;
+	int ret;
 
-	memset(&full_flags, 0, sizeof(full_flags));
-	while ((ret = mail_index_view_sync_next(ctx, &sync)) > 0) {
+	if (ctx->failed)
+		return -1;
+
+	while ((ret = mail_index_view_sync_next(ctx->sync_ctx, &sync)) > 0) {
 		switch (sync.type) {
 		case MAIL_INDEX_SYNC_TYPE_APPEND:
+			/* not interested */
 			break;
 		case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
 			/* later */
 			break;
 		case MAIL_INDEX_SYNC_TYPE_FLAGS:
-			if (sc->update_flags == NULL)
-				break;
-
 			/* FIXME: hide the flag updates for expunged messages */
-
-			if (mail_index_lookup_uid_range(ibox->view,
-							sync.uid1, sync.uid2,
-							&seq1, &seq2) < 0) {
-				ret = -1;
-				break;
+			if (mail_index_lookup_uid_range(ctx->ibox->view,
+						sync.uid1, sync.uid2,
+						&sync_rec_r->seq1,
+						&sync_rec_r->seq2) < 0) {
+				ctx->failed = TRUE;
+				return -1;
 			}
 
-			if (seq1 == 0)
+			if (sync_rec_r->seq1 == 0)
 				break;
 
-			for (seq = seq1; seq <= seq2; seq++) {
-				if (mail_index_lookup(ibox->view,
-						      seq, &rec) < 0) {
-					ret = -1;
-					break;
-				}
-				full_flags.flags = rec->flags; // FIXME
-				if (index_mailbox_is_recent(ibox, seq))
-					full_flags.flags |= MAIL_RECENT;
-				sc->update_flags(&ibox->box, seq,
-						 &full_flags, sc_context);
-			}
-			break;
+			sync_rec_r->type = MAILBOX_SYNC_TYPE_FLAGS;
+			return 1;
 		}
 	}
 
+	if (ret == 0 && ctx->expunges_count > 0) {
+		/* expunges[] is a sorted array of sequences. it's easiest for
+		   us to print them from end to beginning. */
+		sync_rec_r->seq1 = ctx->expunges[ctx->expunges_count*2-2];
+		sync_rec_r->seq2 = ctx->expunges[ctx->expunges_count*2-1];
+		index_mailbox_expunge_recent(ctx->ibox, sync_rec_r->seq1,
+					     sync_rec_r->seq2);
+
+		if (sync_rec_r->seq2 > ctx->messages_count)
+			sync_rec_r->seq2 = ctx->messages_count;
+
+		ctx->messages_count -= sync_rec_r->seq2 - sync_rec_r->seq1 + 1;
+		ctx->expunges_count--;
+
+		sync_rec_r->type = MAILBOX_SYNC_TYPE_EXPUNGE;
+		return 1;
+	}
+
 	if (ret < 0)
-		mail_storage_set_index_error(ibox);
+		mail_storage_set_index_error(ctx->ibox);
+	return ret;
+}
+
+#define SYNC_STATUS_FLAGS \
+	(STATUS_MESSAGES | STATUS_RECENT | STATUS_UIDNEXT | \
+	 STATUS_UIDVALIDITY | STATUS_UNSEEN | STATUS_KEYWORDS)
 
-	if (sc->expunge != NULL) {
-		/* expunges[] is a sorted array of sequences. it's easiest for
-		   us to print them from end to beginning. */
+int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx,
+			      struct mailbox_status *status_r)
+{
+	struct index_mailbox_sync_context *ctx =
+		(struct index_mailbox_sync_context *)_ctx;
+	struct index_mailbox *ibox = ctx->ibox;
+	uint32_t messages_count;
+	int ret = ctx->failed ? -1 : 0;
+
+	if (ctx->sync_ctx != NULL)
+		mail_index_view_sync_end(ctx->sync_ctx);
+
+	if (ret == 0) {
 		messages_count = mail_index_view_get_message_count(ibox->view);
-		for (i = expunges_count*2; i > 0; i -= 2) {
-			seq = expunges[i-1];
-			index_mailbox_expunge_recent(ibox, expunges[i-2], seq);
-			if (seq > messages_count)
-				seq = messages_count;
-			for (; seq >= expunges[i-2]; seq--) {
-				sc->expunge(&ibox->box, seq, sc_context);
-				last_messages_count--;
-			}
+		if (messages_count != ctx->messages_count) {
+			index_mailbox_update_recent(ibox,
+						    ctx->messages_count+1,
+						    messages_count);
 		}
+
+		if (ibox->recent_flags_count != ibox->synced_recent_count)
+			ibox->synced_recent_count = ibox->recent_flags_count;
+
+		ret = index_storage_get_status_locked(ctx->ibox,
+						      SYNC_STATUS_FLAGS,
+						      status_r);
 	}
 
-	mail_index_view_sync_end(ctx);
-
-	messages_count = mail_index_view_get_message_count(ibox->view);
-	if (messages_count != last_messages_count) {
-		index_mailbox_update_recent(ibox, last_messages_count+1,
-					    messages_count);
-		sc->message_count_changed(&ibox->box, messages_count,
-					  sc_context);
-	}
-
-	if (ibox->recent_flags_count != ibox->synced_recent_count) {
-                ibox->synced_recent_count = ibox->recent_flags_count;
-		sc->recent_count_changed(&ibox->box, ibox->synced_recent_count,
-					 sc_context);
-	}
-
-	mail_index_view_unlock(ibox->view);
+	mail_index_view_unlock(ctx->ibox->view);
+	i_free(ctx);
 	return ret;
 }
--- a/src/lib-storage/index/maildir/maildir-storage.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Mon Jul 12 14:35:50 2004 +0300
@@ -798,22 +798,17 @@
 	return ret;
 }
 
-static void maildir_storage_auto_sync(struct mailbox *box,
-				      enum mailbox_sync_flags flags,
-				      unsigned int min_newmail_notify_interval)
+static void
+maildir_notify_changes(struct mailbox *box, unsigned int min_interval,
+		       mailbox_notify_callback_t *callback, void *context)
 {
 	struct index_mailbox *ibox = (struct index_mailbox *)box;
 
-	ibox->min_newmail_notify_interval = min_newmail_notify_interval;
+	ibox->min_notify_interval = min_interval;
+	ibox->notify_callback = callback;
+	ibox->notify_context = context;
 
-	if ((ibox->autosync_flags == 0 && flags == 0) ||
-	    (ibox->autosync_flags != 0 && flags != 0)) {
-		/* flags or interval just changed. or nothing. */
-		ibox->autosync_flags = flags;
-	}
-	ibox->autosync_flags = flags;
-
-	if (flags == 0) {
+	if (callback == NULL) {
 		index_mailbox_check_remove_all(ibox);
 		return;
 	}
@@ -857,8 +852,10 @@
         index_storage_allow_new_keywords,
 	maildir_storage_close,
 	index_storage_get_status,
-	maildir_storage_sync,
-	maildir_storage_auto_sync,
+	maildir_storage_sync_init,
+	index_mailbox_sync_next,
+	index_mailbox_sync_deinit,
+	maildir_notify_changes,
 	maildir_transaction_begin,
 	maildir_transaction_commit,
 	maildir_transaction_rollback,
--- a/src/lib-storage/index/maildir/maildir-storage.h	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.h	Mon Jul 12 14:35:50 2004 +0300
@@ -38,7 +38,8 @@
 struct mailbox_list *
 maildir_mailbox_list_next(struct mailbox_list_context *ctx);
 
-int maildir_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
+struct mailbox_sync_context *
+maildir_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);
 int maildir_storage_sync_force(struct index_mailbox *ibox);
 
 struct mailbox_transaction_context *
--- a/src/lib-storage/index/maildir/maildir-sync.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/maildir/maildir-sync.c	Mon Jul 12 14:35:50 2004 +0300
@@ -913,11 +913,12 @@
 	return ret;
 }
 
-int maildir_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+struct mailbox_sync_context *
+maildir_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
 {
 	struct index_mailbox *ibox = (struct index_mailbox *)box;
 	struct maildir_sync_context *ctx;
-	int ret;
+	int ret = 0;
 
 	if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
 	    ibox->sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <= ioloop_time) {
@@ -926,10 +927,7 @@
 		ctx = maildir_sync_context_new(ibox);
 		ret = maildir_sync_context(ctx, FALSE);
 		maildir_sync_deinit(ctx);
-
-		if (ret < 0)
-			return -1;
 	}
 
-	return index_storage_sync(box, flags);
+	return index_mailbox_sync_init(box, flags, ret < 0);
 }
--- a/src/lib-storage/index/mbox/mbox-storage.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Mon Jul 12 14:35:50 2004 +0300
@@ -831,22 +831,17 @@
 	return 0;
 }
 
-static void mbox_storage_auto_sync(struct mailbox *box,
-				   enum mailbox_sync_flags flags,
-				   unsigned int min_newmail_notify_interval)
+static void
+mbox_notify_changes(struct mailbox *box, unsigned int min_interval,
+		    mailbox_notify_callback_t *callback, void *context)
 {
 	struct index_mailbox *ibox = (struct index_mailbox *)box;
 
-	ibox->min_newmail_notify_interval = min_newmail_notify_interval;
+	ibox->min_notify_interval = min_interval;
+	ibox->notify_callback = callback;
+	ibox->notify_context = context;
 
-	if ((ibox->autosync_flags == 0 && flags == 0) ||
-	    (ibox->autosync_flags != 0 && flags != 0)) {
-		/* flags or interval just changed. or nothing. */
-		ibox->autosync_flags = flags;
-	}
-	ibox->autosync_flags = flags;
-
-	if (flags == 0)
+	if (callback == NULL)
 		index_mailbox_check_remove_all(ibox);
 	else
 		index_mailbox_check_add(ibox, ibox->path, FALSE);
@@ -885,8 +880,10 @@
         index_storage_allow_new_keywords,
 	mbox_storage_close,
 	index_storage_get_status,
-	mbox_storage_sync,
-	mbox_storage_auto_sync,
+	mbox_storage_sync_init,
+	index_mailbox_sync_next,
+	index_mailbox_sync_deinit,
+	mbox_notify_changes,
 	mbox_transaction_begin,
 	mbox_transaction_commit,
 	mbox_transaction_rollback,
--- a/src/lib-storage/index/mbox/mbox-storage.h	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/mbox/mbox-storage.h	Mon Jul 12 14:35:50 2004 +0300
@@ -34,7 +34,8 @@
 int mbox_transaction_commit(struct mailbox_transaction_context *t);
 void mbox_transaction_rollback(struct mailbox_transaction_context *t);
 
-int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags);
+struct mailbox_sync_context *
+mbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);
 
 int mbox_save(struct mailbox_transaction_context *t,
 	      const struct mail_full_flags *flags,
--- a/src/lib-storage/index/mbox/mbox-sync.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/index/mbox/mbox-sync.c	Mon Jul 12 14:35:50 2004 +0300
@@ -1320,17 +1320,18 @@
 	return ret;
 }
 
-int mbox_storage_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+struct mailbox_sync_context *
+mbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
 {
 	struct index_mailbox *ibox = (struct index_mailbox *)box;
+	int ret = 0;
 
 	if ((flags & MAILBOX_SYNC_FLAG_FAST) == 0 ||
 	    ibox->sync_last_check + MAILBOX_FULL_SYNC_INTERVAL <= ioloop_time) {
 		ibox->sync_last_check = ioloop_time;
 
-		if (mbox_sync(ibox, FALSE, FALSE, FALSE) < 0)
-			return -1;
+		ret = mbox_sync(ibox, FALSE, FALSE, FALSE);
 	}
 
-	return index_storage_sync(box, flags);
+	return index_mailbox_sync_init(box, flags, ret < 0);
 }
--- a/src/lib-storage/mail-storage-private.h	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/mail-storage-private.h	Mon Jul 12 14:35:50 2004 +0300
@@ -66,9 +66,17 @@
 	int (*get_status)(struct mailbox *box, enum mailbox_status_items items,
 			  struct mailbox_status *status);
 
-	int (*sync)(struct mailbox *box, enum mailbox_sync_flags flags);
-	void (*auto_sync)(struct mailbox *box, enum mailbox_sync_flags flags,
-			  unsigned int min_newmail_notify_interval);
+	struct mailbox_sync_context *
+		(*sync_init)(struct mailbox *box,
+			     enum mailbox_sync_flags flags);
+	int (*sync_next)(struct mailbox_sync_context *ctx,
+			 struct mailbox_sync_rec *sync_rec_r);
+	int (*sync_deinit)(struct mailbox_sync_context *ctx,
+			   struct mailbox_status *status_r);
+
+	void (*notify_changes)(struct mailbox *box, unsigned int min_interval,
+			       mailbox_notify_callback_t *callback,
+			       void *context);
 
 	struct mailbox_transaction_context *
 		(*transaction_begin)(struct mailbox *box, int hide);
@@ -116,6 +124,10 @@
 	struct mailbox *box;
 };
 
+struct mailbox_sync_context {
+	struct mailbox *box;
+};
+
 /* Set error message in storage. Critical errors are logged with i_error(),
    but user sees only "internal error" message. */
 void mail_storage_clear_error(struct mail_storage *storage);
--- a/src/lib-storage/mail-storage.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/mail-storage.c	Mon Jul 12 14:35:50 2004 +0300
@@ -334,15 +334,28 @@
 	return box->get_status(box, items, status);
 }
 
-int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags)
+struct mailbox_sync_context *
+mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
 {
-	return box->sync(box, flags);
+	return box->sync_init(box, flags);
 }
 
-void mailbox_auto_sync(struct mailbox *box, enum mailbox_sync_flags flags,
-		       unsigned int min_newmail_notify_interval)
+int mailbox_sync_next(struct mailbox_sync_context *ctx,
+		      struct mailbox_sync_rec *sync_rec_r)
 {
-	box->auto_sync(box, flags, min_newmail_notify_interval);
+	return ctx->box->sync_next(ctx, sync_rec_r);
+}
+
+int mailbox_sync_deinit(struct mailbox_sync_context *ctx,
+			struct mailbox_status *status_r)
+{
+	return ctx->box->sync_deinit(ctx, status_r);
+}
+
+void mailbox_notify_changes(struct mailbox *box, unsigned int min_interval,
+			    mailbox_notify_callback_t *callback, void *context)
+{
+	box->notify_changes(box, min_interval, callback, context);
 }
 
 struct mail *mailbox_fetch(struct mailbox_transaction_context *t, uint32_t seq,
--- a/src/lib-storage/mail-storage.h	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/mail-storage.h	Mon Jul 12 14:35:50 2004 +0300
@@ -89,6 +89,11 @@
 	MAILBOX_SYNC_AUTO_STOP		= 0x04
 };
 
+enum mailbox_sync_type {
+	MAILBOX_SYNC_TYPE_EXPUNGE	= 0x01,
+	MAILBOX_SYNC_TYPE_FLAGS		= 0x02
+};
+
 struct mail_storage;
 struct mail_storage_callbacks;
 struct mailbox_list;
@@ -123,6 +128,11 @@
 	const char **keywords;
 };
 
+struct mailbox_sync_rec {
+	uint32_t seq1, seq2;
+	enum mailbox_sync_type type;
+};
+
 struct mail_storage_callbacks {
 	/* Alert: Not enough disk space */
 	void (*alert_no_diskspace)(struct mailbox *mailbox, void *context);
@@ -133,26 +143,9 @@
 	void (*notify_no)(struct mailbox *mailbox, const char *text,
 			  void *context);
 
-	/* EXPUNGE */
-	void (*expunge)(struct mailbox *mailbox, unsigned int seq,
-			void *context);
-	/* FETCH FLAGS */
-	void (*update_flags)(struct mailbox *mailbox, unsigned int seq,
-			     const struct mail_full_flags *flags,
-			     void *context);
+};
 
-	/* EXISTS */
-	void (*message_count_changed)(struct mailbox *mailbox,
-				      unsigned int count, void *context);
-	/* RECENT */
-	void (*recent_count_changed)(struct mailbox *mailbox,
-				     unsigned int count, void *context);
-	/* FLAGS, PERMANENTFLAGS */
-	void (*new_keywords)(struct mailbox *mailbox,
-			     const char *keywords[],
-			     unsigned int keywords_count, void *context);
-
-};
+typedef void mailbox_notify_callback_t(struct mailbox *box, void *context);
 
 extern int full_filesystem_access;
 
@@ -271,12 +264,17 @@
 		       struct mailbox_status *status);
 
 /* Synchronize the mailbox. */
-int mailbox_sync(struct mailbox *box, enum mailbox_sync_flags flags);
+struct mailbox_sync_context *
+mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);
+int mailbox_sync_next(struct mailbox_sync_context *ctx,
+		      struct mailbox_sync_rec *sync_rec_r);
+int mailbox_sync_deinit(struct mailbox_sync_context *ctx,
+			struct mailbox_status *status_r);
 
-/* Synchronize mailbox in background. It's done until this function is
-   called with flags = MAILBOX_SYNC_AUTO_STOP. */
-void mailbox_auto_sync(struct mailbox *box, enum mailbox_sync_flags flags,
-		       unsigned int min_newmail_notify_interval);
+/* Call given callback function when something changes in the mailbox.
+   It's done until this function is called with callback = NULL. */
+void mailbox_notify_changes(struct mailbox *box, unsigned int min_interval,
+			    mailbox_notify_callback_t *callback, void *context);
 
 struct mailbox_transaction_context *
 mailbox_transaction_begin(struct mailbox *box, int hide);
--- a/src/lib-storage/proxy-mailbox.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/lib-storage/proxy-mailbox.c	Mon Jul 12 14:35:50 2004 +0300
@@ -32,19 +32,20 @@
 	return p->box->get_status(p->box, items, status);
 }
 
-static int _sync(struct mailbox *box, enum mailbox_sync_flags flags)
+static struct mailbox_sync_context *
+_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
 {
 	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
 
-	return p->box->sync(p->box, flags);
+	return p->box->sync_init(p->box, flags);
 }
 
-static void _auto_sync(struct mailbox *box, enum mailbox_sync_flags flags,
-		       unsigned int min_newmail_notify_interval)
+static void _notify_changes(struct mailbox *box, unsigned int min_interval,
+			    mailbox_notify_callback_t *callback, void *context)
 {
 	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
 
-	p->box->auto_sync(p->box, flags, min_newmail_notify_interval);
+	return p->box->notify_changes(box, min_interval, callback, context);
 }
 
 static struct mail *_fetch(struct mailbox_transaction_context *t, uint32_t seq,
@@ -150,8 +151,10 @@
 	pb->allow_new_keywords = _allow_new_keywords;
 	pb->close = _close;
 	pb->get_status = _get_status;
-	pb->sync = _sync;
-	pb->auto_sync = _auto_sync;
+	pb->sync_init = _sync_init;
+	pb->sync_next = box->sync_next;
+	pb->sync_deinit = box->sync_deinit;
+	pb->notify_changes = _notify_changes;
 	pb->fetch = _fetch;
 	pb->get_uids = _get_uids;
 
--- a/src/pop3/client.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/pop3/client.c	Mon Jul 12 14:35:50 2004 +0300
@@ -38,6 +38,18 @@
 	o_stream_close(client->output);
 }
 
+static int sync_mailbox(struct mailbox *box)
+{
+	struct mailbox_sync_context *ctx;
+        struct mailbox_sync_rec sync_rec;
+	struct mailbox_status status;
+
+	ctx = mailbox_sync_init(box, 0);
+	while (mailbox_sync_next(ctx, &sync_rec) > 0)
+		;
+	return mailbox_sync_deinit(ctx, &status);
+}
+
 static int init_mailbox(struct client *client)
 {
 	struct mail_search_arg search_arg;
@@ -51,6 +63,10 @@
 	search_arg.type = SEARCH_ALL;
 
 	for (i = 0; i < 2; i++) {
+		if (sync_mailbox(client->mailbox) < 0) {
+			client_send_storage_error(client);
+			return FALSE;
+		}
 		if (mailbox_get_status(client->mailbox, STATUS_MESSAGES,
 				       &status) < 0) {
 			client_send_storage_error(client);
@@ -104,10 +120,6 @@
 
 		/* well, sync and try again */
 		mailbox_transaction_rollback(t);
-		if (mailbox_sync(client->mailbox, 0) < 0) {
-			client_send_storage_error(client);
-			return FALSE;
-		}
 	}
 
 	client_send_line(client, "-ERR [IN-USE] Couldn't sync mailbox.");
--- a/src/pop3/mail-storage-callbacks.c	Mon Jul 12 14:31:34 2004 +0300
+++ b/src/pop3/mail-storage-callbacks.c	Mon Jul 12 14:35:50 2004 +0300
@@ -21,71 +21,8 @@
 {
 }
 
-static void expunge(struct mailbox *mailbox __attr_unused__,
-		    unsigned int seq, void *context)
-{
-	struct client *client = context;
-	unsigned char *mask = client->deleted_bitmask;
-	unsigned int max, i, j;
-
-	/* external deletes - we have to fix our internal deleted array.
-	   this should happen only when we're doing the expunging at quit. */
-	seq--;
-	client->messages_count--;
-
-	if (!client->deleted)
-		return;
-
-	max = client->messages_count / CHAR_BIT;
-	i = seq / CHAR_BIT; j = seq % CHAR_BIT;
-	mask[i] = (mask[i] & ((1 << j) - 1)) |
-		((mask[i] >> (j+1)) << j) |
-		(i == max ? 0 : ((mask[i+1] & 1) << (CHAR_BIT-1)));
-
-	if (i != max) {
-		for (i++; i < max-1; i++) {
-			mask[i] = (mask[i] >> 1) |
-				((mask[i+1] & 1) << (CHAR_BIT-1));
-		}
-
-		mask[i] >>= 1;
-	}
-}
-
-static void update_flags(struct mailbox *mailbox __attr_unused__,
-			 unsigned int seq __attr_unused__,
-			 const struct mail_full_flags *flags __attr_unused__,
-			 void *context __attr_unused__)
-{
-}
-
-static void message_count_changed(struct mailbox *mailbox __attr_unused__,
-				  unsigned int count __attr_unused__,
-				  void *context __attr_unused__)
-{
-}
-
-static void recent_count_changed(struct mailbox *mailbox __attr_unused__,
-				 unsigned int count __attr_unused__,
-				 void *context __attr_unused__)
-{
-}
-
-
-static void new_keywords(struct mailbox *mailbox __attr_unused__,
-			 const char *keywords[] __attr_unused__,
-			 unsigned int keywords_count __attr_unused__,
-			 void *context __attr_unused__)
-{
-}
-
 struct mail_storage_callbacks mail_storage_callbacks = {
 	alert_no_diskspace,
 	notify_ok,
-	notify_no,
-	expunge,
-	update_flags,
-	message_count_changed,
-	recent_count_changed,
-	new_keywords
+	notify_no
 };