dovecot-2.0: maildir: Support saving messages with specified UIDs.

dovecot at dovecot.org dovecot at dovecot.org
Tue Jul 28 02:04:46 EEST 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/be433e394f69
changeset: 9685:be433e394f69
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Jul 27 19:02:12 2009 -0400
description:
maildir: Support saving messages with specified UIDs.

diffstat:

4 files changed, 74 insertions(+), 30 deletions(-)
src/lib-storage/index/maildir/maildir-save.c    |   33 ++++++++---
src/lib-storage/index/maildir/maildir-storage.h |    4 -
src/lib-storage/index/maildir/maildir-uidlist.c |   64 ++++++++++++++++-------
src/lib-storage/index/maildir/maildir-uidlist.h |    3 +

diffs (truncated from 302 to 300 lines):

diff -r fb8bc26d7194 -r be433e394f69 src/lib-storage/index/maildir/maildir-save.c
--- a/src/lib-storage/index/maildir/maildir-save.c	Mon Jul 27 19:00:56 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-save.c	Mon Jul 27 19:02:12 2009 -0400
@@ -32,6 +32,7 @@ struct maildir_filename {
 
 	uoff_t size, vsize;
 	enum mail_flags flags;
+	unsigned int preserve_filename:1;
 	unsigned int keywords_count;
 	/* unsigned int keywords[]; */
 };
@@ -131,8 +132,8 @@ maildir_save_transaction_init(struct mai
 	return ctx;
 }
 
