notify-storage.c revision 263e4b2733768062cb0b8b8917cad78fa2a04ff9
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen#include "lib.h"
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen#include "array.h"
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen#include "mail-storage-private.h"
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#include "mailbox-list-private.h"
4afd50dff16661684ad2acddad7284bcd8c564dbTimo Sirainen#include "notify-plugin-private.h"
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen#define NOTIFY_CONTEXT(obj) \
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen MODULE_CONTEXT(obj, notify_storage_module)
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen#define NOTIFY_MAIL_CONTEXT(obj) \
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen MODULE_CONTEXT(obj, notify_mail_module)
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen#define NOTIFY_LIST_CONTEXT(obj) \
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen MODULE_CONTEXT(obj, notify_mailbox_list_module)
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainenstruct notify_transaction_context {
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen union mailbox_transaction_module_context module_ctx;
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen struct mail *tmp_mail;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen};
f98cd3b7ccfb026fb56c580b5c7c2e2ee5468049Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(notify_storage_module,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen &mail_storage_module_register);
f98cd3b7ccfb026fb56c580b5c7c2e2ee5468049Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(notify_mail_module,
f98cd3b7ccfb026fb56c580b5c7c2e2ee5468049Timo Sirainen &mail_module_register);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(notify_mailbox_list_module,
f98cd3b7ccfb026fb56c580b5c7c2e2ee5468049Timo Sirainen &mailbox_list_module_register);
f98cd3b7ccfb026fb56c580b5c7c2e2ee5468049Timo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic void (*notify_next_hook_mail_storage_created)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen (struct mail_storage *storage);
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic void (*notify_next_hook_mailbox_list_created)
f98cd3b7ccfb026fb56c580b5c7c2e2ee5468049Timo Sirainen (struct mailbox_list *list);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainennotify_mail_expunge(struct mail *_mail)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen union mail_module_context *lmail = NOTIFY_MAIL_CONTEXT(mail);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
cab0827de053c8b58c6528eb430c089576a49ca9Timo Sirainen notify_contexts_mail_expunge(_mail);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen lmail->super.expunge(_mail);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic void
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainennotify_mail_update_flags(struct mail *_mail, enum modify_type modify_type,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen enum mail_flags flags)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen{
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
93a7d1ee4b518b5c85f9721dc6539e4dab6aae00Timo Sirainen union mail_module_context *lmail = NOTIFY_MAIL_CONTEXT(mail);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen enum mail_flags old_flags, new_flags;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
f98cd3b7ccfb026fb56c580b5c7c2e2ee5468049Timo Sirainen old_flags = mail_get_flags(_mail);
f98cd3b7ccfb026fb56c580b5c7c2e2ee5468049Timo Sirainen lmail->super.update_flags(_mail, modify_type, flags);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen new_flags = mail_get_flags(_mail);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen if ((old_flags ^ new_flags) == 0)
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen return;
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen notify_contexts_mail_update_flags(_mail, old_flags);
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen}
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainenstatic void
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainennotify_mail_update_keywords(struct mail *_mail, enum modify_type modify_type,
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen struct mail_keywords *keywords)
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen{
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen struct mail_private *mail = (struct mail_private *)_mail;
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen union mail_module_context *lmail = NOTIFY_MAIL_CONTEXT(mail);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen const char *const *old_keywords, *const *new_keywords;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen unsigned int i;
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen old_keywords = mail_get_keywords(_mail);
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen lmail->super.update_keywords(_mail, modify_type, keywords);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen new_keywords = mail_get_keywords(_mail);
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen for (i = 0; old_keywords[i] != NULL && new_keywords[i] != NULL; i++) {
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen if (strcmp(old_keywords[i], new_keywords[i]) != 0)
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen break;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen }
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (old_keywords[i] == NULL && new_keywords[i] == NULL)
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen return;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen notify_contexts_mail_update_keywords(_mail, old_keywords);
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen}
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainenstatic struct mail *
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainennotify_mail_alloc(struct mailbox_transaction_context *t,
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen enum mail_fetch_field wanted_fields,
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen struct mailbox_header_lookup_ctx *wanted_headers)
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen{
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen union mailbox_module_context *lbox = NOTIFY_CONTEXT(t->box);
55a14bce15b9f44441b5f56616d73651a294d770Timo Sirainen union mail_module_context *lmail;
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen struct mail *_mail;
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen struct mail_private *mail;
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen _mail = lbox->super.mail_alloc(t, wanted_fields, wanted_headers);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen mail = (struct mail_private *)_mail;
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen lmail = p_new(mail->pool, union mail_module_context, 1);
79f416d4000aa4192683207aea58a7b12ce66411Timo Sirainen lmail->super = mail->v;
mail->v.expunge = notify_mail_expunge;
mail->v.update_flags = notify_mail_update_flags;
mail->v.update_keywords = notify_mail_update_keywords;
MODULE_CONTEXT_SET_SELF(mail, notify_mail_module, lmail);
return _mail;
}
static int
notify_copy(struct mail_save_context *ctx, struct mail *mail)
{
struct notify_transaction_context *lt =
NOTIFY_CONTEXT(ctx->transaction);
union mailbox_module_context *lbox =
NOTIFY_CONTEXT(ctx->transaction->box);
int ret;
if (ctx->dest_mail == NULL) {
if (lt->tmp_mail == NULL)
lt->tmp_mail = mail_alloc(ctx->transaction, 0, NULL);
ctx->dest_mail = lt->tmp_mail;
}
if ((ret = lbox->super.copy(ctx, mail)) == 0)
notify_contexts_mail_copy(mail, ctx->dest_mail);
return ret;
}
static int
notify_save_begin(struct mail_save_context *ctx, struct istream *input)
{
struct notify_transaction_context *lt =
NOTIFY_CONTEXT(ctx->transaction);
union mailbox_module_context *lbox =
NOTIFY_CONTEXT(ctx->transaction->box);
if (ctx->dest_mail == NULL) {
if (lt->tmp_mail == NULL)
lt->tmp_mail = mail_alloc(ctx->transaction, 0, NULL);
ctx->dest_mail = lt->tmp_mail;
}
return lbox->super.save_begin(ctx, input);
}
static int
notify_save_finish(struct mail_save_context *ctx)
{
struct notify_transaction_context *lt =
NOTIFY_CONTEXT(ctx->transaction);
union mailbox_module_context *lbox =
NOTIFY_CONTEXT(ctx->transaction->box);
struct mail *dest_mail = ctx->copying ? NULL : ctx->dest_mail;
if (lbox->super.save_finish(ctx) < 0)
return -1;
if (dest_mail != NULL)
notify_contexts_mail_save(dest_mail);
return 0;
}
static struct mailbox_transaction_context *
notify_transaction_begin(struct mailbox *box,
enum mailbox_transaction_flags flags)
{
union mailbox_module_context *lbox = NOTIFY_CONTEXT(box);
struct mailbox_transaction_context *t;
struct notify_transaction_context *lt;
t = lbox->super.transaction_begin(box, flags);
lt = i_new(struct notify_transaction_context, 1);
MODULE_CONTEXT_SET(t, notify_storage_module, lt);
notify_contexts_mail_transaction_begin(t);
return t;
}
static int
notify_transaction_commit(struct mailbox_transaction_context *t,
struct mail_transaction_commit_changes *changes_r)
{
struct notify_transaction_context *lt = NOTIFY_CONTEXT(t);
union mailbox_module_context *lbox = NOTIFY_CONTEXT(t->box);
if (lt->tmp_mail != NULL)
mail_free(&lt->tmp_mail);
i_free(lt);
if ((lbox->super.transaction_commit(t, changes_r)) < 0) {
notify_contexts_mail_transaction_rollback(t);
return -1;
}
notify_contexts_mail_transaction_commit(t, changes_r);
return 0;
}
static void
notify_transaction_rollback(struct mailbox_transaction_context *t)
{
struct notify_transaction_context *lt = NOTIFY_CONTEXT(t);
union mailbox_module_context *lbox = NOTIFY_CONTEXT(t->box);
if (lt->tmp_mail != NULL)
mail_free(&lt->tmp_mail);
i_free(lt);
notify_contexts_mail_transaction_rollback(t);
lbox->super.transaction_rollback(t);
}
static struct mailbox *
notify_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
const char *name, struct istream *input,
enum mailbox_flags flags)
{
union mail_storage_module_context *lstorage = NOTIFY_CONTEXT(storage);
struct mailbox *box;
union mailbox_module_context *lbox;
box = lstorage->super.mailbox_alloc(storage, list, name, input, flags);
lbox = p_new(box->pool, union mailbox_module_context, 1);
lbox->super = box->v;
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;
MODULE_CONTEXT_SET_SELF(box, notify_storage_module, lbox);
return box;
}
static int
notify_mailbox_list_delete(struct mailbox_list *list, const char *name)
{
union mailbox_list_module_context *llist = NOTIFY_LIST_CONTEXT(list);
notify_contexts_mailbox_delete_begin(list, name);
if (llist->super.delete_mailbox(list, name) < 0) {
notify_contexts_mailbox_delete_rollback();
return -1;
}
notify_contexts_mailbox_delete_commit(list, name);
return 0;
}
static int
notify_mailbox_list_rename(struct mailbox_list *oldlist, const char *oldname,
struct mailbox_list *newlist, const char *newname,
bool rename_children)
{
union mailbox_list_module_context *oldllist =
NOTIFY_LIST_CONTEXT(oldlist);
if (oldllist->super.rename_mailbox(oldlist, oldname, newlist, newname,
rename_children) < 0)
return -1;
notify_contexts_mailbox_rename(oldlist, oldname, newlist, newname,
rename_children);
return 0;
}
static void notify_mail_storage_created(struct mail_storage *storage)
{
union mail_storage_module_context *lstorage;
lstorage = p_new(storage->pool, union mail_storage_module_context, 1);
lstorage->super = storage->v;
storage->v.mailbox_alloc = notify_mailbox_alloc;
MODULE_CONTEXT_SET_SELF(storage, notify_storage_module, lstorage);
if (notify_next_hook_mail_storage_created != NULL)
notify_next_hook_mail_storage_created(storage);
}
static void notify_mailbox_list_created(struct mailbox_list *list)
{
union mailbox_list_module_context *llist;
llist = p_new(list->pool, union mailbox_list_module_context, 1);
llist->super = list->v;
list->v.delete_mailbox = notify_mailbox_list_delete;
list->v.rename_mailbox = notify_mailbox_list_rename;
MODULE_CONTEXT_SET_SELF(list, notify_mailbox_list_module, llist);
if (notify_next_hook_mailbox_list_created != NULL)
notify_next_hook_mailbox_list_created(list);
}
void notify_plugin_init_storage(void)
{
notify_next_hook_mail_storage_created = hook_mail_storage_created;
hook_mail_storage_created = notify_mail_storage_created;
notify_next_hook_mailbox_list_created = hook_mailbox_list_created;
hook_mailbox_list_created = notify_mailbox_list_created;
}
void notify_plugin_deinit_storage(void)
{
hook_mail_storage_created = notify_next_hook_mail_storage_created;
hook_mailbox_list_created = notify_next_hook_mailbox_list_created;
}