dovecot-2.0: lib-storage: Fixes to recent plugin API change.

dovecot at dovecot.org dovecot at dovecot.org
Wed Jun 9 20:02:58 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/6d32cf98b5f3
changeset: 11508:6d32cf98b5f3
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Jun 09 18:02:46 2010 +0100
description:
lib-storage: Fixes to recent plugin API change.

diffstat:

 src/lib-storage/mail-storage-hooks.c |  87 +++++++++++++++++++++++++++-
 1 files changed, 82 insertions(+), 5 deletions(-)

diffs (147 lines):

diff -r e85e6b1df82f -r 6d32cf98b5f3 src/lib-storage/mail-storage-hooks.c
--- a/src/lib-storage/mail-storage-hooks.c	Wed Jun 09 17:03:20 2010 +0100
+++ b/src/lib-storage/mail-storage-hooks.c	Wed Jun 09 18:02:46 2010 +0100
@@ -119,16 +119,70 @@
 	array_append_array(&user->hooks, &internal_hooks);
 }
 
+static void hook_vfuncs_update(void *_v, const void *_vlast,
+			       const void *_prev_vlast,
+			       void *_mask, size_t size)
+{
+	/* This function assumes that a struct containing function pointers
+	   equals to an array of function pointers. Not ANSI-C, but should work
+	   in all OSes supported by Dovecot. Much easier anyway than doing this
+	   work manually..
+
+	   The problem this function solves is:
+
+	   1. First hook overrides methods A and B by updating vlast->A+B.
+	      vlast points to v, so v->A+B gets updated.
+	   2. Second hook overrides method B and C by updating vlast->B+C.
+	      vlast points first hook's super struct. now, the call paths go:
+	       B: v->B = hook1_B, which calls its super.B = hook2_B,
+	          which calls super.B = original -> all OK
+	       C: v->C = still the original, so hook2_C won't be called!
+
+	   The idea is to detect the C situation, and update v->C = hook2_C
+	   so that the call path goes:
+	       C: v->C = hook2_C, which calls super.C = original
+	*/
+	void (**v)() = _v;
+	void (*const *prev_vlast)() = _prev_vlast;
+	void (*const *vlast)() = _vlast;
+	void (**mask)() = _mask;
+	unsigned int i, count;
+
+	i_assert((size % sizeof(void (*)())) == 0);
+	count = size / sizeof(void (*)());
+
+	for (i = 0; i < count; i++) {
+		if (mask[i] != NULL)
+			continue;
+
+		if (v[i] != vlast[i]) {
+			/* first hook overriding any method in this object */
+			mask[i] = v[i];
+		} else if (prev_vlast != NULL && v[i] != prev_vlast[i]) {
+			/* first hook overriding this method object
+			   (but earlier hooks already overrode other methods) */
+			v[i] = prev_vlast[i];
+			mask[i] = prev_vlast[i];
+		}
+	}
+}
+
 void hook_mail_user_created(struct mail_user *user)
 {
 	const struct mail_storage_hooks *const *hooks;
+	struct mail_user_vfuncs mask, *prev_vlast = NULL;
 
 	mail_user_add_plugin_hooks(user);
 
+	memset(&mask, 0, sizeof(mask));
 	user->vlast = &user->v;
 	array_foreach(&user->hooks, hooks) {
-		if ((*hooks)->mail_user_created != NULL)
+		if ((*hooks)->mail_user_created != NULL) {
 			(*hooks)->mail_user_created(user);
+			hook_vfuncs_update(&user->v, user->vlast, prev_vlast,
+					   &mask, sizeof(mask));
+			prev_vlast = user->vlast;
+		}
 	}
 }
 
@@ -155,33 +209,51 @@
 void hook_mail_storage_created(struct mail_storage *storage)
 {
 	const struct mail_storage_hooks *const *hooks;
+	struct mail_storage_vfuncs mask, *prev_vlast = NULL;
 
+	memset(&mask, 0, sizeof(mask));
 	storage->vlast = &storage->v;
 	array_foreach(&storage->user->hooks, hooks) {
-		if ((*hooks)->mail_storage_created != NULL)
+		if ((*hooks)->mail_storage_created != NULL) {
 			(*hooks)->mail_storage_created(storage);
+			hook_vfuncs_update(&storage->v, storage->vlast,
+					   prev_vlast, &mask, sizeof(mask));
+			prev_vlast = storage->vlast;
+		}
 	}
 }
 
 void hook_mailbox_list_created(struct mailbox_list *list)
 {
 	const struct mail_storage_hooks *const *hooks;
+	struct mailbox_list_vfuncs mask, *prev_vlast = NULL;
 
+	memset(&mask, 0, sizeof(mask));
 	list->vlast = &list->v;
 	array_foreach(&list->ns->user->hooks, hooks) {
-		if ((*hooks)->mailbox_list_created != NULL)
+		if ((*hooks)->mailbox_list_created != NULL) {
 			(*hooks)->mailbox_list_created(list);
+			hook_vfuncs_update(&list->v, list->vlast, prev_vlast,
+					   &mask, sizeof(mask));
+			prev_vlast = list->vlast;
+		}
 	}
 }
 
 void hook_mailbox_allocated(struct mailbox *box)
 {
 	const struct mail_storage_hooks *const *hooks;
+	struct mailbox_vfuncs mask, *prev_vlast = NULL;
 
+	memset(&mask, 0, sizeof(mask));
 	box->vlast = &box->v;
 	array_foreach(&box->storage->user->hooks, hooks) {
-		if ((*hooks)->mailbox_allocated != NULL)
+		if ((*hooks)->mailbox_allocated != NULL) {
 			(*hooks)->mailbox_allocated(box);
+			hook_vfuncs_update(&box->v, box->vlast, prev_vlast,
+					   &mask, sizeof(mask));
+			prev_vlast = box->vlast;
+		}
 	}
 }
 
@@ -199,10 +271,15 @@
 {
 	const struct mail_storage_hooks *const *hooks;
 	struct mail_private *pmail = (struct mail_private *)mail;
+	struct mail_vfuncs mask, *prev_vlast = NULL;
 
 	pmail->vlast = &pmail->v;
 	array_foreach(&mail->box->storage->user->hooks, hooks) {
-		if ((*hooks)->mail_allocated != NULL)
+		if ((*hooks)->mail_allocated != NULL) {
 			(*hooks)->mail_allocated(mail);
+			hook_vfuncs_update(&pmail->v, pmail->vlast, prev_vlast,
+					   &mask, sizeof(mask));
+			prev_vlast = pmail->vlast;
+		}
 	}
 }


More information about the dovecot-cvs mailing list