changeset 11488:4b20e692c606 HEAD

lib-storage: Plugin API changed to run plugin functions in correct order. Previously the hooks were run in correct order, but the functions they overrode were run in reverse order. This caused problems when multiple plugins were used.
author Timo Sirainen <tss@iki.fi>
date Mon, 07 Jun 2010 17:06:17 +0100
parents 3a0601cb9e67
children c73ddaa39ca4
files src/lib-storage/mail-storage-hooks.c src/lib-storage/mail-storage-hooks.h src/lib-storage/mail-storage-private.h src/lib-storage/mail-user.h src/lib-storage/mail.c src/lib-storage/mailbox-list-private.h src/plugins/acl/acl-mailbox-list.c src/plugins/acl/acl-mailbox.c src/plugins/acl/acl-plugin.c src/plugins/acl/acl-plugin.h src/plugins/acl/acl-storage.c src/plugins/expire/expire-plugin.c src/plugins/fts-solr/fts-solr-plugin.c src/plugins/fts/fts-plugin.c src/plugins/fts/fts-plugin.h src/plugins/fts/fts-storage.c src/plugins/lazy-expunge/lazy-expunge-plugin.c src/plugins/listescape/listescape-plugin.c src/plugins/mbox-snarf/mbox-snarf-plugin.c src/plugins/notify/notify-storage.c src/plugins/quota/quota-plugin.c src/plugins/quota/quota-plugin.h src/plugins/quota/quota-storage.c src/plugins/trash/trash-plugin.c src/plugins/virtual/virtual-storage.c src/plugins/zlib/zlib-plugin.c
diffstat 26 files changed, 254 insertions(+), 219 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/mail-storage-hooks.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/lib-storage/mail-storage-hooks.c	Mon Jun 07 17:06:17 2010 +0100
@@ -125,6 +125,7 @@
 
 	mail_user_add_plugin_hooks(user);
 
