changeset 4453:85fcdb478608 HEAD

Beginnings of joining mail-storage API more closely to mail-index, so that mail-index could be directly used if needed. Currently only transactions are joined.
author Timo Sirainen <timo.sirainen@movial.fi>
date Wed, 28 Jun 2006 19:31:05 +0300
parents 66fc4c35a8de
children a75da1185a18
files src/lib-index/mail-index-dummy-view.c src/lib-index/mail-index-private.h src/lib-index/mail-index-transaction-private.h src/lib-index/mail-index-transaction-view.c src/lib-index/mail-index-transaction.c src/lib-index/mail-index-view-private.h src/lib-index/mail-index-view.c src/lib-index/mail-index.c src/lib-index/mail-index.h src/lib-storage/Makefile.am src/lib-storage/index/dbox/dbox-storage.c src/lib-storage/index/dbox/dbox-storage.h src/lib-storage/index/dbox/dbox-transaction.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-storage.c src/lib-storage/index/maildir/maildir-storage.h src/lib-storage/index/maildir/maildir-transaction.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-storage-private.h src/lib-storage/mail-storage.c
diffstat 24 files changed, 500 insertions(+), 235 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-index-dummy-view.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index-dummy-view.c	Wed Jun 28 19:31:05 2006 +0300
@@ -17,7 +17,7 @@
 	return (uint32_t)-3;
 }
 
-static struct mail_index_view_methods dummy_view_methods = {
+static struct mail_index_view_vfuncs dummy_view_vfuncs = {
 	_dummy_view_close,
 	_dummy_view_get_message_count,
 	NULL,
@@ -35,7 +35,7 @@
 
 	view = i_new(struct mail_index_view, 1);
 	view->refcount = 1;
-	view->methods = dummy_view_methods;
+	view->v = dummy_view_vfuncs;
 	view->index = index;
 	return view;
 }
--- a/src/lib-index/mail-index-private.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index-private.h	Wed Jun 28 19:31:05 2006 +0300
@@ -6,6 +6,8 @@
 #include <fcntl.h>
 
 #include "mail-index.h"
+#include "mail-index-view-private.h"
+#include "mail-index-transaction-private.h"
 
 struct mail_transaction_header;
 struct mail_transaction_log_view;
@@ -168,7 +170,7 @@
 	unsigned int last_grow_count;
 
 	/* Module-specific contexts. See mail_index_module_id. */
-	ARRAY_DEFINE(module_contexts, void);
+	ARRAY_DEFINE(mail_index_module_contexts, void);
 
 	char *error;
 	unsigned int nodiskspace:1;
--- a/src/lib-index/mail-index-transaction-private.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index-transaction-private.h	Wed Jun 28 19:31:05 2006 +0300
@@ -9,8 +9,16 @@
 	ARRAY_TYPE(seq_range) remove_seq;
 };
 
+struct mail_index_transaction_vfuncs {
+	int (*commit)(struct mail_index_transaction *t,
+		      uint32_t *log_file_seq_r, uoff_t *log_file_offset_r);
+	void (*rollback)(struct mail_index_transaction *t);
+};
+
 struct mail_index_transaction {
 	int refcount;
+
+	struct mail_index_transaction_vfuncs v;
 	struct mail_index_view *view;
 
         ARRAY_DEFINE(appends, struct mail_index_record);
@@ -35,6 +43,9 @@
 
         struct mail_cache_transaction_ctx *cache_trans_ctx;
 
+	/* Module-specific contexts. See mail_index_module_id. */
+	ARRAY_DEFINE(mail_index_transaction_module_contexts, void);
+
 	unsigned int hide_transaction:1;
 	unsigned int no_appends:1;
 	unsigned int appends_nonsorted:1;
@@ -44,6 +55,9 @@
 	unsigned int log_updates:1;
 };
 
+extern void (*hook_mail_index_transaction_created)
+		(struct mail_index_transaction *t);
+
 struct mail_index_record *
 mail_index_transaction_lookup(struct mail_index_transaction *t, uint32_t seq);
 
--- a/src/lib-index/mail-index-transaction-view.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index-transaction-view.c	Wed Jun 28 19:31:05 2006 +0300
@@ -10,7 +10,7 @@
 
 struct mail_index_view_transaction {
 	struct mail_index_view view;
-	struct mail_index_view_methods *parent;
+	struct mail_index_view_vfuncs *super;
 	struct mail_index_transaction *t;
 };
 
@@ -18,9 +18,10 @@
 {
 	struct mail_index_view_transaction *tview =
 		(struct mail_index_view_transaction *)view;
+	struct mail_index_transaction *t = tview->t;
 
-	mail_index_transaction_unref(&tview->t);
-	tview->parent->close(view);
+	tview->super->close(view);
+	mail_index_transaction_unref(&t);
 }
 
 static uint32_t _tview_get_message_count(struct mail_index_view *view)
@@ -40,7 +41,7 @@
                 (struct mail_index_view_transaction *)view;
 
 	/* FIXME: header counters may not be correct */
-	return tview->parent->get_header(view);
+	return tview->super->get_header(view);
 }
 
 static int _tview_lookup_full(struct mail_index_view *view, uint32_t seq,
@@ -59,7 +60,7 @@
 		return 1;
 	}
 
-	ret = tview->parent->lookup_full(view, seq, map_r, rec_r);
+	ret = tview->super->lookup_full(view, seq, map_r, rec_r);
 	if (ret <= 0)
 		return ret;
 
@@ -79,7 +80,7 @@
 		*uid_r = mail_index_transaction_lookup(tview->t, seq)->uid;
 		return 0;
 	} else {
-		return tview->parent->lookup_uid(view, seq, uid_r);
+		return tview->super->lookup_uid(view, seq, uid_r);
 	}
 }
 
@@ -90,8 +91,8 @@
 	struct mail_index_view_transaction *tview =
 		(struct mail_index_view_transaction *)view;
 
-	if (tview->parent->lookup_uid_range(view, first_uid, last_uid,
-					    first_seq_r, last_seq_r) < 0)
+	if (tview->super->lookup_uid_range(view, first_uid, last_uid,
+					   first_seq_r, last_seq_r) < 0)
 		return -1;
 
 	/* FIXME: we don't need this function yet.. new UIDs might be 0 as
@@ -117,7 +118,7 @@
 	unsigned int append_count;
 	uint32_t seq, message_count;
 
-	if (tview->parent->lookup_first(view, flags, flags_mask, seq_r) < 0)
+	if (tview->super->lookup_first(view, flags, flags_mask, seq_r) < 0)
 		return -1;
 
 	if (*seq_r != 0)
@@ -168,8 +169,8 @@
 
 	/* not updated, return the existing value */
 	if (seq < tview->t->first_new_seq) {
-		return tview->parent->lookup_ext_full(view, seq, ext_id,
-						      map_r, data_r);
+		return tview->super->lookup_ext_full(view, seq, ext_id,
+						     map_r, data_r);
 	}
 
 	*data_r = NULL;
