/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "llist.h"
#include "mail-storage.h"
#include "notify-plugin-private.h"
struct notify_mail_txn {
struct notify_mail_txn *prev, *next;
struct mailbox_transaction_context *parent_mailbox_txn;
struct mail *tmp_mail;
void *txn;
};
struct notify_context {
struct notify_context *prev, *next;
struct notify_vfuncs v;
struct notify_mail_txn *mail_txn_list;
void *mailbox_delete_txn;
};
const char *notify_plugin_version = DOVECOT_ABI_VERSION;
static struct notify_context *ctx_list = NULL;
static struct notify_mail_txn *
notify_context_find_mail_txn(struct notify_context *ctx,
struct mailbox_transaction_context *t)
{
struct notify_mail_txn *mail_txn = ctx->mail_txn_list;
for (; mail_txn != NULL; mail_txn = mail_txn->next) {
if (mail_txn->parent_mailbox_txn == t)
return mail_txn;
}
i_panic("no notify_mail_txn found");
}
void notify_contexts_mail_transaction_begin(struct mailbox_transaction_context *t)
{
struct notify_context *ctx;
struct notify_mail_txn *mail_txn;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
mail_txn = i_new(struct notify_mail_txn, 1);
mail_txn->parent_mailbox_txn = t;
mail_txn->txn = ctx->v.mail_transaction_begin == NULL ? NULL :
ctx->v.mail_transaction_begin(t);
DLLIST_PREPEND(&ctx->mail_txn_list, mail_txn);
}
}
void notify_contexts_mail_save(struct mail *mail)
{
struct notify_context *ctx;
struct notify_mail_txn *mail_txn;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mail_save == NULL)
continue;
mail_txn = notify_context_find_mail_txn(ctx, mail->transaction);
ctx->v.mail_save(mail_txn->txn, mail);
}
}
void notify_contexts_mail_copy(struct mail *src, struct mail *dst)
{
struct notify_context *ctx;
struct notify_mail_txn *mail_txn;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mail_copy == NULL)
continue;
mail_txn = notify_context_find_mail_txn(ctx, dst->transaction);
ctx->v.mail_copy(mail_txn->txn, src, dst);
}
}
void notify_contexts_mail_expunge(struct mail *mail)
{
struct notify_context *ctx;
struct notify_mail_txn *mail_txn;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mail_expunge == NULL)
continue;
mail_txn = notify_context_find_mail_txn(ctx, mail->transaction);
ctx->v.mail_expunge(mail_txn->txn, mail);
}
}
void notify_contexts_mail_update_flags(struct mail *mail,
enum mail_flags old_flags)
{
struct notify_context *ctx;
struct notify_mail_txn *mail_txn;
if (mail->saving)
return;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mail_update_flags == NULL)
continue;
mail_txn = notify_context_find_mail_txn(ctx, mail->transaction);
ctx->v.mail_update_flags(mail_txn->txn, mail, old_flags);
}
}
void notify_contexts_mail_update_keywords(struct mail *mail,
const char *const *old_keywords)
{
struct notify_context *ctx;
struct notify_mail_txn *mail_txn;
if (mail->saving)
return;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mail_update_keywords == NULL)
continue;
mail_txn = notify_context_find_mail_txn(ctx, mail->transaction);
ctx->v.mail_update_keywords(mail_txn->txn, mail, old_keywords);
}
}
void notify_contexts_mail_transaction_commit(struct mailbox_transaction_context *t,
struct mail_transaction_commit_changes *changes)
{
struct notify_context *ctx;
struct notify_mail_txn *mail_txn;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mail_transaction_commit == NULL)
continue;
mail_txn = notify_context_find_mail_txn(ctx, t);
if (ctx->v.mail_transaction_commit != NULL)
ctx->v.mail_transaction_commit(mail_txn->txn, changes);
DLLIST_REMOVE(&ctx->mail_txn_list, mail_txn);
i_free(mail_txn);
}
}
void notify_contexts_mail_transaction_rollback(struct mailbox_transaction_context *t)
{
struct notify_context *ctx;
struct notify_mail_txn *mail_txn;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
mail_txn = notify_context_find_mail_txn(ctx, t);
if (ctx->v.mail_transaction_rollback != NULL)
ctx->v.mail_transaction_rollback(mail_txn->txn);
DLLIST_REMOVE(&ctx->mail_txn_list, mail_txn);
i_free(mail_txn);
}
}
void notify_contexts_mailbox_create(struct mailbox *box)
{
struct notify_context *ctx;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mailbox_create != NULL)
ctx->v.mailbox_create(box);
}
}
void notify_contexts_mailbox_update(struct mailbox *box)
{
struct notify_context *ctx;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mailbox_update != NULL)
ctx->v.mailbox_update(box);
}
}
void notify_contexts_mailbox_delete_begin(struct mailbox *box)
{
struct notify_context *ctx;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
ctx->mailbox_delete_txn =
ctx->v.mailbox_delete_begin == NULL ? NULL :
ctx->v.mailbox_delete_begin(box);
}
}
void notify_contexts_mailbox_delete_commit(struct mailbox *box)
{
struct notify_context *ctx;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mailbox_delete_commit != NULL) {
ctx->v.mailbox_delete_commit(ctx->mailbox_delete_txn,
box);
}
ctx->mailbox_delete_txn = NULL;
}
}
void notify_contexts_mailbox_delete_rollback(void)
{
struct notify_context *ctx;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mailbox_delete_rollback != NULL)
ctx->v.mailbox_delete_rollback(ctx->mailbox_delete_txn);
ctx->mailbox_delete_txn = NULL;
}
}
void notify_contexts_mailbox_rename(struct mailbox *src, struct mailbox *dest)
{
struct notify_context *ctx;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mailbox_rename != NULL)
ctx->v.mailbox_rename(src, dest);
}
}
void notify_contexts_mailbox_set_subscribed(struct mailbox *box,
bool subscribed)
{
struct notify_context *ctx;
for (ctx = ctx_list; ctx != NULL; ctx = ctx->next) {
if (ctx->v.mailbox_set_subscribed != NULL)
ctx->v.mailbox_set_subscribed(box, subscribed);
}
}
struct notify_context *
notify_register(const struct notify_vfuncs *v)
{
struct notify_context *ctx;
ctx = i_new(struct notify_context, 1);
ctx->v = *v;
DLLIST_PREPEND(&ctx_list, ctx);
return ctx;
}
void notify_unregister(struct notify_context *ctx)
{
struct notify_mail_txn *mail_txn = ctx->mail_txn_list;
for (; mail_txn != NULL; mail_txn = mail_txn->next) {
if (ctx->v.mail_transaction_rollback != NULL)
ctx->v.mail_transaction_rollback(mail_txn->txn);
}
if (ctx->mailbox_delete_txn != NULL &&
ctx->v.mailbox_delete_rollback != NULL)
ctx->v.mailbox_delete_rollback(ctx->mailbox_delete_txn);
DLLIST_REMOVE(&ctx_list, ctx);
i_free(ctx);
}
void notify_plugin_init(struct module *module)
{
notify_plugin_init_storage(module);
}
void notify_plugin_deinit(void)
{
notify_plugin_deinit_storage();
}