changeset 8910:fef8259e7277 HEAD

dbox: Removed code that is no longer necessary with the redesign. - Maildir code now uses dovecot-uidlist directly instead of dbox.index. - Flags and keywords are no longer written to metadata. - Removed metadata modifying code entirely. - dbox.index is no longer read or written. The code will be removed soon.
author Timo Sirainen <tss@iki.fi>
date Mon, 16 Feb 2009 20:30:15 -0500
parents b39e85979c6a
children 0b626cf2dd10
files src/lib-storage/index/dbox/dbox-file-maildir.c src/lib-storage/index/dbox/dbox-file.c src/lib-storage/index/dbox/dbox-file.h src/lib-storage/index/dbox/dbox-index.c src/lib-storage/index/dbox/dbox-index.h src/lib-storage/index/dbox/dbox-save.c src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/dbox/dbox-storage.h src/lib-storage/index/dbox/dbox-sync-file.c src/lib-storage/index/dbox/dbox-sync-rebuild.c src/lib-storage/index/dbox/dbox-sync.c src/lib-storage/index/dbox/dbox-sync.h src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/maildir/maildir-uidlist.h
diffstat 14 files changed, 294 insertions(+), 983 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/dbox/dbox-file-maildir.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-file-maildir.c	Mon Feb 16 20:30:15 2009 -0500
@@ -3,62 +3,24 @@
 #include "lib.h"
 #include "array.h"
 #include "str.h"
+#include "maildir/maildir-storage.h"
+#include "maildir/maildir-uidlist.h"
+#include "maildir/maildir-filename.h"
 #include "dbox-storage.h"
-#include "../maildir/maildir-storage.h"
-#include "../maildir/maildir-filename.h"
-#include "dbox-index.h"
 #include "dbox-file.h"
 #include "dbox-file-maildir.h"
 
 #include <stdlib.h>
 
 static const char *
-dbox_file_maildir_get_flags(struct dbox_file *file, enum dbox_metadata_key key)
+dbox_maildir_file_get_ext(struct dbox_file *file,
+			  enum maildir_uidlist_rec_ext_key key)
 {
-	ARRAY_TYPE(keyword_indexes) keyword_indexes;
-	struct mail_keywords *keywords;
-	enum mail_flags flags;
-	string_t *str;
-
-	if (file->mbox->maildir_sync_keywords == NULL)
-		return NULL;
+	uint32_t uid;
 
-	t_array_init(&keyword_indexes, 32);
-	maildir_filename_get_flags(file->mbox->maildir_sync_keywords,
-				   file->fname, &flags, &keyword_indexes);
-	str = t_str_new(64);
-	if (key == DBOX_METADATA_FLAGS)
-		dbox_mail_metadata_flags_append(str, flags);
-	else {
-		keywords = mail_index_keywords_create_from_indexes(
-			file->mbox->ibox.index, &keyword_indexes);
-		dbox_mail_metadata_keywords_append(file->mbox, str, keywords);
-		mail_index_keywords_free(&keywords);
-	}
-	return str_c(str);
-}
-
-static const char *
-dbox_file_maildir_get_old_metadata(struct dbox_file *file, char key)
-{
-	struct dbox_index_record *rec;
-	const char *p, *end;
-
-	rec = dbox_index_record_lookup(file->mbox->dbox_index, file->file_id);
-	if (rec == NULL)
-		return NULL;
-
-	for (p = strchr(rec->data, ' '); *p != '\0'; p++) {
-		if (*p == ' ') {
-			if (p[1] == key) {
-				end = strchr(p+2, ' ');
-				return t_strdup_until(p+2, end);
-			}
-			if (p[1] == ':')
-				break;
-		}
-	}
-	return NULL;
+	uid = file->file_id & ~DBOX_FILE_ID_FLAG_UID;
+	return maildir_uidlist_lookup_ext(file->mbox->maildir_uidlist,
+					  uid, key);
 }
 
 const char *dbox_file_maildir_metadata_get(struct dbox_file *file,
@@ -69,10 +31,6 @@
 	const char *p, *value = NULL;
 
 	switch (key) {
-	case DBOX_METADATA_FLAGS:
-	case DBOX_METADATA_KEYWORDS:
-		value = dbox_file_maildir_get_flags(file, key);
-		break;
 	case DBOX_METADATA_GUID:
 		p = strchr(file->fname, MAILDIR_INFO_SEP);
 		value = p == NULL ? file->fname :
@@ -101,7 +59,8 @@
 		if (!maildir_filename_get_size(file->fname,
 					       MAILDIR_EXTRA_VIRTUAL_SIZE,
 					       &size)) {
-			value = dbox_file_maildir_get_old_metadata(file, 'W');
+			value = dbox_maildir_file_get_ext(file,
+					MAILDIR_UIDLIST_REC_EXT_VSIZE);
 			if (value == NULL)
 				break;
 			size = strtoull(value, NULL, 10);
@@ -109,7 +68,8 @@
 		value = t_strdup_printf("%llx", (unsigned long long)size);
 		break;
 	case DBOX_METADATA_POP3_UIDL:
-		value = dbox_file_maildir_get_old_metadata(file, 'P');
+		value = dbox_maildir_file_get_ext(file,
+					MAILDIR_UIDLIST_REC_EXT_POP3_UIDL);
 		if (value != NULL && *value == '\0') {
 			/* special case: use base filename */
 			p = strchr(file->fname, MAILDIR_INFO_SEP);
@@ -119,12 +79,12 @@
 				value = t_strdup_until(file->fname, p);
 		}
 		break;
-	case DBOX_METADATA_EXPUNGED:
+	case DBOX_METADATA_OLD_EXPUNGED:
+	case DBOX_METADATA_OLD_FLAGS:
+	case DBOX_METADATA_OLD_KEYWORDS:
 	case DBOX_METADATA_EXT_REF:
 	case DBOX_METADATA_SPACE:
 		break;
 	}
-	if (value != NULL)
-		dbox_file_metadata_set(file, key, value);
 	return value;
 }
--- a/src/lib-storage/index/dbox/dbox-file.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-file.c	Mon Feb 16 20:30:15 2009 -0500
@@ -11,8 +11,8 @@
 #include "fdatasync-path.h"
 #include "write-full.h"
 #include "str.h"
+#include "maildir/maildir-uidlist.h"
 #include "dbox-storage.h"
-#include "dbox-index.h"
 #include "dbox-file.h"
 #include "dbox-file-maildir.h"
 
@@ -126,26 +126,33 @@
 	}
 }
 
+static bool
+dbox_maildir_uid_get_fname(struct dbox_mailbox *mbox, uint32_t uid,
+			   const char **fname_r)
+{
+	enum maildir_uidlist_rec_flag flags;
+
+	*fname_r = maildir_uidlist_lookup(mbox->maildir_uidlist, uid, &flags);
+	return *fname_r != NULL;
+}
+
 static char *
 dbox_file_id_get_fname(struct dbox_mailbox *mbox, unsigned int file_id,
 		       bool *maildir_file_r)
 {
-	struct dbox_index_record *rec;
-	const char *p;
+	const char *fname;
+	uint32_t uid;
 
 	*maildir_file_r = FALSE;
 	if ((file_id & DBOX_FILE_ID_FLAG_UID) != 0) {
-		file_id &= ~DBOX_FILE_ID_FLAG_UID;
-		return i_strdup_printf(DBOX_MAIL_FILE_UID_FORMAT, file_id);
-	}
-
-	rec = dbox_index_record_lookup(mbox->dbox_index, file_id);
-	if (rec != NULL && rec->status == DBOX_INDEX_FILE_STATUS_MAILDIR) {
-		/* data contains <uid> [<fields>] :<filename> */
-		*maildir_file_r = TRUE;
-		p = strstr(rec->data, " :");
-		i_assert(p != NULL);
-		return i_strdup_printf("%s", p + 2);
+		uid = file_id & ~DBOX_FILE_ID_FLAG_UID;
+		if (uid <= mbox->highest_maildir_uid &&
+		    dbox_maildir_uid_get_fname(mbox, uid, &fname)) {
+			*maildir_file_r = TRUE;
+			return i_strdup(fname);
+		} else {
+			return i_strdup_printf(DBOX_MAIL_FILE_UID_FORMAT, uid);
+		}
 	}
 
 	return i_strdup_printf(DBOX_MAIL_FILE_MULTI_FORMAT, file_id);
@@ -192,17 +199,6 @@
 	return file;
 }
 
-struct dbox_file *
-dbox_file_init_new_maildir(struct dbox_mailbox *mbox, const char *fname)
-{
-	struct dbox_file *file;
-
-	file = dbox_file_init(mbox, 0);
-	file->maildir_file = TRUE;
-	file->fname = i_strdup(fname);
-	return file;
-}
-
 int dbox_file_assign_id(struct dbox_file *file, unsigned int file_id)
 {
 	struct dbox_mailbox *mbox = file->mbox;
@@ -551,22 +547,27 @@
 dbox_file_get_maildir_data(struct dbox_file *file, uint32_t *uid_r,
 			   uoff_t *physical_size_r)
 {
-	struct dbox_index_record *rec;
 	struct stat st;
 
+#if 0 //FIXME
+	uint32_t uid;
+
+	if ((file->file_id & DBOX_FILE_ID_FLAG_UID) == 0) {
+		i_assert(file->file_id == 0);
+		if (maildir_uidlist_get_uid(file->mbox->maildir_uidlist,
+					    file->fname, &uid))
+			file->file_id = uid | DBOX_FILE_ID_FLAG_UID;
+	}
+#else
+	i_assert((file->file_id & DBOX_FILE_ID_FLAG_UID) != 0);
+#endif
+
 	if (fstat(file->fd, &st) < 0) {
 		dbox_file_set_syscall_error(file, "fstat");
 		return -1;
 	}
 
-	rec = dbox_index_record_lookup(file->mbox->dbox_index, file->file_id);
-	if (rec == NULL) {
-		/* should happen only when we're rebuilding the index */
-		*uid_r = 0;
-	} else {
-		i_assert(rec->status == DBOX_INDEX_FILE_STATUS_MAILDIR);
-		*uid_r = strtoul(rec->data, NULL, 10);
-	}
+	*uid_r = file->file_id & ~DBOX_FILE_ID_FLAG_UID;
 	*physical_size_r = st.st_size;
 	return 1;
 }
@@ -854,11 +855,9 @@
 
 	*expunged_r = FALSE;
 
-	if (file->metadata_pool != NULL) {
-		if (array_is_created(&file->metadata_changes))
-			array_free(&file->metadata_changes);
+	if (file->metadata_pool != NULL)
 		p_clear(file->metadata_pool);
-	} else {
+	else {
 		file->metadata_pool =
 			pool_alloconly_create("dbox metadata", 1024);
 	}
@@ -894,8 +893,6 @@
 
 		if (*line == DBOX_METADATA_SPACE || *line == '\0') {
 			/* end of metadata */
-			file->metadata_space_pos =
-				prev_offset - metadata_data_offset;
 			*expunged_r = FALSE;
 			break;
 		}
@@ -903,9 +900,6 @@
 		array_append(&file->metadata, &line, 1);
 	}
 	file->metadata_read_offset = metadata_offset;
-	file->metadata_len = file->input->v_offset - metadata_data_offset;
-	if (*expunged_r)
-		file->metadata_space_pos = file->metadata_len;
 	return 1;
 }
 
