mail-storage-hooks.c revision da5c7f6eb2250089c74e00d3dc6284d43949f744
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2009-2017 Dovecot authors, see the included COPYING file */
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen /* Pointer to vfuncs struct. This assumes that a struct containing
78a5b3e697af5db96fe0dffed600b0d6370bb8e5Timo Sirainen function pointers equals to an array of function pointers. Not
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ANSI-C, but should work in all OSes supported by Dovecot. Much
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen easier anyway than doing this work manually.. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* nonzero in the areas where vfuncs has been changed */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* size of the vfuncs struct */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen /* number of function pointers in the struct */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int count;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainenstatic ARRAY(struct mail_storage_module_hooks) module_hooks = ARRAY_INIT;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainenstatic ARRAY(const struct mail_storage_hooks *) internal_hooks = ARRAY_INIT;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* allow calling this even if mail_storage_hooks_init() hasn't been
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen called, because e.g. doveadm plugins could call
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen mail_storage_hooks_add() even though mail storage is never
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen initialized. */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainenvoid mail_storage_hooks_add(struct module *module,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* allow adding hooks before mail_storage_hooks_init() */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenvoid mail_storage_hooks_add_forced(struct module *module,
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainenvoid mail_storage_hooks_remove(const struct mail_storage_hooks *hooks)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const struct mail_storage_module_hooks *module_hook;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen idx = array_foreach_idx(&module_hooks, module_hook);
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainenvoid mail_storage_hooks_add_internal(const struct mail_storage_hooks *hooks)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenvoid mail_storage_hooks_remove_internal(const struct mail_storage_hooks *hooks)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const struct mail_storage_hooks *const *old_hooks;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen idx = array_foreach_idx(&internal_hooks, old_hooks);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenmail_storage_module_hooks_cmp(const struct mail_storage_module_hooks *h1,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const char *s1 = h1->module->path, *s2 = h2->module->path;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const char *p;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainenstatic void mail_user_add_plugin_hooks(struct mail_user *user)
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen const struct mail_storage_module_hooks *module_hook;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen ARRAY(struct mail_storage_module_hooks) tmp_hooks;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen /* first get all hooks wanted by the user */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen t_array_init(&tmp_hooks, array_count(&module_hooks));
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen plugins = t_strsplit_spaces(user->set->mail_plugins, ", ");
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen name = module_get_plugin_name(module_hook->module);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* next we have to sort them by the modules' priority (based on name) */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen array_sort(&tmp_hooks, mail_storage_module_hooks_cmp);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* now that we have them in order, save them to user's hooks */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen array_count(&tmp_hooks) + array_count(&internal_hooks));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen array_append(&user->hooks, &module_hook->hooks, 1);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen array_append_array(&user->hooks, &internal_hooks);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic void hook_build_append(struct hook_build_context *ctx, void (**vfuncs)())
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen stack = p_new(ctx->pool, struct hook_stack, 1);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen DLLIST2_APPEND(&ctx->head, &ctx->tail, stack);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenhook_build_init(void (**vfuncs)(), size_t size)
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen pool = pool_alloconly_create("hook build context", 2048);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen ctx = p_new(pool, struct hook_build_context, 1);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenhook_update_mask(struct hook_build_context *ctx, struct hook_stack *stack,
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen unsigned int i;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenhook_copy_stack(struct hook_build_context *ctx, struct hook_stack *stack)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen unsigned int i;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainenstatic void hook_build_update(struct hook_build_context *ctx, void *_vlast)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* no vfuncs overridden */
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen /* ctx->vfuncs_stack->vfuncs points to the root vfuncs,
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen ctx->vfuncs_stack->next->vfuncs points to the first super function
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen that is being called, and so on.
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen the previous plugin added its vfuncs to the stack tail.
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen vlast contains the previous plugin's super vfuncs, which is where
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen the next plugin should put its own vfuncs.
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen first we'll need to figure out what vfuncs the previous plugin
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen changed and update the mask */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* now go up in the stack as long as the mask isn't set,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen and update the vfuncs */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen for (stack = ctx->tail->prev; stack != NULL; stack = stack->prev)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen /* add vlast to stack */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenvoid hook_mail_user_created(struct mail_user *user)
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen const struct mail_storage_hooks *const *hooks;
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen ctx = hook_build_init((void *)&user->v, sizeof(user->v));
98720d3b830e8ec762e9bdde94a71c0ef184595dTimo Sirainen if ((*hooks)->mail_user_created != NULL) T_BEGIN {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenvoid hook_mail_namespace_storage_added(struct mail_namespace *ns)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const struct mail_storage_hooks *const *hooks;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if ((*hooks)->mail_namespace_storage_added != NULL) T_BEGIN {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainenvoid hook_mail_namespaces_created(struct mail_namespace *namespaces)
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen const struct mail_storage_hooks *const *hooks;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen array_foreach(&namespaces->user->hooks, hooks) {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if ((*hooks)->mail_namespaces_created != NULL) T_BEGIN {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen (*hooks)->mail_namespaces_created(namespaces);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainenvoid hook_mail_namespaces_added(struct mail_namespace *namespaces)
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen const struct mail_storage_hooks *const *hooks;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen array_foreach(&namespaces->user->hooks, hooks) {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if ((*hooks)->mail_namespaces_added != NULL) T_BEGIN {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainenvoid hook_mail_storage_created(struct mail_storage *storage)
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen const struct mail_storage_hooks *const *hooks;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen ctx = hook_build_init((void *)&storage->v, sizeof(storage->v));
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if ((*hooks)->mail_storage_created != NULL) T_BEGIN {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenvoid hook_mailbox_list_created(struct mailbox_list *list)
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen const struct mail_storage_hooks *const *hooks;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen ctx = hook_build_init((void *)&list->v, sizeof(list->v));
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen array_foreach(&list->ns->user->hooks, hooks) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if ((*hooks)->mailbox_list_created != NULL) T_BEGIN {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenvoid hook_mailbox_allocated(struct mailbox *box)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const struct mail_storage_hooks *const *hooks;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen ctx = hook_build_init((void *)&box->v, sizeof(box->v));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen array_foreach(&box->storage->user->hooks, hooks) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if ((*hooks)->mailbox_allocated != NULL) T_BEGIN {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const struct mail_storage_hooks *const *hooks;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen array_foreach(&box->storage->user->hooks, hooks) {
ad5130b3afda4cf30e6272d96d818f84d3ae4e55Timo Sirainen if ((*hooks)->mailbox_opened != NULL) T_BEGIN {
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen const struct mail_storage_hooks *const *hooks;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen struct mail_private *pmail = (struct mail_private *)mail;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen ctx = hook_build_init((void *)&pmail->v, sizeof(pmail->v));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen array_foreach(&mail->box->storage->user->hooks, hooks) {