]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-storage: Fixes to recent plugin API change.
authorTimo Sirainen <tss@iki.fi>
Wed, 9 Jun 2010 17:02:46 +0000 (18:02 +0100)
committerTimo Sirainen <tss@iki.fi>
Wed, 9 Jun 2010 17:02:46 +0000 (18:02 +0100)
--HG--
branch : HEAD

src/lib-storage/mail-storage-hooks.c

index 2038950bda91a836e438a8d5a5ef5c2a2d747640..5b425d26ffd0a9d71a6d0b0ae34a7324b2b6aa44 100644 (file)
@@ -119,16 +119,70 @@ static void mail_user_add_plugin_hooks(struct mail_user *user)
        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_namespaces_created(struct mail_namespace *namespaces)
 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 @@ void hook_mail_allocated(struct mail *mail)
 {
        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;
+               }
        }
 }