Mercurial > dovecot > core-2.2
changeset 11508:6d32cf98b5f3 HEAD
lib-storage: Fixes to recent plugin API change.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 09 Jun 2010 18:02:46 +0100 |
parents | e85e6b1df82f |
children | cc6ebfa394d3 |
files | src/lib-storage/mail-storage-hooks.c |
diffstat | 1 files changed, 82 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- 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; + } } }