changeset 3209:923ff19873d4 HEAD

Major mail-storage API changes. It's now a bit cleaner and much more plugin friendly. Removed proxy_mailbox* stuff, they were difficult to use and there's now much easier way to replace them.
author Timo Sirainen <tss@iki.fi>
date Tue, 15 Mar 2005 21:01:50 +0200
parents b5fd010a4454
children 2715077f9c3e
files src/deliver/deliver.c src/imap/cmd-append.c src/imap/cmd-copy.c src/imap/cmd-search.c src/imap/cmd-store.c src/imap/common.h src/imap/imap-expunge.c src/imap/imap-fetch-body.c src/imap/imap-fetch.c src/imap/imap-fetch.h src/imap/imap-sort.c src/imap/imap-sync.c src/imap/imap-thread.c src/imap/main.c src/imap/namespace.c src/lib-storage/Makefile.am src/lib-storage/index/index-fetch.c src/lib-storage/index/index-mail-headers.c src/lib-storage/index/index-mail.c src/lib-storage/index/index-mail.h src/lib-storage/index/index-search.c src/lib-storage/index/index-storage.c src/lib-storage/index/index-storage.h src/lib-storage/index/index-transaction.c src/lib-storage/index/maildir/maildir-copy.c src/lib-storage/index/maildir/maildir-mail.c src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/maildir/maildir-storage.h src/lib-storage/index/maildir/maildir-transaction.c src/lib-storage/index/mbox/mbox-mail.c src/lib-storage/index/mbox/mbox-save.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/index/mbox/mbox-storage.h src/lib-storage/index/mbox/mbox-transaction.c src/lib-storage/mail-copy.c src/lib-storage/mail-copy.h src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/lib-storage/mail.c src/lib-storage/proxy-mail-storage.c src/lib-storage/proxy-mail-storage.h src/lib-storage/proxy-mail.c src/lib-storage/proxy-mail.h src/lib-storage/proxy-mailbox.c src/lib-storage/proxy-mailbox.h src/pop3/client.c src/pop3/commands.c
diffstat 49 files changed, 906 insertions(+), 1212 deletions(-) [+]
line wrap: on
line diff
--- a/src/deliver/deliver.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/deliver/deliver.c	Tue Mar 15 21:01:50 2005 +0200
@@ -93,7 +93,7 @@
 		return FALSE;
 	}
 
-	t = mailbox_transaction_begin(box, FALSE);
+	t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL);
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.ret = -1;
--- a/src/imap/cmd-append.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/cmd-append.c	Tue Mar 15 21:01:50 2005 +0200
@@ -396,7 +396,8 @@
 					     status.keywords_count);
 		}
 		ctx->t = ctx->box == NULL ? NULL :
-			mailbox_transaction_begin(ctx->box, FALSE);
+			mailbox_transaction_begin(ctx->box,
+				MAILBOX_TRANSACTION_FLAG_EXTERNAL);
 	}
 
 	io_remove(client->io);
--- a/src/imap/cmd-copy.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/cmd-copy.c	Tue Mar 15 21:01:50 2005 +0200
@@ -12,22 +12,15 @@
 	struct mail_search_context *search_ctx;
         struct mailbox_transaction_context *src_trans;
 	struct mail *mail;
-	string_t *dest_str;
 	int ret;
 
-	src_trans = mailbox_transaction_begin(srcbox, FALSE);
-	search_ctx = mailbox_search_init(src_trans, NULL, search_args, NULL,
-					 MAIL_FETCH_STREAM_HEADER |
-					 MAIL_FETCH_STREAM_BODY, NULL);
-	if (search_ctx == NULL) {
-		mailbox_transaction_rollback(src_trans);
-		return -1;
-	}
+	src_trans = mailbox_transaction_begin(srcbox, 0);
+	search_ctx = mailbox_search_init(src_trans, NULL, search_args, NULL);
 
-	dest_str = t_str_new(128);
-
+	mail = mail_alloc(src_trans, MAIL_FETCH_STREAM_HEADER |
+			  MAIL_FETCH_STREAM_BODY, NULL);
 	ret = 1;
-	while ((mail = mailbox_search_next(search_ctx)) != NULL) {
+	while (mailbox_search_next(search_ctx, mail) > 0) {
 		if (mail->expunged) {
 			ret = 0;
 			break;
@@ -36,8 +29,8 @@
 			ret = -1;
 			break;
 		}
-
 	}
+	mail_free(mail);
 
 	if (mailbox_search_deinit(search_ctx) < 0)
 		ret = -1;
@@ -89,7 +82,8 @@
 		}
 	}
 
-	t = mailbox_transaction_begin(destbox, FALSE);
+	t = mailbox_transaction_begin(destbox,
+				      MAILBOX_TRANSACTION_FLAG_EXTERNAL);
 	ret = fetch_and_copy(t, client->mailbox, search_arg);
 
 	if (ret <= 0)
--- a/src/imap/cmd-search.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/cmd-search.c	Tue Mar 15 21:01:50 2005 +0200
@@ -14,23 +14,23 @@
 	struct client *client = cmd->client;
         struct mail_search_context *ctx;
         struct mailbox_transaction_context *trans;
-	const struct mail *mail;
+	struct mail *mail;
 	string_t *str;
 	int ret, uid, first = TRUE;
 
 	str = t_str_new(STRBUF_SIZE);
 	uid = cmd->uid;
 
-	trans = mailbox_transaction_begin(client->mailbox, FALSE);
-	ctx = mailbox_search_init(trans, charset, sargs,
-				  NULL, 0, NULL);
+	trans = mailbox_transaction_begin(client->mailbox, 0);
+	ctx = mailbox_search_init(trans, charset, sargs, NULL);
 	if (ctx == NULL) {
 		mailbox_transaction_rollback(trans);
 		return FALSE;
 	}
 
 	str_append(str, "* SEARCH");