@@ -943,206 +937,11 @@
 	return NULL;
 }
 
-void dbox_file_metadata_set(struct dbox_file *file, enum dbox_metadata_key key,
-			    const char *value)
-{
-	const char **changes, *data;
-	unsigned int i, count;
-
-	data = file->maildir_file ? NULL : dbox_file_metadata_get(file, key);
-	if (data != NULL && strcmp(data, value) == 0) {
-		/* value didn't change */
-		return;
-	}
-
-	data = p_strdup_printf(file->metadata_pool, "%c%s", (char)key, value);
-
-	if (!array_is_created(&file->metadata_changes))
-		p_array_init(&file->metadata_changes, file->metadata_pool, 16);
-	else {
-		/* see if we have already changed this metadata */
-		changes = array_get_modifiable(&file->metadata_changes, &count);
-		for (i = 0; i < count; i++) {
-			if (*changes[i] == (char)key) {
-				changes[i] = data;
-				return;
-			}
-		}
-	}
-
-	array_append(&file->metadata_changes, &data, 1);
-}
-
-static int dbox_file_metadata_is_at_eof(struct dbox_file *file)
-{
-	uoff_t size;
-	uint32_t uid;
-	uoff_t offset;
-	int ret;
-
-	if ((file->file_id & DBOX_FILE_ID_FLAG_UID) != 0)
-		return 1;
-
-	offset = file->metadata_read_offset;
-	ret = dbox_file_seek_next_at_metadata(file, &offset, &uid, &size);
-	return ret <= 0 ? ret : uid == 0;
-}
-
-static int dbox_file_write_empty_block(struct dbox_file *file, uoff_t offset,
-				       unsigned int len)
-{
-	char space[256];
-
-	i_assert(len > 0);
-
-	len--;
-	memset(space, DBOX_METADATA_SPACE, I_MIN(sizeof(space), len));
-	while (len >= sizeof(space)) {
-		if (pwrite_full(file->fd, space, sizeof(space), offset) < 0) {
-			dbox_file_set_syscall_error(file, "pwrite");
-			return -1;
-		}
-	}
-	/* @UNSAFE: last block ends with LF */
-	space[len++] = '\n';
-	if (pwrite_full(file->fd, space, len, offset) < 0) {
-		dbox_file_set_syscall_error(file, "pwrite");
-		return -1;
-	}
-	file->metadata_len += len;
-	return 1;
-}
-
-static int dbox_file_grow_metadata(struct dbox_file *file, unsigned int len)
-{
-	enum dbox_index_file_lock_status lock_status;
-	uoff_t offset;
-	int ret;
-
-	ret = dbox_index_try_lock_file(file->mbox->dbox_index, file->file_id,
-				       &lock_status);
-	if (ret <= 0 || (ret = dbox_file_metadata_is_at_eof(file)) <= 0)
-		return ret;
-
-	offset = file->metadata_read_offset +
-		sizeof(struct dbox_metadata_header) + file->metadata_len;
-	i_stream_seek(file->input, offset);
-	(void)i_stream_read(file->input);
-	if (!i_stream_have_bytes_left(file->input)) {
-		len = len - file->metadata_len + DBOX_EXTRA_SPACE;
-		ret = dbox_file_write_empty_block(file, offset, len);
-	} else {
-		i_error("%s: Metadata changed unexpectedly",
-			dbox_file_get_path(file));
-		ret = -1;
-	}
-
-	dbox_index_unlock_file(file->mbox->dbox_index, file->file_id);
-	return ret;
-}
-
-static int dbox_file_metadata_write_real(struct dbox_file *file)
-{
-	const char *const *metadata, *const *changes;
-	unsigned int i, j, count, changes_count, space_needed, skip_pos;
-	char space[DBOX_EXTRA_SPACE];
-	string_t *str;
-	uoff_t offset;
-	int ret;
-
-	if (!array_is_created(&file->metadata_changes)) {
-		/* nothing to write */
-		return 1;
-	}
-	if (file->maildir_file)
-		return 0;
-
-	offset = file->metadata_read_offset +
-		sizeof(struct dbox_metadata_header);
-	metadata = array_get(&file->metadata, &count);
-	changes = array_get(&file->metadata_changes, &changes_count);
-
-	/* skip as many metadata fields from beginning as we can */
-	for (i = skip_pos = 0; i < count; i++) {
-		for (j = 0; j < changes_count; j++) {
-			if (*changes[j] == *metadata[i])
-				break;
-		}
-		if (j != changes_count)
-			break;
-		skip_pos += strlen(metadata[i]) + 1;
-	}
-
-	str = t_str_new(512);
-	/* overwrite existing metadata fields */
-	for (; i < count; i++) {
-		for (j = 0; j < changes_count; j++) {
-			if (*changes[j] == *metadata[i])
-				break;
-		}
-		if (j != changes_count) {
-			str_append(str, changes[j]);
-			str_append_c(str, '\n');
-		} else {
-			str_append(str, metadata[i]);
-			str_append_c(str, '\n');
-		}
-	}
-	/* add new metadata */
-	for (j = 0; j < changes_count; j++) {
-		for (i = 0; i < count; i++) {
-			if (*changes[j] == *metadata[i])
-				break;
-		}
-		if (i == count) {
-			str_append(str, changes[j]);
-			str_append_c(str, '\n');
-		}
-	}
-	if (skip_pos + str_len(str) >= file->metadata_len) {
-		if ((ret = dbox_file_grow_metadata(file, skip_pos +
-						   str_len(str))) <= 0)
-			return ret;
-	}
-
-	memset(space, DBOX_METADATA_SPACE, sizeof(space));
-	while (skip_pos + str_len(str) < file->metadata_space_pos) {
-		space_needed = file->metadata_space_pos -
-			(skip_pos + str_len(str));
-		str_append_n(str, space, I_MIN(sizeof(space), space_needed));
-	}
-	i_assert(skip_pos + str_len(str) <= file->metadata_len);
-
-	if (file->metadata_space_pos < skip_pos + str_len(str)) {
-		/* metadata was grown, update space position */
-		file->metadata_space_pos = skip_pos + str_len(str);
-	}
-
-	ret = pwrite_full(file->fd, str_data(str), str_len(str),
-			  offset + skip_pos);
-	if (ret < 0) {
-		dbox_file_set_syscall_error(file, "pwrite");
-		return -1;
-	}
-	return 1;
-}
-
-int dbox_file_metadata_write(struct dbox_file *file)
-{
-	int ret;
-
-	T_BEGIN {
-		ret = dbox_file_metadata_write_real(file);
-	} T_END;
-	return ret;
-}
-
 int dbox_file_metadata_write_to(struct dbox_file *file, struct ostream *output)
 {
 	struct dbox_metadata_header metadata_hdr;
-	char space[DBOX_EXTRA_SPACE];
-	const char *const *metadata, *const *changes;
-	unsigned int i, j, count, changes_count;
+	const char *const *metadata;
+	unsigned int i, count;
 
 	memset(&metadata_hdr, 0, sizeof(metadata_hdr));
 	memcpy(metadata_hdr.magic_post, DBOX_MAGIC_POST,
@@ -1151,38 +950,13 @@
 		return -1;
 
 	metadata = array_get(&file->metadata, &count);
-	if (!array_is_created(&file->metadata_changes)) {
-		for (i = 0; i < count; i++) {
-			if (o_stream_send_str(output, metadata[i]) < 0 ||
-			    o_stream_send(output, "\n", 1) < 0)
-				return -1;
-		}
-	} else {
-		changes = array_get(&file->metadata_changes, &changes_count);
-		/* write unmodified metadata */
-		for (i = 0; i < count; i++) {
-			for (j = 0; j < changes_count; j++) {
-				if (*changes[j] == *metadata[i])
-					break;
-			}
-			if (j == changes_count) {
-				if (o_stream_send_str(output, metadata[i]) < 0)
-					return -1;
-				if (o_stream_send(output, "\n", 1) < 0)
-					return -1;
-			}
-		}
-		/* write modified metadata */
-		for (i = 0; i < changes_count; i++) {
-			if (o_stream_send_str(output, changes[i]) < 0 ||
-			    o_stream_send(output, "\n", 1) < 0)
-				return -1;
-		}
+	for (i = 0; i < count; i++) {
+		if (o_stream_send_str(output, metadata[i]) < 0 ||
+		    o_stream_send(output, "\n", 1) < 0)
+			return -1;
 	}
 
-	memset(space, ' ', sizeof(space));
-	if (o_stream_send(output, space, sizeof(space)) < 0 ||
-	    o_stream_send(output, "\n", 1) < 0)
+	if (o_stream_send(output, "\n", 1) < 0)
 		return -1;
 	return 0;
 }
@@ -1204,6 +978,8 @@
 		mail_index_lookup_uid(view, seq, &uid);
 		if ((uid & DBOX_FILE_ID_FLAG_UID) != 0) {
 			/* something's broken, we can't handle this high UIDs */
+			mail_storage_set_critical(mbox->ibox.box.storage,
+						  "found too high uid=%u", uid);
 			return FALSE;
 		}
 		*file_id_r = DBOX_FILE_ID_FLAG_UID | uid;
@@ -1322,41 +1098,6 @@
 	return 0;
 }
 
-void dbox_mail_metadata_flags_append(string_t *str, enum mail_flags flags)
-{
-	unsigned int i;
-
-	for (i = 0; i < DBOX_METADATA_FLAGS_COUNT; i++) {
-		if ((flags & dbox_mail_flags_map[i]) != 0)
-			str_append_c(str, dbox_mail_flag_chars[i]);
-		else
-			str_append_c(str, '0');
-	}
-}
-
-void dbox_mail_metadata_keywords_append(struct dbox_mailbox *mbox,
-					string_t *str,
-					const struct mail_keywords *keywords)
-{
-	const ARRAY_TYPE(keywords) *keyword_names_list;
-	const char *const *keyword_names;
-	unsigned int i, keyword_names_count;
-
-	if (keywords == NULL || keywords->count == 0)
-		return;
-
-	keyword_names_list = mail_index_get_keywords(mbox->ibox.index);
-	keyword_names = array_get(keyword_names_list, &keyword_names_count);
-
-	for (i = 0; i < keywords->count; i++) {
-		i_assert(keywords->idx[i] < keyword_names_count);
-
-		str_append(str, keyword_names[keywords->idx[i]]);
-		str_append_c(str, ' ');
-	}
-	str_truncate(str, str_len(str)-1);
-}
-
 void dbox_msg_header_fill(struct dbox_message_header *dbox_msg_hdr,
 			  uint32_t uid, uoff_t message_size)
 {
--- a/src/lib-storage/index/dbox/dbox-file.h	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-file.h	Mon Feb 16 20:30:15 2009 -0500
@@ -20,7 +20,6 @@
 #define DBOX_MAGIC_PRE "\001\002"
 #define DBOX_MAGIC_POST "\n\001\003\n"
 
-#define DBOX_EXTRA_SPACE 64
 /* If file_id has this flag set, the file is a single file with file_id=UID. */
 #define DBOX_FILE_ID_FLAG_UID 0x80000000
 
@@ -47,16 +46,14 @@
 };
 
 enum dbox_metadata_key {
-	/* Message is marked as expunged. '0' = no, '1' = yes */
-	DBOX_METADATA_EXPUNGED		= 'E',
-	/* Message flags in dbox_metadata_flags order. '0' = not set, anything
-	   else = set. Unknown flags should be preserved. */
-	DBOX_METADATA_FLAGS		= 'F',
+	/* metadata used by old Dovecot versions */
+	DBOX_METADATA_OLD_EXPUNGED	= 'E',
+	DBOX_METADATA_OLD_FLAGS		= 'F',
+	DBOX_METADATA_OLD_KEYWORDS	= 'K',
+
 	/* Globally unique identifier for the message. Preserved when
 	   copying. */
 	DBOX_METADATA_GUID		= 'G',
-	/* Space separated list of keywords */
-	DBOX_METADATA_KEYWORDS		= 'K',
 	/* POP3 UIDL overriding the default format */
 	DBOX_METADATA_POP3_UIDL		= 'P',
 	/* Received UNIX timestamp in hex */
@@ -107,7 +104,7 @@
 	unsigned int append_offset_header_pos;
 
 	unsigned int append_count;
-	uint32_t last_append_uid, maildir_append_seq;
+	uint32_t last_append_uid;
 
 	uoff_t append_offset;
 	time_t create_time;
@@ -127,11 +124,7 @@
 	/* Metadata for the currently seeked metadata block. */
 	pool_t metadata_pool;
 	ARRAY_DEFINE(metadata, const char *);
-	ARRAY_DEFINE(metadata_changes, const char *);
 	uoff_t metadata_read_offset;
-	unsigned int metadata_space_pos;
-	/* Includes the trailing LF that shouldn't be used */
-	unsigned int metadata_len;
 
 	unsigned int alt_path:1;
 	unsigned int maildir_file:1;
@@ -144,8 +137,6 @@
 
 struct dbox_file *
 dbox_file_init(struct dbox_mailbox *mbox, unsigned int file_id);
-struct dbox_file *
-dbox_file_init_new_maildir(struct dbox_mailbox *mbox, const char *fname);
 void dbox_file_unref(struct dbox_file **file);
 
 /* Free all currently opened files. */
@@ -209,13 +200,6 @@
 /* Return wanted metadata value, or NULL if not found. */
 const char *dbox_file_metadata_get(struct dbox_file *file,
 				   enum dbox_metadata_key key);
-/* Add key=value metadata update (not written yet, not visible to _get()).
-   The changes are reset by dbox_file_metadata_seek() call. */
-void dbox_file_metadata_set(struct dbox_file *file, enum dbox_metadata_key key,
-			    const char *value);
-/* Write all metadata updates to disk. Returns 1 if ok, 0 if metadata doesn't
-   fit to its reserved space and message isn't last in file, -1 if I/O error. */
-int dbox_file_metadata_write(struct dbox_file *file);
 /* Write all metadata to output stream. Returns 0 if ok, -1 if I/O error. */
 int dbox_file_metadata_write_to(struct dbox_file *file, struct ostream *output);
 
@@ -226,13 +210,6 @@
 /* Move the file to alt path or back. */
 int dbox_file_move(struct dbox_file *file, bool alt_path);
 
-/* Append flags as metadata value to given string */
-void dbox_mail_metadata_flags_append(string_t *str, enum mail_flags flags);
-/* Append keywords as metadata value to given string */
-void dbox_mail_metadata_keywords_append(struct dbox_mailbox *mbox,
-					string_t *str,
-					const struct mail_keywords *keywords);
-
 /* Fill dbox_message_header with given uid/size. */
 void dbox_msg_header_fill(struct dbox_message_header *dbox_msg_hdr,
 			  uint32_t uid, uoff_t message_size);
--- a/src/lib-storage/index/dbox/dbox-index.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-index.c	Mon Feb 16 20:30:15 2009 -0500
@@ -322,17 +322,6 @@
 	return 0;
 }
 
-int dbox_index_get_uid_validity(struct dbox_index *index,
-				uint32_t *uid_validity_r)
-{
-	if (index->fd == -1) {
-		if (dbox_index_refresh(index) < 0)
-			return -1;
-	}
-	*uid_validity_r = index->uid_validity;
-	return 0;
-}
-
 static int dbox_index_record_cmp(const void *key, const void *data)
 {
 	const unsigned int *file_id = key;
@@ -464,28 +453,6 @@
 	rec->locked = FALSE;
 }
 
-int dbox_index_try_lock_recreate(struct dbox_index *index)
-{
-	int i, ret;
-
-	if (index->fd == -1) {
-		if (dbox_index_refresh(index) < 0)
-			return 1;
-	}
-
-	for (i = 0; i < DBOX_INDEX_LOCK_RETRY_COUNT; i++) {
-		/* lock the whole file */
-		ret = dbox_index_lock_range(index, F_SETLK, F_WRLCK, 0, 0);
-		if (ret <= 0)
-			return ret;
-		if ((ret = dbox_index_refresh(index)) <= 0)
-			return ret < 0 ? -1 : 1;
-	}
-
-	i_warning("dbox index keeps getting recreated: %s", index->path);
-	return 0;
-}
-
 static int dbox_index_lock_header(struct dbox_index *index)
 {
 	int i, ret;
@@ -761,38 +728,10 @@
 	return 0;
 }
 
-void dbox_index_append_file(struct dbox_index_append_context *ctx,
-			    struct dbox_file *file)
-{
-	file->refcount++;
-	array_append(&ctx->files, &file, 1);
-}
-
 static const char *dbox_file_maildir_get_index_data(struct dbox_file *file)
 {
-	const char *pop3_uidl = NULL, *const *changes;
-	unsigned int i, count;
-
-	if (array_is_created(&file->metadata_changes))
-		changes = array_get(&file->metadata_changes, &count);
-	else {
-		changes = NULL;
-		count = 0;
-	}
-	for (i = 0; i < count; i++) {
-		if (*changes[i] == DBOX_METADATA_POP3_UIDL) {
-			pop3_uidl = changes[i] + 1;
-			break;
-		}
-	}
-
-	if (pop3_uidl == NULL) {
-		return t_strdup_printf("%u :%s", file->last_append_uid,
-				       file->fname);
-	} else {
-		return t_strdup_printf("%u P%s :%s", file->last_append_uid,
-				       pop3_uidl, file->fname);
-	}
+	return t_strdup_printf("%u :%s", file->last_append_uid,
+			       file->fname);
 }
 
 static int dbox_index_append_commit_new(struct dbox_index_append_context *ctx,
--- a/src/lib-storage/index/dbox/dbox-index.h	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-index.h	Mon Feb 16 20:30:15 2009 -0500
@@ -92,10 +92,6 @@
 struct dbox_index *dbox_index_init(struct dbox_mailbox *mbox);
 void dbox_index_deinit(struct dbox_index **index);
 
-/* Get the current UIDVALIDITY. Returns 0 if ok, -1 if I/O error. */
-int dbox_index_get_uid_validity(struct dbox_index *index,
-				uint32_t *uid_validity_r);
-
 struct dbox_index_record *
 dbox_index_record_lookup(struct dbox_index *index, unsigned int file_id);
 
@@ -106,10 +102,6 @@
 			     enum dbox_index_file_lock_status *lock_status_r);
 void dbox_index_unlock_file(struct dbox_index *index, unsigned int file_id);
 
-/* Try to lock index file for recreating. Returns 1 if ok, 0 if file already
-   contains locks, -1 if error. */
-int dbox_index_try_lock_recreate(struct dbox_index *index);
-
 struct dbox_index_append_context *
 dbox_index_append_begin(struct dbox_index *index);
 /* Request file for saving a new message with given size. If an existing file
@@ -119,16 +111,10 @@
 			   uoff_t mail_size,
 			   struct dbox_file **file_r,
 			   struct ostream **output_r);
-void dbox_index_append_file(struct dbox_index_append_context *ctx,
-			    struct dbox_file *file);
 /* Assign file_ids to all appended files. */
 int dbox_index_append_assign_file_ids(struct dbox_index_append_context *ctx);
 /* Returns 0 if ok, -1 if error. */
 int dbox_index_append_commit(struct dbox_index_append_context **ctx);
 void dbox_index_append_rollback(struct dbox_index_append_context **ctx);
 
-/* Mark  */
-void dbox_index_mark_expunges(struct dbox_index *index, unsigned int file_id);
-void dbox_index_mark_dirty(struct dbox_index *index, unsigned int file_id);
-
 #endif
--- a/src/lib-storage/index/dbox/dbox-save.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-save.c	Mon Feb 16 20:30:15 2009 -0500
@@ -48,17 +48,6 @@
 	unsigned int finished:1;
 };
 
