diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/plugins/push-notification | |
parent | Initial commit. (diff) | |
download | dovecot-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 'src/plugins/push-notification')
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 |