Mercurial > dovecot > core-2.2
changeset 19189:1afdeb1cae62
Added push-notification plugin
line wrap: on
line diff
--- a/configure.ac Tue Sep 22 21:16:51 2015 +0300 +++ b/configure.ac Tue Sep 22 22:33:41 2015 -0600 @@ -2929,6 +2929,7 @@ src/plugins/mail-log/Makefile src/plugins/mailbox-alias/Makefile src/plugins/notify/Makefile +src/plugins/push-notification/Makefile src/plugins/pop3-migration/Makefile src/plugins/quota/Makefile src/plugins/quota-clone/Makefile
--- a/dovecot-config.in.in Tue Sep 22 21:16:51 2015 +0300 +++ b/dovecot-config.in.in Tue Sep 22 22:33:41 2015 -0600 @@ -31,6 +31,7 @@ LIBDOVECOT_IMAPC_INCLUDE="-I$(incdir)/src/lib-imap-client -I$(incdir)/src/lib-storage/index/imapc" LIBDOVECOT_FTS_INCLUDE="-I$(incdir)/src/plugins/fts" LIBDOVECOT_NOTIFY_INCLUDE="-I$(incdir)/src/plugins/notify" +LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE="-I$(incdir)/src/plugins/push-notification" LIBDOVECOT_ACL_INCLUDE="-I$(incdir)/src/plugins/acl" dovecot_pkgincludedir=
--- a/src/plugins/Makefile.am Tue Sep 22 21:16:51 2015 +0300 +++ b/src/plugins/Makefile.am Tue Sep 22 22:33:41 2015 -0600 @@ -21,6 +21,7 @@ lazy-expunge \ listescape \ notify \ + push-notification \ mail-filter \ mail-log \ mailbox-alias \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/Makefile.am Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,60 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib-http \ + -I$(top_srcdir)/src/lib-index \ + -I$(top_srcdir)/src/lib-mail \ + -I$(top_srcdir)/src/lib-storage \ + -I$(top_srcdir)/src/plugins/notify + +NOPLUGIN_LDFLAGS = +lib20_push_notification_plugin_la_LDFLAGS = -module -avoid-version + +module_LTLIBRARIES = lib20_push_notification_plugin.la + +lib20_push_notification_plugin_la_SOURCES = \ + push-notification-driver-dlog.c \ + push-notification-driver-ox.c \ + push-notification-drivers.c \ + push-notification-event-flagsclear.c \ + push-notification-event-flagsset.c \ + push-notification-event-mailboxcreate.c \ + push-notification-event-mailboxdelete.c \ + push-notification-event-mailboxrename.c \ + push-notification-event-mailboxsubscribe.c \ + push-notification-event-mailboxunsubscribe.c \ + push-notification-event-messageappend.c \ + push-notification-event-messageexpunge.c \ + push-notification-event-messagenew.c \ + push-notification-event-messageread.c \ + push-notification-event-messagetrash.c \ + push-notification-events.c \ + push-notification-events-rfc5423.c \ + push-notification-plugin.c \ + push-notification-triggers.c \ + push-notification-txn-mbox.c \ + push-notification-txn-msg.c + +headers = \ + push-notification-drivers.h \ + push-notification-event-flagsclear.h \ + push-notification-event-flagsset.h \ + push-notification-event-mailboxcreate.h \ + push-notification-event-mailboxdelete.h \ + push-notification-event-mailboxrename.h \ + push-notification-event-mailboxsubscribe.h \ + push-notification-event-mailboxunsubscribe.h \ + push-notification-event-message-common.h \ + push-notification-event-messageappend.h \ + push-notification-event-messageexpunge.h \ + push-notification-event-messagenew.h \ + push-notification-event-messageread.h \ + push-notification-event-messagetrash.h \ + push-notification-events.h \ + push-notification-events-rfc5423.h \ + push-notification-plugin.h \ + push-notification-triggers.h \ + push-notification-txn-mbox.h \ + push-notification-txn-msg.h + +pkginc_libdir = $(pkgincludedir) +pkginc_lib_HEADERS = $(headers)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-driver-dlog.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,116 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-txn-mbox.h" +#include "push-notification-txn-msg.h" + + +static int +push_notification_driver_dlog_init(struct push_notification_driver_config *config, + struct mail_user *user ATTR_UNUSED, + pool_t pool ATTR_UNUSED, + void **context ATTR_UNUSED, + const char **error_r ATTR_UNUSED) +{ + i_debug("Called init push_notification plugin hook."); + + if (config->raw_config != NULL) { + i_debug("Config string for dlog push_notification driver: %s", + config->raw_config); + } + + return 0; +} + +static bool push_notification_driver_dlog_begin_txn +(struct push_notification_driver_txn *dtxn) +{ + const struct push_notification_event *const *event; + + i_debug("Called begin_txn push_notification plugin hook."); + + array_foreach(&push_notification_events, event) { + push_notification_event_init(dtxn, (*event)->name, NULL); + } + + return TRUE; +} + +static void push_notification_driver_dlog_process_mbox +(struct push_notification_driver_txn *dtxn ATTR_UNUSED, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_txn_event *const *event; + + i_debug("Called process_mbox push_notification plugin hook."); + + i_debug("Mailbox data: Mailbox [%s]", mbox->mailbox); + + if (array_is_created(&mbox->eventdata)) { + array_foreach(&mbox->eventdata, event) { + if ((*event)->event->event->mbox.debug_mbox != NULL) { + (*event)->event->event->mbox.debug_mbox(*event); + } + } + } +} + +static void push_notification_driver_dlog_process_msg +(struct push_notification_driver_txn *dtxn ATTR_UNUSED, + struct push_notification_txn_msg *msg) +{ + struct push_notification_txn_event *const *event; + + i_debug("Called process_msg push_notification plugin hook."); + + i_debug("Message data: Mailbox [%s], UID [%u], UIDVALIDITY [%u]", + msg->mailbox, msg->uid, msg->uid_validity); + + if (array_is_created(&msg->eventdata)) { + array_foreach(&msg->eventdata, event) { + if ((*event)->event->event->msg.debug_msg != NULL) { + (*event)->event->event->msg.debug_msg(*event); + } + } + } +} + +static void push_notification_driver_dlog_end_txn +(struct push_notification_driver_txn *dtxn ATTR_UNUSED, + bool success ATTR_UNUSED) +{ + i_debug("Called end_txn push_notification plugin hook."); +} + +static void push_notification_driver_dlog_deinit +(struct push_notification_driver_user *duser ATTR_UNUSED) +{ + i_debug("Called deinit push_notification plugin hook."); +} + +static void push_notification_driver_dlog_cleanup(void) +{ + i_debug("Called cleanup push_notification plugin hook."); +} + + +/* Driver definition */ + +extern struct push_notification_driver push_notification_driver_dlog; + +struct push_notification_driver push_notification_driver_dlog = { + .name = "dlog", + .v = { + .init = push_notification_driver_dlog_init, + .begin_txn = push_notification_driver_dlog_begin_txn, + .process_mbox = push_notification_driver_dlog_process_mbox, + .process_msg = push_notification_driver_dlog_process_msg, + .end_txn = push_notification_driver_dlog_end_txn, + .deinit = push_notification_driver_dlog_deinit, + .cleanup = push_notification_driver_dlog_cleanup + } +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-driver-ox.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,341 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hash.h" +#include "http-client.h" +#include "http-url.h" +#include "ioloop.h" +#include "istream.h" +#include "json-parser.h" +#include "mailbox-attribute.h" +#include "mail-storage-private.h" +#include "str.h" + +#include "push-notification-drivers.h" +#include "push-notification-event-messagenew.h" +#include "push-notification-events.h" +#include "push-notification-txn-msg.h" + + +#define OX_LOG_LABEL "OX Push Notification: " + +#define OX_METADATA_KEY \ + MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER "vendor/vendor.dovecot/http-notify" + +/* Default values. */ +static const char *const default_events[] = { "MessageNew", NULL }; +static const char *const default_mboxes[] = { "INBOX", NULL }; + + +/* This is data that is shared by all plugin users. */ +struct push_notification_driver_ox_global { + struct http_client *http_client; + int refcount; +}; +static struct push_notification_driver_ox_global *ox_global = NULL; + +/* This is data specific to an OX driver. */ +struct push_notification_driver_ox_config { + struct http_url *http_url; +}; + +/* This is data specific to an OX driver transaction. */ +struct push_notification_driver_ox_txn { + const char *user; +}; + +static void +push_notification_driver_ox_init_global(struct mail_user *user) +{ + struct http_client_settings http_set; + + if (ox_global->http_client == NULL) { + memset(&http_set, 0, sizeof(http_set)); + http_set.debug = user->mail_debug; + + ox_global->http_client = http_client_init(&http_set); + } +} + +static int +push_notification_driver_ox_init(struct push_notification_driver_config *config, + struct mail_user *user, pool_t pool, + void **context, const char **error_r) +{ + struct push_notification_driver_ox_config *dconfig; + const char *error, *url; + + /* Valid config keys: url */ + url = hash_table_lookup(config->config, (const char *)"url"); + if (url == NULL) { + *error_r = OX_LOG_LABEL "Driver requires the url parameter"; + return -1; + } + + dconfig = p_new(pool, struct push_notification_driver_ox_config, 1); + + if (http_url_parse(url, NULL, HTTP_URL_ALLOW_USERINFO_PART, pool, + &dconfig->http_url, &error) < 0) { + *error_r = t_strdup_printf(OX_LOG_LABEL "Failed to parse OX REST URL %s: %s", + url, error); + return -1; + } + + push_notification_driver_debug(OX_LOG_LABEL, user, "Using URL %s", url); + + if (ox_global == NULL) { + ox_global = i_new(struct push_notification_driver_ox_global, 1); + ox_global->refcount = 0; + } + + ++ox_global->refcount; + *context = dconfig; + + return 0; +} + +static const char *push_notification_driver_ox_get_metadata +(struct push_notification_driver_txn *dtxn) +{ + struct mail_attribute_value attr; + struct mailbox *inbox; + struct mailbox_transaction_context *mctx = NULL; + struct mail_namespace *ns; + bool success = FALSE; + int ret; + + /* Get canonical INBOX, where private server-level metadata is stored. + * See imap/cmd-getmetadata.c */ + ns = mail_namespace_find_inbox(dtxn->ptxn->muser->namespaces); + inbox = mailbox_alloc(ns->list, "INBOX", MAILBOX_FLAG_READONLY); + if (mailbox_open(inbox) < 0) { + i_error(OX_LOG_LABEL "Skipped because unable to open INBOX: %s", + mailbox_get_last_error(inbox, NULL)); + } else { + mctx = mailbox_transaction_begin(inbox, 0); + } + + if (mctx != NULL) { + ret = mailbox_attribute_get(mctx, MAIL_ATTRIBUTE_TYPE_PRIVATE, + OX_METADATA_KEY, &attr); + if (ret < 0) { + i_error(OX_LOG_LABEL "Skipped because unable to get attribute: %s", + mailbox_get_last_error(inbox, NULL)); + } else if (ret == 0) { + push_notification_driver_debug(OX_LOG_LABEL, dtxn->ptxn->muser, + "Skipped because not active (/private/"OX_METADATA_KEY" METADATA not set)"); + } else { + success = TRUE; + } + + mailbox_transaction_commit(&mctx); + } + + mailbox_free(&inbox); + + return (success == TRUE) ? attr.value : NULL; +} + +static bool push_notification_driver_ox_begin_txn +(struct push_notification_driver_txn *dtxn) +{ + const char *const *args; + struct push_notification_event_messagenew_config *config; + const char *key, *mbox_curr, *md_value, *value; + bool mbox_found = FALSE; + struct push_notification_driver_ox_txn *txn; + + md_value = push_notification_driver_ox_get_metadata(dtxn); + if (md_value == NULL) { + return FALSE; + } + struct mail_user *user = dtxn->ptxn->muser; + + /* Unused keys: events, expire, folder */ + /* TODO: To be implemented later(?) */ + const char *const *events = default_events; + time_t expire = INT_MAX; + const char *const *mboxes = default_mboxes; + + if (expire < ioloop_time) { + push_notification_driver_debug(OX_LOG_LABEL, user, + "Skipped due to expiration (%ld < %ld)", + (long)expire, (long)ioloop_time); + return FALSE; + } + + mbox_curr = mailbox_get_vname(dtxn->ptxn->mbox); + for (; *mboxes != NULL; mboxes++) { + if (strcmp(mbox_curr, *mboxes) == 0) { + mbox_found = TRUE; + break; + } + } + + if (mbox_found == FALSE) { + push_notification_driver_debug(OX_LOG_LABEL, user, + "Skipped because %s is not a watched mailbox", + mbox_curr); + return FALSE; + } + + txn = p_new(dtxn->ptxn->pool, struct push_notification_driver_ox_txn, 1); + + /* Valid keys: user */ + args = t_strsplit_tab(md_value); + for (; *args != NULL; args++) { + key = *args; + + value = strchr(key, '='); + if (value != NULL) { + key = t_strdup_until(key, value++); + if (strcmp(key, "user") == 0) { + txn->user = p_strdup(dtxn->ptxn->pool, value); + } + } + } + + if (txn->user == NULL) { + i_error(OX_LOG_LABEL "No user provided in config"); + return FALSE; + } + + push_notification_driver_debug(OX_LOG_LABEL, user, "User (%s)", txn->user); + + for (; *events != NULL; events++) { + if (strcmp(*events, "MessageNew") == 0) { + config = p_new(dtxn->ptxn->pool, + struct push_notification_event_messagenew_config, 1); + config->flags = PUSH_NOTIFICATION_MESSAGE_HDR_FROM | + PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT | + PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET; + push_notification_event_init(dtxn, "MessageNew", config); + push_notification_driver_debug(OX_LOG_LABEL, user, + "Handling MessageNew event"); + } + } + + dtxn->context = txn; + + return TRUE; +} + +static void push_notification_driver_ox_http_callback +(const struct http_response *response, struct mail_user *user) +{ + switch (response->status / 100) { + case 2: + // Success. + if (user->mail_debug) { + push_notification_driver_debug(OX_LOG_LABEL, user, + "Notification sent successfully: %u %s", + response->status, response->reason); + } + break; + + default: + // Error. + i_error(OX_LOG_LABEL "Error when sending notification: %u %s", + response->status, response->reason); + break; + } +} + +/* Callback needed for i_stream_add_destroy_callback() in + * push_notification_driver_ox_process_msg. */ +static void str_free_i(string_t *str) +{ + str_free(&str); +} + +static void push_notification_driver_ox_process_msg +(struct push_notification_driver_txn *dtxn, + struct push_notification_txn_msg *msg) +{ + struct push_notification_driver_ox_config *dconfig = + (struct push_notification_driver_ox_config *)dtxn->duser->context; + struct http_client_request *http_req; + struct push_notification_event_messagenew_data *messagenew; + struct istream *payload; + string_t *str; + struct push_notification_driver_ox_txn *txn = + (struct push_notification_driver_ox_txn *)dtxn->context; + struct mail_user *user = dtxn->ptxn->muser; + + push_notification_driver_ox_init_global(user); + + messagenew = push_notification_txn_msg_get_eventdata(msg, "MessageNew"); + + http_req = http_client_request_url(ox_global->http_client, "PUT", + dconfig->http_url, + push_notification_driver_ox_http_callback, + user); + + http_client_request_add_header(http_req, "Content-Type", + "application/json; charset=utf-8"); + + str = str_new(default_pool, 256); + str_append(str, "{\"user\":\""); + json_append_escaped(str, txn->user); + str_append(str, "\",\"event\":\"messageNew\",\"folder\":\""); + json_append_escaped(str, msg->mailbox); + str_printfa(str, "\",\"imap-uidvalidity\":%u,\"imap-uid\":%u", + msg->uid_validity, msg->uid); + if (messagenew->from != NULL) { + str_append(str, ",\"from\":\""); + json_append_escaped(str, messagenew->from); + } + if (messagenew->subject != NULL) { + str_append(str, "\",\"subject\":\""); + json_append_escaped(str, messagenew->subject); + } + if (messagenew->snippet != NULL) { + str_append(str, "\",\"snippet\":\""); + json_append_escaped(str, messagenew->snippet); + } + str_append(str, "\"}"); + + push_notification_driver_debug(OX_LOG_LABEL, user, + "Sending notification: %s", str_c(str)); + + payload = i_stream_create_from_data(str_data(str), str_len(str)); + i_stream_add_destroy_callback(payload, str_free_i, str); + http_client_request_set_payload(http_req, payload, FALSE); + + http_client_request_submit(http_req); + i_stream_unref(&payload); +} + +static void push_notification_driver_ox_deinit +(struct push_notification_driver_user *duser ATTR_UNUSED) +{ + if (ox_global != NULL) { + i_assert(ox_global->refcount > 0); + --ox_global->refcount; + } +} + +static void push_notification_driver_ox_cleanup(void) +{ + if ((ox_global != NULL) && (ox_global->refcount <= 0)) { + http_client_wait(ox_global->http_client); + http_client_deinit(&ox_global->http_client); + i_free_and_null(ox_global); + } +} + + +/* Driver definition */ + +extern struct push_notification_driver push_notification_driver_ox; + +struct push_notification_driver push_notification_driver_ox = { + .name = "ox", + .v = { + .init = push_notification_driver_ox_init, + .begin_txn = push_notification_driver_ox_begin_txn, + .process_msg = push_notification_driver_ox_process_msg, + .deinit = push_notification_driver_ox_deinit, + .cleanup = push_notification_driver_ox_cleanup + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-drivers.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,189 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "hash.h" +#include "mail-user.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" + + +static ARRAY(const struct push_notification_driver *) push_notification_drivers; + + +static bool +push_notification_driver_find(const char *name, unsigned int *idx_r) +{ + unsigned int count, i; + const struct push_notification_driver *const *drivers; + + drivers = array_get(&push_notification_drivers, &count); + for (i = 0; i < count; i++) { + if (strcasecmp(drivers[i]->name, name) == 0) { + *idx_r = i; + return TRUE; + } + } + + return FALSE; +} + +static const struct push_notification_driver * +push_notification_driver_find_class(const char *driver) +{ + const struct push_notification_driver *const *class_p; + unsigned int idx; + + if (!push_notification_driver_find(driver, &idx)) { + return NULL; + } + + class_p = array_idx(&push_notification_drivers, idx); + + return *class_p; +} + +static struct push_notification_driver_config * +push_notification_driver_parse_config(const char *p) +{ + const char **args, *key, *p2, *value; + struct push_notification_driver_config *config; + + config = t_new(struct push_notification_driver_config, 1); + config->raw_config = p; + + hash_table_create(&config->config, unsafe_data_stack_pool, 0, + str_hash, strcmp); + + if (p == NULL) { + return config; + } + + args = t_strsplit_spaces(p, " "); + + for (; *args != NULL; args++) { + p2 = strchr(*args, '='); + if (p2 != NULL) { + key = t_strdup_until(*args, p2); + value = t_strdup(p2 + 1); + hash_table_insert(config->config, key, value); + } + } + + return config; +} + +int +push_notification_driver_init(struct mail_user *user, const char *config_in, + pool_t pool, + struct push_notification_driver_user **duser_r) +{ + void *context = NULL; + const struct push_notification_driver *driver; + const char *driver_name, *error_r, *p; + struct push_notification_driver_user *duser; + int ret; + + /* <driver>[:<driver config>] */ + p = strchr(config_in, ':'); + if (p == NULL) { + driver_name = config_in; + } else { + driver_name = t_strdup_until(config_in, p); + } + + driver = push_notification_driver_find_class(driver_name); + if (driver == NULL) { + i_error("Unknown push notification driver: %s", driver_name); + return -1; + } + + if (driver->v.init != NULL) { + T_BEGIN { + struct push_notification_driver_config *config; + + config = push_notification_driver_parse_config( + (p == NULL) ? p : p + 1); + ret = driver->v.init(config, user, pool, &context, &error_r); + + hash_table_destroy(&config->config); + } T_END; + + if (ret < 0) { + i_error("%s: %s", driver_name, error_r); + return -1; + } + } + + duser = p_new(pool, struct push_notification_driver_user, 1); + duser->context = context; + duser->driver = driver; + + *duser_r = duser; + + return 0; +} + +void push_notification_driver_cleanup_all(void) +{ + const struct push_notification_driver *const *driver; + + /* Loop through driver list and perform global cleanup tasks. We may not + * have used all drivers in this plugin/worker, but the cleanup hooks are + * designed to ignore these unused drivers. */ + array_foreach(&push_notification_drivers, driver) { + if ((*driver)->v.cleanup != NULL) { + (*driver)->v.cleanup(); + } + } +} + +void ATTR_FORMAT(3, 4) +push_notification_driver_debug(const char *label, struct mail_user *user, + const char *fmt, ...) +{ + va_list args; + + if (user->mail_debug) T_BEGIN { + va_start(args, fmt); + i_debug("%s%s", label, t_strdup_vprintf(fmt, args)); + va_end(args); + } T_END; +} + +void push_notification_driver_register +(const struct push_notification_driver *driver) +{ + unsigned int idx; + + if (!array_is_created(&push_notification_drivers)) { + i_array_init(&push_notification_drivers, 4); + } + + if (push_notification_driver_find(driver->name, &idx)) { + i_panic("push_notification_driver_register(%s): duplicate driver", + driver->name); + } + + array_append(&push_notification_drivers, &driver, 1); +} + +void push_notification_driver_unregister +(const struct push_notification_driver *driver) +{ + unsigned int idx; + + if (!push_notification_driver_find(driver->name, &idx)) { + i_panic("push_notification_driver_register(%s): unknown driver", + driver->name); + } + + if (array_is_created(&push_notification_drivers)) { + array_delete(&push_notification_drivers, idx, 1); + + if (array_is_empty(&push_notification_drivers)) { + array_free(&push_notification_drivers); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-drivers.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,121 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_DRIVERS_H +#define PUSH_NOTIFICATION_DRIVERS_H + + +#include "mail-user.h" +#include "push-notification-triggers.h" + +struct mail_user; +struct push_notification_driver_config; +struct push_notification_driver_txn; +struct push_notification_driver_user; +struct push_notification_txn_mbox; +struct push_notification_txn_msg; + + +HASH_TABLE_DEFINE_TYPE(push_notification_config, const char *, const char *); +HASH_TABLE_DEFINE_TYPE(push_notification_msgs, void *, + struct push_notification_txn_msg *); + + +struct push_notification_driver_vfuncs { + /* Init driver. Config (from plugin configuration) is parsed once (no + * user variable substitutions). Return 0 on success, or -1 if this + * driver should be disabled (or on error). */ + int (*init)(struct push_notification_driver_config *config, + struct mail_user *user, pool_t pool, void **context, + const char **error_r); + /* Called at the beginning of a notification transaction. Return TRUE on + * success, or FALSE if this driver should be ignored for this + * transaction. */ + bool (*begin_txn)(struct push_notification_driver_txn *dtxn); + /* Called once for every mailbox processed. */ + void (*process_mbox)(struct push_notification_driver_txn *dtxn, + struct push_notification_txn_mbox *mbox); + /* Called once for every message processed. */ + void (*process_msg)(struct push_notification_driver_txn *dtxn, + struct push_notification_txn_msg *msg); + /* Called at the end of a successful notification transaction. */ + void (*end_txn)(struct push_notification_driver_txn *dtxn, bool success); + /* Called when plugin is deinitialized. */ + void (*deinit)(struct push_notification_driver_user *duser); + /* Called to cleanup any global resources used in plugin. */ + void (*cleanup)(void); +}; + +struct push_notification_driver { + const char *name; + struct push_notification_driver_vfuncs v; +}; + +struct push_notification_driver_config { + HASH_TABLE_TYPE(push_notification_config) config; + const char *raw_config; +}; + +struct push_notification_driver_user { + const struct push_notification_driver *driver; + void *context; +}; + +struct push_notification_driver_txn { + const struct push_notification_driver_user *duser; + struct push_notification_txn *ptxn; + + /* Transaction context. */ + void *context; +}; + +struct push_notification_user { + union mail_user_module_context module_ctx; + ARRAY(struct push_notification_driver_user *) drivers; + pool_t pool; +}; + +struct push_notification_trigger_ctx { + const char *name; + void *context; +}; + +struct push_notification_txn { + pool_t pool; + + struct mailbox *mbox; + struct mail_user *muser; + struct push_notification_user *puser; + + enum push_notification_event_trigger trigger; + struct push_notification_trigger_ctx *trigger_ctx; + ARRAY(struct push_notification_driver_txn *) drivers; + ARRAY(struct push_notification_event_config *) events; + + /* Used with mailbox events. */ + struct push_notification_txn_mbox *mbox_txn; + + /* Used with mailbox events. */ + HASH_TABLE_TYPE(push_notification_msgs) messages; + + /* Private (used with message events). */ + struct mailbox_transaction_context *t; +}; + + +int +push_notification_driver_init(struct mail_user *user, const char *config_in, + pool_t pool, + struct push_notification_driver_user **duser_r); +void push_notification_driver_cleanup_all(void); + +void ATTR_FORMAT(3, 4) +push_notification_driver_debug(const char *label, struct mail_user *user, + const char *fmt, ...); + +void push_notification_driver_register +(const struct push_notification_driver *driver); +void push_notification_driver_unregister +(const struct push_notification_driver *driver); + + +#endif /* PUSH_NOTIFICATION_DRIVERS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-flagsclear.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,179 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "mail-storage.h" +#include "mail-types.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-flagsclear.h" +#include "push-notification-txn-msg.h" + + +#define EVENT_NAME "FlagsClear" + +static struct push_notification_event_flagsclear_config default_config; + + +static void *push_notification_event_flagsclear_default_config(void) +{ + memset(&default_config, 0, sizeof(default_config)); + + return &default_config; +} + +static void push_notification_event_flagsclear_debug_msg +(struct push_notification_txn_event *event) +{ + struct push_notification_event_flagsclear_data *data = event->data; + const char *const *keyword; + + if (data->flags_clear & MAIL_ANSWERED) { + i_debug("%s: Answered flag cleared", EVENT_NAME); + } + if (data->flags_clear & MAIL_FLAGGED) { + i_debug("%s: Flagged flag cleared", EVENT_NAME); + } + if (data->flags_clear & MAIL_DELETED) { + i_debug("%s: Deleted flag cleared", EVENT_NAME); + } + if (data->flags_clear & MAIL_SEEN) { + i_debug("%s: Seen flag cleared", EVENT_NAME); + } + if (data->flags_clear & MAIL_DRAFT) { + i_debug("%s: Draft flag cleared", EVENT_NAME); + } + + array_foreach(&data->keywords_clear, keyword) { + i_debug("%s: Keyword clear [%s]", EVENT_NAME, *keyword); + } +} + +static struct push_notification_event_flagsclear_data * +push_notification_event_flagsclear_get_data(struct push_notification_txn *ptxn, + struct push_notification_txn_msg *msg, + struct push_notification_event_config *ec) +{ + struct push_notification_event_flagsclear_config *config = + (struct push_notification_event_flagsclear_config *)ec->config; + struct push_notification_event_flagsclear_data *data; + + data = push_notification_txn_msg_get_eventdata(msg, EVENT_NAME); + if (data == NULL) { + data = p_new(ptxn->pool, + struct push_notification_event_flagsclear_data, 1); + data->flags_clear = 0; + data->flags_old = 0; + p_array_init(&data->keywords_clear, ptxn->pool, 4); + if (config->store_old == TRUE) { + p_array_init(&data->keywords_old, ptxn->pool, 4); + } + + push_notification_txn_msg_set_eventdata(ptxn, msg, ec, data); + } + + return data; +} + +static void push_notification_event_flagsclear_flags_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail, + enum mail_flags old_flags) +{ + struct push_notification_event_flagsclear_config *config = + (struct push_notification_event_flagsclear_config *)ec->config; + struct push_notification_event_flagsclear_data *data; + enum mail_flags flag_check_always[] = { + MAIL_ANSWERED, + MAIL_DELETED, + MAIL_DRAFT, + MAIL_FLAGGED, + MAIL_SEEN + }; + enum mail_flags flags; + unsigned int i; + + data = push_notification_event_flagsclear_get_data(ptxn, msg, ec); + flags = mail_get_flags(mail); + + for (i = 0; i < N_ELEMENTS(flag_check_always); i++) { + if (!(flags & flag_check_always[i]) && + (old_flags & flag_check_always[i])) { + data->flags_clear |= flag_check_always[i]; + } + } + + if (config->store_old == TRUE) { + data->flags_old = old_flags; + } +} + +static void push_notification_event_flagsclear_keywords_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail, + const char *const *old_keywords) +{ + struct push_notification_event_flagsclear_config *config = + (struct push_notification_event_flagsclear_config *)ec->config; + struct push_notification_event_flagsclear_data *data; + const char *const *keywords, *const *kp, *ok; + + data = push_notification_event_flagsclear_get_data(ptxn, msg, ec); + keywords = mail_get_keywords(mail); + + for (; *old_keywords != NULL; old_keywords++) { + for (kp = keywords; *kp != NULL; kp++) { + if (strcmp(*old_keywords, *kp) == 0) { + break; + } + } + + if (*kp == NULL) { + ok = p_strdup(ptxn->pool, *old_keywords); + array_append(&data->keywords_clear, &ok, 1); + } + + if (config->store_old == TRUE) { + ok = p_strdup(ptxn->pool, *old_keywords); + array_append(&data->keywords_old, &ok, 1); + } + } +} + +static void push_notification_event_flagsclear_free_msg( + struct push_notification_txn_event *event) +{ + struct push_notification_event_flagsclear_data *data = event->data; + + if (array_is_created(&data->keywords_clear)) { + array_free(&data->keywords_clear); + } + if (array_is_created(&data->keywords_old)) { + array_free(&data->keywords_old); + } +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_flagsclear; + +struct push_notification_event push_notification_event_flagsclear = { + .name = EVENT_NAME, + .init = { + .default_config = push_notification_event_flagsclear_default_config + }, + .msg = { + .debug_msg = push_notification_event_flagsclear_debug_msg, + .free_msg = push_notification_event_flagsclear_free_msg + }, + .msg_triggers = { + .flagchange = push_notification_event_flagsclear_flags_event, + .keywordchange = push_notification_event_flagsclear_keywords_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-flagsclear.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,25 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_FLAGSCLEAR_H +#define PUSH_NOTIFICATION_EVENT_FLAGSCLEAR_H + + +#include "mail-types.h" + + +struct push_notification_event_flagsclear_config { + /* Store the old flags/keywords? */ + bool store_old; +}; + +struct push_notification_event_flagsclear_data { + enum mail_flags flags_clear; + ARRAY_TYPE(keywords) keywords_clear; + + enum mail_flags flags_old; + ARRAY_TYPE(keywords) keywords_old; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_FLAGSCLEAR_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-flagsset.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,174 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "mail-storage.h" +#include "mail-types.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-flagsset.h" +#include "push-notification-txn-msg.h" + + +#define EVENT_NAME "FlagsSet" + +static struct push_notification_event_flagsset_config default_config; + + +static void *push_notification_event_flagsset_default_config(void) +{ + memset(&default_config, 0, sizeof(default_config)); + + return &default_config; +} + +static void push_notification_event_flagsset_debug_msg +(struct push_notification_txn_event *event) +{ + struct push_notification_event_flagsset_data *data = event->data; + const char *const *keyword; + + if (data->flags_set & MAIL_ANSWERED) { + i_debug("%s: Answered flag set", EVENT_NAME); + } + if (data->flags_set & MAIL_FLAGGED) { + i_debug("%s: Flagged flag set", EVENT_NAME); + } + if (data->flags_set & MAIL_DELETED) { + i_debug("%s: Deleted flag set", EVENT_NAME); + } + if (data->flags_set & MAIL_SEEN) { + i_debug("%s: Seen flag set", EVENT_NAME); + } + if (data->flags_set & MAIL_DRAFT) { + i_debug("%s: Draft flag set", EVENT_NAME); + } + + array_foreach(&data->keywords_set, keyword) { + i_debug("%s: Keyword set [%s]", EVENT_NAME, *keyword); + } +} + +static struct push_notification_event_flagsset_data * +push_notification_event_flagsset_get_data(struct push_notification_txn *ptxn, + struct push_notification_txn_msg *msg, + struct push_notification_event_config *ec) +{ + struct push_notification_event_flagsset_data *data; + + data = push_notification_txn_msg_get_eventdata(msg, EVENT_NAME); + if (data == NULL) { + data = p_new(ptxn->pool, + struct push_notification_event_flagsset_data, 1); + data->flags_set = 0; + p_array_init(&data->keywords_set, ptxn->pool, 4); + + push_notification_txn_msg_set_eventdata(ptxn, msg, ec, data); + } + + return data; +} + +static void push_notification_event_flagsset_flags_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail, + enum mail_flags old_flags) +{ + struct push_notification_event_flagsset_config *config = + (struct push_notification_event_flagsset_config *)ec->config; + struct push_notification_event_flagsset_data *data; + enum mail_flags flag_check_always[] = { + MAIL_ANSWERED, + MAIL_DRAFT, + MAIL_FLAGGED + }; + enum mail_flags flags, flags_set = 0; + unsigned int i; + + flags = mail_get_flags(mail); + + for (i = 0; i < N_ELEMENTS(flag_check_always); i++) { + if ((flags & flag_check_always[i]) && + !(old_flags & flag_check_always[i])) { + flags_set |= flag_check_always[i]; + } + } + + if (!config->hide_deleted && + (flags & MAIL_DELETED) && + !(old_flags & MAIL_DELETED)) { + flags_set |= MAIL_DELETED; + } + + if (!config->hide_seen && + (flags & MAIL_SEEN) && + !(old_flags & MAIL_SEEN)) { + flags_set |= MAIL_SEEN; + } + + /* Only create data element if at least one flag was set. */ + if (flags_set) { + data = push_notification_event_flagsset_get_data(ptxn, msg, ec); + data->flags_set |= flags_set; + } +} + +static void push_notification_event_flagsset_keywords_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail, + const char *const *old_keywords) +{ + struct push_notification_event_flagsset_data *data; + const char *k, *const *keywords, *const *op; + + data = push_notification_event_flagsset_get_data(ptxn, msg, ec); + keywords = mail_get_keywords(mail); + + for (; *keywords != NULL; keywords++) { + for (op = old_keywords; *op != NULL; op++) { + if (strcmp(*keywords, *op) == 0) { + break; + } + } + + if (*op == NULL) { + k = p_strdup(ptxn->pool, *keywords); + array_append(&data->keywords_set, &k, 1); + } + } +} + +static void push_notification_event_flagsset_free_msg( + struct push_notification_txn_event *event) +{ + struct push_notification_event_flagsset_data *data = event->data; + + if (array_is_created(&data->keywords_set)) { + array_free(&data->keywords_set); + } +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_flagsset; + +struct push_notification_event push_notification_event_flagsset = { + .name = EVENT_NAME, + .init = { + .default_config = push_notification_event_flagsset_default_config + }, + .msg = { + .debug_msg = push_notification_event_flagsset_debug_msg, + .free_msg = push_notification_event_flagsset_free_msg + }, + .msg_triggers = { + .flagchange = push_notification_event_flagsset_flags_event, + .keywordchange = push_notification_event_flagsset_keywords_event + } +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-flagsset.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,26 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_FLAGSSET_H +#define PUSH_NOTIFICATION_EVENT_FLAGSSET_H + + +#include "mail-types.h" + + +struct push_notification_event_flagsset_config { + /* RFC 5423[4.2] - allow configuration whether FlagsSet event returns + * Deleted and/or Seen flags, since these flags are also settable + * via MessageRead/MessageTrash events. By default, include them + * here. */ + bool hide_deleted; + bool hide_seen; +}; + +struct push_notification_event_flagsset_data { + enum mail_flags flags_set; + ARRAY_TYPE(keywords) keywords_set; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_FLAGSSET_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxcreate.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,51 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-mailboxcreate.h" +#include "push-notification-txn-mbox.h" + + +#define EVENT_NAME "MailboxCreate" + + +static void push_notification_event_mailboxcreate_debug_mbox +(struct push_notification_txn_event *event ATTR_UNUSED) +{ + i_debug("%s: Mailbox was created", EVENT_NAME); +} + +static void push_notification_event_mailboxcreate_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_event_mailboxcreate_data *data; + struct mailbox_status status; + + mailbox_get_status(ptxn->mbox, STATUS_UIDVALIDITY, &status); + + data = p_new(ptxn->pool, + struct push_notification_event_mailboxcreate_data, 1); + data->uid_validity = status.uidvalidity; + + push_notification_txn_mbox_set_eventdata(ptxn, mbox, ec, data); +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_mailboxcreate; + +struct push_notification_event push_notification_event_mailboxcreate = { + .name = EVENT_NAME, + .mbox = { + .debug_mbox = push_notification_event_mailboxcreate_debug_mbox + }, + .mbox_triggers = { + .create = push_notification_event_mailboxcreate_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxcreate.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,14 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MAILBOXCREATE_H +#define PUSH_NOTIFICATION_EVENT_MAILBOXCREATE_H + + +struct push_notification_event_mailboxcreate_data { + /* RFC 5423 [4.4]: UIDVALIDITY required for create event. */ + uint32_t uid_validity; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MAILBOXCREATE_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxdelete.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,47 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-mailboxdelete.h" +#include "push-notification-txn-mbox.h" + + +#define EVENT_NAME "MailboxDelete" + + +static void push_notification_event_mailboxdelete_debug_mbox +(struct push_notification_txn_event *event ATTR_UNUSED) +{ + i_debug("%s: Mailbox was deleted", EVENT_NAME); +} + +static void push_notification_event_mailboxdelete_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_event_mailboxdelete_data *data; + + data = p_new(ptxn->pool, + struct push_notification_event_mailboxdelete_data, 1); + data->deleted = TRUE; + + push_notification_txn_mbox_set_eventdata(ptxn, mbox, ec, data); +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_mailboxdelete; + +struct push_notification_event push_notification_event_mailboxdelete = { + .name = EVENT_NAME, + .mbox = { + .debug_mbox = push_notification_event_mailboxdelete_debug_mbox + }, + .mbox_triggers = { + .delete = push_notification_event_mailboxdelete_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxdelete.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,14 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MAILBOXDELETE_H +#define PUSH_NOTIFICATION_EVENT_MAILBOXDELETE_H + + +struct push_notification_event_mailboxdelete_data { + /* Can only be true. */ + bool deleted; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MAILBOXDELETE_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxrename.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,52 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-mailboxrename.h" +#include "push-notification-txn-mbox.h" + + +#define EVENT_NAME "MailboxRename" + + +static void push_notification_event_mailboxrename_debug_mbox +(struct push_notification_txn_event *event) +{ + struct push_notification_event_mailboxrename_data *data = event->data; + + i_debug("%s: Mailbox was renamed (old name: %s)", + EVENT_NAME, data->old_mbox); +} + +static void push_notification_event_mailboxrename_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox, + struct mailbox *old) +{ + struct push_notification_event_mailboxrename_data *data; + + data = p_new(ptxn->pool, + struct push_notification_event_mailboxrename_data, 1); + data->old_mbox = mailbox_get_vname(old); + + push_notification_txn_mbox_set_eventdata(ptxn, mbox, ec, data); +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_mailboxrename; + +struct push_notification_event push_notification_event_mailboxrename = { + .name = EVENT_NAME, + .mbox = { + .debug_mbox = push_notification_event_mailboxrename_debug_mbox + }, + .mbox_triggers = { + .rename = push_notification_event_mailboxrename_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxrename.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,13 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MAILBOXRENAME_H +#define PUSH_NOTIFICATION_EVENT_MAILBOXRENAME_H + + +struct push_notification_event_mailboxrename_data { + const char *old_mbox; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MAILBOXRENAME_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxsubscribe.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,48 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-mailboxsubscribe.h" +#include "push-notification-txn-mbox.h" + + +#define EVENT_NAME "MailboxSubscribe" + + +static void push_notification_event_mailboxsubscribe_debug_mbox +(struct push_notification_txn_event *event ATTR_UNUSED) +{ + i_debug("%s: Mailbox was subscribed to", EVENT_NAME); +} + +static void push_notification_event_mailboxsubscribe_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_event_mailboxsubscribe_data *data; + + data = p_new(ptxn->pool, + struct push_notification_event_mailboxsubscribe_data, 1); + data->subscribe = TRUE; + + push_notification_txn_mbox_set_eventdata(ptxn, mbox, ec, data); +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_mailboxsubscribe; + +struct push_notification_event push_notification_event_mailboxsubscribe = { + .name = EVENT_NAME, + .mbox = { + .debug_mbox = push_notification_event_mailboxsubscribe_debug_mbox + }, + .mbox_triggers = { + .subscribe = push_notification_event_mailboxsubscribe_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxsubscribe.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,14 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MAILBOXSUBSCRIBE_H +#define PUSH_NOTIFICATION_EVENT_MAILBOXSUBSCRIBE_H + + +struct push_notification_event_mailboxsubscribe_data { + /* Can only be true. */ + bool subscribe; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MAILBOXSUBSCRIBE_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxunsubscribe.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,48 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-mailboxunsubscribe.h" +#include "push-notification-txn-mbox.h" + + +#define EVENT_NAME "MailboxUnsubscribe" + + +static void push_notification_event_mailboxunsubscribe_debug_mbox +(struct push_notification_txn_event *event ATTR_UNUSED) +{ + i_debug("%s: Mailbox was subscribed to", EVENT_NAME); +} + +static void push_notification_event_mailboxunsubscribe_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_event_mailboxunsubscribe_data *data; + + data = p_new(ptxn->pool, + struct push_notification_event_mailboxunsubscribe_data, 1); + data->subscribe = TRUE; + + push_notification_txn_mbox_set_eventdata(ptxn, mbox, ec, data); +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_mailboxunsubscribe; + +struct push_notification_event push_notification_event_mailboxunsubscribe = { + .name = EVENT_NAME, + .mbox = { + .debug_mbox = push_notification_event_mailboxunsubscribe_debug_mbox + }, + .mbox_triggers = { + .unsubscribe = push_notification_event_mailboxunsubscribe_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-mailboxunsubscribe.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,14 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MAILBOXUNSUBSCRIBE_H +#define PUSH_NOTIFICATION_EVENT_MAILBOXUNSUBSCRIBE_H + + +struct push_notification_event_mailboxunsubscribe_data { + /* Can only be false. */ + bool subscribe; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MAILBOXUNSUBSCRIBE_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-message-common.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,22 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MESSAGE_COMMON_H +#define PUSH_NOTIFICATION_EVENT_MESSAGE_COMMON_H + + +enum push_notification_event_message_flags { + /* Header: From */ + PUSH_NOTIFICATION_MESSAGE_HDR_FROM = 0x01, + /* Header: To */ + PUSH_NOTIFICATION_MESSAGE_HDR_TO = 0x02, + /* Header: Subject */ + PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT = 0x04, + /* Header: Date */ + PUSH_NOTIFICATION_MESSAGE_HDR_DATE = 0x08, + /* Body: Snippet */ + PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET = 0x10 +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MESSAGE_COMMON_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messageappend.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,115 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "hash.h" +#include "istream.h" +#include "mail-storage.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-message-common.h" +#include "push-notification-event-messageappend.h" +#include "push-notification-txn-msg.h" + + +#define EVENT_NAME "MessageAppend" + +static struct push_notification_event_messageappend_config default_config; + + +static void *push_notification_event_messageappend_default_config(void) +{ + memset(&default_config, 0, sizeof(default_config)); + + return &default_config; +} + +static void push_notification_event_messageappend_debug_msg +(struct push_notification_txn_event *event) +{ + struct push_notification_event_messageappend_data *data = event->data; + + if (data->from != NULL) { + i_debug("%s: From [%s]", EVENT_NAME, data->from); + } + + if (data->snippet != NULL) { + i_debug("%s: Snippet [%s]", EVENT_NAME, data->snippet); + } + + if (data->subject != NULL) { + i_debug("%s: Subject [%s]", EVENT_NAME, data->subject); + } + + if (data->to != NULL) { + i_debug("%s: To [%s]", EVENT_NAME, data->to); + } +} + +static void +push_notification_event_messageappend_event(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail) +{ + struct push_notification_event_messageappend_config *config = + (struct push_notification_event_messageappend_config *)ec->config; + struct push_notification_event_messageappend_data *data; + const char *value; + + if (!config->flags) { + return; + } + + data = push_notification_txn_msg_get_eventdata(msg, EVENT_NAME); + if (data == NULL) { + data = p_new(ptxn->pool, + struct push_notification_event_messageappend_data, 1); + push_notification_txn_msg_set_eventdata(ptxn, msg, ec, data); + } + + if ((data->to == NULL) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_HDR_TO) && + (mail_get_first_header(mail, "To", &value) >= 0)) { + data->to = p_strdup(ptxn->pool, value); + } + + if ((data->from == NULL) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_HDR_FROM) && + (mail_get_first_header(mail, "From", &value) >= 0)) { + data->from = p_strdup(ptxn->pool, value); + } + + if ((data->subject == NULL) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT) && + (mail_get_first_header(mail, "Subject", &value) >= 0)) { + data->subject = p_strdup(ptxn->pool, value); + } + + if ((data->snippet == NULL) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET) && + (mail_get_special(mail, MAIL_FETCH_BODY_SNIPPET, &value) >= 0)) { + /* [0] contains the snippet algorithm, skip over it */ + i_assert(value[0] != '\0'); + data->snippet = p_strdup(ptxn->pool, value + 1); + } +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_messageappend; + +struct push_notification_event push_notification_event_messageappend = { + .name = EVENT_NAME, + .init = { + .default_config = push_notification_event_messageappend_default_config + }, + .msg = { + .debug_msg = push_notification_event_messageappend_debug_msg + }, + .msg_triggers = { + .append = push_notification_event_messageappend_event + } +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messageappend.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,20 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MESSAGEAPPEND_H +#define PUSH_NOTIFICATION_EVENT_MESSAGEAPPEND_H + + +struct push_notification_event_messageappend_config { + enum push_notification_event_message_flags flags; +}; + +struct push_notification_event_messageappend_data { + const char *from; + const char *to; + const char *subject; + const char *snippet; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MESSAGEAPPEND_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messageexpunge.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,55 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" +#include "mail-types.h" + +#include "push-notification-drivers.h" +#include "push-notification-event-messageexpunge.h" +#include "push-notification-events.h" +#include "push-notification-txn-msg.h" + + +#define EVENT_NAME "MessageExpunge" + + +static void push_notification_event_messageexpunge_debug_msg +(struct push_notification_txn_event *event) +{ + struct push_notification_event_messageexpunge_data *data = event->data; + + if (data != NULL) { + i_debug("%s: Message was expunged", EVENT_NAME); + } +} + +static void push_notification_event_messageexpunge_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg) +{ + struct push_notification_event_messageexpunge_data *data; + + data = push_notification_txn_msg_get_eventdata(msg, EVENT_NAME); + if (data == NULL) { + data = p_new(ptxn->pool, + struct push_notification_event_messageexpunge_data, 1); + data->expunge = TRUE; + push_notification_txn_msg_set_eventdata(ptxn, msg, ec, data); + } +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_messageexpunge; + +struct push_notification_event push_notification_event_messageexpunge = { + .name = EVENT_NAME, + .msg = { + .debug_msg = push_notification_event_messageexpunge_debug_msg + }, + .msg_triggers = { + .expunge = push_notification_event_messageexpunge_event + } +}; \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messageexpunge.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,14 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MESSAGEEXPUNGE_H +#define PUSH_NOTIFICATION_EVENT_MESSAGEEXPUNGE_H + + +struct push_notification_event_messageexpunge_data { + /* Can only be true. */ + bool expunge; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MESSAGEEXPUNGE_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messagenew.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,136 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "hash.h" +#include "iso8601-date.h" +#include "istream.h" +#include "mail-storage.h" + +#include <time.h> + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-message-common.h" +#include "push-notification-event-messagenew.h" +#include "push-notification-txn-msg.h" + + +#define EVENT_NAME "MessageNew" + +static struct push_notification_event_messagenew_config default_config; + + +static void *push_notification_event_messagenew_default_config(void) +{ + memset(&default_config, 0, sizeof(default_config)); + + return &default_config; +} + +static void push_notification_event_messagenew_debug_msg +(struct push_notification_txn_event *event) +{ + struct push_notification_event_messagenew_data *data = event->data; + struct tm *tm; + + if (data->date != -1) { + tm = gmtime(&data->date); + i_debug("%s: Date [%s]", EVENT_NAME, + iso8601_date_create_tm(tm, data->date_tz)); + } + + if (data->from != NULL) { + i_debug("%s: From [%s]", EVENT_NAME, data->from); + } + + if (data->snippet != NULL) { + i_debug("%s: Snippet [%s]", EVENT_NAME, data->snippet); + } + + if (data->subject != NULL) { + i_debug("%s: Subject [%s]", EVENT_NAME, data->subject); + } + + if (data->to != NULL) { + i_debug("%s: To [%s]", EVENT_NAME, data->to); + } +} + +static void +push_notification_event_messagenew_event(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail) +{ + struct push_notification_event_messagenew_config *config = + (struct push_notification_event_messagenew_config *)ec->config; + struct push_notification_event_messagenew_data *data; + time_t date; + int tz; + const char *value; + + if (!config->flags) { + return; + } + + data = push_notification_txn_msg_get_eventdata(msg, EVENT_NAME); + if (data == NULL) { + data = p_new(ptxn->pool, + struct push_notification_event_messagenew_data, 1); + data->date = -1; + + push_notification_txn_msg_set_eventdata(ptxn, msg, ec, data); + } + + if ((data->to == NULL) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_HDR_TO) && + (mail_get_first_header(mail, "To", &value) >= 0)) { + data->to = p_strdup(ptxn->pool, value); + } + + if ((data->from == NULL) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_HDR_FROM) && + (mail_get_first_header(mail, "From", &value) >= 0)) { + data->from = p_strdup(ptxn->pool, value); + } + + if ((data->subject == NULL) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT) && + (mail_get_first_header(mail, "Subject", &value) >= 0)) { + data->subject = p_strdup(ptxn->pool, value); + } + + if ((data->date == -1) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_HDR_DATE) && + (mail_get_date(mail, &date, &tz) >= 0)) { + data->date = date; + data->date_tz = tz; + } + + if ((data->snippet == NULL) && + (config->flags & PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET) && + (mail_get_special(mail, MAIL_FETCH_BODY_SNIPPET, &value) >= 0)) { + /* [0] contains the snippet algorithm, skip over it */ + i_assert(value[0] != '\0'); + data->snippet = p_strdup(ptxn->pool, value + 1); + } +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_messagenew; + +struct push_notification_event push_notification_event_messagenew = { + .name = EVENT_NAME, + .init = { + .default_config = push_notification_event_messagenew_default_config + }, + .msg = { + .debug_msg = push_notification_event_messagenew_debug_msg + }, + .msg_triggers = { + .save = push_notification_event_messagenew_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messagenew.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,30 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MESSAGENEW_H +#define PUSH_NOTIFICATION_EVENT_MESSAGENEW_H + + +#include "push-notification-event-message-common.h" + + +struct push_notification_event_messagenew_config { + enum push_notification_event_message_flags flags; +}; + +struct push_notification_event_messagenew_data { + /* PUSH_NOTIFICATION_MESSAGE_HDR_FROM */ + const char *from; + /* PUSH_NOTIFICATION_MESSAGE_HDR_TO */ + const char *to; + /* PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT */ + const char *subject; + /* PUSH_NOTIFICATION_MESSAGE_HDR_DATE */ + time_t date; + int date_tz; + /* PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET */ + const char *snippet; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MESSAGENEW_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messageread.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,58 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" +#include "mail-types.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-messageread.h" +#include "push-notification-txn-msg.h" + + +#define EVENT_NAME "MessageRead" + + +static void push_notification_event_messageread_debug_msg +(struct push_notification_txn_event *event ATTR_UNUSED) +{ + i_debug("%s: Message was flagged as seen", EVENT_NAME); +} + +static void push_notification_event_messageread_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail, + enum mail_flags old_flags) +{ + struct push_notification_event_messageread_data *data; + enum mail_flags flags; + + /* If data struct exists, that means the read flag was changed. */ + data = push_notification_txn_msg_get_eventdata(msg, EVENT_NAME); + if ((data == NULL) && !(old_flags & MAIL_SEEN)) { + flags = mail_get_flags(mail); + if (flags & MAIL_SEEN) { + data = p_new(ptxn->pool, + struct push_notification_event_messageread_data, 1); + data->read = TRUE; + push_notification_txn_msg_set_eventdata(ptxn, msg, ec, data); + } + } +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_messageread; + +struct push_notification_event push_notification_event_messageread = { + .name = EVENT_NAME, + .msg = { + .debug_msg = push_notification_event_messageread_debug_msg + }, + .msg_triggers = { + .flagchange = push_notification_event_messageread_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messageread.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,13 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MESSAGEREAD_H +#define PUSH_NOTIFICATION_EVENT_MESSAGEREAD_H + + +struct push_notification_event_messageread_data { + /* Can only be true. */ + bool read; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MESSAGEREAD_H */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messagetrash.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,58 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "mail-storage.h" +#include "mail-types.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-event-messagetrash.h" +#include "push-notification-txn-msg.h" + + +#define EVENT_NAME "MessageTrash" + + +static void push_notification_event_messagetrash_debug_msg +(struct push_notification_txn_event *event ATTR_UNUSED) +{ + i_debug("%s: Message was marked as deleted", EVENT_NAME); +} + +static void push_notification_event_messagetrash_event( + struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail, + enum mail_flags old_flags) +{ + struct push_notification_event_messagetrash_data *data; + enum mail_flags flags; + + /* If data struct exists, that means the deleted flag was changed. */ + data = push_notification_txn_msg_get_eventdata(msg, EVENT_NAME); + if ((data == NULL) && !(old_flags & MAIL_DELETED)) { + flags = mail_get_flags(mail); + if (flags & MAIL_DELETED) { + data = p_new(ptxn->pool, + struct push_notification_event_messagetrash_data, 1); + data->trash = TRUE; + push_notification_txn_msg_set_eventdata(ptxn, msg, ec, data); + } + } +} + + +/* Event definition */ + +extern struct push_notification_event push_notification_event_messagetrash; + +struct push_notification_event push_notification_event_messagetrash = { + .name = EVENT_NAME, + .msg = { + .debug_msg = push_notification_event_messagetrash_debug_msg + }, + .msg_triggers = { + .flagchange = push_notification_event_messagetrash_event + } +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-event-messagetrash.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,14 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENT_MESSAGETRASH_H +#define PUSH_NOTIFICATION_EVENT_MESSAGETRASH_H + + +struct push_notification_event_messagetrash_data { + /* Can only be true. */ + bool trash; +}; + + +#endif /* PUSH_NOTIFICATION_EVENT_MESSAGETRASH_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-events-rfc5423.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,46 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" + +#include "push-notification-events.h" +#include "push-notification-events-rfc5423.h" + + +/* These are the RFC 5423 Mail Store Events currently handled within the core + * push-notification code. + * + * @todo: These events are not currently handled: + * - Login + * - Logout + * - QuotaExceed + * - Quota Within + */ +extern struct push_notification_event push_notification_event_flagsclear; +extern struct push_notification_event push_notification_event_flagsset; +extern struct push_notification_event push_notification_event_mailboxcreate; +extern struct push_notification_event push_notification_event_mailboxdelete; +extern struct push_notification_event push_notification_event_mailboxrename; +extern struct push_notification_event push_notification_event_mailboxsubscribe; +extern struct push_notification_event push_notification_event_mailboxunsubscribe; +extern struct push_notification_event push_notification_event_messageappend; +extern struct push_notification_event push_notification_event_messageexpunge; +extern struct push_notification_event push_notification_event_messagenew; +extern struct push_notification_event push_notification_event_messageread; +extern struct push_notification_event push_notification_event_messagetrash; + + +void push_notification_event_register_rfc5423_events(void) +{ + push_notification_event_register(&push_notification_event_flagsclear); + push_notification_event_register(&push_notification_event_flagsset); + push_notification_event_register(&push_notification_event_mailboxcreate); + push_notification_event_register(&push_notification_event_mailboxdelete); + push_notification_event_register(&push_notification_event_mailboxrename); + push_notification_event_register(&push_notification_event_mailboxsubscribe); + push_notification_event_register(&push_notification_event_mailboxunsubscribe); + push_notification_event_register(&push_notification_event_messageappend); + push_notification_event_register(&push_notification_event_messageexpunge); + push_notification_event_register(&push_notification_event_messagenew); + push_notification_event_register(&push_notification_event_messageread); + push_notification_event_register(&push_notification_event_messagetrash); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-events-rfc5423.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,11 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENTS_RFC5423_H +#define PUSH_NOTIFICATION_EVENTS_RFC5423_H + + +void push_notification_event_register_rfc5423_events(void); + + +#endif /* PUSH_NOTIFICATION_EVENTS_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-events.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,105 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" + + +ARRAY_TYPE(push_notification_event) push_notification_events; + + +static bool +push_notification_event_find(const char *name, unsigned int *idx_r) +{ + unsigned int count, i; + const struct push_notification_event *const *events; + + events = array_get(&push_notification_events, &count); + for (i = 0; i < count; i++) { + if (strcasecmp(events[i]->name, name) == 0) { + *idx_r = i; + return TRUE; + } + } + + return FALSE; +} + +static const struct push_notification_event * +push_notification_event_find_class(const char *driver) +{ + const struct push_notification_event *const *class_p; + unsigned int idx; + + if (!push_notification_event_find(driver, &idx)) { + return NULL; + } + + class_p = array_idx(&push_notification_events, idx); + + return *class_p; +} + +void +push_notification_event_init(struct push_notification_driver_txn *dtxn, + const char *event_name, void *config) +{ + const struct push_notification_event *event; + struct push_notification_event_config *ec; + + if (!array_is_created(&dtxn->ptxn->events)) { + p_array_init(&dtxn->ptxn->events, dtxn->ptxn->pool, 4); + } + + event = push_notification_event_find_class(event_name); + if (event != NULL) { + if ((config == NULL) && + (event->init.default_config != NULL)) { + config = event->init.default_config(); + } + + ec = p_new(dtxn->ptxn->pool, struct push_notification_event_config, 1); + ec->config = config; + ec->event = event; + + array_append(&dtxn->ptxn->events, &ec, 1); + } +} + +void push_notification_event_register +(const struct push_notification_event *event) +{ + unsigned int idx; + + if (!array_is_created(&push_notification_events)) { + i_array_init(&push_notification_events, 16); + } + + if (push_notification_event_find(event->name, &idx)) { + i_panic("push_notification_event_register(%s): duplicate event", + event->name); + } + + array_append(&push_notification_events, &event, 1); +} + +void push_notification_event_unregister +(const struct push_notification_event *event) +{ + unsigned int idx; + + if (!push_notification_event_find(event->name, &idx)) { + i_panic("push_notification_event_register(%s): unknown event", + event->name); + } + + if (array_is_created(&push_notification_events)) { + array_delete(&push_notification_events, idx, 1); + + if (array_is_empty(&push_notification_events)) { + array_free(&push_notification_events); + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-events.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,127 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_EVENTS_H +#define PUSH_NOTIFICATION_EVENTS_H + +#include "mail-types.h" + +struct mail; +struct mailbox; +struct push_notification_event_config; +struct push_notification_driver_txn; +struct push_notification_txn; +struct push_notification_txn_event; +struct push_notification_txn_mbox; +struct push_notification_txn_msg; + +HASH_TABLE_DEFINE_TYPE(push_notification_mq_data, const char *, const char *); + +struct push_notification_event_vfuncs_init { + /* Return the default config for an event (or NULL if config is + * required). */ + void *(*default_config)(void); +}; + +struct push_notification_event_vfuncs_mbox { + /* Output debug information about a message event. */ + void (*debug_mbox)(struct push_notification_txn_event *event); + /* Called when message data is about to be free'd. */ + void (*free_mbox)(struct push_notification_txn_event *event); +}; + +struct push_notification_event_vfuncs_mbox_triggers { + /* Mailbox event: create mailbox. */ + void (*create)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox); + /* Mailbox event: delete mailbox. */ + void (*delete)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox); + /* Mailbox event: rename mailbox. */ + void (*rename)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox, + struct mailbox *old); + /* Mailbox event: subscribe mailbox. */ + void (*subscribe)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox); + /* Mailbox event: unsubscribe mailbox. */ + void (*unsubscribe)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_mbox *mbox); +}; + +struct push_notification_event_vfuncs_msg { + /* Output debug information about a message event. */ + void (*debug_msg)(struct push_notification_txn_event *event); + /* Called when message data is about to be free'd. */ + void (*free_msg)(struct push_notification_txn_event *event); +}; + +struct push_notification_event_vfuncs_msg_triggers { + /* Message event: save message (from MTA). */ + void (*save)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail); + /* Message event: append message (from MUA). */ + void (*append)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail); + /* Message event: expunge message. */ + void (*expunge)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg); + /* Message event: flag change. */ + void (*flagchange)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail, + enum mail_flags old_flags); + /* Message event: keyword change. */ + void (*keywordchange)(struct push_notification_txn *ptxn, + struct push_notification_event_config *ec, + struct push_notification_txn_msg *msg, + struct mail *mail, + const char *const *old_keywords); +}; + +struct push_notification_event_config { + const struct push_notification_event *event; + void *config; +}; + +struct push_notification_event { + const char *name; + struct push_notification_event_vfuncs_init init; + struct push_notification_event_vfuncs_mbox mbox; + struct push_notification_event_vfuncs_mbox_triggers mbox_triggers; + struct push_notification_event_vfuncs_msg msg; + struct push_notification_event_vfuncs_msg_triggers msg_triggers; +}; + +struct push_notification_txn_event { + struct push_notification_event_config *event; + void *data; +}; + +ARRAY_DEFINE_TYPE(push_notification_event, + const struct push_notification_event *); +extern ARRAY_TYPE(push_notification_event) push_notification_events; + + +void +push_notification_event_init(struct push_notification_driver_txn *dtxn, + const char *event_name, void *config); + +void push_notification_event_register +(const struct push_notification_event *event); +void push_notification_event_unregister +(const struct push_notification_event *event); + + +#endif /* PUSH_NOTIFICATION_EVENTS_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-plugin.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,327 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "mail-namespace.h" +#include "mail-storage.h" +#include "mail-storage-private.h" +#include "notify-plugin.h" +#include "str.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-events-rfc5423.h" +#include "push-notification-plugin.h" +#include "push-notification-triggers.h" +#include "push-notification-txn-mbox.h" +#include "push-notification-txn-msg.h" + + +#define PUSH_NOTIFICATION_CONFIG "push_notification_driver" +#define PUSH_NOTIFICATION_CONFIG_OLD "push_notification_backend" + +#define PUSH_NOTIFICATION_USER_CONTEXT(obj) \ + MODULE_CONTEXT(obj, push_notification_user_module) +static MODULE_CONTEXT_DEFINE_INIT(push_notification_user_module, + &mail_user_module_register); + + +static struct push_notification_user *puser = NULL; + + +static struct push_notification_txn * +push_notification_transaction_create(struct mailbox *box, + struct mailbox_transaction_context *t) +{ + struct push_notification_driver_txn *dtxn; + struct push_notification_driver_user **duser; + pool_t pool; + struct push_notification_txn *ptxn; + struct mail_storage *storage; + + pool = pool_alloconly_create("push notification transaction", 2048); + + ptxn = p_new(pool, struct push_notification_txn, 1); + ptxn->mbox = box; + storage = mailbox_get_storage(box); + ptxn->muser = mail_storage_get_user(storage); + ptxn->pool = pool; + ptxn->puser = PUSH_NOTIFICATION_USER_CONTEXT(ptxn->muser); + ptxn->t = t; + ptxn->trigger = PUSH_NOTIFICATION_EVENT_TRIGGER_NONE; + + p_array_init(&ptxn->drivers, pool, 4); + + if (storage->user->autocreated && + (strcmp(storage->name, "raw") == 0)) { + /* no notifications for autocreated raw users */ + return ptxn; + } + + array_foreach_modifiable(&ptxn->puser->drivers, duser) { + dtxn = p_new(pool, struct push_notification_driver_txn, 1); + dtxn->duser = *duser; + dtxn->ptxn = ptxn; + + if ((dtxn->duser->driver->v.begin_txn == NULL) || + dtxn->duser->driver->v.begin_txn(dtxn)) { + array_append(&ptxn->drivers, &dtxn, 1); + } + } + + return ptxn; +} + +static void push_notification_transaction_end +(struct push_notification_txn *ptxn, bool success) +{ + struct push_notification_driver_txn **dtxn; + + array_foreach_modifiable(&ptxn->drivers, dtxn) { + if ((*dtxn)->duser->driver->v.end_txn != NULL) { + (*dtxn)->duser->driver->v.end_txn(*dtxn, success); + } + } + + pool_unref(&ptxn->pool); +} + +static void push_notification_transaction_commit +(void *txn, struct mail_transaction_commit_changes *changes) +{ + struct push_notification_txn *ptxn = (struct push_notification_txn *)txn; + + if (changes == NULL) { + push_notification_txn_mbox_end(ptxn); + } else { + push_notification_txn_msg_end(ptxn, changes); + } + + push_notification_transaction_end(ptxn, TRUE); +} + +static void push_notification_mailbox_create(struct mailbox *box) +{ + struct push_notification_txn *ptxn; + + ptxn = push_notification_transaction_create(box, NULL); + push_notification_trigger_mbox_create(ptxn, box, NULL); + push_notification_transaction_commit(ptxn, NULL); +} + +static void push_notification_mailbox_delete(void *txn ATTR_UNUSED, + struct mailbox *box) +{ + struct push_notification_txn *ptxn; + + ptxn = push_notification_transaction_create(box, NULL); + push_notification_trigger_mbox_delete(ptxn, box, NULL); + push_notification_transaction_commit(ptxn, NULL); +} + +static void push_notification_mailbox_rename(struct mailbox *src, + struct mailbox *dest) +{ + struct push_notification_txn *ptxn; + + ptxn = push_notification_transaction_create(dest, NULL); + push_notification_trigger_mbox_rename(ptxn, src, dest, NULL); + push_notification_transaction_commit(ptxn, NULL); +} + +static void push_notification_mailbox_subscribe(struct mailbox *box, + bool subscribed) +{ + struct push_notification_txn *ptxn; + + ptxn = push_notification_transaction_create(box, NULL); + push_notification_trigger_mbox_subscribe(ptxn, box, subscribed, NULL); + push_notification_transaction_commit(ptxn, NULL); +} + +static void push_notification_mail_save(void *txn, struct mail *mail) +{ + struct push_notification_txn *ptxn = (struct push_notification_txn *)txn; + + /* External means a COPY or APPEND IMAP action. */ + if (ptxn->t->flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) { + push_notification_trigger_msg_save_append(ptxn, mail, NULL); + } else { + push_notification_trigger_msg_save_new(ptxn, mail, NULL); + } +} + +static void push_notification_mail_copy(void *txn, + struct mail *src ATTR_UNUSED, + struct mail *dest) +{ + push_notification_trigger_msg_save_append( + (struct push_notification_txn *)txn, dest, NULL); +} + +static void push_notification_mail_expunge(void *txn, struct mail *mail) +{ + push_notification_trigger_msg_save_expunge( + (struct push_notification_txn *)txn, mail, NULL); +} + +static void +push_notification_mail_update_flags(void *txn, struct mail *mail, + enum mail_flags old_flags) +{ + push_notification_trigger_msg_flag_change( + (struct push_notification_txn *) txn, mail, NULL, old_flags); +} + +static void +push_notification_mail_update_keywords(void *txn, struct mail *mail, + const char *const *old_keywords) +{ + push_notification_trigger_msg_keyword_change( + (struct push_notification_txn *) txn, mail, NULL, old_keywords); +} + +static void * +push_notification_transaction_begin(struct mailbox_transaction_context *t) +{ + return push_notification_transaction_create(mailbox_transaction_get_mailbox(t), t); +} + +static void push_notification_transaction_rollback(void *txn) +{ + struct push_notification_txn *ptxn = (struct push_notification_txn *)txn; + + push_notification_transaction_end(ptxn, FALSE); +} + +static void +push_notification_user_created_init_config(const char *config_name, + struct mail_user *user, + struct push_notification_user *puser) +{ + struct push_notification_driver_user *duser; + const char *env; + unsigned int i; + string_t *root_name; + + root_name = t_str_new(32); + str_append(root_name, config_name); + + for (i = 2;; i++) { + env = mail_user_plugin_getenv(user, str_c(root_name)); + if ((env == NULL) || (*env == '\0')) { + break; + } + + if (push_notification_driver_init(user, env, puser->pool, &duser) < 0) { + break; + } + + // Add driver. + array_append(&puser->drivers, &duser, 1); + + str_truncate(root_name, strlen(config_name)); + str_printfa(root_name, "%d", i); + } +} + +static void push_notification_user_created_init(struct mail_user *user) +{ + pool_t pool; + + pool = pool_alloconly_create("push notification plugin", 1024); + + puser = p_new(pool, struct push_notification_user, 1); + puser->pool = pool; + + p_array_init(&puser->drivers, pool, 4); + + push_notification_user_created_init_config(PUSH_NOTIFICATION_CONFIG, user, + puser); + + if (array_is_empty(&puser->drivers)) { + /* Support old configuration (it was available at time initial OX + * driver was first released. */ + push_notification_user_created_init_config(PUSH_NOTIFICATION_CONFIG_OLD, + user, puser); + } +} + +static void push_notification_user_created(struct mail_user *user) +{ + if (puser == NULL) { + push_notification_user_created_init(user); + } + + MODULE_CONTEXT_SET(user, push_notification_user_module, puser); +} + + +/* Plugin interface. */ + +const char *push_notification_plugin_version = DOVECOT_ABI_VERSION; +const char *push_notification_plugin_dependencies[] = { "notify", NULL }; + +extern struct push_notification_driver push_notification_driver_dlog; +extern struct push_notification_driver push_notification_driver_ox; + +static struct notify_context *push_notification_ctx; + +static const struct notify_vfuncs push_notification_vfuncs = { + /* Mailbox Events */ + .mailbox_create = push_notification_mailbox_create, + .mailbox_delete_commit = push_notification_mailbox_delete, + .mailbox_rename = push_notification_mailbox_rename, + .mailbox_set_subscribed = push_notification_mailbox_subscribe, + + /* Mail Events */ + .mail_copy = push_notification_mail_copy, + .mail_save = push_notification_mail_save, + .mail_expunge = push_notification_mail_expunge, + .mail_update_flags = push_notification_mail_update_flags, + .mail_update_keywords = push_notification_mail_update_keywords, + .mail_transaction_begin = push_notification_transaction_begin, + .mail_transaction_commit = push_notification_transaction_commit, + .mail_transaction_rollback = push_notification_transaction_rollback +}; + +static struct mail_storage_hooks push_notification_storage_hooks = { + .mail_user_created = push_notification_user_created +}; + +void push_notification_plugin_init(struct module *module) +{ + push_notification_ctx = notify_register(&push_notification_vfuncs); + mail_storage_hooks_add(module, &push_notification_storage_hooks); + + push_notification_driver_register(&push_notification_driver_dlog); + push_notification_driver_register(&push_notification_driver_ox); + + push_notification_event_register_rfc5423_events(); +} + +void push_notification_plugin_deinit(void) +{ + struct push_notification_driver_user **duser; + + if (puser != NULL) { + array_foreach_modifiable(&puser->drivers, duser) { + if ((*duser)->driver->v.deinit != NULL) { + (*duser)->driver->v.deinit(*duser); + } + + if ((*duser)->driver->v.cleanup != NULL) { + (*duser)->driver->v.cleanup(); + } + } + + array_free(&puser->drivers); + pool_unref(&puser->pool); + } + + push_notification_driver_unregister(&push_notification_driver_dlog); + push_notification_driver_unregister(&push_notification_driver_ox); + + mail_storage_hooks_remove(&push_notification_storage_hooks); + notify_unregister(push_notification_ctx); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-plugin.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,13 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_PLUGIN_H +#define PUSH_NOTIFICATION_PLUGIN_H + +extern const char *push_notification_plugin_dependencies[]; + +struct module; + +void push_notification_plugin_init(struct module *module); +void push_notification_plugin_deinit(void); + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-triggers.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,222 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" + +#include "mail-storage.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-triggers.h" +#include "push-notification-txn-mbox.h" +#include "push-notification-txn-msg.h" + + +static void +push_notification_trigger_mbox_common(struct push_notification_txn *txn, + struct mailbox *box, + struct push_notification_txn_mbox **mbox, + enum push_notification_event_trigger trigger) +{ + if (*mbox == NULL) { + *mbox = push_notification_txn_mbox_create(txn, box); + } + + txn->trigger |= trigger; +} + +void +push_notification_trigger_mbox_create(struct push_notification_txn *txn, + struct mailbox *box, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_mbox_common(txn, box, &mbox, + PUSH_NOTIFICATION_EVENT_TRIGGER_MBOX_CREATE); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if ((*ec)->event->mbox_triggers.create != NULL) { + (*ec)->event->mbox_triggers.create(txn, *ec, mbox); + } + } + } +} + +void +push_notification_trigger_mbox_delete(struct push_notification_txn *txn, + struct mailbox *box, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_mbox_common(txn, box, &mbox, + PUSH_NOTIFICATION_EVENT_TRIGGER_MBOX_DELETE); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if ((*ec)->event->mbox_triggers.delete != NULL) { + (*ec)->event->mbox_triggers.delete(txn, *ec, mbox); + } + } + } +} + +void +push_notification_trigger_mbox_rename(struct push_notification_txn *txn, + struct mailbox *src, + struct mailbox *dest, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_mbox_common(txn, dest, &mbox, + PUSH_NOTIFICATION_EVENT_TRIGGER_MBOX_RENAME); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if ((*ec)->event->mbox_triggers.rename != NULL) { + (*ec)->event->mbox_triggers.rename(txn, *ec, mbox, src); + } + } + } +} + +void +push_notification_trigger_mbox_subscribe(struct push_notification_txn *txn, + struct mailbox *box, + bool subscribed, + struct push_notification_txn_mbox *mbox) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_mbox_common(txn, box, &mbox, + PUSH_NOTIFICATION_EVENT_TRIGGER_MBOX_SUBSCRIBE); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if (subscribed == TRUE) { + if ((*ec)->event->mbox_triggers.subscribe != NULL) { + (*ec)->event->mbox_triggers.subscribe(txn, *ec, mbox); + } + } else { + if ((*ec)->event->mbox_triggers.unsubscribe != NULL) { + (*ec)->event->mbox_triggers.unsubscribe(txn, *ec, mbox); + } + } + } + } +} + +static void +push_notification_trigger_msg_common(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg **msg, + enum push_notification_event_trigger trigger) +{ + if (*msg == NULL) { + *msg = push_notification_txn_msg_create(txn, mail); + } + + txn->trigger |= trigger; +} + +void +push_notification_trigger_msg_save_new(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_msg_common(txn, mail, &msg, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_SAVE_NEW); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if ((*ec)->event->msg_triggers.save != NULL) { + (*ec)->event->msg_triggers.save(txn, *ec, msg, mail); + } + } + } +} + +void +push_notification_trigger_msg_save_append(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_msg_common(txn, mail, &msg, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_SAVE_APPEND); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if ((*ec)->event->msg_triggers.append != NULL) { + (*ec)->event->msg_triggers.append(txn, *ec, msg, mail); + } + } + } +} + +void +push_notification_trigger_msg_save_expunge(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_msg_common(txn, mail, &msg, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_EXPUNGE); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if ((*ec)->event->msg_triggers.expunge != NULL) { + (*ec)->event->msg_triggers.expunge(txn, *ec, msg); + } + } + } +} + +void +push_notification_trigger_msg_flag_change(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg, + enum mail_flags old_flags) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_msg_common(txn, mail, &msg, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_FLAGCHANGE); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if ((*ec)->event->msg_triggers.flagchange != NULL) { + (*ec)->event->msg_triggers.flagchange(txn, *ec, msg, mail, + old_flags); + } + } + } +} + +void +push_notification_trigger_msg_keyword_change(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg, + const char *const *old_keywords) +{ + struct push_notification_event_config **ec; + + push_notification_trigger_msg_common(txn, mail, &msg, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_KEYWORDCHANGE); + + if (array_is_created(&txn->events)) { + array_foreach_modifiable(&txn->events, ec) { + if ((*ec)->event->msg_triggers.keywordchange != NULL) { + (*ec)->event->msg_triggers.keywordchange(txn, *ec, msg, mail, + old_keywords); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-triggers.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,78 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_TRIGGERS_H +#define PUSH_NOTIFICATION_TRIGGERS_H + +#include "mail-types.h" + +struct mail; +struct mailbox; +struct push_notification_txn; +struct push_notification_txn_mbox; +struct push_notification_txn_msg; + + +enum push_notification_event_trigger { + PUSH_NOTIFICATION_EVENT_TRIGGER_NONE, + + /* Mailbox actions */ + PUSH_NOTIFICATION_EVENT_TRIGGER_MBOX_CREATE = 0x001, + PUSH_NOTIFICATION_EVENT_TRIGGER_MBOX_DELETE = 0x002, + PUSH_NOTIFICATION_EVENT_TRIGGER_MBOX_RENAME = 0x004, + PUSH_NOTIFICATION_EVENT_TRIGGER_MBOX_SUBSCRIBE = 0x008, + + /* Message actions */ + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_SAVE_NEW = 0x010, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_SAVE_APPEND = 0x020, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_EXPUNGE = 0x040, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_FLAGCHANGE = 0x080, + PUSH_NOTIFICATION_EVENT_TRIGGER_MSG_KEYWORDCHANGE = 0x100, +}; + +/* Mailbox actions. */ +void +push_notification_trigger_mbox_create(struct push_notification_txn *txn, + struct mailbox *box, + struct push_notification_txn_mbox *mbox); +void +push_notification_trigger_mbox_delete(struct push_notification_txn *txn, + struct mailbox *box, + struct push_notification_txn_mbox *mbox); +void +push_notification_trigger_mbox_rename(struct push_notification_txn *txn, + struct mailbox *src, + struct mailbox *dest, + struct push_notification_txn_mbox *mbox); +void +push_notification_trigger_mbox_subscribe(struct push_notification_txn *txn, + struct mailbox *box, + bool subscribed, + struct push_notification_txn_mbox *mbox); + +/* Message actions. */ +void +push_notification_trigger_msg_save_new(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg); +void +push_notification_trigger_msg_save_append(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg); +void +push_notification_trigger_msg_save_expunge(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg); +void +push_notification_trigger_msg_flag_change(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg, + enum mail_flags old_flags); +void +push_notification_trigger_msg_keyword_change(struct push_notification_txn *txn, + struct mail *mail, + struct push_notification_txn_msg *msg, + const char *const *old_keywords); + + +#endif /* PUSH_NOTIFICATION_TRIGGERS_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-txn-mbox.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,90 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hash.h" +#include "mail-storage-private.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-txn-mbox.h" + + +struct push_notification_txn_mbox * +push_notification_txn_mbox_create(struct push_notification_txn *txn, + struct mailbox *box) +{ + if (txn->mbox_txn == NULL) { + txn->mbox_txn = p_new(txn->pool, struct push_notification_txn_mbox, 1); + txn->mbox_txn->mailbox = mailbox_get_vname(box); + } + + return txn->mbox_txn; +} + +void +push_notification_txn_mbox_end(struct push_notification_txn *ptxn) +{ + struct push_notification_driver_txn **dtxn; + + if (ptxn->mbox_txn != NULL) { + array_foreach_modifiable(&ptxn->drivers, dtxn) { + if ((*dtxn)->duser->driver->v.process_mbox != NULL) { + (*dtxn)->duser->driver->v.process_mbox(*dtxn, ptxn->mbox_txn); + } + } + + push_notification_txn_mbox_deinit_eventdata(ptxn->mbox_txn); + } +} + +void * +push_notification_txn_mbox_get_eventdata(struct push_notification_txn_mbox *mbox, + const char *event_name) +{ + struct push_notification_txn_event **mevent; + + if (array_is_created(&mbox->eventdata)) { + array_foreach_modifiable(&mbox->eventdata, mevent) { + if (strcmp((*mevent)->event->event->name, event_name) == 0) { + return (*mevent)->data; + } + } + } + + return NULL; +} + +void +push_notification_txn_mbox_set_eventdata(struct push_notification_txn *txn, + struct push_notification_txn_mbox *mbox, + struct push_notification_event_config *event, + void *data) +{ + struct push_notification_txn_event *mevent; + + if (!array_is_created(&mbox->eventdata)) { + p_array_init(&mbox->eventdata, txn->pool, 4); + } + + mevent = p_new(txn->pool, struct push_notification_txn_event, 1); + mevent->data = data; + mevent->event = event; + + array_append(&mbox->eventdata, &mevent, 1); +} + +void +push_notification_txn_mbox_deinit_eventdata +(struct push_notification_txn_mbox *mbox) +{ + struct push_notification_txn_event **mevent; + + if (array_is_created(&mbox->eventdata)) { + array_foreach_modifiable(&mbox->eventdata, mevent) { + if (((*mevent)->data != NULL) && + ((*mevent)->event->event->mbox.free_mbox != NULL)) { + (*mevent)->event->event->mbox.free_mbox(*mevent); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-txn-mbox.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,34 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_TXN_MBOX_H +#define PUSH_NOTIFICATION_TXN_MBOX_H + + +struct push_notification_txn_event; + +struct push_notification_txn_mbox { + const char *mailbox; + + ARRAY(struct push_notification_txn_event *) eventdata; +}; + + +struct push_notification_txn_mbox * +push_notification_txn_mbox_create(struct push_notification_txn *txn, + struct mailbox *box); +void +push_notification_txn_mbox_end(struct push_notification_txn *ptxn); + +void * +push_notification_txn_mbox_get_eventdata(struct push_notification_txn_mbox *mbox, + const char *event_name); +void +push_notification_txn_mbox_set_eventdata(struct push_notification_txn *txn, + struct push_notification_txn_mbox *mbox, + struct push_notification_event_config *event, + void *data); +void +push_notification_txn_mbox_deinit_eventdata(struct push_notification_txn_mbox *mbox); + + +#endif /* PUSH_NOTIFICATION_TXN_MBOX_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-txn-msg.c Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,135 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "hash.h" +#include "mail-storage-private.h" + +#include "push-notification-drivers.h" +#include "push-notification-events.h" +#include "push-notification-txn-msg.h" + + +struct push_notification_txn_msg * +push_notification_txn_msg_create(struct push_notification_txn *txn, + struct mail *mail) +{ + struct push_notification_txn_msg *msg = NULL; + + if (hash_table_is_created(txn->messages)) { + msg = hash_table_lookup(txn->messages, + POINTER_CAST(txn->t->save_count + 1)); + } else { + hash_table_create_direct(&txn->messages, txn->pool, 4); + } + + if (msg == NULL) { + msg = p_new(txn->pool, struct push_notification_txn_msg, 1); + msg->mailbox = mailbox_get_vname(mail->box); + /* Save sequence number - used to determine UID later. */ + msg->seq = txn->t->save_count; + msg->uid = mail->uid; + + hash_table_insert(txn->messages, POINTER_CAST(txn->t->save_count + 1), + msg); + } + + return msg; +} + +void +push_notification_txn_msg_end(struct push_notification_txn *ptxn, + struct mail_transaction_commit_changes *changes) +{ + struct hash_iterate_context *hiter; + void *key; + struct push_notification_driver_txn **dtxn; + struct seq_range_iter siter; + struct mailbox_status status; + uint32_t uid; + struct push_notification_txn_msg *value; + + if (!hash_table_is_created(ptxn->messages)) { + return; + } + + hiter = hash_table_iterate_init(ptxn->messages); + seq_range_array_iter_init(&siter, &changes->saved_uids); + + while (hash_table_iterate(hiter, ptxn->messages, &key, &value)) { + if (value->uid == 0) { + if (seq_range_array_iter_nth(&siter, value->seq, &uid)) { + value->uid = uid; + } + } + + /* uid_validity is only set in changes if message is new. */ + if (changes->uid_validity == 0) { + mailbox_get_open_status(ptxn->mbox, STATUS_UIDVALIDITY, &status); + value->uid_validity = status.uidvalidity; + } else { + value->uid_validity = changes->uid_validity; + } + + array_foreach_modifiable(&ptxn->drivers, dtxn) { + if ((*dtxn)->duser->driver->v.process_msg != NULL) { + (*dtxn)->duser->driver->v.process_msg(*dtxn, value); + } + } + + push_notification_txn_msg_deinit_eventdata(value); + } + + hash_table_iterate_deinit(&hiter); + hash_table_destroy(&ptxn->messages); +} + +void * +push_notification_txn_msg_get_eventdata(struct push_notification_txn_msg *msg, + const char *event_name) +{ + struct push_notification_txn_event **mevent; + + if (array_is_created(&msg->eventdata)) { + array_foreach_modifiable(&msg->eventdata, mevent) { + if (strcmp((*mevent)->event->event->name, event_name) == 0) { + return (*mevent)->data; + } + } + } + + return NULL; +} + +void +push_notification_txn_msg_set_eventdata(struct push_notification_txn *txn, + struct push_notification_txn_msg *msg, + struct push_notification_event_config *event, + void *data) +{ + struct push_notification_txn_event *mevent; + + if (!array_is_created(&msg->eventdata)) { + p_array_init(&msg->eventdata, txn->pool, 4); + } + + mevent = p_new(txn->pool, struct push_notification_txn_event, 1); + mevent->data = data; + mevent->event = event; + + array_append(&msg->eventdata, &mevent, 1); +} + +void +push_notification_txn_msg_deinit_eventdata(struct push_notification_txn_msg *msg) +{ + struct push_notification_txn_event **mevent; + + if (array_is_created(&msg->eventdata)) { + array_foreach_modifiable(&msg->eventdata, mevent) { + if (((*mevent)->data != NULL) && + ((*mevent)->event->event->msg.free_msg != NULL)) { + (*mevent)->event->event->msg.free_msg(*mevent); + } + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/push-notification/push-notification-txn-msg.h Tue Sep 22 22:33:41 2015 -0600 @@ -0,0 +1,43 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#ifndef PUSH_NOTIFICATION_TXN_MSG_H +#define PUSH_NOTIFICATION_TXN_MSG_H + + +struct mail_transaction_commit_changes; +struct push_notification_event_config; +struct push_notification_txn; +struct push_notification_txn_event; + +struct push_notification_txn_msg { + const char *mailbox; + uint32_t uid; + uint32_t uid_validity; + + ARRAY(struct push_notification_txn_event *) eventdata; + + /* Private */ + unsigned int seq; +}; + + +struct push_notification_txn_msg * +push_notification_txn_msg_create(struct push_notification_txn *txn, + struct mail *mail); +void +push_notification_txn_msg_end(struct push_notification_txn *ptxn, + struct mail_transaction_commit_changes *changes); + +void * +push_notification_txn_msg_get_eventdata(struct push_notification_txn_msg *msg, + const char *event_name); +void +push_notification_txn_msg_set_eventdata(struct push_notification_txn *txn, + struct push_notification_txn_msg *msg, + struct push_notification_event_config *event, + void *data); +void +push_notification_txn_msg_deinit_eventdata(struct push_notification_txn_msg *msg); + + +#endif /* PUSH_NOTIFICATION_TXN_MSG_H */