-static void dbox_save_keywords(struct dbox_save_context *ctx,
-			       struct mail_keywords *keywords)
-{
-	if (ctx->cur_keywords == NULL)
-		ctx->cur_keywords = str_new(default_pool, 128);
-	else
-		str_truncate(ctx->cur_keywords, 0);
-	dbox_mail_metadata_keywords_append(ctx->mbox, ctx->cur_keywords,
-					   keywords);
-}
-
 struct mail_save_context *
 dbox_save_alloc(struct mailbox_transaction_context *_t)
 {
@@ -141,7 +130,6 @@
 
 	if (_ctx->received_date == (time_t)-1)
 		_ctx->received_date = ioloop_time;
-	dbox_save_keywords(ctx, _ctx->keywords);
 	return ctx->failed ? -1 : 0;
 }
 
@@ -177,7 +165,6 @@
 static void dbox_save_write_metadata(struct dbox_save_context *ctx)
 {
 	struct dbox_metadata_header metadata_hdr;
-	char space[DBOX_EXTRA_SPACE];
 	const char *guid;
 	string_t *str;
 	uoff_t vsize;
@@ -201,23 +188,9 @@
 	guid = ctx->ctx.guid != NULL ? ctx->ctx.guid :
 		mail_generate_guid_string();
 	str_printfa(str, "%c%s\n", DBOX_METADATA_GUID, guid);
-
-	/* flags */
-	str_append_c(str, DBOX_METADATA_FLAGS);
-	dbox_mail_metadata_flags_append(str, ctx->ctx.flags);
 	str_append_c(str, '\n');
 
-	/* keywords */
-	if (ctx->cur_keywords != NULL && str_len(ctx->cur_keywords) > 0) {
-		str_append_c(str, DBOX_METADATA_KEYWORDS);
-		str_append_str(str, ctx->cur_keywords);
-		str_append_c(str, '\n');
-	}
-
 	o_stream_send(ctx->cur_output, str_data(str), str_len(str));
-	memset(space, ' ', sizeof(space));
-	o_stream_send(ctx->cur_output, space, sizeof(space));
-	o_stream_send(ctx->cur_output, "\n", 1);
 }
 
 static int dbox_save_mail_write_header(struct dbox_save_mail *mail)