-	while ((mail = mailbox_search_next(ctx)) != NULL) {
+	mail = mail_alloc(trans, 0, NULL);
+	while ((ret = mailbox_search_next(ctx, mail)) > 0) {
 		if (str_len(str) >= STRBUF_SIZE-MAX_INT_STRLEN) {
 			/* flush */
 			o_stream_send(client->output,
@@ -41,6 +41,7 @@
 
 		str_printfa(str, " %u", uid ? mail->uid : mail->seq);
 	}
+	mail_free(mail);
 
 	ret = mailbox_search_deinit(ctx);
 
--- a/src/imap/cmd-store.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/cmd-store.c	Tue Mar 15 21:01:50 2005 +0200
@@ -85,28 +85,30 @@
 	if (search_arg == NULL)
 		return TRUE;
 
-	t = mailbox_transaction_begin(box, silent);
+	t = mailbox_transaction_begin(box, !silent ? 0 :
+				      MAILBOX_TRANSACTION_FLAG_HIDE);
 	keywords = keywords_list != NULL || modify_type == MODIFY_REPLACE ?
 		mailbox_keywords_create(t, keywords_list) : NULL;
-	search_ctx = mailbox_search_init(t, NULL, search_arg, NULL,
-					 MAIL_FETCH_FLAGS, NULL);
+	search_ctx = mailbox_search_init(t, NULL, search_arg, NULL);
 
 	failed = FALSE;
-	while ((mail = mailbox_search_next(search_ctx)) != NULL) {
+	mail = mail_alloc(t, MAIL_FETCH_FLAGS, NULL);
+	while (mailbox_search_next(search_ctx, mail) > 0) {
 		if (modify_type == MODIFY_REPLACE || flags != 0) {
-			if (mail->update_flags(mail, modify_type, flags) < 0) {
+			if (mail_update_flags(mail, modify_type, flags) < 0) {
 				failed = TRUE;
 				break;
 			}
 		}
 		if (modify_type == MODIFY_REPLACE || keywords != NULL) {
-			if (mail->update_keywords(mail, modify_type,
-						  keywords) < 0) {
+			if (mail_update_keywords(mail, modify_type,
+						 keywords) < 0) {
 				failed = TRUE;
 				break;
 			}
 		}
 	}
+	mail_free(mail);
 
 	if (keywords != NULL)
 		mailbox_keywords_free(t, keywords);
--- a/src/imap/common.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/common.h	Tue Mar 15 21:01:50 2005 +0200
@@ -37,7 +37,7 @@
 
 extern string_t *capability_string;
 
-extern void (*hook_mail_storage_created)(struct mail_storage **storage);
+extern void (*hook_mail_storage_created)(struct mail_storage *storage);
 extern void (*hook_client_created)(struct client **client);
 
 #endif
--- a/src/imap/imap-expunge.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/imap-expunge.c	Tue Mar 15 21:01:50 2005 +0200
@@ -18,17 +18,19 @@
 	search_arg.type = SEARCH_DELETED;
 	search_arg.next = next_search_arg;
 
-	t = mailbox_transaction_begin(box, FALSE);
-	ctx = mailbox_search_init(t, NULL, &search_arg, NULL, 0, NULL);
+	t = mailbox_transaction_begin(box, 0);
+	ctx = mailbox_search_init(t, NULL, &search_arg, NULL);
 	if (ctx == NULL)
 		failed = TRUE;
 	else {
-		while ((mail = mailbox_search_next(ctx)) != NULL) {
-			if (mail->expunge(mail) < 0) {
+		mail = mail_alloc(t, 0, NULL);
+		while (mailbox_search_next(ctx, mail) > 0) {
+			if (mail_expunge(mail) < 0) {
 				failed = TRUE;
 				break;
 			}
 		}
+		mail_free(mail);
 	}
 
 	if (mailbox_search_deinit(ctx) < 0)
--- a/src/imap/imap-fetch-body.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/imap-fetch-body.c	Tue Mar 15 21:01:50 2005 +0200
@@ -304,8 +304,8 @@
 	struct message_size hdr_size, body_size;
 
 	ctx->cur_input =
-		mail->get_stream(mail, &hdr_size,
-				 body->section[0] == 'H' ? NULL : &body_size);
+		mail_get_stream(mail, &hdr_size,
+				body->section[0] == 'H' ? NULL : &body_size);
 	if (ctx->cur_input == NULL)
 		return -1;
 
@@ -419,7 +419,7 @@
 {
 	const struct imap_fetch_body_data *body = context;
 
-	ctx->cur_input = mail->get_stream(mail, NULL, NULL);
+	ctx->cur_input = mail_get_stream(mail, NULL, NULL);
 	if (ctx->cur_input == NULL)
 		return -1;
 
@@ -436,7 +436,7 @@
 	struct message_size size;
 	uoff_t old_offset;
 
-	ctx->cur_input = mail->get_headers(mail, body->header_ctx);
+	ctx->cur_input = mail_get_headers(mail, body->header_ctx);
 	if (ctx->cur_input == NULL)
 		return -1;
 
@@ -463,7 +463,7 @@
 	const char *path;
 	unsigned int num;
 
-	part = mail->get_parts(mail);
+	part = mail_get_parts(mail);
 	if (part == NULL)
 		return -1;
 
@@ -526,7 +526,7 @@
 		return 1;
 	}
 
-	ctx->cur_input = mail->get_stream(mail, NULL, NULL);
+	ctx->cur_input = mail_get_stream(mail, NULL, NULL);
 	if (ctx->cur_input == NULL)
 		return -1;
 
@@ -831,7 +831,7 @@
 {
 	uoff_t size;
 
-	size = mail->get_virtual_size(mail);
+	size = mail_get_virtual_size(mail);
 	if (size == (uoff_t)-1)
 		return -1;
 
@@ -845,7 +845,7 @@
 	struct message_size hdr_size, body_size;
 	const char *str;
 
-	ctx->cur_input = mail->get_stream(mail, &hdr_size, &body_size);
+	ctx->cur_input = mail_get_stream(mail, &hdr_size, &body_size);
 	if (ctx->cur_input == NULL)
 		return -1;
 
@@ -874,7 +874,7 @@
 	struct message_size hdr_size;
 	const char *str;
 
-	ctx->cur_input = mail->get_stream(mail, &hdr_size, NULL);
+	ctx->cur_input = mail_get_stream(mail, &hdr_size, NULL);
 	if (ctx->cur_input == NULL)
 		return -1;
 
@@ -899,7 +899,7 @@
 	struct message_size hdr_size, body_size;
 	const char *str;
 
-	ctx->cur_input = mail->get_stream(mail, &hdr_size, &body_size);
+	ctx->cur_input = mail_get_stream(mail, &hdr_size, &body_size);
 	if (ctx->cur_input == NULL)
 		return -1;
 
--- a/src/imap/imap-fetch.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/imap-fetch.c	Tue Mar 15 21:01:50 2005 +0200
@@ -149,11 +149,13 @@
 			mailbox_header_lookup_init(ctx->box, data);
 	}
 
-	ctx->trans = mailbox_transaction_begin(ctx->box, TRUE);
+	ctx->trans = mailbox_transaction_begin(ctx->box,
+		MAILBOX_TRANSACTION_FLAG_HIDE);
 	ctx->select_counter = ctx->client->select_counter;
+	ctx->mail = mail_alloc(ctx->trans, ctx->fetch_data,
+			       ctx->all_headers_ctx);
 	ctx->search_ctx =
-		mailbox_search_init(ctx->trans, NULL, search_arg, NULL,
-				    ctx->fetch_data, ctx->all_headers_ctx);
+		mailbox_search_init(ctx->trans, NULL, search_arg, NULL);
 }
 
 int imap_fetch(struct imap_fetch_context *ctx)
@@ -199,9 +201,10 @@
                                 ctx->cur_input = NULL;
 			}
 
-			ctx->cur_mail = mailbox_search_next(ctx->search_ctx);
-			if (ctx->cur_mail == NULL)
+			if (mailbox_search_next(ctx->search_ctx,
+						ctx->mail) <= 0)
 				break;
+			ctx->cur_mail = ctx->mail;
 
 			str_printfa(ctx->cur_str, "* %u FETCH (",
 				    ctx->cur_mail->seq);
@@ -275,6 +278,9 @@
 		ctx->cur_input = NULL;
 	}
 
+	if (ctx->mail != NULL)
+		mail_free(ctx->mail);
+
 	if (ctx->search_ctx != NULL) {
 		if (mailbox_search_deinit(ctx->search_ctx) < 0)
 			ctx->failed = TRUE;
@@ -298,7 +304,7 @@
 {
 	const char *body;
 
-	body = mail->get_special(mail, MAIL_FETCH_IMAP_BODY);
+	body = mail_get_special(mail, MAIL_FETCH_IMAP_BODY);
 	if (body == NULL)
 		return -1;
 
@@ -332,7 +338,7 @@
 {
 	const char *bodystructure;
 
-	bodystructure = mail->get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE);
+	bodystructure = mail_get_special(mail, MAIL_FETCH_IMAP_BODYSTRUCTURE);
 	if (bodystructure == NULL)
 		return -1;
 
@@ -365,7 +371,7 @@
 {
 	const char *envelope;
 
-	envelope = mail->get_special(mail, MAIL_FETCH_IMAP_ENVELOPE);
+	envelope = mail_get_special(mail, MAIL_FETCH_IMAP_ENVELOPE);
 	if (envelope == NULL)
 		return -1;
 
@@ -398,13 +404,13 @@
 	enum mail_flags flags;
 	const char *const *keywords;
 
-	flags = mail->get_flags(mail);
-	keywords = mail->get_keywords(mail);
+	flags = mail_get_flags(mail);
+	keywords = mail_get_keywords(mail);
 
 	if (ctx->flags_update_seen && (flags & MAIL_SEEN) == 0) {
 		/* Add \Seen flag */
 		flags |= MAIL_SEEN;
-		if (mail->update_flags(mail, MODIFY_ADD, MAIL_SEEN) < 0)
+		if (mail_update_flags(mail, MODIFY_ADD, MAIL_SEEN) < 0)
 			return -1;
 	} else if (ctx->flags_show_only_seen_changes) {
 		return 1;
@@ -431,7 +437,7 @@
 {
 	time_t time;
 
-	time = mail->get_received_date(mail);
+	time = mail_get_received_date(mail);
 	if (time == (time_t)-1)
 		return -1;
 
--- a/src/imap/imap-fetch.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/imap-fetch.h	Tue Mar 15 21:01:50 2005 +0200
@@ -28,6 +28,7 @@
 
 	struct mailbox_transaction_context *trans;
 	struct mail_search_context *search_ctx;
+	struct mail *mail;
 
 	enum mail_fetch_field fetch_data;
 	buffer_t *all_headers_buf;
--- a/src/imap/imap-sort.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/imap-sort.c	Tue Mar 15 21:01:50 2005 +0200
@@ -30,6 +30,7 @@
 struct sort_context {
 	struct mail_search_context *search_ctx;
 	struct mailbox_transaction_context *t;
+	struct mail *other_mail;
 
 	enum mail_sort_type sort_program[MAX_SORT_PROGRAM_SIZE];
 	enum mail_sort_type common_mask, cache_mask;
@@ -228,15 +229,9 @@
 						 wanted_headers);
 
 	/* initialize searching */
-	ctx->t = mailbox_transaction_begin(client->mailbox, FALSE);
-	ctx->search_ctx =
-		mailbox_search_init(ctx->t, charset, args, norm_prog,
-				    wanted_fields, headers_ctx);
-	if (ctx->search_ctx == NULL) {
-		mailbox_transaction_rollback(ctx->t);
-		mailbox_header_lookup_deinit(headers_ctx);
-		return -1;
-	}
+	ctx->t = mailbox_transaction_begin(client->mailbox, 0);
+	ctx->search_ctx = mailbox_search_init(ctx->t, charset, args, norm_prog);
+	ctx->other_mail = mail_alloc(ctx->t, wanted_fields, headers_ctx);
 
 	ctx->box = client->mailbox;
 	ctx->output = client->output;
@@ -248,9 +243,13 @@
 
         ctx->id_is_uid = cmd->uid;
 
-	while ((mail = mailbox_search_next(ctx->search_ctx)) != NULL)
+	mail = mail_alloc(ctx->t, wanted_fields, headers_ctx);
+	while (mailbox_search_next(ctx->search_ctx, mail) > 0)
 		mail_sort_input(ctx, mail);
 
+	mail_free(mail);
+	mail_free(ctx->other_mail);
+
 	mail_sort_flush(ctx);
 	ret = mailbox_search_deinit(ctx->search_ctx);
 
@@ -291,7 +290,7 @@
 	struct message_address *addr;
 	const char *str;
 
-	str = mail->get_header(mail, field);
+	str = mail_get_header(mail, field);
 	if (str == NULL)
 		return NULL;
 
@@ -309,7 +308,7 @@
 	int changed = FALSE;
 
 	if (ctx->common_mask & MAIL_SORT_ARRIVAL) {
-		t = mail->get_received_date(mail);
+		t = mail_get_received_date(mail);
 		if (t != ctx->last_arrival) {
 			ctx->last_arrival = t;
 			changed = TRUE;
@@ -329,7 +328,7 @@
 	}
 
 	if (ctx->common_mask & MAIL_SORT_DATE) {
-		t = mail->get_date(mail, NULL);
+		t = mail_get_date(mail, NULL);
 		if (t != ctx->last_date) {
 			ctx->last_date = t;
 			changed = TRUE;
@@ -349,7 +348,7 @@
 	}
 
 	if (ctx->common_mask & MAIL_SORT_SIZE) {
-		size = mail->get_virtual_size(mail);
+		size = mail_get_virtual_size(mail);
 		if (size != ctx->last_size) {
 			ctx->last_size = size;
 			changed = TRUE;
@@ -357,7 +356,7 @@
 	}
 
 	if (ctx->common_mask & MAIL_SORT_SUBJECT) {
-		str = mail->get_header(mail, "subject");
+		str = mail_get_header(mail, "subject");
 		if (str != NULL) {
 			str = imap_get_base_subject_cased(
 				pool_datastack_create(), str, NULL);
@@ -409,7 +408,7 @@
 		if (ctx->common_mask & MAIL_SORT_ARRIVAL)
 			t = ctx->last_arrival;
 		else
-			t = mail->get_received_date(mail);
+			t = mail_get_received_date(mail);
 		memcpy(buf + pos, &t, sizeof(t)); pos += sizeof(t);
 	}
 
@@ -417,7 +416,7 @@
 		if (ctx->common_mask & MAIL_SORT_DATE)
 			t = ctx->last_date;
 		else
-			t = mail->get_date(mail, NULL);
+			t = mail_get_date(mail, NULL);
 		memcpy(buf + pos, &t, sizeof(t)); pos += sizeof(t);
 	}
 
@@ -425,7 +424,7 @@
 		if (ctx->common_mask & MAIL_SORT_SIZE)
 			size = ctx->last_size;
 		else
-			size = mail->get_virtual_size(mail);
+			size = mail_get_virtual_size(mail);
 
 		memcpy(buf + pos, &size, sizeof(size)); pos += sizeof(size);
 	}
@@ -476,7 +475,7 @@
 		if (ctx->common_mask & MAIL_SORT_SUBJECT)
 			str = ctx->last_subject;
 		else {
-			str = mail->get_header(mail, "subject");
+			str = mail_get_header(mail, "subject");
 
 			if (str != NULL) {
 				str = imap_get_base_subject_cased(
@@ -507,7 +506,10 @@
 		if (mailbox_get_uids(ctx->box, id, id, &seq, &seq) < 0)
 			return NULL;
 	}
-	return mailbox_fetch(ctx->t, seq, 0);
+
+	if (mail_set_seq(ctx->other_mail, seq) < 0)
+		return NULL;
+	return ctx->other_mail;
 
 }
 
@@ -524,9 +526,9 @@
 
 		switch (type) {
 		case MAIL_SORT_ARRIVAL:
-			return mail->get_received_date(mail);
+			return mail_get_received_date(mail);
 		case MAIL_SORT_DATE:
-			t = mail->get_date(mail, NULL);
+			t = mail_get_date(mail, NULL);
 			if (t == (time_t)-1)
 				t = 0;
 			return t;
@@ -554,7 +556,7 @@
 
 		i_assert(type == MAIL_SORT_SIZE);
 
-		return mail->get_virtual_size(mail);
+		return mail_get_virtual_size(mail);
 	}
 
 	/* use memcpy() to avoid any alignment problems */
@@ -578,7 +580,7 @@
 
 		switch (type) {
 		case MAIL_SORT_SUBJECT:
-			str = mail->get_header(mail, "subject");
+			str = mail_get_header(mail, "subject");
 			if (str == NULL)
 				return NULL;
 
--- a/src/imap/imap-sync.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/imap-sync.c	Tue Mar 15 21:01:50 2005 +0200
@@ -18,6 +18,7 @@
 
 	struct mailbox_transaction_context *t;
 	struct mailbox_sync_context *sync_ctx;
+	struct mail *mail;
 
 	struct mailbox_sync_rec sync_rec;
 	uint32_t seq;
@@ -40,7 +41,8 @@
 	ctx->box = box;
 
 	ctx->sync_ctx = mailbox_sync_init(box, flags);
-	ctx->t = mailbox_transaction_begin(box, FALSE);
+	ctx->t = mailbox_transaction_begin(box, 0);
+	ctx->mail = mail_alloc(ctx->t, MAIL_FETCH_FLAGS, 0);
 	ctx->messages_count = client->messages_count;
 	return ctx;
 }
@@ -49,6 +51,8 @@
 {
 	struct mailbox_status status;
 
+	mail_free(ctx->mail);
+
 	if (mailbox_sync_deinit(ctx->sync_ctx, &status) < 0 || ctx->failed) {
 		mailbox_transaction_rollback(ctx->t);
 		i_free(ctx);
@@ -80,7 +84,6 @@
 
 int imap_sync_more(struct imap_sync_context *ctx)
 {
-	struct mail *mail;
 	enum mail_flags flags;
 	const char *const *keywords;
 	string_t *str;
@@ -110,11 +113,13 @@
 				ctx->seq = ctx->sync_rec.seq1;
 
 			for (; ctx->seq <= ctx->sync_rec.seq2; ctx->seq++) {
-				mail = mailbox_fetch(ctx->t, ctx->seq,
-						     MAIL_FETCH_FLAGS);
+				if (mail_set_seq(ctx->mail, ctx->seq) < 0) {
+					t_pop();
+					return -1;
+				}
 
-				flags = mail->get_flags(mail);
-				keywords = mail->get_keywords(mail);
+				flags = mail_get_flags(ctx->mail);
+				keywords = mail_get_keywords(ctx->mail);
 
 				str_truncate(str, 0);
 				str_printfa(str, "* %u FETCH (FLAGS (",
--- a/src/imap/imap-thread.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/imap-thread.c	Tue Mar 15 21:01:50 2005 +0200
@@ -73,6 +73,7 @@
 	struct mailbox_transaction_context *t;
 	struct mailbox *box;
 	struct ostream *output;
+	struct mail *mail;
 
 	pool_t pool;
 	pool_t temp_pool;
@@ -117,19 +118,10 @@
 		i_fatal("Only REFERENCES threading supported");
 
 	ctx = t_new(struct thread_context, 1);
-	headers_ctx = mailbox_header_lookup_init(client->mailbox,
-						 wanted_headers);
 
 	/* initialize searching */
-	ctx->t = mailbox_transaction_begin(client->mailbox, FALSE);
-	ctx->search_ctx =
-		mailbox_search_init(ctx->t, charset, args, NULL,
-				    MAIL_FETCH_DATE, headers_ctx);
-	if (ctx->search_ctx == NULL) {
-		mailbox_transaction_rollback(ctx->t);
-		mailbox_header_lookup_deinit(headers_ctx);
-		return -1;
-	}
+	ctx->t = mailbox_transaction_begin(client->mailbox, 0);
+	ctx->search_ctx = mailbox_search_init(ctx->t, charset, args, NULL);
 
 	ctx->box = client->mailbox;
 	ctx->output = client->output;
@@ -142,11 +134,16 @@
 	ctx->msgid_hash = hash_create(default_pool, ctx->temp_pool,
 				      APPROX_MSG_COUNT*2, str_hash,
 				      (hash_cmp_callback_t *)strcmp);
+	ctx->id_is_uid = cmd->uid;
 
-	ctx->id_is_uid = cmd->uid;
-	while ((mail = mailbox_search_next(ctx->search_ctx)) != NULL)
+	headers_ctx = mailbox_header_lookup_init(client->mailbox,
+						 wanted_headers);
+	mail = mail_alloc(ctx->t, MAIL_FETCH_DATE, headers_ctx);
+	while (mailbox_search_next(ctx->search_ctx, mail) > 0)
 		mail_thread_input(ctx, mail);
 
+	mail_free(mail);
+
 	o_stream_send_str(client->output, "* THREAD");
 	mail_thread_finish(ctx);
 	o_stream_send_str(client->output, "\r\n");
@@ -447,18 +444,18 @@
 
 	t_push();
 
-	sent_date = mail->get_date(mail, NULL);
+	sent_date = mail_get_date(mail, NULL);
 	if (sent_date == (time_t)-1)
 		sent_date = 0;
 
-	message_id = mail->get_header(mail, "message-id");
+	message_id = mail_get_header(mail, "message-id");
 	node = update_message(ctx, get_msgid(&message_id), sent_date,
 			      ctx->id_is_uid ? mail->uid : mail->seq);
 
 	/* link references */
-	references = mail->get_header(mail, "references");
+	references = mail_get_header(mail, "references");
 	if (!link_references(ctx, node, references)) {
-		in_reply_to = mail->get_header(mail, "in-reply-to");
+		in_reply_to = mail_get_header(mail, "in-reply-to");
 		refid = in_reply_to == NULL ? NULL : get_msgid(&in_reply_to);
 
 		if (refid != NULL)
@@ -661,8 +658,10 @@
 
 static void gather_base_subjects(struct thread_context *ctx)
 {
-	struct mail *mail;
+	static const char *wanted_headers[] = { "subject", NULL };
+	struct mailbox_header_lookup_ctx *headers_ctx;
 	struct node *node;
+	const char *subject;
 	unsigned int id;
 	uint32_t seq;
 
@@ -670,6 +669,9 @@
 		hash_create(default_pool, ctx->temp_pool, ctx->root_count * 2,
 			    str_hash, (hash_cmp_callback_t *)strcmp);
 
+	headers_ctx = mailbox_header_lookup_init(ctx->box, wanted_headers);
+	ctx->mail = mail_alloc(ctx->t, 0, headers_ctx);
+
 	node = ctx->root_node.first_child;
 	for (; node != NULL; node = node->next) {
 		if (!NODE_IS_DUMMY(node))
@@ -689,15 +691,16 @@
 				seq = 0;
 		}
 
-		mail = seq == 0 ? NULL : mailbox_fetch(ctx->t, seq, 0);
-
-		if (mail != NULL) {
+		if (seq != 0 && mail_set_seq(ctx->mail, seq) == 0) {
 			t_push();
-			add_base_subject(ctx, mail->get_header(mail, "subject"),
-					 node);
+                        subject = mail_get_header(ctx->mail, "subject");
+			add_base_subject(ctx, subject, node);
 			t_pop();
 		}
 	}
+
+	mail_free(ctx->mail);
+	mailbox_header_lookup_deinit(headers_ctx);
 }
 
 static void reset_children_parent(struct node *parent)
--- a/src/imap/main.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/main.c	Tue Mar 15 21:01:50 2005 +0200
@@ -45,7 +45,7 @@
 static char log_prefix[128]; /* syslog() needs this to be permanent */
 static pool_t namespace_pool;
 
-void (*hook_mail_storage_created)(struct mail_storage **storage) = NULL;
+void (*hook_mail_storage_created)(struct mail_storage *storage) = NULL;
 void (*hook_client_created)(struct client **client) = NULL;
 
 string_t *capability_string;
--- a/src/imap/namespace.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/imap/namespace.c	Tue Mar 15 21:01:50 2005 +0200
@@ -22,7 +22,7 @@
 	}
 
 	if (hook_mail_storage_created != NULL)
-		hook_mail_storage_created(&ns->storage);
+		hook_mail_storage_created(ns->storage);
 }
 
 static struct namespace *
--- a/src/lib-storage/Makefile.am	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/Makefile.am	Tue Mar 15 21:01:50 2005 +0200
@@ -8,20 +8,15 @@
 	-I$(top_srcdir)/src/lib-imap
 
 libstorage_a_SOURCES = \
+	mail.c \
 	mail-copy.c \
 	mail-search.c \
 	mail-storage.c \
-	mailbox-tree.c \
-	proxy-mail.c \
-	proxy-mail-storage.c \
-	proxy-mailbox.c
+	mailbox-tree.c
 
 noinst_HEADERS = \
 	mail-copy.h \
 	mail-search.h \
 	mail-storage.h \
 	mail-storage-private.h \
-	mailbox-tree.h \
-	proxy-mail.h \
-	proxy-mail-storage.h \
-	proxy-mailbox.h
+	mailbox-tree.h
--- a/src/lib-storage/index/index-fetch.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/index-fetch.c	Tue Mar 15 21:01:50 2005 +0200
@@ -4,22 +4,6 @@
 #include "index-storage.h"
 #include "index-mail.h"
 
-struct mail *
-index_storage_fetch(struct mailbox_transaction_context *_t, uint32_t seq,
-		    enum mail_fetch_field wanted_fields)
-{
-	struct index_transaction_context *t =
-		(struct index_transaction_context *)_t;
-
-	if (t->fetch_mail.pool != NULL)
-		index_mail_deinit(&t->fetch_mail);
-
-	index_mail_init(t, &t->fetch_mail, wanted_fields, NULL);
-	if (index_mail_next(&t->fetch_mail, seq) < 0)
-		return NULL;
-	return &t->fetch_mail.mail;
-}
-
 int index_storage_get_uids(struct mailbox *box,
 			   uint32_t uid1, uint32_t uid2,
 			   uint32_t *seq1_r, uint32_t *seq2_r)
--- a/src/lib-storage/index/index-mail-headers.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/index-mail-headers.c	Tue Mar 15 21:01:50 2005 +0200
@@ -163,7 +163,7 @@
 {
 	string_t *str;
 
-	str = str_new(mail->pool, 256);
+	str = str_new(mail->data_pool, 256);
 	imap_envelope_write_part_data(mail->data.envelope_data, str);
 	mail->data.envelope = str_c(str);
 
@@ -187,11 +187,11 @@
 
 	if (data->save_bodystructure_header) {
 		i_assert(part != NULL);
-		imap_bodystructure_parse_header(mail->pool, part, hdr);
+		imap_bodystructure_parse_header(mail->data_pool, part, hdr);
 	}
 
 	if (data->save_envelope) {
-		imap_envelope_parse_header(mail->pool,
+		imap_envelope_parse_header(mail->data_pool,
 					   &data->envelope_data, hdr);
 
 		if (hdr == NULL)
@@ -313,7 +313,7 @@
 {
 	struct index_mail_data *data = &mail->data;
 
-	if (mail->mail.get_stream(&mail->mail, NULL, NULL) == NULL)
+	if (mail_get_stream(&mail->mail.mail, NULL, NULL) == NULL)
 		return -1;
 
 	index_mail_parse_header_init(mail, headers);
@@ -322,7 +322,7 @@
 		/* initialize bodystructure parsing in case we read the whole
 		   message. */
 		data->parser_ctx =
-			message_parser_init(mail->pool, data->stream);
+			message_parser_init(mail->data_pool, data->stream);
 		message_parser_parse_header(data->parser_ctx, &data->hdr_size,
 					    index_mail_parse_header_cb, mail);
 	} else {
@@ -342,7 +342,8 @@
 {
 	struct index_mail *mail = context;
 
-	imap_envelope_parse_header(mail->pool, &mail->data.envelope_data, hdr);
+	imap_envelope_parse_header(mail->data_pool,
+				   &mail->data.envelope_data, hdr);
 
 	if (hdr == NULL)
 		index_mail_parse_finish_imap_envelope(mail);
@@ -356,7 +357,7 @@
 	mail->data.save_envelope = TRUE;
 	header_ctx = mailbox_header_lookup_init(&mail->ibox->box,
 						imap_envelope_headers);
-	stream = mail->mail.get_headers(&mail->mail, header_ctx);
+	stream = mail_get_headers(&mail->mail.mail, header_ctx);
 	if (mail->data.envelope == NULL && stream != NULL) {
 		/* we got the headers from cache - parse them to get the
 		   envelope */
@@ -437,7 +438,7 @@
 
 	data = buffer_get_data(mail->header_data, &size);
         size = get_header_size(mail->header_data, offsets[field_idx]);
-	return p_strndup(mail->pool, data + offsets[field_idx], size);
+	return p_strndup(mail->data_pool, data + offsets[field_idx], size);
 }
 
 const char *index_mail_get_header(struct mail *_mail, const char *field)
@@ -453,11 +454,11 @@
 
 	field_idx = get_header_field_idx(mail->ibox, field);
 
-	dest = str_new(mail->pool, 128);
+	dest = str_new(mail->data_pool, 128);
 	if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
 				      mail->data.seq, &field_idx, 1) <= 0) {
 		/* not in cache / error - first see if it's already parsed */
-		p_free(mail->pool, dest);
+		p_free(mail->data_pool, dest);
 		if (mail->header_seq == mail->data.seq) {
 			ret = index_mail_header_is_parsed(mail, field_idx);
 			if (ret != -1) {
@@ -529,17 +530,17 @@
 			return NULL;
 	}
 
-	dest = str_new(mail->pool, 256);
+	dest = str_new(mail->data_pool, 256);
 	if (mail_cache_lookup_headers(mail->trans->cache_view, dest,
 				      mail->data.seq, headers->idx,
 				      headers->count) > 0) {
-		return i_stream_create_from_data(mail->pool,
+		return i_stream_create_from_data(mail->data_pool,
 						 str_data(dest), str_len(dest));
 	}
 	/* not in cache / error */
-	p_free(mail->pool, dest);
+	p_free(mail->data_pool, dest);
 
-	if (mail->mail.get_stream(&mail->mail, NULL, NULL) == NULL)
+	if (mail_get_stream(&mail->mail.mail, NULL, NULL) == NULL)
 		return NULL;
 
 	if (mail->data.filter_stream != NULL)
--- a/src/lib-storage/index/index-mail.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/index-mail.c	Tue Mar 15 21:01:50 2005 +0200
@@ -48,7 +48,7 @@
 		return NULL;
 	}
 
-	part = message_part_deserialize(mail->pool,
+	part = message_part_deserialize(mail->data_pool,
 					buffer_get_data(part_buf, NULL),
 					buffer_get_used_size(part_buf),
 					&error);
@@ -62,11 +62,11 @@
 
 	/* we know the NULs now, update them */
 	if ((part->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
-		mail->mail.has_nuls = TRUE;
-		mail->mail.has_no_nuls = FALSE;
+		mail->mail.mail.has_nuls = TRUE;
+		mail->mail.mail.has_no_nuls = FALSE;
 	} else {
-		mail->mail.has_nuls = FALSE;
-		mail->mail.has_no_nuls = TRUE;
+		mail->mail.mail.has_nuls = FALSE;
+		mail->mail.mail.has_no_nuls = TRUE;
 	}
 
 	return part;
@@ -77,11 +77,11 @@
 {
 	string_t *str;
 
-	str = str_new(mail->pool, 32);
+	str = str_new(mail->data_pool, 32);
 	if (mail_cache_lookup_field(mail->trans->cache_view, str,
 				    mail->data.seq,
 				    mail->ibox->cache_fields[field].idx) <= 0) {
-		p_free(mail->pool, str);
+		p_free(mail->data_pool, str);
 		return NULL;
 	}
 
@@ -172,8 +172,10 @@
 	struct index_mail_data *data = &mail->data;
 	const char *const *keywords;
 
-	if (data->keywords_buf == NULL)
-		data->keywords_buf = buffer_create_dynamic(mail->pool, 128);
+	if (data->keywords_buf == NULL) {
+		data->keywords_buf =
+			buffer_create_dynamic(mail->data_pool, 128);
+	}
 
 	if (mail_index_lookup_keywords(mail->ibox->view, mail->data.seq,
 				       data->keywords_buf, &keywords) < 0) {
@@ -238,7 +240,7 @@
 
 	if (data->sent_date.time == (time_t)-1) {
 		data->save_sent_date = TRUE;
-		str = _mail->get_header(_mail, "Date");
+		str = mail_get_header(_mail, "Date");
 		if (data->sent_date.time == (time_t)-1) {
 			if (!message_date_parse((const unsigned char *)str,
 						(size_t)-1,
@@ -298,7 +300,7 @@
 	if (get_cached_msgpart_sizes(mail))
 		return data->virtual_size;
 
-	if (_mail->get_stream(_mail, &hdr_size, &body_size) == NULL)
+	if (mail_get_stream(_mail, &hdr_size, &body_size) == NULL)
 		return (uoff_t)-1;
 
 	mail_cache_add(mail->trans->cache_trans, mail->data.seq,
@@ -355,7 +357,7 @@
 		i_assert(!data->save_bodystructure_header);
 		message_parser_parse_body(data->parser_ctx,
 					  parse_bodystructure_part_header,
-					  NULL, mail->pool);
+					  NULL, mail->data_pool);
 		data->save_bodystructure_body = FALSE;
 		data->parsed_bodystructure = TRUE;
 	} else {
@@ -368,17 +370,17 @@
 	data->body_size_set = TRUE;
 
 	cache_flags = 0;
-	if (!mail->mail.has_nuls && !mail->mail.has_no_nuls) {
+	if (!mail->mail.mail.has_nuls && !mail->mail.mail.has_no_nuls) {
 		/* we know the NULs now, update them */
 		if ((data->parts->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
-			mail->mail.has_nuls = TRUE;
-			mail->mail.has_no_nuls = FALSE;
+			mail->mail.mail.has_nuls = TRUE;
+			mail->mail.mail.has_no_nuls = FALSE;
 		} else {
-			mail->mail.has_nuls = FALSE;
-			mail->mail.has_no_nuls = TRUE;
+			mail->mail.mail.has_nuls = FALSE;
+			mail->mail.mail.has_no_nuls = TRUE;
 		}
 
-		if (mail->mail.has_nuls)
+		if (mail->mail.mail.has_nuls)
 			cache_flags |= MAIL_CACHE_FLAG_HAS_NULS;
 		else
 			cache_flags |= MAIL_CACHE_FLAG_HAS_NO_NULS;
@@ -480,7 +482,7 @@
 			message_parse_from_parts(data->parts->children,
 						data->stream,
 						parse_bodystructure_part_header,
-						mail->pool);
+						mail->data_pool);
 			data->parsed_bodystructure = TRUE;
 		} else {
 			index_mail_parse_body(mail, FALSE);
@@ -493,7 +495,7 @@
 	    ((dec & ~MAIL_CACHE_DECISION_FORCED) != MAIL_CACHE_DECISION_NO &&
 	     mail_cache_field_exists(mail->trans->cache_view, data->seq,
 			cache_fields[MAIL_CACHE_BODYSTRUCTURE].idx) == 0)) {
-		str = str_new(mail->pool, 128);
+		str = str_new(mail->data_pool, 128);
 		imap_bodystructure_write(data->parts, str, TRUE);
 		data->bodystructure = str_c(str);
 
@@ -512,7 +514,7 @@
 	    ((dec & ~MAIL_CACHE_DECISION_FORCED) != MAIL_CACHE_DECISION_NO &&
 	     mail_cache_field_exists(mail->trans->cache_view, data->seq,
 				     cache_fields[MAIL_CACHE_BODY].idx) == 0)) {
-		str = str_new(mail->pool, 128);
+		str = str_new(mail->data_pool, 128);
 		imap_bodystructure_write(data->parts, str, FALSE);
 		data->body = str_c(str);
 
@@ -544,7 +546,7 @@
 		   3) parse body structure, and save BODY/BODYSTRUCTURE
 		      depending on what we want cached */
 
-		str = str_new(mail->pool, 128);
+		str = str_new(mail->data_pool, 128);
 		if (mail_cache_lookup_field(mail->trans->cache_view, str,
 				mail->data.seq,
 				cache_fields[MAIL_CACHE_BODY].idx) > 0) {
@@ -554,7 +556,8 @@
 		if (mail_cache_lookup_field(mail->trans->cache_view, str,
 			      mail->data.seq,
 			      cache_fields[MAIL_CACHE_BODYSTRUCTURE].idx) > 0) {
-			data->bodystructure = p_strdup(mail->pool, str_c(str));
+			data->bodystructure =
+				p_strdup(mail->data_pool, str_c(str));
 			str_truncate(str, 0);
 
 			if (imap_body_parse_from_bodystructure(
@@ -566,10 +569,10 @@
 			/* broken, continue.. */
 			mail_cache_set_corrupted(mail->ibox->cache,
 				"Corrupted BODYSTRUCTURE for mail %u",
-				mail->mail.uid);
+				mail->mail.mail.uid);
 			data->bodystructure = NULL;
 		}
-		p_free(mail->pool, str);
+		p_free(mail->data_pool, str);
 
 		index_mail_parse_bodystructure(mail, MAIL_CACHE_BODY);
 		return data->body;
@@ -577,14 +580,14 @@
 		if (data->bodystructure != NULL)
 			return data->bodystructure;
 
-		str = str_new(mail->pool, 128);
+		str = str_new(mail->data_pool, 128);
 		if (mail_cache_lookup_field(mail->trans->cache_view, str,
 			      mail->data.seq,
 			      cache_fields[MAIL_CACHE_BODYSTRUCTURE].idx) > 0) {
 			data->bodystructure = str_c(str);
 			return data->bodystructure;
 		}
-		p_free(mail->pool, str);
+		p_free(mail->data_pool, str);
 
 		index_mail_parse_bodystructure(mail, MAIL_CACHE_BODYSTRUCTURE);
 		return data->bodystructure;
@@ -611,28 +614,39 @@
 	}
 }
 
-void index_mail_init(struct index_transaction_context *t,
-		     struct index_mail *mail,
-		     enum mail_fetch_field wanted_fields,
-		     struct mailbox_header_lookup_ctx *_wanted_headers)
+struct mail *
+index_mail_alloc(struct mailbox_transaction_context *_t,
+		 enum mail_fetch_field wanted_fields,
+		 struct mailbox_header_lookup_ctx *_wanted_headers)
 {
+	struct index_transaction_context *t =
+		(struct index_transaction_context *)_t;
 	struct index_header_lookup_ctx *wanted_headers =
 		(struct index_header_lookup_ctx *)_wanted_headers;
+	struct index_mail *mail;
 	const struct mail_index_header *hdr;
+	pool_t pool;
 
-	mail->mail = *t->ibox->mail_interface;
-	mail->mail.box = &t->ibox->box;
-	mail->mail.transaction = &t->mailbox_ctx;
+	pool = pool_alloconly_create("mail", 256);
+	mail = p_new(pool, struct index_mail, 1);
+	mail->mail.pool = pool;
+	ARRAY_CREATE(&mail->mail.module_contexts, pool, void *, 5);
+
+	mail->mail.v = *t->ibox->mail_vfuncs;
+	mail->mail.mail.box = &t->ibox->box;
+	mail->mail.mail.transaction = &t->mailbox_ctx;
 
 	/* only reason we couldn't get header is if view is invalidated */
 	hdr = mail_index_get_header(t->ibox->view);
 	mail->uid_validity = hdr->uid_validity;
 
-	mail->pool = pool_alloconly_create("index_mail", 16384);
+	mail->data_pool = pool_alloconly_create("index_mail", 16384);
 	mail->ibox = t->ibox;
 	mail->trans = t;
 	mail->wanted_fields = wanted_fields;
 	mail->wanted_headers = wanted_headers;
+
+	return &mail->mail.mail;
 }
 
 static void index_mail_close(struct index_mail *mail)
@@ -643,8 +657,9 @@
 		i_stream_unref(mail->data.filter_stream);
 }
 
-int index_mail_next(struct index_mail *mail, uint32_t seq)
+int index_mail_set_seq(struct mail *_mail, uint32_t seq)
 {
+	struct index_mail *mail = (struct index_mail *)_mail;
 	struct index_mail_data *data = &mail->data;
         const struct mail_index_record *rec;
 
@@ -656,7 +671,7 @@
 	index_mail_close(mail);
 
 	memset(data, 0, sizeof(*data));
-	p_clear(mail->pool);
+	p_clear(mail->data_pool);
 
 	data->rec = rec;
 	data->seq = seq;
@@ -669,11 +684,11 @@
 					sizeof(data->cache_flags)))
 		data->cache_flags = 0;
 
-	mail->mail.seq = seq;
-	mail->mail.uid = rec->uid;
-	mail->mail.has_nuls =
+	mail->mail.mail.seq = seq;
+	mail->mail.mail.uid = rec->uid;
+	mail->mail.mail.has_nuls =
 		(data->cache_flags & MAIL_CACHE_FLAG_HAS_NULS) != 0;
-	mail->mail.has_no_nuls =
+	mail->mail.mail.has_no_nuls =
 		(data->cache_flags & MAIL_CACHE_FLAG_HAS_NO_NULS) != 0;
 
 	t_push();
@@ -722,7 +737,7 @@
 					  MAIL_FETCH_STREAM_BODY)) {
 		data->open_mail = TRUE;
 		/* open stream to set expunged flag */
-		(void)mail->mail.get_stream(&mail->mail, NULL, NULL);
+		(void)mail_get_stream(_mail, NULL, NULL);
 	}
 
 	if ((mail->wanted_fields & MAIL_FETCH_DATE) &&
@@ -736,8 +751,10 @@
 	return 0;
 }
 
-void index_mail_deinit(struct index_mail *mail)
+void index_mail_free(struct mail *_mail)
 {
+	struct index_mail *mail = (struct index_mail *)_mail;
+
 	index_mail_close(mail);
 
 	if (mail->header_data != NULL)
@@ -749,8 +766,8 @@
 	if (mail->header_offsets != NULL)
 		buffer_free(mail->header_offsets);
 
-	pool_unref(mail->pool);
-	memset(mail, 0, sizeof(*mail));
+	pool_unref(mail->data_pool);
+	pool_unref(mail->mail.pool);
 }
 
 int index_mail_update_flags(struct mail *mail, enum modify_type modify_type,
--- a/src/lib-storage/index/index-mail.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/index-mail.h	Tue Mar 15 21:01:50 2005 +0200
@@ -87,10 +87,10 @@
 };
 
 struct index_mail {
-	struct mail mail;
+        struct mail_private mail;
 	struct index_mail_data data;
 
-	pool_t pool;
+	pool_t data_pool;
 	struct index_mailbox *ibox;
 	struct index_transaction_context *trans;
 	uint32_t uid_validity;
@@ -107,12 +107,12 @@
 	uint8_t header_match_value;
 };
 
-void index_mail_init(struct index_transaction_context *t,
-		     struct index_mail *mail,
-		     enum mail_fetch_field wanted_fields,
-		     struct mailbox_header_lookup_ctx *wanted_headers);
-int index_mail_next(struct index_mail *mail, uint32_t seq);
-void index_mail_deinit(struct index_mail *mail);
+struct mail *
+index_mail_alloc(struct mailbox_transaction_context *t,
+		 enum mail_fetch_field wanted_fields,
+		 struct mailbox_header_lookup_ctx *wanted_headers);
+int index_mail_set_seq(struct mail *mail, uint32_t seq);
+void index_mail_free(struct mail *mail);
 
 void index_mail_parse_header_init(struct index_mail *mail,
 				  struct mailbox_header_lookup_ctx *headers);
--- a/src/lib-storage/index/index-search.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/index-search.c	Tue Mar 15 21:01:50 2005 +0200
@@ -27,8 +27,8 @@
 	struct mail_search_arg *args;
 
 	uint32_t seq1, seq2;
-	struct index_mail imail;
 	struct mail *mail;
+	struct index_mail *imail;
 
 	pool_t hdr_pool;
 	const char *error;
@@ -103,9 +103,9 @@
 	case SEARCH_SEEN:
 		return rec->flags & MAIL_SEEN;
 	case SEARCH_RECENT:
-		return imail->mail.get_flags(&imail->mail) & MAIL_RECENT;
+		return mail_get_flags(&imail->mail.mail) & MAIL_RECENT;
 	case SEARCH_KEYWORD:
-		keywords = imail->mail.get_keywords(&imail->mail);
+		keywords = mail_get_keywords(&imail->mail.mail);
 		if (keywords != NULL) {
 			while (*keywords != NULL) {
 				if (strcasecmp(*keywords, value) == 0)
@@ -131,13 +131,13 @@
 		return;
 	}
 
-	if (ctx->imail.data.rec == NULL) {
+	if (ctx->imail->data.rec == NULL) {
 		/* expunged message */
 		ARG_SET_RESULT(arg, 0);
 		return;
 	}
 
-	switch (search_arg_match_index(&ctx->imail, arg->type,
+	switch (search_arg_match_index(ctx->imail, arg->type,
 				       arg->value.str)) {
 	case -1:
 		/* unknown */
@@ -165,7 +165,7 @@
 	case SEARCH_BEFORE:
 	case SEARCH_ON:
 	case SEARCH_SINCE:
-		date = ctx->mail->get_received_date(ctx->mail);
+		date = mail_get_received_date(ctx->mail);
 		if (date == (time_t)-1)
 			return -1;
 
@@ -191,7 +191,7 @@
 	case SEARCH_SENTSINCE:
 		/* NOTE: RFC-3501 specifies that timezone is ignored
 		   in searches. date is returned as UTC, so change it. */
-		date = ctx->mail->get_date(ctx->mail, &timezone_offset);
+		date = mail_get_date(ctx->mail, &timezone_offset);
 		if (date == (time_t)-1)
 			return -1;
 		date += timezone_offset * 60;
@@ -215,7 +215,7 @@
 	/* sizes */
 	case SEARCH_SMALLER:
 	case SEARCH_LARGER:
-		virtual_size = ctx->mail->get_virtual_size(ctx->mail);
+		virtual_size = mail_get_virtual_size(ctx->mail);
 		if (virtual_size == (uoff_t)-1)
 			return -1;
 
@@ -423,7 +423,7 @@
 	if (hdr->eoh)
 		return;
 
-	index_mail_parse_header(NULL, hdr, &ctx->index_context->imail);
+	index_mail_parse_header(NULL, hdr, ctx->index_context->imail);
 
 	if (ctx->custom_header || strcasecmp(hdr->name, "Date") == 0) {
 		ctx->hdr = hdr;
@@ -478,7 +478,7 @@
 
 		if (headers == NULL) {
 			headers_ctx = NULL;
-			input = ctx->mail->get_stream(ctx->mail, NULL, NULL);
+			input = mail_get_stream(ctx->mail, NULL, NULL);
 			if (input == NULL)
 				return FALSE;
 		} else {
@@ -486,7 +486,7 @@
 			headers_ctx =
 				mailbox_header_lookup_init(&ctx->ibox->box,
 							   headers);
-			input = ctx->mail->get_headers(ctx->mail, headers_ctx);
+			input = mail_get_headers(ctx->mail, headers_ctx);
 			if (input == NULL) {
 				mailbox_header_lookup_deinit(headers_ctx);
 				return FALSE;
@@ -498,7 +498,7 @@
 		hdr_ctx.custom_header = TRUE;
 		hdr_ctx.args = args;
 
-		index_mail_parse_header_init(&ctx->imail, headers_ctx);
+		index_mail_parse_header_init(ctx->imail, headers_ctx);
 		message_parse_header(NULL, input, NULL,
 				     search_header, &hdr_ctx);
 		if (headers_ctx != NULL)
@@ -506,7 +506,7 @@
 	} else {
 		struct message_size hdr_size;
 
-		input = ctx->mail->get_stream(ctx->mail, &hdr_size, NULL);
+		input = mail_get_stream(ctx->mail, &hdr_size, NULL);
 		if (input == NULL)
 			return FALSE;
 
@@ -519,7 +519,7 @@
 		memset(&body_ctx, 0, sizeof(body_ctx));
 		body_ctx.index_ctx = ctx;
 		body_ctx.input = input;
-		body_ctx.part = ctx->mail->get_parts(ctx->mail);
+		body_ctx.part = mail_get_parts(ctx->mail);
 
 		mail_search_args_foreach(args, search_body, &body_ctx);
 	}
@@ -710,9 +710,7 @@
 struct mail_search_context *
 index_storage_search_init(struct mailbox_transaction_context *_t,
 			  const char *charset, struct mail_search_arg *args,
-			  const enum mail_sort_type *sort_program,
-			  enum mail_fetch_field wanted_fields,
-			  struct mailbox_header_lookup_ctx *wanted_headers)
+			  const enum mail_sort_type *sort_program)
 {
 	struct index_transaction_context *t =
 		(struct index_transaction_context *)_t;
@@ -724,15 +722,12 @@
 	}
 
 	ctx = i_new(struct index_search_context, 1);
-	ctx->mail_ctx.box = &t->ibox->box;
+	ctx->mail_ctx.transaction = _t;
 	ctx->ibox = t->ibox;
 	ctx->view = t->trans_view;
 	ctx->charset = i_strdup(charset);
 	ctx->args = args;
 
-	ctx->mail = &ctx->imail.mail;
-	index_mail_init(t, &ctx->imail, wanted_fields, wanted_headers);
-
 	mail_search_args_reset(ctx->args, TRUE);
 
 	if (search_get_seqset(ctx, args) < 0) {
@@ -750,9 +745,6 @@
 
 	ret = ctx->failed || ctx->error != NULL ? -1 : 0;
 
-	if (ctx->imail.pool != NULL)
-		index_mail_deinit(&ctx->imail);
-
 	if (ctx->error != NULL) {
 		mail_storage_set_error(ctx->ibox->box.storage,
 				       "%s", ctx->error);
@@ -777,7 +769,7 @@
 	if (ret >= 0)
 		return ret > 0;
 
-	if (ctx->imail.data.rec == NULL) {
+	if (ctx->imail->data.rec == NULL) {
 		/* expunged message, no way to check if the rest would have
 		   matched */
 		return FALSE;
@@ -800,16 +792,20 @@
 	return TRUE;
 }
 
-struct mail *index_storage_search_next(struct mail_search_context *_ctx)
+int index_storage_search_next(struct mail_search_context *_ctx,
+			      struct mail *mail)
 {
         struct index_search_context *ctx = (struct index_search_context *)_ctx;
 	int ret;
 
+	ctx->mail = mail;
+	ctx->imail = (struct index_mail *)mail;
+
 	ret = 0;
 	while (ctx->seq1 <= ctx->seq2) {
-		if (index_mail_next(&ctx->imail, ctx->seq1++) < 0) {
+		if (mail_set_seq(mail, ctx->seq1++) < 0) {
 			ctx->failed = TRUE;
-			return NULL;
+			break;
 		}
 
 		t_push();
@@ -821,11 +817,8 @@
 		if (ret != 0)
 			break;
 	}
+	ctx->mail = NULL;
+	ctx->imail = NULL;
 
-	if (ret <= 0) {
-		/* error or last record */
-		return NULL;
-	}
-
-	return ctx->mail;
+	return ret;
 }
--- a/src/lib-storage/index/index-storage.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/index-storage.c	Tue Mar 15 21:01:50 2005 +0200
@@ -5,6 +5,7 @@
 #include "ioloop.h"
 #include "mail-index.h"
 #include "index-storage.h"
+#include "index-mail.h"
 
 #include <stdlib.h>
 #include <time.h>
@@ -42,6 +43,8 @@
 			enum mail_storage_flags flags)
 {
 	storage->storage.flags = flags;
+	ARRAY_CREATE(&storage->storage.module_contexts,
+		     storage->storage.pool, void *, 5);
 	index_storage_refcount++;
 }
 
@@ -279,12 +282,10 @@
 	ibox->last_notify_type = MAILBOX_LOCK_NOTIFY_NONE;
 }
 
-struct index_mailbox *
-index_storage_mailbox_init(struct index_storage *storage, struct mailbox *box,
-			   struct mail_index *index, const char *name,
-			   enum mailbox_open_flags flags)
+int index_storage_mailbox_init(struct index_mailbox *ibox,
+			       struct mail_index *index, const char *name,
+			       enum mailbox_open_flags flags)
 {
-	struct index_mailbox *ibox;
 	enum mail_index_open_flags index_flags;
 	enum mail_index_lock_method lock_method = 0;
 	const char *str;
@@ -312,15 +313,13 @@
 		i_fatal("Unknown lock_method: %s", str);
 
 	do {
-		ibox = i_new(struct index_mailbox, 1);
-		ibox->box = *box;
-		ibox->storage = storage;
+		ibox->box.storage = &ibox->storage->storage;
+		ibox->box.name = p_strdup(ibox->box.pool, name);
+		ARRAY_CREATE(&ibox->box.module_contexts,
+			     ibox->box.pool, void *, 5);
 
-		ibox->box.storage = &storage->storage;
-		ibox->box.name = i_strdup(name);
 		ibox->readonly = (flags & MAILBOX_OPEN_READONLY) != 0;
 		ibox->keep_recent = (flags & MAILBOX_OPEN_KEEP_RECENT) != 0;
-
 		ibox->index = index;
 
 		ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
@@ -333,12 +332,12 @@
 		ibox->cache = mail_index_get_cache(index);
 		index_cache_register_defaults(ibox);
 		ibox->view = mail_index_view_open(index);
-		return ibox;
+		return 0;
 	} while (0);
 
 	mail_storage_set_index_error(ibox);
 	index_storage_mailbox_free(&ibox->box);
-	return NULL;
+	return -1;
 }
 
 void index_storage_mailbox_free(struct mailbox *box)
@@ -352,11 +351,7 @@
 	if (ibox->index != NULL)
 		index_storage_unref(ibox->index);
         i_free(ibox->cache_fields);
-	i_free(ibox->path);
-	i_free(ibox->control_dir);
-
-	i_free(box->name);
-	i_free(box);
+	pool_unref(box->pool);
 }
 
 int index_storage_is_readonly(struct mailbox *box)
--- a/src/lib-storage/index/index-storage.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/index-storage.h	Tue Mar 15 21:01:50 2005 +0200
@@ -4,7 +4,6 @@
 #include "file-dotlock.h"
 #include "mail-storage-private.h"
 #include "mail-index.h"
-#include "index-mail.h"
 
 /* Max. mmap()ed size for a message */
 #define MAIL_MMAP_BLOCK_SIZE (1024*256)
@@ -25,13 +24,13 @@
 struct index_storage {
 	struct mail_storage storage;
 
-	char *dir; /* root directory */
-	char *index_dir;
-	char *control_dir;
-	char *inbox_path; /* INBOX location */
-        char *temp_prefix; /* prefix for temporary files */
+	const char *dir; /* root directory */
+	const char *index_dir;
+	const char *control_dir;
+	const char *inbox_path; /* INBOX location */
+        const char *temp_prefix; /* prefix for temporary files */
 
-	char *user; /* name of user accessing the storage */
+	const char *user; /* name of user accessing the storage */
 
 	struct mail_storage_callbacks *callbacks;
 	void *callback_context;
@@ -40,12 +39,12 @@
 struct index_mailbox {
 	struct mailbox box;
 	struct index_storage *storage;
-	char *path, *control_dir;
+	const char *path, *control_dir;
 
 	struct mail_index *index;
 	struct mail_index_view *view;
 	struct mail_cache *cache;
-	struct mail *mail_interface;
+	struct mail_vfuncs *mail_vfuncs;
 
 	int (*is_recent)(struct index_mailbox *ibox, uint32_t uid);
 
@@ -110,13 +109,13 @@
 struct index_transaction_context {
 	struct mailbox_transaction_context mailbox_ctx;
 	struct index_mailbox *ibox;
+        enum mailbox_transaction_flags flags;
 
 	struct mail_index_transaction *trans;
 	struct mail_index_view *trans_view;
 	struct mail_cache_view *cache_view;
 	struct mail_cache_transaction_ctx *cache_trans;
 
-	struct index_mail fetch_mail; /* for index_storage_fetch() */
 	unsigned int cache_trans_failed:1;
 };
 
@@ -137,10 +136,9 @@
 			enum mail_storage_flags flags);
 void index_storage_deinit(struct index_storage *storage);
 
-struct index_mailbox *
-index_storage_mailbox_init(struct index_storage *storage, struct mailbox *box,
-			   struct mail_index *index, const char *name,
-			   enum mailbox_open_flags flags);
+int index_storage_mailbox_init(struct index_mailbox *ibox,
+			       struct mail_index *index, const char *name,
+			       enum mailbox_open_flags flags);
 void index_storage_mailbox_free(struct mailbox *box);
 
 int index_storage_is_readonly(struct mailbox *box);
@@ -184,9 +182,6 @@
 				    enum mailbox_status_items items,
 				    struct mailbox_status *status_r);
 
-struct mail *
-index_storage_fetch(struct mailbox_transaction_context *t, uint32_t seq,
-		    enum mail_fetch_field wanted_fields);
 int index_storage_get_uids(struct mailbox *box, uint32_t uid1, uint32_t uid2,
 			   uint32_t *seq1_r, uint32_t *seq2_r);
 
@@ -199,14 +194,14 @@
 struct mail_search_context *
 index_storage_search_init(struct mailbox_transaction_context *t,
 			  const char *charset, struct mail_search_arg *args,
-			  const enum mail_sort_type *sort_program,
-			  enum mail_fetch_field wanted_fields,
-			  struct mailbox_header_lookup_ctx *wanted_headers);
+			  const enum mail_sort_type *sort_program);
 int index_storage_search_deinit(struct mail_search_context *ctx);
-struct mail *index_storage_search_next(struct mail_search_context *ctx);
+int index_storage_search_next(struct mail_search_context *ctx,
+			      struct mail *mail);
 
 void index_transaction_init(struct index_transaction_context *t,
-			    struct index_mailbox *ibox, int hide);
+			    struct index_mailbox *ibox,
+			    enum mailbox_transaction_flags flags);
 int index_transaction_commit(struct mailbox_transaction_context *t);
 void index_transaction_rollback(struct mailbox_transaction_context *t);
 
--- a/src/lib-storage/index/index-transaction.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/index-transaction.c	Tue Mar 15 21:01:50 2005 +0200
@@ -2,13 +2,19 @@
 
 #include "lib.h"
 #include "index-storage.h"
+#include "index-mail.h"
 
 void index_transaction_init(struct index_transaction_context *t,
-			    struct index_mailbox *ibox, int hide)
+			    struct index_mailbox *ibox,
+			    enum mailbox_transaction_flags flags)
 {
 	t->mailbox_ctx.box = &ibox->box;
 	t->ibox = ibox;
-	t->trans = mail_index_transaction_begin(ibox->view, hide, FALSE);
+	t->flags = flags;
+
+	t->trans = mail_index_transaction_begin(ibox->view,
+		(flags & MAILBOX_TRANSACTION_FLAG_HIDE) != 0,
+		(flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
 	t->trans_view = mail_index_transaction_open_updated_view(t->trans);
 	t->cache_view = mail_cache_view_open(ibox->cache, t->trans_view);
 	t->cache_trans = mail_cache_get_transaction(t->cache_view, t->trans);
@@ -30,9 +36,6 @@
 	uoff_t offset;
 	int ret;
 
-	if (t->fetch_mail.pool != NULL)
-		index_mail_deinit(&t->fetch_mail);
-
 	ret = mail_index_transaction_commit(t->trans, &seq, &offset);
 	if (ret < 0)
 		mail_storage_set_index_error(t->ibox);
@@ -52,9 +55,6 @@
 	struct index_transaction_context *t =
 		(struct index_transaction_context *)_t;
 
-	if (t->fetch_mail.pool != NULL)
-		index_mail_deinit(&t->fetch_mail);
-
 	mail_index_transaction_rollback(t->trans);
 	index_transaction_free(t);
 }
--- a/src/lib-storage/index/maildir/maildir-copy.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/maildir/maildir-copy.c	Tue Mar 15 21:01:50 2005 +0200
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "ioloop.h"
 #include "maildir-storage.h"
+#include "index-mail.h"
 #include "mail-copy.h"
 
 #include <stdlib.h>
@@ -63,8 +64,8 @@
 	const char *const *keywords;
 	const char *dest_fname;
 
-        flags = mail->get_flags(mail);
-        keywords = mail->get_keywords(mail);
+        flags = mail_get_flags(mail);
+        keywords = mail_get_keywords(mail);
 	dest_fname = maildir_generate_tmp_filename(&ioloop_timeval);
 	dest_fname = maildir_filename_set_flags(dest_fname, flags, keywords);
 
@@ -72,7 +73,7 @@
 	do_ctx.dest_path =
 		t_strconcat(ctx->ibox->path, "/new/", dest_fname, NULL);
 
-	if (maildir_file_do(imail->ibox, imail->mail.uid,
+	if (maildir_file_do(imail->ibox, imail->mail.mail.uid,
 			    do_hardlink, &do_ctx) < 0)
 		return -1;
 
@@ -123,7 +124,7 @@
 }
 
 int maildir_copy(struct mailbox_transaction_context *_t, struct mail *mail,
-		 struct mail **dest_mail_r)
+		 struct mail *dest_mail)
 {
 	struct maildir_transaction_context *t =
 		(struct maildir_transaction_context *)_t;
@@ -135,7 +136,7 @@
 	ctx = t->copy_ctx;
 
 	if (ctx->hardlink && mail->box->storage == ctx->ibox->box.storage) {
-		// FIXME: handle dest_mail_r
+		// FIXME: handle dest_mail
 		t_push();
 		ret = maildir_copy_hardlink(mail, ctx);
 		t_pop();
@@ -148,5 +149,5 @@
 		/* non-fatal hardlinking failure, try the slow way */
 	}
 
-	return mail_storage_copy(_t, mail, dest_mail_r);
+	return mail_storage_copy(_t, mail, dest_mail);
 }
--- a/src/lib-storage/index/maildir/maildir-mail.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/maildir/maildir-mail.c	Tue Mar 15 21:01:50 2005 +0200
@@ -77,7 +77,7 @@
 
 	if (data->open_mail && data->stream == NULL) {
 		/* we're going to open the mail anyway */
-		(void)_mail->get_stream(_mail, NULL, NULL);
+		(void)mail_get_stream(_mail, NULL, NULL);
 	}
 
 	if (data->stream != NULL) {
@@ -90,7 +90,7 @@
 			return (time_t)-1;
 		}
 	} else {
-		if (maildir_file_do(mail->ibox, mail->mail.uid,
+		if (maildir_file_do(mail->ibox, mail->mail.mail.uid,
 				    do_stat, &st) <= 0)
 			return (time_t)-1;
 	}
@@ -120,7 +120,7 @@
 	}
 
 	fname = maildir_uidlist_lookup(mail->ibox->uidlist,
-				       mail->mail.uid, &flags);
+				       mail->mail.mail.uid, &flags);
 	if (fname == NULL)
 		return (uoff_t)-1;
 
@@ -154,7 +154,7 @@
 
 	if (field == MAIL_FETCH_UIDL_FILE_NAME) {
 	    	fname = maildir_uidlist_lookup(mail->ibox->uidlist,
-					       mail->mail.uid, &flags);
+					       mail->mail.mail.uid, &flags);
 		end = strchr(fname, ':');
 		return end == NULL ? fname : t_strdup_until(fname, end);
 	}
@@ -176,7 +176,7 @@
 		return size;
 
 	fname = maildir_uidlist_lookup(mail->ibox->uidlist,
-				       mail->mail.uid, &flags);
+				       mail->mail.mail.uid, &flags);
 	if (fname == NULL)
 		return (uoff_t)-1;
 
@@ -195,7 +195,7 @@
 	}
 
 	if (size == (uoff_t)-1) {
-		if (maildir_file_do(mail->ibox, mail->mail.uid,
+		if (maildir_file_do(mail->ibox, mail->mail.mail.uid,
 				    do_stat, &st) <= 0)
 			return (uoff_t)-1;
 		size = st.st_size;
@@ -217,8 +217,8 @@
 	int deleted;
 
 	if (data->stream == NULL) {
-		data->stream = maildir_open_mail(mail->ibox, mail->mail.uid,
-						 &deleted);
+		data->stream = maildir_open_mail(mail->ibox,
+						 mail->mail.mail.uid, &deleted);
 		if (data->stream == NULL) {
 			_mail->expunged = deleted;
 			return NULL;
@@ -228,8 +228,9 @@
 	return index_mail_init_stream(mail, hdr_size, body_size);
 }
 
-struct mail maildir_mail = {
-	0, 0, 0, 0, 0, 0, 0,
+struct mail_vfuncs maildir_mail_vfuncs = {
+	index_mail_free,
+	index_mail_set_seq,
 
 	index_mail_get_flags,
 	index_mail_get_keywords,
--- a/src/lib-storage/index/maildir/maildir-save.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/maildir/maildir-save.c	Tue Mar 15 21:01:50 2005 +0200
@@ -27,7 +27,6 @@
 	struct index_mailbox *ibox;
 	struct mail_index_transaction *trans;
 	struct maildir_uidlist_sync_ctx *sync_ctx;
-	struct index_mail mail;
 
 	const char *tmpdir, *newdir, *curdir;
 	struct maildir_filename *files;
@@ -81,7 +80,7 @@
 }
 
 static struct maildir_save_context *
-maildir_transaction_save_init(struct maildir_transaction_context *t)
+maildir_save_transaction_init(struct maildir_transaction_context *t)
 {
         struct index_mailbox *ibox = t->ictx.ibox;
 	struct maildir_save_context *ctx;
@@ -89,12 +88,10 @@
 
 	pool = pool_alloconly_create("maildir_save_context", 4096);
 	ctx = p_new(pool, struct maildir_save_context, 1);
-	ctx->ctx.box = &ibox->box;
+	ctx->ctx.transaction = &t->ictx.mailbox_ctx;
 	ctx->pool = pool;
 	ctx->ibox = ibox;
-	ctx->trans = mail_index_transaction_begin(ibox->view, FALSE, TRUE);
-
-	index_mail_init(&t->ictx, &ctx->mail, 0, NULL);
+	ctx->trans = t->ictx.trans;
 
 	ctx->tmpdir = p_strconcat(pool, ibox->path, "/tmp", NULL);
 	ctx->newdir = p_strconcat(pool, ibox->path, "/new", NULL);
@@ -119,10 +116,12 @@
 	struct ostream *output;
 	const char *fname, *dest_fname, *path;
 
+	i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
+
 	t_push();
 
 	if (t->save_ctx == NULL)
-		t->save_ctx = maildir_transaction_save_init(t);
+		t->save_ctx = maildir_save_transaction_init(t);
 	ctx = t->save_ctx;
 
 	/* create a new file in tmp/ directory */
@@ -191,7 +190,7 @@
 	return 0;
 }
 
-int maildir_save_finish(struct mail_save_context *_ctx, struct mail **mail_r)
+int maildir_save_finish(struct mail_save_context *_ctx, struct mail *dest_mail)
 {
 	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
 	struct utimbuf buf;
@@ -257,12 +256,11 @@
 		return -1;
 	}
 
-	if (mail_r != NULL) {
+	if (dest_mail != NULL) {
 		i_assert(ctx->seq != 0);
 
-		if (index_mail_next(&ctx->mail, ctx->seq) < 0)
+		if (mail_set_seq(dest_mail, ctx->seq) < 0)
 			return -1;
-		*mail_r = &ctx->mail.mail;
 	}
 
 	t_pop();
@@ -308,9 +306,7 @@
 	uint32_t first_uid, last_uid;
 	enum maildir_uidlist_rec_flag flags;
 	const char *fname;
-	uint32_t seq;
-	uoff_t offset;
-	int ret = 0;
+	int ret;
 
 	i_assert(ctx->output == NULL);
 
@@ -352,10 +348,7 @@
 		}
 	}
 
-	if (mail_index_transaction_commit(ctx->trans, &seq, &offset) < 0)
-		ret = -1;
-	return ret;
-
+	return 0;
 }
 
 void maildir_transaction_save_commit_post(struct maildir_save_context *ctx)
@@ -363,7 +356,6 @@
 	/* can't do anything anymore if we fail */
 	(void)maildir_uidlist_sync_deinit(ctx->sync_ctx);
 
-	index_mail_deinit(&ctx->mail);
 	pool_unref(ctx->pool);
 }
 
@@ -385,7 +377,5 @@
 	}
 	t_pop();
 
-	mail_index_transaction_rollback(ctx->trans);
-	index_mail_deinit(&ctx->mail);
 	pool_unref(ctx->pool);
 }
--- a/src/lib-storage/index/maildir/maildir-storage.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Tue Mar 15 21:01:50 2005 +0200
@@ -8,6 +8,7 @@
 #include "subscription-file/subscription-file.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
+#include "index-mail.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -38,6 +39,7 @@
 	const char *root_dir, *inbox_dir, *index_dir, *control_dir;
 	const char *home, *path, *p;
 	size_t len;
+	pool_t pool;
 
 	inbox_dir = root_dir = index_dir = control_dir = NULL;
 
@@ -114,19 +116,21 @@
 		       inbox_dir == NULL ? "" : inbox_dir);
 	}
 
-	storage = i_new(struct index_storage, 1);
+	pool = pool_alloconly_create("storage", 256);
+	storage = p_new(pool, struct index_storage, 1);
 	storage->storage = maildir_storage;
+	storage->storage.pool = pool;
 
 	/* the default ".temp.xxx" prefix would be treated as directory */
 	storage->temp_prefix =
-		i_strconcat("temp.", my_hostname, ".", my_pid, ".", NULL);
+		p_strconcat(pool, "temp.", my_hostname, ".", my_pid, ".", NULL);
 
-	storage->dir = i_strdup(home_expand(root_dir));
-	storage->inbox_path = i_strdup(home_expand(inbox_dir));
-	storage->index_dir = i_strdup(home_expand(index_dir));
-	storage->control_dir = i_strdup(home_expand(control_dir));
-	storage->user = i_strdup(user);
-	storage->callbacks = i_new(struct mail_storage_callbacks, 1);
+	storage->dir = p_strdup(pool, home_expand(root_dir));
+	storage->inbox_path = p_strdup(pool, home_expand(inbox_dir));
+	storage->index_dir = p_strdup(pool, home_expand(index_dir));
+	storage->control_dir = p_strdup(pool, home_expand(control_dir));
+	storage->user = p_strdup(pool, user);
+	storage->callbacks = p_new(pool, struct mail_storage_callbacks, 1);
 	index_storage_init(storage, flags);
 
 	(void)verify_inbox(storage);
@@ -138,15 +142,7 @@
 	struct index_storage *storage = (struct index_storage *) _storage;
 
 	index_storage_deinit(storage);
-
-	i_free(storage->temp_prefix);
-	i_free(storage->dir);
-	i_free(storage->inbox_path);
-	i_free(storage->index_dir);
-	i_free(storage->control_dir);
-	i_free(storage->user);
-	i_free(storage->callbacks);
-	i_free(storage);
+	pool_unref(storage->storage.pool);
 }
 
 static int maildir_autodetect(const char *data, enum mail_storage_flags flags)
@@ -406,6 +402,7 @@
 	const char *path, *index_dir, *control_dir;
 	struct stat st;
 	int shared;
+	pool_t pool;
 
 	path = maildir_get_path(storage, name);
 	index_dir = maildir_get_index_path(storage, name);
@@ -419,15 +416,21 @@
 	if (shared)
 		mail_index_set_permissions(index, st.st_mode & 0666, st.st_gid);
 
-	ibox = index_storage_mailbox_init(storage, &maildir_mailbox,
-					  index, name, flags);
-	if (ibox == NULL)
-		return NULL;
+	pool = pool_alloconly_create("mailbox", 256);
+	ibox = p_new(pool, struct index_mailbox, 1);
+	ibox->box = maildir_mailbox;
+	ibox->box.pool = pool;
+	ibox->storage = storage;
 
-	ibox->path = i_strdup(path);
-	ibox->control_dir = i_strdup(control_dir);
+	if (index_storage_mailbox_init(ibox, index, name, flags) < 0) {
+		/* the memory was already freed */
+		return NULL;
+	}
 
-	ibox->mail_interface = &maildir_mail;
+	ibox->path = p_strdup(pool, path);
+	ibox->control_dir = p_strdup(pool, control_dir);
+
+	ibox->mail_vfuncs = &maildir_mail_vfuncs;
 	ibox->uidlist = maildir_uidlist_init(ibox);
 	ibox->is_recent = maildir_is_recent;
 
@@ -836,59 +839,67 @@
 }
 
 struct mail_storage maildir_storage = {
-	"maildir", /* name */
-
-	'.', /* hierarchy separator */
+	MEMBER(name) "maildir",
+	MEMBER(hierarchy_sep) '.',
 
-	maildir_create,
-	maildir_free,
-	maildir_autodetect,
-	index_storage_set_callbacks,
-	maildir_mailbox_open,
-	maildir_mailbox_create,
-	maildir_mailbox_delete,
-	maildir_mailbox_rename,
-	maildir_mailbox_list_init,
-	maildir_mailbox_list_next,
-	maildir_mailbox_list_deinit,
-	maildir_set_subscribed,
-	maildir_get_mailbox_name_status,
-	index_storage_get_last_error,
+	{
+		maildir_create,
+		maildir_free,
+		maildir_autodetect,
+		index_storage_set_callbacks,
+		maildir_mailbox_open,
+		maildir_mailbox_create,
+		maildir_mailbox_delete,
+		maildir_mailbox_rename,
+		maildir_mailbox_list_init,
+		maildir_mailbox_list_next,
+		maildir_mailbox_list_deinit,
+		maildir_set_subscribed,
+		maildir_get_mailbox_name_status,
+		index_storage_get_last_error
+	},
 
-	NULL,
-	0,
-	0
+	MEMBER(pool) NULL,
+	MEMBER(error) NULL,
+	MEMBER(flags) 0,
+	MEMBER(module_contexts) ARRAY_INIT,
+	MEMBER(syntax_error) 0
 };
 
 struct mailbox maildir_mailbox = {
-	NULL, /* name */
-	NULL, /* storage */
+	MEMBER(name) NULL, 
+	MEMBER(storage) NULL, 
 
-	index_storage_is_readonly,
-        index_storage_allow_new_keywords,
-	maildir_storage_close,
-	index_storage_get_status,
-	maildir_storage_sync_init,
-	index_mailbox_sync_next,
-	index_mailbox_sync_deinit,
-	maildir_notify_changes,
-	maildir_transaction_begin,
-	maildir_transaction_commit,
-	maildir_transaction_rollback,
-	index_keywords_create,
-	index_keywords_free,
-	index_storage_fetch,
-	index_storage_get_uids,
-	index_header_lookup_init,
-        index_header_lookup_deinit,
-	index_storage_search_get_sorting,
-	index_storage_search_init,
-	index_storage_search_deinit,
-	index_storage_search_next,
-	maildir_save_init,
-	maildir_save_continue,
-	maildir_save_finish,
-	maildir_save_cancel,
-	maildir_copy,
-	index_storage_is_inconsistent
+	{
+		index_storage_is_readonly,
+		index_storage_allow_new_keywords,
+		maildir_storage_close,
+		index_storage_get_status,
+		maildir_storage_sync_init,
+		index_mailbox_sync_next,
+		index_mailbox_sync_deinit,
+		maildir_notify_changes,
+		maildir_transaction_begin,
+		maildir_transaction_commit,
+		maildir_transaction_rollback,
+		index_keywords_create,
+		index_keywords_free,
+		index_storage_get_uids,
+		index_mail_alloc,
+		index_header_lookup_init,
+		index_header_lookup_deinit,
+		index_storage_search_get_sorting,
+		index_storage_search_init,
+		index_storage_search_deinit,
+		index_storage_search_next,
+		maildir_save_init,
+		maildir_save_continue,
+		maildir_save_finish,
+		maildir_save_cancel,
+		maildir_copy,
+		index_storage_is_inconsistent
+	},
+
+	MEMBER(pool) NULL,
+	MEMBER(module_contexts) ARRAY_INIT
 };
--- a/src/lib-storage/index/maildir/maildir-storage.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.h	Tue Mar 15 21:01:50 2005 +0200
@@ -20,7 +20,7 @@
 	struct maildir_copy_context *copy_ctx;
 };
 
-extern struct mail maildir_mail;
+extern struct mail_vfuncs maildir_mail_vfuncs;
 
 /* Return -1 = error, 0 = file not found, 1 = ok */
 typedef int maildir_file_do_func(struct index_mailbox *ibox,
@@ -51,7 +51,8 @@
 			      int partial);
 
 struct mailbox_transaction_context *
-maildir_transaction_begin(struct mailbox *box, int hide);
+maildir_transaction_begin(struct mailbox *box,
+			  enum mailbox_transaction_flags flags);
 int maildir_transaction_commit(struct mailbox_transaction_context *t,
 			       enum mailbox_sync_flags flags);
 void maildir_transaction_rollback(struct mailbox_transaction_context *t);
@@ -63,7 +64,7 @@
 		  const char *from_envelope, struct istream *input,
 		  int want_mail);
 int maildir_save_continue(struct mail_save_context *ctx);
-int maildir_save_finish(struct mail_save_context *ctx, struct mail **mail_r);
+int maildir_save_finish(struct mail_save_context *ctx, struct mail *dest_mail);
 void maildir_save_cancel(struct mail_save_context *ctx);
 
 int maildir_transaction_save_commit_pre(struct maildir_save_context *ctx);
@@ -71,7 +72,7 @@
 void maildir_transaction_save_rollback(struct maildir_save_context *ctx);
 
 int maildir_copy(struct mailbox_transaction_context *t, struct mail *mail,
-		 struct mail **dest_mail_r);
+		 struct mail *dest_mail);
 int maildir_transaction_copy_commit(struct maildir_copy_context *ctx);
 void maildir_transaction_copy_rollback(struct maildir_copy_context *ctx);
 
--- a/src/lib-storage/index/maildir/maildir-transaction.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/maildir/maildir-transaction.c	Tue Mar 15 21:01:50 2005 +0200
@@ -4,13 +4,14 @@
 #include "maildir-storage.h"
 
 struct mailbox_transaction_context *
-maildir_transaction_begin(struct mailbox *box, int hide)
+maildir_transaction_begin(struct mailbox *box,
+			  enum mailbox_transaction_flags flags)
 {
 	struct index_mailbox *ibox = (struct index_mailbox *)box;
 	struct maildir_transaction_context *t;
 
 	t = i_new(struct maildir_transaction_context, 1);
-        index_transaction_init(&t->ictx, ibox, hide);
+	index_transaction_init(&t->ictx, ibox, flags);
 	return &t->ictx.mailbox_ctx;
 }
 
--- a/src/lib-storage/index/mbox/mbox-mail.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/mbox/mbox-mail.c	Tue Mar 15 21:01:50 2005 +0200
@@ -22,7 +22,7 @@
 	enum mbox_sync_flags sync_flags = 0;
 	int ret, deleted;
 
-	if (mail->mail.expunged)
+	if (mail->mail.mail.expunged)
 		return 0;
 
 __again:
@@ -45,11 +45,11 @@
 	if (mbox_file_open_stream(ibox) < 0)
 		return -1;
 
-	ret = mbox_file_seek(ibox, mail->trans->trans_view, mail->mail.seq,
-			     &deleted);
+	ret = mbox_file_seek(ibox, mail->trans->trans_view,
+			     mail->mail.mail.seq, &deleted);
 	if (ret < 0) {
 		if (deleted) {
-			mail->mail.expunged = TRUE;
+			mail->mail.mail.expunged = TRUE;
 			return 0;
 		}
 		return -1;
@@ -160,8 +160,9 @@
 	return index_mail_init_stream(mail, hdr_size, body_size);
 }
 
-struct mail mbox_mail = {
-	0, 0, 0, 0, 0, 0, 0,
+struct mail_vfuncs mbox_mail_vfuncs = {
+	index_mail_free,
+	index_mail_set_seq,
 
 	index_mail_get_flags,
 	index_mail_get_keywords,
--- a/src/lib-storage/index/mbox/mbox-save.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/mbox/mbox-save.c	Tue Mar 15 21:01:50 2005 +0200
@@ -40,7 +40,6 @@
 	uoff_t extra_hdr_offset, eoh_offset, eoh_input_offset;
 	char last_char;
 
-	struct index_mail mail;
 	struct mbox_md5_context *mbox_md5_ctx;
 
 	unsigned int synced:1;
@@ -191,8 +190,6 @@
 	ctx->next_uid = hdr->next_uid;
 	ctx->synced = TRUE;
         t->mbox_modified = TRUE;
-
-	index_mail_init(&t->ictx, &ctx->mail, 0, NULL);
 }
 
 static void status_flags_append(string_t *str, enum mail_flags flags,
@@ -312,16 +309,17 @@
 	enum mail_flags save_flags;
 	uint64_t offset;
 
+	i_assert((t->ictx.flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
+
 	/* FIXME: we could write timezone_offset to From-line.. */
 	if (received_date == (time_t)-1)
 		received_date = ioloop_time;
 
 	if (ctx == NULL) {
 		ctx = t->save_ctx = i_new(struct mbox_save_context, 1);
-		ctx->ctx.box = &ibox->box;
+		ctx->ctx.transaction = &t->ictx.mailbox_ctx;
 		ctx->ibox = ibox;
-		ctx->trans = mail_index_transaction_begin(ibox->view,
-							  FALSE, TRUE);
+		ctx->trans = t->ictx.trans;
 		ctx->append_offset = (uoff_t)-1;
 		ctx->headers = str_new(default_pool, 512);
 		ctx->save_crlf = getenv("MAIL_SAVE_CRLF") != NULL;
@@ -463,7 +461,7 @@
 	return ctx->input->eof && size == 0 ? 0 : mbox_save_continue(_ctx);
 }
 
-int mbox_save_finish(struct mail_save_context *_ctx, struct mail **mail_r)
+int mbox_save_finish(struct mail_save_context *_ctx, struct mail *dest_mail)
 {
 	struct mbox_save_context *ctx = (struct mbox_save_context *)_ctx;
 
@@ -501,12 +499,11 @@
 		return -1;
 	}
 
-	if (mail_r != NULL) {
+	if (dest_mail != NULL) {
 		i_assert(ctx->seq != 0);
 
-		if (index_mail_next(&ctx->mail, ctx->seq) < 0)
+		if (mail_set_seq(dest_mail, ctx->seq) < 0)
 			return -1;
-		*mail_r = &ctx->mail.mail;
 	}
 
 	return 0;
@@ -524,9 +521,6 @@
 {
 	i_assert(ctx->body_output == NULL);
 
-	if (ctx->mail.pool != NULL)
-		index_mail_deinit(&ctx->mail);
-
 	if (ctx->output != NULL)
 		o_stream_unref(ctx->output);
 	str_free(ctx->headers);
@@ -535,8 +529,6 @@
 
 int mbox_transaction_save_commit(struct mbox_save_context *ctx)
 {
-	uint32_t seq;
-	uoff_t offset;
 	int ret = 0;
 
 	if (ctx->synced) {
@@ -553,9 +545,6 @@
 		}
 	}
 
-	if (mail_index_transaction_commit(ctx->trans, &seq, &offset) < 0)
-		ret = -1;
-
 	mbox_transaction_save_deinit(ctx);
 	return ret;
 }
@@ -576,6 +565,5 @@
 			mbox_set_syscall_error(ibox, "ftruncate()");
 	}
 
-	mail_index_transaction_rollback(ctx->trans);
 	mbox_transaction_save_deinit(ctx);
 }
--- a/src/lib-storage/index/mbox/mbox-storage.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Tue Mar 15 21:01:50 2005 +0200
@@ -11,6 +11,7 @@
 #include "mbox-file.h"
 #include "mbox-sync-private.h"
 #include "mail-copy.h"
+#include "index-mail.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -248,6 +249,7 @@
 	const char *root_dir, *inbox_file, *index_dir, *p;
 	struct stat st;
 	int autodetect;
+	pool_t pool;
 
 	root_dir = inbox_file = index_dir = NULL;
 
@@ -325,14 +327,16 @@
 		       inbox_file == NULL ? "" : inbox_file);
 	}
 
-	storage = i_new(struct index_storage, 1);
+	pool = pool_alloconly_create("storage", 256);
+	storage = p_new(pool, struct index_storage, 1);
 	storage->storage = mbox_storage;
+	storage->storage.pool = pool;
 
-	storage->dir = i_strdup(home_expand(root_dir));
-	storage->inbox_path = i_strdup(home_expand(inbox_file));
-	storage->index_dir = i_strdup(home_expand(index_dir));
-	storage->user = i_strdup(user);
-	storage->callbacks = i_new(struct mail_storage_callbacks, 1);
+	storage->dir = p_strdup(pool, home_expand(root_dir));
+	storage->inbox_path = p_strdup(pool, home_expand(inbox_file));
+	storage->index_dir = p_strdup(pool, home_expand(index_dir));
+	storage->user = p_strdup(pool, user);
+	storage->callbacks = p_new(pool, struct mail_storage_callbacks, 1);
 	index_storage_init(storage, flags);
 	return &storage->storage;
 }
@@ -342,13 +346,7 @@
 	struct index_storage *storage = (struct index_storage *)_storage;
 
 	index_storage_deinit(storage);
-
-	i_free(storage->dir);
-	i_free(storage->inbox_path);
-	i_free(storage->index_dir);
-	i_free(storage->user);
-	i_free(storage->callbacks);
-	i_free(storage);
+	pool_unref(storage->storage.pool);
 }
 
 int mbox_is_valid_mask(struct mail_storage *storage, const char *mask)
@@ -488,6 +486,7 @@
 	struct mail_index *index;
 	const char *path, *index_dir;
 	uint32_t mbox_ext_idx;
+	pool_t pool;
 
 	if (strcmp(name, "INBOX") == 0) {
 		/* name = "INBOX"
@@ -507,18 +506,25 @@
 	mbox_ext_idx = mail_index_ext_register(index, "mbox", 0,
 					       sizeof(uint64_t),
 					       sizeof(uint64_t));
-	ibox = index_storage_mailbox_init(storage, &mbox_mailbox,
-					  index, name, flags);
-	if (ibox == NULL)
+
+	pool = pool_alloconly_create("mailbox", 256);
+	ibox = p_new(pool, struct index_mailbox, 1);
+	ibox->box = mbox_mailbox;
+	ibox->box.pool = pool;
+	ibox->storage = storage;
+
+	if (index_storage_mailbox_init(ibox, index, name, flags) < 0) {
+		/* the memory was already freed */
 		return NULL;
+	}
 
-	ibox->path = i_strdup(path);
+	ibox->path = p_strdup(pool, path);
 	ibox->mbox_fd = -1;
 	ibox->mbox_lock_type = F_UNLCK;
 	ibox->mbox_ext_idx = mbox_ext_idx;
 
 	ibox->is_recent = mbox_mail_is_recent;
-	ibox->mail_interface = &mbox_mail;
+	ibox->mail_vfuncs = &mbox_mail_vfuncs;
         ibox->mbox_very_dirty_syncs = getenv("MBOX_VERY_DIRTY_SYNCS") != NULL;
 	ibox->mbox_do_dirty_syncs = ibox->mbox_very_dirty_syncs ||
 		getenv("MBOX_DIRTY_SYNCS") != NULL;
@@ -931,59 +937,67 @@
 }
 
 struct mail_storage mbox_storage = {
-	"mbox", /* name */
-
-	'/', /* hierarchy separator */
+	MEMBER(name) "mbox",
+	MEMBER(hierarchy_sep) '/',
 
-	mbox_create,
-	mbox_free,
-	mbox_autodetect,
-	index_storage_set_callbacks,
-	mbox_mailbox_open,
-	mbox_mailbox_create,
-	mbox_mailbox_delete,
-	mbox_mailbox_rename,
-	mbox_mailbox_list_init,
-	mbox_mailbox_list_next,
-	mbox_mailbox_list_deinit,
-	mbox_set_subscribed,
-	mbox_get_mailbox_name_status,
-	index_storage_get_last_error,
+	{
+		mbox_create,
+		mbox_free,
+		mbox_autodetect,
+		index_storage_set_callbacks,
+		mbox_mailbox_open,
+		mbox_mailbox_create,
+		mbox_mailbox_delete,
+		mbox_mailbox_rename,
+		mbox_mailbox_list_init,
+		mbox_mailbox_list_next,
+		mbox_mailbox_list_deinit,
+		mbox_set_subscribed,
+		mbox_get_mailbox_name_status,
+		index_storage_get_last_error
+	},
 
-	NULL,
-	0,
-	0
+	MEMBER(pool) NULL,
+	MEMBER(error) NULL,
+	MEMBER(flags) 0,
+	MEMBER(module_contexts) ARRAY_INIT,
+	MEMBER(syntax_error) 0
 };
 
 struct mailbox mbox_mailbox = {
-	NULL, /* name */
-	NULL, /* storage */
+	MEMBER(name) NULL, 
+	MEMBER(storage) NULL, 
 
-	index_storage_is_readonly,
-        index_storage_allow_new_keywords,
-	mbox_storage_close,
-	index_storage_get_status,
-	mbox_storage_sync_init,
-	index_mailbox_sync_next,
-	index_mailbox_sync_deinit,
-	mbox_notify_changes,
-	mbox_transaction_begin,
-	mbox_transaction_commit,
-	mbox_transaction_rollback,
-	index_keywords_create,
-	index_keywords_free,
-	index_storage_fetch,
-	index_storage_get_uids,
-	index_header_lookup_init,
-        index_header_lookup_deinit,
-        index_storage_search_get_sorting,
-	index_storage_search_init,
-	index_storage_search_deinit,
-	index_storage_search_next,
-	mbox_save_init,
-	mbox_save_continue,
-	mbox_save_finish,
-	mbox_save_cancel,
-	mail_storage_copy,
-	index_storage_is_inconsistent
+	{
+		index_storage_is_readonly,
+		index_storage_allow_new_keywords,
+		mbox_storage_close,
+		index_storage_get_status,
+		mbox_storage_sync_init,
+		index_mailbox_sync_next,
+		index_mailbox_sync_deinit,
+		mbox_notify_changes,
+		mbox_transaction_begin,
+		mbox_transaction_commit,
+		mbox_transaction_rollback,
+		index_keywords_create,
+		index_keywords_free,
+		index_storage_get_uids,
+		index_mail_alloc,
+		index_header_lookup_init,
+		index_header_lookup_deinit,
+		index_storage_search_get_sorting,
+		index_storage_search_init,
+		index_storage_search_deinit,
+		index_storage_search_next,
+		mbox_save_init,
+		mbox_save_continue,
+		mbox_save_finish,
+		mbox_save_cancel,
+		mail_storage_copy,
+		index_storage_is_inconsistent
+	},
+
+	MEMBER(pool) NULL,
+	MEMBER(module_contexts) ARRAY_INIT
 };
--- a/src/lib-storage/index/mbox/mbox-storage.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.h	Tue Mar 15 21:01:50 2005 +0200
@@ -19,7 +19,7 @@
 	unsigned int mbox_modified:1;
 };
 
-extern struct mail mbox_mail;
+extern struct mail_vfuncs mbox_mail_vfuncs;
 extern const char *mbox_hide_headers[];
 extern size_t mbox_hide_headers_count;
 
@@ -33,7 +33,8 @@
 struct mailbox_list *mbox_mailbox_list_next(struct mailbox_list_context *ctx);
 
 struct mailbox_transaction_context *
-mbox_transaction_begin(struct mailbox *box, int hide);
+mbox_transaction_begin(struct mailbox *box,
+		       enum mailbox_transaction_flags flags);
 int mbox_transaction_commit(struct mailbox_transaction_context *t,
 			    enum mailbox_sync_flags flags);
 void mbox_transaction_rollback(struct mailbox_transaction_context *t);
@@ -47,7 +48,7 @@
 	       time_t received_date, int timezone_offset,
 	       const char *from_envelope, struct istream *input, int want_mail);
 int mbox_save_continue(struct mail_save_context *ctx);
-int mbox_save_finish(struct mail_save_context *ctx, struct mail **mail_r);
+int mbox_save_finish(struct mail_save_context *ctx, struct mail *dest_mail);
 void mbox_save_cancel(struct mail_save_context *ctx);
 
 int mbox_transaction_save_commit(struct mbox_save_context *ctx);
--- a/src/lib-storage/index/mbox/mbox-transaction.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/index/mbox/mbox-transaction.c	Tue Mar 15 21:01:50 2005 +0200
@@ -6,13 +6,14 @@
 #include "mbox-sync-private.h"
 
 struct mailbox_transaction_context *
-mbox_transaction_begin(struct mailbox *box, int hide)
+mbox_transaction_begin(struct mailbox *box,
+		       enum mailbox_transaction_flags flags)
 {
 	struct index_mailbox *ibox = (struct index_mailbox *)box;
 	struct mbox_transaction_context *t;
 
 	t = i_new(struct mbox_transaction_context, 1);
-        index_transaction_init(&t->ictx, ibox, hide);
+	index_transaction_init(&t->ictx, ibox, flags);
 	return &t->ictx.mailbox_ctx;
 }
 
--- a/src/lib-storage/mail-copy.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/mail-copy.c	Tue Mar 15 21:01:50 2005 +0200
@@ -6,25 +6,25 @@
 #include "mail-copy.h"
 
 int mail_storage_copy(struct mailbox_transaction_context *t, struct mail *mail,
-		      struct mail **dest_mail_r)
+		      struct mail *dest_mail)
 {
 	struct mail_save_context *ctx;
 	struct istream *input;
 	struct mail_keywords *keywords;
 	const char *from_envelope, *const *keywords_list;
 
-	input = mail->get_stream(mail, NULL, NULL);
+	input = mail_get_stream(mail, NULL, NULL);
 	if (input == NULL)
 		return -1;
 
-	from_envelope = mail->get_special(mail, MAIL_FETCH_FROM_ENVELOPE);
+	from_envelope = mail_get_special(mail, MAIL_FETCH_FROM_ENVELOPE);
 
-	keywords_list = mail->get_keywords(mail);
+	keywords_list = mail_get_keywords(mail);
 	keywords = keywords_list == NULL ? NULL :
 		mailbox_keywords_create(t, keywords_list);
-	ctx = mailbox_save_init(t, mail->get_flags(mail), keywords,
-				mail->get_received_date(mail),
-				0, from_envelope, input, dest_mail_r != NULL);
+	ctx = mailbox_save_init(t, mail_get_flags(mail), keywords,
+				mail_get_received_date(mail),
+				0, from_envelope, input, dest_mail != NULL);
 	if (keywords != NULL)
 		mailbox_keywords_free(t, keywords);
 
@@ -38,5 +38,5 @@
 		return -1;
 	}
 
-	return mailbox_save_finish(ctx, dest_mail_r);
+	return mailbox_save_finish(ctx, dest_mail);
 }
--- a/src/lib-storage/mail-copy.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/mail-copy.h	Tue Mar 15 21:01:50 2005 +0200
@@ -2,6 +2,6 @@
 #define __MAIL_COPY_H
 
 int mail_storage_copy(struct mailbox_transaction_context *t, struct mail *mail,
-		      struct mail **dest_mail_r);
+		      struct mail *dest_mail);
 
 #endif
--- a/src/lib-storage/mail-storage-private.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/mail-storage-private.h	Tue Mar 15 21:01:50 2005 +0200
@@ -3,10 +3,11 @@
 
 #include "mail-storage.h"
 
-struct mail_storage {
-	char *name;
-	char hierarchy_sep;
+/* Modules should use do "my_id = mail_storage_module_id++" and
+   use objects' module_contexts[id] for their own purposes. */
+extern unsigned int mail_storage_module_id;
 
+struct mail_storage_vfuncs {
 	struct mail_storage *(*create)(const char *data, const char *user,
 				       enum mail_storage_flags flags);
 	void (*destroy)(struct mail_storage *storage);
@@ -44,19 +45,27 @@
 
 	const char *(*get_last_error)(struct mail_storage *storage,
 				      int *syntax_error_r);
+};
+
+struct mail_storage {
+	char *name;
+	char hierarchy_sep;
+
+        struct mail_storage_vfuncs v;
 
 /* private: */
+	pool_t pool;
+
 	char *error;
 	enum mail_storage_flags flags;
 
+	/* Module-specific contexts. See mail_storage_module_id. */
+	array_t ARRAY_DEFINE(module_contexts, void);
+
 	unsigned int syntax_error:1; /* Give a BAD reply instead of NO */
 };
 
-struct mailbox {
-	char *name;
-
-	struct mail_storage *storage;
-
+struct mailbox_vfuncs {
 	int (*is_readonly)(struct mailbox *box);
 	int (*allow_new_keywords)(struct mailbox *box);
 
@@ -78,7 +87,8 @@
 			       void *context);
 
 	struct mailbox_transaction_context *
-		(*transaction_begin)(struct mailbox *box, int hide);
+		(*transaction_begin)(struct mailbox *box,
+				     enum mailbox_transaction_flags flags);
 	int (*transaction_commit)(struct mailbox_transaction_context *t,
 				  enum mailbox_sync_flags flags);
 	void (*transaction_rollback)(struct mailbox_transaction_context *t);
@@ -89,12 +99,14 @@
 	void (*keywords_free)(struct mailbox_transaction_context *t,
 			      struct mail_keywords *keywords);
 
-	struct mail *(*fetch)(struct mailbox_transaction_context *t,
-			      uint32_t seq,
-			      enum mail_fetch_field wanted_fields);
 	int (*get_uids)(struct mailbox *box, uint32_t uid1, uint32_t uid2,
 			uint32_t *seq1_r, uint32_t *seq2_r);
 
+	struct mail *
+		(*mail_alloc)(struct mailbox_transaction_context *t,
+			      enum mail_fetch_field wanted_fields,
+			      struct mailbox_header_lookup_ctx *wanted_headers);
+
 	struct mailbox_header_lookup_ctx *
 		(*header_lookup_init)(struct mailbox *box,
 				      const char *const headers[]);
@@ -105,11 +117,9 @@
 	struct mail_search_context *
 	(*search_init)(struct mailbox_transaction_context *t,
 		       const char *charset, struct mail_search_arg *args,
-		       const enum mail_sort_type *sort_program,
-		       enum mail_fetch_field wanted_fields,
-		       struct mailbox_header_lookup_ctx *wanted_headers);
+		       const enum mail_sort_type *sort_program);
 	int (*search_deinit)(struct mail_search_context *ctx);
-	struct mail *(*search_next)(struct mail_search_context *ctx);
+	int (*search_next)(struct mail_search_context *ctx, struct mail *mail);
 
 	struct mail_save_context *
 		(*save_init)(struct mailbox_transaction_context *t,
@@ -119,15 +129,68 @@
 			     const char *from_envelope, struct istream *input,
 			     int want_mail);
 	int (*save_continue)(struct mail_save_context *ctx);
-	int (*save_finish)(struct mail_save_context *ctx, struct mail **mail_r);
+	int (*save_finish)(struct mail_save_context *ctx,
+			   struct mail *dest_mail);
 	void (*save_cancel)(struct mail_save_context *ctx);
 
 	int (*copy)(struct mailbox_transaction_context *t, struct mail *mail,
-		    struct mail **dest_mail_r);
+		    struct mail *dest_mail);
 
 	int (*is_inconsistent)(struct mailbox *box);
 };
 
+struct mailbox {
+	char *name;
+	struct mail_storage *storage;
+
+        struct mailbox_vfuncs v;
+/* private: */
+	pool_t pool;
+
+	/* Module-specific contexts. See mail_storage_module_id. */
+	array_t ARRAY_DEFINE(module_contexts, void);
+};
+
+struct mail_vfuncs {
+	void (*free)(struct mail *mail);
+	int (*set_seq)(struct mail *mail, uint32_t seq);
+
+	enum mail_flags (*get_flags)(struct mail *mail);
+	const char *const *(*get_keywords)(struct mail *mail);
+	const struct message_part *(*get_parts)(struct mail *mail);
+
+	time_t (*get_received_date)(struct mail *mail);
+	time_t (*get_date)(struct mail *mail, int *timezone);
+	uoff_t (*get_virtual_size)(struct mail *mail);
+	uoff_t (*get_physical_size)(struct mail *mail);
+
+	const char *(*get_header)(struct mail *mail, const char *field);
+	struct istream *
+		(*get_headers)(struct mail *mail,
+			       struct mailbox_header_lookup_ctx *headers);
+	struct istream *(*get_stream)(struct mail *mail,
+				      struct message_size *hdr_size,
+				      struct message_size *body_size);
+
+	const char *(*get_special)(struct mail *mail,
+				   enum mail_fetch_field field);
+
+	int (*update_flags)(struct mail *mail, enum modify_type modify_type,
+			    enum mail_flags flags);
+	int (*update_keywords)(struct mail *mail, enum modify_type modify_type,
+			       struct mail_keywords *keywords);
+
+	int (*expunge)(struct mail *mail);
+};
+
+struct mail_private {
+	struct mail mail;
+	struct mail_vfuncs v;
+
+	pool_t pool;
+	array_t ARRAY_DEFINE(module_contexts, void);
+};
+
 struct mailbox_list_context {
 	struct mail_storage *storage;
 };
@@ -137,11 +200,11 @@
 };
 
 struct mail_search_context {
-	struct mailbox *box;
+	struct mailbox_transaction_context *transaction;
 };
 
 struct mail_save_context {
-	struct mailbox *box;
+	struct mailbox_transaction_context *transaction;
 };
 
 struct mailbox_sync_context {
--- a/src/lib-storage/mail-storage.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/mail-storage.c	Tue Mar 15 21:01:50 2005 +0200
@@ -18,6 +18,8 @@
 	struct mail_storage *storage;
 };
 
+unsigned int mail_storage_module_id = 0;
+
 static struct mail_storage_list *storages = NULL;
 
 void mail_storage_init(void)
@@ -76,7 +78,7 @@
 
 	for (list = storages; list != NULL; list = list->next) {
 		if (strcasecmp(list->storage->name, name) == 0)
-			return list->storage->create(data, user, flags);
+			return list->storage->v.create(data, user, flags);
 	}
 
 	return NULL;
@@ -89,7 +91,7 @@
 	struct mail_storage *storage;
 
 	for (list = storages; list != NULL; list = list->next) {
-		storage = list->storage->create(NULL, user, flags);
+		storage = list->storage->v.create(NULL, user, flags);
 		if (storage != NULL)
 			return storage;
 	}
@@ -103,7 +105,7 @@
 	struct mail_storage_list *list;
 
 	for (list = storages; list != NULL; list = list->next) {
-		if (list->storage->autodetect(data, flags))
+		if (list->storage->v.autodetect(data, flags))
 			return list->storage;
 	}
 
@@ -131,7 +133,7 @@
 	} else {
 		storage = mail_storage_autodetect(data, flags);
 		if (storage != NULL)
-			storage = storage->create(data, user, flags);
+			storage = storage->v.create(data, user, flags);
 	}
 
 	return storage;
@@ -141,7 +143,7 @@
 {
 	i_assert(storage != NULL);
 
-	storage->destroy(storage);
+	storage->v.destroy(storage);
 }
 
 void mail_storage_clear_error(struct mail_storage *storage)
@@ -228,24 +230,24 @@
 				struct mail_storage_callbacks *callbacks,
 				void *context)
 {
-	storage->set_callbacks(storage, callbacks, context);
+	storage->v.set_callbacks(storage, callbacks, context);
 }
 
 int mail_storage_mailbox_create(struct mail_storage *storage, const char *name,
 				int directory)
 {
-	return storage->mailbox_create(storage, name, directory);
+	return storage->v.mailbox_create(storage, name, directory);
 }
 
 int mail_storage_mailbox_delete(struct mail_storage *storage, const char *name)
 {
-	return storage->mailbox_delete(storage, name);
+	return storage->v.mailbox_delete(storage, name);
 }
 
 int mail_storage_mailbox_rename(struct mail_storage *storage,
 				const char *oldname, const char *newname)
 {
-	return storage->mailbox_rename(storage, oldname, newname);
+	return storage->v.mailbox_rename(storage, oldname, newname);
 }
 
 struct mailbox_list_context *
@@ -253,48 +255,48 @@
 			       const char *ref, const char *mask,
 			       enum mailbox_list_flags flags)
 {
-	return storage->mailbox_list_init(storage, ref, mask, flags);
+	return storage->v.mailbox_list_init(storage, ref, mask, flags);
 }
 
 struct mailbox_list *
 mail_storage_mailbox_list_next(struct mailbox_list_context *ctx)
 {
-	return ctx->storage->mailbox_list_next(ctx);
+	return ctx->storage->v.mailbox_list_next(ctx);
 }
 
 int mail_storage_mailbox_list_deinit(struct mailbox_list_context *ctx)
 {
-	return ctx->storage->mailbox_list_deinit(ctx);
+	return ctx->storage->v.mailbox_list_deinit(ctx);
 }
 
 int mail_storage_set_subscribed(struct mail_storage *storage,
 				const char *name, int set)
 {
-	return storage->set_subscribed(storage, name, set);
+	return storage->v.set_subscribed(storage, name, set);
 }
 
 int mail_storage_get_mailbox_name_status(struct mail_storage *storage,
 					 const char *name,
 					 enum mailbox_name_status *status)
 {
-	return storage->get_mailbox_name_status(storage, name, status);
+	return storage->v.get_mailbox_name_status(storage, name, status);
 }
 
 const char *mail_storage_get_last_error(struct mail_storage *storage,
 					int *syntax_error_r)
 {
-	return storage->get_last_error(storage, syntax_error_r);
+	return storage->v.get_last_error(storage, syntax_error_r);
 }
 
 struct mailbox *mailbox_open(struct mail_storage *storage,
 			     const char *name, enum mailbox_open_flags flags)
 {
-	return storage->mailbox_open(storage, name, flags);
+	return storage->v.mailbox_open(storage, name, flags);
 }
 
 int mailbox_close(struct mailbox *box)
 {
-	return box->close(box);
+	return box->v.close(box);
 }
 
 struct mail_storage *mailbox_get_storage(struct mailbox *box)
@@ -309,123 +311,115 @@
 
 int mailbox_is_readonly(struct mailbox *box)
 {
-	return box->is_readonly(box);
+	return box->v.is_readonly(box);
 }
 
 int mailbox_allow_new_keywords(struct mailbox *box)
 {
-	return box->allow_new_keywords(box);
+	return box->v.allow_new_keywords(box);
 }
 
 int mailbox_get_status(struct mailbox *box,
 		       enum mailbox_status_items items,
 		       struct mailbox_status *status)
 {
-	return box->get_status(box, items, status);
+	return box->v.get_status(box, items, status);
 }
 
 struct mailbox_sync_context *
 mailbox_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
 {
-	return box->sync_init(box, flags);
+	return box->v.sync_init(box, flags);
 }
 
 int mailbox_sync_next(struct mailbox_sync_context *ctx,
 		      struct mailbox_sync_rec *sync_rec_r)
 {
-	return ctx->box->sync_next(ctx, sync_rec_r);
+	return ctx->box->v.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);
+	return ctx->box->v.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);
+	box->v.notify_changes(box, min_interval, callback, context);
 }
 
 struct mail_keywords *
 mailbox_keywords_create(struct mailbox_transaction_context *t,
 			const char *const keywords[])
 {
-	return t->box->keywords_create(t, keywords);
+	return t->box->v.keywords_create(t, keywords);
 }
 
 void mailbox_keywords_free(struct mailbox_transaction_context *t,
 			   struct mail_keywords *keywords)
 {
-	t->box->keywords_free(t, keywords);
-}
-
-struct mail *mailbox_fetch(struct mailbox_transaction_context *t, uint32_t seq,
-			   enum mail_fetch_field wanted_fields)
-{
-	return t->box->fetch(t, seq, wanted_fields);
+	t->box->v.keywords_free(t, keywords);
 }
 
 int mailbox_get_uids(struct mailbox *box, uint32_t uid1, uint32_t uid2,
 		     uint32_t *seq1_r, uint32_t *seq2_r)
 {
-	return box->get_uids(box, uid1, uid2, seq1_r, seq2_r);
+	return box->v.get_uids(box, uid1, uid2, seq1_r, seq2_r);
 }
 
 struct mailbox_header_lookup_ctx *
 mailbox_header_lookup_init(struct mailbox *box, const char *const headers[])
 {
-	return box->header_lookup_init(box, headers);
+	return box->v.header_lookup_init(box, headers);
 }
 
 void mailbox_header_lookup_deinit(struct mailbox_header_lookup_ctx *ctx)
 {
-	ctx->box->header_lookup_deinit(ctx);
+	ctx->box->v.header_lookup_deinit(ctx);
 }
 
 int mailbox_search_get_sorting(struct mailbox *box,
 			       enum mail_sort_type *sort_program)
 {
-	return box->search_get_sorting(box, sort_program);
+	return box->v.search_get_sorting(box, sort_program);
 }
 
 struct mail_search_context *
 mailbox_search_init(struct mailbox_transaction_context *t,
 		    const char *charset, struct mail_search_arg *args,
-		    const enum mail_sort_type *sort_program,
-		    enum mail_fetch_field wanted_fields,
-		    struct mailbox_header_lookup_ctx *wanted_headers)
+		    const enum mail_sort_type *sort_program)
 {
-	return t->box->search_init(t, charset, args, sort_program,
-				   wanted_fields, wanted_headers);
+	return t->box->v.search_init(t, charset, args, sort_program);
 }
 
 int mailbox_search_deinit(struct mail_search_context *ctx)
 {
-	return ctx->box->search_deinit(ctx);
+	return ctx->transaction->box->v.search_deinit(ctx);
 }
 
-struct mail *mailbox_search_next(struct mail_search_context *ctx)
+int mailbox_search_next(struct mail_search_context *ctx, struct mail *mail)
 {
-	return ctx->box->search_next(ctx);
+	return ctx->transaction->box->v.search_next(ctx, mail);
 }
 
 struct mailbox_transaction_context *
-mailbox_transaction_begin(struct mailbox *box, int hide)
+mailbox_transaction_begin(struct mailbox *box,
+			  enum mailbox_transaction_flags flags)
 {
-	return box->transaction_begin(box, hide);
+	return box->v.transaction_begin(box, flags);
 }
 
 int mailbox_transaction_commit(struct mailbox_transaction_context *t,
 			       enum mailbox_sync_flags flags)
 {
-	return t->box->transaction_commit(t, flags);
+	return t->box->v.transaction_commit(t, flags);
 }
 
 void mailbox_transaction_rollback(struct mailbox_transaction_context *t)
 {
-	t->box->transaction_rollback(t);
+	t->box->v.transaction_rollback(t);
 }
 
 struct mail_save_context *
@@ -435,33 +429,33 @@
 		  const char *from_envelope, struct istream *input,
 		  int want_mail)
 {
-	return t->box->save_init(t, flags, keywords,
-				 received_date, timezone_offset,
-				 from_envelope, input, want_mail);
+	return t->box->v.save_init(t, flags, keywords,
+				   received_date, timezone_offset,
+				   from_envelope, input, want_mail);
 }
 
 int mailbox_save_continue(struct mail_save_context *ctx)
 {
-	return ctx->box->save_continue(ctx);
+	return ctx->transaction->box->v.save_continue(ctx);
 }
 
-int mailbox_save_finish(struct mail_save_context *ctx, struct mail **mail_r)
+int mailbox_save_finish(struct mail_save_context *ctx, struct mail *dest_mail)
 {
-	return ctx->box->save_finish(ctx, mail_r);
+	return ctx->transaction->box->v.save_finish(ctx, dest_mail);
 }
 
 void mailbox_save_cancel(struct mail_save_context *ctx)
 {
-	ctx->box->save_cancel(ctx);
+	ctx->transaction->box->v.save_cancel(ctx);
 }
 
 int mailbox_copy(struct mailbox_transaction_context *t, struct mail *mail,
-		 struct mail **dest_mail_r)
+		 struct mail *dest_mail)
 {
-	return t->box->copy(t, mail, dest_mail_r);
+	return t->box->v.copy(t, mail, dest_mail);
 }
 
 int mailbox_is_inconsistent(struct mailbox *box)
 {
-	return box->is_inconsistent(box);
+	return box->v.is_inconsistent(box);
 }
--- a/src/lib-storage/mail-storage.h	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/lib-storage/mail-storage.h	Tue Mar 15 21:01:50 2005 +0200
@@ -94,6 +94,14 @@
 	MAIL_FETCH_UIDL_FILE_NAME	= 0x00020000
 };
 
+enum mailbox_transaction_flags {
+	/* Hide changes done in this transaction from next view sync */
+	MAILBOX_TRANSACTION_FLAG_HIDE		= 0x01,
+	/* External transaction. Should be used for copying and appends,
+	   but nothing else. */
+	MAILBOX_TRANSACTION_FLAG_EXTERNAL	= 0x02
+};
+
 enum mailbox_sync_flags {
 	/* Make sure we sync all external changes done to mailbox */
 	MAILBOX_SYNC_FLAG_FULL_READ	= 0x01,
@@ -119,7 +127,6 @@
 struct mail_storage;
 struct mail_search_arg;
 struct mail_keywords;
-struct mail;
 struct mailbox;
 struct mailbox_list_context;
 struct mailbox_transaction_context;
@@ -151,6 +158,17 @@
 	enum mailbox_sync_type type;
 };
 
+struct mail {
+	/* always set */
+	struct mailbox *box;
+	struct mailbox_transaction_context *transaction;
+	uint32_t seq, uid;
+
+	unsigned int expunged:1;
+	unsigned int has_nuls:1; /* message data is known to contain NULs */
+	unsigned int has_no_nuls:1; /* -''- known to not contain NULs */
+};
+
 struct mail_storage_callbacks {
 	/* Alert: Not enough disk space */
 	void (*alert_no_diskspace)(struct mailbox *mailbox, void *context);
@@ -291,7 +309,8 @@
 			    mailbox_notify_callback_t *callback, void *context);
 
 struct mailbox_transaction_context *
-mailbox_transaction_begin(struct mailbox *box, int hide);
+mailbox_transaction_begin(struct mailbox *box,
+			  enum mailbox_transaction_flags flags);
 int mailbox_transaction_commit(struct mailbox_transaction_context *t,
 			       enum mailbox_sync_flags flags);
 void mailbox_transaction_rollback(struct mailbox_transaction_context *t);
@@ -303,10 +322,6 @@
 void mailbox_keywords_free(struct mailbox_transaction_context *t,
 			   struct mail_keywords *keywords);
 
-/* Simplified fetching for a single sequence. */
-struct mail *mailbox_fetch(struct mailbox_transaction_context *t, uint32_t seq,
-			   enum mail_fetch_field wanted_fields);
-
 /* Convert uid range to sequence range. */
 int mailbox_get_uids(struct mailbox *box, uint32_t uid1, uint32_t uid2,
 		     uint32_t *seq1_r, uint32_t *seq2_r);
@@ -326,21 +341,15 @@
 
    If sort_program is non-NULL, it requests that the returned messages
    are sorted by the given criteria. sort_program must have gone
-   through search_get_sorting().
-
-   wanted_fields and wanted_headers aren't required, but they can be
-   used for optimizations. */
+   through search_get_sorting(). */
 struct mail_search_context *
 mailbox_search_init(struct mailbox_transaction_context *t,
 		    const char *charset, struct mail_search_arg *args,
-		    const enum mail_sort_type *sort_program,
-		    enum mail_fetch_field wanted_fields,
-                    struct mailbox_header_lookup_ctx *wanted_headers);
+		    const enum mail_sort_type *sort_program);
 /* Deinitialize search request. */
 int mailbox_search_deinit(struct mail_search_context *ctx);
-/* Search the next message. Returned mail object can be used until
-   the next call to search_next() or search_deinit(). */
-struct mail *mailbox_search_next(struct mail_search_context *ctx);
+/* Search the next message. Returns 1 if found, 0 if not, -1 if failure. */
+int mailbox_search_next(struct mail_search_context *ctx, struct mail *mail);
 
 /* Save a mail into mailbox. timezone_offset specifies the timezone in
    minutes in which received_date was originally given with. To use
@@ -356,14 +365,14 @@
 		  const char *from_envelope, struct istream *input,
 		  int want_mail);
 int mailbox_save_continue(struct mail_save_context *ctx);
-int mailbox_save_finish(struct mail_save_context *ctx, struct mail **mail_r);
+int mailbox_save_finish(struct mail_save_context *ctx, struct mail *dest_mail);
 void mailbox_save_cancel(struct mail_save_context *ctx);
 
-/* Copy given message. If dest_mail_r is non-NULL, the copied message can be
+/* Copy given message. If dest_mail is non-NULL, the copied message can be
    accessed using it. Note that setting it non-NULL may require mailbox
    syncing, so don't give give it unless you need it. */
 int mailbox_copy(struct mailbox_transaction_context *t, struct mail *mail,
-		 struct mail **dest_mail_r);
+		 struct mail *dest_mail);
 
 /* Returns TRUE if mailbox is now in inconsistent state, meaning that
    the message IDs etc. may have changed - only way to recover this
@@ -372,60 +381,56 @@
    do forced CLOSE. */
 int mailbox_is_inconsistent(struct mailbox *box);
 
-struct mail {
-	/* always set */
-	struct mailbox *box;
-	struct mailbox_transaction_context *transaction;
-	uint32_t seq, uid;
-
-	unsigned int expunged:1;
-	unsigned int has_nuls:1; /* message data is known to contain NULs */
-	unsigned int has_no_nuls:1; /* -''- known to not contain NULs */
-
-	enum mail_flags (*get_flags)(struct mail *mail);
-	const char *const *(*get_keywords)(struct mail *mail);
-	const struct message_part *(*get_parts)(struct mail *mail);
+/* Returns message's flags */
+enum mail_flags mail_get_flags(struct mail *mail);
+/* Returns message's keywords */
+const char *const *mail_get_keywords(struct mail *mail);
+/* Returns message's MIME parts */
+const struct message_part *mail_get_parts(struct mail *mail);
 
-	/* Get the time message was received (IMAP INTERNALDATE).
-	   Returns (time_t)-1 if error occured. */
-	time_t (*get_received_date)(struct mail *mail);
-	/* Get the Date-header in mail. Timezone is in minutes.
-	   Returns (time_t)-1 if error occured, 0 if field wasn't found or
-	   couldn't be parsed. */
-	time_t (*get_date)(struct mail *mail, int *timezone);
-	/* Get the full virtual size of mail (IMAP RFC822.SIZE).
-	   Returns (uoff_t)-1 if error occured */
-	uoff_t (*get_virtual_size)(struct mail *mail);
-	/* Get the full physical size of mail.
-	   Returns (uoff_t)-1 if error occured */
-	uoff_t (*get_physical_size)(struct mail *mail);
+struct mail *mail_alloc(struct mailbox_transaction_context *t,
+			enum mail_fetch_field wanted_fields,
+			struct mailbox_header_lookup_ctx *wanted_headers);
+void mail_free(struct mail *mail);
+int mail_set_seq(struct mail *mail, uint32_t seq);
+
+/* Get the time message was received (IMAP INTERNALDATE).
+   Returns (time_t)-1 if error occured. */
+time_t mail_get_received_date(struct mail *mail);
+/* Get the Date-header in mail. Timezone is in minutes.
+   Returns (time_t)-1 if error occured, 0 if field wasn't found or
+   couldn't be parsed. */
+time_t mail_get_date(struct mail *mail, int *timezone);
 
-	/* Get value for single header field */
-	const char *(*get_header)(struct mail *mail, const char *field);
-	/* Returns stream containing specified headers. */
-	struct istream *
-		(*get_headers)(struct mail *mail,
-			       struct mailbox_header_lookup_ctx *headers);
-
-	/* Returns input stream pointing to beginning of message header.
-	   hdr_size and body_size are updated unless they're NULL. */
-	struct istream *(*get_stream)(struct mail *mail,
-				      struct message_size *hdr_size,
-				      struct message_size *body_size);
+/* Get the full virtual size of mail (IMAP RFC822.SIZE).
+   Returns (uoff_t)-1 if error occured */
+uoff_t mail_get_virtual_size(struct mail *mail);
+/* Get the full physical size of mail.
+   Returns (uoff_t)-1 if error occured */
+uoff_t mail_get_physical_size(struct mail *mail);
 
-	/* Get any of the "special" fields. */
-	const char *(*get_special)(struct mail *mail,
-				   enum mail_fetch_field field);
+/* Get value for single header field */
+const char *mail_get_header(struct mail *mail, const char *field);
+/* Returns stream containing specified headers. */
+struct istream *mail_get_headers(struct mail *mail,
+				 struct mailbox_header_lookup_ctx *headers);
+/* Returns input stream pointing to beginning of message header.
+   hdr_size and body_size are updated unless they're NULL. */
+struct istream *mail_get_stream(struct mail *mail,
+				struct message_size *hdr_size,
+				struct message_size *body_size);
 
-	/* Update message flags. */
-	int (*update_flags)(struct mail *mail, enum modify_type modify_type,
-			    enum mail_flags flags);
-	/* Update message keywords. */
-	int (*update_keywords)(struct mail *mail, enum modify_type modify_type,
-			       struct mail_keywords *keywords);
+/* Get any of the "special" fields. */
+const char *mail_get_special(struct mail *mail, enum mail_fetch_field field);
 
-	/* Expunge this message. Sequence numbers don't change until commit. */
-	int (*expunge)(struct mail *mail);
-};
+/* Update message flags. */
+int mail_update_flags(struct mail *mail, enum modify_type modify_type,
+		      enum mail_flags flags);
+/* Update message keywords. */
+int mail_update_keywords(struct mail *mail, enum modify_type modify_type,
+			 struct mail_keywords *keywords);
+
+/* Expunge this message. Sequence numbers don't change until commit. */
+int mail_expunge(struct mail *mail);
 
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mail.c	Tue Mar 15 21:01:50 2005 +0200
@@ -0,0 +1,133 @@
+/* Copyright (C) 2002-2003 Timo Sirainen */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "mail-storage-private.h"
+
+struct mail *mail_alloc(struct mailbox_transaction_context *t,
+			enum mail_fetch_field wanted_fields,
+			struct mailbox_header_lookup_ctx *wanted_headers)
+{
+	return t->box->v.mail_alloc(t, wanted_fields, wanted_headers);
+}
+
+void mail_free(struct mail *mail)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.free(mail);
+}
+
+int mail_set_seq(struct mail *mail, uint32_t seq)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.set_seq(mail, seq);
+}
+
+enum mail_flags mail_get_flags(struct mail *mail)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_flags(mail);
+}
+
+const char *const *mail_get_keywords(struct mail *mail)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_keywords(mail);
+}
+
+const struct message_part *mail_get_parts(struct mail *mail)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_parts(mail);
+}
+
+time_t mail_get_received_date(struct mail *mail)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_received_date(mail);
+}
+
+time_t mail_get_date(struct mail *mail, int *timezone)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_date(mail, timezone);
+}
+
+uoff_t mail_get_virtual_size(struct mail *mail)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_virtual_size(mail);
+}
+
+uoff_t mail_get_physical_size(struct mail *mail)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_physical_size(mail);
+}
+
+const char *mail_get_header(struct mail *mail, const char *field)
+{
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_header(mail, field);
+}
+}
+
+struct istream *mail_get_headers(struct mail *mail,
+				 struct mailbox_header_lookup_ctx *headers)
+{
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_headers(mail, headers);
+}
+}
+
+struct istream *mail_get_stream(struct mail *mail,
+				struct message_size *hdr_size,
+				struct message_size *body_size)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_stream(mail, hdr_size, body_size);
+}
+
+const char *mail_get_special(struct mail *mail, enum mail_fetch_field field)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.get_special(mail, field);
+}
+
+int mail_update_flags(struct mail *mail, enum modify_type modify_type,
+		      enum mail_flags flags)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.update_flags(mail, modify_type, flags);
+}
+
+int mail_update_keywords(struct mail *mail, enum modify_type modify_type,
+			 struct mail_keywords *keywords)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.update_keywords(mail, modify_type, keywords);
+}
+
+int mail_expunge(struct mail *mail)
+{
+	struct mail_private *p = (struct mail_private *)mail;
+
+	return p->v.expunge(mail);
+}
--- a/src/lib-storage/proxy-mail-storage.c	Tue Mar 15 20:58:18 2005 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-/* Copyright (C) 2003 Timo Sirainen */
-
-#include "lib.h"
-#include "proxy-mail-storage.h"
-
-static void _destroy(struct mail_storage *storage)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	s->storage->destroy(s->storage);
-}
-
-static void _set_callbacks(struct mail_storage *storage,
-			   struct mail_storage_callbacks *callbacks,
-			   void *context)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	s->storage->set_callbacks(s->storage, callbacks, context);
-}
-
-static struct mailbox *_mailbox_open(struct mail_storage *storage,
-				     const char *name,
-				     enum mailbox_open_flags flags)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-        return s->storage->mailbox_open(s->storage, name, flags);
-}
-
-static int _mailbox_create(struct mail_storage *storage, const char *name,
-			   int only_hierarchy)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	return s->storage->mailbox_create(s->storage, name, only_hierarchy);
-}
-
-static int _mailbox_delete(struct mail_storage *storage, const char *name)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	return s->storage->mailbox_delete(s->storage, name);
-}
-
-static int _mailbox_rename(struct mail_storage *storage, const char *oldname,
-			   const char *newname)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	return s->storage->mailbox_rename(s->storage, oldname, newname);
-}
-
-static struct mailbox_list_context *
-_mailbox_list_init(struct mail_storage *storage,
-		   const char *ref, const char *mask,
-		   enum mailbox_list_flags flags)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	return s->storage->mailbox_list_init(s->storage, ref, mask, flags);
-}
-
-static int _set_subscribed(struct mail_storage *storage,
-			   const char *name, int set)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	return s->storage->set_subscribed(s->storage, name, set);
-}
-
-static int _get_mailbox_name_status(struct mail_storage *storage,
-				    const char *name,
-				    enum mailbox_name_status *status)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	return s->storage->get_mailbox_name_status(s->storage, name, status);
-}
-
-static const char *_get_last_error(struct mail_storage *storage,
-				   int *syntax_error)
-{
-	struct proxy_mail_storage *s = (struct proxy_mail_storage *) storage;
-
-	return s->storage->get_last_error(s->storage, syntax_error);
-}
-
-void proxy_mail_storage_init(struct proxy_mail_storage *proxy,
-			     struct mail_storage *storage)
-{
-	struct mail_storage *ps = &proxy->proxy_storage;
-
-	proxy->storage = storage;
-
-	ps->name = storage->name;
-	ps->hierarchy_sep = storage->hierarchy_sep;
-
-	ps->create = storage->create;
-	ps->autodetect = storage->autodetect;
-	ps->mailbox_list_deinit = storage->mailbox_list_deinit;
-	ps->mailbox_list_next = storage->mailbox_list_next;
-
-	ps->destroy = _destroy;
-	ps->set_callbacks = _set_callbacks;
-	ps->mailbox_open = _mailbox_open;
-	ps->mailbox_create = _mailbox_create;
-	ps->mailbox_delete = _mailbox_delete;
-	ps->mailbox_rename = _mailbox_rename;
-	ps->mailbox_list_init = _mailbox_list_init;
-	ps->set_subscribed = _set_subscribed;
-	ps->get_mailbox_name_status = _get_mailbox_name_status;
-	ps->get_last_error = _get_last_error;
-}
--- a/src/lib-storage/proxy-mail-storage.h	Tue Mar 15 20:58:18 2005 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-#ifndef __PROXY_MAIL_STORAGE_H
-#define __PROXY_MAIL_STORAGE_H
-
-#include "mail-storage-private.h"
-
-struct proxy_mail_storage {
-	struct mail_storage proxy_storage;
-	struct mail_storage *storage;
-};
-
-void proxy_mail_storage_init(struct proxy_mail_storage *proxy,
-			     struct mail_storage *storage);
-
-#endif
--- a/src/lib-storage/proxy-mail.c	Tue Mar 15 20:58:18 2005 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/* Copyright (C) 2003 Timo Sirainen */
-
-#include "lib.h"
-#include "proxy-mail.h"
-
-static enum mail_flags _get_flags(struct mail *mail)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_flags(p->mail);
-}
-
-static const char *const *_get_keywords(struct mail *mail)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_keywords(p->mail);
-}
-
-static const struct message_part *_get_parts(struct mail *mail)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_parts(p->mail);
-}
-
-static time_t _get_received_date(struct mail *mail)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_received_date(p->mail);
-}
-
-static time_t _get_date(struct mail *mail, int *timezone)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_date(p->mail, timezone);
-}
-
-static uoff_t _get_virtual_size(struct mail *mail)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_virtual_size(p->mail);
-}
-
-static uoff_t _get_physical_size(struct mail *mail)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_physical_size(p->mail);
-}
-
-static const char *_get_header(struct mail *mail, const char *field)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_header(p->mail, field);
-}
-
-static struct istream *
-_get_headers(struct mail *mail, struct mailbox_header_lookup_ctx *headers)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_headers(p->mail, headers);
-}
-
-static struct istream *_get_stream(struct mail *mail,
-				   struct message_size *hdr_size,
-				   struct message_size *body_size)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_stream(p->mail, hdr_size, body_size);
-}
-
-static const char *_get_special(struct mail *mail, enum mail_fetch_field field)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->get_special(p->mail, field);
-}
-
-static int _update_flags(struct mail *mail, enum modify_type modify_type,
-			 enum mail_flags flags)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->update_flags(p->mail, modify_type, flags);
-}
-
-static int _update_keywords(struct mail *mail, enum modify_type modify_type,
-			    struct mail_keywords *keywords)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->update_keywords(p->mail, modify_type, keywords);
-}
-
-static int _expunge(struct mail *mail)
-{
-	struct proxy_mail *p = (struct proxy_mail *) mail;
-
-	return p->mail->expunge(p->mail);
-}
-
-void proxy_mail_init(struct proxy_mail *proxy, struct mail *mail)
-{
-	struct mail *pm = &proxy->proxy_mail;
-
-	proxy->mail = mail;
-
-	pm->box = mail->box;
-
-	pm->get_flags = _get_flags;
-	pm->get_keywords = _get_keywords;
-	pm->get_parts = _get_parts;
-	pm->get_received_date = _get_received_date;
-	pm->get_date = _get_date;
-	pm->get_virtual_size = _get_virtual_size;
-	pm->get_physical_size = _get_physical_size;
-	pm->get_header = _get_header;
-	pm->get_headers = _get_headers;
-	pm->get_stream = _get_stream;
-	pm->get_special = _get_special;
-	pm->update_flags = _update_flags;
-	pm->update_keywords = _update_keywords;
-	pm->expunge = _expunge;
-}
-
-void proxy_mail_next(struct proxy_mail *proxy)
-{
-	proxy->proxy_mail.seq = proxy->mail->seq;
-	proxy->proxy_mail.uid = proxy->mail->uid;
-
-	proxy->proxy_mail.has_nuls = proxy->mail->has_nuls;
-	proxy->proxy_mail.has_no_nuls = proxy->mail->has_no_nuls;
-}
--- a/src/lib-storage/proxy-mail.h	Tue Mar 15 20:58:18 2005 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-#ifndef __PROXY_MAIL_H
-#define __PROXY_MAIL_H
-
-#include "mail-storage.h"
-
-struct proxy_mail {
-	struct mail proxy_mail;
-	struct mail *mail;
-};
-
-void proxy_mail_init(struct proxy_mail *proxy, struct mail *mail);
-void proxy_mail_next(struct proxy_mail *proxy);
-
-#endif
--- a/src/lib-storage/proxy-mailbox.c	Tue Mar 15 20:58:18 2005 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,220 +0,0 @@
-/* Copyright (C) 2003 Timo Sirainen */
-
-#include "lib.h"
-#include "proxy-mailbox.h"
-
-static int _is_readonly(struct mailbox *box)
-{
-	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
-
-	return p->box->is_readonly(p->box);
-}
-
-static int _allow_new_keywords(struct mailbox *box)
-{
-	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
-
-	return p->box->allow_new_keywords(p->box);
-}
-
-static int _close(struct mailbox *box)
-{
-	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
-
-	return p->box->close(p->box);
-}
-
-static int _get_status(struct mailbox *box, enum mailbox_status_items items,
-		       struct mailbox_status *status)
-{
-	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
-
-	return p->box->get_status(p->box, items, status);
-}
-
-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_init(p->box, flags);
-}
-
-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->notify_changes(box, min_interval, callback, context);
-}
-
-static struct mail *_fetch(struct mailbox_transaction_context *t, uint32_t seq,
-			   enum mail_fetch_field wanted_fields)
-{
-	struct proxy_mailbox_transaction_context *pt =
-		(struct proxy_mailbox_transaction_context *)t;
-	struct proxy_mailbox *pbox = (struct proxy_mailbox *)t->box;
-
-	return pbox->box->fetch(pt->ctx, seq, wanted_fields);
-}
-
-static int _get_uids(struct mailbox *box, uint32_t uid1, uint32_t uid2,
-		     uint32_t *seq1_r, uint32_t *seq2_r)
-{
-	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
-
-	return p->box->get_uids(p->box, uid1, uid2, seq1_r, seq2_r);
-}
-
-static struct mailbox_header_lookup_ctx *
-_header_lookup_init(struct mailbox *box, const char *const headers[])
-{
-	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
-
-	return p->box->header_lookup_init(p->box, headers);
-}
-
-static int _search_get_sorting(struct mailbox *box,
-			       enum mail_sort_type *sort_program)
-{
-	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
-
-	return p->box->search_get_sorting(p->box, sort_program);
-}
-
-static struct mail_search_context *
-_search_init(struct mailbox_transaction_context *t,
-	     const char *charset, struct mail_search_arg *args,
-	     const enum mail_sort_type *sort_program,
-	     enum mail_fetch_field wanted_fields,
-	     struct mailbox_header_lookup_ctx *wanted_headers)
-{
-	struct proxy_mailbox_transaction_context *pt =
-		(struct proxy_mailbox_transaction_context *)t;
-	struct proxy_mailbox *pbox = (struct proxy_mailbox *)t->box;
-
-	return pbox->box->search_init(pt->ctx, charset, args, sort_program,
-				      wanted_fields, wanted_headers);
-}
-
-static int _transaction_commit(struct mailbox_transaction_context *t,
-			       enum mailbox_sync_flags flags)
-{
-	struct proxy_mailbox_transaction_context *pt =
-		(struct proxy_mailbox_transaction_context *)t;
-	struct proxy_mailbox *pbox = (struct proxy_mailbox *)t->box;
-
-	return pbox->box->transaction_commit(pt->ctx, flags);
-}
-
-static void _transaction_rollback(struct mailbox_transaction_context *t)
-{
-	struct proxy_mailbox_transaction_context *pt =
-		(struct proxy_mailbox_transaction_context *)t;
-	struct proxy_mailbox *pbox = (struct proxy_mailbox *)t->box;
-
-	pbox->box->transaction_rollback(pt->ctx);
-}
-
-static struct mail_keywords *
-_keywords_create(struct mailbox_transaction_context *t,
-		 const char *const keywords[])
-{
-	struct proxy_mailbox_transaction_context *pt =
-		(struct proxy_mailbox_transaction_context *)t;
-	struct proxy_mailbox *pbox = (struct proxy_mailbox *)t->box;
-
-	return pbox->box->keywords_create(pt->ctx, keywords);
-}
-
-static void _keywords_free(struct mailbox_transaction_context *t,
-			   struct mail_keywords *keywords)
-{
-	struct proxy_mailbox_transaction_context *pt =
-		(struct proxy_mailbox_transaction_context *)t;
-	struct proxy_mailbox *pbox = (struct proxy_mailbox *)t->box;
-
-	pbox->box->keywords_free(pt->ctx, keywords);
-}
-
-static struct mail_save_context *
-_save_init(struct mailbox_transaction_context *t,
-	   enum mail_flags flags, struct mail_keywords *keywords,
-	   time_t received_date, int timezone_offset,
-	   const char *from_envelope, struct istream *input, int want_mail)
-{
-	struct proxy_mailbox_transaction_context *pt =
-		(struct proxy_mailbox_transaction_context *)t;
-	struct proxy_mailbox *pbox = (struct proxy_mailbox *)t->box;
-
-	return pbox->box->save_init(pt->ctx, flags, keywords, received_date,
-				    timezone_offset, from_envelope, input,
-				    want_mail);
-}
-
-static int _copy(struct mailbox_transaction_context *t, struct mail *mail,
-		 struct mail **dest_mail_r)
-{
-	struct proxy_mailbox_transaction_context *pt =
-		(struct proxy_mailbox_transaction_context *)t;
-	struct proxy_mailbox *pbox = (struct proxy_mailbox *)t->box;
-
-	return pbox->box->copy(pt->ctx, mail, dest_mail_r);
-}
-
-static int _is_inconsistent(struct mailbox *box)
-{
-	struct proxy_mailbox *p = (struct proxy_mailbox *) box;
-
-	return p->box->is_inconsistent(p->box);
-}
-
-void proxy_mailbox_init(struct proxy_mailbox *proxy, struct mailbox *box)
-{
-	struct mailbox *pb = &proxy->proxy_box;
-
-	proxy->box = box;
-
-	pb->name = box->name;
-	pb->storage = box->storage;
-
-	pb->is_readonly = _is_readonly;
-	pb->allow_new_keywords = _allow_new_keywords;
-	pb->close = _close;
-	pb->get_status = _get_status;
-	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;
-	pb->header_lookup_init = _header_lookup_init;
-
-	pb->search_get_sorting = _search_get_sorting;
-	pb->search_init = _search_init;
-	pb->search_next = box->search_next;
-	pb->search_deinit = box->search_deinit;
-
-	pb->transaction_begin = NULL; /* must be implemented */
-	pb->transaction_commit = _transaction_commit;
-	pb->transaction_rollback = _transaction_rollback;
-
-	pb->keywords_create = _keywords_create;
-	pb->keywords_free = _keywords_free;
-
-	pb->save_init = _save_init;
-	pb->save_continue = box->save_continue;
-	pb->save_finish = box->save_finish;
-	pb->save_cancel = box->save_cancel;
-	pb->copy = _copy;
-
-	pb->is_inconsistent = _is_inconsistent;
-}
-
-void proxy_transaction_init(struct proxy_mailbox *proxy_box,
-			    struct proxy_mailbox_transaction_context *proxy_ctx,
-			    struct mailbox_transaction_context *ctx)
-{
-	proxy_ctx->proxy_ctx.box = &proxy_box->proxy_box;
-	proxy_ctx->ctx = ctx;
-}
--- a/src/lib-storage/proxy-mailbox.h	Tue Mar 15 20:58:18 2005 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#ifndef __PROXY_MAILBOX_H
-#define __PROXY_MAILBOX_H
-
-#include "mail-storage-private.h"
-
-struct proxy_mailbox {
-	struct mailbox proxy_box;
-	struct mailbox *box;
-};
-
-struct proxy_mailbox_transaction_context {
-	struct mailbox_transaction_context proxy_ctx;
-	struct mailbox_transaction_context *ctx;
-};
-
-void proxy_mailbox_init(struct proxy_mailbox *proxy_box, struct mailbox *box);
-void proxy_transaction_init(struct proxy_mailbox *proxy_box,
-			    struct proxy_mailbox_transaction_context *proxy_ctx,
-                            struct mailbox_transaction_context *ctx);
-
-#endif
--- a/src/pop3/client.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/pop3/client.c	Tue Mar 15 21:01:50 2005 +0200
@@ -70,9 +70,8 @@
 		}
 		client->uid_validity = status.uidvalidity;
 
