summaryrefslogtreecommitdiffstats
path: root/src/plugins/push-notification/push-notification-driver-lua.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/push-notification/push-notification-driver-lua.c')
-rw-r--r--src/plugins/push-notification/push-notification-driver-lua.c663
1 files changed, 663 insertions, 0 deletions
diff --git a/src/plugins/push-notification/push-notification-driver-lua.c b/src/plugins/push-notification/push-notification-driver-lua.c
new file mode 100644
index 0000000..e1178fa
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-driver-lua.c
@@ -0,0 +1,663 @@
+/* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "ioloop.h"
+#include "str.h"
+#include "hash.h"
+#include "dlua-script.h"
+#include "dlua-script-private.h"
+
+#include "mail-storage.h"
+#include "mail-user.h"
+#include "mail-lua-plugin.h"
+#include "mail-storage-lua.h"
+
+#include "push-notification-plugin.h"
+#include "push-notification-drivers.h"
+#include "push-notification-events.h"
+#include "push-notification-event-message-common.h"
+#include "push-notification-txn-mbox.h"
+#include "push-notification-txn-msg.h"
+
+#include "push-notification-event-flagsclear.h"
+#include "push-notification-event-flagsset.h"
+#include "push-notification-event-mailboxcreate.h"
+#include "push-notification-event-mailboxdelete.h"
+#include "push-notification-event-mailboxrename.h"
+#include "push-notification-event-mailboxsubscribe.h"
+#include "push-notification-event-mailboxunsubscribe.h"
+#include "push-notification-event-messageappend.h"
+#include "push-notification-event-message-common.h"
+#include "push-notification-event-messageexpunge.h"
+#include "push-notification-event-messagenew.h"
+#include "push-notification-event-messageread.h"
+#include "push-notification-event-messagetrash.h"
+
+#define DLUA_LOG_USERENV_KEY "push_notification_lua_script_file"
+
+#define DLUA_FN_BEGIN_TXN "dovecot_lua_notify_begin_txn"
+#define DLUA_FN_EVENT_PREFIX "dovecot_lua_notify_event"
+#define DLUA_FN_END_TXN "dovecot_lua_notify_end_txn"
+
+#define DLUA_CALL_FINISHED "push_notification_lua_call_finished"
+
+struct dlua_push_notification_context {
+ struct dlua_script *script;
+ struct event *event;
+ bool debug;
+
+ struct push_notification_event_messagenew_config config_mn;
+ struct push_notification_event_messageappend_config config_ma;
+ struct push_notification_event_flagsclear_config config_fc;
+ struct push_notification_event_flagsset_config config_fs;
+};
+
+struct dlua_push_notification_txn_context {
+ int tx_ref;
+};
+
+#define DLUA_DEFAULT_EVENTS (\
+ PUSH_NOTIFICATION_MESSAGE_HDR_FROM | \
+ PUSH_NOTIFICATION_MESSAGE_HDR_TO | \
+ PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT | \
+ PUSH_NOTIFICATION_MESSAGE_HDR_DATE | \
+ PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET | \
+ PUSH_NOTIFICATION_MESSAGE_FLAGS | \
+ PUSH_NOTIFICATION_MESSAGE_KEYWORDS | \
+ PUSH_NOTIFICATION_MESSAGE_HDR_MESSAGE_ID)
+
+static const char *push_notification_driver_lua_to_fn(const char *evname);
+
+static int
+push_notification_driver_lua_init(
+ struct push_notification_driver_config *config, struct mail_user *user,
+ pool_t pool, void **context, const char **error_r)
+{
+ struct dlua_push_notification_context *ctx;
+ const char *tmp, *file;
+ struct event *event = event_create(user->event);
+ event_add_category(event, push_notification_get_event_category());
+ event_set_append_log_prefix(event, "lua: ");
+
+ if ((tmp = mail_user_plugin_getenv(user, DLUA_LOG_USERENV_KEY)) == NULL)
+ tmp = hash_table_lookup(config->config, (const char *)"file");
+
+ if (tmp == NULL) {
+ struct dlua_script *script;
+ /* If there is a script loaded, use the same context */
+ if (mail_lua_plugin_get_script(user, &script)) {
+ dlua_script_ref(script);
+ ctx = p_new(
+ pool, struct dlua_push_notification_context, 1);
+ ctx->script = script;
+ ctx->event = event;
+ *context = ctx;
+ return 0;
+ }
+
+ event_unref(&event);
+ *error_r = "No file in config and no "
+ DLUA_LOG_USERENV_KEY " set";
+ return -1;
+ }
+ file = tmp;
+
+ ctx = p_new(pool, struct dlua_push_notification_context, 1);
+ ctx->event = event;
+
+ e_debug(ctx->event, "Loading %s", file);
+
+ if (dlua_script_create_file(file, &ctx->script, event, error_r) < 0) {
+ /* There is a T_POP after this, which will break errors */
+ event_unref(&event);
+ *error_r = p_strdup(pool, *error_r);
+ return -1;
+ }
+
+ /* Register dovecot helpers */
+ dlua_dovecot_register(ctx->script);
+ dlua_register_mail_storage(ctx->script);
+
+ e_debug(ctx->event, "Calling script_init");
+
+ /* Initialize script */
+ if (dlua_script_init(ctx->script, error_r) < 0) {
+ *error_r = p_strdup(pool, *error_r);
+ event_unref(&event);
+ dlua_script_unref(&ctx->script);
+ return -1;
+ }
+
+ *context = ctx;
+ return 0;
+}
+
+static bool
+push_notification_driver_lua_init_events(
+ struct push_notification_driver_txn *dtxn)
+{
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ const struct push_notification_event *event;
+ ctx->config_mn.flags = DLUA_DEFAULT_EVENTS;
+ ctx->config_ma.flags = DLUA_DEFAULT_EVENTS;
+ ctx->config_fc.store_old = TRUE;
+ bool found_one = FALSE;
+
+ /* Register *all* events that are present in Lua */
+ array_foreach_elem(push_notification_get_events(), event) {
+ const char *name = event->name;
+ const char *fn = push_notification_driver_lua_to_fn(name);
+ if (!dlua_script_has_function(ctx->script, fn))
+ continue;
+
+ found_one = TRUE;
+
+ e_debug(ctx->event, "Found %s, handling %s event", fn, name);
+
+ if (strcmp(name, "MessageNew") == 0) {
+ push_notification_event_init(dtxn, name,
+ &ctx->config_mn);
+ } else if (strcmp(name, "MessageAppend") == 0) {
+ push_notification_event_init(dtxn, name,
+ &ctx->config_ma);
+ } else if (strcmp(name, "FlagsSet") == 0) {
+ push_notification_event_init(dtxn, name,
+ &ctx->config_fs);
+ } else if (strcmp(name, "FlagsClear") == 0) {
+ push_notification_event_init(dtxn, name,
+ &ctx->config_fc);
+ } else if (event->init.default_config != NULL) {
+ void *config = event->init.default_config();
+ push_notification_event_init(dtxn, name, config);
+ } else {
+ push_notification_event_init(dtxn, name, NULL);
+ }
+ }
+
+ return found_one;
+}
+
+static bool
+push_notification_driver_lua_begin_txn(
+ struct push_notification_driver_txn *dtxn)
+{
+ struct mail_user *user = dtxn->ptxn->muser;
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ struct event *event = event_create(ctx->event);
+ const char *error;
+
+ event_set_name(event, DLUA_CALL_FINISHED);
+ event_add_str(event, "function_name", DLUA_FN_BEGIN_TXN);
+
+ if (!dlua_script_has_function(ctx->script, DLUA_FN_BEGIN_TXN)) {
+ event_add_str(event, "error",
+ "Missing function " DLUA_FN_BEGIN_TXN);
+ e_error(event, "Missing function " DLUA_FN_BEGIN_TXN);
+ event_unref(&event);
+ return FALSE;
+ }
+
+ if (!push_notification_driver_lua_init_events(dtxn)) {
+ e_debug(event, "No event handlers found in script");
+ event_unref(&event);
+ return FALSE;
+ }
+
+ e_debug(ctx->event, "Calling " DLUA_FN_BEGIN_TXN "(%s)",
+ user->username);
+
+ /* Push mail user as argument */
+ dlua_push_mail_user(ctx->script->L, user);
+ if (dlua_pcall(ctx->script->L, DLUA_FN_BEGIN_TXN, 1, 1, &error) < 0) {
+ event_add_str(event, "error", error);
+ e_error(event, "%s", error);
+ return FALSE;
+ }
+
+ e_debug(event, "Called " DLUA_FN_BEGIN_TXN);
+ event_unref(&event);
+
+ /* Store the result */
+ struct dlua_push_notification_txn_context *tctx =
+ p_new(dtxn->ptxn->pool,
+ struct dlua_push_notification_txn_context, 1);
+
+ tctx->tx_ref = luaL_ref(ctx->script->L, LUA_REGISTRYINDEX);
+ dtxn->context = tctx;
+ mail_user_ref(user);
+
+ return TRUE;
+}
+
+/* This function only works here, it converts MessageType to event_message_type
+ */
+static const char *push_notification_driver_lua_to_fn(const char *evname)
+{
+ /* Camelcase to event_event_name (most events have two underscores) */
+ string_t *fn = t_str_new(strlen(evname) +
+ strlen(DLUA_FN_EVENT_PREFIX) + 2);
+ str_append(fn, DLUA_FN_EVENT_PREFIX);
+
+ for(; *evname != '\0'; evname++) {
+ if (*evname >= 'A' && *evname <= 'Z') {
+ str_append_c(fn, '_');
+ str_append_c(fn, (*evname) - 'A' + 'a');
+ } else {
+ str_append_c(fn, *evname);
+ }
+ }
+
+ return str_c(fn);
+}
+
+/* Pushes lua list of flags */
+static void dlua_push_flags(struct dlua_script *script, enum mail_flags flags)
+{
+ lua_newtable(script->L);
+ int idx = 1;
+
+ if ((flags & MAIL_ANSWERED) != 0) {
+ lua_pushliteral(script->L, "\\Answered");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_FLAGGED) != 0) {
+ lua_pushliteral(script->L, "\\Flagged");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_DELETED) != 0) {
+ lua_pushliteral(script->L, "\\Deleted");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_SEEN) != 0) {
+ lua_pushliteral(script->L, "\\Seen");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_DRAFT) != 0) {
+ lua_pushliteral(script->L, "\\Draft");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_RECENT) != 0) {
+ lua_pushliteral(script->L, "\\Recent");
+ lua_rawseti(script->L, -2, idx++);
+ }
+}
+
+static void
+dlua_push_keywords(struct dlua_script *script, const char *const *keywords,
+ unsigned int count)
+{
+ lua_newtable(script->L);
+ if (keywords == NULL)
+ return;
+ for (unsigned int idx = 0; idx < count; idx++) {
+ lua_pushstring(script->L, keywords[idx]);
+ lua_rawseti(script->L, -2, idx+1);
+ }
+}
+
+static void
+push_notification_lua_push_flagsclear(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ /* Push cleared flags */
+ unsigned int size = 0;
+ struct push_notification_event_flagsclear_data *data = event->data;
+
+ dlua_push_flags(script, data->flags_clear);
+ lua_setfield(script->L, -2, "flags");
+ dlua_push_flags(script, data->flags_old);
+ lua_setfield(script->L, -2, "flags_old");
+
+ if (array_is_created(&data->keywords_clear)) {
+ const char *const *kw = array_get(&data->keywords_clear, &size);
+ dlua_push_keywords(script, kw, size);
+ lua_setfield(script->L, -2, "keywords");
+ }
+
+ if (array_is_created(&data->keywords_old)) {
+ const char *const *kw = array_get(&data->keywords_old, &size);
+ dlua_push_keywords(script, kw, size);
+ lua_setfield(script->L, -2, "keywords_old");
+ }
+}
+
+static void
+push_notification_lua_push_flagsset(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ /* push set flags */
+ unsigned int size = 0;
+ struct push_notification_event_flagsset_data *data = event->data;
+
+ dlua_push_flags(script, data->flags_set);
+ lua_setfield(script->L, -2, "flags");
+
+ if (array_is_created(&data->keywords_set)) {
+ const char *const *kw = array_get(&data->keywords_set, &size);
+ dlua_push_keywords(script, kw, size);
+ lua_setfield(script->L, -2, "keywords");
+ }
+}
+
+static void
+push_notification_lua_push_mailboxrename(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ struct push_notification_event_mailboxrename_data *data = event->data;
+
+ lua_pushstring(script->L, data->old_mbox);
+ lua_setfield(script->L, -2, "mailbox_old");
+}
+
+#define push_notification_lua_push_string(L, value) \
+ lua_pushstring((L), (value) == NULL ? "" : (value))
+
+static void
+push_notification_lua_push_message_ext(
+ const struct push_notification_message_ext *ext,
+ struct dlua_script *script)
+{
+ push_notification_lua_push_string(script->L, ext->from_address);
+ lua_setfield(script->L, -2, "from_address");
+ push_notification_lua_push_string(script->L, ext->from_display_name_utf8);
+ lua_setfield(script->L, -2, "from_display_name");
+
+ push_notification_lua_push_string(script->L, ext->to_address);
+ lua_setfield(script->L, -2, "to_address");
+ push_notification_lua_push_string(script->L, ext->to_display_name_utf8);
+ lua_setfield(script->L, -2, "to_display_name");
+
+ lua_pushstring(script->L, ext->subject_utf8);
+ lua_setfield(script->L, -2, "subject");
+}
+
+static void
+push_notification_lua_push_messageappend(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ struct push_notification_event_messageappend_data *data = event->data;
+
+ lua_pushnumber(script->L, data->date);
+ lua_setfield(script->L, -2, "date");
+
+ lua_pushnumber(script->L, data->date_tz);
+ lua_setfield(script->L, -2, "tz");
+
+ push_notification_lua_push_string(script->L, data->from);
+ lua_setfield(script->L, -2, "from");
+
+ push_notification_lua_push_string(script->L, data->to);
+ lua_setfield(script->L, -2, "to");
+
+ lua_pushstring(script->L, data->snippet);
+ lua_setfield(script->L, -2, "snippet");
+
+ dlua_push_flags(script, data->flags);
+ lua_setfield(script->L, -2, "flags");
+
+ dlua_push_keywords(script, data->keywords,
+ str_array_length(data->keywords));
+ lua_setfield(script->L, -2, "keywords");
+
+ lua_pushstring(script->L, data->message_id);
+ lua_setfield(script->L, -2, "message_id");
+
+ push_notification_lua_push_message_ext(&data->ext, script);
+}
+
+static void
+push_notification_lua_push_messagenew(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ struct push_notification_event_messagenew_data *data = event->data;
+
+ lua_pushnumber(script->L, data->date);
+ lua_setfield(script->L, -2, "date");
+
+ lua_pushnumber(script->L, data->date_tz);
+ lua_setfield(script->L, -2, "tz");
+
+ push_notification_lua_push_string(script->L, data->from);
+ lua_setfield(script->L, -2, "from");
+
+ push_notification_lua_push_string(script->L, data->to);
+ lua_setfield(script->L, -2, "to");
+
+ lua_pushstring(script->L, data->snippet);
+ lua_setfield(script->L, -2, "snippet");
+
+ dlua_push_flags(script, data->flags);
+ lua_setfield(script->L, -2, "flags");
+
+ dlua_push_keywords(script, data->keywords,
+ str_array_length(data->keywords));
+ lua_setfield(script->L, -2, "keywords");
+
+ lua_pushstring(script->L, data->message_id);
+ lua_setfield(script->L, -2, "message_id");
+
+ push_notification_lua_push_message_ext(&data->ext, script);
+}
+
+/* Events that need special treatment */
+static struct push_notification_event_to_lua {
+ const char *event_name;
+ void (*push)(const struct push_notification_txn_event *event,
+ struct dlua_script *script);
+} event_to_push_table[] = {
+ {
+ .event_name = "FlagsClear",
+ .push = push_notification_lua_push_flagsclear
+ },
+ {
+ .event_name = "FlagsSet",
+ .push = push_notification_lua_push_flagsset
+ },
+ {
+ .event_name = "MailboxRename",
+ .push = push_notification_lua_push_mailboxrename
+ },
+ {
+ .event_name = "MessageAppend",
+ .push = push_notification_lua_push_messageappend
+ },
+ {
+ .event_name = "MessageNew",
+ .push = push_notification_lua_push_messagenew
+ },
+};
+
+static void
+push_notification_driver_lua_push_event(
+ const struct push_notification_txn_event *event,
+ struct dlua_push_notification_context *ctx)
+{
+ struct dlua_script *script = ctx->script;
+ const char *name = event->event->event->name;
+
+ /* Create a table */
+ lua_newtable(script->L);
+
+ /* Event name */
+ lua_pushstring(script->L, name);
+ lua_setfield(script->L, -2, "name");
+
+ for(size_t i = 0; i < N_ELEMENTS(event_to_push_table); i++)
+ if (strcmp(event_to_push_table[i].event_name, name) == 0)
+ event_to_push_table[i].push(event, script);
+}
+
+static void
+push_notification_driver_lua_call(
+ struct dlua_push_notification_context *ctx,
+ struct dlua_push_notification_txn_context *tctx,
+ const struct push_notification_txn_event *event,
+ const struct push_notification_txn_mbox *mbox,
+ struct push_notification_txn_msg *msg)
+{
+ const char *error;
+ const char *fn =
+ push_notification_driver_lua_to_fn(event->event->event->name);
+ struct event *e = event_create(ctx->event);
+ event_set_name(e, DLUA_CALL_FINISHED);
+ event_add_str(e, "event_name", event->event->event->name);
+ event_add_str(e, "function_name", fn);
+
+ /* Push context */
+ lua_rawgeti(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
+
+ /* Push event + common fields */
+ push_notification_driver_lua_push_event(event, ctx);
+
+ if (mbox != NULL) {
+ lua_pushstring(ctx->script->L, mbox->mailbox);
+ lua_setfield(ctx->script->L, -2, "mailbox");
+ e_debug(ctx->event,
+ "Calling %s(ctx, event[name=%s,mailbox=%s])",
+ fn, event->event->event->name, mbox->mailbox);
+ event_add_str(e, "mailbox", mbox->mailbox);
+ } else if (msg != NULL) {
+ lua_pushstring(ctx->script->L, msg->mailbox);
+ lua_setfield(ctx->script->L, -2, "mailbox");
+ lua_pushnumber(ctx->script->L, msg->uid);
+ lua_setfield(ctx->script->L, -2, "uid");
+ lua_pushnumber(ctx->script->L, msg->uid_validity);
+ lua_setfield(ctx->script->L, -2, "uid_validity");
+ e_debug(ctx->event,
+ "Calling %s(ctx, event[name=%s,mailbox=%s,uid=%u])",
+ fn, event->event->event->name, msg->mailbox, msg->uid);
+ event_add_str(e, "mailbox", msg->mailbox);
+ event_add_int(e, "uid", msg->uid);
+ } else
+ i_unreached();
+
+ /* Perform call */
+ if (dlua_pcall(ctx->script->L, fn, 2, 0, &error) < 0) {
+ event_add_str(e, "error", error);
+ e_error(e, "%s", error);
+ } else {
+ e_debug(e, "Called %s", fn);
+ }
+ event_unref(&e);
+}
+
+static void
+push_notification_driver_lua_process_mbox(
+ struct push_notification_driver_txn *dtxn,
+ struct push_notification_txn_mbox *mbox)
+{
+ struct push_notification_txn_event *event;
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ struct dlua_push_notification_txn_context *tctx = dtxn->context;
+
+ if (array_is_created(&mbox->eventdata)) {
+ array_foreach_elem(&mbox->eventdata, event) {
+ push_notification_driver_lua_call(ctx, tctx,
+ event, mbox, NULL);
+ }
+ }
+}
+
+static void
+push_notification_driver_lua_process_msg(
+ struct push_notification_driver_txn *dtxn,
+ struct push_notification_txn_msg *msg)
+{
+ struct push_notification_txn_event *event;
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ struct dlua_push_notification_txn_context *tctx = dtxn->context;
+
+ if (array_is_created(&msg->eventdata)) {
+ array_foreach_elem(&msg->eventdata, event) {
+ push_notification_driver_lua_call(ctx, tctx,
+ event, NULL, msg);
+ }
+ }
+}
+
+static void
+push_notification_driver_lua_end_txn(struct push_notification_driver_txn *dtxn,
+ bool success)
+{
+ /* Call end txn */
+ const char *error;
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ struct dlua_push_notification_txn_context *tctx = dtxn->context;
+ struct mail_user *user = dtxn->ptxn->muser;
+ struct event *event = event_create(ctx->event);
+ event_set_name(event, DLUA_CALL_FINISHED);
+ event_add_str(event, "function_name", DLUA_FN_END_TXN);
+
+ if (!dlua_script_has_function(ctx->script, DLUA_FN_END_TXN)) {
+ e_error(event, "Missing function " DLUA_FN_END_TXN);
+ } else {
+ e_debug(ctx->event, "Calling " DLUA_FN_END_TXN);
+ lua_rawgeti(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
+ lua_pushboolean(ctx->script->L, success);
+ if (dlua_pcall(ctx->script->L, DLUA_FN_END_TXN, 2, 0, &error) < 0) {
+ event_add_str(event, "error", error);
+ e_error(event, "%s", error);
+ } else {
+ e_debug(event, "Called " DLUA_FN_END_TXN);
+ }
+ }
+
+ event_unref(&event);
+ /* Release context */
+ luaL_unref(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
+ /* Call gc here */
+ (void)lua_gc(ctx->script->L, LUA_GCCOLLECT, 1);
+ mail_user_unref(&user);
+}
+
+static void
+push_notification_driver_lua_deinit(struct push_notification_driver_user *duser)
+{
+ /* Call lua deinit */
+ struct dlua_push_notification_context *ctx = duser->context;
+ dlua_script_unref(&ctx->script);
+ event_unref(&ctx->event);
+}
+
+static void push_notification_driver_lua_cleanup(void)
+{
+ /* noop */
+}
+
+/* Driver definition */
+
+struct push_notification_driver push_notification_driver_lua = {
+ .name = "lua",
+ .v = {
+ .init = push_notification_driver_lua_init,
+ .begin_txn = push_notification_driver_lua_begin_txn,
+ .process_mbox = push_notification_driver_lua_process_mbox,
+ .process_msg = push_notification_driver_lua_process_msg,
+ .end_txn = push_notification_driver_lua_end_txn,
+ .deinit = push_notification_driver_lua_deinit,
+ .cleanup = push_notification_driver_lua_cleanup,
+ },
+};
+
+void push_notification_lua_plugin_init(struct module *module);
+void push_notification_lua_plugin_deinit(void);
+
+void push_notification_lua_plugin_init(struct module *module ATTR_UNUSED)
+{
+ push_notification_driver_register(&push_notification_driver_lua);
+}
+
+void push_notification_lua_plugin_deinit(void)
+{
+ push_notification_driver_unregister(&push_notification_driver_lua);
+}
+
+const char *push_notification_lua_plugin_version = DOVECOT_ABI_VERSION;
+const char *push_notification_lua_plugin_dependencies[] =
+ { "push_notification", "mail_lua", NULL};