@@ -436,7 +409,7 @@
 
 	i_assert(ctx->finished);
 
-	if (dbox_sync_begin(ctx->mbox, &ctx->sync_ctx, FALSE, TRUE) < 0) {
+	if (dbox_sync_begin(ctx->mbox, TRUE, &ctx->sync_ctx) < 0) {
 		ctx->failed = TRUE;
 		dbox_transaction_save_rollback(ctx);
 		return -1;
--- a/src/lib-storage/index/dbox/dbox-storage.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Mon Feb 16 20:30:15 2009 -0500
@@ -8,6 +8,7 @@
 #include "unlink-old-files.h"
 #include "index-mail.h"
 #include "mail-copy.h"
+#include "maildir/maildir-uidlist.h"
 #include "dbox-sync.h"
 #include "dbox-index.h"
 #include "dbox-file.h"
@@ -214,7 +215,6 @@
 	mbox->path = p_strdup(pool, path);
 	mbox->alt_path = p_strdup(pool, dbox_get_alt_path(storage, path));
 	mbox->storage = storage;
-	mbox->last_interactive_change = ioloop_time;
 
 	value = getenv("DBOX_ROTATE_SIZE");
 	if (value != NULL)
@@ -252,6 +252,7 @@
 	mbox->dbox_index = dbox_index_init(mbox);
 
 	index_storage_mailbox_init(&mbox->ibox, name, flags, FALSE);
+	mbox->maildir_uidlist = maildir_uidlist_init_readonly(&mbox->ibox);
 	return &mbox->ibox.box;
 }
 
@@ -319,18 +320,13 @@
 static int dbox_storage_mailbox_close(struct mailbox *box)
 {
 	struct dbox_mailbox *mbox = (struct dbox_mailbox *)box;
-	int ret = 0;
 
-	if (box->opened) {
-		/* see if we want to flush dirty flags */
-		ret = dbox_sync(mbox, TRUE);
-	}
-
+	maildir_uidlist_deinit(&mbox->maildir_uidlist);
 	dbox_index_deinit(&mbox->dbox_index);
 	dbox_files_free(mbox);
 	array_free(&mbox->open_files);
 
-	return index_storage_mailbox_close(box) < 0 ? -1 : ret;
+	return index_storage_mailbox_close(box);
 }
 
 static int dbox_mailbox_create(struct mail_storage *_storage,
--- a/src/lib-storage/index/dbox/dbox-storage.h	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-storage.h	Mon Feb 16 20:30:15 2009 -0500
@@ -31,7 +31,8 @@
 #define DBOX_INDEX_FLAG_ALT MAIL_INDEX_MAIL_FLAG_BACKEND
 
 struct dbox_index_header {
-	uint32_t last_dirty_flush_stamp;
+	uint32_t unused; /* for backwards compatibility */
+	uint32_t highest_maildir_uid;
 };
 
 struct dbox_storage {
@@ -49,12 +50,11 @@
 	struct index_mailbox ibox;
 	struct dbox_storage *storage;
 
+	struct maildir_uidlist *maildir_uidlist;
+	uint32_t highest_maildir_uid;
+
 	struct dbox_index *dbox_index;
 	uint32_t dbox_ext_id, dbox_hdr_ext_id;
-	/* timestamp when the mailbox was last modified interactively */
-	time_t last_interactive_change;
-	/* set while rebuilding indexes with converted maildir files */
-	struct maildir_keywords_sync_ctx *maildir_sync_keywords;
 
 	uoff_t rotate_size, rotate_min_size;
 	unsigned int rotate_days;
--- a/src/lib-storage/index/dbox/dbox-sync-file.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-sync-file.c	Mon Feb 16 20:30:15 2009 -0500
@@ -13,13 +13,10 @@
 static int dbox_sync_file_unlink(struct dbox_file *file)
 {
 	const char *path;
-	int i;
+	int i = 0;
 
 	path = t_strdup_printf("%s/%s", file->mbox->path, file->fname);
-	for (i = 0;; i++) {
-		if (unlink(path) == 0)
-			break;
-
+	while (unlink(path) < 0) {
 		if (errno != ENOENT) {
 			mail_storage_set_critical(file->mbox->ibox.box.storage,
 				"unlink(%s) failed: %m", path);
@@ -29,58 +26,15 @@
 			/* not found */
 			i_warning("dbox: File unexpectedly lost: %s/%s",
 				  file->mbox->path, file->fname);
-			break;
+			return 0;
 		}
 
 		/* try the alternative path */
 		path = t_strdup_printf("%s/%s", file->mbox->alt_path,
 				       file->fname);
+		i++;
 	}
-	return 0;
-}
-
-static void
-dbox_sync_update_metadata(struct dbox_sync_context *ctx, struct dbox_file *file,
-			  const struct dbox_sync_file_entry *entry,
-			  uint32_t seq)
-{
-	const struct mail_index_record *rec;
-	ARRAY_TYPE(keyword_indexes) keyword_indexes;
-	struct mail_keywords *keywords;
-	string_t *value;
-	const char *old_value;
-
-	value = t_str_new(256);
-
-	/* flags */
-	rec = mail_index_lookup(ctx->sync_view, seq);
-	dbox_mail_metadata_flags_append(value, rec->flags);
-	dbox_file_metadata_set(file, DBOX_METADATA_FLAGS, str_c(value));
-
-	/* keywords */
-	t_array_init(&keyword_indexes, 32);
-	mail_index_lookup_keywords(ctx->sync_view, seq, &keyword_indexes);
-	old_value = dbox_file_metadata_get(file, DBOX_METADATA_KEYWORDS);
-	if (array_count(&keyword_indexes) > 0 ||
-	    (old_value != NULL && *old_value != '\0' &&
-	     array_count(&keyword_indexes) == 0)) {
-		str_truncate(value, 0);
-		keywords = mail_index_keywords_create_from_indexes(
-				ctx->mbox->ibox.index, &keyword_indexes);
-		dbox_mail_metadata_keywords_append(ctx->mbox, value, keywords);
-		mail_index_keywords_free(&keywords);
-
-		dbox_file_metadata_set(file, DBOX_METADATA_KEYWORDS,
-				       str_c(value));
-	}
-
-	/* expunge state */
-	if (entry != NULL &&
-	    array_is_created(&entry->expunges) &&
-	    seq_range_exists(&entry->expunges, seq)) {
-		dbox_file_metadata_set(file, DBOX_METADATA_EXPUNGED, "1");
-		mail_index_expunge(ctx->trans, seq);
-	}
+	return 1;
 }
 
 static int
@@ -152,9 +106,6 @@
 		/* write metadata */
 		(void)dbox_file_metadata_seek_mail_offset(file, offset,
 							  &expunged);
-		T_BEGIN {
-			dbox_sync_update_metadata(ctx, file, entry, seq);
-		} T_END;
 		if ((ret = dbox_file_metadata_write_to(file, output)) < 0)
 			break;
 
@@ -192,6 +143,7 @@
 	return ret;
 }
 
+#if 0
 static int
 dbox_sync_file_split(struct dbox_sync_context *ctx, struct dbox_file *in_file,
 		     uoff_t offset, uint32_t seq)
@@ -236,9 +188,6 @@
 	}
 	append_offset = output->offset;
 	dbox_msg_header_fill(&dbox_msg_hdr, uid, size);
-	T_BEGIN {
-		dbox_sync_update_metadata(ctx, out_file, NULL, seq);
-	} T_END;
 
 	/* set static metadata */
 	for (i = 0; i < N_ELEMENTS(maildir_metadata_keys); i++) {
@@ -288,103 +237,19 @@
 	}
 	return ret < 0 ? -1 : 1;
 }
-
-static int
-dbox_sync_file_changes(struct dbox_sync_context *ctx, struct dbox_file *file,
-		       const struct dbox_sync_file_entry *entry, uint32_t seq)
-{
-	uint32_t file_id;
-	uoff_t offset;
-	bool expunged;
-	int ret;
-
-	if (!dbox_file_lookup(ctx->mbox, ctx->sync_view, seq,
-			      &file_id, &offset))
-		return 0;
-	i_assert(file_id == file->file_id);
-
-	ret = dbox_file_metadata_seek_mail_offset(file, offset, &expunged);
-	if (ret <= 0)
-		return ret;
-	if (expunged) {
-		mail_index_expunge(ctx->trans, seq);
-		return 1;
-	}
-
-	T_BEGIN {
-		dbox_sync_update_metadata(ctx, file, entry, seq);
-	} T_END;
-	ret = dbox_file_metadata_write(file);
-	if (ret <= 0) {
-		return ret < 0 ? -1 :
-			dbox_sync_file_split(ctx, file, offset, seq);
-	}
-
-	mail_index_update_flags(ctx->trans, seq, MODIFY_REMOVE,
-				(enum mail_flags)MAIL_INDEX_MAIL_FLAG_DIRTY);
-	return 1;
-}
-
-static int
-dbox_sync_file_int(struct dbox_sync_context *ctx, struct dbox_file *file,
-		   const struct dbox_sync_file_entry *entry, bool full_expunge)
-{
-	const struct seq_range *seqs;
-	unsigned int i, count;
-	uint32_t seq, first_expunge_seq;
-	int ret;
-
-	if (array_is_created(&entry->expunges) && full_expunge) {
-		seqs = array_idx(&entry->expunges, 0);
-		first_expunge_seq = seqs->seq1;
-	} else {
-		first_expunge_seq = (uint32_t)-1;
-	}
-
-	if (array_is_created(&entry->changes)) {
-		seqs = array_get(&entry->changes, &count);
-	} else {
-		seqs = NULL;
-		count = 0;
-	}
-	for (i = 0; i < count; ) {
-		for (seq = seqs[i].seq1; seq <= seqs[i].seq2; seq++) {
-			if (seq >= first_expunge_seq)
-				return dbox_sync_file_expunge(ctx, file, entry);
-
-			ret = dbox_sync_file_changes(ctx, file, entry, seq);
-			if (ret <= 0)
-				return ret;
-		}
-		i++;
-	}
-	if (first_expunge_seq != (uint32_t)-1)
-		return dbox_sync_file_expunge(ctx, file, entry);
-	return 1;
-}
+#endif
 
 static void
-dbox_sync_file_move_if_needed(struct dbox_sync_context *ctx,
-			      struct dbox_file *file,
+dbox_sync_file_move_if_needed(struct dbox_file *file,
 			      const struct dbox_sync_file_entry *entry)
 {
-	const struct seq_range *seq;
-	const struct mail_index_record *rec;
-	bool new_alt_path;
-
-	if (!array_is_created(&entry->changes))
+	if (!entry->move_to_alt && !entry->move_from_alt)
 		return;
 
-	/* check if we want to move the file to alt path or back.
-	   FIXME: change this check somehow when a file may contain
-	   multiple messages. */
-	seq = array_idx(&entry->changes, 0);
-	rec = mail_index_lookup(ctx->sync_view, seq[0].seq1);
-	new_alt_path = (rec->flags & DBOX_INDEX_FLAG_ALT) != 0;
-	if (new_alt_path != file->alt_path) {
+	if (entry->move_to_alt != file->alt_path) {
 		/* move the file. if it fails, nothing broke so
 		   don't worry about it. */
-		(void)dbox_file_move(file, new_alt_path);
+		(void)dbox_file_move(file, !file->alt_path);
 	}
 }
 
@@ -436,17 +301,17 @@
 	     status == DBOX_INDEX_FILE_STATUS_MAILDIR) &&
 	    array_is_created(&entry->expunges)) {
 		/* fast path to expunging the whole file */
-		if (dbox_sync_file_unlink(file) < 0)
-			ret = -1;
-		else {
+		if ((ret = dbox_sync_file_unlink(file)) == 0) {
+			/* file was lost, delete it */
 			dbox_sync_mark_single_file_expunged(ctx, entry);
 			ret = 1;
 		}
 	} else {
 		ret = dbox_file_open_or_create(file, TRUE, &deleted);
 		if (ret > 0 && !deleted) {
-			dbox_sync_file_move_if_needed(ctx, file, entry);
-			ret = dbox_sync_file_int(ctx, file, entry, locked);
+			dbox_sync_file_move_if_needed(file, entry);
+			if (array_is_created(&entry->expunges) && locked)
+				ret = dbox_sync_file_expunge(ctx, file, entry);
 		}
 	}
 	dbox_file_unref(&file);
--- a/src/lib-storage/index/dbox/dbox-sync-rebuild.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-sync-rebuild.c	Mon Feb 16 20:30:15 2009 -0500
@@ -1,11 +1,12 @@
 /* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "ioloop.h"
 #include "array.h"
 #include "dbox-storage.h"
-#include "../maildir/maildir-uidlist.h"
-#include "../maildir/maildir-keywords.h"
-#include "dbox-index.h"
+#include "maildir/maildir-uidlist.h"
+#include "maildir/maildir-keywords.h"
+#include "maildir/maildir-filename.h"
 #include "dbox-file.h"
 #include "dbox-sync.h"
 
@@ -14,34 +15,34 @@
 
 struct dbox_sync_rebuild_context {
 	struct dbox_mailbox *mbox;
-	struct dbox_index_append_context *append_ctx;
 
 	struct mail_index_view *view;
 	struct mail_index_transaction *trans;
 	uint32_t cache_ext_id;
 	uint32_t cache_reset_id;
 
-	struct maildir_uidlist *maildir_uidlist;
+	struct maildir_uidlist_sync_ctx *maildir_sync_ctx;
 	struct maildir_keywords *mk;
+	struct maildir_keywords_sync_ctx *maildir_sync_keywords;
 
-	ARRAY_DEFINE(maildir_new_files, char *);
-	uint32_t maildir_new_uid;
+	uint32_t highest_uid;
 
 	unsigned int cache_used:1;
 };
 
-static int dbox_sync_set_uidvalidity(struct dbox_sync_rebuild_context *ctx)
+static void dbox_sync_set_uidvalidity(struct dbox_sync_rebuild_context *ctx)
 {
+
 	uint32_t uid_validity;
 
-	if (dbox_index_get_uid_validity(ctx->mbox->dbox_index,
-					&uid_validity) < 0)
-		return -1;
+	/* if uidvalidity is set in the old index, use it */
+	uid_validity = mail_index_get_header(ctx->view)->uid_validity;
+	if (uid_validity == 0)
+		uid_validity = ioloop_time;
 
 	mail_index_update_header(ctx->trans,
 		offsetof(struct mail_index_header, uid_validity),
 		&uid_validity, sizeof(uid_validity), TRUE);
-	return 0;
 }
 
 static void
@@ -103,39 +104,40 @@
 }
 
 static void