-		t = mailbox_transaction_begin(client->mailbox, FALSE);
-		ctx = mailbox_search_init(t, NULL, &search_arg, NULL,
-					  MAIL_FETCH_VIRTUAL_SIZE, NULL);
+		t = mailbox_transaction_begin(client->mailbox, 0);
+		ctx = mailbox_search_init(t, NULL, &search_arg, NULL);
 		if (ctx == NULL) {
 			client_send_storage_error(client);
 			mailbox_transaction_rollback(t);
@@ -84,15 +83,16 @@
 		buffer_set_used_size(message_sizes_buf, 0);
 
 		failed = FALSE;
-		while ((mail = mailbox_search_next(ctx)) != NULL) {
-			uoff_t size = mail->get_virtual_size(mail);
+		mail = mail_alloc(t, MAIL_FETCH_VIRTUAL_SIZE, NULL);
+		while (mailbox_search_next(ctx, mail) > 0) {
+			uoff_t size = mail_get_virtual_size(mail);
 
 			if (size == (uoff_t)-1) {
 				failed = TRUE;
 				break;
 			}
 
-			if ((mail->get_flags(mail) & MAIL_SEEN) != 0)
+			if ((mail_get_flags(mail) & MAIL_SEEN) != 0)
 				client->last_seen = mail->seq;
                         client->total_size += size;
 
@@ -101,6 +101,7 @@
 		client->messages_count =
 			message_sizes_buf->used / sizeof(uoff_t);
 
+		mail_free(mail);
 		if (mailbox_search_deinit(ctx) < 0) {
 			client_send_storage_error(client);
 			mailbox_transaction_rollback(t);
--- a/src/pop3/commands.c	Tue Mar 15 20:58:18 2005 +0200
+++ b/src/pop3/commands.c	Tue Mar 15 21:01:50 2005 +0200
@@ -185,6 +185,7 @@
 	struct mail_search_context *ctx;
 	struct mail *mail;
 	uint32_t idx;
+	int ret = TRUE;
 
 	if (client->deleted_bitmask == NULL)
 		return TRUE;
@@ -192,18 +193,23 @@
 	memset(&search_arg, 0, sizeof(search_arg));
 	search_arg.type = SEARCH_ALL;
 
-	ctx = mailbox_search_init(client->trans, NULL, &search_arg,
-				  NULL, 0, NULL);
-	while ((mail = mailbox_search_next(ctx)) != NULL) {
+	ctx = mailbox_search_init(client->trans, NULL, &search_arg, NULL);
+	mail = mail_alloc(client->trans, 0, NULL);
+	while (mailbox_search_next(ctx, mail) > 0) {
 		idx = mail->seq - 1;
 		if ((client->deleted_bitmask[idx / CHAR_BIT] &
 		     1 << (idx % CHAR_BIT)) != 0) {
-			if (mail->expunge(mail) < 0)
-				return FALSE;
+			if (mail_expunge(mail) < 0) {
+				ret = FALSE;
+				break;
+			}
 		}
 	}
+	mail_free(mail);
 
-	return mailbox_search_deinit(ctx) == 0;
+	if (mailbox_search_deinit(ctx) < 0)
+		ret = FALSE;
+	return ret;
 }
 
 static int cmd_quit(struct client *client, const char *args __attr_unused__)
@@ -230,6 +236,7 @@
 
 struct fetch_context {
 	struct mail_search_context *search_ctx;
+	struct mail *mail;
 	struct istream *stream;
 	uoff_t body_lines;
 
@@ -243,6 +250,7 @@
 static void fetch_deinit(struct fetch_context *ctx)
 {
 	(void)mailbox_search_deinit(ctx->search_ctx);
+	mail_free(ctx->mail);
 	i_free(ctx);
 }
 
@@ -342,7 +350,6 @@
 static void fetch(struct client *client, unsigned int msgnum, uoff_t body_lines)
 {
         struct fetch_context *ctx;
-	struct mail *mail;
 
 	ctx = i_new(struct fetch_context, 1);
 
@@ -351,11 +358,15 @@
 	ctx->search_arg.value.seqset = &ctx->seqset;
 
 	ctx->search_ctx = mailbox_search_init(client->trans, NULL,
-					      &ctx->search_arg,
-					      NULL, MAIL_FETCH_STREAM_HEADER |
-					      MAIL_FETCH_STREAM_BODY, NULL);
-	mail = mailbox_search_next(ctx->search_ctx);
-	ctx->stream = mail == NULL ? NULL : mail->get_stream(mail, NULL, NULL);
+					      &ctx->search_arg, NULL);
+	ctx->mail = mail_alloc(client->trans, MAIL_FETCH_STREAM_HEADER |
+			       MAIL_FETCH_STREAM_BODY, NULL);
+
+	if (mailbox_search_next(ctx->search_ctx, ctx->mail) <= 0)
+		ctx->stream = NULL;
+	else
+		ctx->stream = mail_get_stream(ctx->mail, NULL, NULL);
+
 	if (ctx->stream == NULL) {
 		client_send_line(client, "-ERR Message not found.");
 		fetch_deinit(ctx);
@@ -363,9 +374,10 @@
 	}
 
 	if (body_lines == (uoff_t)-1 && !no_flag_updates) {
-		if ((mail->get_flags(mail) & MAIL_SEEN) == 0) {
+		if ((mail_get_flags(ctx->mail) & MAIL_SEEN) == 0) {
 			/* mark the message seen with RETR command */
-			(void)mail->update_flags(mail, MODIFY_ADD, MAIL_SEEN);
+			(void)mail_update_flags(ctx->mail,
+						MODIFY_ADD, MAIL_SEEN);
 		}
 	}
 
@@ -414,7 +426,7 @@
 
 	/* forget all our seen flag updates as well.. */
 	mailbox_transaction_rollback(client->trans);
-	client->trans = mailbox_transaction_begin(client->mailbox, FALSE);
+	client->trans = mailbox_transaction_begin(client->mailbox, 0);
 
 	if (enable_last_command) {
 		/* remove all \Seen flags */
@@ -422,12 +434,14 @@
 		search_arg.type = SEARCH_ALL;
 
 		search_ctx = mailbox_search_init(client->trans, NULL,
-						 &search_arg, NULL, 0, NULL);
-		while ((mail = mailbox_search_next(search_ctx)) != NULL) {
-			if (mail->update_flags(mail, MAIL_SEEN,
-					       MODIFY_REMOVE) < 0)
+						 &search_arg, NULL);
+		mail = mail_alloc(client->trans, 0, NULL);
+		while (mailbox_search_next(search_ctx, mail) > 0) {
+			if (mail_update_flags(mail, MAIL_SEEN,
+					      MODIFY_REMOVE) < 0)
 				break;
 		}
+		mail_free(mail);
 		(void)mailbox_search_deinit(search_ctx);
 	}
 
@@ -460,6 +474,7 @@
 
 struct cmd_uidl_context {
 	struct mail_search_context *search_ctx;
+	struct mail *mail;
 	unsigned int message;
 
 	struct mail_search_arg search_arg;
@@ -476,7 +491,6 @@
 		{ '\0', NULL }
 	};
 	struct var_expand_table *tab;
-	struct mail *mail;
 	string_t *str;
 	int ret, found = FALSE;
 
@@ -485,10 +499,9 @@
 	tab[0].value = t_strdup_printf("%u", client->uid_validity);
 
 	str = str_new(default_pool, 128);
-
-	while ((mail = mailbox_search_next(ctx->search_ctx)) != NULL) {
+	while (mailbox_search_next(ctx->search_ctx, ctx->mail) > 0) {
 		if (client->deleted) {
-			uint32_t idx = mail->seq - 1;
+			uint32_t idx = ctx->mail->seq - 1;
 			if (client->deleted_bitmask[idx / CHAR_BIT] &
 			    (1 << (idx % CHAR_BIT)))
 				continue;
@@ -497,20 +510,20 @@
 
 		t_push();
 		if ((uidl_keymask & UIDL_UID) != 0)
-			tab[1].value = dec2str(mail->uid);
+			tab[1].value = dec2str(ctx->mail->uid);
 		if ((uidl_keymask & UIDL_MD5) != 0) {
-			tab[2].value =
-				mail->get_special(mail, MAIL_FETCH_HEADER_MD5);
+			tab[2].value = mail_get_special(ctx->mail,
+							MAIL_FETCH_HEADER_MD5);
 		}
 		if ((uidl_keymask & UIDL_FILE_NAME) != 0) {
 			tab[3].value =
-				mail->get_special(mail,
-						  MAIL_FETCH_UIDL_FILE_NAME);
+				mail_get_special(ctx->mail,
+						 MAIL_FETCH_UIDL_FILE_NAME);
 		}
 
 		str_truncate(str, 0);
 		str_printfa(str, ctx->message == 0 ? "%u " : "+OK %u ",
-			    mail->seq);
+			    ctx->mail->seq);
 		var_expand(str, uidl_format, tab);
 
 		ret = client_send_line(client, "%s", str_c(str));
@@ -528,6 +541,7 @@
 	str_free(str);
 
 	/* finished */
+	mail_free(ctx->mail);
 	(void)mailbox_search_deinit(ctx->search_ctx);
 
 	client->cmd = NULL;
@@ -567,8 +581,8 @@
 		wanted_fields |= MAIL_FETCH_HEADER_MD5;
 
 	ctx->search_ctx = mailbox_search_init(client->trans, NULL,
-					      &ctx->search_arg, NULL,
-					      wanted_fields, NULL);
+					      &ctx->search_arg, NULL);
+	ctx->mail = mail_alloc(client->trans, wanted_fields, NULL);
 	if (message == 0) {
 		client->cmd = cmd_uidl_callback;
 		client->cmd_context = ctx;