summaryrefslogtreecommitdiffstats
path: root/src/plugins/push-notification
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 09:51:24 +0000
commitf7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch)
treea3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/plugins/push-notification
parentInitial commit. (diff)
downloaddovecot-upstream.tar.xz
dovecot-upstream.zip
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/plugins/push-notification/Makefile.am83
-rw-r--r--src/plugins/push-notification/Makefile.in1037
-rw-r--r--src/plugins/push-notification/push-notification-driver-dlog.c114
-rw-r--r--src/plugins/push-notification/push-notification-driver-lua.c663
-rw-r--r--src/plugins/push-notification/push-notification-driver-ox.c470
-rw-r--r--src/plugins/push-notification/push-notification-drivers.c181
-rw-r--r--src/plugins/push-notification/push-notification-drivers.h123
-rw-r--r--src/plugins/push-notification/push-notification-event-flagsclear.c170
-rw-r--r--src/plugins/push-notification/push-notification-event-flagsclear.h22
-rw-r--r--src/plugins/push-notification/push-notification-event-flagsset.c167
-rw-r--r--src/plugins/push-notification/push-notification-event-flagsset.h22
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxcreate.c56
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxcreate.h12
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxdelete.c46
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxdelete.h12
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxrename.c50
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxrename.h11
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxsubscribe.c48
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxsubscribe.h12
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxunsubscribe.c48
-rw-r--r--src/plugins/push-notification/push-notification-event-mailboxunsubscribe.h12
-rw-r--r--src/plugins/push-notification/push-notification-event-message-common.c117
-rw-r--r--src/plugins/push-notification/push-notification-event-message-common.h40
-rw-r--r--src/plugins/push-notification/push-notification-event-messageappend.c99
-rw-r--r--src/plugins/push-notification/push-notification-event-messageappend.h30
-rw-r--r--src/plugins/push-notification/push-notification-event-messageexpunge.c53
-rw-r--r--src/plugins/push-notification/push-notification-event-messageexpunge.h12
-rw-r--r--src/plugins/push-notification/push-notification-event-messagenew.c97
-rw-r--r--src/plugins/push-notification/push-notification-event-messagenew.h36
-rw-r--r--src/plugins/push-notification/push-notification-event-messageread.c58
-rw-r--r--src/plugins/push-notification/push-notification-event-messageread.h11
-rw-r--r--src/plugins/push-notification/push-notification-event-messagetrash.c58
-rw-r--r--src/plugins/push-notification/push-notification-event-messagetrash.h12
-rw-r--r--src/plugins/push-notification/push-notification-events-rfc5423.c59
-rw-r--r--src/plugins/push-notification/push-notification-events-rfc5423.h10
-rw-r--r--src/plugins/push-notification/push-notification-events.c100
-rw-r--r--src/plugins/push-notification/push-notification-events.h124
-rw-r--r--src/plugins/push-notification/push-notification-plugin.c390
-rw-r--r--src/plugins/push-notification/push-notification-plugin.h18
-rw-r--r--src/plugins/push-notification/push-notification-triggers.c215
-rw-r--r--src/plugins/push-notification/push-notification-triggers.h64
-rw-r--r--src/plugins/push-notification/push-notification-txn-mbox.c90
-rw-r--r--src/plugins/push-notification/push-notification-txn-mbox.h29
-rw-r--r--src/plugins/push-notification/push-notification-txn-msg.c139
-rw-r--r--src/plugins/push-notification/push-notification-txn-msg.h39
45 files changed, 5259 insertions, 0 deletions
diff --git a/src/plugins/push-notification/Makefile.am b/src/plugins/push-notification/Makefile.am
new file mode 100644
index 0000000..c065e38
--- /dev/null
+++ b/src/plugins/push-notification/Makefile.am
@@ -0,0 +1,83 @@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
+ -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/lib-ssl-iostream \
+ -I$(top_srcdir)/src/plugins/notify
+
+NOPLUGIN_LDFLAGS =
+lib20_push_notification_plugin_la_LDFLAGS = -module -avoid-version
+
+module_LTLIBRARIES = lib20_push_notification_plugin.la
+
+if DOVECOT_PLUGIN_DEPS
+notify_deps = ../notify/lib15_notify_plugin.la
+endif
+
+lib20_push_notification_plugin_la_LIBADD = \
+ $(notify_deps)
+
+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-event-message-common.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)
+
+if HAVE_LUA
+lib22_push_notification_lua_plugin_la_CFLAGS = $(AM_CPPFLAGS) \
+ -I$(top_srcdir)/src/lib-lua \
+ -I$(top_srcdir)/src/plugins/mail-lua \
+ $(LUA_CFLAGS)
+lib22_push_notification_lua_plugin_la_LDFLAGS = module -avoid-version
+module_LTLIBRARIES += \
+ lib22_push_notification_lua_plugin.la
+lib22_push_notification_lua_plugin_la_LIBADD = $(notify_deps) $(LUA_LIBS)
+lib22_push_notification_lua_plugin_la_SOURCES = \
+ push-notification-driver-lua.c
+endif
diff --git a/src/plugins/push-notification/Makefile.in b/src/plugins/push-notification/Makefile.in
new file mode 100644
index 0000000..f785877
--- /dev/null
+++ b/src/plugins/push-notification/Makefile.in
@@ -0,0 +1,1037 @@
+# Makefile.in generated by automake 1.16.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2018 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_LUA_TRUE@am__append_1 = \
+@HAVE_LUA_TRUE@ lib22_push_notification_lua_plugin.la
+
+subdir = src/plugins/push-notification
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/ac_checktype2.m4 \
+ $(top_srcdir)/m4/ac_typeof.m4 $(top_srcdir)/m4/arc4random.m4 \
+ $(top_srcdir)/m4/blockdev.m4 $(top_srcdir)/m4/c99_vsnprintf.m4 \
+ $(top_srcdir)/m4/clock_gettime.m4 $(top_srcdir)/m4/crypt.m4 \
+ $(top_srcdir)/m4/crypt_xpg6.m4 $(top_srcdir)/m4/dbqlk.m4 \
+ $(top_srcdir)/m4/dirent_dtype.m4 $(top_srcdir)/m4/dovecot.m4 \
+ $(top_srcdir)/m4/fd_passing.m4 $(top_srcdir)/m4/fdatasync.m4 \
+ $(top_srcdir)/m4/flexible_array_member.m4 \
+ $(top_srcdir)/m4/glibc.m4 $(top_srcdir)/m4/gmtime_max.m4 \
+ $(top_srcdir)/m4/gmtime_tm_gmtoff.m4 \
+ $(top_srcdir)/m4/ioloop.m4 $(top_srcdir)/m4/iovec.m4 \
+ $(top_srcdir)/m4/ipv6.m4 $(top_srcdir)/m4/libcap.m4 \
+ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/libwrap.m4 \
+ $(top_srcdir)/m4/linux_mremap.m4 $(top_srcdir)/m4/ltoptions.m4 \
+ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+ $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mmap_write.m4 \
+ $(top_srcdir)/m4/mntctl.m4 $(top_srcdir)/m4/modules.m4 \
+ $(top_srcdir)/m4/notify.m4 $(top_srcdir)/m4/nsl.m4 \
+ $(top_srcdir)/m4/off_t_max.m4 $(top_srcdir)/m4/pkg.m4 \
+ $(top_srcdir)/m4/pr_set_dumpable.m4 \
+ $(top_srcdir)/m4/q_quotactl.m4 $(top_srcdir)/m4/quota.m4 \
+ $(top_srcdir)/m4/random.m4 $(top_srcdir)/m4/rlimit.m4 \
+ $(top_srcdir)/m4/sendfile.m4 $(top_srcdir)/m4/size_t_signed.m4 \
+ $(top_srcdir)/m4/sockpeercred.m4 $(top_srcdir)/m4/sql.m4 \
+ $(top_srcdir)/m4/ssl.m4 $(top_srcdir)/m4/st_tim.m4 \
+ $(top_srcdir)/m4/static_array.m4 $(top_srcdir)/m4/test_with.m4 \
+ $(top_srcdir)/m4/time_t.m4 $(top_srcdir)/m4/typeof.m4 \
+ $(top_srcdir)/m4/typeof_dev_t.m4 \
+ $(top_srcdir)/m4/uoff_t_max.m4 $(top_srcdir)/m4/vararg.m4 \
+ $(top_srcdir)/m4/want_apparmor.m4 \
+ $(top_srcdir)/m4/want_bsdauth.m4 \
+ $(top_srcdir)/m4/want_bzlib.m4 \
+ $(top_srcdir)/m4/want_cassandra.m4 \
+ $(top_srcdir)/m4/want_cdb.m4 \
+ $(top_srcdir)/m4/want_checkpassword.m4 \
+ $(top_srcdir)/m4/want_clucene.m4 $(top_srcdir)/m4/want_db.m4 \
+ $(top_srcdir)/m4/want_gssapi.m4 $(top_srcdir)/m4/want_icu.m4 \
+ $(top_srcdir)/m4/want_ldap.m4 $(top_srcdir)/m4/want_lua.m4 \
+ $(top_srcdir)/m4/want_lz4.m4 $(top_srcdir)/m4/want_lzma.m4 \
+ $(top_srcdir)/m4/want_mysql.m4 $(top_srcdir)/m4/want_pam.m4 \
+ $(top_srcdir)/m4/want_passwd.m4 $(top_srcdir)/m4/want_pgsql.m4 \
+ $(top_srcdir)/m4/want_prefetch.m4 \
+ $(top_srcdir)/m4/want_shadow.m4 \
+ $(top_srcdir)/m4/want_sodium.m4 $(top_srcdir)/m4/want_solr.m4 \
+ $(top_srcdir)/m4/want_sqlite.m4 \
+ $(top_srcdir)/m4/want_stemmer.m4 \
+ $(top_srcdir)/m4/want_systemd.m4 \
+ $(top_srcdir)/m4/want_textcat.m4 \
+ $(top_srcdir)/m4/want_unwind.m4 $(top_srcdir)/m4/want_zlib.m4 \
+ $(top_srcdir)/m4/want_zstd.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(pkginc_lib_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(moduledir)" \
+ "$(DESTDIR)$(pkginc_libdir)"
+LTLIBRARIES = $(module_LTLIBRARIES)
+lib20_push_notification_plugin_la_DEPENDENCIES = $(notify_deps)
+am_lib20_push_notification_plugin_la_OBJECTS = \
+ push-notification-driver-dlog.lo \
+ push-notification-driver-ox.lo push-notification-drivers.lo \
+ push-notification-event-flagsclear.lo \
+ push-notification-event-flagsset.lo \
+ push-notification-event-mailboxcreate.lo \
+ push-notification-event-mailboxdelete.lo \
+ push-notification-event-mailboxrename.lo \
+ push-notification-event-mailboxsubscribe.lo \
+ push-notification-event-mailboxunsubscribe.lo \
+ push-notification-event-messageappend.lo \
+ push-notification-event-messageexpunge.lo \
+ push-notification-event-messagenew.lo \
+ push-notification-event-messageread.lo \
+ push-notification-event-messagetrash.lo \
+ push-notification-event-message-common.lo \
+ push-notification-events.lo \
+ push-notification-events-rfc5423.lo \
+ push-notification-plugin.lo push-notification-triggers.lo \
+ push-notification-txn-mbox.lo push-notification-txn-msg.lo
+lib20_push_notification_plugin_la_OBJECTS = \
+ $(am_lib20_push_notification_plugin_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+lib20_push_notification_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(lib20_push_notification_plugin_la_LDFLAGS) $(LDFLAGS) -o $@
+am__DEPENDENCIES_1 =
+@HAVE_LUA_TRUE@lib22_push_notification_lua_plugin_la_DEPENDENCIES = \
+@HAVE_LUA_TRUE@ $(notify_deps) $(am__DEPENDENCIES_1)
+am__lib22_push_notification_lua_plugin_la_SOURCES_DIST = \
+ push-notification-driver-lua.c
+@HAVE_LUA_TRUE@am_lib22_push_notification_lua_plugin_la_OBJECTS = lib22_push_notification_lua_plugin_la-push-notification-driver-lua.lo
+lib22_push_notification_lua_plugin_la_OBJECTS = \
+ $(am_lib22_push_notification_lua_plugin_la_OBJECTS)
+lib22_push_notification_lua_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(lib22_push_notification_lua_plugin_la_CFLAGS) \
+ $(CFLAGS) $(lib22_push_notification_lua_plugin_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@HAVE_LUA_TRUE@am_lib22_push_notification_lua_plugin_la_rpath = \
+@HAVE_LUA_TRUE@ -rpath $(moduledir)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/lib22_push_notification_lua_plugin_la-push-notification-driver-lua.Plo \
+ ./$(DEPDIR)/push-notification-driver-dlog.Plo \
+ ./$(DEPDIR)/push-notification-driver-ox.Plo \
+ ./$(DEPDIR)/push-notification-drivers.Plo \
+ ./$(DEPDIR)/push-notification-event-flagsclear.Plo \
+ ./$(DEPDIR)/push-notification-event-flagsset.Plo \
+ ./$(DEPDIR)/push-notification-event-mailboxcreate.Plo \
+ ./$(DEPDIR)/push-notification-event-mailboxdelete.Plo \
+ ./$(DEPDIR)/push-notification-event-mailboxrename.Plo \
+ ./$(DEPDIR)/push-notification-event-mailboxsubscribe.Plo \
+ ./$(DEPDIR)/push-notification-event-mailboxunsubscribe.Plo \
+ ./$(DEPDIR)/push-notification-event-message-common.Plo \
+ ./$(DEPDIR)/push-notification-event-messageappend.Plo \
+ ./$(DEPDIR)/push-notification-event-messageexpunge.Plo \
+ ./$(DEPDIR)/push-notification-event-messagenew.Plo \
+ ./$(DEPDIR)/push-notification-event-messageread.Plo \
+ ./$(DEPDIR)/push-notification-event-messagetrash.Plo \
+ ./$(DEPDIR)/push-notification-events-rfc5423.Plo \
+ ./$(DEPDIR)/push-notification-events.Plo \
+ ./$(DEPDIR)/push-notification-plugin.Plo \
+ ./$(DEPDIR)/push-notification-triggers.Plo \
+ ./$(DEPDIR)/push-notification-txn-mbox.Plo \
+ ./$(DEPDIR)/push-notification-txn-msg.Plo
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(lib20_push_notification_plugin_la_SOURCES) \
+ $(lib22_push_notification_lua_plugin_la_SOURCES)
+DIST_SOURCES = $(lib20_push_notification_plugin_la_SOURCES) \
+ $(am__lib22_push_notification_lua_plugin_la_SOURCES_DIST)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(pkginc_lib_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_LIBS = @APPARMOR_LIBS@
+AR = @AR@
+AUTH_CFLAGS = @AUTH_CFLAGS@
+AUTH_LIBS = @AUTH_LIBS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BINARY_CFLAGS = @BINARY_CFLAGS@
+BINARY_LDFLAGS = @BINARY_LDFLAGS@
+BISON = @BISON@
+CASSANDRA_CFLAGS = @CASSANDRA_CFLAGS@
+CASSANDRA_LIBS = @CASSANDRA_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CLUCENE_CFLAGS = @CLUCENE_CFLAGS@
+CLUCENE_LIBS = @CLUCENE_LIBS@
+COMPRESS_LIBS = @COMPRESS_LIBS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CRYPT_LIBS = @CRYPT_LIBS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DICT_LIBS = @DICT_LIBS@
+DLLIB = @DLLIB@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FLEX = @FLEX@
+FUZZER_CPPFLAGS = @FUZZER_CPPFLAGS@
+FUZZER_LDFLAGS = @FUZZER_LDFLAGS@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+KRB5CONFIG = @KRB5CONFIG@
+KRB5_CFLAGS = @KRB5_CFLAGS@
+KRB5_LIBS = @KRB5_LIBS@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LD_NO_WHOLE_ARCHIVE = @LD_NO_WHOLE_ARCHIVE@
+LD_WHOLE_ARCHIVE = @LD_WHOLE_ARCHIVE@
+LIBCAP = @LIBCAP@
+LIBDOVECOT = @LIBDOVECOT@
+LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@
+LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@
+LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@
+LIBDOVECOT_LA_LIBS = @LIBDOVECOT_LA_LIBS@
+LIBDOVECOT_LDA = @LIBDOVECOT_LDA@
+LIBDOVECOT_LDAP = @LIBDOVECOT_LDAP@
+LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@
+LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@
+LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@
+LIBDOVECOT_LUA = @LIBDOVECOT_LUA@
+LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@
+LIBDOVECOT_SQL = @LIBDOVECOT_SQL@
+LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@
+LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@
+LIBEXTTEXTCAT_CFLAGS = @LIBEXTTEXTCAT_CFLAGS@
+LIBEXTTEXTCAT_LIBS = @LIBEXTTEXTCAT_LIBS@
+LIBICONV = @LIBICONV@
+LIBICU_CFLAGS = @LIBICU_CFLAGS@
+LIBICU_LIBS = @LIBICU_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTIRPC_CFLAGS = @LIBTIRPC_CFLAGS@
+LIBTIRPC_LIBS = @LIBTIRPC_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBWRAP_LIBS = @LIBWRAP_LIBS@
+LINKED_STORAGE_LDADD = @LINKED_STORAGE_LDADD@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBOBJS = @LTLIBOBJS@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MODULE_LIBS = @MODULE_LIBS@
+MODULE_SUFFIX = @MODULE_SUFFIX@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_CONFIG = @MYSQL_CONFIG@
+MYSQL_LIBS = @MYSQL_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NOPLUGIN_LDFLAGS =
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_CFLAGS = @PGSQL_CFLAGS@
+PGSQL_LIBS = @PGSQL_LIBS@
+PG_CONFIG = @PG_CONFIG@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+QUOTA_LIBS = @QUOTA_LIBS@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+RPCGEN = @RPCGEN@
+RUN_TEST = @RUN_TEST@
+SED = @SED@
+SETTING_FILES = @SETTING_FILES@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE_CFLAGS = @SQLITE_CFLAGS@
+SQLITE_LIBS = @SQLITE_LIBS@
+SQL_CFLAGS = @SQL_CFLAGS@
+SQL_LIBS = @SQL_LIBS@
+SSL_CFLAGS = @SSL_CFLAGS@
+SSL_LIBS = @SSL_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+VALGRIND = @VALGRIND@
+VERSION = @VERSION@
+ZSTD_CFLAGS = @ZSTD_CFLAGS@
+ZSTD_LIBS = @ZSTD_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+dict_drivers = @dict_drivers@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledir = @moduledir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+rundir = @rundir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sql_drivers = @sql_drivers@
+srcdir = @srcdir@
+ssldir = @ssldir@
+statedir = @statedir@
+sysconfdir = @sysconfdir@
+systemdservicetype = @systemdservicetype@
+systemdsystemunitdir = @systemdsystemunitdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src/lib \
+ -I$(top_srcdir)/src/lib-settings \
+ -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/lib-ssl-iostream \
+ -I$(top_srcdir)/src/plugins/notify
+
+lib20_push_notification_plugin_la_LDFLAGS = -module -avoid-version
+module_LTLIBRARIES = lib20_push_notification_plugin.la $(am__append_1)
+@DOVECOT_PLUGIN_DEPS_TRUE@notify_deps = ../notify/lib15_notify_plugin.la
+lib20_push_notification_plugin_la_LIBADD = \
+ $(notify_deps)
+
+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-event-message-common.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)
+@HAVE_LUA_TRUE@lib22_push_notification_lua_plugin_la_CFLAGS = $(AM_CPPFLAGS) \
+@HAVE_LUA_TRUE@ -I$(top_srcdir)/src/lib-lua \
+@HAVE_LUA_TRUE@ -I$(top_srcdir)/src/plugins/mail-lua \
+@HAVE_LUA_TRUE@ $(LUA_CFLAGS)
+
+@HAVE_LUA_TRUE@lib22_push_notification_lua_plugin_la_LDFLAGS = module -avoid-version
+@HAVE_LUA_TRUE@lib22_push_notification_lua_plugin_la_LIBADD = $(notify_deps) $(LUA_LIBS)
+@HAVE_LUA_TRUE@lib22_push_notification_lua_plugin_la_SOURCES = \
+@HAVE_LUA_TRUE@ push-notification-driver-lua.c
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/push-notification/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/plugins/push-notification/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-moduleLTLIBRARIES: $(module_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(module_LTLIBRARIES)'; test -n "$(moduledir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(moduledir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(moduledir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(moduledir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(moduledir)"; \
+ }
+
+uninstall-moduleLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(module_LTLIBRARIES)'; test -n "$(moduledir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(moduledir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(moduledir)/$$f"; \
+ done
+
+clean-moduleLTLIBRARIES:
+ -test -z "$(module_LTLIBRARIES)" || rm -f $(module_LTLIBRARIES)
+ @list='$(module_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+lib20_push_notification_plugin.la: $(lib20_push_notification_plugin_la_OBJECTS) $(lib20_push_notification_plugin_la_DEPENDENCIES) $(EXTRA_lib20_push_notification_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib20_push_notification_plugin_la_LINK) -rpath $(moduledir) $(lib20_push_notification_plugin_la_OBJECTS) $(lib20_push_notification_plugin_la_LIBADD) $(LIBS)
+
+lib22_push_notification_lua_plugin.la: $(lib22_push_notification_lua_plugin_la_OBJECTS) $(lib22_push_notification_lua_plugin_la_DEPENDENCIES) $(EXTRA_lib22_push_notification_lua_plugin_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(lib22_push_notification_lua_plugin_la_LINK) $(am_lib22_push_notification_lua_plugin_la_rpath) $(lib22_push_notification_lua_plugin_la_OBJECTS) $(lib22_push_notification_lua_plugin_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib22_push_notification_lua_plugin_la-push-notification-driver-lua.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-driver-dlog.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-driver-ox.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-drivers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-flagsclear.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-flagsset.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-mailboxcreate.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-mailboxdelete.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-mailboxrename.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-mailboxsubscribe.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-mailboxunsubscribe.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-message-common.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-messageappend.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-messageexpunge.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-messagenew.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-messageread.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-event-messagetrash.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-events-rfc5423.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-events.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-plugin.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-triggers.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-txn-mbox.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/push-notification-txn-msg.Plo@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+lib22_push_notification_lua_plugin_la-push-notification-driver-lua.lo: push-notification-driver-lua.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib22_push_notification_lua_plugin_la_CFLAGS) $(CFLAGS) -MT lib22_push_notification_lua_plugin_la-push-notification-driver-lua.lo -MD -MP -MF $(DEPDIR)/lib22_push_notification_lua_plugin_la-push-notification-driver-lua.Tpo -c -o lib22_push_notification_lua_plugin_la-push-notification-driver-lua.lo `test -f 'push-notification-driver-lua.c' || echo '$(srcdir)/'`push-notification-driver-lua.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib22_push_notification_lua_plugin_la-push-notification-driver-lua.Tpo $(DEPDIR)/lib22_push_notification_lua_plugin_la-push-notification-driver-lua.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='push-notification-driver-lua.c' object='lib22_push_notification_lua_plugin_la-push-notification-driver-lua.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(lib22_push_notification_lua_plugin_la_CFLAGS) $(CFLAGS) -c -o lib22_push_notification_lua_plugin_la-push-notification-driver-lua.lo `test -f 'push-notification-driver-lua.c' || echo '$(srcdir)/'`push-notification-driver-lua.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
+ done
+
+uninstall-pkginc_libHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(moduledir)" "$(DESTDIR)$(pkginc_libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-moduleLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/lib22_push_notification_lua_plugin_la-push-notification-driver-lua.Plo
+ -rm -f ./$(DEPDIR)/push-notification-driver-dlog.Plo
+ -rm -f ./$(DEPDIR)/push-notification-driver-ox.Plo
+ -rm -f ./$(DEPDIR)/push-notification-drivers.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-flagsclear.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-flagsset.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxcreate.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxdelete.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxrename.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxsubscribe.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxunsubscribe.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-message-common.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messageappend.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messageexpunge.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messagenew.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messageread.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messagetrash.Plo
+ -rm -f ./$(DEPDIR)/push-notification-events-rfc5423.Plo
+ -rm -f ./$(DEPDIR)/push-notification-events.Plo
+ -rm -f ./$(DEPDIR)/push-notification-plugin.Plo
+ -rm -f ./$(DEPDIR)/push-notification-triggers.Plo
+ -rm -f ./$(DEPDIR)/push-notification-txn-mbox.Plo
+ -rm -f ./$(DEPDIR)/push-notification-txn-msg.Plo
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-moduleLTLIBRARIES install-pkginc_libHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/lib22_push_notification_lua_plugin_la-push-notification-driver-lua.Plo
+ -rm -f ./$(DEPDIR)/push-notification-driver-dlog.Plo
+ -rm -f ./$(DEPDIR)/push-notification-driver-ox.Plo
+ -rm -f ./$(DEPDIR)/push-notification-drivers.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-flagsclear.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-flagsset.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxcreate.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxdelete.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxrename.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxsubscribe.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-mailboxunsubscribe.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-message-common.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messageappend.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messageexpunge.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messagenew.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messageread.Plo
+ -rm -f ./$(DEPDIR)/push-notification-event-messagetrash.Plo
+ -rm -f ./$(DEPDIR)/push-notification-events-rfc5423.Plo
+ -rm -f ./$(DEPDIR)/push-notification-events.Plo
+ -rm -f ./$(DEPDIR)/push-notification-plugin.Plo
+ -rm -f ./$(DEPDIR)/push-notification-triggers.Plo
+ -rm -f ./$(DEPDIR)/push-notification-txn-mbox.Plo
+ -rm -f ./$(DEPDIR)/push-notification-txn-msg.Plo
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-moduleLTLIBRARIES uninstall-pkginc_libHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \
+ clean-generic clean-libtool clean-moduleLTLIBRARIES \
+ cscopelist-am ctags ctags-am distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man \
+ install-moduleLTLIBRARIES install-pdf install-pdf-am \
+ install-pkginc_libHEADERS install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-moduleLTLIBRARIES uninstall-pkginc_libHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/plugins/push-notification/push-notification-driver-dlog.c b/src/plugins/push-notification/push-notification-driver-dlog.c
new file mode 100644
index 0000000..e0cf790
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-driver-dlog.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2015-2018 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 *event;
+
+ i_debug("Called begin_txn push_notification plugin hook.");
+
+ array_foreach_elem(&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 *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_elem(&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 *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_elem(&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
+ }
+};
diff --git a/src/plugins/push-notification/push-notification-driver-lua.c b/src/plugins/push-notification/push-notification-driver-lua.c
new file mode 100644
index 0000000..e1178fa
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-driver-lua.c
@@ -0,0 +1,663 @@
+/* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "ioloop.h"
+#include "str.h"
+#include "hash.h"
+#include "dlua-script.h"
+#include "dlua-script-private.h"
+
+#include "mail-storage.h"
+#include "mail-user.h"
+#include "mail-lua-plugin.h"
+#include "mail-storage-lua.h"
+
+#include "push-notification-plugin.h"
+#include "push-notification-drivers.h"
+#include "push-notification-events.h"
+#include "push-notification-event-message-common.h"
+#include "push-notification-txn-mbox.h"
+#include "push-notification-txn-msg.h"
+
+#include "push-notification-event-flagsclear.h"
+#include "push-notification-event-flagsset.h"
+#include "push-notification-event-mailboxcreate.h"
+#include "push-notification-event-mailboxdelete.h"
+#include "push-notification-event-mailboxrename.h"
+#include "push-notification-event-mailboxsubscribe.h"
+#include "push-notification-event-mailboxunsubscribe.h"
+#include "push-notification-event-messageappend.h"
+#include "push-notification-event-message-common.h"
+#include "push-notification-event-messageexpunge.h"
+#include "push-notification-event-messagenew.h"
+#include "push-notification-event-messageread.h"
+#include "push-notification-event-messagetrash.h"
+
+#define DLUA_LOG_USERENV_KEY "push_notification_lua_script_file"
+
+#define DLUA_FN_BEGIN_TXN "dovecot_lua_notify_begin_txn"
+#define DLUA_FN_EVENT_PREFIX "dovecot_lua_notify_event"
+#define DLUA_FN_END_TXN "dovecot_lua_notify_end_txn"
+
+#define DLUA_CALL_FINISHED "push_notification_lua_call_finished"
+
+struct dlua_push_notification_context {
+ struct dlua_script *script;
+ struct event *event;
+ bool debug;
+
+ struct push_notification_event_messagenew_config config_mn;
+ struct push_notification_event_messageappend_config config_ma;
+ struct push_notification_event_flagsclear_config config_fc;
+ struct push_notification_event_flagsset_config config_fs;
+};
+
+struct dlua_push_notification_txn_context {
+ int tx_ref;
+};
+
+#define DLUA_DEFAULT_EVENTS (\
+ PUSH_NOTIFICATION_MESSAGE_HDR_FROM | \
+ PUSH_NOTIFICATION_MESSAGE_HDR_TO | \
+ PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT | \
+ PUSH_NOTIFICATION_MESSAGE_HDR_DATE | \
+ PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET | \
+ PUSH_NOTIFICATION_MESSAGE_FLAGS | \
+ PUSH_NOTIFICATION_MESSAGE_KEYWORDS | \
+ PUSH_NOTIFICATION_MESSAGE_HDR_MESSAGE_ID)
+
+static const char *push_notification_driver_lua_to_fn(const char *evname);
+
+static int
+push_notification_driver_lua_init(
+ struct push_notification_driver_config *config, struct mail_user *user,
+ pool_t pool, void **context, const char **error_r)
+{
+ struct dlua_push_notification_context *ctx;
+ const char *tmp, *file;
+ struct event *event = event_create(user->event);
+ event_add_category(event, push_notification_get_event_category());
+ event_set_append_log_prefix(event, "lua: ");
+
+ if ((tmp = mail_user_plugin_getenv(user, DLUA_LOG_USERENV_KEY)) == NULL)
+ tmp = hash_table_lookup(config->config, (const char *)"file");
+
+ if (tmp == NULL) {
+ struct dlua_script *script;
+ /* If there is a script loaded, use the same context */
+ if (mail_lua_plugin_get_script(user, &script)) {
+ dlua_script_ref(script);
+ ctx = p_new(
+ pool, struct dlua_push_notification_context, 1);
+ ctx->script = script;
+ ctx->event = event;
+ *context = ctx;
+ return 0;
+ }
+
+ event_unref(&event);
+ *error_r = "No file in config and no "
+ DLUA_LOG_USERENV_KEY " set";
+ return -1;
+ }
+ file = tmp;
+
+ ctx = p_new(pool, struct dlua_push_notification_context, 1);
+ ctx->event = event;
+
+ e_debug(ctx->event, "Loading %s", file);
+
+ if (dlua_script_create_file(file, &ctx->script, event, error_r) < 0) {
+ /* There is a T_POP after this, which will break errors */
+ event_unref(&event);
+ *error_r = p_strdup(pool, *error_r);
+ return -1;
+ }
+
+ /* Register dovecot helpers */
+ dlua_dovecot_register(ctx->script);
+ dlua_register_mail_storage(ctx->script);
+
+ e_debug(ctx->event, "Calling script_init");
+
+ /* Initialize script */
+ if (dlua_script_init(ctx->script, error_r) < 0) {
+ *error_r = p_strdup(pool, *error_r);
+ event_unref(&event);
+ dlua_script_unref(&ctx->script);
+ return -1;
+ }
+
+ *context = ctx;
+ return 0;
+}
+
+static bool
+push_notification_driver_lua_init_events(
+ struct push_notification_driver_txn *dtxn)
+{
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ const struct push_notification_event *event;
+ ctx->config_mn.flags = DLUA_DEFAULT_EVENTS;
+ ctx->config_ma.flags = DLUA_DEFAULT_EVENTS;
+ ctx->config_fc.store_old = TRUE;
+ bool found_one = FALSE;
+
+ /* Register *all* events that are present in Lua */
+ array_foreach_elem(push_notification_get_events(), event) {
+ const char *name = event->name;
+ const char *fn = push_notification_driver_lua_to_fn(name);
+ if (!dlua_script_has_function(ctx->script, fn))
+ continue;
+
+ found_one = TRUE;
+
+ e_debug(ctx->event, "Found %s, handling %s event", fn, name);
+
+ if (strcmp(name, "MessageNew") == 0) {
+ push_notification_event_init(dtxn, name,
+ &ctx->config_mn);
+ } else if (strcmp(name, "MessageAppend") == 0) {
+ push_notification_event_init(dtxn, name,
+ &ctx->config_ma);
+ } else if (strcmp(name, "FlagsSet") == 0) {
+ push_notification_event_init(dtxn, name,
+ &ctx->config_fs);
+ } else if (strcmp(name, "FlagsClear") == 0) {
+ push_notification_event_init(dtxn, name,
+ &ctx->config_fc);
+ } else if (event->init.default_config != NULL) {
+ void *config = event->init.default_config();
+ push_notification_event_init(dtxn, name, config);
+ } else {
+ push_notification_event_init(dtxn, name, NULL);
+ }
+ }
+
+ return found_one;
+}
+
+static bool
+push_notification_driver_lua_begin_txn(
+ struct push_notification_driver_txn *dtxn)
+{
+ struct mail_user *user = dtxn->ptxn->muser;
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ struct event *event = event_create(ctx->event);
+ const char *error;
+
+ event_set_name(event, DLUA_CALL_FINISHED);
+ event_add_str(event, "function_name", DLUA_FN_BEGIN_TXN);
+
+ if (!dlua_script_has_function(ctx->script, DLUA_FN_BEGIN_TXN)) {
+ event_add_str(event, "error",
+ "Missing function " DLUA_FN_BEGIN_TXN);
+ e_error(event, "Missing function " DLUA_FN_BEGIN_TXN);
+ event_unref(&event);
+ return FALSE;
+ }
+
+ if (!push_notification_driver_lua_init_events(dtxn)) {
+ e_debug(event, "No event handlers found in script");
+ event_unref(&event);
+ return FALSE;
+ }
+
+ e_debug(ctx->event, "Calling " DLUA_FN_BEGIN_TXN "(%s)",
+ user->username);
+
+ /* Push mail user as argument */
+ dlua_push_mail_user(ctx->script->L, user);
+ if (dlua_pcall(ctx->script->L, DLUA_FN_BEGIN_TXN, 1, 1, &error) < 0) {
+ event_add_str(event, "error", error);
+ e_error(event, "%s", error);
+ return FALSE;
+ }
+
+ e_debug(event, "Called " DLUA_FN_BEGIN_TXN);
+ event_unref(&event);
+
+ /* Store the result */
+ struct dlua_push_notification_txn_context *tctx =
+ p_new(dtxn->ptxn->pool,
+ struct dlua_push_notification_txn_context, 1);
+
+ tctx->tx_ref = luaL_ref(ctx->script->L, LUA_REGISTRYINDEX);
+ dtxn->context = tctx;
+ mail_user_ref(user);
+
+ return TRUE;
+}
+
+/* This function only works here, it converts MessageType to event_message_type
+ */
+static const char *push_notification_driver_lua_to_fn(const char *evname)
+{
+ /* Camelcase to event_event_name (most events have two underscores) */
+ string_t *fn = t_str_new(strlen(evname) +
+ strlen(DLUA_FN_EVENT_PREFIX) + 2);
+ str_append(fn, DLUA_FN_EVENT_PREFIX);
+
+ for(; *evname != '\0'; evname++) {
+ if (*evname >= 'A' && *evname <= 'Z') {
+ str_append_c(fn, '_');
+ str_append_c(fn, (*evname) - 'A' + 'a');
+ } else {
+ str_append_c(fn, *evname);
+ }
+ }
+
+ return str_c(fn);
+}
+
+/* Pushes lua list of flags */
+static void dlua_push_flags(struct dlua_script *script, enum mail_flags flags)
+{
+ lua_newtable(script->L);
+ int idx = 1;
+
+ if ((flags & MAIL_ANSWERED) != 0) {
+ lua_pushliteral(script->L, "\\Answered");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_FLAGGED) != 0) {
+ lua_pushliteral(script->L, "\\Flagged");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_DELETED) != 0) {
+ lua_pushliteral(script->L, "\\Deleted");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_SEEN) != 0) {
+ lua_pushliteral(script->L, "\\Seen");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_DRAFT) != 0) {
+ lua_pushliteral(script->L, "\\Draft");
+ lua_rawseti(script->L, -2, idx++);
+ }
+ if ((flags & MAIL_RECENT) != 0) {
+ lua_pushliteral(script->L, "\\Recent");
+ lua_rawseti(script->L, -2, idx++);
+ }
+}
+
+static void
+dlua_push_keywords(struct dlua_script *script, const char *const *keywords,
+ unsigned int count)
+{
+ lua_newtable(script->L);
+ if (keywords == NULL)
+ return;
+ for (unsigned int idx = 0; idx < count; idx++) {
+ lua_pushstring(script->L, keywords[idx]);
+ lua_rawseti(script->L, -2, idx+1);
+ }
+}
+
+static void
+push_notification_lua_push_flagsclear(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ /* Push cleared flags */
+ unsigned int size = 0;
+ struct push_notification_event_flagsclear_data *data = event->data;
+
+ dlua_push_flags(script, data->flags_clear);
+ lua_setfield(script->L, -2, "flags");
+ dlua_push_flags(script, data->flags_old);
+ lua_setfield(script->L, -2, "flags_old");
+
+ if (array_is_created(&data->keywords_clear)) {
+ const char *const *kw = array_get(&data->keywords_clear, &size);
+ dlua_push_keywords(script, kw, size);
+ lua_setfield(script->L, -2, "keywords");
+ }
+
+ if (array_is_created(&data->keywords_old)) {
+ const char *const *kw = array_get(&data->keywords_old, &size);
+ dlua_push_keywords(script, kw, size);
+ lua_setfield(script->L, -2, "keywords_old");
+ }
+}
+
+static void
+push_notification_lua_push_flagsset(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ /* push set flags */
+ unsigned int size = 0;
+ struct push_notification_event_flagsset_data *data = event->data;
+
+ dlua_push_flags(script, data->flags_set);
+ lua_setfield(script->L, -2, "flags");
+
+ if (array_is_created(&data->keywords_set)) {
+ const char *const *kw = array_get(&data->keywords_set, &size);
+ dlua_push_keywords(script, kw, size);
+ lua_setfield(script->L, -2, "keywords");
+ }
+}
+
+static void
+push_notification_lua_push_mailboxrename(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ struct push_notification_event_mailboxrename_data *data = event->data;
+
+ lua_pushstring(script->L, data->old_mbox);
+ lua_setfield(script->L, -2, "mailbox_old");
+}
+
+#define push_notification_lua_push_string(L, value) \
+ lua_pushstring((L), (value) == NULL ? "" : (value))
+
+static void
+push_notification_lua_push_message_ext(
+ const struct push_notification_message_ext *ext,
+ struct dlua_script *script)
+{
+ push_notification_lua_push_string(script->L, ext->from_address);
+ lua_setfield(script->L, -2, "from_address");
+ push_notification_lua_push_string(script->L, ext->from_display_name_utf8);
+ lua_setfield(script->L, -2, "from_display_name");
+
+ push_notification_lua_push_string(script->L, ext->to_address);
+ lua_setfield(script->L, -2, "to_address");
+ push_notification_lua_push_string(script->L, ext->to_display_name_utf8);
+ lua_setfield(script->L, -2, "to_display_name");
+
+ lua_pushstring(script->L, ext->subject_utf8);
+ lua_setfield(script->L, -2, "subject");
+}
+
+static void
+push_notification_lua_push_messageappend(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ struct push_notification_event_messageappend_data *data = event->data;
+
+ lua_pushnumber(script->L, data->date);
+ lua_setfield(script->L, -2, "date");
+
+ lua_pushnumber(script->L, data->date_tz);
+ lua_setfield(script->L, -2, "tz");
+
+ push_notification_lua_push_string(script->L, data->from);
+ lua_setfield(script->L, -2, "from");
+
+ push_notification_lua_push_string(script->L, data->to);
+ lua_setfield(script->L, -2, "to");
+
+ lua_pushstring(script->L, data->snippet);
+ lua_setfield(script->L, -2, "snippet");
+
+ dlua_push_flags(script, data->flags);
+ lua_setfield(script->L, -2, "flags");
+
+ dlua_push_keywords(script, data->keywords,
+ str_array_length(data->keywords));
+ lua_setfield(script->L, -2, "keywords");
+
+ lua_pushstring(script->L, data->message_id);
+ lua_setfield(script->L, -2, "message_id");
+
+ push_notification_lua_push_message_ext(&data->ext, script);
+}
+
+static void
+push_notification_lua_push_messagenew(
+ const struct push_notification_txn_event *event,
+ struct dlua_script *script)
+{
+ struct push_notification_event_messagenew_data *data = event->data;
+
+ lua_pushnumber(script->L, data->date);
+ lua_setfield(script->L, -2, "date");
+
+ lua_pushnumber(script->L, data->date_tz);
+ lua_setfield(script->L, -2, "tz");
+
+ push_notification_lua_push_string(script->L, data->from);
+ lua_setfield(script->L, -2, "from");
+
+ push_notification_lua_push_string(script->L, data->to);
+ lua_setfield(script->L, -2, "to");
+
+ lua_pushstring(script->L, data->snippet);
+ lua_setfield(script->L, -2, "snippet");
+
+ dlua_push_flags(script, data->flags);
+ lua_setfield(script->L, -2, "flags");
+
+ dlua_push_keywords(script, data->keywords,
+ str_array_length(data->keywords));
+ lua_setfield(script->L, -2, "keywords");
+
+ lua_pushstring(script->L, data->message_id);
+ lua_setfield(script->L, -2, "message_id");
+
+ push_notification_lua_push_message_ext(&data->ext, script);
+}
+
+/* Events that need special treatment */
+static struct push_notification_event_to_lua {
+ const char *event_name;
+ void (*push)(const struct push_notification_txn_event *event,
+ struct dlua_script *script);
+} event_to_push_table[] = {
+ {
+ .event_name = "FlagsClear",
+ .push = push_notification_lua_push_flagsclear
+ },
+ {
+ .event_name = "FlagsSet",
+ .push = push_notification_lua_push_flagsset
+ },
+ {
+ .event_name = "MailboxRename",
+ .push = push_notification_lua_push_mailboxrename
+ },
+ {
+ .event_name = "MessageAppend",
+ .push = push_notification_lua_push_messageappend
+ },
+ {
+ .event_name = "MessageNew",
+ .push = push_notification_lua_push_messagenew
+ },
+};
+
+static void
+push_notification_driver_lua_push_event(
+ const struct push_notification_txn_event *event,
+ struct dlua_push_notification_context *ctx)
+{
+ struct dlua_script *script = ctx->script;
+ const char *name = event->event->event->name;
+
+ /* Create a table */
+ lua_newtable(script->L);
+
+ /* Event name */
+ lua_pushstring(script->L, name);
+ lua_setfield(script->L, -2, "name");
+
+ for(size_t i = 0; i < N_ELEMENTS(event_to_push_table); i++)
+ if (strcmp(event_to_push_table[i].event_name, name) == 0)
+ event_to_push_table[i].push(event, script);
+}
+
+static void
+push_notification_driver_lua_call(
+ struct dlua_push_notification_context *ctx,
+ struct dlua_push_notification_txn_context *tctx,
+ const struct push_notification_txn_event *event,
+ const struct push_notification_txn_mbox *mbox,
+ struct push_notification_txn_msg *msg)
+{
+ const char *error;
+ const char *fn =
+ push_notification_driver_lua_to_fn(event->event->event->name);
+ struct event *e = event_create(ctx->event);
+ event_set_name(e, DLUA_CALL_FINISHED);
+ event_add_str(e, "event_name", event->event->event->name);
+ event_add_str(e, "function_name", fn);
+
+ /* Push context */
+ lua_rawgeti(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
+
+ /* Push event + common fields */
+ push_notification_driver_lua_push_event(event, ctx);
+
+ if (mbox != NULL) {
+ lua_pushstring(ctx->script->L, mbox->mailbox);
+ lua_setfield(ctx->script->L, -2, "mailbox");
+ e_debug(ctx->event,
+ "Calling %s(ctx, event[name=%s,mailbox=%s])",
+ fn, event->event->event->name, mbox->mailbox);
+ event_add_str(e, "mailbox", mbox->mailbox);
+ } else if (msg != NULL) {
+ lua_pushstring(ctx->script->L, msg->mailbox);
+ lua_setfield(ctx->script->L, -2, "mailbox");
+ lua_pushnumber(ctx->script->L, msg->uid);
+ lua_setfield(ctx->script->L, -2, "uid");
+ lua_pushnumber(ctx->script->L, msg->uid_validity);
+ lua_setfield(ctx->script->L, -2, "uid_validity");
+ e_debug(ctx->event,
+ "Calling %s(ctx, event[name=%s,mailbox=%s,uid=%u])",
+ fn, event->event->event->name, msg->mailbox, msg->uid);
+ event_add_str(e, "mailbox", msg->mailbox);
+ event_add_int(e, "uid", msg->uid);
+ } else
+ i_unreached();
+
+ /* Perform call */
+ if (dlua_pcall(ctx->script->L, fn, 2, 0, &error) < 0) {
+ event_add_str(e, "error", error);
+ e_error(e, "%s", error);
+ } else {
+ e_debug(e, "Called %s", fn);
+ }
+ event_unref(&e);
+}
+
+static void
+push_notification_driver_lua_process_mbox(
+ struct push_notification_driver_txn *dtxn,
+ struct push_notification_txn_mbox *mbox)
+{
+ struct push_notification_txn_event *event;
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ struct dlua_push_notification_txn_context *tctx = dtxn->context;
+
+ if (array_is_created(&mbox->eventdata)) {
+ array_foreach_elem(&mbox->eventdata, event) {
+ push_notification_driver_lua_call(ctx, tctx,
+ event, mbox, NULL);
+ }
+ }
+}
+
+static void
+push_notification_driver_lua_process_msg(
+ struct push_notification_driver_txn *dtxn,
+ struct push_notification_txn_msg *msg)
+{
+ struct push_notification_txn_event *event;
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ struct dlua_push_notification_txn_context *tctx = dtxn->context;
+
+ if (array_is_created(&msg->eventdata)) {
+ array_foreach_elem(&msg->eventdata, event) {
+ push_notification_driver_lua_call(ctx, tctx,
+ event, NULL, msg);
+ }
+ }
+}
+
+static void
+push_notification_driver_lua_end_txn(struct push_notification_driver_txn *dtxn,
+ bool success)
+{
+ /* Call end txn */
+ const char *error;
+ struct dlua_push_notification_context *ctx = dtxn->duser->context;
+ struct dlua_push_notification_txn_context *tctx = dtxn->context;
+ struct mail_user *user = dtxn->ptxn->muser;
+ struct event *event = event_create(ctx->event);
+ event_set_name(event, DLUA_CALL_FINISHED);
+ event_add_str(event, "function_name", DLUA_FN_END_TXN);
+
+ if (!dlua_script_has_function(ctx->script, DLUA_FN_END_TXN)) {
+ e_error(event, "Missing function " DLUA_FN_END_TXN);
+ } else {
+ e_debug(ctx->event, "Calling " DLUA_FN_END_TXN);
+ lua_rawgeti(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
+ lua_pushboolean(ctx->script->L, success);
+ if (dlua_pcall(ctx->script->L, DLUA_FN_END_TXN, 2, 0, &error) < 0) {
+ event_add_str(event, "error", error);
+ e_error(event, "%s", error);
+ } else {
+ e_debug(event, "Called " DLUA_FN_END_TXN);
+ }
+ }
+
+ event_unref(&event);
+ /* Release context */
+ luaL_unref(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
+ /* Call gc here */
+ (void)lua_gc(ctx->script->L, LUA_GCCOLLECT, 1);
+ mail_user_unref(&user);
+}
+
+static void
+push_notification_driver_lua_deinit(struct push_notification_driver_user *duser)
+{
+ /* Call lua deinit */
+ struct dlua_push_notification_context *ctx = duser->context;
+ dlua_script_unref(&ctx->script);
+ event_unref(&ctx->event);
+}
+
+static void push_notification_driver_lua_cleanup(void)
+{
+ /* noop */
+}
+
+/* Driver definition */
+
+struct push_notification_driver push_notification_driver_lua = {
+ .name = "lua",
+ .v = {
+ .init = push_notification_driver_lua_init,
+ .begin_txn = push_notification_driver_lua_begin_txn,
+ .process_mbox = push_notification_driver_lua_process_mbox,
+ .process_msg = push_notification_driver_lua_process_msg,
+ .end_txn = push_notification_driver_lua_end_txn,
+ .deinit = push_notification_driver_lua_deinit,
+ .cleanup = push_notification_driver_lua_cleanup,
+ },
+};
+
+void push_notification_lua_plugin_init(struct module *module);
+void push_notification_lua_plugin_deinit(void);
+
+void push_notification_lua_plugin_init(struct module *module ATTR_UNUSED)
+{
+ push_notification_driver_register(&push_notification_driver_lua);
+}
+
+void push_notification_lua_plugin_deinit(void)
+{
+ push_notification_driver_unregister(&push_notification_driver_lua);
+}
+
+const char *push_notification_lua_plugin_version = DOVECOT_ABI_VERSION;
+const char *push_notification_lua_plugin_dependencies[] =
+ { "push_notification", "mail_lua", NULL};
diff --git a/src/plugins/push-notification/push-notification-driver-ox.c b/src/plugins/push-notification/push-notification-driver-ox.c
new file mode 100644
index 0000000..728cce9
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-driver-ox.c
@@ -0,0 +1,470 @@
+/* Copyright (c) 2015-2018 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 "settings-parser.h"
+#include "json-parser.h"
+#include "mailbox-attribute.h"
+#include "mail-storage-private.h"
+#include "str.h"
+#include "strescape.h"
+#include "iostream-ssl.h"
+
+#include "push-notification-plugin.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_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 };
+#define DEFAULT_CACHE_LIFETIME_SECS 60
+#define DEFAULT_TIMEOUT_MSECS 2000
+#define DEFAULT_RETRY_COUNT 1
+
+/* 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;
+ struct event *event;
+ unsigned int cached_ox_metadata_lifetime_secs;
+ bool use_unsafe_username;
+ unsigned int http_max_retries;
+ unsigned int http_timeout_msecs;
+
+ char *cached_ox_metadata;
+ time_t cached_ox_metadata_timestamp;
+};
+
+/* This is data specific to an OX driver transaction. */
+struct push_notification_driver_ox_txn {
+ const char *unsafe_user;
+};
+
+static void
+push_notification_driver_ox_init_global(
+ struct mail_user *user,
+ struct push_notification_driver_ox_config *config)
+{
+ struct http_client_settings http_set;
+ struct ssl_iostream_settings ssl_set;
+
+ if (ox_global->http_client == NULL) {
+ /* This is going to use the first user's settings, but these are
+ unlikely to change between users so it shouldn't matter much.
+ */
+ i_zero(&http_set);
+ http_set.debug = user->mail_debug;
+ http_set.max_attempts = config->http_max_retries+1;
+ http_set.request_timeout_msecs = config->http_timeout_msecs;
+ http_set.event_parent = user->event;
+ mail_user_init_ssl_client_settings(user, &ssl_set);
+ http_set.ssl = &ssl_set;
+
+ 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, *tmp;
+
+ /* Valid config keys: cache_lifetime, url */
+ tmp = hash_table_lookup(config->config, (const char *)"url");
+ if (tmp == NULL) {
+ *error_r = "Driver requires the url parameter";
+ return -1;
+ }
+
+ dconfig = p_new(pool, struct push_notification_driver_ox_config, 1);
+ dconfig->event = event_create(user->event);
+ event_add_category(dconfig->event, &event_category_push_notification);
+ event_set_append_log_prefix(dconfig->event, "push-notification-ox: ");
+
+ if (http_url_parse(tmp, NULL, HTTP_URL_ALLOW_USERINFO_PART, pool,
+ &dconfig->http_url, &error) < 0) {
+ event_unref(&dconfig->event);
+ *error_r = t_strdup_printf("Failed to parse OX REST URL %s: %s",
+ tmp, error);
+ return -1;
+ }
+ dconfig->use_unsafe_username =
+ hash_table_lookup(config->config,
+ (const char *)"user_from_metadata") != NULL;
+
+ e_debug(dconfig->event, "Using URL %s", tmp);
+
+ tmp = hash_table_lookup(config->config, (const char *)"cache_lifetime");
+ if (tmp == NULL) {
+ dconfig->cached_ox_metadata_lifetime_secs =
+ DEFAULT_CACHE_LIFETIME_SECS;
+ } else if (settings_get_time(
+ tmp, &dconfig->cached_ox_metadata_lifetime_secs, &error) < 0) {
+ event_unref(&dconfig->event);
+ *error_r = t_strdup_printf(
+ "Failed to parse OX cache_lifetime %s: %s", tmp, error);
+ return -1;
+ }
+
+ tmp = hash_table_lookup(config->config, (const char *)"max_retries");
+ if ((tmp == NULL) ||
+ (str_to_uint(tmp, &dconfig->http_max_retries) < 0)) {
+ dconfig->http_max_retries = DEFAULT_RETRY_COUNT;
+ }
+ tmp = hash_table_lookup(config->config, (const char *)"timeout_msecs");
+ if ((tmp == NULL) ||
+ (str_to_uint(tmp, &dconfig->http_timeout_msecs) < 0)) {
+ dconfig->http_timeout_msecs = DEFAULT_TIMEOUT_MSECS;
+ }
+
+ e_debug(dconfig->event, "Using cache lifetime: %u",
+ dconfig->cached_ox_metadata_lifetime_secs);
+
+ 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 push_notification_driver_ox_config *dconfig =
+ dtxn->duser->context;
+ struct mail_attribute_value attr;
+ struct mailbox *inbox;
+ struct mail_namespace *ns;
+ bool success = FALSE, use_existing_txn = FALSE;
+ int ret;
+
+ if ((dconfig->cached_ox_metadata != NULL) &&
+ ((dconfig->cached_ox_metadata_timestamp +
+ (time_t)dconfig->cached_ox_metadata_lifetime_secs) >
+ ioloop_time)) {
+ return dconfig->cached_ox_metadata;
+ }
+
+ /* Get canonical INBOX, where private server-level metadata is stored.
+ * See imap/cmd-getmetadata.c */
+ if ((dtxn->ptxn->t != NULL) && dtxn->ptxn->mbox->inbox_user) {
+ inbox = dtxn->ptxn->mbox;
+ use_existing_txn = TRUE;
+ } else {
+ ns = mail_namespace_find_inbox(dtxn->ptxn->muser->namespaces);
+ inbox = mailbox_alloc(ns->list, "INBOX", MAILBOX_FLAG_READONLY);
+ }
+
+ ret = mailbox_attribute_get(inbox, MAIL_ATTRIBUTE_TYPE_PRIVATE,
+ OX_METADATA_KEY, &attr);
+ if (ret < 0) {
+ e_error(dconfig->event,
+ "Skipped because unable to get attribute: %s",
+ mailbox_get_last_internal_error(inbox, NULL));
+ } else if (ret == 0) {
+ e_debug(dconfig->event,
+ "Skipped because not active "
+ "(/private/"OX_METADATA_KEY" METADATA not set)");
+ } else {
+ success = TRUE;
+ }
+
+ if (!use_existing_txn)
+ mailbox_free(&inbox);
+ if (!success)
+ return NULL;
+
+ i_free(dconfig->cached_ox_metadata);
+ dconfig->cached_ox_metadata = i_strdup(attr.value);
+ dconfig->cached_ox_metadata_timestamp = ioloop_time;
+
+ return dconfig->cached_ox_metadata;
+}
+
+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;
+ struct push_notification_driver_ox_config *dconfig =
+ dtxn->duser->context;
+
+ md_value = push_notification_driver_ox_get_metadata(dtxn);
+ if (md_value == NULL)
+ return FALSE;
+
+ /* 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) {
+ e_debug(dconfig->event, "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) {
+ e_debug(dconfig->event,
+ "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_tabescaped(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->unsafe_user =
+ p_strdup(dtxn->ptxn->pool, value);
+ }
+ }
+ }
+
+ if (txn->unsafe_user == NULL) {
+ e_error(dconfig->event, "No user provided in config");
+ return FALSE;
+ }
+
+ e_debug(dconfig->event, "User (%s)", txn->unsafe_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);
+ e_debug(dconfig->event, "Handling MessageNew event");
+ }
+ }
+
+ dtxn->context = txn;
+
+ return TRUE;
+}
+
+static void
+push_notification_driver_ox_http_callback(
+ const struct http_response *response,
+ struct push_notification_driver_ox_config *dconfig)
+{
+ switch (response->status / 100) {
+ case 2:
+ // Success.
+ e_debug(dconfig->event, "Notification sent successfully: %s",
+ http_response_get_message(response));
+ break;
+
+ default:
+ // Error.
+ e_error(dconfig->event, "Error when sending notification: %s",
+ http_response_get_message(response));
+ 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 int
+push_notification_driver_ox_get_mailbox_status(
+ struct push_notification_driver_txn *dtxn,
+ struct mailbox_status *r_box_status)
+{
+ struct push_notification_driver_ox_config *dconfig =
+ dtxn->duser->context;
+ /* The already opened mailbox. We cannot use or sync it, because we are
+ within a save transaction. */
+ struct mailbox *mbox = dtxn->ptxn->mbox;
+ struct mailbox *box;
+ int ret;
+
+ /* Open and sync new instance of the same mailbox to get most recent
+ status */
+ box = mailbox_alloc(mailbox_get_namespace(mbox)->list,
+ mailbox_get_name(mbox), MAILBOX_FLAG_READONLY);
+ if (mailbox_sync(box, 0) < 0) {
+ e_error(dconfig->event, "mailbox_sync(%s) failed: %s",
+ mailbox_get_vname(mbox),
+ mailbox_get_last_internal_error(box, NULL));
+ ret = -1;
+ } else {
+ /* only 'unseen' is needed at the moment */
+ mailbox_get_open_status(box, STATUS_UNSEEN, r_box_status);
+ e_debug(dconfig->event,
+ "Got status of mailbox '%s': (unseen: %u)",
+ mailbox_get_vname(box), r_box_status->unseen);
+ ret = 0;
+ }
+
+ mailbox_free(&box);
+ return ret;
+}
+
+
+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;
+ struct mailbox_status box_status;
+ bool status_success = TRUE;
+
+ if (push_notification_driver_ox_get_mailbox_status(
+ dtxn, &box_status) < 0) {
+ status_success = FALSE;
+ }
+
+ messagenew = push_notification_txn_msg_get_eventdata(msg, "MessageNew");
+ if (messagenew == NULL)
+ return;
+
+ push_notification_driver_ox_init_global(user, dconfig);
+
+ http_req = http_client_request_url(
+ ox_global->http_client, "PUT", dconfig->http_url,
+ push_notification_driver_ox_http_callback, dconfig);
+ http_client_request_set_event(http_req, dtxn->ptxn->event);
+ 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, dconfig->use_unsafe_username ?
+ txn->unsafe_user : user->username);
+ 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);
+ str_append(str, "\"");
+ }
+ if (messagenew->subject != NULL) {
+ str_append(str, ",\"subject\":\"");
+ json_append_escaped(str, messagenew->subject);
+ str_append(str, "\"");
+ }
+ if (messagenew->snippet != NULL) {
+ str_append(str, ",\"snippet\":\"");
+ json_append_escaped(str, messagenew->snippet);
+ str_append(str, "\"");
+ }
+ if (status_success) {
+ str_printfa(str, ",\"unseen\":%u", box_status.unseen);
+ }
+ str_append(str, "}");
+
+ e_debug(dconfig->event, "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)
+{
+ struct push_notification_driver_ox_config *dconfig = duser->context;
+
+ i_free(dconfig->cached_ox_metadata);
+ if (ox_global != NULL) {
+ if (ox_global->http_client != NULL)
+ http_client_wait(ox_global->http_client);
+ i_assert(ox_global->refcount > 0);
+ --ox_global->refcount;
+ }
+ event_unref(&dconfig->event);
+}
+
+static void push_notification_driver_ox_cleanup(void)
+{
+ if ((ox_global != NULL) && (ox_global->refcount <= 0)) {
+ if (ox_global->http_client != NULL) {
+ 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-drivers.c b/src/plugins/push-notification/push-notification-drivers.c
new file mode 100644
index 0000000..67295d1
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-drivers.c
@@ -0,0 +1,181 @@
+/* Copyright (c) 2015-2018 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)
+{
+ unsigned int idx;
+
+ if (!push_notification_driver_find(driver, &idx))
+ return NULL;
+
+ return array_idx_elem(&push_notification_drivers, idx);
+}
+
+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);
+ } else {
+ key = *args;
+ value = "";
+ }
+ hash_table_update(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);
+ if (ret < 0)
+ i_error("%s: %s", driver_name, error_r);
+ hash_table_destroy(&config->config);
+ } T_END;
+
+ if (ret < 0)
+ 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 *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_elem(&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;
+
+ T_BEGIN {
+ va_start(args, fmt);
+ e_debug(user->event, "%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_push_back(&push_notification_drivers, &driver);
+}
+
+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);
+ }
+}
diff --git a/src/plugins/push-notification/push-notification-drivers.h b/src/plugins/push-notification/push-notification-drivers.h
new file mode 100644
index 0000000..07b570f
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-drivers.h
@@ -0,0 +1,123 @@
+/* Copyright (c) 2015-2018 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_driver_list {
+ ARRAY(struct push_notification_driver_user *) drivers;
+};
+
+struct push_notification_user {
+ union mail_user_module_context module_ctx;
+ struct push_notification_driver_list *driverlist;
+};
+
+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;
+ bool initialized;
+
+ 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;
+
+ struct event *event;
+
+ /* 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
diff --git a/src/plugins/push-notification/push-notification-event-flagsclear.c b/src/plugins/push-notification/push-notification-event-flagsclear.c
new file mode 100644
index 0000000..2ce0c3f
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-flagsclear.c
@@ -0,0 +1,170 @@
+/* Copyright (c) 2015-2018 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)
+{
+ i_zero(&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 *keyword;
+
+ if ((data->flags_clear & MAIL_ANSWERED) != 0)
+ i_debug("%s: Answered flag cleared", EVENT_NAME);
+ if ((data->flags_clear & MAIL_FLAGGED) != 0)
+ i_debug("%s: Flagged flag cleared", EVENT_NAME);
+ if ((data->flags_clear & MAIL_DELETED) != 0)
+ i_debug("%s: Deleted flag cleared", EVENT_NAME);
+ if ((data->flags_clear & MAIL_SEEN) != 0)
+ i_debug("%s: Seen flag cleared", EVENT_NAME);
+ if ((data->flags_clear & MAIL_DRAFT) != 0)
+ i_debug("%s: Draft flag cleared", EVENT_NAME);
+
+ array_foreach_elem(&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]) == 0 &&
+ (old_flags & flag_check_always[i]) != 0)
+ 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_push_back(&data->keywords_clear, &ok);
+ }
+
+ if (config->store_old == TRUE) {
+ ok = p_strdup(ptxn->pool, *old_keywords);
+ array_push_back(&data->keywords_old, &ok);
+ }
+ }
+}
+
+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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-flagsclear.h b/src/plugins/push-notification/push-notification-event-flagsclear.h
new file mode 100644
index 0000000..5412335
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-flagsclear.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-event-flagsset.c b/src/plugins/push-notification/push-notification-event-flagsset.c
new file mode 100644
index 0000000..c596ced
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-flagsset.c
@@ -0,0 +1,167 @@
+/* Copyright (c) 2015-2018 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)
+{
+ i_zero(&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 *keyword;
+
+ if ((data->flags_set & MAIL_ANSWERED) != 0)
+ i_debug("%s: Answered flag set", EVENT_NAME);
+ if ((data->flags_set & MAIL_FLAGGED) != 0)
+ i_debug("%s: Flagged flag set", EVENT_NAME);
+ if ((data->flags_set & MAIL_DELETED) != 0)
+ i_debug("%s: Deleted flag set", EVENT_NAME);
+ if ((data->flags_set & MAIL_SEEN) != 0)
+ i_debug("%s: Seen flag set", EVENT_NAME);
+ if ((data->flags_set & MAIL_DRAFT) != 0)
+ i_debug("%s: Draft flag set", EVENT_NAME);
+
+ array_foreach_elem(&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]) != 0 &&
+ (old_flags & flag_check_always[i]) == 0)
+ flags_set |= flag_check_always[i];
+ }
+
+ if (!config->hide_deleted && (flags & MAIL_DELETED) != 0 &&
+ (old_flags & MAIL_DELETED) == 0) {
+ flags_set |= MAIL_DELETED;
+ }
+
+ if (!config->hide_seen && (flags & MAIL_SEEN) != 0 &&
+ (old_flags & MAIL_SEEN) == 0) {
+ flags_set |= MAIL_SEEN;
+ }
+
+ /* Only create data element if at least one flag was set. */
+ if (flags_set != 0) {
+ 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_push_back(&data->keywords_set, &k);
+ }
+ }
+}
+
+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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-flagsset.h b/src/plugins/push-notification/push-notification-event-flagsset.h
new file mode 100644
index 0000000..4830260
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-flagsset.h
@@ -0,0 +1,22 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-event-mailboxcreate.c b/src/plugins/push-notification/push-notification-event-mailboxcreate.c
new file mode 100644
index 0000000..87e46c1
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxcreate.c
@@ -0,0 +1,56 @@
+/* Copyright (c) 2015-2018 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;
+
+ if (mailbox_get_status(ptxn->mbox, STATUS_UIDVALIDITY, &status) < 0) {
+ i_error(EVENT_NAME
+ "Failed to get created mailbox '%s' uidvalidity: %s",
+ mailbox_get_vname(ptxn->mbox),
+ mailbox_get_last_internal_error(ptxn->mbox, NULL));
+ status.uidvalidity = 0;
+ }
+
+ 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-mailboxcreate.h b/src/plugins/push-notification/push-notification-event-mailboxcreate.h
new file mode 100644
index 0000000..9a5e1bf
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxcreate.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-event-mailboxdelete.c b/src/plugins/push-notification/push-notification-event-mailboxdelete.c
new file mode 100644
index 0000000..8e65f3c
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxdelete.c
@@ -0,0 +1,46 @@
+/* Copyright (c) 2015-2018 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-mailboxdelete.h b/src/plugins/push-notification/push-notification-event-mailboxdelete.h
new file mode 100644
index 0000000..ac36747
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxdelete.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-event-mailboxrename.c b/src/plugins/push-notification/push-notification-event-mailboxrename.c
new file mode 100644
index 0000000..e4c2cae
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxrename.c
@@ -0,0 +1,50 @@
+/* Copyright (c) 2015-2018 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-mailboxrename.h b/src/plugins/push-notification/push-notification-event-mailboxrename.h
new file mode 100644
index 0000000..66e21f8
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxrename.h
@@ -0,0 +1,11 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-event-mailboxsubscribe.c b/src/plugins/push-notification/push-notification-event-mailboxsubscribe.c
new file mode 100644
index 0000000..0bcd101
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxsubscribe.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2015-2018 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-mailboxsubscribe.h b/src/plugins/push-notification/push-notification-event-mailboxsubscribe.h
new file mode 100644
index 0000000..d278482
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxsubscribe.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-event-mailboxunsubscribe.c b/src/plugins/push-notification/push-notification-event-mailboxunsubscribe.c
new file mode 100644
index 0000000..b8d078f
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxunsubscribe.c
@@ -0,0 +1,48 @@
+/* Copyright (c) 2015-2018 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 = FALSE;
+
+ 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-mailboxunsubscribe.h b/src/plugins/push-notification/push-notification-event-mailboxunsubscribe.h
new file mode 100644
index 0000000..c519da2
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-mailboxunsubscribe.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-event-message-common.c b/src/plugins/push-notification/push-notification-event-message-common.c
new file mode 100644
index 0000000..7965039
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-message-common.c
@@ -0,0 +1,117 @@
+/* Copyright (c) 2015-2019 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "message-address.h"
+#include "message-header-decode.h"
+#include "mail-storage.h"
+#include "push-notification-event-message-common.h"
+
+static void
+decode_address_header(pool_t pool, const char *hdr,
+ const char **address_r, const char **name_r)
+{
+ struct message_address *addr;
+ const char *display_name;
+
+ if (hdr == NULL)
+ return;
+
+ addr = message_address_parse(pool_datastack_create(),
+ (const unsigned char *)hdr, strlen(hdr), 1, 0);
+ if (addr == NULL)
+ return;
+
+ display_name = addr->name;
+ if (addr->domain == NULL) {
+ /* group */
+ display_name = addr->mailbox;
+ } else if (addr->domain[0] != '\0')
+ *address_r = p_strdup_printf(pool, "%s@%s", addr->mailbox,
+ addr->domain);
+ else if (addr->mailbox != NULL && addr->mailbox[0] != '\0')
+ *address_r = p_strdup(pool, addr->mailbox);
+
+ if (display_name != NULL && display_name[0] != '\0') {
+ string_t *name_utf8 = t_str_new(128);
+
+ message_header_decode_utf8((const unsigned char *)display_name,
+ strlen(display_name), name_utf8, NULL);
+ *name_r = p_strdup(pool, str_c(name_utf8));
+ }
+}
+
+void push_notification_message_fill(
+ struct mail *mail, pool_t pool,
+ enum push_notification_event_message_flags event_flags,
+ const char **from, const char **to, const char **subject, time_t *date,
+ int *date_tz, const char **message_id, enum mail_flags *flags,
+ bool *flags_set, const char *const **keywords, const char **snippet,
+ struct push_notification_message_ext *ext)
+{
+ const char *value;
+ time_t tmp_date;
+ int tmp_tz;
+
+ if ((*from == NULL) &&
+ (event_flags & PUSH_NOTIFICATION_MESSAGE_HDR_FROM) != 0 &&
+ (mail_get_first_header(mail, "From", &value) >= 0)) {
+ *from = p_strdup(pool, value);
+ decode_address_header(pool, value, &ext->from_address,
+ &ext->from_display_name_utf8);
+ }
+
+ if ((*to == NULL) &&
+ (event_flags & PUSH_NOTIFICATION_MESSAGE_HDR_TO) != 0 &&
+ (mail_get_first_header(mail, "To", &value) >= 0)) {
+ *to = p_strdup(pool, value);
+ decode_address_header(pool, value, &ext->to_address,
+ &ext->to_display_name_utf8);
+ }
+
+ if ((*subject == NULL) &&
+ (event_flags & PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT) != 0 &&
+ (mail_get_first_header(mail, "Subject", &value) >= 0)) {
+ string_t *subject_utf8 = t_str_new(128);
+
+ *subject = p_strdup(pool, value);
+ if (value != NULL) {
+ message_header_decode_utf8(
+ (const unsigned char *)value,
+ strlen(value), subject_utf8, NULL);
+ ext->subject_utf8 = p_strdup(pool, str_c(subject_utf8));
+ }
+ }
+
+ if ((*date == -1) &&
+ (event_flags & PUSH_NOTIFICATION_MESSAGE_HDR_DATE) != 0 &&
+ (mail_get_date(mail, &tmp_date, &tmp_tz) >= 0)) {
+ *date = tmp_date;
+ *date_tz = tmp_tz;
+ }
+
+ if ((*message_id == NULL) &&
+ (event_flags & PUSH_NOTIFICATION_MESSAGE_HDR_MESSAGE_ID) != 0 &&
+ (mail_get_first_header(mail, "Message-ID", &value) >= 0)) {
+ *message_id = p_strdup(pool, value);
+ }
+
+ if (!*flags_set &&
+ (event_flags & PUSH_NOTIFICATION_MESSAGE_FLAGS) != 0) {
+ *flags = mail_get_flags(mail);
+ *flags_set = TRUE;
+ }
+
+ if ((*keywords == NULL) &&
+ (event_flags & PUSH_NOTIFICATION_MESSAGE_KEYWORDS) != 0) {
+ *keywords = p_strarray_dup(pool, mail_get_keywords(mail));
+ }
+
+ if ((*snippet == NULL) &&
+ (event_flags & PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET) != 0 &&
+ (mail_get_special(mail, MAIL_FETCH_BODY_SNIPPET, &value) >= 0)) {
+ /* [0] contains the snippet algorithm, skip over it */
+ i_assert(value[0] != '\0');
+ *snippet = p_strdup(pool, value + 1);
+ }
+}
diff --git a/src/plugins/push-notification/push-notification-event-message-common.h b/src/plugins/push-notification/push-notification-event-message-common.h
new file mode 100644
index 0000000..48c37de
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-message-common.h
@@ -0,0 +1,40 @@
+/* Copyright (c) 2015-2018 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,
+ /* Meta: Flags */
+ PUSH_NOTIFICATION_MESSAGE_FLAGS = 0x20,
+ /* Meta: Keywords */
+ PUSH_NOTIFICATION_MESSAGE_KEYWORDS = 0x40,
+ /* Header: Message-ID */
+ PUSH_NOTIFICATION_MESSAGE_HDR_MESSAGE_ID = 0x80,
+};
+
+struct push_notification_message_ext {
+ const char *from_address, *from_display_name_utf8;
+ const char *to_address, *to_display_name_utf8;
+ const char *subject_utf8;
+};
+
+void push_notification_message_fill(
+ struct mail *mail, pool_t pool,
+ enum push_notification_event_message_flags event_flags,
+ const char **from, const char **to, const char **subject, time_t *date,
+ int *date_tz, const char **message_id, enum mail_flags *flags,
+ bool *flags_set, const char *const **keywords, const char **snippet,
+ struct push_notification_message_ext *ext);
+
+#endif
+
diff --git a/src/plugins/push-notification/push-notification-event-messageappend.c b/src/plugins/push-notification/push-notification-event-messageappend.c
new file mode 100644
index 0000000..b6e0318
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messageappend.c
@@ -0,0 +1,99 @@
+/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "hash.h"
+#include "istream.h"
+#include "iso8601-date.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-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)
+{
+ i_zero(&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;
+ 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_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;
+
+ if (config->flags == 0)
+ 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);
+ data->date = -1;
+ push_notification_txn_msg_set_eventdata(ptxn, msg, ec, data);
+ }
+
+ push_notification_message_fill(mail, ptxn->pool, config->flags,
+ &data->from, &data->to, &data->subject,
+ &data->date, &data->date_tz,
+ &data->message_id,
+ &data->flags, &data->flags_set,
+ &data->keywords,
+ &data->snippet, &data->ext);
+}
+
+/* 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-messageappend.h b/src/plugins/push-notification/push-notification-event-messageappend.h
new file mode 100644
index 0000000..511fc6b
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messageappend.h
@@ -0,0 +1,30 @@
+/* Copyright (c) 2015-2018 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;
+ /* PUSH_NOTIFICATION_MESSAGE_HDR_DATE */
+ time_t date;
+ int date_tz;
+ /* PUSH_NOTIFICATION_MESSAGE_FLAGS */
+ bool flags_set;
+ enum mail_flags flags;
+ /* PUSH_NOTIFICATION_MESSAGE_KEYWORDS */
+ const char *const *keywords;
+ /* PUSH_NOTIFICATION_MESSAGE_HDR_MESSAGE_ID */
+ const char *message_id;
+
+ struct push_notification_message_ext ext;
+};
+
+#endif
+
diff --git a/src/plugins/push-notification/push-notification-event-messageexpunge.c b/src/plugins/push-notification/push-notification-event-messageexpunge.c
new file mode 100644
index 0000000..cfa301e
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messageexpunge.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2015-2018 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-messageexpunge.h b/src/plugins/push-notification/push-notification-event-messageexpunge.h
new file mode 100644
index 0000000..bc20f73
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messageexpunge.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-event-messagenew.c b/src/plugins/push-notification/push-notification-event-messagenew.c
new file mode 100644
index 0000000..930c0ee
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messagenew.c
@@ -0,0 +1,97 @@
+/* Copyright (c) 2015-2018 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)
+{
+ i_zero(&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;
+
+ if (config->flags == 0)
+ 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);
+ }
+
+ push_notification_message_fill(mail, ptxn->pool, config->flags,
+ &data->from, &data->to, &data->subject,
+ &data->date, &data->date_tz,
+ &data->message_id,
+ &data->flags, &data->flags_set,
+ &data->keywords,
+ &data->snippet, &data->ext);
+}
+
+/* Event definition */
+
+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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-messagenew.h b/src/plugins/push-notification/push-notification-event-messagenew.h
new file mode 100644
index 0000000..a939668
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messagenew.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 2015-2018 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;
+ /* PUSH_NOTIFICATION_MESSAGE_FLAGS */
+ bool flags_set;
+ enum mail_flags flags;
+ /* PUSH_NOTIFICATION_MESSAGE_KEYWORDS */
+ const char *const *keywords;
+ /* PUSH_NOTIFICATION_MESSAGE_HDR_MESSAGE_ID */
+ const char *message_id;
+
+ struct push_notification_message_ext ext;
+};
+
+#endif
+
diff --git a/src/plugins/push-notification/push-notification-event-messageread.c b/src/plugins/push-notification/push-notification-event-messageread.c
new file mode 100644
index 0000000..8f0d709
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messageread.c
@@ -0,0 +1,58 @@
+/* Copyright (c) 2015-2018 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) == 0) {
+ flags = mail_get_flags(mail);
+ if ((flags & MAIL_SEEN) != 0) {
+ 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-messageread.h b/src/plugins/push-notification/push-notification-event-messageread.h
new file mode 100644
index 0000000..6eb5c18
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messageread.h
@@ -0,0 +1,11 @@
+/* Copyright (c) 2015-2018 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
diff --git a/src/plugins/push-notification/push-notification-event-messagetrash.c b/src/plugins/push-notification/push-notification-event-messagetrash.c
new file mode 100644
index 0000000..2284b6f
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messagetrash.c
@@ -0,0 +1,58 @@
+/* Copyright (c) 2015-2018 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) == 0) {
+ flags = mail_get_flags(mail);
+ if ((flags & MAIL_DELETED) != 0) {
+ 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,
+ },
+};
diff --git a/src/plugins/push-notification/push-notification-event-messagetrash.h b/src/plugins/push-notification/push-notification-event-messagetrash.h
new file mode 100644
index 0000000..712732f
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-event-messagetrash.h
@@ -0,0 +1,12 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-events-rfc5423.c b/src/plugins/push-notification/push-notification-events-rfc5423.c
new file mode 100644
index 0000000..10dd0c7
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-events-rfc5423.c
@@ -0,0 +1,59 @@
+/* Copyright (c) 2015-2018 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;
+
+static struct push_notification_event *rfc5423_events[] = {
+ &push_notification_event_flagsclear,
+ &push_notification_event_flagsset,
+ &push_notification_event_mailboxcreate,
+ &push_notification_event_mailboxdelete,
+ &push_notification_event_mailboxrename,
+ &push_notification_event_mailboxsubscribe,
+ &push_notification_event_mailboxunsubscribe,
+ &push_notification_event_messageappend,
+ &push_notification_event_messageexpunge,
+ &push_notification_event_messagenew,
+ &push_notification_event_messageread,
+ &push_notification_event_messagetrash
+};
+
+void push_notification_event_register_rfc5423_events(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < N_ELEMENTS(rfc5423_events); i++)
+ push_notification_event_register(rfc5423_events[i]);
+}
+
+void push_notification_event_unregister_rfc5423_events(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < N_ELEMENTS(rfc5423_events); i++)
+ push_notification_event_unregister(rfc5423_events[i]);
+}
diff --git a/src/plugins/push-notification/push-notification-events-rfc5423.h b/src/plugins/push-notification/push-notification-events-rfc5423.h
new file mode 100644
index 0000000..71f7009
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-events-rfc5423.h
@@ -0,0 +1,10 @@
+/* Copyright (c) 2015-2018 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);
+void push_notification_event_unregister_rfc5423_events(void);
+
+#endif
+
diff --git a/src/plugins/push-notification/push-notification-events.c b/src/plugins/push-notification/push-notification-events.c
new file mode 100644
index 0000000..a71e8a6
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-events.c
@@ -0,0 +1,100 @@
+/* Copyright (c) 2015-2018 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;
+
+ARRAY_TYPE(push_notification_event) *push_notification_get_events(void)
+{
+ return &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)
+{
+ unsigned int idx;
+
+ if (!push_notification_event_find(driver, &idx))
+ return NULL;
+
+ return array_idx_elem(&push_notification_events, idx);
+}
+
+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_push_back(&dtxn->ptxn->events, &ec);
+ }
+}
+
+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_push_back(&push_notification_events, &event);
+}
+
+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);
+ }
+}
diff --git a/src/plugins/push-notification/push-notification-events.h b/src/plugins/push-notification/push-notification-events.h
new file mode 100644
index 0000000..f20075f
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-events.h
@@ -0,0 +1,124 @@
+/* Copyright (c) 2015-2018 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;
+
+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;
+
+ARRAY_TYPE(push_notification_event) *push_notification_get_events(void);
+
+
+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
+
diff --git a/src/plugins/push-notification/push-notification-plugin.c b/src/plugins/push-notification/push-notification-plugin.c
new file mode 100644
index 0000000..22c2fb0
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-plugin.c
@@ -0,0 +1,390 @@
+/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "ioloop.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_EVENT_FINISHED "push_notification_finished"
+
+#define PUSH_NOTIFICATION_USER_CONTEXT(obj) \
+ MODULE_CONTEXT_REQUIRE(obj, push_notification_user_module)
+static MODULE_CONTEXT_DEFINE_INIT(push_notification_user_module,
+ &mail_user_module_register);
+static struct ioloop *main_ioloop;
+
+struct event_category event_category_push_notification = {
+ .name = "push-notification",
+};
+
+struct event_category *push_notification_get_event_category(void)
+{
+ return &event_category_push_notification;
+}
+
+struct push_notification_event *push_notification_get_event_messagenew(void)
+{
+ return &push_notification_event_messagenew;
+}
+
+static void
+push_notification_transaction_init(struct push_notification_txn *ptxn)
+{
+ struct push_notification_driver_txn *dtxn;
+ struct push_notification_driver_user *duser;
+ struct mail_storage *storage;
+
+ if (ptxn->initialized)
+ return;
+
+ ptxn->initialized = TRUE;
+
+ storage = mailbox_get_storage(ptxn->mbox);
+ if (storage->user->autocreated &&
+ (strcmp(storage->name, "raw") == 0)) {
+ /* No notifications for autocreated raw users */
+ return;
+ }
+
+ array_foreach_elem(&ptxn->puser->driverlist->drivers, duser) {
+ dtxn = p_new(ptxn->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_push_back(&ptxn->drivers, &dtxn);
+ }
+ }
+}
+
+static struct push_notification_txn *
+push_notification_transaction_create(struct mailbox *box,
+ struct mailbox_transaction_context *t)
+{
+ 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;
+ ptxn->event = event_create(ptxn->muser->event);
+ event_add_category(ptxn->event, &event_category_push_notification);
+ event_set_append_log_prefix(ptxn->event, "push-notification: ");
+ p_array_init(&ptxn->drivers, pool, 4);
+
+ return ptxn;
+}
+
+static void
+push_notification_transaction_end(struct push_notification_txn *ptxn,
+ bool success)
+{
+ struct push_notification_driver_txn *dtxn;
+
+ if (ptxn->initialized) {
+ array_foreach_elem(&ptxn->drivers, dtxn) {
+ if (dtxn->duser->driver->v.end_txn != NULL)
+ dtxn->duser->driver->v.end_txn(dtxn, success);
+ }
+ }
+
+ if (success && ptxn->trigger != 0) {
+ struct event_passthrough *e = event_create_passthrough(ptxn->event)->
+ set_name(PUSH_NOTIFICATION_EVENT_FINISHED);
+ /* Emit event */
+ e_debug(e->event(), "Push notification transaction completed");
+ }
+
+ event_unref(&ptxn->event);
+ 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;
+ struct ioloop *prev_ioloop = current_ioloop;
+
+ /* Make sure we're not in just any random ioloop, which could get
+ destroyed soon. This way the push-notification drivers can do async
+ operations that finish in the main ioloop. */
+ io_loop_set_current(main_ioloop);
+ if (changes == NULL)
+ push_notification_txn_mbox_end(ptxn);
+ else
+ push_notification_txn_msg_end(ptxn, changes);
+
+ push_notification_transaction_end(ptxn, TRUE);
+ io_loop_set_current(prev_ioloop);
+}
+
+static void push_notification_mailbox_create(struct mailbox *box)
+{
+ struct push_notification_txn *ptxn;
+
+ ptxn = push_notification_transaction_create(box, NULL);
+ push_notification_transaction_init(ptxn);
+ 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_transaction_init(ptxn);
+ 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_transaction_init(ptxn);
+ 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_transaction_init(ptxn);
+ 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 = txn;
+
+ push_notification_transaction_init(ptxn);
+
+ /* POST_SESSION means MTA delivery. */
+ if ((mail->box->flags & MAILBOX_FLAG_POST_SESSION) != 0)
+ push_notification_trigger_msg_save_new(ptxn, mail, NULL);
+ else
+ push_notification_trigger_msg_save_append(ptxn, mail, NULL);
+}
+
+static void
+push_notification_mail_copy(void *txn, struct mail *src ATTR_UNUSED,
+ struct mail *dest)
+{
+ push_notification_mail_save(txn, dest);
+}
+
+static void push_notification_mail_expunge(void *txn, struct mail *mail)
+{
+ struct push_notification_txn *ptxn = txn;
+
+ push_notification_transaction_init(ptxn);
+ push_notification_trigger_msg_save_expunge(txn, mail, NULL);
+}
+
+static void
+push_notification_mail_update_flags(void *txn, struct mail *mail,
+ enum mail_flags old_flags)
+{
+ struct push_notification_txn *ptxn = txn;
+
+ push_notification_transaction_init(ptxn);
+ push_notification_trigger_msg_flag_change(txn, mail, NULL, old_flags);
+}
+
+static void
+push_notification_mail_update_keywords(void *txn, struct mail *mail,
+ const char *const *old_keywords)
+{
+ struct push_notification_txn *ptxn = txn;
+
+ push_notification_transaction_init(ptxn);
+ push_notification_trigger_msg_keyword_change(
+ 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 = txn;
+
+ push_notification_transaction_end(ptxn, FALSE);
+}
+
+static void
+push_notification_config_init(const char *config_name, struct mail_user *user,
+ struct push_notification_driver_list *dlist)
+{
+ 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, user->pool, &duser) < 0)
+ break;
+
+ /* Add driver. */
+ array_push_back(&dlist->drivers, &duser);
+
+ str_truncate(root_name, strlen(config_name));
+ str_printfa(root_name, "%d", i);
+ }
+}
+
+static struct push_notification_driver_list *
+push_notification_driver_list_init(struct mail_user *user)
+{
+ struct push_notification_driver_list *dlist;
+
+ dlist = p_new(user->pool, struct push_notification_driver_list, 1);
+ p_array_init(&dlist->drivers, user->pool, 4);
+
+ push_notification_config_init(PUSH_NOTIFICATION_CONFIG, user, dlist);
+
+ if (array_is_empty(&dlist->drivers)) {
+ /* Support old configuration (it was available at time initial
+ OX driver was first released). */
+ push_notification_config_init(PUSH_NOTIFICATION_CONFIG_OLD,
+ user, dlist);
+ }
+ return dlist;
+}
+
+static void push_notification_user_deinit(struct mail_user *user)
+{
+ struct push_notification_user *puser =
+ PUSH_NOTIFICATION_USER_CONTEXT(user);
+ struct push_notification_driver_list *dlist = puser->driverlist;
+ struct push_notification_driver_user *duser;
+ struct ioloop *prev_ioloop = current_ioloop;
+
+ /* Make sure we're in the main ioloop, so if the deinit/cleanup moves
+ any I/Os or timeouts they won't get moved to some temporary ioloop.
+ */
+ io_loop_set_current(main_ioloop);
+
+ array_foreach_elem(&dlist->drivers, duser) {
+ if (duser->driver->v.deinit != NULL)
+ duser->driver->v.deinit(duser);
+ if (duser->driver->v.cleanup != NULL)
+ duser->driver->v.cleanup();
+ }
+ io_loop_set_current(prev_ioloop);
+
+ puser->module_ctx.super.deinit(user);
+}
+
+static void push_notification_user_created(struct mail_user *user)
+{
+ struct mail_user_vfuncs *v = user->vlast;
+ struct push_notification_user *puser;
+
+ puser = p_new(user->pool, struct push_notification_user, 1);
+ puser->module_ctx.super = *v;
+ user->vlast = &puser->module_ctx.super;
+ v->deinit = push_notification_user_deinit;
+ puser->driverlist = push_notification_driver_list_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();
+ main_ioloop = current_ioloop;
+ i_assert(main_ioloop != NULL);
+}
+
+void push_notification_plugin_deinit(void)
+{
+ push_notification_driver_unregister(&push_notification_driver_dlog);
+ push_notification_driver_unregister(&push_notification_driver_ox);
+
+ push_notification_event_unregister_rfc5423_events();
+ mail_storage_hooks_remove(&push_notification_storage_hooks);
+ notify_unregister(push_notification_ctx);
+}
diff --git a/src/plugins/push-notification/push-notification-plugin.h b/src/plugins/push-notification/push-notification-plugin.h
new file mode 100644
index 0000000..7db5397
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-plugin.h
@@ -0,0 +1,18 @@
+/* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
+
+#ifndef PUSH_NOTIFICATION_PLUGIN_H
+#define PUSH_NOTIFICATION_PLUGIN_H
+
+extern const char *push_notification_plugin_dependencies[];
+extern struct event_category event_category_push_notification;
+extern struct push_notification_event push_notification_event_messagenew;
+
+struct module;
+
+struct event_category *push_notification_get_event_category(void);
+struct push_notification_event *push_notification_get_event_messagenew(void);
+
+void push_notification_plugin_init(struct module *module);
+void push_notification_plugin_deinit(void);
+
+#endif
diff --git a/src/plugins/push-notification/push-notification-triggers.c b/src/plugins/push-notification/push-notification-triggers.c
new file mode 100644
index 0000000..3882982
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-triggers.c
@@ -0,0 +1,215 @@
+/* Copyright (c) 2015-2018 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;
+ event_add_str(txn->event, "mailbox", mailbox_get_vname(box));
+}
+
+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_elem(&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_elem(&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_elem(&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_elem(&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_elem(&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_elem(&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_elem(&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_elem(&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_elem(&txn->events, ec) {
+ if (ec->event->msg_triggers.keywordchange != NULL) {
+ ec->event->msg_triggers.keywordchange(
+ txn, ec, msg, mail, old_keywords);
+ }
+ }
+ }
+}
diff --git a/src/plugins/push-notification/push-notification-triggers.h b/src/plugins/push-notification/push-notification-triggers.h
new file mode 100644
index 0000000..b29bc47
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-triggers.h
@@ -0,0 +1,64 @@
+/* Copyright (c) 2015-2018 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
+
diff --git a/src/plugins/push-notification/push-notification-txn-mbox.c b/src/plugins/push-notification/push-notification-txn-mbox.c
new file mode 100644
index 0000000..4401819
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-txn-mbox.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2015-2018 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_push_back(&mbox->eventdata, &mevent);
+}
+
+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);
+ }
+ }
+ }
+}
diff --git a/src/plugins/push-notification/push-notification-txn-mbox.h b/src/plugins/push-notification/push-notification-txn-mbox.h
new file mode 100644
index 0000000..c7a7e55
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-txn-mbox.h
@@ -0,0 +1,29 @@
+/* Copyright (c) 2015-2018 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
diff --git a/src/plugins/push-notification/push-notification-txn-msg.c b/src/plugins/push-notification/push-notification-txn-msg.c
new file mode 100644
index 0000000..ff37bff
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-txn-msg.c
@@ -0,0 +1,139 @@
+/* Copyright (c) 2015-2018 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(mail->seq));
+ } 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. */
+ if (mail->uid == 0)
+ msg->save_idx = txn->t->save_count;
+ else
+ msg->save_idx = UINT_MAX;
+ msg->uid = mail->uid;
+
+ hash_table_insert(txn->messages, POINTER_CAST(mail->seq),
+ 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, uid_validity;
+ 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);
+
+ /* 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);
+ uid_validity = status.uidvalidity;
+ } else {
+ uid_validity = changes->uid_validity;
+ }
+
+ while (hash_table_iterate(hiter, ptxn->messages, &key, &value)) {
+ if (value->uid == 0) {
+ if (seq_range_array_iter_nth(&siter, value->save_idx, &uid)) {
+ value->uid = uid;
+ }
+ } else
+ i_assert(value->save_idx == UINT_MAX);
+ value->uid_validity = 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_push_back(&msg->eventdata, &mevent);
+}
+
+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);
+ }
+ }
+ }
+}
diff --git a/src/plugins/push-notification/push-notification-txn-msg.h b/src/plugins/push-notification/push-notification-txn-msg.h
new file mode 100644
index 0000000..777f115
--- /dev/null
+++ b/src/plugins/push-notification/push-notification-txn-msg.h
@@ -0,0 +1,39 @@
+/* Copyright (c) 2015-2018 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 save_idx;
+};
+
+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