summaryrefslogtreecommitdiffstats
path: root/src/plugins/notify/notify-plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/notify/notify-plugin.c')
-rw-r--r--src/plugins/notify/notify-plugin.c265
1 files changed, 265 insertions, 0 deletions
diff --git a/src/plugins/notify/notify-plugin.c b/src/plugins/notify/notify-plugin.c
new file mode 100644
index 0000000..e9ff9bb
--- /dev/null
+++ b/src/plugins/notify/notify-plugin.c
@@ -0,0 +1,265 @@
+/* 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) {
+ 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();
+}