+	user->vlast = &user->v;
 	array_foreach(&user->hooks, hooks) {
 		if ((*hooks)->mail_user_created != NULL)
 			(*hooks)->mail_user_created(user);
@@ -155,6 +156,7 @@
 {
 	const struct mail_storage_hooks *const *hooks;
 
+	storage->vlast = &storage->v;
 	array_foreach(&storage->user->hooks, hooks) {
 		if ((*hooks)->mail_storage_created != NULL)
 			(*hooks)->mail_storage_created(storage);
@@ -165,6 +167,7 @@
 {
 	const struct mail_storage_hooks *const *hooks;
 
+	list->vlast = &list->v;
 	array_foreach(&list->ns->user->hooks, hooks) {
 		if ((*hooks)->mailbox_list_created != NULL)
 			(*hooks)->mailbox_list_created(list);
@@ -175,6 +178,7 @@
 {
 	const struct mail_storage_hooks *const *hooks;
 
+	box->vlast = &box->v;
 	array_foreach(&box->storage->user->hooks, hooks) {
 		if ((*hooks)->mailbox_allocated != NULL)
 			(*hooks)->mailbox_allocated(box);
@@ -190,3 +194,15 @@
 			(*hooks)->mailbox_opened(box);
 	}
 }
+
+void hook_mail_allocated(struct mail *mail)
+{
+	const struct mail_storage_hooks *const *hooks;
+	struct mail_private *pmail = (struct mail_private *)mail;
+
+	pmail->vlast = &pmail->v;
+	array_foreach(&mail->box->storage->user->hooks, hooks) {
+		if ((*hooks)->mail_allocated != NULL)
+			(*hooks)->mail_allocated(mail);
+	}
+}
--- a/src/lib-storage/mail-storage-hooks.h	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/lib-storage/mail-storage-hooks.h	Mon Jun 07 17:06:17 2010 +0100
@@ -7,6 +7,7 @@
 struct mail_namespace;
 struct mailbox_list;
 struct mailbox;
+struct mail;
 
 struct mail_storage_hooks {
 	void (*mail_user_created)(struct mail_user *user);
@@ -16,6 +17,7 @@
 	void (*mailbox_list_created)(struct mailbox_list *list);
 	void (*mailbox_allocated)(struct mailbox *box);
 	void (*mailbox_opened)(struct mailbox *box);
+	void (*mail_allocated)(struct mail *mail);
 };
 
 void mail_storage_hooks_init(void);
@@ -35,5 +37,6 @@
 void hook_mailbox_list_created(struct mailbox_list *list);
 void hook_mailbox_allocated(struct mailbox *box);
 void hook_mailbox_opened(struct mailbox *box);
+void hook_mail_allocated(struct mail *mail);
 
 #endif
--- a/src/lib-storage/mail-storage-private.h	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/lib-storage/mail-storage-private.h	Mon Jun 07 17:06:17 2010 +0100
@@ -61,7 +61,7 @@
 	const char *name;
 	enum mail_storage_class_flags class_flags;
 
-        struct mail_storage_vfuncs v;
+        struct mail_storage_vfuncs v, *vlast;
 
 /* private: */
 	pool_t pool;
@@ -219,7 +219,7 @@
 	struct mail_storage *storage;
 	struct mailbox_list *list;
 
-        struct mailbox_vfuncs v;
+        struct mailbox_vfuncs v, *vlast;
 /* private: */
 	pool_t pool;
 
@@ -327,7 +327,7 @@
 
 struct mail_private {
 	struct mail mail;
-	struct mail_vfuncs v;
+	struct mail_vfuncs v, *vlast;
 
 	enum mail_fetch_field wanted_fields;
 	struct mailbox_header_lookup_ctx *wanted_headers;
--- a/src/lib-storage/mail-user.h	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/lib-storage/mail-user.h	Mon Jun 07 17:06:17 2010 +0100
@@ -13,7 +13,7 @@
 
 struct mail_user {
 	pool_t pool;
-	struct mail_user_vfuncs v;
+	struct mail_user_vfuncs v, *vlast;
 	int refcount;
 
 	const char *username;
--- a/src/lib-storage/mail.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/lib-storage/mail.c	Mon Jun 07 17:06:17 2010 +0100
@@ -15,7 +15,14 @@
 			enum mail_fetch_field wanted_fields,
 			struct mailbox_header_lookup_ctx *wanted_headers)
 {
-	return t->box->v.mail_alloc(t, wanted_fields, wanted_headers);
+	struct mail *mail;
+
+	T_BEGIN {
+		mail = t->box->v.mail_alloc(t, wanted_fields, wanted_headers);
+		hook_mail_allocated(mail);
+	} T_END;
+
+	return mail;
 }
 
 void mail_free(struct mail **mail)
--- a/src/lib-storage/mailbox-list-private.h	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/lib-storage/mailbox-list-private.h	Mon Jun 07 17:06:17 2010 +0100
@@ -88,7 +88,7 @@
 	enum mailbox_list_properties props;
 	size_t mailbox_name_max_length;
 
-	struct mailbox_list_vfuncs v;
+	struct mailbox_list_vfuncs v, *vlast;
 
 /* private: */
 	pool_t pool;
--- a/src/plugins/acl/acl-mailbox-list.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/acl/acl-mailbox-list.c	Mon Jun 07 17:06:17 2010 +0100
@@ -502,10 +502,12 @@
 static void acl_mailbox_list_init_shared(struct mailbox_list *list)
 {
 	struct acl_mailbox_list *alist;
+	struct mailbox_list_vfuncs *v = list->vlast;
 
 	alist = p_new(list->pool, struct acl_mailbox_list, 1);
-	alist->module_ctx.super = list->v;
-	list->v.iter_init = acl_mailbox_list_iter_init_shared;
+	alist->module_ctx.super = *v;
+	list->vlast = &alist->module_ctx.super;
+	v->iter_init = acl_mailbox_list_iter_init_shared;
 
 	MODULE_CONTEXT_SET(list, acl_mailbox_list_module, alist);
 }
@@ -526,6 +528,7 @@
 static void acl_mailbox_list_init_default(struct mailbox_list *list)
 {
 	struct acl_user *auser = ACL_USER_CONTEXT(list->ns->user);
+	struct mailbox_list_vfuncs *v = list->vlast;
 	struct acl_mailbox_list *alist;
 	struct acl_backend *backend;
 	struct mail_namespace *ns;
@@ -558,12 +561,13 @@
 	}
 
 	alist = p_new(list->pool, struct acl_mailbox_list, 1);
-	alist->module_ctx.super = list->v;
-	list->v.iter_init = acl_mailbox_list_iter_init;
-	list->v.iter_next = acl_mailbox_list_iter_next;
-	list->v.iter_deinit = acl_mailbox_list_iter_deinit;
-	list->v.get_mailbox_name_status = acl_get_mailbox_name_status;
-	list->v.create_mailbox_dir = acl_mailbox_list_create_dir;
+	alist->module_ctx.super = *v;
+	list->vlast = &alist->module_ctx.super;
+	v->iter_init = acl_mailbox_list_iter_init;
+	v->iter_next = acl_mailbox_list_iter_next;
+	v->iter_deinit = acl_mailbox_list_iter_deinit;
+	v->get_mailbox_name_status = acl_get_mailbox_name_status;
+	v->create_mailbox_dir = acl_mailbox_list_create_dir;
 
 	acl_storage_rights_ctx_init(&alist->rights, backend);
 	MODULE_CONTEXT_SET(list, acl_mailbox_list_module, alist);
--- a/src/plugins/acl/acl-mailbox.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/acl/acl-mailbox.c	Mon Jun 07 17:06:17 2010 +0100
@@ -20,6 +20,7 @@
 	union mailbox_module_context module_ctx;
 	struct acl_object *aclobj;
 	bool skip_acl_checks;
+	bool acl_enabled;
 };
 
 struct acl_transaction_context {
@@ -335,28 +336,24 @@
 	amail->super.expunge(_mail);
 }
 
-static struct mail *
-acl_mail_alloc(struct mailbox_transaction_context *t,
-	       enum mail_fetch_field wanted_fields,
-	       struct mailbox_header_lookup_ctx *wanted_headers)
+void acl_mail_allocated(struct mail *_mail)
 {
-	struct acl_mailbox *abox = ACL_CONTEXT(t->box);
+	struct acl_mailbox *abox = ACL_CONTEXT(_mail->box);
+	struct mail_private *mail = (struct mail_private *)_mail;
+	struct mail_vfuncs *v = mail->vlast;
 	union mail_module_context *amail;
-	struct mail *_mail;
-	struct mail_private *mail;
 
-	_mail = abox->module_ctx.super.
-		mail_alloc(t, wanted_fields, wanted_headers);
-	mail = (struct mail_private *)_mail;
+	if (abox == NULL || !abox->acl_enabled)
+		return;
 
 	amail = p_new(mail->pool, union mail_module_context, 1);
-	amail->super = mail->v;
+	amail->super = *v;
+	mail->vlast = &amail->super;
 
-	mail->v.update_flags = acl_mail_update_flags;
-	mail->v.update_keywords = acl_mail_update_keywords;
-	mail->v.expunge = acl_mail_expunge;
+	v->update_flags = acl_mail_update_flags;
+	v->update_keywords = acl_mail_update_keywords;
+	v->expunge = acl_mail_expunge;
 	MODULE_CONTEXT_SET_SELF(mail, acl_mail_module, amail);
-	return _mail;
 }
 
 static int acl_save_get_flags(struct mailbox *box, enum mail_flags *flags,
@@ -502,6 +499,7 @@
 void acl_mailbox_allocated(struct mailbox *box)
 {
 	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(box->list);
+	struct mailbox_vfuncs *v = box->vlast;
 	struct acl_mailbox *abox;
 
 	if (alist == NULL) {
@@ -510,24 +508,25 @@
 	}
 
 	abox = p_new(box->pool, struct acl_mailbox, 1);
-	abox->module_ctx.super = box->v;
+	abox->module_ctx.super = *v;
+	box->vlast = &abox->module_ctx.super;
 	abox->aclobj = acl_object_init_from_name(alist->rights.backend,
 						 mailbox_get_name(box));
 
 	if ((box->flags & MAILBOX_FLAG_IGNORE_ACLS) == 0) {
-		box->v.is_readonly = acl_is_readonly;
-		box->v.allow_new_keywords = acl_allow_new_keywords;
-		box->v.open = acl_mailbox_open;
-		box->v.free = acl_mailbox_free;
-		box->v.create = acl_mailbox_create;
-		box->v.update = acl_mailbox_update;
-		box->v.delete = acl_mailbox_delete;
-		box->v.rename = acl_mailbox_rename;
-		box->v.mail_alloc = acl_mail_alloc;
-		box->v.save_begin = acl_save_begin;
-		box->v.keywords_create = acl_keywords_create;
-		box->v.copy = acl_copy;
-		box->v.transaction_commit = acl_transaction_commit;
+		abox->acl_enabled = TRUE;
+		v->is_readonly = acl_is_readonly;
+		v->allow_new_keywords = acl_allow_new_keywords;
+		v->open = acl_mailbox_open;
+		v->free = acl_mailbox_free;
+		v->create = acl_mailbox_create;
+		v->update = acl_mailbox_update;
+		v->delete = acl_mailbox_delete;
+		v->rename = acl_mailbox_rename;
+		v->save_begin = acl_save_begin;
+		v->keywords_create = acl_keywords_create;
+		v->copy = acl_copy;
+		v->transaction_commit = acl_transaction_commit;
 	}
 	MODULE_CONTEXT_SET(box, acl_storage_module, abox);
 }
--- a/src/plugins/acl/acl-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/acl/acl-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -12,7 +12,8 @@
 static struct mail_storage_hooks acl_mail_storage_hooks = {
 	.mail_user_created = acl_mail_user_created,
 	.mail_namespace_storage_added = acl_mail_namespace_storage_added,
-	.mailbox_allocated = acl_mailbox_allocated
+	.mailbox_allocated = acl_mailbox_allocated,
+	.mail_allocated = acl_mail_allocated
 };
 
 void acl_plugin_init(struct module *module)
--- a/src/plugins/acl/acl-plugin.h	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/acl/acl-plugin.h	Mon Jun 07 17:06:17 2010 +0100
@@ -43,6 +43,7 @@
 void acl_mail_user_created(struct mail_user *list);
 
 void acl_mailbox_allocated(struct mailbox *box);
+void acl_mail_allocated(struct mail *mail);
 
 struct acl_backend *acl_mailbox_list_get_backend(struct mailbox_list *list);
 int acl_mailbox_list_have_right(struct mailbox_list *list, const char *name,
--- a/src/plugins/acl/acl-storage.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/acl/acl-storage.c	Mon Jun 07 17:06:17 2010 +0100
@@ -26,11 +26,13 @@
 
 static void acl_mail_user_create(struct mail_user *user, const char *env)
 {
+	struct mail_user_vfuncs *v = user->vlast;
 	struct acl_user *auser;
 
 	auser = p_new(user->pool, struct acl_user, 1);
-	auser->module_ctx.super = user->v;
-	user->v.deinit = acl_user_deinit;
+	auser->module_ctx.super = *v;
+	user->vlast = &auser->module_ctx.super;
+	v->deinit = acl_user_deinit;
 	auser->acl_lookup_dict = acl_lookup_dict_init(user);
 
 	auser->acl_env = env;
--- a/src/plugins/expire/expire-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/expire/expire-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -179,26 +179,22 @@
 	xpr_mail->super.expunge(_mail);
 }
 
-static struct mail *
-expire_mail_alloc(struct mailbox_transaction_context *t,
-		  enum mail_fetch_field wanted_fields,
-		  struct mailbox_header_lookup_ctx *wanted_headers)
+static void expire_mail_allocated(struct mail *_mail)
 {
-	struct expire_mailbox *xpr_box = EXPIRE_CONTEXT(t->box);
+	struct expire_mailbox *xpr_box = EXPIRE_CONTEXT(_mail->box);
+	struct mail_private *mail = (struct mail_private *)_mail;
+	struct mail_vfuncs *v = mail->vlast;
 	union mail_module_context *xpr_mail;
-	struct mail *_mail;
-	struct mail_private *mail;
 
-	_mail = xpr_box->module_ctx.super.
-		mail_alloc(t, wanted_fields, wanted_headers);
-	mail = (struct mail_private *)_mail;
+	if (xpr_box == NULL)
+		return;
 
 	xpr_mail = p_new(mail->pool, union mail_module_context, 1);
-	xpr_mail->super = mail->v;
+	xpr_mail->super = *v;
+	mail->vlast = &xpr_mail->super;
 
-	mail->v.expunge = expire_mail_expunge;
+	v->expunge = expire_mail_expunge;
 	MODULE_CONTEXT_SET_SELF(mail, expire_mail_module, xpr_mail);
-	return _mail;
 }
 
 static int expire_save_finish(struct mail_save_context *ctx)
@@ -224,17 +220,18 @@
 
 static void expire_mailbox_allocate_init(struct mailbox *box)
 {
+	struct mailbox_vfuncs *v = box->vlast;
 	struct expire_mailbox *xpr_box;
 
 	xpr_box = p_new(box->pool, struct expire_mailbox, 1);
-	xpr_box->module_ctx.super = box->v;
+	xpr_box->module_ctx.super = *v;
+	box->vlast = &xpr_box->module_ctx.super;
 
-	box->v.transaction_begin = expire_mailbox_transaction_begin;
-	box->v.transaction_commit = expire_mailbox_transaction_commit;
-	box->v.transaction_rollback = expire_mailbox_transaction_rollback;
-	box->v.mail_alloc = expire_mail_alloc;
-	box->v.save_finish = expire_save_finish;
-	box->v.copy = expire_copy;
+	v->transaction_begin = expire_mailbox_transaction_begin;
+	v->transaction_commit = expire_mailbox_transaction_commit;
+	v->transaction_rollback = expire_mailbox_transaction_rollback;
+	v->save_finish = expire_save_finish;
+	v->copy = expire_copy;
 
 	MODULE_CONTEXT_SET(box, expire_storage_module, xpr_box);
 }
@@ -290,9 +287,12 @@
 	} else if (dict_uri == NULL) {
 		i_error("expire plugin: expire_dict setting missing");
 	} else {
+		struct mail_user_vfuncs *v = user->vlast;
+
 		euser = p_new(user->pool, struct expire_mail_user, 1);
-		euser->module_ctx.super = user->v;
-		user->v.deinit = expire_mail_user_deinit;
+		euser->module_ctx.super = *v;
+		user->vlast = &euser->module_ctx.super;
+		v->deinit = expire_mail_user_deinit;
 
 		euser->set = expire_set_init(expire_get_patterns(user));
 		/* we're using only shared dictionary, the username
@@ -308,7 +308,8 @@
 
 static struct mail_storage_hooks expire_mail_storage_hooks = {
 	.mail_namespaces_created = expire_mail_namespaces_created,
-	.mailbox_allocated = expire_mailbox_allocated
+	.mailbox_allocated = expire_mailbox_allocated,
+	.mail_allocated = expire_mail_allocated
 };
 
 void expire_plugin_init(struct module *module)
--- a/src/plugins/fts-solr/fts-solr-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/fts-solr/fts-solr-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -49,7 +49,6 @@
 	struct fts_solr_user *fuser;
 
 	fuser = p_new(user->pool, struct fts_solr_user, 1);
-	fuser->module_ctx.super = user->v;
 	if (fts_solr_plugin_init_settings(user, &fuser->set, env) < 0) {
 		/* invalid settings, disabling */
 		return;
--- a/src/plugins/fts/fts-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/fts/fts-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -9,7 +9,8 @@
 const char *fts_plugin_version = DOVECOT_VERSION;
 
 static struct mail_storage_hooks fts_mail_storage_hooks = {
-	.mailbox_allocated = fts_mailbox_allocated
+	.mailbox_allocated = fts_mailbox_allocated,
+	.mail_allocated = fts_mail_allocated
 };
 
 void fts_plugin_init(struct module *module)
--- a/src/plugins/fts/fts-plugin.h	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/fts/fts-plugin.h	Mon Jun 07 17:06:17 2010 +0100
@@ -2,6 +2,7 @@
 #define FTS_PLUGIN_H
 
 void fts_mailbox_allocated(struct mailbox *box);
+void fts_mail_allocated(struct mail *mail);
 
 void fts_plugin_init(struct module *module);
 void fts_plugin_deinit(void);
--- a/src/plugins/fts/fts-storage.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/fts/fts-storage.c	Mon Jun 07 17:06:17 2010 +0100
@@ -951,29 +951,24 @@
 	return fmail->module_ctx.super.get_special(_mail, field, value_r);
 }
 
-static struct mail *
-fts_mail_alloc(struct mailbox_transaction_context *t,
-	       enum mail_fetch_field wanted_fields,
-	       struct mailbox_header_lookup_ctx *wanted_headers)
+void fts_mail_allocated(struct mail *_mail)
 {
-	struct fts_mailbox *fbox = FTS_CONTEXT(t->box);
+	struct mail_private *mail = (struct mail_private *)_mail;
+	struct mail_vfuncs *v = mail->vlast;
+	struct fts_mailbox *fbox = FTS_CONTEXT(_mail->box);
 	struct fts_mail *fmail;
-	struct mail *_mail;
-	struct mail_private *mail;
 
-	_mail = fbox->module_ctx.super.
-		mail_alloc(t, wanted_fields, wanted_headers);
-	if (fbox->backend_substr != NULL || fbox->backend_fast != NULL) {
-		mail = (struct mail_private *)_mail;
+	if (fbox == NULL ||
+	    (fbox->backend_substr == NULL && fbox->backend_fast == NULL))
+		return;
 
-		fmail = p_new(mail->pool, struct fts_mail, 1);
-		fmail->module_ctx.super = mail->v;
+	fmail = p_new(mail->pool, struct fts_mail, 1);
+	fmail->module_ctx.super = *v;
+	mail->vlast = &fmail->module_ctx.super;
 
-		mail->v.expunge = fts_mail_expunge;
-		mail->v.get_special = fts_mail_get_special;
-		MODULE_CONTEXT_SET(mail, fts_mail_module, fmail);
-	}
-	return _mail;
+	v->expunge = fts_mail_expunge;
+	v->get_special = fts_mail_get_special;
+	MODULE_CONTEXT_SET(mail, fts_mail_module, fmail);
 }
 
 static void fts_box_backends_init(struct mailbox *box)
@@ -1092,23 +1087,25 @@
 
 static void fts_mailbox_init(struct mailbox *box, const char *env)
 {
+	struct mailbox_vfuncs *v = box->vlast;
 	struct fts_mailbox *fbox;
 
 	fbox = i_new(struct fts_mailbox, 1);
 	fbox->virtual = strcmp(box->storage->name, "virtual") == 0;
 	fbox->env = env;
-	fbox->module_ctx.super = box->v;
-	box->v.free = fts_mailbox_free;
-	box->v.search_init = fts_mailbox_search_init;
-	box->v.search_next_nonblock = fts_mailbox_search_next_nonblock;
-	box->v.search_next_update_seq = fbox->virtual ?
+	fbox->module_ctx.super = *v;
+	box->vlast = &fbox->module_ctx.super;
+
+	v->free = fts_mailbox_free;
+	v->search_init = fts_mailbox_search_init;
+	v->search_next_nonblock = fts_mailbox_search_next_nonblock;
+	v->search_next_update_seq = fbox->virtual ?
 		fts_mailbox_search_next_update_seq_virtual :
 		fts_mailbox_search_next_update_seq;
-	box->v.search_deinit = fts_mailbox_search_deinit;
-	box->v.mail_alloc = fts_mail_alloc;
-	box->v.transaction_begin = fts_transaction_begin;
-	box->v.transaction_rollback = fts_transaction_rollback;
-	box->v.transaction_commit = fts_transaction_commit;
+	v->search_deinit = fts_mailbox_search_deinit;
+	v->transaction_begin = fts_transaction_begin;
+	v->transaction_rollback = fts_transaction_rollback;
+	v->transaction_commit = fts_transaction_commit;
 
 	MODULE_CONTEXT_SET(box, fts_storage_module, fbox);
 }
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -208,25 +208,23 @@
 	lazy_expunge_transaction_free(lt);
 }
 
-static struct mail *
-lazy_expunge_mail_alloc(struct mailbox_transaction_context *t,
-			enum mail_fetch_field wanted_fields,
-			struct mailbox_header_lookup_ctx *wanted_headers)
+static void lazy_expunge_mail_allocated(struct mail *_mail)
 {
-	union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT(t->box);
+	struct lazy_expunge_transaction *lt =
+		LAZY_EXPUNGE_CONTEXT(_mail->transaction);
+	struct mail_private *mail = (struct mail_private *)_mail;
+	struct mail_vfuncs *v = mail->vlast;
 	union mail_module_context *mmail;
-	struct mail *_mail;
-	struct mail_private *mail;
 
-	_mail = mbox->super.mail_alloc(t, wanted_fields, wanted_headers);
-	mail = (struct mail_private *)_mail;
+	if (lt == NULL)
+		return;
 
 	mmail = p_new(mail->pool, union mail_module_context, 1);
-	mmail->super = mail->v;
+	mmail->super = *v;
+	mail->vlast = &mmail->super;
 
-	mail->v.expunge = lazy_expunge_mail_expunge;
+	v->expunge = lazy_expunge_mail_expunge;
 	MODULE_CONTEXT_SET_SELF(mail, lazy_expunge_mail_module, mmail);
-	return _mail;
 }
 
 static int
@@ -471,23 +469,24 @@
 	struct lazy_expunge_mailbox_list *llist =
 		LAZY_EXPUNGE_LIST_CONTEXT(box->list);
 	union mailbox_module_context *mbox;
+	struct mailbox_vfuncs *v = box->vlast;
 
 	if (llist == NULL)
 		return;
 
 	mbox = p_new(box->pool, union mailbox_module_context, 1);
-	mbox->super = box->v;
+	mbox->super = *v;
+	box->vlast = &mbox->super;
 	MODULE_CONTEXT_SET_SELF(box, lazy_expunge_mail_storage_module, mbox);
 
 	if (!llist->internal_namespace) {
-		box->v.transaction_begin = lazy_expunge_transaction_begin;
-		box->v.transaction_commit = lazy_expunge_transaction_commit;
-		box->v.transaction_rollback = lazy_expunge_transaction_rollback;
-		box->v.mail_alloc = lazy_expunge_mail_alloc;
-		box->v.delete = lazy_expunge_mailbox_delete;
-		box->v.rename = lazy_expunge_mailbox_rename;
+		v->transaction_begin = lazy_expunge_transaction_begin;
+		v->transaction_commit = lazy_expunge_transaction_commit;
+		v->transaction_rollback = lazy_expunge_transaction_rollback;
+		v->delete = lazy_expunge_mailbox_delete;
+		v->rename = lazy_expunge_mailbox_rename;
 	} else {
-		box->v.rename = lazy_expunge_mailbox_rename;
+		v->rename = lazy_expunge_mailbox_rename;
 	}
 }
 
@@ -515,8 +514,6 @@
 
 	if (luser != NULL && ns->type == NAMESPACE_PRIVATE) {
 		llist = p_new(list->pool, struct lazy_expunge_mailbox_list, 1);
-		llist->module_ctx.super = list->v;
-
 		MODULE_CONTEXT_SET(list, lazy_expunge_mailbox_list_module,
 				   llist);
 	}
@@ -562,7 +559,6 @@
 	env = mail_user_plugin_getenv(user, "lazy_expunge");
 	if (env != NULL) {
 		luser = p_new(user->pool, struct lazy_expunge_mail_user, 1);
-		luser->module_ctx.super = user->v;
 		luser->env = env;
 
 		MODULE_CONTEXT_SET(user, lazy_expunge_mail_user_module, luser);
@@ -576,7 +572,8 @@
 	.mail_user_created = lazy_expunge_mail_user_created,
 	.mail_namespaces_created = lazy_expunge_mail_namespaces_created,
 	.mail_namespace_storage_added = lazy_expunge_mail_namespace_storage_added,
-	.mailbox_allocated = lazy_expunge_mailbox_allocated
+	.mailbox_allocated = lazy_expunge_mailbox_allocated,
+	.mail_allocated = lazy_expunge_mail_allocated
 };
 
 void lazy_expunge_plugin_init(struct module *module)
--- a/src/plugins/listescape/listescape-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/listescape/listescape-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -265,10 +265,12 @@
 static void listescape_mail_storage_created(struct mail_storage *storage)
 {
 	struct listescape_mail_storage *mstorage;
+	struct mail_storage_vfuncs *v = storage->vlast;
 
 	mstorage = p_new(storage->pool, struct listescape_mail_storage, 1);
-	mstorage->module_ctx.super = storage->v;
-	storage->v.mailbox_alloc = listescape_mailbox_alloc;
+	mstorage->module_ctx.super = *v;
+	storage->vlast = &mstorage->module_ctx.super;
+	v->mailbox_alloc = listescape_mailbox_alloc;
 
 	MODULE_CONTEXT_SET(storage, listescape_storage_module, mstorage);
 }
@@ -276,6 +278,7 @@
 static void listescape_mail_namespace_storage_added(struct mail_namespace *ns)
 {
 	struct mailbox_list *list = ns->list;
+	struct mailbox_list_vfuncs *v = list->vlast;
 	struct listescape_mailbox_list *mlist;
 	const char *env;
 
@@ -285,15 +288,16 @@
 	ns->real_sep = ns->sep;
 
 	mlist = p_new(list->pool, struct listescape_mailbox_list, 1);
-	mlist->module_ctx.super = list->v;
+	mlist->module_ctx.super = *v;
+	list->vlast = &mlist->module_ctx.super;
 	mlist->list_name = str_new(list->pool, 256);
-	list->v.iter_init = listescape_mailbox_list_iter_init;
-	list->v.iter_next = listescape_mailbox_list_iter_next;
-	list->v.iter_deinit = listescape_mailbox_list_iter_deinit;
-	list->v.set_subscribed = listescape_set_subscribed;
-	list->v.get_mailbox_name_status = listescape_get_mailbox_name_status;
-	list->v.is_valid_existing_name = listescape_is_valid_existing_name;
-	list->v.is_valid_create_name = listescape_is_valid_create_name;
+	v->iter_init = listescape_mailbox_list_iter_init;
+	v->iter_next = listescape_mailbox_list_iter_next;
+	v->iter_deinit = listescape_mailbox_list_iter_deinit;
+	v->set_subscribed = listescape_set_subscribed;
+	v->get_mailbox_name_status = listescape_get_mailbox_name_status;
+	v->is_valid_existing_name = listescape_is_valid_existing_name;
+	v->is_valid_create_name = listescape_is_valid_create_name;
 
 	env = mail_user_plugin_getenv(list->ns->user, "listescape_char");
 	mlist->escape_char = env != NULL && *env != '\0' ?
--- a/src/plugins/mbox-snarf/mbox-snarf-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/mbox-snarf/mbox-snarf-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -169,12 +169,14 @@
 mbox_snarf_mail_storage_create(struct mail_storage *storage, const char *path)
 {
 	struct mbox_snarf_mail_storage *mstorage;
+	struct mail_storage_vfuncs *v = storage->vlast;
 
 	path = mail_user_home_expand(storage->user, path);
 	mstorage = p_new(storage->pool, struct mbox_snarf_mail_storage, 1);
 	mstorage->snarf_inbox_path = p_strdup(storage->pool, path);
-	mstorage->module_ctx.super = storage->v;
-	storage->v.mailbox_alloc = mbox_snarf_mailbox_alloc;
+	mstorage->module_ctx.super = *v;
+	storage->vlast = &mstorage->module_ctx.super;
+	v->mailbox_alloc = mbox_snarf_mailbox_alloc;
 
 	MODULE_CONTEXT_SET(storage, mbox_snarf_storage_module, mstorage);
 }
--- a/src/plugins/notify/notify-storage.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/notify/notify-storage.c	Mon Jun 07 17:06:17 2010 +0100
@@ -71,27 +71,20 @@
 	notify_contexts_mail_update_keywords(_mail, old_keywords);
 }
 
-static struct mail *
-notify_mail_alloc(struct mailbox_transaction_context *t,
-		  enum mail_fetch_field wanted_fields,
-		  struct mailbox_header_lookup_ctx *wanted_headers)
+static void notify_mail_allocated(struct mail *_mail)
 {
-	union mailbox_module_context *lbox = NOTIFY_CONTEXT(t->box);
+	struct mail_private *mail = (struct mail_private *)_mail;
+	struct mail_vfuncs *v = mail->vlast;
 	union mail_module_context *lmail;
-	struct mail *_mail;
-	struct mail_private *mail;
-
-	_mail = lbox->super.mail_alloc(t, wanted_fields, wanted_headers);
-	mail = (struct mail_private *)_mail;
 
 	lmail = p_new(mail->pool, union mail_module_context, 1);
-	lmail->super = mail->v;
+	lmail->super = *v;
+	mail->vlast = &lmail->super;
 
-	mail->v.expunge = notify_mail_expunge;
-	mail->v.update_flags = notify_mail_update_flags;
-	mail->v.update_keywords = notify_mail_update_keywords;
+	v->expunge = notify_mail_expunge;
+	v->update_flags = notify_mail_update_flags;
+	v->update_keywords = notify_mail_update_keywords;
 	MODULE_CONTEXT_SET_SELF(mail, notify_mail_module, lmail);
-	return _mail;
 }
 
 static int
@@ -224,25 +217,27 @@
 
 static void notify_mailbox_allocated(struct mailbox *box)
 {
+	struct mailbox_vfuncs *v = box->vlast;
 	union mailbox_module_context *lbox;
 
 	lbox = p_new(box->pool, union mailbox_module_context, 1);
-	lbox->super = box->v;
+	lbox->super = *v;
+	box->vlast = &lbox->super;
 
-	box->v.mail_alloc = notify_mail_alloc;
-	box->v.copy = notify_copy;
-	box->v.save_begin = notify_save_begin;
-	box->v.save_finish = notify_save_finish;
-	box->v.transaction_begin = notify_transaction_begin;
-	box->v.transaction_commit = notify_transaction_commit;
-	box->v.transaction_rollback = notify_transaction_rollback;
-	box->v.delete = notify_mailbox_delete;
-	box->v.rename = notify_mailbox_rename;
+	v->copy = notify_copy;
+	v->save_begin = notify_save_begin;
+	v->save_finish = notify_save_finish;
+	v->transaction_begin = notify_transaction_begin;
+	v->transaction_commit = notify_transaction_commit;
+	v->transaction_rollback = notify_transaction_rollback;
+	v->delete = notify_mailbox_delete;
+	v->rename = notify_mailbox_rename;
 	MODULE_CONTEXT_SET_SELF(box, notify_storage_module, lbox);
 }
 
 static struct mail_storage_hooks notify_mail_storage_hooks = {
-	.mailbox_allocated = notify_mailbox_allocated
+	.mailbox_allocated = notify_mailbox_allocated,
+	.mail_allocated = notify_mail_allocated
 };
 
 void notify_plugin_init_storage(struct module *module)
--- a/src/plugins/quota/quota-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/quota/quota-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -13,7 +13,8 @@
 	.mail_user_created = quota_mail_user_created,
 	.mail_namespaces_created = quota_mail_namespaces_created,
 	.mail_namespace_storage_added = quota_mail_namespace_storage_added,
-	.mailbox_allocated = quota_mailbox_allocated
+	.mailbox_allocated = quota_mailbox_allocated,
+	.mail_allocated = quota_mail_allocated
 };
 
 void quota_plugin_init(struct module *module)
--- a/src/plugins/quota/quota-plugin.h	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/quota/quota-plugin.h	Mon Jun 07 17:06:17 2010 +0100
@@ -6,6 +6,7 @@
 
 struct module;
 struct mailbox;
+struct mail;
 
 #define QUOTA_USER_CONTEXT(obj) \
 	MODULE_CONTEXT(obj, quota_user_module)
@@ -24,6 +25,7 @@
 void quota_mail_namespace_storage_added(struct mail_namespace *ns);
 void quota_mail_namespaces_created(struct mail_namespace *namespaces);
 void quota_mailbox_allocated(struct mailbox *box);
+void quota_mail_allocated(struct mail *mail);
 
 void quota_plugin_init(struct module *module);
 void quota_plugin_deinit(void);
--- a/src/plugins/quota/quota-storage.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/quota/quota-storage.c	Mon Jun 07 17:06:17 2010 +0100
@@ -113,26 +113,22 @@
 	quota_transaction_rollback(&qt);
 }
 
-static struct mail *
-quota_mail_alloc(struct mailbox_transaction_context *t,
-		 enum mail_fetch_field wanted_fields,
-		 struct mailbox_header_lookup_ctx *wanted_headers)
+void quota_mail_allocated(struct mail *_mail)
 {
-	struct quota_mailbox *qbox = QUOTA_CONTEXT(t->box);
+	struct quota_mailbox *qbox = QUOTA_CONTEXT(_mail->box);
+	struct mail_private *mail = (struct mail_private *)_mail;
+	struct mail_vfuncs *v = mail->vlast;
 	union mail_module_context *qmail;
-	struct mail *_mail;
-	struct mail_private *mail;
 
-	_mail = qbox->module_ctx.super.
-		mail_alloc(t, wanted_fields, wanted_headers);
-	mail = (struct mail_private *)_mail;
+	if (qbox == NULL)
+		return;
 
 	qmail = p_new(mail->pool, union mail_module_context, 1);
-	qmail->super = mail->v;
+	qmail->super = *v;
+	mail->vlast = &qmail->super;
 
-	mail->v.expunge = quota_mail_expunge;
+	v->expunge = quota_mail_expunge;
 	MODULE_CONTEXT_SET_SELF(mail, quota_mail_module, qmail);
-	return _mail;
 }
 
 static int quota_check(struct mailbox_transaction_context *t, struct mail *mail)
@@ -389,25 +385,26 @@
 
 void quota_mailbox_allocated(struct mailbox *box)
 {
+	struct mailbox_vfuncs *v = box->vlast;
 	struct quota_mailbox *qbox;
 
 	if (QUOTA_LIST_CONTEXT(box->list) == NULL)
 		return;
 
 	qbox = p_new(box->pool, struct quota_mailbox, 1);
-	qbox->module_ctx.super = box->v;
+	qbox->module_ctx.super = *v;
+	box->vlast = &qbox->module_ctx.super;
 
-	box->v.transaction_begin = quota_mailbox_transaction_begin;
-	box->v.transaction_commit = quota_mailbox_transaction_commit;
-	box->v.transaction_rollback = quota_mailbox_transaction_rollback;
-	box->v.mail_alloc = quota_mail_alloc;
-	box->v.save_begin = quota_save_begin;
-	box->v.save_finish = quota_save_finish;
-	box->v.copy = quota_copy;
-	box->v.sync_notify = quota_mailbox_sync_notify;
-	box->v.sync_deinit = quota_mailbox_sync_deinit;
-	box->v.delete = quota_mailbox_delete;
-	box->v.free = quota_mailbox_free;
+	v->transaction_begin = quota_mailbox_transaction_begin;
+	v->transaction_commit = quota_mailbox_transaction_commit;
+	v->transaction_rollback = quota_mailbox_transaction_rollback;
+	v->save_begin = quota_save_begin;
+	v->save_finish = quota_save_finish;
+	v->copy = quota_copy;
+	v->sync_notify = quota_mailbox_sync_notify;
+	v->sync_deinit = quota_mailbox_sync_deinit;
+	v->delete = quota_mailbox_delete;
+	v->free = quota_mailbox_free;
 	MODULE_CONTEXT_SET(box, quota_storage_module, qbox);
 }
 
@@ -436,14 +433,16 @@
 
 void quota_mail_user_created(struct mail_user *user)
 {
+	struct mail_user_vfuncs *v = user->vlast;
 	struct quota_user *quser;
 	struct quota_settings *set;
 
 	set = quota_user_read_settings(user);
 	if (set != NULL) {
 		quser = p_new(user->pool, struct quota_user, 1);
-		quser->module_ctx.super = user->v;
-		user->v.deinit = quota_user_deinit;
+		quser->module_ctx.super = *v;
+		user->vlast = &quser->module_ctx.super;
+		v->deinit = quota_user_deinit;
 		quser->quota = quota_init(set, user);
 
 		MODULE_CONTEXT_SET(user, quota_user_module, quser);
@@ -490,9 +489,12 @@
 	}
 
 	if (add) {
+		struct mailbox_list_vfuncs *v = list->vlast;
+
 		qlist = p_new(list->pool, struct quota_mailbox_list, 1);
-		qlist->module_ctx.super = list->v;
-		list->v.deinit = quota_mailbox_list_deinit;
+		qlist->module_ctx.super = *v;
+		list->vlast = &qlist->module_ctx.super;
+		v->deinit = quota_mailbox_list_deinit;
 		MODULE_CONTEXT_SET(list, quota_mailbox_list_module, qlist);
 
 		/* register to owner's quota roots */
--- a/src/plugins/trash/trash-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/trash/trash-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -312,7 +312,6 @@
 		i_error("trash plugin: quota plugin not initialized");
 	} else {
 		tuser = p_new(user->pool, struct trash_user, 1);
-		tuser->module_ctx.super = user->v;
 		MODULE_CONTEXT_SET(user, trash_user_module, tuser);
 
 		if (read_configuration(user, env) == 0) {
--- a/src/plugins/virtual/virtual-storage.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/virtual/virtual-storage.c	Mon Jun 07 17:06:17 2010 +0100
@@ -389,13 +389,15 @@
 static void virtual_storage_add_list(struct mail_storage *storage ATTR_UNUSED,
 				     struct mailbox_list *list)
 {
+	struct mailbox_list_vfuncs *v = list->vlast;
 	struct virtual_mailbox_list *mlist;
 
 	mlist = p_new(list->pool, struct virtual_mailbox_list, 1);
-	mlist->module_ctx.super = list->v;
+	mlist->module_ctx.super = *v;
+	list->vlast = &mlist->module_ctx.super;
 
 	list->ns->flags |= NAMESPACE_FLAG_NOQUOTA;
-	list->v.get_mailbox_flags = virtual_list_get_mailbox_flags;
+	v->get_mailbox_flags = virtual_list_get_mailbox_flags;
 
 	MODULE_CONTEXT_SET(list, virtual_mailbox_list_module, mlist);
 }
--- a/src/plugins/zlib/zlib-plugin.c	Mon Jun 07 14:05:42 2010 +0100
+++ b/src/plugins/zlib/zlib-plugin.c	Mon Jun 07 17:06:17 2010 +0100
@@ -168,25 +168,22 @@
 	return index_mail_init_stream(imail, hdr_size, body_size, stream_r);
 }
 
-static struct mail *
-zlib_permail_mail_alloc(struct mailbox_transaction_context *t,
-			enum mail_fetch_field wanted_fields,
-			struct mailbox_header_lookup_ctx *wanted_headers)
+static void zlib_mail_allocated(struct mail *_mail)
 {
-	union mailbox_module_context *zbox = ZLIB_CONTEXT(t->box);
+	struct zlib_transaction_context *zt = ZLIB_CONTEXT(_mail->transaction);
+	struct mail_private *mail = (struct mail_private *)_mail;
+	struct mail_vfuncs *v = mail->vlast;
 	union mail_module_context *zmail;
-	struct mail *_mail;
-	struct mail_private *mail;
 
-	_mail = zbox->super.mail_alloc(t, wanted_fields, wanted_headers);
-	mail = (struct mail_private *)_mail;
+	if (zt == NULL)
+		return;
 
 	zmail = p_new(mail->pool, union mail_module_context, 1);
-	zmail->super = mail->v;
+	zmail->super = *v;
+	mail->vlast = &zmail->super;
 
-	mail->v.get_stream = zlib_permail_get_stream;
+	v->get_stream = zlib_permail_get_stream;
 	MODULE_CONTEXT_SET_SELF(mail, zlib_mail_module, zmail);
-	return _mail;
 }
 
 static struct mailbox_transaction_context *
@@ -292,19 +289,19 @@
 	return 0;
 }
 
-static void zlib_permail_alloc_init(struct mailbox *box)
+static void
+zlib_permail_alloc_init(struct mailbox *box, struct mailbox_vfuncs *v)
 {
 	struct zlib_user *zuser = ZLIB_USER_CONTEXT(box->storage->user);
 
-	box->v.mail_alloc = zlib_permail_mail_alloc;
-	box->v.transaction_begin = zlib_mailbox_transaction_begin;
-	box->v.transaction_rollback = zlib_mailbox_transaction_rollback;
-	box->v.transaction_commit = zlib_mailbox_transaction_commit;
+	v->transaction_begin = zlib_mailbox_transaction_begin;
+	v->transaction_rollback = zlib_mailbox_transaction_rollback;
+	v->transaction_commit = zlib_mailbox_transaction_commit;
 	if (zuser->save_handler == NULL) {
-		box->v.save_begin = zlib_mail_save_begin;
-		box->v.save_finish = zlib_mail_save_finish;
+		v->save_begin = zlib_mail_save_begin;
+		v->save_finish = zlib_mail_save_finish;
 	} else {
-		box->v.save_begin = zlib_mail_save_compress_begin;
+		v->save_begin = zlib_mail_save_compress_begin;
 	}
 }
 
@@ -352,18 +349,20 @@
 
 static void zlib_mailbox_allocated(struct mailbox *box)
 {
+	struct mailbox_vfuncs *v = box->vlast;
 	union mailbox_module_context *zbox;
 
 	zbox = p_new(box->pool, union mailbox_module_context, 1);
-	zbox->super = box->v;
-	box->v.open = zlib_mailbox_open;
+	zbox->super = *v;
+	box->vlast = &zbox->super;
+	v->open = zlib_mailbox_open;
 
 	MODULE_CONTEXT_SET_SELF(box, zlib_storage_module, zbox);
 
 	if (strcmp(box->storage->name, "maildir") == 0 ||
 	    strcmp(box->storage->name, "mdbox") == 0 ||
 	    strcmp(box->storage->name, "dbox") == 0)
-		zlib_permail_alloc_init(box);
+		zlib_permail_alloc_init(box, v);
 }
 
 static void zlib_mail_user_created(struct mail_user *user)
@@ -372,7 +371,6 @@
 	const char *name;
 
 	zuser = p_new(user->pool, struct zlib_user, 1);
-	zuser->module_ctx.super = user->v;
 
 	name = mail_user_plugin_getenv(user, "zlib_save");
 	if (name != NULL && *name != '\0') {
@@ -395,7 +393,8 @@
 
 static struct mail_storage_hooks zlib_mail_storage_hooks = {
 	.mail_user_created = zlib_mail_user_created,
-	.mailbox_allocated = zlib_mailbox_allocated
+	.mailbox_allocated = zlib_mailbox_allocated,
+	.mail_allocated = zlib_mail_allocated
 };
 
 void zlib_plugin_init(struct module *module)