changeset 5393:434047e53586 HEAD

When saving/copying mails, we must not do any sorting based on the filename to saved mails when they're added to uidlist, otherwise they could be saved to index with wrong UID.
author Timo Sirainen <tss@iki.fi>
date Fri, 23 Mar 2007 22:23:24 +0200
parents 9a8402768b42
children 344ae496ee7e
files src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/maildir/maildir-uidlist.h
diffstat 3 files changed, 61 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/maildir/maildir-save.c	Fri Mar 23 19:20:24 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-save.c	Fri Mar 23 22:23:24 2007 +0200
@@ -137,6 +137,30 @@
 	return ctx;
 }
 
+static void maildir_save_add_existing_to_index(struct maildir_save_context *ctx)
+{
+	struct maildir_filename *mf;
+	struct mail_keywords *kw;
+	uint32_t seq;
+
+	for (mf = ctx->files; mf != NULL; mf = mf->next) {
+		mail_index_append(ctx->trans, 0, &seq);
+		mail_index_update_flags(ctx->trans, seq,
+					MODIFY_REPLACE, mf->flags);
+		if (mf->keywords_count != 0) {
+			t_push();
+			/* @UNSAFE */
+			kw = t_malloc(sizeof(*kw) + sizeof(kw->idx[0]) *
+				      mf->keywords_count);
+			memcpy(kw->idx, mf + 1, sizeof(kw->idx[0]) *
+			       mf->keywords_count);
+			mail_index_update_keywords(ctx->trans, ctx->seq,
+						   MODIFY_REPLACE, kw);
+			t_pop();
+		}
+	}
+}
+
 uint32_t maildir_save_add(struct maildir_transaction_context *t,
 			  const char *base_fname, enum mail_flags flags,
 			  struct mail_keywords *keywords,
@@ -146,8 +170,12 @@
 	struct maildir_filename *mf;
 	struct tee_istream *tee;
 
-	if (dest_mail != NULL)
+	if (dest_mail != NULL && !ctx->want_mails) {
 		ctx->want_mails = TRUE;
+		/* if there are any existing mails, we need to append them
+		   to index here to keep the UIDs correct */
+		maildir_save_add_existing_to_index(ctx);
+	}
 
 	/* now, we want to be able to rollback the whole append session,
 	   so we'll just store the name of this temp file and move it later
@@ -484,7 +512,7 @@
 int maildir_transaction_save_commit_pre(struct maildir_save_context *ctx)
 {
 	struct maildir_filename *mf;
-	uint32_t first_uid, last_uid;
+	uint32_t first_uid, next_uid;
 	enum maildir_uidlist_rec_flag flags;
 	const char *dest;
 	bool newdir, sync_commit = FALSE;
@@ -519,7 +547,7 @@
 
 		first_uid = maildir_uidlist_get_next_uid(ctx->mbox->uidlist);
 		i_assert(first_uid != 0);
-		mail_index_append_assign_uids(ctx->trans, first_uid, &last_uid);
+		mail_index_append_assign_uids(ctx->trans, first_uid, &next_uid);
 	}
 
 	flags = MAILDIR_UIDLIST_REC_FLAG_NEW_DIR |
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Mar 23 19:20:24 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Fri Mar 23 22:23:24 2007 +0200
@@ -63,6 +63,7 @@
 
 struct maildir_uidlist_sync_ctx {
 	struct maildir_uidlist *uidlist;
+	enum maildir_uidlist_sync_flags sync_flags;
 
 	pool_t record_pool;
 	buffer_t *record_buf;
@@ -695,7 +696,8 @@
 	}
 }
 
-int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist, bool partial,
+int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
+			      enum maildir_uidlist_sync_flags sync_flags,
 			      struct maildir_uidlist_sync_ctx **sync_ctx_r)
 {
 	struct maildir_uidlist_sync_ctx *ctx;
@@ -707,9 +709,10 @@
 
 	*sync_ctx_r = ctx = i_new(struct maildir_uidlist_sync_ctx, 1);
 	ctx->uidlist = uidlist;
-	ctx->partial = partial;
+	ctx->sync_flags = sync_flags;
+	ctx->partial = (sync_flags & MAILDIR_UIDLIST_SYNC_PARTIAL) != 0;
 
-	if (partial) {
+	if (ctx->partial) {
 		/* initially mark all nonsynced */
                 maildir_uidlist_mark_all(uidlist, TRUE);
 		return 1;
@@ -879,32 +882,36 @@
 	return t1 < t2 ? -1 : t1 > t2 ? 1 : 0;
 }
 
