diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/enotify')
16 files changed, 5440 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.am b/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.am new file mode 100644 index 0000000..4b65630 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.am @@ -0,0 +1,44 @@ +SUBDIRS = mailto + +noinst_LTLIBRARIES = libsieve_ext_enotify.la + +AM_CPPFLAGS = \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../variables \ + $(LIBDOVECOT_INCLUDE) + +commands = \ + cmd-notify.c + +tests = \ + tst-valid-notify-method.c \ + tst-notify-method-capability.c + +var_modifiers = \ + vmodf-encodeurl.c + +notify_methods = \ + ./mailto/libsieve_ext_enotify_mailto.la + +libsieve_ext_enotify_la_DEPENDENCIES = \ + $(notify_methods) +libsieve_ext_enotify_la_LIBADD = \ + $(notify_methods) + +libsieve_ext_enotify_la_SOURCES = \ + ext-enotify.c \ + ext-enotify-common.c \ + $(commands) \ + $(tests) \ + $(var_modifiers) + +public_headers = \ + sieve-ext-enotify.h + +headers = \ + ext-enotify-limits.h \ + ext-enotify-common.h + +pkginc_libdir=$(dovecot_pkgincludedir)/sieve +pkginc_lib_HEADERS = $(public_headers) +noinst_HEADERS = $(headers) diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.in b/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.in new file mode 100644 index 0000000..33c43d0 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/Makefile.in @@ -0,0 +1,904 @@ +# 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@ +subdir = src/lib-sieve/plugins/enotify +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(pkginc_lib_HEADERS) $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/dummy-config.h \ + $(top_builddir)/pigeonhole-config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +am__objects_1 = cmd-notify.lo +am__objects_2 = tst-valid-notify-method.lo \ + tst-notify-method-capability.lo +am__objects_3 = vmodf-encodeurl.lo +am_libsieve_ext_enotify_la_OBJECTS = ext-enotify.lo \ + ext-enotify-common.lo $(am__objects_1) $(am__objects_2) \ + $(am__objects_3) +libsieve_ext_enotify_la_OBJECTS = \ + $(am_libsieve_ext_enotify_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 = +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)/cmd-notify.Plo \ + ./$(DEPDIR)/ext-enotify-common.Plo ./$(DEPDIR)/ext-enotify.Plo \ + ./$(DEPDIR)/tst-notify-method-capability.Plo \ + ./$(DEPDIR)/tst-valid-notify-method.Plo \ + ./$(DEPDIR)/vmodf-encodeurl.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 = $(libsieve_ext_enotify_la_SOURCES) +DIST_SOURCES = $(libsieve_ext_enotify_la_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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)$(pkginc_libdir)" +HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +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 +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINARY_CFLAGS = @BINARY_CFLAGS@ +BINARY_LDFLAGS = @BINARY_LDFLAGS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@ +DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@ +DOVECOT_CFLAGS = @DOVECOT_CFLAGS@ +DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@ +DOVECOT_INSTALLED = @DOVECOT_INSTALLED@ +DOVECOT_LIBS = @DOVECOT_LIBS@ +DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@ +DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@ +DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@ +DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDAP_LIBS = @LDAP_LIBS@ +LDFLAGS = @LDFLAGS@ +LIBDOVECOT = @LIBDOVECOT@ +LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@ +LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@ +LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@ +LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@ +LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@ +LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@ +LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@ +LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@ +LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@ +LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@ +LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@ +LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@ +LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@ +LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@ +LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@ +LIBDOVECOT_LDA = @LIBDOVECOT_LDA@ +LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@ +LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@ +LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@ +LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@ +LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@ +LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@ +LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@ +LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@ +LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@ +LIBDOVECOT_LUA = @LIBDOVECOT_LUA@ +LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@ +LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@ +LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@ +LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@ +LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@ +LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@ +LIBDOVECOT_SQL = @LIBDOVECOT_SQL@ +LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@ +LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@ +LIBDOVECOT_SSL = @LIBDOVECOT_SSL@ +LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@ +LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@ +LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@ +LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@ +LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +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@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RUN_TEST = @RUN_TEST@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +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_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@ +docdir = @docdir@ +dovecot_docdir = @dovecot_docdir@ +dovecot_installed_moduledir = @dovecot_installed_moduledir@ +dovecot_moduledir = @dovecot_moduledir@ +dovecot_pkgincludedir = @dovecot_pkgincludedir@ +dovecot_pkglibdir = @dovecot_pkglibdir@ +dovecot_pkglibexecdir = @dovecot_pkglibexecdir@ +dovecot_statedir = @dovecot_statedir@ +dovecotdir = @dovecotdir@ +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@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sieve_docdir = @sieve_docdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = mailto +noinst_LTLIBRARIES = libsieve_ext_enotify.la +AM_CPPFLAGS = \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../variables \ + $(LIBDOVECOT_INCLUDE) + +commands = \ + cmd-notify.c + +tests = \ + tst-valid-notify-method.c \ + tst-notify-method-capability.c + +var_modifiers = \ + vmodf-encodeurl.c + +notify_methods = \ + ./mailto/libsieve_ext_enotify_mailto.la + +libsieve_ext_enotify_la_DEPENDENCIES = \ + $(notify_methods) + +libsieve_ext_enotify_la_LIBADD = \ + $(notify_methods) + +libsieve_ext_enotify_la_SOURCES = \ + ext-enotify.c \ + ext-enotify-common.c \ + $(commands) \ + $(tests) \ + $(var_modifiers) + +public_headers = \ + sieve-ext-enotify.h + +headers = \ + ext-enotify-limits.h \ + ext-enotify-common.h + +pkginc_libdir = $(dovecot_pkgincludedir)/sieve +pkginc_lib_HEADERS = $(public_headers) +noinst_HEADERS = $(headers) +all: all-recursive + +.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/lib-sieve/plugins/enotify/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/lib-sieve/plugins/enotify/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): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_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}; \ + } + +libsieve_ext_enotify.la: $(libsieve_ext_enotify_la_OBJECTS) $(libsieve_ext_enotify_la_DEPENDENCIES) $(EXTRA_libsieve_ext_enotify_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libsieve_ext_enotify_la_OBJECTS) $(libsieve_ext_enotify_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-notify.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-enotify-common.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-enotify.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-notify-method-capability.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-valid-notify-method.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vmodf-encodeurl.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 $@ $< + +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) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(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-recursive + +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-recursive + +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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(pkginc_libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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-recursive + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/cmd-notify.Plo + -rm -f ./$(DEPDIR)/ext-enotify-common.Plo + -rm -f ./$(DEPDIR)/ext-enotify.Plo + -rm -f ./$(DEPDIR)/tst-notify-method-capability.Plo + -rm -f ./$(DEPDIR)/tst-valid-notify-method.Plo + -rm -f ./$(DEPDIR)/vmodf-encodeurl.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-pkginc_libHEADERS + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/cmd-notify.Plo + -rm -f ./$(DEPDIR)/ext-enotify-common.Plo + -rm -f ./$(DEPDIR)/ext-enotify.Plo + -rm -f ./$(DEPDIR)/tst-notify-method-capability.Plo + -rm -f ./$(DEPDIR)/tst-valid-notify-method.Plo + -rm -f ./$(DEPDIR)/vmodf-encodeurl.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-pkginc_libHEADERS + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-generic clean-libtool \ + clean-noinstLTLIBRARIES 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-pdf install-pdf-am install-pkginc_libHEADERS \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am 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-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/pigeonhole/src/lib-sieve/plugins/enotify/cmd-notify.c b/pigeonhole/src/lib-sieve/plugins/enotify/cmd-notify.c new file mode 100644 index 0000000..4fe121a --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/cmd-notify.c @@ -0,0 +1,621 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str-sanitize.h" + +#include "sieve-common.h" +#include "sieve-error.h" +#include "sieve-code.h" +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-actions.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" +#include "sieve-result.h" + +#include "ext-enotify-common.h" + +/* + * Forward declarations + */ + +static const struct sieve_argument_def notify_importance_tag; +static const struct sieve_argument_def notify_from_tag; +static const struct sieve_argument_def notify_options_tag; +static const struct sieve_argument_def notify_message_tag; + +/* + * Notify command + * + * Syntax: + * notify [":from" string] + * [":importance" <"1" / "2" / "3">] + * [":options" string-list] + * [":message" string] + * <method: string> + */ + +static bool +cmd_notify_registered(struct sieve_validator *valdtr, + const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg); +static bool +cmd_notify_pre_validate(struct sieve_validator *validator, + struct sieve_command *cmd); +static bool +cmd_notify_validate(struct sieve_validator *valdtr, struct sieve_command *cmd); +static bool +cmd_notify_generate(const struct sieve_codegen_env *cgenv, + struct sieve_command *ctx); + +const struct sieve_command_def notify_command = { + .identifier = "notify", + .type = SCT_COMMAND, + .positional_args = 1, + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .registered = cmd_notify_registered, + .pre_validate = cmd_notify_pre_validate, + .validate = cmd_notify_validate, + .generate = cmd_notify_generate, +}; + +/* + * Notify command tags + */ + +/* Forward declarations */ + +static bool +cmd_notify_validate_string_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd); +static bool +cmd_notify_validate_stringlist_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd); +static bool +cmd_notify_validate_importance_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd); + +/* Argument objects */ + +static const struct sieve_argument_def notify_from_tag = { + .identifier = "from", + .validate = cmd_notify_validate_string_tag +}; + +static const struct sieve_argument_def notify_options_tag = { + .identifier = "options", + .validate = cmd_notify_validate_stringlist_tag +}; + +static const struct sieve_argument_def notify_message_tag = { + .identifier = "message", + .validate = cmd_notify_validate_string_tag +}; + +static const struct sieve_argument_def notify_importance_tag = { + .identifier = "importance", + .validate = cmd_notify_validate_importance_tag +}; + +/* + * Notify operation + */ + +static bool +cmd_notify_operation_dump(const struct sieve_dumptime_env *denv, + sieve_size_t *address); +static int +cmd_notify_operation_execute(const struct sieve_runtime_env *renv, + sieve_size_t *address); + +const struct sieve_operation_def notify_operation = { + .mnemonic = "NOTIFY", + .ext_def = &enotify_extension, + .code = EXT_ENOTIFY_OPERATION_NOTIFY, + .dump = cmd_notify_operation_dump, + .execute = cmd_notify_operation_execute +}; + +/* + * Notify action + */ + +/* Forward declarations */ + +static int +act_notify_check_duplicate(const struct sieve_runtime_env *renv, + const struct sieve_action *act, + const struct sieve_action *act_other); +static void +act_notify_print(const struct sieve_action *action, + const struct sieve_result_print_env *rpenv, + bool *keep); +static int +act_notify_commit(const struct sieve_action_exec_env *aenv, void *tr_context); + +/* Action object */ + +const struct sieve_action_def act_notify = { + .name = "notify", + .check_duplicate =act_notify_check_duplicate, + .print = act_notify_print, + .commit = act_notify_commit, +}; + +/* + * Command validation context + */ + +struct cmd_notify_context_data { + struct sieve_ast_argument *from; + struct sieve_ast_argument *message; + struct sieve_ast_argument *options; +}; + +/* + * Tag validation + */ + +static bool +cmd_notify_validate_string_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct sieve_ast_argument *tag = *arg; + struct cmd_notify_context_data *ctx_data = + (struct cmd_notify_context_data *)cmd->data; + + /* Detach the tag itself */ + *arg = sieve_ast_arguments_detach(*arg,1); + + /* Check syntax: + * :from <string> + * :message <string> + */ + if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0, + SAAT_STRING, FALSE)) + return FALSE; + + if (sieve_argument_is(tag, notify_from_tag)) { + ctx_data->from = *arg; + + /* Skip parameter */ + *arg = sieve_ast_argument_next(*arg); + } else if (sieve_argument_is(tag, notify_message_tag)) { + ctx_data->message = *arg; + + /* Skip parameter */ + *arg = sieve_ast_argument_next(*arg); + } + return TRUE; +} + +static bool +cmd_notify_validate_stringlist_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct sieve_ast_argument *tag = *arg; + struct cmd_notify_context_data *ctx_data = + (struct cmd_notify_context_data *)cmd->data; + + /* Detach the tag itself */ + *arg = sieve_ast_arguments_detach(*arg,1); + + /* Check syntax: + * :options string-list + */ + if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0, + SAAT_STRING_LIST, FALSE)) + return FALSE; + + /* Assign context */ + ctx_data->options = *arg; + + /* Skip parameter */ + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +static bool +cmd_notify_validate_importance_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd ATTR_UNUSED) +{ + const struct sieve_ast_argument *tag = *arg; + const char *impstr; + + /* Detach the tag itself */ + *arg = sieve_ast_arguments_detach(*arg,1); + + /* Check syntax: + * :importance <"1" / "2" / "3"> + */ + if (sieve_ast_argument_type(*arg) != SAAT_STRING) { + /* Not a string */ + sieve_argument_validate_error( + valdtr, *arg, + "the :importance tag for the notify command requires a string parameter, " + "but %s was found", sieve_ast_argument_name(*arg)); + return FALSE; + } + + impstr = sieve_ast_argument_strc(*arg); + if (impstr[0] < '1' || impstr[0] > '3' || impstr[1] != '\0') { + /* Invalid importance */ + sieve_argument_validate_error( + valdtr, *arg, + "invalid :importance value for notify command: %s", + impstr); + return FALSE; + } + + sieve_ast_argument_number_substitute(*arg, impstr[0] - '0'); + (*arg)->argument = sieve_argument_create((*arg)->ast, &number_argument, + tag->argument->ext, + tag->argument->id_code); + + /* Skip parameter */ + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +/* + * Command registration + */ + +static bool +cmd_notify_registered(struct sieve_validator *valdtr, + const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg) +{ + sieve_validator_register_tag(valdtr, cmd_reg, ext, + ¬ify_importance_tag, + CMD_NOTIFY_OPT_IMPORTANCE); + sieve_validator_register_tag(valdtr, cmd_reg, ext, + ¬ify_from_tag, CMD_NOTIFY_OPT_FROM); + sieve_validator_register_tag(valdtr, cmd_reg, ext, + ¬ify_options_tag, + CMD_NOTIFY_OPT_OPTIONS); + sieve_validator_register_tag(valdtr, cmd_reg, ext, + ¬ify_message_tag, + CMD_NOTIFY_OPT_MESSAGE); + return TRUE; +} + +/* + * Command validation + */ + +static bool +cmd_notify_pre_validate(struct sieve_validator *validator ATTR_UNUSED, + struct sieve_command *cmd) +{ + struct cmd_notify_context_data *ctx_data; + + /* Assign context */ + ctx_data = p_new(sieve_command_pool(cmd), + struct cmd_notify_context_data, 1); + cmd->data = ctx_data; + + return TRUE; +} + +static bool +cmd_notify_validate(struct sieve_validator *valdtr, struct sieve_command *cmd) +{ + struct sieve_ast_argument *arg = cmd->first_positional; + struct cmd_notify_context_data *ctx_data = + (struct cmd_notify_context_data *)cmd->data; + + if (!sieve_validate_positional_argument(valdtr, cmd, arg, "method", 1, + SAAT_STRING)) + return FALSE; + + if (!sieve_validator_argument_activate(valdtr, cmd, arg, FALSE)) + return FALSE; + + return ext_enotify_compile_check_arguments( + valdtr, cmd, arg, ctx_data->message, ctx_data->from, + ctx_data->options); +} + +/* + * Code generation + */ + +static bool +cmd_notify_generate(const struct sieve_codegen_env *cgenv, + struct sieve_command *cmd) +{ + sieve_operation_emit(cgenv->sblock, cmd->ext, ¬ify_operation); + + /* Generate arguments */ + return sieve_generate_arguments(cgenv, cmd, NULL); +} + +/* + * Code dump + */ + +static bool +cmd_notify_operation_dump(const struct sieve_dumptime_env *denv, + sieve_size_t *address) +{ + int opt_code = 0; + + sieve_code_dumpf(denv, "NOTIFY"); + sieve_code_descend(denv); + + /* Dump optional operands */ + + for (;;) { + int opt; + bool opok = TRUE; + + if ((opt = sieve_opr_optional_dump(denv, address, + &opt_code)) < 0) + return FALSE; + + if (opt == 0) + break; + + switch (opt_code) { + case CMD_NOTIFY_OPT_IMPORTANCE: + opok = sieve_opr_number_dump(denv, address, + "importance"); + break; + case CMD_NOTIFY_OPT_FROM: + opok = sieve_opr_string_dump(denv, address, "from"); + break; + case CMD_NOTIFY_OPT_OPTIONS: + opok = sieve_opr_stringlist_dump(denv, address, + "options"); + break; + case CMD_NOTIFY_OPT_MESSAGE: + opok = sieve_opr_string_dump(denv, address, "message"); + break; + default: + return FALSE; + } + + if (!opok) + return FALSE; + } + + /* Dump method operand */ + return sieve_opr_string_dump(denv, address, "method"); +} + +/* + * Code execution + */ + +static int +cmd_notify_operation_execute(const struct sieve_runtime_env *renv, + sieve_size_t *address) +{ + const struct sieve_extension *this_ext = renv->oprtn->ext; + struct sieve_side_effects_list *slist = NULL; + struct sieve_enotify_action *act; + void *method_context; + pool_t pool; + int opt_code = 0; + sieve_number_t importance = 2; + struct sieve_stringlist *options = NULL; + const struct sieve_enotify_method *method; + string_t *method_uri, *message = NULL, *from = NULL; + int ret; + + /* + * Read operands + */ + + /* Optional operands */ + + for (;;) { + int opt; + + if ((opt = sieve_opr_optional_read(renv, address, + &opt_code)) < 0) + return SIEVE_EXEC_BIN_CORRUPT; + + if (opt == 0) break; + + switch (opt_code) { + case CMD_NOTIFY_OPT_IMPORTANCE: + ret = sieve_opr_number_read(renv, address, "importance", + &importance); + break; + case CMD_NOTIFY_OPT_FROM: + ret = sieve_opr_string_read(renv, address, "from", + &from); + break; + case CMD_NOTIFY_OPT_MESSAGE: + ret = sieve_opr_string_read(renv, address, "message", + &message); + break; + case CMD_NOTIFY_OPT_OPTIONS: + ret = sieve_opr_stringlist_read(renv, address, + "options", &options); + break; + default: + sieve_runtime_trace_error( + renv, "unknown optional operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + if (ret <= 0) + return ret; + } + + /* Method operand */ + + if ((ret = sieve_opr_string_read(renv, address, "method", + &method_uri)) <= 0) + return ret; + + /* + * Perform operation + */ + + /* Enforce 0 < importance < 4 (just to be sure) */ + + if (importance < 1) + importance = 1; + else if (importance > 3) + importance = 3; + + /* Trace */ + + if (sieve_runtime_trace_active(renv, SIEVE_TRLVL_ACTIONS)) { + sieve_runtime_trace(renv, 0, "notify action"); + sieve_runtime_trace_descend(renv); + sieve_runtime_trace(renv, 0, "notify with uri `%s'", + str_sanitize(str_c(method_uri), 80)); + } + + /* Check operands */ + + if ((ret = ext_enotify_runtime_check_operands(renv, method_uri, message, + from, options, &method, + &method_context)) > 0) + { + /* Add notify action to the result */ + pool = sieve_result_pool(renv->result); + act = p_new(pool, struct sieve_enotify_action, 1); + act->method = method; + act->method_context = method_context; + act->importance = importance; + if (message != NULL) + act->message = p_strdup(pool, str_c(message)); + if (from != NULL) + act->from = p_strdup(pool, str_c(from)); + + if (sieve_result_add_action(renv, this_ext, "notify", + &act_notify, slist, + (void *)act, 0, FALSE) < 0) + return SIEVE_EXEC_FAILURE; + + return SIEVE_EXEC_OK; + } + return ret; +} + +/* + * Action + */ + +/* Runtime verification */ + +static int +act_notify_check_duplicate(const struct sieve_runtime_env *renv, + const struct sieve_action *act, + const struct sieve_action *act_other) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_enotify_action *nact, *nact_other; + const struct sieve_enotify_method_def *nmth_def; + struct sieve_enotify_env nenv; + int result; + + if (act->context == NULL || act_other->context == NULL) + return 0; + + nact = (const struct sieve_enotify_action *)act->context; + nact_other = (const struct sieve_enotify_action *)act_other->context; + + if (nact->method == NULL || nact->method->def == NULL) + return 0; + + nmth_def = nact->method->def; + if (nmth_def->action_check_duplicates == NULL) + return 0; + + i_zero(&nenv); + nenv.svinst = eenv->svinst; + nenv.method = nact->method; + nenv.ehandler = renv->ehandler; + nenv.location = act->location; + nenv.event = event_create(nenv.svinst->event); + event_set_append_log_prefix(nenv.event, "notify: "); + + result = nmth_def->action_check_duplicates(&nenv, nact, nact_other); + + event_unref(&nenv.event); + + return result; +} + +/* Result printing */ + +static void +act_notify_print(const struct sieve_action *action, + const struct sieve_result_print_env *rpenv, + bool *keep ATTR_UNUSED) +{ + const struct sieve_enotify_action *act = + (const struct sieve_enotify_action *)action->context; + const struct sieve_enotify_method *method; + + method = act->method; + + if (method->def != NULL) { + sieve_result_action_printf( + rpenv, "send notification with method '%s:':", + method->def->identifier); + + if (method->def->action_print != NULL) { + struct sieve_enotify_print_env penv; + + i_zero(&penv); + penv.result_penv = rpenv; + + method->def->action_print(&penv, act); + } + } +} + +/* Result execution */ + +static int +act_notify_commit(const struct sieve_action_exec_env *aenv, + void *tr_context ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = aenv->exec_env; + const struct sieve_enotify_action *act = + (const struct sieve_enotify_action *)aenv->action->context; + const struct sieve_enotify_method *method = act->method; + struct sieve_enotify_exec_env nenv; + int ret = 0; + + if (method->def != NULL && method->def->action_execute != NULL) { + /* Compose log structure */ + i_zero(&nenv); + nenv.svinst = eenv->svinst; + nenv.flags = eenv->flags; + nenv.method = method; + nenv.scriptenv = eenv->scriptenv; + nenv.msgdata = eenv->msgdata; + nenv.msgctx = aenv->msgctx; + + nenv.ehandler = aenv->ehandler; + nenv.event = aenv->event; + + ret = method->def->action_execute(&nenv, act); + if (ret >= 0) + eenv->exec_status->significant_action_executed = TRUE; + } + + return (ret >= 0 ? SIEVE_EXEC_OK : SIEVE_EXEC_TEMP_FAILURE); +} diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.c b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.c new file mode 100644 index 0000000..e0539f0 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.c @@ -0,0 +1,718 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "str-sanitize.h" +#include "array.h" + +#include "sieve-common.h" +#include "sieve-ast.h" +#include "sieve-stringlist.h" +#include "sieve-code.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-interpreter.h" +#include "sieve-result.h" + +#include "ext-enotify-limits.h" +#include "ext-enotify-common.h" + +#include <ctype.h> + +/* FIXME: (from draft RFC) + + Header/envelope tests [Sieve] together with Sieve variables can be used to + extract the list of users to receive notifications from the incoming email + message or its envelope. This is potentially quite dangerous, as this can be + used for Deny Of Service attacks on recipients controlled by the message + sender. For this reason implementations SHOULD NOT allow use of variables + containing values extracted from the email message in the method parameter to + the notify action. Note that violation of this SHOULD NOT may result in* the + creation of an open relay, i.e. any sender would be able to create specially + crafted email messages that would result in notifications delivered to + recipients under the control of the sender. In worst case this might result + in financial loss by user controlling the Sieve script and/or by recipients + of notifications (e.g. if a notification is an SMS message). + + --> This is currently not possible to check. + */ + +/* + * Notify capability + */ + +static const char * +ext_notify_get_methods_string(const struct sieve_extension *ntfy_ext); + +const struct sieve_extension_capabilities notify_capabilities = { + "notify", + ext_notify_get_methods_string +}; + +/* + * Core notification methods + */ + +extern const struct sieve_enotify_method_def mailto_notify; + +/* + * Notify method registry + */ + +static const struct sieve_enotify_method * +ext_enotify_method_register(struct sieve_instance *svinst, + struct ext_enotify_context *ectx, + const struct sieve_enotify_method_def *nmth_def) +{ + struct sieve_enotify_method *nmth; + int nmth_id = (int)array_count(&ectx->notify_methods); + + nmth = array_append_space(&ectx->notify_methods); + nmth->def = nmth_def; + nmth->id = nmth_id; + nmth->svinst = svinst; + + if (nmth_def->load != NULL) + nmth_def->load(nmth, &nmth->context); + + return nmth; +} + +void ext_enotify_methods_init(struct sieve_instance *svinst, + struct ext_enotify_context *ectx) +{ + p_array_init(&ectx->notify_methods, default_pool, 4); + + ext_enotify_method_register(svinst, ectx, &mailto_notify); +} + +void ext_enotify_methods_deinit(struct ext_enotify_context *ectx) +{ + const struct sieve_enotify_method *methods; + unsigned int meth_count, i; + + methods = array_get(&ectx->notify_methods, &meth_count); + for (i = 0; i < meth_count; i++) { + if (methods[i].def != NULL && methods[i].def->unload != NULL) + methods[i].def->unload(&methods[i]); + } + + array_free(&ectx->notify_methods); +} + +const struct sieve_enotify_method * +sieve_enotify_method_register(struct sieve_instance *svinst, + const struct sieve_enotify_method_def *nmth_def) +{ + const struct sieve_extension *ntfy_ext = + sieve_extension_get_by_name(svinst, "enotify"); + + if (ntfy_ext != NULL) { + struct ext_enotify_context *ectx = + (struct ext_enotify_context *) ntfy_ext->context; + + return ext_enotify_method_register(svinst, ectx, nmth_def); + } + return NULL; +} + +void sieve_enotify_method_unregister(const struct sieve_enotify_method *nmth) +{ + struct sieve_instance *svinst = nmth->svinst; + const struct sieve_extension *ntfy_ext = + sieve_extension_get_by_name(svinst, "enotify"); + + if (ntfy_ext != NULL) { + struct ext_enotify_context *ectx = + (struct ext_enotify_context *) ntfy_ext->context; + int nmth_id = nmth->id; + + if (nmth_id >= 0 && + nmth_id < (int)array_count(&ectx->notify_methods)) { + struct sieve_enotify_method *nmth_mod = + array_idx_modifiable(&ectx->notify_methods, + nmth_id); + + nmth_mod->def = NULL; + } + } +} + +const struct sieve_enotify_method * +ext_enotify_method_find(const struct sieve_extension *ntfy_ext, + const char *identifier) +{ + struct ext_enotify_context *ectx = + (struct ext_enotify_context *)ntfy_ext->context; + unsigned int meth_count, i; + const struct sieve_enotify_method *methods; + + methods = array_get(&ectx->notify_methods, &meth_count); + for (i = 0; i < meth_count; i++) { + if (methods[i].def == NULL) + continue; + + if (strcasecmp(methods[i].def->identifier, identifier) == 0) + return &methods[i]; + } + return NULL; +} + +static const char * +ext_notify_get_methods_string(const struct sieve_extension *ntfy_ext) +{ + struct ext_enotify_context *ectx = + (struct ext_enotify_context *) ntfy_ext->context; + unsigned int meth_count, i; + const struct sieve_enotify_method *methods; + string_t *result = t_str_new(128); + + methods = array_get(&ectx->notify_methods, &meth_count); + if (meth_count > 0) { + for (i = 0; i < meth_count; i++) { + if (str_len(result) > 0) + str_append_c(result, ' '); + if (methods[i].def != NULL) + str_append(result, methods[i].def->identifier); + } + return str_c(result); + } + return NULL; +} + +/* + * Compile-time argument validation + */ + +static const char *ext_enotify_uri_scheme_parse(const char **uri_p) +{ + string_t *scheme = t_str_new(EXT_ENOTIFY_MAX_SCHEME_LEN); + const char *p = *uri_p; + unsigned int len = 0; + + /* RFC 3968: + + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + + FIXME: we do not allow '%' in schemes. Is this correct? + */ + + if (!i_isalpha(*p)) + return NULL; + + str_append_c(scheme, *p); + p++; + + while (*p != '\0' && len < EXT_ENOTIFY_MAX_SCHEME_LEN) { + if (!i_isalnum(*p) && *p != '+' && *p != '-' && *p != '.') + break; + + str_append_c(scheme, *p); + p++; + len++; + } + + if (*p != ':') + return NULL; + p++; + + *uri_p = p; + return str_c(scheme); +} + +static bool +ext_enotify_option_parse(struct sieve_enotify_env *nenv, + const char *option, bool name_only, + const char **opt_name_r, const char **opt_value_r) +{ + const char *p = option; + + /* "<optionname>=<value>". + + l-d = ALPHA / DIGIT + l-d-p = l-d / "." / "-" / "_" + optionname = l-d *l-d-p + value = *(%x01-09 / %x0B-0C / %x0E-FF) + */ + + /* + * Parse option name + */ + + /* optionname = l-d *l-d-p + */ + + /* Explicitly report empty option as such */ + if (*p == '\0') { + sieve_enotify_error(nenv, "empty option specified"); + return FALSE; + } + + /* l-d = ALPHA / DIGIT */ + if (i_isalnum(*p)) { + p++; + + /* l-d-p = l-d / "." / "-" / "_" */ + while (i_isalnum(*p) || *p == '.' || *p == '-' || *p == '_') + p++; + } + + /* Parsing must end at '=' and we must parse at least one character */ + if (*p != '=' || p == option) { + sieve_enotify_error( + nenv, "invalid option name specified in option '%s'", + str_sanitize(option, 80)); + return FALSE; + } + + /* Assign option name */ + if (opt_name_r != NULL) + *opt_name_r = t_strdup_until(option, p); + + /* Skip '=' */ + p++; + + /* Exit now if only the option name is of interest */ + if (name_only) + return TRUE; + + /* + * Parse option value + */ + + /* value = *(%x01-09 / %x0B-0C / %x0E-FF) */ + while (*p != '\0' && *p != 0x0A && *p != 0x0D) + p++; + + /* Parse must end at end of string */ + if (*p != '\0') { + sieve_enotify_error( + nenv, "notify command: " + "invalid option value specified in option '%s'", + str_sanitize(option, 80)); + return FALSE; + } + + /* Assign option value */ + if (opt_value_r != NULL) + *opt_value_r = p; + + return TRUE; +} + +struct _ext_enotify_option_check_context { + struct sieve_instance *svinst; + struct sieve_validator *valdtr; + const struct sieve_enotify_method *method; +}; + +static int +_ext_enotify_option_check(void *context, struct sieve_ast_argument *arg) +{ + struct _ext_enotify_option_check_context *optn_context = + (struct _ext_enotify_option_check_context *) context; + struct sieve_validator *valdtr = optn_context->valdtr; + const struct sieve_enotify_method *method = optn_context->method; + struct sieve_enotify_env nenv; + const char *option = sieve_ast_argument_strc(arg); + const char *opt_name = NULL, *opt_value = NULL; + bool check = TRUE; + int result = 1; + + /* Compose log structure */ + i_zero(&nenv); + nenv.svinst = optn_context->svinst; + nenv.method = method; + nenv.ehandler = sieve_validator_error_handler(valdtr); + nenv.location = sieve_error_script_location( + sieve_validator_script(valdtr), arg->source_line); + nenv.event = event_create(nenv.svinst->event); + event_set_append_log_prefix(nenv.event, "notify command: "); + + /* Parse option */ + if (!sieve_argument_is_string_literal(arg)) { + /* Variable string: partial option parse + + If the string item is not a string literal, it cannot be + validated fully at compile time. We can however check whether + the '=' is in the string specification and whether the part + before the '=' is a valid option name. In that case, the + method option check function is called with the value + parameter equal to NULL, meaning that it should only check + the validity of the option itself and not the assigned value. + */ + if (!ext_enotify_option_parse(NULL, option, TRUE, + &opt_name, &opt_value)) + check = FALSE; + } else { + /* Literal string: full option parse */ + if (!ext_enotify_option_parse(&nenv, option, FALSE, + &opt_name, &opt_value)) + result = -1; + } + + /* Call method's option check function */ + if (result > 0 && check && method->def != NULL && + method->def->compile_check_option != NULL) { + result = (method->def->compile_check_option(&nenv, opt_name, + opt_value) ? + 1 : -1 ); + } + + event_unref(&nenv.event); + return result; +} + +bool ext_enotify_compile_check_arguments(struct sieve_validator *valdtr, + struct sieve_command *cmd, + struct sieve_ast_argument *uri_arg, + struct sieve_ast_argument *msg_arg, + struct sieve_ast_argument *from_arg, + struct sieve_ast_argument *options_arg) +{ + const struct sieve_extension *this_ext = cmd->ext; + struct sieve_instance *svinst = this_ext->svinst; + const char *uri = sieve_ast_argument_strc(uri_arg); + const char *scheme; + const struct sieve_enotify_method *method; + struct sieve_enotify_env nenv; + bool result = TRUE; + + /* If the uri string is not a constant literal, we cannot determine + which method is used, so we bail out successfully and defer checking + to runtime. + */ + if (!sieve_argument_is_string_literal(uri_arg)) + return TRUE; + + /* Parse scheme part of URI */ + if ((scheme = ext_enotify_uri_scheme_parse(&uri)) == NULL) { + sieve_argument_validate_error( + valdtr, uri_arg, "notify command: " + "invalid scheme part for method URI '%s'", + str_sanitize(sieve_ast_argument_strc(uri_arg), 80)); + return FALSE; + } + + /* Find used method with the parsed scheme identifier */ + if ((method = ext_enotify_method_find(this_ext, scheme)) == NULL) { + sieve_argument_validate_error( + valdtr, uri_arg, "notify command: " + "invalid method '%s'", scheme); + return FALSE; + } + + if (method->def == NULL) + return TRUE; + + /* Compose log structure */ + i_zero(&nenv); + nenv.svinst = svinst; + nenv.method = method; + + /* Check URI itself */ + if (result && method->def->compile_check_uri != NULL) { + /* Set log location to location of URI argument */ + nenv.ehandler = sieve_validator_error_handler(valdtr); + nenv.location = sieve_error_script_location( + sieve_validator_script(valdtr), uri_arg->source_line); + nenv.event = event_create(nenv.svinst->event); + event_set_append_log_prefix(nenv.event, "notify command: "); + + /* Execute method check function */ + result = method->def->compile_check_uri( + &nenv, sieve_ast_argument_strc(uri_arg), uri); + } + + /* Check :message argument */ + if (result && msg_arg != NULL && + sieve_argument_is_string_literal(msg_arg) && + method->def->compile_check_message != NULL ) { + /* Set log location to location of :message argument */ + event_unref(&nenv.event); + nenv.ehandler = sieve_validator_error_handler(valdtr); + nenv.location = sieve_error_script_location( + sieve_validator_script(valdtr), msg_arg->source_line); + nenv.event = event_create(nenv.svinst->event); + event_set_append_log_prefix(nenv.event, "notify command: "); + + /* Execute method check function */ + result = method->def->compile_check_message( + &nenv, sieve_ast_argument_str(msg_arg)); + } + + /* Check :from argument */ + if (result && from_arg != NULL && + sieve_argument_is_string_literal(from_arg) && + method->def->compile_check_from != NULL ) { + /* Set log location to location of :from argument */ + event_unref(&nenv.event); + nenv.ehandler = sieve_validator_error_handler(valdtr); + nenv.location = sieve_error_script_location( + sieve_validator_script(valdtr), from_arg->source_line); + nenv.event = event_create(nenv.svinst->event); + event_set_append_log_prefix(nenv.event, "notify command: "); + + /* Execute method check function */ + result = method->def->compile_check_from( + &nenv, sieve_ast_argument_str(from_arg)); + } + + event_unref(&nenv.event); + + /* Check :options argument */ + if (result && options_arg != NULL) { + struct sieve_ast_argument *option = options_arg; + struct _ext_enotify_option_check_context optn_context = { + svinst, valdtr, method }; + + /* Parse and check options */ + result = (sieve_ast_stringlist_map( + &option, (void *) &optn_context, + _ext_enotify_option_check) > 0); + + /* Discard argument if options are not accepted by method */ + if (result && method->def->compile_check_option == NULL) { + sieve_argument_validate_warning( + valdtr, options_arg, "notify command: " + "method '%s' accepts no options", scheme); + (void)sieve_ast_arguments_detach(options_arg, 1); + } + } + return result; +} + +/* + * Runtime operand checking + */ + +bool ext_enotify_runtime_method_validate(const struct sieve_runtime_env *renv, + string_t *method_uri) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_extension *this_ext = renv->oprtn->ext; + const struct sieve_enotify_method *method; + const char *uri = str_c(method_uri); + const char *scheme; + bool result = TRUE; + + /* Get the method */ + + if ((scheme = ext_enotify_uri_scheme_parse(&uri)) == NULL) + return FALSE; + if ((method = ext_enotify_method_find(this_ext, scheme)) == NULL) + return FALSE; + + /* Validate the provided URI */ + + if (method->def != NULL && method->def->runtime_check_uri != NULL) { + struct sieve_enotify_env nenv; + + i_zero(&nenv); + nenv.svinst = eenv->svinst; + nenv.method = method; + nenv.ehandler = renv->ehandler; + nenv.location = sieve_runtime_get_full_command_location(renv), + nenv.event = event_create(nenv.svinst->event); + event_set_append_log_prefix(nenv.event, + "valid_notify_method test: "); + + /* Use the method check function to validate the URI */ + result = method->def->runtime_check_uri( + &nenv, str_c(method_uri), uri); + + event_unref(&nenv.event); + } + + return result; +} + +static const struct +sieve_enotify_method *ext_enotify_get_method( + const struct sieve_runtime_env *renv, string_t *method_uri, + const char **uri_body_r) +{ + const struct sieve_extension *this_ext = renv->oprtn->ext; + const struct sieve_enotify_method *method; + const char *uri = str_c(method_uri); + const char *scheme; + + /* Parse part before ':' of the uri (the scheme) and use it to identify + notify method. + */ + if ((scheme = ext_enotify_uri_scheme_parse(&uri)) == NULL) { + sieve_runtime_error( + renv, NULL, "invalid scheme part for method URI '%s'", + str_sanitize(str_c(method_uri), 80)); + return NULL; + } + + /* Find the notify method */ + if ((method = ext_enotify_method_find(this_ext, scheme)) == NULL) { + sieve_runtime_error(renv, NULL, "invalid notify method '%s'", + scheme); + return NULL; + } + + /* Return the parse pointer and the found method */ + *uri_body_r = uri; + return method; +} + +const char * +ext_enotify_runtime_get_method_capability(const struct sieve_runtime_env *renv, + string_t *method_uri, + const char *capability) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_enotify_method *method; + const char *uri_body; + const char *result = NULL; + + /* Get method */ + method = ext_enotify_get_method(renv, method_uri, &uri_body); + if ( method == NULL ) return NULL; + + /* Get requested capability */ + if (method->def != NULL && + method->def->runtime_get_method_capability != NULL) { + struct sieve_enotify_env nenv; + + i_zero(&nenv); + nenv.svinst = eenv->svinst; + nenv.method = method; + nenv.ehandler = renv->ehandler; + nenv.location = sieve_runtime_get_full_command_location(renv), + nenv.event = event_create(nenv.svinst->event); + event_set_append_log_prefix(nenv.event, + "notify_method_capability test: "); + + /* Execute method function to acquire capability value */ + result = method->def->runtime_get_method_capability( + &nenv, str_c(method_uri), uri_body, capability); + + event_unref(&nenv.event); + } + + return result; +} + +int ext_enotify_runtime_check_operands( + const struct sieve_runtime_env *renv, string_t *method_uri, + string_t *message, string_t *from, struct sieve_stringlist *options, + const struct sieve_enotify_method **method_r, void **method_context) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_enotify_method *method; + const char *uri_body; + + /* Get method */ + method = ext_enotify_get_method(renv, method_uri, &uri_body); + if (method == NULL) + return SIEVE_EXEC_FAILURE; + + /* Check provided operands */ + if (method->def != NULL && + method->def->runtime_check_operands != NULL) { + struct sieve_enotify_env nenv; + int result = SIEVE_EXEC_OK; + + i_zero(&nenv); + nenv.svinst = eenv->svinst; + nenv.method = method; + nenv.ehandler = renv->ehandler; + nenv.location = sieve_runtime_get_full_command_location(renv), + nenv.event = event_create(nenv.svinst->event); + event_set_append_log_prefix(nenv.event, "notify_action: "); + + /* Execute check function */ + if (method->def->runtime_check_operands( + &nenv, str_c(method_uri), uri_body, message, from, + sieve_result_pool(renv->result), method_context)) { + + /* Check any provided options */ + if (options != NULL) { + string_t *option = NULL; + int ret; + + /* Iterate through all provided options */ + while ((ret = sieve_stringlist_next_item( + options, &option)) > 0) { + const char *opt_name = NULL; + const char *opt_value = NULL; + + /* Parse option into <optionname> and + <value> */ + if (ext_enotify_option_parse( + &nenv, str_c(option), FALSE, + &opt_name, &opt_value)) { + + /* Set option */ + if (method->def->runtime_set_option != NULL) { + (void)method->def->runtime_set_option( + &nenv, *method_context, + opt_name, opt_value); + } + } + } + + /* Check for binary corruptions encountered + during string list iteration */ + if (ret >= 0) { + *method_r = method; + } else { + /* Binary corrupt */ + sieve_runtime_trace_error( + renv, "invalid item in options string list"); + result = SIEVE_EXEC_BIN_CORRUPT; + } + + } else { + /* No options */ + *method_r = method; + } + + } else { + /* Operand check failed */ + result = SIEVE_EXEC_FAILURE; + } + + event_unref(&nenv.event); + return result; + } + + /* No check function defined: a most unlikely situation */ + *method_context = NULL; + *method_r = method; + return SIEVE_EXEC_OK; +} + +/* + * Notify method printing + */ + +void sieve_enotify_method_printf(const struct sieve_enotify_print_env *penv, + const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + sieve_result_vprintf(penv->result_penv, fmt, args); + va_end(args); +} + +/* + * Action execution + */ + +struct event_passthrough * +sieve_enotify_create_finish_event(const struct sieve_enotify_exec_env *nenv) +{ + struct event_passthrough *e = + event_create_passthrough(nenv->event)-> + set_name("sieve_action_finished"); + + return e; +} + diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.h b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.h new file mode 100644 index 0000000..ec43202 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-common.h @@ -0,0 +1,122 @@ +#ifndef EXT_ENOTIFY_COMMON_H +#define EXT_ENOTIFY_COMMON_H + +#include "lib.h" +#include "array.h" + +#include "sieve-common.h" + +#include "sieve-ext-variables.h" + +#include "sieve-ext-enotify.h" + +/* + * Extension + */ + +extern const struct sieve_extension_def enotify_extension; +extern const struct sieve_extension_capabilities notify_capabilities; + +struct ext_enotify_context { + const struct sieve_extension *var_ext; + ARRAY(struct sieve_enotify_method) notify_methods; +}; + + +/* + * Commands + */ + +extern const struct sieve_command_def notify_command; + +/* Codes for optional arguments */ + +enum cmd_notify_optional { + CMD_NOTIFY_OPT_END, + CMD_NOTIFY_OPT_FROM, + CMD_NOTIFY_OPT_OPTIONS, + CMD_NOTIFY_OPT_MESSAGE, + CMD_NOTIFY_OPT_IMPORTANCE +}; + +/* + * Tests + */ + +extern const struct sieve_command_def valid_notify_method_test; +extern const struct sieve_command_def notify_method_capability_test; + +/* + * Operations + */ + +extern const struct sieve_operation_def notify_operation; +extern const struct sieve_operation_def valid_notify_method_operation; +extern const struct sieve_operation_def notify_method_capability_operation; + +enum ext_variables_opcode { + EXT_ENOTIFY_OPERATION_NOTIFY, + EXT_ENOTIFY_OPERATION_VALID_NOTIFY_METHOD, + EXT_ENOTIFY_OPERATION_NOTIFY_METHOD_CAPABILITY +}; + +/* + * Operands + */ + +extern const struct sieve_operand_def encodeurl_operand; + +/* + * Modifiers + */ + +extern const struct sieve_variables_modifier_def encodeurl_modifier; + +/* + * Notify methods + */ + +void ext_enotify_methods_init(struct sieve_instance *svinst, + struct ext_enotify_context *ectx); +void ext_enotify_methods_deinit(struct ext_enotify_context *ectx); + +const struct sieve_enotify_method * +ext_enotify_method_find(const struct sieve_extension *ntfy_ext, + const char *identifier); + +/* + * Validation + */ + +bool ext_enotify_compile_check_arguments( + struct sieve_validator *valdtr, struct sieve_command *cmd, + struct sieve_ast_argument *uri_arg, struct sieve_ast_argument *msg_arg, + struct sieve_ast_argument *from_arg, + struct sieve_ast_argument *options_arg); + +/* + * Runtime + */ + +bool ext_enotify_runtime_method_validate(const struct sieve_runtime_env *renv, + string_t *method_uri); + +const char * +ext_enotify_runtime_get_method_capability(const struct sieve_runtime_env *renv, + string_t *method_uri, + const char *capability); + +int ext_enotify_runtime_check_operands( + const struct sieve_runtime_env *renv, string_t *method_uri, + string_t *message, string_t *from, struct sieve_stringlist *options, + const struct sieve_enotify_method **method_r, void **method_context); + +/* + * Method printing + */ + +struct sieve_enotify_print_env { + const struct sieve_result_print_env *result_penv; +}; + +#endif diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-limits.h b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-limits.h new file mode 100644 index 0000000..aac48df --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify-limits.h @@ -0,0 +1,6 @@ +#ifndef EXT_ENOTIFY_LIMITS_H +#define EXT_ENOTIFY_LIMITS_H + +#define EXT_ENOTIFY_MAX_SCHEME_LEN 32 + +#endif diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify.c b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify.c new file mode 100644 index 0000000..df479b3 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/ext-enotify.c @@ -0,0 +1,103 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +/* Extension enotify + * ------------------ + * + * Authors: Stephan Bosch + * Specification: RFC 5435 + * Implementation: full + * Status: testing + * + */ + +#include "sieve-common.h" + +#include "sieve-code.h" +#include "sieve-extensions.h" +#include "sieve-actions.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-result.h" + +#include "sieve-ext-variables.h" + +#include "ext-enotify-common.h" + +/* + * Operations + */ + +const struct sieve_operation_def *ext_enotify_operations[] = { + ¬ify_operation, + &valid_notify_method_operation, + ¬ify_method_capability_operation +}; + +/* + * Extension + */ + +static bool ext_enotify_load(const struct sieve_extension *ext, void **context); +static void ext_enotify_unload(const struct sieve_extension *ext); +static bool ext_enotify_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); + +const struct sieve_extension_def enotify_extension = { + .name = "enotify", + .load = ext_enotify_load, + .unload = ext_enotify_unload, + .validator_load = ext_enotify_validator_load, + SIEVE_EXT_DEFINE_OPERATIONS(ext_enotify_operations), + SIEVE_EXT_DEFINE_OPERAND(encodeurl_operand) +}; + +static bool ext_enotify_load(const struct sieve_extension *ext, void **context) +{ + struct ext_enotify_context *ectx; + + if ( *context != NULL ) { + ext_enotify_unload(ext); + } + + ectx = i_new(struct ext_enotify_context, 1); + ectx->var_ext = sieve_ext_variables_get_extension(ext->svinst); + *context = (void *) ectx; + + ext_enotify_methods_init(ext->svinst, ectx); + + sieve_extension_capabilities_register(ext, ¬ify_capabilities); + + return TRUE; +} + +static void ext_enotify_unload(const struct sieve_extension *ext) +{ + struct ext_enotify_context *ectx = + (struct ext_enotify_context *) ext->context; + + ext_enotify_methods_deinit(ectx); + + i_free(ectx); +} + +static bool ext_enotify_validator_load +(const struct sieve_extension *ext, struct sieve_validator *valdtr) +{ + struct ext_enotify_context *ectx = + (struct ext_enotify_context *) ext->context; + + /* Register new commands */ + sieve_validator_register_command(valdtr, ext, ¬ify_command); + sieve_validator_register_command(valdtr, ext, &valid_notify_method_test); + sieve_validator_register_command(valdtr, ext, ¬ify_method_capability_test); + + /* Register new set modifier for variables extension */ + sieve_variables_modifier_register + (ectx->var_ext, valdtr, ext, &encodeurl_modifier); + + return TRUE; +} + diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.am b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.am new file mode 100644 index 0000000..83f129c --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.am @@ -0,0 +1,16 @@ +noinst_LTLIBRARIES = libsieve_ext_enotify_mailto.la + +AM_CPPFLAGS = \ + -I$(srcdir)/.. \ + -I$(srcdir)/../../.. \ + -I$(srcdir)/../../../util \ + $(LIBDOVECOT_INCLUDE) + +libsieve_ext_enotify_mailto_la_SOURCES = \ + uri-mailto.c \ + ntfy-mailto.c + +noinst_HEADERS = \ + uri-mailto.h + + diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.in b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.in new file mode 100644 index 0000000..84fee51 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/Makefile.in @@ -0,0 +1,687 @@ +# 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@ +subdir = src/lib-sieve/plugins/enotify/mailto +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/dummy-config.h \ + $(top_builddir)/pigeonhole-config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libsieve_ext_enotify_mailto_la_LIBADD = +am_libsieve_ext_enotify_mailto_la_OBJECTS = uri-mailto.lo \ + ntfy-mailto.lo +libsieve_ext_enotify_mailto_la_OBJECTS = \ + $(am_libsieve_ext_enotify_mailto_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 = +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)/ntfy-mailto.Plo \ + ./$(DEPDIR)/uri-mailto.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 = $(libsieve_ext_enotify_mailto_la_SOURCES) +DIST_SOURCES = $(libsieve_ext_enotify_mailto_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_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@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINARY_CFLAGS = @BINARY_CFLAGS@ +BINARY_LDFLAGS = @BINARY_LDFLAGS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@ +DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@ +DOVECOT_CFLAGS = @DOVECOT_CFLAGS@ +DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@ +DOVECOT_INSTALLED = @DOVECOT_INSTALLED@ +DOVECOT_LIBS = @DOVECOT_LIBS@ +DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@ +DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@ +DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@ +DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDAP_LIBS = @LDAP_LIBS@ +LDFLAGS = @LDFLAGS@ +LIBDOVECOT = @LIBDOVECOT@ +LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@ +LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@ +LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@ +LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@ +LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@ +LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@ +LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@ +LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@ +LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@ +LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@ +LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@ +LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@ +LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@ +LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@ +LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@ +LIBDOVECOT_LDA = @LIBDOVECOT_LDA@ +LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@ +LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@ +LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@ +LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@ +LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@ +LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@ +LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@ +LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@ +LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@ +LIBDOVECOT_LUA = @LIBDOVECOT_LUA@ +LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@ +LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@ +LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@ +LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@ +LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@ +LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@ +LIBDOVECOT_SQL = @LIBDOVECOT_SQL@ +LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@ +LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@ +LIBDOVECOT_SSL = @LIBDOVECOT_SSL@ +LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@ +LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@ +LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@ +LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@ +LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +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@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RUN_TEST = @RUN_TEST@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +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_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@ +docdir = @docdir@ +dovecot_docdir = @dovecot_docdir@ +dovecot_installed_moduledir = @dovecot_installed_moduledir@ +dovecot_moduledir = @dovecot_moduledir@ +dovecot_pkgincludedir = @dovecot_pkgincludedir@ +dovecot_pkglibdir = @dovecot_pkglibdir@ +dovecot_pkglibexecdir = @dovecot_pkglibexecdir@ +dovecot_statedir = @dovecot_statedir@ +dovecotdir = @dovecotdir@ +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@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sieve_docdir = @sieve_docdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libsieve_ext_enotify_mailto.la +AM_CPPFLAGS = \ + -I$(srcdir)/.. \ + -I$(srcdir)/../../.. \ + -I$(srcdir)/../../../util \ + $(LIBDOVECOT_INCLUDE) + +libsieve_ext_enotify_mailto_la_SOURCES = \ + uri-mailto.c \ + ntfy-mailto.c + +noinst_HEADERS = \ + uri-mailto.h + +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/lib-sieve/plugins/enotify/mailto/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/lib-sieve/plugins/enotify/mailto/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): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_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}; \ + } + +libsieve_ext_enotify_mailto.la: $(libsieve_ext_enotify_mailto_la_OBJECTS) $(libsieve_ext_enotify_mailto_la_DEPENDENCIES) $(EXTRA_libsieve_ext_enotify_mailto_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libsieve_ext_enotify_mailto_la_OBJECTS) $(libsieve_ext_enotify_mailto_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ntfy-mailto.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uri-mailto.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 $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +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: +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-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/ntfy-mailto.Plo + -rm -f ./$(DEPDIR)/uri-mailto.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-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)/ntfy-mailto.Plo + -rm -f ./$(DEPDIR)/uri-mailto.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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + 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-pdf \ + install-pdf-am 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 + +.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/pigeonhole/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c new file mode 100644 index 0000000..4e104d1 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c @@ -0,0 +1,794 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +/* Notify method mailto + * -------------------- + * + * Authors: Stephan Bosch + * Specification: RFC 5436 + * Implementation: full + * Status: testing + * + */ + +/* FIXME: URI syntax conforms to something somewhere in between RFC 2368 and + * draft-duerst-mailto-bis-05.txt. Should fully migrate to new specification + * when it matures. This requires modifications to the address parser (no + * whitespace allowed within the address itself) and UTF-8 support will be + * required in the URL. + */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "ioloop.h" +#include "str-sanitize.h" +#include "ostream.h" +#include "message-date.h" +#include "mail-storage.h" + +#include "sieve-common.h" +#include "sieve-address.h" +#include "sieve-address-source.h" +#include "sieve-message.h" +#include "sieve-smtp.h" +#include "sieve-settings.h" + +#include "sieve-ext-enotify.h" + +#include "rfc2822.h" + +#include "uri-mailto.h" + +/* + * Configuration + */ + +#define NTFY_MAILTO_MAX_RECIPIENTS 8 +#define NTFY_MAILTO_MAX_HEADERS 16 +#define NTFY_MAILTO_MAX_SUBJECT 256 + +/* + * Mailto notification configuration + */ + +struct ntfy_mailto_config { + pool_t pool; + struct sieve_address_source envelope_from; +}; + +/* + * Mailto notification method + */ + +static bool ntfy_mailto_load + (const struct sieve_enotify_method *nmth, void **context); +static void ntfy_mailto_unload + (const struct sieve_enotify_method *nmth); + +static bool ntfy_mailto_compile_check_uri + (const struct sieve_enotify_env *nenv, const char *uri, const char *uri_body); +static bool ntfy_mailto_compile_check_from + (const struct sieve_enotify_env *nenv, string_t *from); + +static const char *ntfy_mailto_runtime_get_notify_capability + (const struct sieve_enotify_env *nenv, const char *uri, const char *uri_body, + const char *capability); +static bool ntfy_mailto_runtime_check_uri + (const struct sieve_enotify_env *nenv, const char *uri, const char *uri_body); +static bool ntfy_mailto_runtime_check_operands + (const struct sieve_enotify_env *nenv, const char *uri,const char *uri_body, + string_t *message, string_t *from, pool_t context_pool, + void **method_context); + +static int ntfy_mailto_action_check_duplicates + (const struct sieve_enotify_env *nenv, + const struct sieve_enotify_action *nact, + const struct sieve_enotify_action *nact_other); + +static void ntfy_mailto_action_print + (const struct sieve_enotify_print_env *penv, + const struct sieve_enotify_action *nact); + +static int ntfy_mailto_action_execute + (const struct sieve_enotify_exec_env *nenv, + const struct sieve_enotify_action *nact); + +const struct sieve_enotify_method_def mailto_notify = { + "mailto", + ntfy_mailto_load, + ntfy_mailto_unload, + ntfy_mailto_compile_check_uri, + NULL, + ntfy_mailto_compile_check_from, + NULL, + ntfy_mailto_runtime_check_uri, + ntfy_mailto_runtime_get_notify_capability, + ntfy_mailto_runtime_check_operands, + NULL, + ntfy_mailto_action_check_duplicates, + ntfy_mailto_action_print, + ntfy_mailto_action_execute +}; + +/* + * Reserved and unique headers + */ + +static const char *_reserved_headers[] = { + "auto-submitted", + "received", + "message-id", + "data", + "bcc", + "in-reply-to", + "references", + "resent-date", + "resent-from", + "resent-sender", + "resent-to", + "resent-cc", + "resent-bcc", + "resent-msg-id", + "from", + "sender", + NULL +}; + +static const char *_unique_headers[] = { + "reply-to", + NULL +}; + +/* + * Method context data + */ + +struct ntfy_mailto_context { + struct uri_mailto *uri; + const struct smtp_address *from_address; +}; + +/* + * Method registration + */ + +static bool ntfy_mailto_load +(const struct sieve_enotify_method *nmth, void **context) +{ + struct sieve_instance *svinst = nmth->svinst; + struct ntfy_mailto_config *config; + pool_t pool; + + if ( *context != NULL ) { + ntfy_mailto_unload(nmth); + } + + pool = pool_alloconly_create("ntfy_mailto_config", 256); + config = p_new(pool, struct ntfy_mailto_config, 1); + config->pool = pool; + + (void)sieve_address_source_parse_from_setting (svinst, + config->pool, "sieve_notify_mailto_envelope_from", + &config->envelope_from); + + *context = (void *) config; + + return TRUE; +} + +static void ntfy_mailto_unload +(const struct sieve_enotify_method *nmth) +{ + struct ntfy_mailto_config *config = + (struct ntfy_mailto_config *) nmth->context; + + pool_unref(&config->pool); +} + +/* + * URI parsing + */ + +struct ntfy_mailto_uri_env { + const struct sieve_enotify_env *nenv; + + struct event *event; + + struct uri_mailto_log uri_log; +}; + +static void ATTR_FORMAT(5, 0) +ntfy_mailto_uri_logv(void *context, enum log_type log_type, + const char *csrc_filename, unsigned int csrc_linenum, + const char *fmt, va_list args) +{ + struct ntfy_mailto_uri_env *nmuenv = context; + const struct sieve_enotify_env *nenv = nmuenv->nenv; + + sieve_event_logv(nenv->svinst, nenv->ehandler, nmuenv->event, + log_type, csrc_filename, csrc_linenum, + nenv->location, 0, fmt, args); +} + +static void +ntfy_mailto_uri_env_init(struct ntfy_mailto_uri_env *nmuenv, + const struct sieve_enotify_env *nenv) +{ + i_zero(nmuenv); + nmuenv->nenv = nenv; + nmuenv->event = event_create(nenv->event); + event_set_append_log_prefix(nmuenv->event, "mailto URI: "); + + nmuenv->uri_log.context = nmuenv; + nmuenv->uri_log.logv = ntfy_mailto_uri_logv; +} + +static void +ntfy_mailto_uri_env_deinit(struct ntfy_mailto_uri_env *nmuenv) +{ + event_unref(&nmuenv->event); +} + +/* + * Validation + */ + + +static bool ntfy_mailto_compile_check_uri +(const struct sieve_enotify_env *nenv, const char *uri ATTR_UNUSED, + const char *uri_body) +{ + struct ntfy_mailto_uri_env nmuenv; + bool result; + + ntfy_mailto_uri_env_init(&nmuenv, nenv); + result = uri_mailto_validate( + uri_body, _reserved_headers, _unique_headers, + NTFY_MAILTO_MAX_RECIPIENTS, NTFY_MAILTO_MAX_HEADERS, + &nmuenv.uri_log); + ntfy_mailto_uri_env_deinit(&nmuenv); + + return result; +} + +static bool ntfy_mailto_compile_check_from +(const struct sieve_enotify_env *nenv, string_t *from) +{ + const char *error; + bool result = FALSE; + + T_BEGIN { + result = sieve_address_validate_str(from, &error); + if ( !result ) { + sieve_enotify_error(nenv, + "specified :from address '%s' is invalid for " + "the mailto method: %s", + str_sanitize(str_c(from), 128), error); + } + } T_END; + + return result; +} + +/* + * Runtime + */ + +struct ntfy_mailto_runtime_env { + const struct sieve_enotify_env *nenv; + + struct event *event; +}; + +static const char *ntfy_mailto_runtime_get_notify_capability +(const struct sieve_enotify_env *nenv ATTR_UNUSED, const char *uri ATTR_UNUSED, + const char *uri_body, const char *capability) +{ + if ( !uri_mailto_validate(uri_body, _reserved_headers, _unique_headers, + NTFY_MAILTO_MAX_RECIPIENTS, NTFY_MAILTO_MAX_HEADERS, NULL) ) { + return NULL; + } + + if ( strcasecmp(capability, "online") == 0 ) + return "maybe"; + + return NULL; +} + +static bool ntfy_mailto_runtime_check_uri +(const struct sieve_enotify_env *nenv ATTR_UNUSED, const char *uri ATTR_UNUSED, + const char *uri_body) +{ + return uri_mailto_validate + (uri_body, _reserved_headers, _unique_headers, + NTFY_MAILTO_MAX_RECIPIENTS, NTFY_MAILTO_MAX_HEADERS, NULL); +} + +static bool ntfy_mailto_runtime_check_operands +(const struct sieve_enotify_env *nenv, const char *uri ATTR_UNUSED, + const char *uri_body, string_t *message ATTR_UNUSED, string_t *from, + pool_t context_pool, void **method_context) +{ + struct ntfy_mailto_context *mtctx; + struct uri_mailto *parsed_uri; + const struct smtp_address *address; + struct ntfy_mailto_uri_env nmuenv; + const char *error; + + /* Need to create context before validation to have arrays present */ + mtctx = p_new(context_pool, struct ntfy_mailto_context, 1); + + /* Validate :from */ + if ( from != NULL ) { + T_BEGIN { + address = sieve_address_parse_str(from, &error); + if ( address == NULL ) { + sieve_enotify_error(nenv, + "specified :from address '%s' is invalid for " + "the mailto method: %s", + str_sanitize(str_c(from), 128), error); + } else + mtctx->from_address = + smtp_address_clone(context_pool, address); + } T_END; + + if ( address == NULL ) return FALSE; + } + + ntfy_mailto_uri_env_init(&nmuenv, nenv); + parsed_uri = uri_mailto_parse(uri_body, context_pool, + _reserved_headers, _unique_headers, + NTFY_MAILTO_MAX_RECIPIENTS, + NTFY_MAILTO_MAX_HEADERS, + &nmuenv.uri_log); + ntfy_mailto_uri_env_deinit(&nmuenv); + + if (parsed_uri == NULL) + return FALSE; + + mtctx->uri = parsed_uri; + *method_context = (void *) mtctx; + return TRUE; +} + +/* + * Action duplicates + */ + +static int ntfy_mailto_action_check_duplicates +(const struct sieve_enotify_env *nenv ATTR_UNUSED, + const struct sieve_enotify_action *nact, + const struct sieve_enotify_action *nact_other) +{ + struct ntfy_mailto_context *mtctx = + (struct ntfy_mailto_context *) nact->method_context; + struct ntfy_mailto_context *mtctx_other = + (struct ntfy_mailto_context *) nact_other->method_context; + const struct uri_mailto_recipient *new_rcpts, *old_rcpts; + unsigned int new_count, old_count, i, j; + unsigned int del_start = 0, del_len = 0; + + new_rcpts = array_get(&mtctx->uri->recipients, &new_count); + old_rcpts = array_get(&mtctx_other->uri->recipients, &old_count); + + for ( i = 0; i < new_count; i++ ) { + for ( j = 0; j < old_count; j++ ) { + if ( smtp_address_equals + (new_rcpts[i].address, old_rcpts[j].address) ) + break; + } + + if ( j == old_count ) { + /* Not duplicate */ + if ( del_len > 0 ) { + /* Perform pending deletion */ + array_delete(&mtctx->uri->recipients, del_start, del_len); + + /* Make sure the loop integrity is maintained */ + i -= del_len; + new_rcpts = array_get(&mtctx->uri->recipients, &new_count); + } + del_len = 0; + } else { + /* Mark deletion */ + if ( del_len == 0 ) + del_start = i; + del_len++; + } + } + + /* Perform pending deletion */ + if ( del_len > 0 ) { + array_delete(&mtctx->uri->recipients, del_start, del_len); + } + + return ( array_count(&mtctx->uri->recipients) > 0 ? 0 : 1 ); +} + +/* + * Action printing + */ + +static void ntfy_mailto_action_print +(const struct sieve_enotify_print_env *penv, + const struct sieve_enotify_action *nact) +{ + unsigned int count, i; + const struct uri_mailto_recipient *recipients; + const struct uri_mailto_header_field *headers; + struct ntfy_mailto_context *mtctx = + (struct ntfy_mailto_context *) nact->method_context; + + /* Print main method parameters */ + + sieve_enotify_method_printf + (penv, " => importance : %llu\n", + (unsigned long long)nact->importance); + + if ( nact->message != NULL ) + sieve_enotify_method_printf + (penv, " => subject : %s\n", nact->message); + else if ( mtctx->uri->subject != NULL ) + sieve_enotify_method_printf + (penv, " => subject : %s\n", mtctx->uri->subject); + + if ( nact->from != NULL ) + sieve_enotify_method_printf + (penv, " => from : %s\n", nact->from); + + /* Print mailto: recipients */ + + sieve_enotify_method_printf(penv, " => recipients :\n" ); + + recipients = array_get(&mtctx->uri->recipients, &count); + if ( count == 0 ) { + sieve_enotify_method_printf(penv, " NONE, action has no effect\n"); + } else { + for ( i = 0; i < count; i++ ) { + if ( recipients[i].carbon_copy ) + sieve_enotify_method_printf + (penv, " + Cc: %s\n", recipients[i].full); + else + sieve_enotify_method_printf + (penv, " + To: %s\n", recipients[i].full); + } + } + + /* Print accepted headers for notification message */ + + headers = array_get(&mtctx->uri->headers, &count); + if ( count > 0 ) { + sieve_enotify_method_printf(penv, " => headers :\n" ); + for ( i = 0; i < count; i++ ) { + sieve_enotify_method_printf(penv, " + %s: %s\n", + headers[i].name, headers[i].body); + } + } + + /* Print body for notification message */ + + if ( mtctx->uri->body != NULL ) + sieve_enotify_method_printf + (penv, " => body : \n--\n%s\n--\n", mtctx->uri->body); + + /* Finish output with an empty line */ + + sieve_enotify_method_printf(penv, "\n"); +} + +/* + * Action execution + */ + +static bool _contains_8bit(const char *msg) +{ + const unsigned char *s = (const unsigned char *)msg; + + for (; *s != '\0'; s++) { + if ((*s & 0x80) != 0) + return TRUE; + } + + return FALSE; +} + +static int ntfy_mailto_send +(const struct sieve_enotify_exec_env *nenv, + const struct sieve_enotify_action *nact, + const struct smtp_address *owner_email) +{ + struct sieve_instance *svinst = nenv->svinst; + const struct sieve_message_data *msgdata = nenv->msgdata; + const struct sieve_script_env *senv = nenv->scriptenv; + struct ntfy_mailto_context *mtctx = + (struct ntfy_mailto_context *) nact->method_context; + struct ntfy_mailto_config *mth_config = + (struct ntfy_mailto_config *)nenv->method->context; + struct sieve_address_source env_from = + mth_config->envelope_from; + const char *from = NULL; + const struct smtp_address *from_smtp = NULL; + const char *subject = mtctx->uri->subject; + const char *body = mtctx->uri->body; + string_t *to, *cc, *all; + const struct uri_mailto_recipient *recipients; + const struct uri_mailto_header_field *headers; + struct sieve_smtp_context *sctx; + struct ostream *output; + string_t *msg; + unsigned int count, i, hcount, h; + const char *outmsgid, *error; + int ret; + + /* Get recipients */ + recipients = array_get(&mtctx->uri->recipients, &count); + if ( count == 0 ) { + sieve_enotify_warning(nenv, + "notify mailto uri specifies no recipients; action has no effect"); + return 0; + } + + /* Just to be sure */ + if ( !sieve_smtp_available(senv) ) { + sieve_enotify_global_warning(nenv, + "notify mailto method has no means to send mail"); + return 0; + } + + /* Determine which sender to use + + From RFC 5436, Section 2.3: + + The ":from" tag overrides the default sender of the notification + message. "Sender", here, refers to the value used in the [RFC5322] + "From" header. Implementations MAY also use this value in the + [RFC5321] "MAIL FROM" command (the "envelope sender"), or they may + prefer to establish a mailbox that receives bounces from notification + messages. + */ + if ( (nenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 ) { + from_smtp = sieve_message_get_sender(nenv->msgctx); + if ( from_smtp == NULL ) { + /* "<>" */ + i_zero(&env_from); + env_from.type = SIEVE_ADDRESS_SOURCE_EXPLICIT; + } + } + from = nact->from; + if ( (ret=sieve_address_source_get_address(&env_from, svinst, + senv, nenv->msgctx, nenv->flags, &from_smtp)) < 0 ) { + from_smtp = NULL; + } else if ( ret == 0 ) { + if ( mtctx->from_address != NULL ) + from_smtp = mtctx->from_address; + else if ( svinst->user_email != NULL ) + from_smtp = svinst->user_email; + else { + from_smtp = sieve_get_postmaster_smtp(senv); + if (from == NULL) + from = sieve_get_postmaster_address(senv); + } + } + + /* Determine message from address */ + if ( from == NULL ) { + if ( from_smtp == NULL ) + from = sieve_get_postmaster_address(senv); + else { + from = t_strdup_printf("<%s>", + smtp_address_encode(from_smtp)); + } + } + + /* Determine subject */ + if ( nact->message != NULL ) { + /* FIXME: handle UTF-8 */ + subject = str_sanitize(nact->message, NTFY_MAILTO_MAX_SUBJECT); + } else if ( subject == NULL ) { + const char *const *hsubject; + + /* Fetch subject from original message */ + if ( mail_get_headers_utf8 + (msgdata->mail, "subject", &hsubject) > 0 ) + subject = str_sanitize(t_strdup_printf("Notification: %s", hsubject[0]), + NTFY_MAILTO_MAX_SUBJECT); + else + subject = "Notification: (no subject)"; + } + + /* Compose To and Cc headers */ + to = NULL; + cc = NULL; + all = t_str_new(256); + for ( i = 0; i < count; i++ ) { + if ( recipients[i].carbon_copy ) { + if ( cc == NULL ) { + cc = t_str_new(256); + str_append(cc, recipients[i].full); + } else { + str_append(cc, ", "); + str_append(cc, recipients[i].full); + } + } else { + if ( to == NULL ) { + to = t_str_new(256); + str_append(to, recipients[i].full); + } else { + str_append(to, ", "); + str_append(to, recipients[i].full); + } + } + if ( i < 3) { + if ( i > 0 ) + str_append(all, ", "); + str_append(all, + smtp_address_encode_path(recipients[i].address)); + } else if (i == 3) { + str_printfa(all, ", ... (%u total)", count); + } + } + + msg = t_str_new(512); + outmsgid = sieve_message_get_new_id(svinst); + + rfc2822_header_write(msg, "X-Sieve", SIEVE_IMPLEMENTATION); + rfc2822_header_write(msg, "Message-ID", outmsgid); + rfc2822_header_write(msg, "Date", message_date_create(ioloop_time)); + rfc2822_header_utf8_printf(msg, "Subject", "%s", subject); + + rfc2822_header_write_address(msg, "From", from); + + if ( to != NULL ) + rfc2822_header_write_address(msg, "To", str_c(to)); + if ( cc != NULL ) + rfc2822_header_write_address(msg, "Cc", str_c(cc)); + + rfc2822_header_printf(msg, "Auto-Submitted", + "auto-notified; owner-email=\"%s\"", + smtp_address_encode(owner_email)); + rfc2822_header_write(msg, "Precedence", "bulk"); + + /* Set importance */ + switch ( nact->importance ) { + case 1: + rfc2822_header_write(msg, "X-Priority", "1 (Highest)"); + rfc2822_header_write(msg, "Importance", "High"); + break; + case 3: + rfc2822_header_write(msg, "X-Priority", "5 (Lowest)"); + rfc2822_header_write(msg, "Importance", "Low"); + break; + case 2: + default: + rfc2822_header_write(msg, "X-Priority", "3 (Normal)"); + rfc2822_header_write(msg, "Importance", "Normal"); + break; + } + + /* Add custom headers */ + + headers = array_get(&mtctx->uri->headers, &hcount); + for ( h = 0; h < hcount; h++ ) { + const char *name = rfc2822_header_field_name_sanitize(headers[h].name); + + rfc2822_header_write(msg, name, headers[h].body); + } + + /* Generate message body */ + + rfc2822_header_write(msg, "MIME-Version", "1.0"); + if ( body != NULL ) { + if (_contains_8bit(body)) { + rfc2822_header_write + (msg, "Content-Type", "text/plain; charset=utf-8"); + rfc2822_header_write(msg, "Content-Transfer-Encoding", "8bit"); + } else { + rfc2822_header_write + (msg, "Content-Type", "text/plain; charset=us-ascii"); + rfc2822_header_write(msg, "Content-Transfer-Encoding", "7bit"); + } + str_printfa(msg, "\r\n%s\r\n", body); + + } else { + rfc2822_header_write + (msg, "Content-Type", "text/plain; charset=US-ASCII"); + rfc2822_header_write(msg, "Content-Transfer-Encoding", "7bit"); + + str_append(msg, "\r\nNotification of new message.\r\n"); + } + + sctx = sieve_smtp_start(senv, from_smtp); + + /* Send message to all recipients */ + for ( i = 0; i < count; i++ ) + sieve_smtp_add_rcpt(sctx, recipients[i].address); + + output = sieve_smtp_send(sctx); + o_stream_nsend(output, str_data(msg), str_len(msg)); + + if ( (ret=sieve_smtp_finish(sctx, &error)) <= 0 ) { + if (ret < 0) { + sieve_enotify_global_error(nenv, + "failed to send mail notification to %s: %s (temporary failure)", + str_c(all), str_sanitize(error, 512)); + } else { + sieve_enotify_global_log_error(nenv, + "failed to send mail notification to %s: %s (permanent failure)", + str_c(all), str_sanitize(error, 512)); + } + } else { + struct event_passthrough *e = + sieve_enotify_create_finish_event(nenv)-> + add_str("notify_target", str_c(all)); + + sieve_enotify_event_log(nenv, e->event(), + "sent mail notification to %s", + str_c(all)); + } + + return 0; +} + +static int ntfy_mailto_action_execute +(const struct sieve_enotify_exec_env *nenv, + const struct sieve_enotify_action *nact) +{ + struct sieve_instance *svinst = nenv->svinst; + const struct sieve_script_env *senv = nenv->scriptenv; + struct mail *mail = nenv->msgdata->mail; + const struct smtp_address *owner_email; + const char *const *hdsp; + int ret; + + owner_email = svinst->user_email; + if ( owner_email == NULL && + (nenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 ) + owner_email = sieve_message_get_final_recipient(nenv->msgctx); + if ( owner_email == NULL ) { + owner_email = sieve_get_postmaster_smtp(senv); + } + i_assert( owner_email != NULL ); + + /* Is the message an automatic reply ? */ + if ( (ret=mail_get_headers(mail, "auto-submitted", &hdsp)) < 0 ) { + sieve_enotify_critical(nenv, + "mailto notification: " + "failed to read `auto-submitted' header field", + "mailto notification: " + "failed to read `auto-submitted' header field: %s", + mailbox_get_last_internal_error(mail->box, NULL)); + return -1; + } + + /* Theoretically multiple headers could exist, so lets make sure */ + if ( ret > 0 ) { + while ( *hdsp != NULL ) { + if ( strcasecmp(*hdsp, "no") != 0 ) { + const struct smtp_address *sender = NULL; + const char *from; + + if ( (nenv->flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) == 0 ) + sender = sieve_message_get_sender(nenv->msgctx); + from = (sender == NULL ? "" : t_strdup_printf + (" from <%s>", smtp_address_encode(sender))); + + sieve_enotify_global_info(nenv, + "not sending notification " + "for auto-submitted message%s", from); + return 0; + } + hdsp++; + } + } + + T_BEGIN { + ret = ntfy_mailto_send(nenv, nact, owner_email); + } T_END; + + return ret; +} + + + + diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c new file mode 100644 index 0000000..c5a0953 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.c @@ -0,0 +1,683 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +/* FIXME: URI syntax conforms to something somewhere in between RFC 2368 and + draft-duerst-mailto-bis-05.txt. Should fully migrate to new + specification when it matures. This requires modifications to the + address parser (no whitespace allowed within the address itself) and + UTF-8 support will be required in the URL. + */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "str-sanitize.h" + +#include "rfc2822.h" + +#include "sieve-common.h" +#include "sieve-error.h" +#include "sieve-address.h" +#include "sieve-message.h" + +#include "uri-mailto.h" + +/* Parser object */ + +struct uri_mailto_parser { + pool_t pool; + const struct uri_mailto_log *log; + + struct uri_mailto *uri; + + const char **reserved_headers; + const char **unique_headers; + + int max_recipients; + int max_headers; +}; + +/* Error handling */ + +#define uri_mailto_error(PARSER, ...) \ + uri_mailto_log((PARSER), LOG_TYPE_ERROR, \ + __FILE__, __LINE__, __VA_ARGS__) +#define uri_mailto_warning(PARSER, ...) \ + uri_mailto_log((PARSER), LOG_TYPE_WARNING, \ + __FILE__, __LINE__, __VA_ARGS__) + +static inline void ATTR_FORMAT(5, 6) +uri_mailto_log(struct uri_mailto_parser *parser, enum log_type log_type, + const char *csrc_filename, unsigned int csrc_linenum, + const char *fmt, ...) +{ + va_list args; + + if (parser->log == NULL || parser->log->logv == NULL) + return; + + va_start(args, fmt); + parser->log->logv(parser->log->context, log_type, + csrc_filename, csrc_linenum, fmt, args); + va_end(args); +} + + +/* + * Error handling + */ + +/* + * Reserved and unique headers + */ + +static inline bool +uri_mailto_header_is_reserved(struct uri_mailto_parser *parser, + const char *field_name) +{ + const char **hdr = parser->reserved_headers; + + if (hdr == NULL) + return FALSE; + + /* Check whether it is reserved */ + while (*hdr != NULL) { + if (strcasecmp(field_name, *hdr) == 0) + return TRUE; + hdr++; + } + return FALSE; +} + +static inline bool +uri_mailto_header_is_unique(struct uri_mailto_parser *parser, + const char *field_name) +{ + const char **hdr = parser->unique_headers; + + if (hdr == NULL) + return FALSE; + + /* Check whether it is supposed to be unique */ + while (*hdr != NULL) { + if (strcasecmp(field_name, *hdr) == 0) + return TRUE; + hdr++; + } + return FALSE; +} + +/* + * Low-level URI parsing. + * + * FIXME: much of this implementation will be common to other URI schemes. This + * should be merged into a common implementation. + */ + +static const char _qchar_lookup[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 + 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 20 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 30 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 40 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, // 50 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 60 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, // 70 + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 90 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // F0 +}; + +static inline bool _is_qchar(char c) +{ + return ((_qchar_lookup[(unsigned char)c] & 0x01) != 0); +} + +static inline int _decode_hex_digit(unsigned char digit) +{ + switch (digit) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + return (int) digit - '0'; + case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': + return (int) digit - 'a' + 0x0a; + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': + return (int) digit - 'A' + 0x0A; + } + return -1; +} + +static bool _parse_hex_value(const char **in, char *out) +{ + int value, digit; + + if ((digit = _decode_hex_digit((unsigned char)**in)) < 0) + return FALSE; + + value = digit << 4; + (*in)++; + + if ((digit = _decode_hex_digit((unsigned char)**in)) < 0) + return FALSE; + + value |= digit; + (*in)++; + + if (value == 0) + return FALSE; + + *out = (char)value; + return TRUE; +} + +/* + * URI recipient parsing + */ + +static bool +uri_mailto_add_valid_recipient(struct uri_mailto_parser *parser, + string_t *recipient, bool cc) +{ + struct uri_mailto *uri = parser->uri; + struct uri_mailto_recipient *new_recipient; + struct uri_mailto_recipient *rcpts; + unsigned int count, i; + const char *error; + const struct smtp_address *address; + + /* Verify recipient */ + if ((address = sieve_address_parse_str(recipient, &error)) == NULL) { + uri_mailto_error(parser, "invalid recipient '%s': %s", + str_sanitize(str_c(recipient), 80), error); + return FALSE; + } + + /* Add recipient to the uri */ + if (uri != NULL) { + /* Get current recipients */ + rcpts = array_get_modifiable(&uri->recipients, &count); + + /* Enforce limits */ + if (parser->max_recipients > 0 && + (int)count >= parser->max_recipients) { + if ((int)count == parser->max_recipients) { + uri_mailto_warning( + parser, + "more than the maximum %u recipients specified; " + "rest is discarded", + parser->max_recipients); + } + return TRUE; + } + + /* Check for duplicate first */ + for (i = 0; i < count; i++) { + if (smtp_address_equals(rcpts[i].address, address)) { + /* Upgrade existing Cc: recipient to a To: + recipient if possible */ + rcpts[i].carbon_copy = + (rcpts[i].carbon_copy && cc); + + uri_mailto_warning( + parser, + "ignored duplicate recipient '%s'", + str_sanitize(str_c(recipient), 80)); + return TRUE; + } + } + + /* Add */ + new_recipient = array_append_space(&uri->recipients); + new_recipient->carbon_copy = cc; + new_recipient->full = p_strdup(parser->pool, str_c(recipient)); + new_recipient->address = + smtp_address_clone(parser->pool, address); + } + + return TRUE; +} + +static bool +uri_mailto_parse_recipients(struct uri_mailto_parser *parser, + const char **uri_p) +{ + string_t *to = t_str_new(128); + const char *p = *uri_p; + + if (*p == '\0' || *p == '?') + return TRUE; + + while (*p != '\0' && *p != '?') { + if (*p == '%') { + /* % encoded character */ + char ch; + + p++; + + /* Parse 2-digit hex value */ + if (!_parse_hex_value(&p, &ch)) { + uri_mailto_error(parser, "invalid %% encoding"); + return FALSE; + } + + /* Check for delimiter */ + if (ch == ',') { + /* Verify and add recipient */ + if (!uri_mailto_add_valid_recipient( + parser, to, FALSE)) + return FALSE; + + /* Reset for next recipient */ + str_truncate(to, 0); + } else { + /* Content character */ + str_append_c(to, ch); + } + } else { + if (*p == ':' || *p == ';' || *p == ',' || + !_is_qchar(*p)) { + uri_mailto_error( + parser, + "invalid character '%c' in 'to' part", *p); + return FALSE; + } + + /* Content character */ + str_append_c(to, *p); + p++; + } + } + + i_assert(*p == '\0' || *p == '?'); + + /* Verify and add recipient */ + if (!uri_mailto_add_valid_recipient(parser, to, FALSE)) + return FALSE; + + *uri_p = p; + return TRUE; +} + +static bool +uri_mailto_parse_header_recipients(struct uri_mailto_parser *parser, + string_t *rcpt_header, bool cc) +{ + string_t *to = t_str_new(128); + const char *p = (const char *)str_data(rcpt_header); + const char *pend = p + str_len(rcpt_header); + + while (p < pend) { + if (*p == ',') { + /* Verify and add recipient */ + if (!uri_mailto_add_valid_recipient(parser, to, cc)) + return FALSE; + + /* Reset for next recipient */ + str_truncate(to, 0); + } else { + /* Content character */ + str_append_c(to, *p); + } + p++; + } + + /* Verify and add recipient */ + if (!uri_mailto_add_valid_recipient(parser, to, cc)) + return FALSE; + + return TRUE; +} + +/* URI header parsing */ + +static bool +uri_mailto_header_is_duplicate(struct uri_mailto_parser *parser, + const char *field_name) +{ + struct uri_mailto *uri = parser->uri; + + if (uri == NULL) + return FALSE; + + if (uri_mailto_header_is_unique(parser, field_name)) { + const struct uri_mailto_header_field *hdrs; + unsigned int count, i; + + hdrs = array_get(&uri->headers, &count); + for (i = 0; i < count; i++) { + if (strcasecmp(hdrs[i].name, field_name) == 0) + return TRUE; + } + } + return FALSE; +} + +static bool +uri_mailto_parse_headers(struct uri_mailto_parser *parser, const char **uri_p) +{ + struct uri_mailto *uri = parser->uri; + unsigned int header_count = 0; + string_t *field = t_str_new(128); + const char *p = *uri_p; + + while (*p != '\0') { + enum { + _HNAME_IGNORED, + _HNAME_GENERIC, + _HNAME_TO, + _HNAME_CC, + _HNAME_SUBJECT, + _HNAME_BODY, + } hname_type = _HNAME_GENERIC; + struct uri_mailto_header_field *hdrf = NULL; + const char *field_name; + + /* Parse field name */ + while (*p != '\0' && *p != '=') { + char ch = *p; + p++; + + if (ch == '%') { + /* Encoded, parse 2-digit hex value */ + if (!_parse_hex_value(&p, &ch)) { + uri_mailto_error(parser, + "invalid %% encoding"); + return FALSE; + } + } else if (ch != '=' && !_is_qchar(ch)) { + uri_mailto_error( + parser, + "invalid character '%c' in header field name part", + ch); + return FALSE; + } + + str_append_c(field, ch); + } + if (*p != '\0') + p++; + + /* Verify field name */ + if (!rfc2822_header_field_name_verify(str_c(field), + str_len(field))) { + uri_mailto_error(parser, "invalid header field name"); + return FALSE; + } + + if (parser->max_headers > -1 && + (int)header_count >= parser->max_headers) { + /* Refuse to accept more headers than allowed by policy + */ + if ((int)header_count == parser->max_headers) { + uri_mailto_warning( + parser, + "more than the maximum %u headers specified; " + "rest is discarded", + parser->max_headers); + } + + hname_type = _HNAME_IGNORED; + } else { + /* Add new header field to array and assign its name */ + + field_name = str_c(field); + if (strcasecmp(field_name, "to") == 0) + hname_type = _HNAME_TO; + else if (strcasecmp(field_name, "cc") == 0) + hname_type = _HNAME_CC; + else if (strcasecmp(field_name, "subject") == 0) + hname_type = _HNAME_SUBJECT; + else if (strcasecmp(field_name, "body") == 0) + hname_type = _HNAME_BODY; + else if (!uri_mailto_header_is_reserved(parser, field_name)) { + if (uri != NULL) { + if (!uri_mailto_header_is_duplicate(parser, field_name)) { + hdrf = array_append_space(&uri->headers); + hdrf->name = p_strdup(parser->pool, field_name); + } else { + uri_mailto_warning( + parser, + "ignored duplicate for unique header field '%s'", + str_sanitize(field_name, 32)); + hname_type = _HNAME_IGNORED; + } + } else { + hname_type = _HNAME_IGNORED; + } + } else { + uri_mailto_warning( + parser, + "ignored reserved header field '%s'", + str_sanitize(field_name, 32)); + hname_type = _HNAME_IGNORED; + } + } + + header_count++; + + /* Reset for field body */ + str_truncate(field, 0); + + /* Parse field body */ + while (*p != '\0' && *p != '&') { + char ch = *p; + p++; + + if (ch == '%') { + /* Encoded, parse 2-digit hex value */ + if (!_parse_hex_value(&p, &ch)) { + uri_mailto_error(parser, + "invalid %% encoding"); + return FALSE; + } + } else if (ch != '=' && !_is_qchar(ch)) { + uri_mailto_error( + parser, + "invalid character '%c' in header field value part", + ch); + return FALSE; + } + str_append_c(field, ch); + } + if (*p != '\0') + p++; + + /* Verify field body */ + if (hname_type == _HNAME_BODY) { + // FIXME: verify body ... + } else { + if (!rfc2822_header_field_body_verify( + str_c(field), str_len(field), FALSE, FALSE)) { + uri_mailto_error(parser, + "invalid header field body"); + return FALSE; + } + } + + /* Assign field body */ + + switch (hname_type) { + case _HNAME_IGNORED: + break; + case _HNAME_TO: + /* Gracefully allow duplicate To fields */ + if (!uri_mailto_parse_header_recipients( + parser, field, FALSE)) + return FALSE; + break; + case _HNAME_CC: + /* Gracefully allow duplicate Cc fields */ + if (!uri_mailto_parse_header_recipients( + parser, field, TRUE)) + return FALSE; + break; + case _HNAME_SUBJECT: + /* Ignore duplicate subject field */ + if (uri != NULL) { + if (uri->subject == NULL) { + uri->subject = + p_strdup(parser->pool, str_c(field)); + } else { + uri_mailto_warning( + parser, + "ignored duplicate subject field"); + } + } + break; + case _HNAME_BODY: + /* Ignore duplicate body field */ + if (uri != NULL) { + if (uri->body == NULL) { + uri->body = p_strdup( + parser->pool, str_c(field)); + } else { + uri_mailto_warning( + parser, "ignored duplicate body field"); + } + } + break; + case _HNAME_GENERIC: + if (uri != NULL && hdrf != NULL) + hdrf->body = p_strdup(parser->pool, str_c(field)); + break; + } + + /* Reset for next name */ + str_truncate(field, 0); + } + + /* Skip '&' */ + if (*p != '\0') + p++; + + *uri_p = p; + return TRUE; +} + +static bool +uri_mailto_parse_uri(struct uri_mailto_parser *parser, const char *uri_body) +{ + const char *p = uri_body; + + /* + * mailtoURI = "mailto:" [ to ] [ hfields ] + * to = [ addr-spec *("%2C" addr-spec ) ] + * hfields = "?" hfield *( "&" hfield ) + * hfield = hfname "=" hfvalue + * hfname = *qchar + * hfvalue = *qchar + * addr-spec = local-part "@" domain + * local-part = dot-atom / quoted-string + * qchar = unreserved / pct-encoded / some-delims + * some-delims = "!" / "$" / "'" / "(" / ")" / "*" + * / "+" / "," / ";" / ":" / "@" + * + * to ~= *tqchar + * tqchar ~= <qchar> without ";" and ":" + * + * Scheme 'mailto:' already parsed, starting parse after colon + */ + + /* First extract to-part by searching for '?' and decoding % items + */ + + if (!uri_mailto_parse_recipients(parser, &p)) + return FALSE; + + if (*p == '\0') + return TRUE; + i_assert(*p == '?'); + p++; + + /* Extract hfield items */ + + while (*p != '\0') { + /* Extract hfield item by searching for '&' and decoding '%' + items */ + if (!uri_mailto_parse_headers(parser, &p)) + return FALSE; + } + return TRUE; +} + +/* + * Validation + */ + +bool uri_mailto_validate(const char *uri_body, + const char **reserved_headers, + const char **unique_headers, int max_recipients, + int max_headers, const struct uri_mailto_log *log) +{ + struct uri_mailto_parser parser; + + i_zero(&parser); + parser.log = log; + parser.max_recipients = max_recipients; + parser.max_headers = max_headers; + parser.reserved_headers = reserved_headers; + parser.unique_headers = unique_headers; + + /* If no errors are reported, we don't need to record any data */ + if (log != NULL) { + parser.pool = pool_datastack_create(); + + parser.uri = p_new(parser.pool, struct uri_mailto, 1); + p_array_init(&parser.uri->recipients, parser.pool, max_recipients); + p_array_init(&parser.uri->headers, parser.pool, max_headers); + } + + if (!uri_mailto_parse_uri(&parser, uri_body)) + return FALSE; + + if (log != NULL) { + if (array_count(&parser.uri->recipients) == 0) { + uri_mailto_warning( + &parser, + "notification URI specifies no recipients"); + } + } + return TRUE; +} + +/* + * Parsing + */ + +struct uri_mailto * +uri_mailto_parse(const char *uri_body, pool_t pool, + const char **reserved_headers, const char **unique_headers, + int max_recipients, int max_headers, + const struct uri_mailto_log *log) +{ + struct uri_mailto_parser parser; + + parser.pool = pool; + parser.log = log; + parser.max_recipients = max_recipients; + parser.max_headers = max_headers; + parser.reserved_headers = reserved_headers; + parser.unique_headers = unique_headers; + + parser.uri = p_new(pool, struct uri_mailto, 1); + p_array_init(&parser.uri->recipients, pool, max_recipients); + p_array_init(&parser.uri->headers, pool, max_headers); + + if (!uri_mailto_parse_uri(&parser, uri_body)) + return NULL; + + if (log != NULL) { + if (array_count(&parser.uri->recipients) == 0) { + uri_mailto_warning( + &parser, + "notification URI specifies no recipients"); + } + } + return parser.uri; +} diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.h b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.h new file mode 100644 index 0000000..8e9e057 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/mailto/uri-mailto.h @@ -0,0 +1,49 @@ +#ifndef URI_MAILTO_H +#define URI_MAILTO_H + +/* + * Types + */ + +struct uri_mailto_header_field { + const char *name; + const char *body; +}; + +struct uri_mailto_recipient { + const char *full; + const struct smtp_address *address; + bool carbon_copy; +}; + +ARRAY_DEFINE_TYPE(recipients, struct uri_mailto_recipient); +ARRAY_DEFINE_TYPE(headers, struct uri_mailto_header_field); + +struct uri_mailto_log { + void *context; + + void (*logv)(void *context, enum log_type log_type, + const char *csrc_filename, unsigned int csrc_linenum, + const char *fmt, va_list args) ATTR_FORMAT(5, 0); +}; + +struct uri_mailto { + ARRAY_TYPE(recipients) recipients; + ARRAY_TYPE(headers) headers; + const char *subject; + const char *body; +}; + +bool uri_mailto_validate + (const char *uri_body, const char **reserved_headers, + const char **unique_headers, int max_recipients, int max_headers, + const struct uri_mailto_log *log); + +struct uri_mailto *uri_mailto_parse +(const char *uri_body, pool_t pool, const char **reserved_headers, + const char **unique_headers, int max_recipients, int max_headers, + const struct uri_mailto_log *log); + +#endif + + diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/sieve-ext-enotify.h b/pigeonhole/src/lib-sieve/plugins/enotify/sieve-ext-enotify.h new file mode 100644 index 0000000..fd8b574 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/sieve-ext-enotify.h @@ -0,0 +1,197 @@ +#ifndef SIEVE_EXT_ENOTIFY_H +#define SIEVE_EXT_ENOTIFY_H + +#include "lib.h" +#include "compat.h" +#include <stdarg.h> + +#include "sieve-common.h" +#include "sieve-error.h" + +/* + * Forward declarations + */ + +struct sieve_enotify_method; +struct sieve_enotify_env; +struct sieve_enotify_action; +struct sieve_enotify_print_env; +struct sieve_enotify_exec_env; + +/* + * Notify method definition + */ + +struct sieve_enotify_method_def { + const char *identifier; + + /* Registration */ + bool (*load) + (const struct sieve_enotify_method *nmth, void **context); + void (*unload) + (const struct sieve_enotify_method *nmth); + + /* Validation */ + bool (*compile_check_uri) + (const struct sieve_enotify_env *nenv, const char *uri, + const char *uri_body); + bool (*compile_check_message) + (const struct sieve_enotify_env *nenv, string_t *message); + bool (*compile_check_from) + (const struct sieve_enotify_env *nenv, string_t *from); + bool (*compile_check_option) + (const struct sieve_enotify_env *nenv, const char *option, + const char *value); + + /* Runtime */ + bool (*runtime_check_uri) + (const struct sieve_enotify_env *nenv, const char *uri, + const char *uri_body); + const char *(*runtime_get_method_capability) + (const struct sieve_enotify_env *nenv, const char *uri, + const char *uri_body, const char *capability); + bool (*runtime_check_operands) + (const struct sieve_enotify_env *nenv, const char *uri, + const char *uri_body, string_t *message, string_t *from, + pool_t context_pool, void **method_context); + bool (*runtime_set_option) + (const struct sieve_enotify_env *nenv, void *method_context, + const char *option, const char *value); + + /* Action duplicates */ + int (*action_check_duplicates) + (const struct sieve_enotify_env *nenv, + const struct sieve_enotify_action *nact, + const struct sieve_enotify_action *nact_other); + + /* Action print */ + void (*action_print) + (const struct sieve_enotify_print_env *penv, + const struct sieve_enotify_action *nact); + + /* Action execution + (returns 0 if all is ok and -1 for temporary error) + */ + int (*action_execute) + (const struct sieve_enotify_exec_env *nenv, + const struct sieve_enotify_action *nact); +}; + +/* + * Notify method instance + */ + +struct sieve_enotify_method { + const struct sieve_enotify_method_def *def; + int id; + + struct sieve_instance *svinst; + void *context; +}; + +const struct sieve_enotify_method *sieve_enotify_method_register + (struct sieve_instance *svinst, + const struct sieve_enotify_method_def *nmth_def); +void sieve_enotify_method_unregister + (const struct sieve_enotify_method *nmth); + +/* + * Notify method environment + */ + +struct sieve_enotify_env { + struct sieve_instance *svinst; + + const struct sieve_enotify_method *method; + + struct sieve_error_handler *ehandler; + const char *location; + struct event *event; +}; + +/* + * Notify method printing + */ + +void sieve_enotify_method_printf + (const struct sieve_enotify_print_env *penv, const char *fmt, ...) + ATTR_FORMAT(2, 3); + +/* + * Notify execution environment + */ + +struct sieve_enotify_exec_env { + struct sieve_instance *svinst; + enum sieve_execute_flags flags; + + const struct sieve_enotify_method *method; + + const struct sieve_script_env *scriptenv; + const struct sieve_message_data *msgdata; + struct sieve_message_context *msgctx; + + struct sieve_error_handler *ehandler; + const char *location; + struct event *event; +}; + +struct event_passthrough * +sieve_enotify_create_finish_event(const struct sieve_enotify_exec_env *nenv); + +/* + * Notify action + */ + +struct sieve_enotify_action { + const struct sieve_enotify_method *method; + void *method_context; + + sieve_number_t importance; + const char *message; + const char *from; +}; + +/* + * Error handling + */ + +#define sieve_enotify_error(ENV, ...) \ + sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \ + LOG_TYPE_ERROR, (ENV)->location, 0, __VA_ARGS__ ) +#define sieve_enotify_warning(ENV, ...) \ + sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \ + LOG_TYPE_WARNING, \ + (ENV)->location, 0, __VA_ARGS__ ) +#define sieve_enotify_info(ENV, ...) \ + sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \ + LOG_TYPE_INFO, \ + (ENV)->location, 0, __VA_ARGS__ ) +#define sieve_enotify_critical(ENV, ...) \ + sieve_critical((ENV)->svinst, (ENV)->ehandler, NULL, __VA_ARGS__ ) + +#define sieve_enotify_global_error(ENV, ...) \ + sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \ + LOG_TYPE_ERROR, (ENV)->location, \ + SIEVE_ERROR_FLAG_GLOBAL, __VA_ARGS__ ) +#define sieve_enotify_global_warning(ENV, ...) \ + sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \ + LOG_TYPE_WARNING, (ENV)->location, \ + SIEVE_ERROR_FLAG_GLOBAL, __VA_ARGS__ ) +#define sieve_enotify_global_info(ENV, ...) \ + sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \ + LOG_TYPE_INFO, (ENV)->location, \ + SIEVE_ERROR_FLAG_GLOBAL, __VA_ARGS__ ) + +#define sieve_enotify_event_log(ENV, EVENT, ...) \ + sieve_event_log((ENV)->svinst, (ENV)->ehandler, (EVENT), \ + LOG_TYPE_INFO, (ENV)->location, \ + SIEVE_ERROR_FLAG_GLOBAL, __VA_ARGS__ ) + +#define sieve_enotify_global_log_error(ENV, ...) \ + sieve_event_log((ENV)->svinst, (ENV)->ehandler, (ENV)->event, \ + LOG_TYPE_ERROR, (ENV)->location, \ + (SIEVE_ERROR_FLAG_GLOBAL | \ + SIEVE_ERROR_FLAG_GLOBAL_MAX_INFO), __VA_ARGS__ ) +#endif + diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c b/pigeonhole/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c new file mode 100644 index 0000000..8a6c071 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/tst-notify-method-capability.c @@ -0,0 +1,233 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "sieve-common.h" +#include "sieve-commands.h" +#include "sieve-stringlist.h" +#include "sieve-code.h" +#include "sieve-comparators.h" +#include "sieve-match-types.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" +#include "sieve-match.h" + +#include "ext-enotify-common.h" + +/* + * String test + * + * Syntax: + * notify_method_capability [COMPARATOR] [MATCH-TYPE] + * <notification-uri: string> + * <notification-capability: string> + * <key-list: string-list> + */ + +static bool tst_notifymc_registered + (struct sieve_validator *valdtr, const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg); +static bool tst_notifymc_validate + (struct sieve_validator *valdtr, struct sieve_command *tst); +static bool tst_notifymc_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx); + +const struct sieve_command_def notify_method_capability_test = { + .identifier = "notify_method_capability", + .type = SCT_TEST, + .positional_args = 3, + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .registered = tst_notifymc_registered, + .validate = tst_notifymc_validate, + .generate = tst_notifymc_generate +}; + +/* + * String operation + */ + +static bool tst_notifymc_operation_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int tst_notifymc_operation_execute + (const struct sieve_runtime_env *renv, sieve_size_t *address); + +const struct sieve_operation_def notify_method_capability_operation = { + .mnemonic = "NOTIFY_METHOD_CAPABILITY", + .ext_def = &enotify_extension, + .code = EXT_ENOTIFY_OPERATION_NOTIFY_METHOD_CAPABILITY, + .dump = tst_notifymc_operation_dump, + .execute = tst_notifymc_operation_execute +}; + +/* + * Optional arguments + */ + +enum tst_notifymc_optional { + OPT_END, + OPT_COMPARATOR, + OPT_MATCH_TYPE +}; + +/* + * Test registration + */ + +static bool tst_notifymc_registered +(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED, + struct sieve_command_registration *cmd_reg) +{ + /* The order of these is not significant */ + sieve_comparators_link_tag(valdtr, cmd_reg, OPT_COMPARATOR); + sieve_match_types_link_tags(valdtr, cmd_reg, OPT_MATCH_TYPE); + + return TRUE; +} + +/* + * Test validation + */ + +static bool tst_notifymc_validate +(struct sieve_validator *valdtr, struct sieve_command *tst) +{ + struct sieve_ast_argument *arg = tst->first_positional; + const struct sieve_match_type mcht_default = + SIEVE_MATCH_TYPE_DEFAULT(is_match_type); + const struct sieve_comparator cmp_default = + SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); + + if ( !sieve_validate_positional_argument + (valdtr, tst, arg, "notification-uri", 1, SAAT_STRING) ) { + return FALSE; + } + + if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) ) + return FALSE; + + arg = sieve_ast_argument_next(arg); + + if ( !sieve_validate_positional_argument + (valdtr, tst, arg, "notification-capability", 2, SAAT_STRING) ) { + return FALSE; + } + + if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) ) + return FALSE; + + arg = sieve_ast_argument_next(arg); + + if ( !sieve_validate_positional_argument + (valdtr, tst, arg, "key-list", 3, SAAT_STRING_LIST) ) { + return FALSE; + } + + if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) ) + return FALSE; + + /* Validate the key argument to a specified match type */ + return sieve_match_type_validate + (valdtr, tst, arg, &mcht_default, &cmp_default); +} + +/* + * Test generation + */ + +static bool tst_notifymc_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) +{ + sieve_operation_emit + (cgenv->sblock, cmd->ext, ¬ify_method_capability_operation); + + /* Generate arguments */ + return sieve_generate_arguments(cgenv, cmd, NULL); +} + +/* + * Code dump + */ + +static bool tst_notifymc_operation_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + sieve_code_dumpf(denv, "NOTIFY_METHOD_CAPABILITY"); + sieve_code_descend(denv); + + /* Handle any optional arguments */ + if ( sieve_match_opr_optional_dump(denv, address, NULL) != 0 ) + return FALSE; + + return + sieve_opr_string_dump(denv, address, "notify uri") && + sieve_opr_string_dump(denv, address, "notify capability") && + sieve_opr_stringlist_dump(denv, address, "key list"); +} + +/* + * Code execution + */ + +static int tst_notifymc_operation_execute +(const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + struct sieve_match_type mcht = + SIEVE_MATCH_TYPE_DEFAULT(is_match_type); + struct sieve_comparator cmp = + SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); + string_t *notify_uri, *notify_capability; + struct sieve_stringlist *value_list, *key_list; + const char *cap_value; + int match, ret; + + /* + * Read operands + */ + + /* Handle match-type and comparator operands */ + if ( sieve_match_opr_optional_read + (renv, address, NULL, &ret, &cmp, &mcht) < 0 ) + return ret; + + /* Read notify uri */ + if ( (ret=sieve_opr_string_read(renv, address, "notify-uri", ¬ify_uri)) + <= 0 ) + return ret; + + /* Read notify capability */ + if ( (ret=sieve_opr_string_read + (renv, address, "notify-capability", ¬ify_capability)) <= 0 ) + return ret; + + /* Read key-list */ + if ( (ret=sieve_opr_stringlist_read(renv, address, "key-list", &key_list)) + <= 0) + return ret; + + /* + * Perform operation + */ + + sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "notify_method_capability test"); + + cap_value = ext_enotify_runtime_get_method_capability + (renv, notify_uri, str_c(notify_capability)); + + if ( cap_value != NULL ) { + value_list = sieve_single_stringlist_create_cstr(renv, cap_value, TRUE); + + /* Perform match */ + if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) + < 0 ) + return ret; + } else { + match = 0; + } + + /* Set test result for subsequent conditional jump */ + sieve_interpreter_set_test_result(renv->interp, match > 0); + return SIEVE_EXEC_OK; +} diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c b/pigeonhole/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c new file mode 100644 index 0000000..becc41c --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/tst-valid-notify-method.c @@ -0,0 +1,144 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "sieve-common.h" +#include "sieve-commands.h" +#include "sieve-stringlist.h" +#include "sieve-code.h" +#include "sieve-comparators.h" +#include "sieve-match-types.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" +#include "sieve-match.h" + +#include "ext-enotify-common.h" + +/* + * Valid_notify_method test + * + * Syntax: + * valid_notify_method <notification-uris: string-list> + */ + +static bool tst_vnotifym_validate + (struct sieve_validator *valdtr, struct sieve_command *tst); +static bool tst_vnotifym_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx); + +const struct sieve_command_def valid_notify_method_test = { + .identifier = "valid_notify_method", + .type = SCT_TEST, + .positional_args = 1, + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = tst_vnotifym_validate, + .generate = tst_vnotifym_generate +}; + +/* + * Valid_notify_method operation + */ + +static bool tst_vnotifym_operation_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int tst_vnotifym_operation_execute + (const struct sieve_runtime_env *renv, sieve_size_t *address); + +const struct sieve_operation_def valid_notify_method_operation = { + .mnemonic = "VALID_NOTIFY_METHOD", + .ext_def = &enotify_extension, + .code = EXT_ENOTIFY_OPERATION_VALID_NOTIFY_METHOD, + .dump = tst_vnotifym_operation_dump, + .execute = tst_vnotifym_operation_execute +}; + +/* + * Test validation + */ + +static bool tst_vnotifym_validate + (struct sieve_validator *valdtr, struct sieve_command *tst) +{ + struct sieve_ast_argument *arg = tst->first_positional; + + if ( !sieve_validate_positional_argument + (valdtr, tst, arg, "notification-uris", 1, SAAT_STRING_LIST) ) { + return FALSE; + } + + return sieve_validator_argument_activate(valdtr, tst, arg, FALSE); +} + +/* + * Test generation + */ + +static bool tst_vnotifym_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) +{ + sieve_operation_emit(cgenv->sblock, cmd->ext, &valid_notify_method_operation); + + /* Generate arguments */ + return sieve_generate_arguments(cgenv, cmd, NULL); +} + +/* + * Code dump + */ + +static bool tst_vnotifym_operation_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + sieve_code_dumpf(denv, "VALID_NOTIFY_METHOD"); + sieve_code_descend(denv); + + return + sieve_opr_stringlist_dump(denv, address, "notify-uris"); +} + +/* + * Code execution + */ + +static int tst_vnotifym_operation_execute +(const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + struct sieve_stringlist *notify_uris; + string_t *uri_item; + bool all_valid = TRUE; + int ret; + + /* + * Read operands + */ + + /* Read notify uris */ + if ( (ret=sieve_opr_stringlist_read + (renv, address, "notify-uris", ¬ify_uris)) <= 0 ) + return ret; + + /* + * Perform operation + */ + + sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "valid_notify_method test"); + + uri_item = NULL; + while ( (ret=sieve_stringlist_next_item(notify_uris, &uri_item)) > 0 ) { + if ( !ext_enotify_runtime_method_validate(renv, uri_item) ) { + all_valid = FALSE; + break; + } + } + + if ( ret < 0 ) { + sieve_runtime_trace_error(renv, "invalid method uri item"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + sieve_interpreter_set_test_result(renv->interp, all_valid); + return SIEVE_EXEC_OK; +} diff --git a/pigeonhole/src/lib-sieve/plugins/enotify/vmodf-encodeurl.c b/pigeonhole/src/lib-sieve/plugins/enotify/vmodf-encodeurl.c new file mode 100644 index 0000000..801f882 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/enotify/vmodf-encodeurl.c @@ -0,0 +1,119 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "unichar.h" +#include "str.h" + +#include "sieve-common.h" +#include "sieve-code.h" + +#include "sieve-ext-variables.h" + +#include "ext-enotify-common.h" + +/* + * Encodeurl modifier + */ + +static bool +mod_encodeurl_modify(const struct sieve_variables_modifier *modf, + string_t *in, string_t **result); + +const struct sieve_variables_modifier_def encodeurl_modifier = { + SIEVE_OBJECT("encodeurl", &encodeurl_operand, 0), + 15, + mod_encodeurl_modify +}; + +/* + * Modifier operand + */ + +static const struct sieve_extension_objects ext_enotify_modifiers = + SIEVE_VARIABLES_DEFINE_MODIFIER(encodeurl_modifier); + +const struct sieve_operand_def encodeurl_operand = { + .name = "modifier", + .ext_def = &enotify_extension, + .class = &sieve_variables_modifier_operand_class, + .interface = &ext_enotify_modifiers +}; + +/* + * Modifier implementation + */ + +static const char _uri_reserved_lookup[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 00 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, // 20 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, // 30 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, // 50 + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, // 70 + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 90 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // A0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // B0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // C0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // D0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // E0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // F0 +}; + +static bool +mod_encodeurl_modify(const struct sieve_variables_modifier *modf, + string_t *in, string_t **result) +{ + size_t max_var_size = + sieve_variables_get_max_variable_size(modf->var_ext); + const unsigned char *p, *poff, *pend; + size_t new_size; + + if ( str_len(in) == 0 ) { + *result = in; + return TRUE; + } + + /* allocate new string */ + new_size = str_len(in) + 32; + if (new_size > max_var_size) + new_size = max_var_size; + *result = t_str_new(new_size + 1); + + /* escape string */ + p = str_data(in); + pend = p + str_len(in); + poff = p; + while (p < pend) { + unsigned int i, n = uni_utf8_char_bytes(*p); + + if (n > 1 || (_uri_reserved_lookup[*p] & 0x01) != 0) { + str_append_data(*result, poff, p - poff); + poff = p; + + if (str_len(*result) + 3 * n > max_var_size) + break; + + str_printfa(*result, "%%%02X", *p); + for (i = 1; i < n && p < pend; i++) { + p++; + poff++; + str_printfa(*result, "%%%02X", *p); + } + + poff++; + } else if ((str_len(*result) + (p - poff) + 1) > max_var_size) { + break; + } + p++; + } + + str_append_data(*result, poff, p - poff); + return TRUE; +} + + |