+dbox_sync_index_copy_from_maildir(struct dbox_sync_rebuild_context *ctx,
+				  struct dbox_file *file, uint32_t seq)
+{
+	struct dbox_mailbox *mbox = file->mbox;
+	ARRAY_TYPE(keyword_indexes) keyword_indexes;
+	struct mail_keywords *keywords;
+	enum mail_flags flags;
+
+	t_array_init(&keyword_indexes, 32);
+	maildir_filename_get_flags(ctx->maildir_sync_keywords,
+				   file->fname, &flags, &keyword_indexes);
+	mail_index_update_flags(ctx->trans, seq, MODIFY_REPLACE, flags);
+
+	keywords = mail_index_keywords_create_from_indexes(mbox->ibox.index,
+							   &keyword_indexes);
+	mail_index_update_keywords(ctx->trans, seq, MODIFY_REPLACE, keywords);
+	mail_index_keywords_free(&keywords);
+}
+
+static void
 dbox_sync_index_metadata(struct dbox_sync_rebuild_context *ctx,
 			 struct dbox_file *file, uint32_t seq, uint32_t uid)
 {
-	const char *value;
-	struct mail_keywords *keywords;
-	enum mail_flags flags = 0;
 	uint32_t old_seq;
-	unsigned int i;
 
 	if (mail_index_lookup_seq(ctx->view, uid, &old_seq)) {
 		/* the message exists in the old index.
 		   copy the metadata from it. */
 		dbox_sync_index_copy_from_old(ctx, old_seq, seq);
-		return;
+	} else if (file->maildir_file) {
+		/* we're probably doing initial sync after migration from
+		   maildir. preserve the old flags. */
+		dbox_sync_index_copy_from_maildir(ctx, file, seq);
 	}
-
-	value = dbox_file_metadata_get(file, DBOX_METADATA_FLAGS);
-	if (value != NULL) {
-		for (i = 0; value[i] != '\0'; i++) {
-			if (value[i] != '0' && i < DBOX_METADATA_FLAGS_COUNT)
-				flags |= dbox_mail_flags_map[i];
-		}
-		mail_index_update_flags(ctx->trans, seq, MODIFY_REPLACE, flags);
-	}
-
-	value = dbox_file_metadata_get(file, DBOX_METADATA_KEYWORDS);
-	if (value != NULL) T_BEGIN {
-		keywords = mail_index_keywords_create(ctx->mbox->ibox.index,
-						t_strsplit_spaces(value, " "));
-		mail_index_update_keywords(ctx->trans, seq, MODIFY_REPLACE,
-					   keywords);
-		mail_index_keywords_free(&keywords);
-	} T_END;
 }
 
 static int dbox_sync_index_file_next(struct dbox_sync_rebuild_context *ctx,
@@ -143,7 +145,7 @@
 {
 	uint32_t seq, uid;
 	uoff_t physical_size;
-	const char *path, *value;
+	const char *path;
 	bool expunged;
 	int ret;
 
@@ -167,18 +169,8 @@
 		return 0;
 	}
 	if (file->maildir_file) {
-		i_assert(uid == 0);
-		if (!maildir_uidlist_get_uid(ctx->maildir_uidlist, file->fname,
-					     &uid)) {
-			if (ctx->maildir_new_uid == 0) {
-				/* not in uidlist, give it an uid later */
-				char *fname = i_strdup(file->fname);
-				array_append(&ctx->maildir_new_files,
-					     &fname, 1);
-				return 0;
-			}
-			uid = ctx->maildir_new_uid++;
-		}
+		i_assert(uid != 0);
+
 		file->append_count = 1;
 		file->last_append_uid = uid;
 	}
@@ -190,18 +182,8 @@
 		i_warning("%s: Ignoring broken file (metadata)", path);
 		return 0;
 	}