-static void maildir_uidlist_assign_uids(struct maildir_uidlist *uidlist,
+static void maildir_uidlist_assign_uids(struct maildir_uidlist_sync_ctx *ctx,
 					unsigned int first_new_pos)
 {
 	struct maildir_uidlist_rec **rec_p;
 	unsigned int dest;
 	size_t size;
 
-	i_assert(UIDLIST_IS_LOCKED(uidlist));
+	i_assert(UIDLIST_IS_LOCKED(ctx->uidlist));
 
-	rec_p = buffer_get_modifiable_data(uidlist->record_buf, &size);
+	rec_p = buffer_get_modifiable_data(ctx->uidlist->record_buf, &size);
 	size /= sizeof(*rec_p);
 
 	/* sort new files and assign UIDs for them */
-	qsort(rec_p + first_new_pos, size - first_new_pos,
-	      sizeof(*rec_p), maildir_time_cmp);
+	if ((ctx->sync_flags & MAILDIR_UIDLIST_SYNC_ORDERED) == 0) {
+		qsort(rec_p + first_new_pos, size - first_new_pos,
+		      sizeof(*rec_p), maildir_time_cmp);
+	}
 	for (dest = first_new_pos; dest < size; dest++) {
 		i_assert(rec_p[dest]->uid == (uint32_t)-1);
-		rec_p[dest]->uid = uidlist->next_uid++;
+		rec_p[dest]->uid = ctx->uidlist->next_uid++;
 		rec_p[dest]->flags &= ~MAILDIR_UIDLIST_REC_FLAG_MOVED;
 
 		if ((rec_p[dest]->flags &
-		     MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0)
-			maildir_uidlist_mark_recent(uidlist, rec_p[dest]->uid);
+		     MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0) {
+			maildir_uidlist_mark_recent(ctx->uidlist,
+						    rec_p[dest]->uid);
+		}
 	}
 
-        uidlist->last_seen_uid = uidlist->next_uid-1;
+        ctx->uidlist->last_seen_uid = ctx->uidlist->next_uid-1;
 }
 
 static int maildir_uid_cmp(const void *p1, const void *p2)
@@ -939,10 +946,8 @@
 	uidlist->record_pool = ctx->record_pool;
 	ctx->record_pool = NULL;
 
-	if (ctx->new_files_count != 0) {
-		maildir_uidlist_assign_uids(uidlist,
-					    size - ctx->new_files_count);
-	}
+	if (ctx->new_files_count != 0)
+		maildir_uidlist_assign_uids(ctx, size - ctx->new_files_count);
 }
 
 void maildir_uidlist_sync_finish(struct maildir_uidlist_sync_ctx *ctx)
@@ -951,10 +956,8 @@
 		if (!ctx->failed)
 			maildir_uidlist_swap(ctx);
 	} else {
-		if (ctx->new_files_count != 0) {
-			maildir_uidlist_assign_uids(ctx->uidlist,
-						    ctx->first_new_pos);
-		}
+		if (ctx->new_files_count != 0)
+			maildir_uidlist_assign_uids(ctx, ctx->first_new_pos);
 	}
 
 	ctx->finished = TRUE;
--- a/src/lib-storage/index/maildir/maildir-uidlist.h	Fri Mar 23 19:20:24 2007 +0200
+++ b/src/lib-storage/index/maildir/maildir-uidlist.h	Fri Mar 23 22:23:24 2007 +0200
@@ -5,6 +5,11 @@
 
 struct maildir_uidlist_sync_ctx;
 
+enum maildir_uidlist_sync_flags {
+	MAILDIR_UIDLIST_SYNC_PARTIAL	= 0x01,
+	MAILDIR_UIDLIST_SYNC_ORDERED	= 0x02
+};
+
 enum maildir_uidlist_rec_flag {
 	MAILDIR_UIDLIST_REC_FLAG_NEW_DIR	= 0x01,
 	MAILDIR_UIDLIST_REC_FLAG_MOVED		= 0x02,
@@ -42,7 +47,8 @@
 
 /* Sync uidlist with what's actually on maildir. Returns same as
    maildir_uidlist_lock(). */
-int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist, bool partial,
+int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
+			      enum maildir_uidlist_sync_flags sync_flags,
 			      struct maildir_uidlist_sync_ctx **sync_ctx_r);
 /* Returns 1 = ok, -1 = error, 0 = new file and dovecot-uidlist is locked */
 int maildir_uidlist_sync_next_pre(struct maildir_uidlist_sync_ctx *ctx,