@@ -184,11 +185,11 @@
 		(struct mail_index_view_transaction *)view;
 
 	/* FIXME: check updates */
-	return tview->parent->get_header_ext(view, map, ext_id,
-					     data_r, data_size_r);
+	return tview->super->get_header_ext(view, map, ext_id,
+					    data_r, data_size_r);
 }
 
-static struct mail_index_view_methods view_methods = {
+static struct mail_index_view_vfuncs trans_view_vfuncs = {
 	_tview_close,
         _tview_get_message_count,
 	_tview_get_header,
@@ -215,8 +216,8 @@
 
 	tview = i_new(struct mail_index_view_transaction, 1);
 	mail_index_view_clone(&tview->view, t->view);
-	tview->view.methods = view_methods;
-	tview->parent = &t->view->methods;
+	tview->view.v = trans_view_vfuncs;
+	tview->super = &t->view->v;
 	tview->t = t;
 
 	mail_index_transaction_ref(t);
--- a/src/lib-index/mail-index-transaction.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index-transaction.c	Wed Jun 28 19:31:05 2006 +0300
@@ -15,31 +15,8 @@
 #include <stddef.h>
 #include <stdlib.h>
 
-struct mail_index_transaction *
-mail_index_transaction_begin(struct mail_index_view *view,
-			     bool hide, bool external)
-{
-	struct mail_index_transaction *t;
-
-	/* don't allow syncing view while there's ongoing transactions */
-	mail_index_view_transaction_ref(view);
- 	mail_index_view_ref(view);
-
-	t = i_new(struct mail_index_transaction, 1);
-	t->refcount = 1;
-	t->view = view;
-	t->hide_transaction = hide;
-	t->external = external;
-	t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
-
-	if (view->syncing) {
-		/* transaction view cannot work if new records are being added
-		   in two places. make sure it doesn't happen. */
-		t->no_appends = TRUE;
-	}
-
-	return t;
-}
+void (*hook_mail_index_transaction_created)
+		(struct mail_index_transaction *t) = NULL;
 
 static void mail_index_transaction_free(struct mail_index_transaction *t)
 {
@@ -340,18 +317,12 @@
 	i_free(old_to_new_map);
 }
 
-int mail_index_transaction_commit(struct mail_index_transaction **_t,
-				  uint32_t *log_file_seq_r,
-				  uoff_t *log_file_offset_r)
+static int _mail_index_transaction_commit(struct mail_index_transaction *t,
+					  uint32_t *log_file_seq_r,
+					  uoff_t *log_file_offset_r)
 {
-	struct mail_index_transaction *t = *_t;
 	int ret;
 
-	if (mail_index_view_is_inconsistent(t->view)) {
-		mail_index_transaction_rollback(_t);
-		return -1;
-	}
-
 	if (t->cache_trans_ctx != NULL) {
 		mail_cache_transaction_commit(t->cache_trans_ctx);
                 t->cache_trans_ctx = NULL;
@@ -367,19 +338,40 @@
 						  log_file_offset_r);
 	}
 
-	mail_index_transaction_unref(_t);
+	mail_index_transaction_unref(&t);
 	return ret;
 }
 
+static void _mail_index_transaction_rollback(struct mail_index_transaction *t)
+{
+	if (t->cache_trans_ctx != NULL) {
+		mail_cache_transaction_rollback(t->cache_trans_ctx);
+                t->cache_trans_ctx = NULL;
+	}
+        mail_index_transaction_unref(&t);
+}
+
+int mail_index_transaction_commit(struct mail_index_transaction **_t,
+				  uint32_t *log_file_seq_r,
+				  uoff_t *log_file_offset_r)
+{
+	struct mail_index_transaction *t = *_t;
+
+	if (mail_index_view_is_inconsistent(t->view)) {
+		mail_index_transaction_rollback(_t);
+		return -1;
+	}
+
+	*_t = NULL;
+	return t->v.commit(t, log_file_seq_r, log_file_offset_r);
+}
+
 void mail_index_transaction_rollback(struct mail_index_transaction **_t)
 {
 	struct mail_index_transaction *t = *_t;
 
-	if (t->cache_trans_ctx != NULL) {
-		mail_cache_transaction_rollback(t->cache_trans_ctx);
-                t->cache_trans_ctx = NULL;
-	}
-        mail_index_transaction_unref(_t);
+	*_t = NULL;
+	t->v.rollback(t);
 }
 
 struct mail_index_record *
@@ -951,3 +943,40 @@
 
 	t->log_updates = TRUE;
 }
+
+struct mail_index_transaction_vfuncs trans_vfuncs = {
+	_mail_index_transaction_commit,
+	_mail_index_transaction_rollback
+};
+
+struct mail_index_transaction *
+mail_index_transaction_begin(struct mail_index_view *view,
+			     bool hide, bool external)
+{
+	struct mail_index_transaction *t;
+
+	/* don't allow syncing view while there's ongoing transactions */
+	mail_index_view_transaction_ref(view);
+ 	mail_index_view_ref(view);
+
+	t = i_new(struct mail_index_transaction, 1);
+	t->refcount = 1;
+	t->v = trans_vfuncs;
+	t->view = view;
+	t->hide_transaction = hide;
+	t->external = external;
+	t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
+
+	if (view->syncing) {
+		/* transaction view cannot work if new records are being added
+		   in two places. make sure it doesn't happen. */
+		t->no_appends = TRUE;
+	}
+
+	ARRAY_CREATE(&t->mail_index_transaction_module_contexts, default_pool,
+		     void *, I_MIN(5, mail_index_module_id));
+
+	if (hook_mail_index_transaction_created != NULL)
+		hook_mail_index_transaction_created(t);
+	return t;
+}
--- a/src/lib-index/mail-index-view-private.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index-view-private.h	Wed Jun 28 19:31:05 2006 +0300
@@ -9,7 +9,7 @@
 };
 ARRAY_DEFINE_TYPE(view_log_sync_pos, struct mail_index_view_log_sync_pos);
 