-	if (file->maildir_file) {
-		/* preserve POP3 UIDL */
-		value = maildir_uidlist_lookup_ext(ctx->maildir_uidlist, uid,
-					MAILDIR_UIDLIST_REC_EXT_POP3_UIDL);
-		if (value != NULL) {
-			dbox_file_metadata_set(file, DBOX_METADATA_POP3_UIDL,
-					       value);
-		}
-	}
 	if (!expunged) {
 		mail_index_append(ctx->trans, uid, &seq);
-		file->maildir_append_seq = seq;
 		dbox_sync_index_metadata(ctx, file, seq, uid);
 	}
 	return 1;
@@ -225,6 +207,9 @@
 		return 0;
 	}
 
+	if (ctx->highest_uid < uid)
+		ctx->highest_uid = uid;
+
 	file = dbox_file_init(ctx->mbox, uid | DBOX_FILE_ID_FLAG_UID);
 	file->current_path = i_strdup_printf("%s/%s", dir, fname);
 
@@ -246,31 +231,33 @@
 dbox_sync_index_maildir_file(struct dbox_sync_rebuild_context *ctx,
 			     const char *fname)
 {
-	struct dbox_file *file;
-	uoff_t offset = 0;
 	int ret;
 
-	if (ctx->mbox->maildir_sync_keywords == NULL) {
-		ctx->maildir_uidlist =
-			maildir_uidlist_init_readonly(&ctx->mbox->ibox);
+	if (ctx->maildir_sync_ctx == NULL) {
+		i_assert(ctx->mk == NULL);
+
 		ctx->mk = maildir_keywords_init_readonly(&ctx->mbox->ibox.box);
-		ctx->mbox->maildir_sync_keywords =
+		ctx->maildir_sync_keywords =
 			maildir_keywords_sync_init(ctx->mk,
 						   ctx->mbox->ibox.index);
 
-		if (maildir_uidlist_refresh(ctx->maildir_uidlist) < 0)
+		ret = maildir_uidlist_sync_init(ctx->mbox->maildir_uidlist,
+						MAILDIR_UIDLIST_SYNC_NOLOCK,
+						&ctx->maildir_sync_ctx);
+		if (ret <= 0) {
+			i_assert(ret < 0);
 			return -1;
+		}
 	}
 
-	file = dbox_file_init_new_maildir(ctx->mbox, fname);
-	if ((ret = dbox_sync_index_file_next(ctx, file, &offset)) > 0) {
-		dbox_index_append_file(ctx->append_ctx, file);
-		/* appending referenced the file, so make sure it gets closed
-		   so we don't have too many open files. */
-		dbox_file_close(file);
+	/* sync all maildir files first and let maildir uidlist code assign
+	   UIDs for unseen files. */
+	ret = maildir_uidlist_sync_next(ctx->maildir_sync_ctx, fname, 0);
+	if (ret == 0) {
+		i_warning("%s: Ignoring duplicate maildir file: %s",
+			  ctx->mbox->path, fname);
 	}
-	dbox_file_unref(&file);
-	return ret < 0 ? -1 : 0;
+	return ret;
 }
 
 static int
@@ -312,7 +299,7 @@
 			"opendir(%s) failed: %m", path);
 		return -1;
 	}
-	for (;;) {
+	do {
 		errno = 0;
 		if ((d = readdir(dir)) == NULL)
 			break;
@@ -321,7 +308,7 @@
 			ret = dbox_sync_index_file(ctx, path, d->d_name,
 						   primary);
 		} T_END;
-	}
+	} while (ret >= 0);
 	if (errno != 0) {
 		mail_storage_set_critical(storage,
 			"readdir(%s) failed: %m", path);
@@ -336,34 +323,81 @@
 	return ret;
 }
 
-static int dbox_sync_new_maildir(struct dbox_sync_rebuild_context *ctx)
+static int dbox_sync_maildir_finish(struct dbox_sync_rebuild_context *ctx)
 {
+	struct dbox_mailbox *mbox = ctx->mbox;
+	struct maildir_uidlist_iter_ctx *iter;
 	struct mail_index_view *trans_view;
-	char *const *fnames;
-	unsigned int i, count;
+	struct dbox_file *file;
+	const char *fname;
+	enum maildir_uidlist_rec_flag flags;
+	uint32_t uid, next_uid;
+	uoff_t offset;
 	int ret = 0;
 
-	fnames = array_get(&ctx->maildir_new_files, &count);
-	if (count == 0)
-		return 0;
+	/* we'll need the uidlist to contain the latest filenames.
+	   since there's no easy way to figure out if they changed, just
+	   recreate the uidlist always. */
+	maildir_uidlist_sync_recreate(ctx->maildir_sync_ctx);
 
+	/* update the maildir uidlist's next_uid if we have seen higher
+	   dbox UIDs */
 	trans_view = mail_index_transaction_open_updated_view(ctx->trans);
-	ctx->maildir_new_uid = mail_index_get_header(trans_view)->next_uid;
+	next_uid = mail_index_get_header(trans_view)->next_uid;
 	mail_index_view_close(&trans_view);
+	maildir_uidlist_set_next_uid(mbox->maildir_uidlist, next_uid, FALSE);
+	maildir_uidlist_set_next_uid(mbox->maildir_uidlist,
+				     ctx->highest_uid + 1, FALSE);
+	/* assign UIDs for new maildir mails before iterating */
+	maildir_uidlist_sync_finish(ctx->maildir_sync_ctx);
 
-	for (i = 0; i < count && ret == 0; i++) {
-		T_BEGIN {
-			ret = dbox_sync_index_maildir_file(ctx, fnames[i]);
-		} T_END;
+	mbox->highest_maildir_uid =
+		maildir_uidlist_get_next_uid(mbox->maildir_uidlist);
+
+	iter = maildir_uidlist_iter_init(mbox->maildir_uidlist);
+	while (maildir_uidlist_iter_next(iter, &uid, &flags, &fname)) {
+		file = dbox_file_init(mbox, uid | DBOX_FILE_ID_FLAG_UID);
+		file->current_path =
+			i_strdup_printf("%s/%s", ctx->mbox->path, fname);
+
+		offset = 0;
+		ret = dbox_sync_index_file_next(ctx, file, &offset);
+		dbox_file_unref(&file);
+		if (ret < 0)
+			break;
 	}
-	return ret;
+	maildir_uidlist_iter_deinit(&iter);
+	return ret < 0 ? -1 : 0;
+}
+
+static void dbox_sync_update_header(struct dbox_sync_rebuild_context *ctx)
+{
+	const struct dbox_index_header *hdr;
+	struct dbox_index_header new_hdr;
+	const void *data;
+	size_t data_size;
+
+	mail_index_get_header_ext(ctx->mbox->ibox.view,
+				  ctx->mbox->dbox_hdr_ext_id,
+				  &data, &data_size);
+	hdr = data;
+	if (data_size == sizeof(*hdr)) {
+		if (hdr->highest_maildir_uid >= ctx->mbox->highest_maildir_uid) {
+			/* nothing to change */
+			return;
+		}
+		new_hdr = *hdr;
+	} else {
+		memset(&new_hdr, 0, sizeof(new_hdr));
+	}
+	new_hdr.highest_maildir_uid = ctx->mbox->highest_maildir_uid;
+	mail_index_update_header_ext(ctx->trans, ctx->mbox->dbox_hdr_ext_id, 0,
+				     &new_hdr, sizeof(new_hdr));
 }
 
 static int dbox_sync_index_rebuild_ctx(struct dbox_sync_rebuild_context *ctx)
 {
-	if (dbox_sync_set_uidvalidity(ctx) < 0)
-		return -1;
-
+	dbox_sync_set_uidvalidity(ctx);
 	if (dbox_sync_index_rebuild_dir(ctx, ctx->mbox->path, TRUE) < 0)
 		return -1;
 
@@ -373,27 +407,10 @@
 			return -1;
 	}
 
-	/* finally give UIDs to newly seen maildir files */
-	return dbox_sync_new_maildir(ctx);
-}
-
-static void dbox_sync_update_maildir_ids(struct dbox_sync_rebuild_context *ctx)
-{
-	struct dbox_mail_index_record rec;
-	struct dbox_file *const *files;
-	unsigned int i, count;
-
-	memset(&rec, 0, sizeof(rec));
-	files = array_get(&ctx->mbox->open_files, &count);
-	for (i = 0; i < count; i++) {
-		if (!files[i]->maildir_file)
-			continue;
-
-		i_assert(files[i]->file_id != 0);
-		rec.file_id = files[i]->file_id;
-		mail_index_update_ext(ctx->trans, files[i]->maildir_append_seq,
-				      ctx->mbox->dbox_ext_id, &rec, NULL);
-	}
+	if (dbox_sync_maildir_finish(ctx) < 0)
+		return -1;
+	dbox_sync_update_header(ctx);
+	return 0;
 }
 
 int dbox_sync_index_rebuild(struct dbox_mailbox *mbox)
@@ -401,48 +418,30 @@
 	struct dbox_sync_rebuild_context ctx;
 	uint32_t seq;
 	uoff_t offset;
-	char **fnames;
-	unsigned int i, count;
 	int ret;
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.mbox = mbox;
-	ctx.append_ctx = dbox_index_append_begin(mbox->dbox_index);
 	ctx.view = mail_index_view_open(mbox->ibox.index);
 	ctx.trans = mail_index_transaction_begin(ctx.view,
 					MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL);
-	i_array_init(&ctx.maildir_new_files, 8);
 	mail_index_reset(ctx.trans);
 	index_mailbox_reset_uidvalidity(&mbox->ibox);
 	mail_index_ext_lookup(mbox->ibox.index, "cache", &ctx.cache_ext_id);
 
 	if ((ret = dbox_sync_index_rebuild_ctx(&ctx)) < 0)
 		mail_index_transaction_rollback(&ctx.trans);