-uint32_t maildir_save_add(struct mail_save_context *_ctx,
-			  const char *base_fname)
+struct maildir_filename *
+maildir_save_add(struct mail_save_context *_ctx, const char *base_fname)
 {
 	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
 	struct maildir_filename *mf;
@@ -171,7 +172,7 @@ uint32_t maildir_save_add(struct mail_sa
 	}
 
 	/* insert into index */
-	mail_index_append(ctx->trans, 0, &ctx->seq);
+	mail_index_append(ctx->trans, _ctx->uid, &ctx->seq);
 	mail_index_update_flags(ctx->trans, ctx->seq,
 				MODIFY_REPLACE, _ctx->flags);
 	if (_ctx->keywords != NULL) {
@@ -202,7 +203,7 @@ uint32_t maildir_save_add(struct mail_sa
 		ctx->input = input;
 		ctx->cur_dest_mail = _ctx->dest_mail;
 	}
-	return ctx->seq;
+	return mf;
 }
 
 static bool
@@ -213,12 +214,12 @@ maildir_get_updated_filename(struct mail
 	const char *basename = mf->basename;
 
 	if (ctx->mbox->storage->save_size_in_filename &&
-	    mf->size != (uoff_t)-1) {
+	    mf->size != (uoff_t)-1 && !mf->preserve_filename) {
 		basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
 					   MAILDIR_EXTRA_FILE_SIZE, mf->size);
 	}
 
-	if (mf->vsize != (uoff_t)-1) {
+	if (mf->vsize != (uoff_t)-1 && !mf->preserve_filename) {
 		basename = t_strdup_printf("%s,%c=%"PRIuUOFF_T, basename,
 					   MAILDIR_EXTRA_VIRTUAL_SIZE,
 					   mf->vsize);
@@ -370,6 +371,7 @@ int maildir_save_begin(struct mail_save_
 int maildir_save_begin(struct mail_save_context *_ctx, struct istream *input)
 {
 	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
+	struct maildir_filename *mf;
 
 	T_BEGIN {
 		/* create a new file in tmp/ directory */
@@ -383,7 +385,9 @@ int maildir_save_begin(struct mail_save_
 				ctx->input = i_stream_create_crlf(input);
 			else
 				ctx->input = i_stream_create_lf(input);
-			maildir_save_add(_ctx, fname);
+			mf = maildir_save_add(_ctx, fname);
+			if (fname == _ctx->guid)
+				mf->preserve_filename = TRUE;
 		}
 	} T_END;
 
@@ -728,22 +732,31 @@ maildir_save_move_files_to_newcur(struct
 
 static void maildir_save_sync_uidlist(struct maildir_save_context *ctx)
 {
+	struct mailbox_transaction_context *t = ctx->ctx.transaction;
 	struct maildir_filename *mf;
+	struct seq_range_iter iter;
 	enum maildir_uidlist_rec_flag flags;
-	bool newdir;
+	unsigned int n = 0;
+	uint32_t uid;
+	bool newdir, bret;
 	int ret;
 
+	seq_range_array_iter_init(&iter, &t->changes->saved_uids);
 	for (mf = ctx->files; mf != NULL; mf = mf->next) T_BEGIN {
 		const char *dest;
+
+		bret = seq_range_array_iter_nth(&iter, n++, &uid);
+		i_assert(bret);
 
 		newdir = maildir_get_updated_filename(ctx, mf, &dest);
 		flags = MAILDIR_UIDLIST_REC_FLAG_RECENT;
 		if (newdir)
 			flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
-		ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
-						dest, flags);
+		ret = maildir_uidlist_sync_next_uid(ctx->uidlist_sync_ctx,
+						    dest, uid, flags);
 		i_assert(ret > 0);
 	} T_END;
+	i_assert(!seq_range_array_iter_nth(&iter, n, &uid));
 }
 
 int maildir_transaction_save_commit_pre(struct maildir_save_context *ctx)
diff -r fb8bc26d7194 -r be433e394f69 src/lib-storage/index/maildir/maildir-storage.h
--- a/src/lib-storage/index/maildir/maildir-storage.h	Mon Jul 27 19:00:56 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-storage.h	Mon Jul 27 19:02:12 2009 -0400
@@ -133,8 +133,8 @@ void maildir_save_cancel(struct mail_sav
 
 struct maildir_save_context *
 maildir_save_transaction_init(struct maildir_transaction_context *t);
-uint32_t maildir_save_add(struct mail_save_context *ctx,
-			  const char *base_fname);
+struct maildir_filename *
+maildir_save_add(struct mail_save_context *_ctx, const char *base_fname);
 const char *maildir_save_file_get_path(struct mailbox_transaction_context *t,
 				       uint32_t seq);
 
diff -r fb8bc26d7194 -r be433e394f69 src/lib-storage/index/maildir/maildir-uidlist.c
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Mon Jul 27 19:00:56 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Mon Jul 27 19:02:12 2009 -0400
@@ -110,7 +110,7 @@ struct maildir_uidlist_sync_ctx {
 	ARRAY_TYPE(maildir_uidlist_rec_p) records;
 	struct hash_table *files;
 
-	unsigned int first_unwritten_pos, first_nouid_pos;
+	unsigned int first_unwritten_pos, first_new_pos;
 	unsigned int new_files_count;
 	unsigned int finish_change_counter;
 
@@ -1551,7 +1551,7 @@ int maildir_uidlist_sync_init(struct mai
 		(sync_flags & MAILDIR_UIDLIST_SYNC_PARTIAL) != 0;
 	ctx->locked = locked;
 	ctx->first_unwritten_pos = (unsigned int)-1;
-	ctx->first_nouid_pos = (unsigned int)-1;
+	ctx->first_new_pos = (unsigned int)-1;
 
 	if (ctx->partial) {
 		if ((sync_flags & MAILDIR_UIDLIST_SYNC_KEEP_STATE) == 0) {
@@ -1574,7 +1574,7 @@ int maildir_uidlist_sync_init(struct mai
 
 static void
 maildir_uidlist_sync_next_partial(struct maildir_uidlist_sync_ctx *ctx,
-				  const char *filename,
+				  const char *filename, uint32_t uid,
 				  enum maildir_uidlist_rec_flag flags)
 {
 	struct maildir_uidlist *uidlist = ctx->uidlist;
@@ -1588,8 +1588,8 @@ maildir_uidlist_sync_next_partial(struct
 			/* we can't add it, so just ignore it */
 			return;
 		}
-		if (ctx->first_nouid_pos == (unsigned int)-1)
-			ctx->first_nouid_pos = array_count(&uidlist->records);
+		if (ctx->first_new_pos == (unsigned int)-1)
+			ctx->first_new_pos = array_count(&uidlist->records);
 		ctx->new_files_count++;
 		ctx->changed = TRUE;
 
@@ -1606,6 +1606,11 @@ maildir_uidlist_sync_next_partial(struct
 		array_append(&uidlist->records, &rec, 1);
 		uidlist->change_counter++;
 	}
+	if (uid != 0) {
+		rec->uid = uid;
+		if (uidlist->next_uid <= uid)
+			uidlist->next_uid = uid + 1;
+	}
 
 	rec->flags = (rec->flags | flags) & ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
 	rec->filename = p_strdup(uidlist->record_pool, filename);
@@ -1636,6 +1641,13 @@ int maildir_uidlist_sync_next(struct mai
 int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
 			      const char *filename,
 			      enum maildir_uidlist_rec_flag flags)
+{
+	return maildir_uidlist_sync_next_uid(ctx, filename, 0, flags);
+}
+
+int maildir_uidlist_sync_next_uid(struct maildir_uidlist_sync_ctx *ctx,
+				  const char *filename, uint32_t uid,
+				  enum maildir_uidlist_rec_flag flags)
 {
 	struct maildir_uidlist *uidlist = ctx->uidlist;
 	struct maildir_uidlist_rec *rec, *old_rec;
@@ -1656,7 +1668,7 @@ int maildir_uidlist_sync_next(struct mai
 	}
 
 	if (ctx->partial) {
-		maildir_uidlist_sync_next_partial(ctx, filename, flags);
+		maildir_uidlist_sync_next_partial(ctx, filename, uid, flags);
 		return 1;
 	}
 
@@ -1693,6 +1705,11 @@ int maildir_uidlist_sync_next(struct mai
 
 		array_append(&ctx->records, &rec, 1);
 	}
+	if (uid != 0) {
+		rec->uid = uid;
+		if (uidlist->next_uid <= uid)
+			uidlist->next_uid = uid + 1;
+	}
 
 	rec->flags = (rec->flags | flags) & ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED;
 	rec->filename = p_strdup(ctx->record_pool, filename);
@@ -1720,9 +1737,9 @@ void maildir_uidlist_sync_remove(struct 
 		i_assert(ctx->first_unwritten_pos > idx);
 		ctx->first_unwritten_pos--;
 	}
-	if (ctx->first_nouid_pos != (unsigned int)-1) {
-		i_assert(ctx->first_nouid_pos > idx);
-		ctx->first_nouid_pos--;
+	if (ctx->first_new_pos != (unsigned int)-1) {
+		i_assert(ctx->first_new_pos > idx);
+		ctx->first_new_pos--;
 	}
 
 	ctx->changed = TRUE;
@@ -1762,10 +1779,16 @@ maildir_uidlist_get_full_filename(struct
 	return rec == NULL ? NULL : rec->filename;
 }
 
-static int maildir_time_cmp(const void *p1, const void *p2)
+static int maildir_assign_uid_cmp(const void *p1, const void *p2)
 {
 	const struct maildir_uidlist_rec *const *rec1 = p1, *const *rec2 = p2;
 
+	if ((*rec1)->uid != (*rec2)->uid) {
+		if ((*rec1)->uid < (*rec2)->uid)
+			return -1;
+		else
+			return 1;
+	}
 	return maildir_filename_sort_cmp((*rec1)->filename, (*rec2)->filename);
 }
 
@@ -1775,17 +1798,22 @@ static void maildir_uidlist_assign_uids(
 	unsigned int dest, count;
 
 	i_assert(UIDLIST_ALLOW_WRITING(ctx->uidlist));
-	i_assert(ctx->first_nouid_pos != (unsigned int)-1);
+	i_assert(ctx->first_new_pos != (unsigned int)-1);
 
 	if (ctx->first_unwritten_pos == (unsigned int)-1)
-		ctx->first_unwritten_pos = ctx->first_nouid_pos;
+		ctx->first_unwritten_pos = ctx->first_new_pos;
 
 	/* sort new files and assign UIDs for them */
 	recs = array_get_modifiable(&ctx->uidlist->records, &count);
-	qsort(recs + ctx->first_nouid_pos, count - ctx->first_nouid_pos,
-	      sizeof(*recs), maildir_time_cmp);
-
-	for (dest = ctx->first_nouid_pos; dest < count; dest++) {
+	qsort(recs + ctx->first_new_pos, count - ctx->first_new_pos,
+	      sizeof(*recs), maildir_assign_uid_cmp);
+
+	for (dest = ctx->first_new_pos; dest < count; dest++) {
+		if (recs[dest]->uid == (uint32_t)-1)
+			break;
+	}
+
+	for (; dest < count; dest++) {
 		i_assert(recs[dest]->uid == (uint32_t)-1);
 		i_assert(ctx->uidlist->next_uid < (uint32_t)-1);
 		recs[dest]->uid = ctx->uidlist->next_uid++;
@@ -1796,7 +1824,7 @@ static void maildir_uidlist_assign_uids(
 		ctx->uidlist->last_seen_uid = ctx->uidlist->next_uid-1;
 
 	ctx->new_files_count = 0;
-	ctx->first_nouid_pos = (unsigned int)-1;
+	ctx->first_new_pos = (unsigned int)-1;
 	ctx->uidlist->change_counter++;
 	ctx->finish_change_counter = ctx->uidlist->change_counter;
 }
@@ -1822,7 +1850,7 @@ static void maildir_uidlist_swap(struct 
 	ctx->record_pool = NULL;
 
 	if (ctx->new_files_count != 0) {
-		ctx->first_nouid_pos = array_count(&uidlist->records) -
+		ctx->first_new_pos = array_count(&uidlist->records) -
 			ctx->new_files_count;
 		maildir_uidlist_assign_uids(ctx);
 	} else {
diff -r fb8bc26d7194 -r be433e394f69 src/lib-storage/index/maildir/maildir-uidlist.h
--- a/src/lib-storage/index/maildir/maildir-uidlist.h	Mon Jul 27 19:00:56 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-uidlist.h	Mon Jul 27 19:02:12 2009 -0400
@@ -110,6 +110,9 @@ int maildir_uidlist_sync_next(struct mai
 int maildir_uidlist_sync_next(struct maildir_uidlist_sync_ctx *ctx,
 			      const char *filename,
 			      enum maildir_uidlist_rec_flag flags);
+int maildir_uidlist_sync_next_uid(struct maildir_uidlist_sync_ctx *ctx,
+				  const char *filename, uint32_t uid,
+				  enum maildir_uidlist_rec_flag flags);
 void maildir_uidlist_sync_remove(struct maildir_uidlist_sync_ctx *ctx,


More information about the dovecot-cvs mailing list