-struct mail_index_view_methods {
+struct mail_index_view_vfuncs {
 	void (*close)(struct mail_index_view *view);
 	uint32_t (*get_messages_count)(struct mail_index_view *view);
 	const struct mail_index_header *
@@ -35,7 +35,7 @@
 struct mail_index_view {
 	int refcount;
 
-	struct mail_index_view_methods methods;
+	struct mail_index_view_vfuncs v;
 	struct mail_index *index;
         struct mail_transaction_log_view *log_view;
 
@@ -56,6 +56,9 @@
 	/* Transaction log offsets which we don't want to return in view sync */
 	ARRAY_TYPE(view_log_sync_pos) syncs_hidden;
 
+	/* Module-specific contexts. See mail_index_module_id. */
+	ARRAY_DEFINE(mail_index_view_module_contexts, void);
+
 	int transactions;
 	unsigned int lock_id;
 
--- a/src/lib-index/mail-index-view.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index-view.c	Wed Jun 28 19:31:05 2006 +0300
@@ -11,13 +11,14 @@
 {
 	memset(dest, 0, sizeof(dest));
 	dest->refcount = 1;
-	dest->methods = src->methods;
+	dest->v = src->v;
 	dest->index = src->index;
 	dest->log_view = mail_transaction_log_view_open(src->index->log);
 
 	dest->indexid = src->indexid;
 	dest->map = src->map;
-	dest->map->refcount++;
+	if (dest->map != NULL)
+		dest->map->refcount++;
 	dest->hdr = src->hdr;
 	dest->broken_counters = src->broken_counters;
 
@@ -452,18 +453,18 @@
 	if (--view->refcount > 0)
 		return;
 
-	view->methods.close(view);
+	view->v.close(view);
 }
 
 uint32_t mail_index_view_get_messages_count(struct mail_index_view *view)
 {
-	return view->methods.get_messages_count(view);
+	return view->v.get_messages_count(view);
 }
 
 const struct mail_index_header *
 mail_index_get_header(struct mail_index_view *view)
 {
-	return view->methods.get_header(view);
+	return view->v.get_header(view);
 }
 
 int mail_index_lookup(struct mail_index_view *view, uint32_t seq,
@@ -478,7 +479,7 @@
 			   struct mail_index_map **map_r,
 			   const struct mail_index_record **rec_r)
 {
-	return view->methods.lookup_full(view, seq, map_r, rec_r);
+	return view->v.lookup_full(view, seq, map_r, rec_r);
 }
 
 int mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
@@ -561,21 +562,21 @@
 int mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
 			  uint32_t *uid_r)
 {
-	return view->methods.lookup_uid(view, seq, uid_r);
+	return view->v.lookup_uid(view, seq, uid_r);
 }
 
 int mail_index_lookup_uid_range(struct mail_index_view *view,
 				uint32_t first_uid, uint32_t last_uid,
 				uint32_t *first_seq_r, uint32_t *last_seq_r)
 {
-	return view->methods.lookup_uid_range(view, first_uid, last_uid,
-					      first_seq_r, last_seq_r);
+	return view->v.lookup_uid_range(view, first_uid, last_uid,
+					first_seq_r, last_seq_r);
 }
 
 int mail_index_lookup_first(struct mail_index_view *view, enum mail_flags flags,
 			    uint8_t flags_mask, uint32_t *seq_r)
 {
-	return view->methods.lookup_first(view, flags, flags_mask, seq_r);
+	return view->v.lookup_first(view, flags, flags_mask, seq_r);
 }
 
 int mail_index_lookup_ext(struct mail_index_view *view, uint32_t seq,
@@ -583,29 +584,27 @@
 {
 	struct mail_index_map *map;
 
-	return view->methods.lookup_ext_full(view, seq, ext_id, &map, data_r);
+	return view->v.lookup_ext_full(view, seq, ext_id, &map, data_r);
 }
 
 int mail_index_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
 			       uint32_t ext_id, struct mail_index_map **map_r,
 			       const void **data_r)
 {
-	return view->methods.lookup_ext_full(view, seq, ext_id, map_r, data_r);
+	return view->v.lookup_ext_full(view, seq, ext_id, map_r, data_r);
 }
 
 int mail_index_get_header_ext(struct mail_index_view *view, uint32_t ext_id,
 			      const void **data_r, size_t *data_size_r)
 {
-	return view->methods.get_header_ext(view, NULL, ext_id,
-					    data_r, data_size_r);
+	return view->v.get_header_ext(view, NULL, ext_id, data_r, data_size_r);
 }
 
 int mail_index_map_get_header_ext(struct mail_index_view *view,
 				  struct mail_index_map *map, uint32_t ext_id,
 				  const void **data_r, size_t *data_size_r)
 {
-	return view->methods.get_header_ext(view, map, ext_id,
-					    data_r, data_size_r);
+	return view->v.get_header_ext(view, map, ext_id, data_r, data_size_r);
 }
 
 int mail_index_ext_get_size(struct mail_index_view *view __attr_unused__,
@@ -639,7 +638,7 @@
 	return 0;
 }
 
-static struct mail_index_view_methods view_methods = {
+static struct mail_index_view_vfuncs view_vfuncs = {
 	_view_close,
 	_view_get_messages_count,
 	_view_get_header,
@@ -659,7 +658,7 @@
 
 	view = i_new(struct mail_index_view, 1);
 	view->refcount = 1;
-	view->methods = view_methods;
+	view->v = view_vfuncs;
 	view->index = index;
 	view->log_view = mail_transaction_log_view_open(index->log);
 
--- a/src/lib-index/mail-index.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index.c	Wed Jun 28 19:31:05 2006 +0300
@@ -18,6 +18,8 @@
 #include <time.h>
 #include <sys/stat.h>
 
+unsigned int mail_index_module_id = 0;
+
 static int mail_index_try_open_only(struct mail_index *index);
 static void mail_index_create_in_memory(struct mail_index *index,
 					const struct mail_index_header *hdr);
@@ -38,6 +40,9 @@
 	ARRAY_CREATE(&index->sync_lost_handlers, default_pool,
 		     mail_index_sync_lost_handler_t *, 4);
 
+	ARRAY_CREATE(&index->mail_index_module_contexts, default_pool,
+		     void *, I_MIN(5, mail_index_module_id));
+
 	index->mode = 0600;
 	index->gid = (gid_t)-1;
 
--- a/src/lib-index/mail-index.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-index/mail-index.h	Wed Jun 28 19:31:05 2006 +0300
@@ -142,6 +142,8 @@
 	enum mail_index_sync_type type;
 };
 
+extern unsigned int mail_index_module_id;
+
 ARRAY_DEFINE_TYPE(keyword_indexes, unsigned int);
 
 struct mail_index;
--- a/src/lib-storage/Makefile.am	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/Makefile.am	Wed Jun 28 19:31:05 2006 +0300
@@ -5,7 +5,8 @@
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
 	-I$(top_srcdir)/src/lib-mail \
-	-I$(top_srcdir)/src/lib-imap
+	-I$(top_srcdir)/src/lib-imap \
+	-I$(top_srcdir)/src/lib-index
 
 libstorage_a_SOURCES = \
 	mail.c \
--- a/src/lib-storage/index/dbox/dbox-storage.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/dbox/dbox-storage.c	Wed Jun 28 19:31:05 2006 +0300
@@ -667,11 +667,23 @@
 		t_strconcat(mbox->path, "/"DBOX_MAILDIR_NAME, NULL));
 }
 
+static void dbox_class_init(void)
+{
+	dbox_transaction_class_init();
+}
+
+static void dbox_class_deinit(void)
+{
+	dbox_transaction_class_deinit();
+}
+
 struct mail_storage dbox_storage = {
-	MEMBER(name) "dbox",
+	MEMBER(name) DBOX_STORAGE_NAME,
 	MEMBER(hierarchy_sep) '/',
 
 	{
+		dbox_class_init,
+		dbox_class_deinit,
 		dbox_create,
 		dbox_free,
 		dbox_autodetect,
@@ -704,9 +716,9 @@
 		index_mailbox_sync_next,
 		index_mailbox_sync_deinit,
 		dbox_notify_changes,
-		dbox_transaction_begin,
-		dbox_transaction_commit,
-		dbox_transaction_rollback,
+		index_transaction_begin,
+		index_transaction_commit,
+		index_transaction_rollback,
 		index_keywords_create,
 		index_keywords_free,
 		index_storage_get_uids,
--- a/src/lib-storage/index/dbox/dbox-storage.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/dbox/dbox-storage.h	Wed Jun 28 19:31:05 2006 +0300
@@ -4,6 +4,7 @@
 #include "index-storage.h"
 #include "dbox-format.h"
 
+#define DBOX_STORAGE_NAME "dbox"
 #define STORAGE(mbox_storage) \
 	(&(mbox_storage)->storage.storage)
 #define INDEX_STORAGE(mbox_storage) \
@@ -83,12 +84,9 @@
 int dbox_mailbox_list_deinit(struct mailbox_list_context *ctx);
 struct mailbox_list *dbox_mailbox_list_next(struct mailbox_list_context *ctx);
 
-struct mailbox_transaction_context *
-dbox_transaction_begin(struct mailbox *box,
-		       enum mailbox_transaction_flags flags);
-int dbox_transaction_commit(struct mailbox_transaction_context *t,
-			    enum mailbox_sync_flags flags);
-void dbox_transaction_rollback(struct mailbox_transaction_context *t);
+void dbox_transaction_created(struct mail_index_transaction *t);
+void dbox_transaction_class_init(void);
+void dbox_transaction_class_deinit(void);
 
 int dbox_save_init(struct mailbox_transaction_context *_t,
 		   enum mail_flags flags, struct mail_keywords *keywords,
--- a/src/lib-storage/index/dbox/dbox-transaction.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/dbox/dbox-transaction.c	Wed Jun 28 19:31:05 2006 +0300
@@ -1,47 +1,42 @@
 /* Copyright (C) 2005 Timo Sirainen */
 
 #include "lib.h"
+#include "array.h"
 #include "dbox-sync.h"
 #include "dbox-storage.h"
 
-struct mailbox_transaction_context *
-dbox_transaction_begin(struct mailbox *box,
-		       enum mailbox_transaction_flags flags)
-{
-	struct dbox_mailbox *dbox = (struct dbox_mailbox *)box;
-	struct dbox_transaction_context *t;
+static void (*next_hook_mail_index_transaction_created)
+	(struct mail_index_transaction *t) = NULL;
 
-	t = i_new(struct dbox_transaction_context, 1);
-	index_transaction_init(&t->ictx, &dbox->ibox, flags);
-	return &t->ictx.mailbox_ctx;
-}
-
-int dbox_transaction_commit(struct mailbox_transaction_context *_t,
-			    enum mailbox_sync_flags flags __attr_unused__)
+static int dbox_transaction_commit(struct mail_index_transaction *t,
+				   uint32_t *log_file_seq_r,
+				   uoff_t *log_file_offset_r)
 {
-	struct dbox_transaction_context *t =
-		(struct dbox_transaction_context *)_t;
-	struct dbox_mailbox *dbox = (struct dbox_mailbox *)t->ictx.ibox;
+	struct dbox_transaction_context *dt = MAIL_STORAGE_TRANSACTION(t);
+	struct dbox_mailbox *dbox = (struct dbox_mailbox *)dt->ictx.ibox;
 	struct dbox_save_context *save_ctx;
+	bool external = t->external;
 	int ret = 0;
 
-	if (t->save_ctx != NULL) {
-		if (dbox_transaction_save_commit_pre(t->save_ctx) < 0) {
-			t->save_ctx = NULL;
+	if (dt->save_ctx != NULL) {
+		if (dbox_transaction_save_commit_pre(dt->save_ctx) < 0) {
+			dt->save_ctx = NULL;
 			ret = -1;
 		}
 	}
 
-	save_ctx = t->save_ctx;
+	save_ctx = dt->save_ctx;
 
-	if (ret == 0) {
-		if (index_transaction_commit(_t) < 0)
+	if (ret < 0)
+		index_transaction_finish_rollback(&dt->ictx);
+	else {
+		if (index_transaction_finish_commit(&dt->ictx, log_file_seq_r,
+						    log_file_offset_r) < 0)
 			ret = -1;
-	} else {
-		index_transaction_rollback(_t);
 	}
-	/* transaction is destroyed. */
-	t = NULL; _t = NULL;
+
+	/* transaction is destroyed now. */
+	dt = NULL;
 
 	if (save_ctx != NULL) {
 		/* unlock uidlist file after writing to transaction log,
@@ -49,7 +44,7 @@
 		dbox_transaction_save_commit_post(save_ctx);
 	}
 
-	if (ret == 0) {
+	if (ret == 0 && !external) {
 		if (dbox_sync(dbox, FALSE) < 0)
 			ret = -1;
 	}
@@ -57,13 +52,52 @@
 	return ret;
 }
 
-void dbox_transaction_rollback(struct mailbox_transaction_context *_t)
+static void dbox_transaction_rollback(struct mail_index_transaction *t)
+{
+	struct dbox_transaction_context *dt = MAIL_STORAGE_TRANSACTION(t);
+
+	if (dt->save_ctx != NULL)
+		dbox_transaction_save_rollback(dt->save_ctx);
+
+	index_transaction_finish_rollback(&dt->ictx);
+}
+
+void dbox_transaction_created(struct mail_index_transaction *t)
 {
-	struct dbox_transaction_context *t =
-		(struct dbox_transaction_context *)_t;
+	struct mailbox *box = MAIL_STORAGE_INDEX(t->view->index);
+
+	if (strcmp(box->storage->name, DBOX_STORAGE_NAME) == 0) {
+		struct dbox_mailbox *dbox = (struct dbox_mailbox *)box;
+		struct dbox_transaction_context *mt;
+
+		mt = i_new(struct dbox_transaction_context, 1);
+		mt->ictx.trans = t;
+		mt->ictx.super = t->v;
+
+		t->v.commit = dbox_transaction_commit;
+		t->v.rollback = dbox_transaction_rollback;
 
-	if (t->save_ctx != NULL)
-		dbox_transaction_save_rollback(t->save_ctx);
+		array_idx_set(&t->mail_index_transaction_module_contexts,
+			      mail_storage_mail_index_module_id, &mt);
+
+		index_transaction_init(&mt->ictx, &dbox->ibox);
+	}
+
+	if (next_hook_mail_index_transaction_created != NULL)
+		next_hook_mail_index_transaction_created(t);
+}
 
-	index_transaction_rollback(_t);
+void dbox_transaction_class_init(void)
+{
+	next_hook_mail_index_transaction_created =
+		hook_mail_index_transaction_created;
+	hook_mail_index_transaction_created = dbox_transaction_created;
 }
+
+void dbox_transaction_class_deinit(void)
+{
+	i_assert(hook_mail_index_transaction_created ==
+		 dbox_transaction_created);
+	hook_mail_index_transaction_created =
+		next_hook_mail_index_transaction_created;
+}
--- a/src/lib-storage/index/index-storage.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/index-storage.c	Wed Jun 28 19:31:05 2006 +0300
@@ -379,6 +379,9 @@
 	index_cache_register_defaults(ibox);
 	ibox->view = mail_index_view_open(index);
 	ibox->keyword_names = mail_index_get_keywords(index);
+
+	array_idx_set(&index->mail_index_module_contexts,
+		      mail_storage_mail_index_module_id, &ibox);
 	return 0;
 }
 
@@ -395,6 +398,9 @@
 	if (ibox->recent_flags != NULL)
 		buffer_free(ibox->recent_flags);
 	i_free(ibox->cache_fields);
+
+	array_idx_clear(&ibox->index->mail_index_module_contexts,
+			mail_storage_mail_index_module_id);
 	pool_unref(box->pool);
 }
 
--- a/src/lib-storage/index/index-storage.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/index-storage.h	Wed Jun 28 19:31:05 2006 +0300
@@ -3,7 +3,7 @@
 
 #include "file-dotlock.h"
 #include "mail-storage-private.h"
-#include "mail-index.h"
+#include "mail-index-private.h"
 
 /* Max. mmap()ed size for a message */
 #define MAIL_MMAP_BLOCK_SIZE (1024*256)
@@ -84,8 +84,11 @@
 
 struct index_transaction_context {
 	struct mailbox_transaction_context mailbox_ctx;
+	struct mail_index_transaction_vfuncs super;
+
 	struct index_mailbox *ibox;
-        enum mailbox_transaction_flags flags;
+	enum mailbox_transaction_flags flags;
+	enum mailbox_sync_flags commit_flags;
 
 	struct mail_index_transaction *trans;
 	struct mail_index_view *trans_view;
@@ -178,9 +181,17 @@
 int index_storage_search_next_update_seq(struct mail_search_context *ctx);
 
 void index_transaction_init(struct index_transaction_context *t,
-			    struct index_mailbox *ibox,
-			    enum mailbox_transaction_flags flags);
-int index_transaction_commit(struct mailbox_transaction_context *t);
+			    struct index_mailbox *ibox);
+int index_transaction_finish_commit(struct index_transaction_context *t,
+				    uint32_t *log_file_seq_r,
+				    uoff_t *log_file_offset_r);
+void index_transaction_finish_rollback(struct index_transaction_context *t);
+
+struct mailbox_transaction_context *
+index_transaction_begin(struct mailbox *box,
+			enum mailbox_transaction_flags flags);
+int index_transaction_commit(struct mailbox_transaction_context *t,
+			     enum mailbox_sync_flags flags);
 void index_transaction_rollback(struct mailbox_transaction_context *t);
 
 bool index_keyword_array_cmp(const ARRAY_TYPE(keyword_indexes) *k1,
--- a/src/lib-storage/index/index-transaction.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/index-transaction.c	Wed Jun 28 19:31:05 2006 +0300
@@ -6,19 +6,14 @@
 #include "index-mail.h"
 
 void index_transaction_init(struct index_transaction_context *t,
-			    struct index_mailbox *ibox,
-			    enum mailbox_transaction_flags flags)
+			    struct index_mailbox *ibox)
 {
 	t->mailbox_ctx.box = &ibox->box;
 	t->ibox = ibox;
-	t->flags = flags;
 
 	array_create(&t->mailbox_ctx.module_contexts, default_pool,
 		     sizeof(void *), 5);
 
-	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);
@@ -33,21 +28,19 @@
 	i_free(t);
 }
 
-int index_transaction_commit(struct mailbox_transaction_context *_t)
+int index_transaction_finish_commit(struct index_transaction_context *t,
+				    uint32_t *log_file_seq_r,
+				    uoff_t *log_file_offset_r)
 {
-	struct index_transaction_context *t =
-		(struct index_transaction_context *)_t;
-	uint32_t seq;
-	uoff_t offset;
 	int ret;
 
-	ret = mail_index_transaction_commit(&t->trans, &seq, &offset);
+	ret = t->super.commit(t->trans, log_file_seq_r, log_file_offset_r);
 	if (ret < 0)
 		mail_storage_set_index_error(t->ibox);
 	else {
-		if (seq != 0) {
-			t->ibox->commit_log_file_seq = seq;
-			t->ibox->commit_log_file_offset = offset;
+		if (*log_file_seq_r != 0) {
+			t->ibox->commit_log_file_seq = *log_file_seq_r;
+			t->ibox->commit_log_file_offset = *log_file_offset_r;
 		}
 	}
 
@@ -55,11 +48,46 @@
 	return ret;
 }
 
+void index_transaction_finish_rollback(struct index_transaction_context *t)
+{
+	t->super.rollback(t->trans);
+	index_transaction_free(t);
+}
+
+struct mailbox_transaction_context *
+index_transaction_begin(struct mailbox *box,
+			enum mailbox_transaction_flags flags)
+{
+	struct index_mailbox *ibox = (struct index_mailbox *)box;
+	struct mail_index_transaction *t;
+	struct index_transaction_context *it;
+
+	t = mail_index_transaction_begin(ibox->view,
+		(flags & MAILBOX_TRANSACTION_FLAG_HIDE) != 0,
+		(flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0);
+
+	it = MAIL_STORAGE_TRANSACTION(t);
+	it->flags = flags;
+	return &it->mailbox_ctx;
+}
+int index_transaction_commit(struct mailbox_transaction_context *_t,
+			     enum mailbox_sync_flags flags)
+{
+	struct index_transaction_context *t =
+		(struct index_transaction_context *)_t;
+	struct mail_index_transaction *itrans = t->trans;
+	uint32_t seq;
+	uoff_t offset;
+
+	t->commit_flags = flags;
+	return mail_index_transaction_commit(&itrans, &seq, &offset);
+}
+
 void index_transaction_rollback(struct mailbox_transaction_context *_t)
 {
 	struct index_transaction_context *t =
 		(struct index_transaction_context *)_t;
+	struct mail_index_transaction *itrans = t->trans;
 
-	mail_index_transaction_rollback(&t->trans);
-	index_transaction_free(t);
+	mail_index_transaction_rollback(&itrans);
 }
--- a/src/lib-storage/index/maildir/maildir-storage.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Wed Jun 28 19:31:05 2006 +0300
@@ -979,11 +979,23 @@
 		t_strconcat(mbox->path, "/cur", NULL));
 }
 
+static void maildir_class_init(void)
+{
+	maildir_transaction_class_init();
+}
+
+static void maildir_class_deinit(void)
+{
+	maildir_transaction_class_deinit();
+}
+
 struct mail_storage maildir_storage = {
-	MEMBER(name) "maildir",
+	MEMBER(name) MAILDIR_STORAGE_NAME,
 	MEMBER(hierarchy_sep) MAILDIR_FS_SEP,
 
 	{
+		maildir_class_init,
+		maildir_class_deinit,
 		maildir_create,
 		maildir_free,
 		maildir_autodetect,
@@ -1016,9 +1028,9 @@
 		index_mailbox_sync_next,
 		index_mailbox_sync_deinit,
 		maildir_notify_changes,
-		maildir_transaction_begin,
-		maildir_transaction_commit,
-		maildir_transaction_rollback,
+		index_transaction_begin,
+		index_transaction_commit,
+		index_transaction_rollback,
 		index_keywords_create,
 		index_keywords_free,
 		index_storage_get_uids,
--- a/src/lib-storage/index/maildir/maildir-storage.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/maildir/maildir-storage.h	Wed Jun 28 19:31:05 2006 +0300
@@ -5,6 +5,7 @@
 #define MAILDIR_FS_SEP '.'
 #define MAILDIR_FS_SEP_S "."
 
+#define MAILDIR_STORAGE_NAME "maildir"
 #define SUBSCRIPTION_FILE_NAME "subscriptions"
 #define MAILDIR_INDEX_PREFIX "dovecot.index"
 #define MAILDIR_UNLINK_DIRNAME MAILDIR_FS_SEP_S"DOVECOT-TRASHED"
@@ -113,12 +114,9 @@
 int maildir_sync_index_finish(struct maildir_index_sync_context **sync_ctx,
 			      bool failed);
 
-struct mailbox_transaction_context *
-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);
+void maildir_transaction_created(struct mail_index_transaction *t);
+void maildir_transaction_class_init(void);
+void maildir_transaction_class_deinit(void);
 
 int maildir_save_init(struct mailbox_transaction_context *_t,
 		      enum mail_flags flags, struct mail_keywords *keywords,
--- a/src/lib-storage/index/maildir/maildir-transaction.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/maildir/maildir-transaction.c	Wed Jun 28 19:31:05 2006 +0300
@@ -1,56 +1,90 @@
 /* Copyright (C) 2004 Timo Sirainen */
 
 #include "lib.h"
+#include "array.h"
 #include "maildir-storage.h"
 
-struct mailbox_transaction_context *
-maildir_transaction_begin(struct mailbox *box,
-			  enum mailbox_transaction_flags flags)
-{
-	struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
-	struct maildir_transaction_context *t;
+static void (*next_hook_mail_index_transaction_created)
+	(struct mail_index_transaction *t) = NULL;
 
-	t = i_new(struct maildir_transaction_context, 1);
-	index_transaction_init(&t->ictx, &mbox->ibox, flags);
-	return &t->ictx.mailbox_ctx;
-}
-
-int maildir_transaction_commit(struct mailbox_transaction_context *_t,
-			       enum mailbox_sync_flags flags __attr_unused__)
+static int maildir_transaction_commit(struct mail_index_transaction *t,
+				      uint32_t *log_file_seq_r,
+				      uoff_t *log_file_offset_r)
 {
-	struct maildir_transaction_context *t =
-		(struct maildir_transaction_context *)_t;
-	struct maildir_mailbox *mbox = (struct maildir_mailbox *)t->ictx.ibox;
+	struct maildir_transaction_context *mt = MAIL_STORAGE_TRANSACTION(t);
+	struct maildir_mailbox *mbox = (struct maildir_mailbox *)mt->ictx.ibox;
 	struct maildir_save_context *save_ctx;
+	bool external = t->external;
 	int ret = 0;
 
-	if (t->save_ctx != NULL) {
-		if (maildir_transaction_save_commit_pre(t->save_ctx) < 0) {
-			t->save_ctx = NULL;
+	if (mt->save_ctx != NULL) {
+		if (maildir_transaction_save_commit_pre(mt->save_ctx) < 0) {
+			mt->save_ctx = NULL;
 			ret = -1;
 		}
 	}
 
-	save_ctx = t->save_ctx;
+	save_ctx = mt->save_ctx;
 
-	if (index_transaction_commit(_t) < 0)
+	if (index_transaction_finish_commit(&mt->ictx, log_file_seq_r,
+					    log_file_offset_r) < 0)
 		ret = -1;
 
-	/* transaction is destroyed. */
-	t = NULL; _t = NULL;
+	/* transaction is destroyed now. */
+	mt = NULL;
 
 	if (save_ctx != NULL)
 		maildir_transaction_save_commit_post(save_ctx);
 
-	return ret < 0 ? -1 : maildir_sync_last_commit(mbox);
+	if (ret == 0 && !external)
+		ret = maildir_sync_last_commit(mbox);
+	return ret;
+}
+
+static void maildir_transaction_rollback(struct mail_index_transaction *t)
+{
+	struct maildir_transaction_context *mt = MAIL_STORAGE_TRANSACTION(t);
+
+	if (mt->save_ctx != NULL)
+		maildir_transaction_save_rollback(mt->save_ctx);
+	index_transaction_finish_rollback(&mt->ictx);
 }
 
-void maildir_transaction_rollback(struct mailbox_transaction_context *_t)
+void maildir_transaction_created(struct mail_index_transaction *t)
 {
-	struct maildir_transaction_context *t =
-		(struct maildir_transaction_context *)_t;
+	struct mailbox *box = MAIL_STORAGE_INDEX(t->view->index);
+
+	if (strcmp(box->storage->name, MAILDIR_STORAGE_NAME) == 0) {
+		struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
+		struct maildir_transaction_context *mt;
+
+		mt = i_new(struct maildir_transaction_context, 1);
+		mt->ictx.trans = t;
+		mt->ictx.super = t->v;
+
+		t->v.commit = maildir_transaction_commit;
+		t->v.rollback = maildir_transaction_rollback;
+
+		array_idx_set(&t->mail_index_transaction_module_contexts,
+			      mail_storage_mail_index_module_id, &mt);
 
-	if (t->save_ctx != NULL)
-		maildir_transaction_save_rollback(t->save_ctx);
-	index_transaction_rollback(_t);
+		index_transaction_init(&mt->ictx, &mbox->ibox);
+	}
+	if (next_hook_mail_index_transaction_created != NULL)
+		next_hook_mail_index_transaction_created(t);
 }
+
+void maildir_transaction_class_init(void)
+{
+	next_hook_mail_index_transaction_created =
+		hook_mail_index_transaction_created;
+	hook_mail_index_transaction_created = maildir_transaction_created;
+}
+
+void maildir_transaction_class_deinit(void)
+{
+	i_assert(hook_mail_index_transaction_created ==
+		 maildir_transaction_created);
+	hook_mail_index_transaction_created =
+		next_hook_mail_index_transaction_created;
+}
--- a/src/lib-storage/index/mbox/mbox-storage.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Wed Jun 28 19:31:05 2006 +0300
@@ -1085,11 +1085,23 @@
 		index_mailbox_check_add(&mbox->ibox, mbox->path);
 }
 
+static void mbox_class_init(void)
+{
+	mbox_transaction_class_init();
+}
+
+static void mbox_class_deinit(void)
+{
+	mbox_transaction_class_deinit();
+}
+
 struct mail_storage mbox_storage = {
-	MEMBER(name) "mbox",
+	MEMBER(name) MBOX_STORAGE_NAME,
 	MEMBER(hierarchy_sep) '/',
 
 	{
+		mbox_class_init,
+		mbox_class_deinit,
 		mbox_create,
 		mbox_free,
 		mbox_autodetect,
@@ -1122,9 +1134,9 @@
 		index_mailbox_sync_next,
 		index_mailbox_sync_deinit,
 		mbox_notify_changes,
-		mbox_transaction_begin,
-		mbox_transaction_commit,
-		mbox_transaction_rollback,
+		index_transaction_begin,
+		index_transaction_commit,
+		index_transaction_rollback,
 		index_keywords_create,
 		index_keywords_free,
 		index_storage_get_uids,
--- a/src/lib-storage/index/mbox/mbox-storage.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/mbox/mbox-storage.h	Wed Jun 28 19:31:05 2006 +0300
@@ -6,6 +6,7 @@
 /* Don't write Content-Length header unless it's value is larger than this. */
 #define MBOX_MIN_CONTENT_LENGTH_SIZE 1024
 
+#define MBOX_STORAGE_NAME "mbox"
 #define SUBSCRIPTION_FILE_NAME ".subscriptions"
 #define MBOX_INDEX_PREFIX "dovecot.index"
 #define MBOX_INDEX_DIR_NAME ".imap"
@@ -70,12 +71,9 @@
 int mbox_mailbox_list_deinit(struct mailbox_list_context *ctx);
 struct mailbox_list *mbox_mailbox_list_next(struct mailbox_list_context *ctx);
 
-struct mailbox_transaction_context *
-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);
+void mbox_transaction_created(struct mail_index_transaction *t);
+void mbox_transaction_class_init(void);
+void mbox_transaction_class_deinit(void);
 
 struct mailbox_sync_context *
 mbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags);
--- a/src/lib-storage/index/mbox/mbox-transaction.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/index/mbox/mbox-transaction.c	Wed Jun 28 19:31:05 2006 +0300
@@ -1,43 +1,40 @@
 /* Copyright (C) 2004 Timo Sirainen */
 
 #include "lib.h"
+#include "array.h"
 #include "mbox-storage.h"
 #include "mbox-lock.h"
 #include "mbox-sync-private.h"
 
-struct mailbox_transaction_context *
-mbox_transaction_begin(struct mailbox *box,
-		       enum mailbox_transaction_flags flags)
-{
-	struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
-	struct mbox_transaction_context *t;
+static void (*next_hook_mail_index_transaction_created)
+	(struct mail_index_transaction *t) = NULL;
 
-	t = i_new(struct mbox_transaction_context, 1);
-	index_transaction_init(&t->ictx, &mbox->ibox, flags);
-	return &t->ictx.mailbox_ctx;
-}
-
-int mbox_transaction_commit(struct mailbox_transaction_context *_t,
-			    enum mailbox_sync_flags flags)
+static int mbox_transaction_commit(struct mail_index_transaction *t,
+				   uint32_t *log_file_seq_r,
+				   uoff_t *log_file_offset_r)
 {
-	struct mbox_transaction_context *t =
-		(struct mbox_transaction_context *)_t;
-	struct mbox_mailbox *mbox = (struct mbox_mailbox *)t->ictx.ibox;
-	unsigned int lock_id = t->mbox_lock_id;
+	struct mbox_transaction_context *mt = MAIL_STORAGE_TRANSACTION(t);
+	struct mbox_mailbox *mbox = (struct mbox_mailbox *)mt->ictx.ibox;
+	unsigned int lock_id = mt->mbox_lock_id;
+	enum mailbox_sync_flags flags = mt->ictx.commit_flags;
 	bool mbox_modified;
+	bool external = t->external;
 	int ret = 0;
 
-	if (t->save_ctx != NULL)
-		ret = mbox_transaction_save_commit(t->save_ctx);
-	mbox_modified = t->mbox_modified;
+	if (mt->save_ctx != NULL)
+		ret = mbox_transaction_save_commit(mt->save_ctx);
+	mbox_modified = mt->mbox_modified;
 
-	if (ret == 0) {
-		if (index_transaction_commit(_t) < 0)
+	if (ret < 0)
+		index_transaction_finish_rollback(&mt->ictx);
+	else {
+		if (index_transaction_finish_commit(&mt->ictx, log_file_seq_r,
+						    log_file_offset_r) < 0)
 			ret = -1;
-	} else {
-		index_transaction_rollback(_t);
 	}
-	t = NULL;
+
+	/* transaction is destroyed now. */
+	mt = NULL;
 
 	if (lock_id != 0 && mbox->mbox_lock_type != F_WRLCK) {
 		/* unlock before writing any changes */
@@ -45,7 +42,7 @@
 		lock_id = 0;
 	}
 
-	if (ret == 0) {
+	if (ret == 0 && !external) {
 		enum mbox_sync_flags mbox_sync_flags = MBOX_SYNC_LAST_COMMIT;
 		if ((flags & MAILBOX_SYNC_FLAG_FULL_READ) != 0 &&
 		    !mbox->mbox_very_dirty_syncs)
@@ -65,16 +62,55 @@
 	return ret;
 }
 
-void mbox_transaction_rollback(struct mailbox_transaction_context *_t)
+static void mbox_transaction_rollback(struct mail_index_transaction *t)
 {
-	struct mbox_transaction_context *t =
-		(struct mbox_transaction_context *)_t;
-	struct mbox_mailbox *mbox = (struct mbox_mailbox *)t->ictx.ibox;
+	struct mbox_transaction_context *mt = MAIL_STORAGE_TRANSACTION(t);
+	struct mbox_mailbox *mbox = (struct mbox_mailbox *)mt->ictx.ibox;
+
+	if (mt->save_ctx != NULL)
+		mbox_transaction_save_rollback(mt->save_ctx);
+
+	if (mt->mbox_lock_id != 0)
+		(void)mbox_unlock(mbox, mt->mbox_lock_id);
+	index_transaction_finish_rollback(&mt->ictx);
+}
+
+void mbox_transaction_created(struct mail_index_transaction *t)
+{
+	struct mailbox *box = MAIL_STORAGE_INDEX(t->view->index);
+
+	if (strcmp(box->storage->name, MBOX_STORAGE_NAME) == 0) {
+		struct mbox_mailbox *mbox = (struct mbox_mailbox *)box;
+		struct mbox_transaction_context *mt;
+
+		mt = i_new(struct mbox_transaction_context, 1);
+		mt->ictx.trans = t;
+		mt->ictx.super = t->v;
 
-	if (t->save_ctx != NULL)
-		mbox_transaction_save_rollback(t->save_ctx);
+		t->v.commit = mbox_transaction_commit;
+		t->v.rollback = mbox_transaction_rollback;
+
+		array_idx_set(&t->mail_index_transaction_module_contexts,
+			      mail_storage_mail_index_module_id, &mt);
+
+		index_transaction_init(&mt->ictx, &mbox->ibox);
+	}
+
+	if (next_hook_mail_index_transaction_created != NULL)
+		next_hook_mail_index_transaction_created(t);
+}
 
-	if (t->mbox_lock_id != 0)
-		(void)mbox_unlock(mbox, t->mbox_lock_id);
-	index_transaction_rollback(_t);
+void mbox_transaction_class_init(void)
+{
+	next_hook_mail_index_transaction_created =
+		hook_mail_index_transaction_created;
+	hook_mail_index_transaction_created = mbox_transaction_created;
 }
+
+void mbox_transaction_class_deinit(void)
+{
+	i_assert(hook_mail_index_transaction_created ==
+		 mbox_transaction_created);
+	hook_mail_index_transaction_created =
+		next_hook_mail_index_transaction_created;
+}
--- a/src/lib-storage/mail-storage-private.h	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/mail-storage-private.h	Wed Jun 28 19:31:05 2006 +0300
@@ -8,11 +8,10 @@
 #define MAIL_STORAGE_ERR_MAILBOX_NOT_FOUND "Mailbox doesn't exist: %s"
 #define MAIL_STORAGE_ERR_NO_PERMISSION "Permission denied"
 
-/* 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 {
+	void (*class_init)(void);
+	void (*class_deinit)(void);
 
-struct mail_storage_vfuncs {
 	struct mail_storage *
 		(*create)(const char *data, const char *user,
 			  enum mail_storage_flags flags,
@@ -241,6 +240,28 @@
 	struct mailbox *box;
 };
 
+/* 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;
+
+/* Storage's module_id for mail_index. */
+extern unsigned int mail_storage_mail_index_module_id;
+
+#define MAIL_STORAGE_INDEX(index) \
+	*((void **)array_idx_modifiable( \
+		&(index)->mail_index_module_contexts, \
+		mail_storage_mail_index_module_id))
+
+#define MAIL_STORAGE_VIEW(view) \
+	*((void **)array_idx_modifiable( \
+		&(view)->mail_index_view_module_contexts, \
+		mail_storage_mail_index_module_id))
+
+#define MAIL_STORAGE_TRANSACTION(trans) \
+	*((void **)array_idx_modifiable( \
+		&(trans)->mail_index_transaction_module_contexts, \
+		mail_storage_mail_index_module_id))
+
 /* Set error message in storage. Critical errors are logged with i_error(),
    but user sees only "internal error" message. */
 void mail_storage_clear_error(struct mail_storage *storage);
--- a/src/lib-storage/mail-storage.c	Wed Jun 28 18:36:42 2006 +0300
+++ b/src/lib-storage/mail-storage.c	Wed Jun 28 19:31:05 2006 +0300
@@ -1,9 +1,10 @@
-/* Copyright (C) 2002-2003 Timo Sirainen */
+/* Copyright (C) 2002-2006 Timo Sirainen */
 
 #include "lib.h"
 #include "ioloop.h"
 #include "array.h"
 #include "var-expand.h"
+#include "mail-index-private.h"
 #include "mail-storage-private.h"
 
 #include <stdlib.h>
@@ -24,12 +25,15 @@
 #define MAILBOX_MAX_HIERARCHY_NAME_LENGTH 200
 
 unsigned int mail_storage_module_id = 0;
+unsigned int mail_storage_mail_index_module_id = 0;
 
 static ARRAY_DEFINE(storages, struct mail_storage *);
 
 void mail_storage_init(void)
 {
 	ARRAY_CREATE(&storages, default_pool, struct mail_storage *, 8);
+
+	mail_storage_mail_index_module_id = mail_index_module_id++;
 }
 
 void mail_storage_deinit(void)
@@ -40,6 +44,9 @@
 
 void mail_storage_class_register(struct mail_storage *storage_class)
 {
+	if (storage_class->v.class_init != NULL)
+		storage_class->v.class_init();
+
 	/* append it after the list, so the autodetection order is correct */
 	array_append(&storages, &storage_class, 1);
 }
@@ -56,6 +63,8 @@
 			break;
 		}
 	}
+
+	storage_class->v.class_deinit();
 }
 
 void mail_storage_parse_env(enum mail_storage_flags *flags_r,