-	else {
-		ret = dbox_index_append_assign_file_ids(ctx.append_ctx);
-		if (ret == 0) {
-			dbox_sync_update_maildir_ids(&ctx);
-			ret = mail_index_transaction_commit(&ctx.trans,
-							    &seq, &offset);
-		}
-	}
+	else
+		ret = mail_index_transaction_commit(&ctx.trans, &seq, &offset);
 	mail_index_view_close(&ctx.view);
 
-	fnames = array_get_modifiable(&ctx.maildir_new_files, &count);
-	for (i = 0; i < count; i++)
-		i_free(fnames[i]);
-	array_free(&ctx.maildir_new_files);
-
-	if (ret == 0)
-		ret = dbox_index_append_commit(&ctx.append_ctx);
-	else
-		dbox_index_append_rollback(&ctx.append_ctx);
-
-	if (mbox->maildir_sync_keywords != NULL)
-		maildir_keywords_sync_deinit(&mbox->maildir_sync_keywords);
+	if (ctx.maildir_sync_ctx != NULL) {
+		if (maildir_uidlist_sync_deinit(&ctx.maildir_sync_ctx) < 0)
+			ret = -1;
+	}
+	if (ctx.maildir_sync_keywords != NULL)
+		maildir_keywords_sync_deinit(&ctx.maildir_sync_keywords);
 	if (ctx.mk != NULL)
 		maildir_keywords_deinit(&ctx.mk);
-	if (ctx.maildir_uidlist != NULL)
-		maildir_uidlist_deinit(&ctx.maildir_uidlist);
 	return ret;
 }
--- a/src/lib-storage/index/dbox/dbox-sync.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-sync.c	Mon Feb 16 20:30:15 2009 -0500
@@ -6,14 +6,9 @@
 #include "str.h"
 #include "hash.h"
 #include "dbox-storage.h"
-#include "dbox-index.h"
 #include "dbox-file.h"
 #include "dbox-sync.h"
 
-#define DBOX_FLUSH_SECS_INTERACTIVE (4*60*60)
-#define DBOX_FLUSH_SECS_CLOSE (4*60*60)
-#define DBOX_FLUSH_SECS_IMMEDIATE (24*60*60)
-
 #define DBOX_REBUILD_COUNT 3
 
 static int dbox_sync_add_seq(struct dbox_sync_context *ctx,
@@ -23,7 +18,10 @@
 	struct dbox_sync_file_entry *entry;
 	uint32_t file_id;
 	uoff_t offset;
-	bool uid_file, add;
+	bool uid_file;
+
+	i_assert(sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE ||
+		 sync_rec->type == MAIL_INDEX_SYNC_TYPE_FLAGS);
 
 	if (!dbox_file_lookup(ctx->mbox, ctx->sync_view, seq,
 			      &file_id, &offset))
@@ -31,27 +29,6 @@
 
 	entry = hash_table_lookup(ctx->syncs, POINTER_CAST(file_id));
 	if (entry == NULL) {
-		if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE ||
-		    ctx->flush_dirty_flags) {
-			/* expunges / flushing dirty flags */
-			add = TRUE;
-		} else if (sync_rec->type != MAIL_INDEX_SYNC_TYPE_FLAGS) {
-			/* keywords, not flushing dirty flags */
-			add = FALSE;
-		} else {
-			/* add if we're moving from/to alternative storage
-			   and we actually have an alt directory specified */
-			add = ((sync_rec->add_flags | sync_rec->remove_flags) &
-			       DBOX_INDEX_FLAG_ALT) != 0 &&
-				ctx->mbox->alt_path != NULL;
-		}
-
-		if (!add) {
-			mail_index_update_flags(ctx->trans, seq, MODIFY_ADD,
-				(enum mail_flags)MAIL_INDEX_MAIL_FLAG_DIRTY);
-			return 0;
-		}
-
 		entry = p_new(ctx->pool, struct dbox_sync_file_entry, 1);
 		entry->file_id = file_id;
 		hash_table_insert(ctx->syncs, POINTER_CAST(file_id), entry);
@@ -62,15 +39,13 @@
 		if (!array_is_created(&entry->expunges)) {
 			p_array_init(&entry->expunges, ctx->pool,
 				     uid_file ? 1 : 3);
-			seq_range_array_add(&ctx->expunge_files, 0, file_id);
 		}
 		seq_range_array_add(&entry->expunges, 0, seq);
 	} else {
-		if (!array_is_created(&entry->changes)) {
-			p_array_init(&entry->changes, ctx->pool,
-				     uid_file ? 1 : 8);
-		}
-		seq_range_array_add(&entry->changes, 0, seq);
+		if ((sync_rec->add_flags & DBOX_INDEX_FLAG_ALT) != 0)
+			entry->move_to_alt = TRUE;
+		else
+			entry->move_from_alt = TRUE;
 	}
 	return 0;
 }
@@ -80,14 +55,18 @@
 {
 	uint32_t seq, seq1, seq2;
 
-	if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_APPEND) {
-		/* don't care about appends */
+	if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE) {
+		/* we're interested */
+	} else if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_FLAGS) {
+		/* we care only about alt flag changes */
+		if ((sync_rec->add_flags & DBOX_INDEX_FLAG_ALT) == 0 &&
+		    (sync_rec->remove_flags & DBOX_INDEX_FLAG_ALT) == 0)
+			return 0;
+	} else {
+		/* not interested */
 		return 0;
 	}
 
-	/* we assume that anything else than appends are interactive changes */
-	ctx->mbox->last_interactive_change = ioloop_time;
-
 	if (!mail_index_lookup_seq_range(ctx->sync_view,
 					 sync_rec->uid1, sync_rec->uid2,
 					 &seq1, &seq2)) {
@@ -102,84 +81,6 @@
 	return 0;
 }
 
-static int
-dbox_sync_lock_expunge_file(struct dbox_sync_context *ctx, unsigned int file_id)
-{
-	struct dbox_index_record *rec;
-	enum dbox_index_file_lock_status lock_status;
-	int ret;
-
-	ret = dbox_index_try_lock_file(ctx->mbox->dbox_index, file_id,
-				       &lock_status);
-	if (ret < 0)
-		return -1;
-
-	rec = dbox_index_record_lookup(ctx->mbox->dbox_index, file_id);
-	switch (lock_status) {
-	case DBOX_INDEX_FILE_LOCKED:
-		seq_range_array_add(&ctx->locked_files, 0, file_id);
-		rec->status = DBOX_INDEX_FILE_STATUS_NONAPPENDABLE;
-		break;
-	case DBOX_INDEX_FILE_LOCK_NOT_NEEDED:
-	case DBOX_INDEX_FILE_LOCK_UNLINKED:
-		i_assert(rec == NULL ||
-			 rec->status != DBOX_INDEX_FILE_STATUS_APPENDABLE);
-		break;
-	case DBOX_INDEX_FILE_LOCK_TRY_AGAIN:
-		rec->expunges = TRUE;
-		break;
-	}
-	return 0;
-}
-
-static int dbox_sync_lock_expunge_files(struct dbox_sync_context *ctx)
-{
-	const struct seq_range *range;
-	unsigned int i, count, id;
-
-	range = array_get(&ctx->expunge_files, &count);
-	for (i = 0; i < count; i++) {
-		for (id = range[i].seq1; id <= range[i].seq2; id++) {
-			if (dbox_sync_lock_expunge_file(ctx, id) < 0)
-				return -1;
-		}
-	}
-	return 0;
-}
-
-static void dbox_sync_unlock_files(struct dbox_sync_context *ctx)
-{
-	const struct seq_range *range;
-	unsigned int i, count, id;
-
-	range = array_get(&ctx->locked_files, &count);
-	for (i = 0; i < count; i++) {
-		for (id = range[i].seq1; id <= range[i].seq2; id++)
-			dbox_index_unlock_file(ctx->mbox->dbox_index, id);
-	}
-}
-
-static void dbox_sync_update_header(struct dbox_sync_context *ctx)
-{
-	struct dbox_index_header hdr;
-	const void *data;
-	size_t data_size;
-
-	if (!ctx->flush_dirty_flags) {
-		/* write the header if it doesn't exist yet */
-		mail_index_get_header_ext(ctx->mbox->ibox.view,
-					  ctx->mbox->dbox_hdr_ext_id,
-					  &data, &data_size);
-		if (data_size != 0)
-			return;
-	}
-
-	hdr.last_dirty_flush_stamp = ioloop_time;
-	mail_index_update_header_ext(ctx->trans, ctx->mbox->dbox_hdr_ext_id, 0,
-				     &hdr.last_dirty_flush_stamp,
-				     sizeof(hdr.last_dirty_flush_stamp));
-}
-
 static int dbox_sync_index(struct dbox_sync_context *ctx)
 {
 	struct mailbox *box = &ctx->mbox->ibox.box;
@@ -206,8 +107,6 @@
 	/* read all changes and sort them to file_id order */
 	ctx->pool = pool_alloconly_create("dbox sync pool", 1024*32);
 	ctx->syncs = hash_table_create(default_pool, ctx->pool, 0, NULL, NULL);
-	i_array_init(&ctx->expunge_files, 32);
-	i_array_init(&ctx->locked_files, 32);
 
 	for (;;) {
 		if (!mail_index_sync_next(ctx->index_sync_ctx, &sync_rec))
@@ -217,11 +116,6 @@
 			break;
 		}
 	}
-	if (ret > 0) {
-		if (dbox_sync_lock_expunge_files(ctx) < 0)
-			ret = -1;
-	}
-	array_free(&ctx->expunge_files);
 
 	if (ret > 0) {
 		/* now sync each file separately */
@@ -235,35 +129,26 @@
 		hash_table_iterate_deinit(&iter);
 	}
 
-	if (ret > 0)
-		dbox_sync_update_header(ctx);
-
 	if (box->v.sync_notify != NULL)
 		box->v.sync_notify(box, 0, 0);
 
-	dbox_sync_unlock_files(ctx);
-	array_free(&ctx->locked_files);
 	hash_table_destroy(&ctx->syncs);
 	pool_unref(&ctx->pool);
 	return ret;
 }
 
-static int dbox_sync_want_flush_dirty(struct dbox_mailbox *mbox,
-				      bool close_flush_dirty_flags)
+static int dbox_refresh_header(struct dbox_mailbox *mbox)
 {
 	const struct dbox_index_header *hdr;
 	const void *data;
 	size_t data_size;
 
-	if (mbox->last_interactive_change <
-	    ioloop_time - DBOX_FLUSH_SECS_INTERACTIVE)
-		return 1;
-
 	mail_index_get_header_ext(mbox->ibox.view, mbox->dbox_hdr_ext_id,
 				  &data, &data_size);
 	if (data_size != sizeof(*hdr)) {
-		/* data_size=0 means it's never been synced as dbox */
-		if (data_size != 0) {
+		/* data_size=0 means it's never been synced as dbox.
+		   data_size=4 is for backwards compatibility */
+		if (data_size != 0 && data_size != 4) {
 			i_warning("dbox %s: Invalid dbox header size",
 				  mbox->path);
 		}
@@ -271,46 +156,24 @@
 	}
 	hdr = data;
 
-	if (!close_flush_dirty_flags) {
-		if ((time_t)hdr->last_dirty_flush_stamp <
-		    ioloop_time - DBOX_FLUSH_SECS_IMMEDIATE)
-			return 1;
-	} else {
-		if ((time_t)hdr->last_dirty_flush_stamp <
-		    ioloop_time - DBOX_FLUSH_SECS_CLOSE)
-			return 1;
-	}
+	mbox->highest_maildir_uid = hdr->highest_maildir_uid;
 	return 0;
 }
 
-int dbox_sync_begin(struct dbox_mailbox *mbox,
-		    struct dbox_sync_context **ctx_r,
-		    bool close_flush_dirty_flags, bool force)
+int dbox_sync_begin(struct dbox_mailbox *mbox, bool force,
+		    struct dbox_sync_context **ctx_r)
 {
 	struct mail_storage *storage = mbox->ibox.box.storage;
 	struct dbox_sync_context *ctx;
 	enum mail_index_sync_flags sync_flags = 0;
 	unsigned int i;
 	int ret;
-	bool rebuild = FALSE;
+	bool rebuild;
 
-	ret = dbox_sync_want_flush_dirty(mbox, close_flush_dirty_flags);
-	if (ret > 0)
-		sync_flags |= MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY;
-	else if (ret < 0)
-		rebuild = TRUE;
-	else {
-		if (close_flush_dirty_flags) {
-			/* no need to sync */
-			*ctx_r = NULL;
-			return 0;
-		}
-	}
+	rebuild = dbox_refresh_header(mbox) < 0;
 
 	ctx = i_new(struct dbox_sync_context, 1);
 	ctx->mbox = mbox;
-	ctx->flush_dirty_flags =
-		(sync_flags & MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY) != 0;
 
 	if (!mbox->ibox.keep_recent)
 		sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
@@ -332,7 +195,7 @@
 			return ret;
 		}
 
-		if (rebuild && dbox_sync_want_flush_dirty(mbox, FALSE) >= 0) {
+		if (rebuild && dbox_refresh_header(mbox) < 0) {
 			/* another process rebuilt it already */
 			rebuild = FALSE;
 		}
@@ -389,12 +252,11 @@
 	return 0;
 }
 
-int dbox_sync(struct dbox_mailbox *mbox, bool close_flush_dirty_flags)
+int dbox_sync(struct dbox_mailbox *mbox)
 {
 	struct dbox_sync_context *sync_ctx;
 
-	if (dbox_sync_begin(mbox, &sync_ctx,
-			    close_flush_dirty_flags, FALSE) < 0)
+	if (dbox_sync_begin(mbox, FALSE, &sync_ctx) < 0)
 		return -1;
 
 	if (sync_ctx == NULL)
@@ -412,7 +274,7 @@
 		index_storage_mailbox_open(&mbox->ibox);
 
 	if (index_mailbox_want_full_sync(&mbox->ibox, flags))
-		ret = dbox_sync(mbox, FALSE);
+		ret = dbox_sync(mbox);
 
 	return index_mailbox_sync_init(box, flags, ret < 0);
 }
--- a/src/lib-storage/index/dbox/dbox-sync.h	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/dbox/dbox-sync.h	Mon Feb 16 20:30:15 2009 -0500
@@ -6,7 +6,8 @@
 struct dbox_sync_file_entry {
 	uint32_t file_id;
 
-	ARRAY_TYPE(seq_range) changes;
+	unsigned int move_from_alt:1;
+	unsigned int move_to_alt:1;
 	ARRAY_TYPE(seq_range) expunges;
 };
 
@@ -21,17 +22,12 @@
 
 	pool_t pool;
 	struct hash_table *syncs; /* struct dbox_sync_file_entry */
-	ARRAY_TYPE(seq_range) expunge_files;
-	ARRAY_TYPE(seq_range) locked_files;
-
-	unsigned int flush_dirty_flags:1;
 };
 
-int dbox_sync_begin(struct dbox_mailbox *mbox,
-		    struct dbox_sync_context **ctx_r,
-		    bool close_flush_dirty_flags, bool force);
+int dbox_sync_begin(struct dbox_mailbox *mbox, bool force,
+		    struct dbox_sync_context **ctx_r);
 int dbox_sync_finish(struct dbox_sync_context **ctx, bool success);
-int dbox_sync(struct dbox_mailbox *mbox, bool close_flush_dirty_flags);
+int dbox_sync(struct dbox_mailbox *mbox);
 
 int dbox_sync_file(struct dbox_sync_context *ctx,
 		   const struct dbox_sync_file_entry *entry);
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Mon Feb 16 20:30:15 2009 -0500
@@ -51,6 +51,8 @@
 
 #define UIDLIST_IS_LOCKED(uidlist) \
 	((uidlist)->lock_count > 0)
+#define UIDLIST_ALLOW_WRITING(uidlist) \
+	(UIDLIST_IS_LOCKED(uidlist) || (uidlist)->mbox == NULL)
 
 struct maildir_uidlist_rec {
 	uint32_t uid;
@@ -1341,7 +1343,7 @@
 	*sync_ctx_r = ctx = i_new(struct maildir_uidlist_sync_ctx, 1);
 	ctx->uidlist = uidlist;
 	ctx->sync_flags = sync_flags;
-	ctx->partial = !locked ||
+	ctx->partial = (!locked && ctx->uidlist->mbox != NULL) ||
 		(sync_flags & MAILDIR_UIDLIST_SYNC_PARTIAL) != 0;
 	ctx->locked = locked;
 	ctx->first_unwritten_pos = (unsigned int)-1;
@@ -1432,15 +1434,20 @@
 {
 	struct maildir_uidlist *uidlist = ctx->uidlist;
 	struct maildir_uidlist_rec *rec, *old_rec;
-	const char *p;
+	const char *p, *dir;
 
 	if (ctx->failed)
 		return -1;
 
 	for (p = filename; *p != '\0'; p++) {
 		if (*p == 13 || *p == 10) {
+			struct mailbox *box = &uidlist->ibox->box;
+
+			dir = mailbox_list_get_path(box->storage->list,
+						box->name,
+						MAILBOX_LIST_PATH_TYPE_MAILBOX);
 			i_warning("Maildir %s: Ignoring a file with #0x%x: %s",
-				  uidlist->mbox->path, *p, filename);
+				  dir, *p, filename);
 			return 1;
 		}
 	}
@@ -1465,7 +1472,7 @@
 				MAILDIR_UIDLIST_REC_FLAG_MOVED);
 	} else {
 		old_rec = hash_table_lookup(uidlist->files, filename);
-		i_assert(old_rec != NULL || UIDLIST_IS_LOCKED(uidlist));
+		i_assert(old_rec != NULL || UIDLIST_ALLOW_WRITING(uidlist));
 
 		rec = p_new(ctx->record_pool, struct maildir_uidlist_rec, 1);
 
@@ -1563,7 +1570,7 @@
 	struct maildir_uidlist_rec **recs;
 	unsigned int dest, count;
 
-	i_assert(UIDLIST_IS_LOCKED(ctx->uidlist));
+	i_assert(UIDLIST_ALLOW_WRITING(ctx->uidlist));
 	i_assert(ctx->first_nouid_pos != (unsigned int)-1);
 
 	if (ctx->first_unwritten_pos == (unsigned int)-1)
@@ -1619,6 +1626,11 @@
 	}
 }
 
+void maildir_uidlist_sync_recreate(struct maildir_uidlist_sync_ctx *ctx)
+{
+	ctx->uidlist->recreate = TRUE;
+}
+
 void maildir_uidlist_sync_finish(struct maildir_uidlist_sync_ctx *ctx)
 {
 	if (!ctx->partial) {
@@ -1632,13 +1644,17 @@
 	ctx->finished = TRUE;
 	ctx->uidlist->initial_sync = TRUE;
 
-	i_assert(ctx->locked || !ctx->changed);
+	/* mbox=NULL means we're coming from dbox rebuilding code.
+	   the dbox is already locked, so allow uidlist recreation */
+	i_assert(ctx->locked || !ctx->changed || ctx->uidlist->mbox == NULL);
 	if ((ctx->changed || ctx->uidlist->recreate ||
 	     maildir_uidlist_want_compress(ctx)) &&
-	    !ctx->failed && ctx->locked) T_BEGIN {
-		if (maildir_uidlist_sync_update(ctx) < 0)
-			ctx->failed = TRUE;
-	} T_END;
+	    !ctx->failed && (ctx->locked || ctx->uidlist->mbox == NULL)) {
+		T_BEGIN {
+			if (maildir_uidlist_sync_update(ctx) < 0)
+				ctx->failed = TRUE;
+		} T_END;
+	}
 }
 
 int maildir_uidlist_sync_deinit(struct maildir_uidlist_sync_ctx **_ctx)
--- a/src/lib-storage/index/maildir/maildir-uidlist.h	Fri Feb 13 17:44:00 2009 -0500
+++ b/src/lib-storage/index/maildir/maildir-uidlist.h	Mon Feb 16 20:30:15 2009 -0500
@@ -106,6 +106,7 @@
 const char *
 maildir_uidlist_sync_get_full_filename(struct maildir_uidlist_sync_ctx *ctx,
 				       const char *filename);
+void maildir_uidlist_sync_recreate(struct maildir_uidlist_sync_ctx *ctx);
 void maildir_uidlist_sync_finish(struct maildir_uidlist_sync_ctx *ctx);
 int maildir_uidlist_sync_deinit(struct maildir_uidlist_sync_ctx **ctx);