diff options
Diffstat (limited to 'pigeonhole/src/plugins')
57 files changed, 15693 insertions, 0 deletions
diff --git a/pigeonhole/src/plugins/Makefile.am b/pigeonhole/src/plugins/Makefile.am new file mode 100644 index 0000000..b6c7551 --- /dev/null +++ b/pigeonhole/src/plugins/Makefile.am @@ -0,0 +1,7 @@ +SUBDIRS = \ + doveadm-sieve \ + lda-sieve \ + sieve-extprograms \ + imapsieve \ + imap-filter-sieve \ + settings diff --git a/pigeonhole/src/plugins/Makefile.in b/pigeonhole/src/plugins/Makefile.in new file mode 100644 index 0000000..890ce14 --- /dev/null +++ b/pigeonhole/src/plugins/Makefile.in @@ -0,0 +1,699 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 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/plugins +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 $(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 = +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 = +SOURCES = +DIST_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 +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 +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 = \ + doveadm-sieve \ + lda-sieve \ + sieve-extprograms \ + imapsieve \ + imap-filter-sieve \ + settings + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/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): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# 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 +installdirs: installdirs-recursive +installdirs-am: +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 mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +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 Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean 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 \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean 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/plugins/doveadm-sieve/Makefile.am b/pigeonhole/src/plugins/doveadm-sieve/Makefile.am new file mode 100644 index 0000000..9f98dab --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/Makefile.am @@ -0,0 +1,31 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + $(LIBDOVECOT_INCLUDE) \ + $(LIBDOVECOT_STORAGE_INCLUDE) \ + $(LIBDOVECOT_DOVEADM_INCLUDE) + +doveadm_moduledir = $(dovecot_moduledir)/doveadm +lib10_doveadm_sieve_plugin_la_LDFLAGS = -module -avoid-version + +doveadm_module_LTLIBRARIES = lib10_doveadm_sieve_plugin.la + +lib10_doveadm_sieve_plugin_la_LIBADD = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la + +commands = \ + doveadm-sieve-cmd-list.c \ + doveadm-sieve-cmd-get.c \ + doveadm-sieve-cmd-put.c \ + doveadm-sieve-cmd-delete.c \ + doveadm-sieve-cmd-activate.c \ + doveadm-sieve-cmd-rename.c + +lib10_doveadm_sieve_plugin_la_SOURCES = \ + $(commands) \ + doveadm-sieve-cmd.c \ + doveadm-sieve-sync.c \ + doveadm-sieve-plugin.c + +noinst_HEADERS = \ + doveadm-sieve-cmd.h \ + doveadm-sieve-plugin.h diff --git a/pigeonhole/src/plugins/doveadm-sieve/Makefile.in b/pigeonhole/src/plugins/doveadm-sieve/Makefile.in new file mode 100644 index 0000000..be3b853 --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/Makefile.in @@ -0,0 +1,796 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 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/plugins/doveadm-sieve +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 = +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)$(doveadm_moduledir)" +LTLIBRARIES = $(doveadm_module_LTLIBRARIES) +lib10_doveadm_sieve_plugin_la_DEPENDENCIES = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la +am__objects_1 = doveadm-sieve-cmd-list.lo doveadm-sieve-cmd-get.lo \ + doveadm-sieve-cmd-put.lo doveadm-sieve-cmd-delete.lo \ + doveadm-sieve-cmd-activate.lo doveadm-sieve-cmd-rename.lo +am_lib10_doveadm_sieve_plugin_la_OBJECTS = $(am__objects_1) \ + doveadm-sieve-cmd.lo doveadm-sieve-sync.lo \ + doveadm-sieve-plugin.lo +lib10_doveadm_sieve_plugin_la_OBJECTS = \ + $(am_lib10_doveadm_sieve_plugin_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +lib10_doveadm_sieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(lib10_doveadm_sieve_plugin_la_LDFLAGS) $(LDFLAGS) -o $@ +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)/doveadm-sieve-cmd-activate.Plo \ + ./$(DEPDIR)/doveadm-sieve-cmd-delete.Plo \ + ./$(DEPDIR)/doveadm-sieve-cmd-get.Plo \ + ./$(DEPDIR)/doveadm-sieve-cmd-list.Plo \ + ./$(DEPDIR)/doveadm-sieve-cmd-put.Plo \ + ./$(DEPDIR)/doveadm-sieve-cmd-rename.Plo \ + ./$(DEPDIR)/doveadm-sieve-cmd.Plo \ + ./$(DEPDIR)/doveadm-sieve-plugin.Plo \ + ./$(DEPDIR)/doveadm-sieve-sync.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 = $(lib10_doveadm_sieve_plugin_la_SOURCES) +DIST_SOURCES = $(lib10_doveadm_sieve_plugin_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@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + $(LIBDOVECOT_INCLUDE) \ + $(LIBDOVECOT_STORAGE_INCLUDE) \ + $(LIBDOVECOT_DOVEADM_INCLUDE) + +doveadm_moduledir = $(dovecot_moduledir)/doveadm +lib10_doveadm_sieve_plugin_la_LDFLAGS = -module -avoid-version +doveadm_module_LTLIBRARIES = lib10_doveadm_sieve_plugin.la +lib10_doveadm_sieve_plugin_la_LIBADD = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la + +commands = \ + doveadm-sieve-cmd-list.c \ + doveadm-sieve-cmd-get.c \ + doveadm-sieve-cmd-put.c \ + doveadm-sieve-cmd-delete.c \ + doveadm-sieve-cmd-activate.c \ + doveadm-sieve-cmd-rename.c + +lib10_doveadm_sieve_plugin_la_SOURCES = \ + $(commands) \ + doveadm-sieve-cmd.c \ + doveadm-sieve-sync.c \ + doveadm-sieve-plugin.c + +noinst_HEADERS = \ + doveadm-sieve-cmd.h \ + doveadm-sieve-plugin.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/plugins/doveadm-sieve/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/doveadm-sieve/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-doveadm_moduleLTLIBRARIES: $(doveadm_module_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(doveadm_module_LTLIBRARIES)'; test -n "$(doveadm_moduledir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(doveadm_moduledir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(doveadm_moduledir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(doveadm_moduledir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(doveadm_moduledir)"; \ + } + +uninstall-doveadm_moduleLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(doveadm_module_LTLIBRARIES)'; test -n "$(doveadm_moduledir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(doveadm_moduledir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(doveadm_moduledir)/$$f"; \ + done + +clean-doveadm_moduleLTLIBRARIES: + -test -z "$(doveadm_module_LTLIBRARIES)" || rm -f $(doveadm_module_LTLIBRARIES) + @list='$(doveadm_module_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +lib10_doveadm_sieve_plugin.la: $(lib10_doveadm_sieve_plugin_la_OBJECTS) $(lib10_doveadm_sieve_plugin_la_DEPENDENCIES) $(EXTRA_lib10_doveadm_sieve_plugin_la_DEPENDENCIES) + $(AM_V_CCLD)$(lib10_doveadm_sieve_plugin_la_LINK) -rpath $(doveadm_moduledir) $(lib10_doveadm_sieve_plugin_la_OBJECTS) $(lib10_doveadm_sieve_plugin_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-activate.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-delete.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-get.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-list.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-put.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd-rename.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-cmd.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-plugin.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doveadm-sieve-sync.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: + for dir in "$(DESTDIR)$(doveadm_moduledir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-doveadm_moduleLTLIBRARIES clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-activate.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-delete.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-get.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-list.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-put.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-rename.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-plugin.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-sync.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-doveadm_moduleLTLIBRARIES + +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)/doveadm-sieve-cmd-activate.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-delete.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-get.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-list.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-put.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd-rename.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-cmd.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-plugin.Plo + -rm -f ./$(DEPDIR)/doveadm-sieve-sync.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-doveadm_moduleLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-doveadm_moduleLTLIBRARIES clean-generic clean-libtool \ + 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-doveadm_moduleLTLIBRARIES \ + 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 uninstall-doveadm_moduleLTLIBRARIES + +.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/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c new file mode 100644 index 0000000..f392478 --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-activate.c @@ -0,0 +1,145 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "doveadm-mail.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "doveadm-sieve-cmd.h" + +struct doveadm_sieve_activate_cmd_context { + struct doveadm_sieve_cmd_context ctx; + + const char *scriptname; +}; + +static int +cmd_sieve_activate_run(struct doveadm_sieve_cmd_context *_ctx) +{ + struct doveadm_sieve_activate_cmd_context *ctx = + (struct doveadm_sieve_activate_cmd_context *)_ctx; + struct sieve_storage *storage = _ctx->storage; + struct sieve_script *script; + enum sieve_error error; + int ret = 0; + + script = sieve_storage_open_script + (storage, ctx->scriptname, NULL); + if ( script == NULL ) { + i_error("Failed to activate Sieve script: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + return -1; + } + + if ( sieve_script_is_active(script) <= 0 ) { + /* Script is first being activated; compile it again without the UPLOAD + * flag. + */ + struct sieve_error_handler *ehandler; + enum sieve_compile_flags cpflags = + SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_ACTIVATED; + struct sieve_binary *sbin; + enum sieve_error error; + + /* Compile */ + ehandler = sieve_master_ehandler_create(ctx->ctx.svinst, 0); + if ( (sbin=sieve_compile_script + (script, ehandler, cpflags, &error)) == NULL ) { + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + } else { + sieve_close(&sbin); + } + sieve_error_handler_unref(&ehandler); + } + + /* Activate only when script is valid (or already active) */ + if ( ret == 0 ) { + /* Refresh activation no matter what; this can also resolve some erroneous + * situations. + */ + ret = sieve_script_activate(script, (time_t)-1); + if ( ret < 0 ) { + i_error("Failed to activate Sieve script: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + } + } + + sieve_script_unref(&script); + return ret; +} + +static int cmd_sieve_deactivate_run +(struct doveadm_sieve_cmd_context *_ctx) +{ + struct sieve_storage *storage = _ctx->storage; + enum sieve_error error; + + if (sieve_storage_deactivate(storage, (time_t)-1) < 0) { + i_error("Failed to deactivate Sieve script: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + return -1; + } + return 0; +} + +static void cmd_sieve_activate_init +(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct doveadm_sieve_activate_cmd_context *ctx = + (struct doveadm_sieve_activate_cmd_context *)_ctx; + + if (str_array_length(args) != 1) + doveadm_mail_help_name("sieve activate"); + doveadm_sieve_cmd_scriptnames_check(args); + + ctx->scriptname = p_strdup(ctx->ctx.ctx.pool, args[0]); +} + +static struct doveadm_mail_cmd_context * +cmd_sieve_activate_alloc(void) +{ + struct doveadm_sieve_activate_cmd_context *ctx; + + ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_activate_cmd_context); + ctx->ctx.ctx.v.init = cmd_sieve_activate_init; + ctx->ctx.v.run = cmd_sieve_activate_run; + return &ctx->ctx.ctx; +} + +static struct doveadm_mail_cmd_context * +cmd_sieve_deactivate_alloc(void) +{ + struct doveadm_sieve_cmd_context *ctx; + + ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_cmd_context); + ctx->v.run = cmd_sieve_deactivate_run; + return &ctx->ctx; +} + +struct doveadm_cmd_ver2 doveadm_sieve_cmd_activate = { + .name = "sieve activate", + .mail_cmd = cmd_sieve_activate_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<scriptname>", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_sieve_cmd_deactivate = { + .name = "sieve deactivate", + .mail_cmd = cmd_sieve_deactivate_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX, +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAMS_END +}; diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c new file mode 100644 index 0000000..8517abd --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-delete.c @@ -0,0 +1,116 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "array.h" +#include "doveadm-mail.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "doveadm-sieve-cmd.h" + +struct doveadm_sieve_delete_cmd_context { + struct doveadm_sieve_cmd_context ctx; + + ARRAY_TYPE(const_string) scriptnames; + bool ignore_active:1; +}; + +static int +cmd_sieve_delete_run(struct doveadm_sieve_cmd_context *_ctx) +{ + struct doveadm_sieve_delete_cmd_context *ctx = + (struct doveadm_sieve_delete_cmd_context *)_ctx; + struct sieve_storage *storage = _ctx->storage; + const ARRAY_TYPE(const_string) *scriptnames = &ctx->scriptnames; + const char *scriptname; + struct sieve_script *script; + enum sieve_error error; + int ret = 0; + + array_foreach_elem(scriptnames, scriptname) { + int sret = 0; + + script = sieve_storage_open_script + (storage, scriptname, NULL); + if (script == NULL) { + sret = -1; + } else { + if (sieve_script_delete(script, ctx->ignore_active) < 0) { + (void)sieve_storage_get_last_error(storage, &error); + sret = -1; + } + sieve_script_unref(&script); + } + + if (sret < 0) { + i_error("Failed to delete Sieve script: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + } + } + return ret; +} + +static void cmd_sieve_delete_init +(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct doveadm_sieve_delete_cmd_context *ctx = + (struct doveadm_sieve_delete_cmd_context *)_ctx; + const char *name; + unsigned int i; + + if (args[0] == NULL) + doveadm_mail_help_name("sieve delete"); + doveadm_sieve_cmd_scriptnames_check(args); + + for (i = 0; args[i] != NULL; i++) { + name = p_strdup(ctx->ctx.ctx.pool, args[i]); + array_append(&ctx->scriptnames, &name, 1); + } +} + +static bool +cmd_sieve_delete_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) +{ + struct doveadm_sieve_delete_cmd_context *ctx = + (struct doveadm_sieve_delete_cmd_context *)_ctx; + + switch ( c ) { + case 'a': + ctx->ignore_active = TRUE; + break; + default: + return FALSE; + } + return TRUE; +} + +static struct doveadm_mail_cmd_context * +cmd_sieve_delete_alloc(void) +{ + struct doveadm_sieve_delete_cmd_context *ctx; + + ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_delete_cmd_context); + ctx->ctx.ctx.getopt_args = "a"; + ctx->ctx.ctx.v.parse_arg = cmd_sieve_delete_parse_arg; + ctx->ctx.ctx.v.init = cmd_sieve_delete_init; + ctx->ctx.v.run = cmd_sieve_delete_run; + p_array_init(&ctx->scriptnames, ctx->ctx.ctx.pool, 16); + return &ctx->ctx.ctx; +} + +struct doveadm_cmd_ver2 doveadm_sieve_cmd_delete = { + .name = "sieve delete", + .mail_cmd = cmd_sieve_delete_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-a] <scriptname> [...]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('a',"ignore-active",CMD_PARAM_BOOL,0) +DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_ARRAY,CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c new file mode 100644 index 0000000..e1bf7e3 --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-get.c @@ -0,0 +1,83 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "doveadm-print.h" +#include "doveadm-mail.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "doveadm-sieve-cmd.h" + +struct doveadm_sieve_get_cmd_context { + struct doveadm_sieve_cmd_context ctx; + + const char *scriptname; +}; + +static int +cmd_sieve_get_run(struct doveadm_sieve_cmd_context *_ctx) +{ + struct doveadm_sieve_get_cmd_context *ctx = + (struct doveadm_sieve_get_cmd_context *)_ctx; + struct sieve_script *script; + struct istream *input; + enum sieve_error error; + int ret; + + script = sieve_storage_open_script + (_ctx->storage, ctx->scriptname, &error); + if ( script == NULL || sieve_script_get_stream + (script, &input, &error) < 0 ) { + i_error("Failed to open Sieve script: %s", + sieve_storage_get_last_error(_ctx->storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + if (script != NULL) + sieve_script_unref(&script); + return -1; + } + + ret = doveadm_print_istream(input); + sieve_script_unref(&script); + return ret; +} + +static void cmd_sieve_get_init +(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct doveadm_sieve_get_cmd_context *ctx = + (struct doveadm_sieve_get_cmd_context *)_ctx; + + if ( str_array_length(args) != 1 ) + doveadm_mail_help_name("sieve get"); + doveadm_sieve_cmd_scriptnames_check(args); + + ctx->scriptname = p_strdup(ctx->ctx.ctx.pool, args[0]); + + doveadm_print_header_simple("sieve script"); +} + +static struct doveadm_mail_cmd_context * +cmd_sieve_get_alloc(void) +{ + struct doveadm_sieve_get_cmd_context *ctx; + + ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_get_cmd_context); + ctx->ctx.ctx.v.init = cmd_sieve_get_init; + ctx->ctx.v.run = cmd_sieve_get_run; + doveadm_print_init("pager"); + return &ctx->ctx.ctx; +} + +struct doveadm_cmd_ver2 doveadm_sieve_cmd_get = { + .name = "sieve get", + .mail_cmd = cmd_sieve_get_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<scriptname>", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c new file mode 100644 index 0000000..0dbf379 --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-list.c @@ -0,0 +1,79 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "doveadm-print.h" +#include "doveadm-mail.h" + +#include "sieve.h" +#include "sieve-storage.h" + +#include "doveadm-sieve-cmd.h" + +static int +cmd_sieve_list_run(struct doveadm_sieve_cmd_context *_ctx) +{ + struct sieve_storage *storage = _ctx->storage; + struct sieve_storage_list_context *lctx; + enum sieve_error error; + const char *scriptname; + bool active; + + if ( (lctx = sieve_storage_list_init(storage)) + == NULL ) { + i_error("Listing Sieve scripts failed: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + return -1; + } + + while ( (scriptname=sieve_storage_list_next(lctx, &active)) + != NULL ) { + doveadm_print(scriptname); + if ( active ) + doveadm_print("ACTIVE"); + else + doveadm_print(""); + } + + if ( sieve_storage_list_deinit(&lctx) < 0 ) { + i_error("Listing Sieve scripts failed: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + return -1; + } + return 0; +} + +static void cmd_sieve_list_init +(struct doveadm_mail_cmd_context *_ctx ATTR_UNUSED, + const char *const args[] ATTR_UNUSED) +{ + doveadm_print_header("script", "script", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); + doveadm_print_header("active", "active", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); +} + +static struct doveadm_mail_cmd_context * +cmd_sieve_list_alloc(void) +{ + struct doveadm_sieve_cmd_context *ctx; + + ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_cmd_context); + ctx->ctx.v.init = cmd_sieve_list_init; + ctx->ctx.getopt_args = "s"; + ctx->v.run = cmd_sieve_list_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW); + return &ctx->ctx; +} + +struct doveadm_cmd_ver2 doveadm_sieve_cmd_list = { + .name = "sieve list", + .mail_cmd = cmd_sieve_list_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX, +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAMS_END +}; + diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c new file mode 100644 index 0000000..ef9472d --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-put.c @@ -0,0 +1,189 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "istream.h" +#include "doveadm-mail.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "doveadm-sieve-cmd.h" + +struct doveadm_sieve_put_cmd_context { + struct doveadm_sieve_cmd_context ctx; + + const char *scriptname; + + bool activate:1; +}; + +static int cmd_sieve_put_run +(struct doveadm_sieve_cmd_context *_ctx) +{ + struct doveadm_sieve_put_cmd_context *ctx = + (struct doveadm_sieve_put_cmd_context *)_ctx; + struct sieve_storage_save_context *save_ctx; + struct sieve_storage *storage = _ctx->storage; + struct istream *input = _ctx->ctx.cmd_input; + enum sieve_error error; + ssize_t ret; + bool save_failed = FALSE; + + save_ctx = sieve_storage_save_init + (storage, ctx->scriptname, input); + if ( save_ctx == NULL ) { + i_error("Saving failed: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + return -1; + } + + while ( (ret = i_stream_read(input)) > 0 || ret == -2 ) { + if ( sieve_storage_save_continue(save_ctx) < 0 ) { + save_failed = TRUE; + ret = -1; + break; + } + } + i_assert(ret == -1); + + if ( input->stream_errno != 0 ) { + i_error("read(script input) failed: %s", i_stream_get_error(input)); + doveadm_sieve_cmd_failed_error + (&ctx->ctx, SIEVE_ERROR_TEMP_FAILURE); + } else if ( save_failed ) { + i_error("Saving failed: %s", + sieve_storage_get_last_error(storage, NULL)); + doveadm_sieve_cmd_failed_storage(&ctx->ctx, storage); + } else if ( sieve_storage_save_finish(save_ctx) < 0 ) { + i_error("Saving failed: %s", + sieve_storage_get_last_error(storage, NULL)); + doveadm_sieve_cmd_failed_storage(&ctx->ctx, storage); + } else { + ret = 0; + } + + /* Verify that script compiles */ + if ( ret == 0 ) { + struct sieve_error_handler *ehandler; + enum sieve_compile_flags cpflags = + SIEVE_COMPILE_FLAG_NOGLOBAL | SIEVE_COMPILE_FLAG_UPLOADED; + struct sieve_script *script; + struct sieve_binary *sbin; + + /* Obtain script object for uploaded script */ + script = sieve_storage_save_get_tempscript(save_ctx); + + /* Check result */ + if ( script == NULL ) { + i_error("Saving failed: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + + } else { + /* Mark this as an activation when we are replacing the active script */ + if ( ctx->activate || sieve_storage_save_will_activate(save_ctx) ) + cpflags |= SIEVE_COMPILE_FLAG_ACTIVATED; + + /* Compile */ + ehandler = sieve_master_ehandler_create(ctx->ctx.svinst, 0); + if ( (sbin=sieve_compile_script + (script, ehandler, cpflags, &error)) == NULL ) { + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + } else { + sieve_close(&sbin); + + /* Script is valid; commit it to storage */ + ret = sieve_storage_save_commit(&save_ctx); + if (ret < 0) { + i_error("Saving failed: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + } + } + sieve_error_handler_unref(&ehandler); + } + } + + if ( save_ctx != NULL ) + sieve_storage_save_cancel(&save_ctx); + + if ( ctx->activate && ret == 0 ) { + struct sieve_script *script = sieve_storage_open_script + (storage, ctx->scriptname, NULL); + if ( script == NULL || + sieve_script_activate(script, (time_t)-1) < 0) { + i_error("Failed to activate Sieve script: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + } + if (script != NULL) + sieve_script_unref(&script); + } + + i_assert(input->eof); + return ret < 0 ? -1 : 0; +} + +static void cmd_sieve_put_init +(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct doveadm_sieve_put_cmd_context *ctx = + (struct doveadm_sieve_put_cmd_context *)_ctx; + + if ( str_array_length(args) != 1 ) + doveadm_mail_help_name("sieve put"); + doveadm_sieve_cmd_scriptnames_check(args); + + ctx->scriptname = p_strdup(ctx->ctx.ctx.pool, args[0]); + + doveadm_mail_get_input(_ctx); +} + +static bool +cmd_sieve_put_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) +{ + struct doveadm_sieve_put_cmd_context *ctx = + (struct doveadm_sieve_put_cmd_context *)_ctx; + + switch ( c ) { + case 'a': + ctx->activate = TRUE; + break; + default: + return FALSE; + } + return TRUE; +} + +static struct doveadm_mail_cmd_context * +cmd_sieve_put_alloc(void) +{ + struct doveadm_sieve_put_cmd_context *ctx; + + ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_put_cmd_context); + ctx->ctx.ctx.getopt_args = "a"; + ctx->ctx.ctx.v.parse_arg = cmd_sieve_put_parse_arg; + ctx->ctx.ctx.v.init = cmd_sieve_put_init; + ctx->ctx.v.run = cmd_sieve_put_run; + return &ctx->ctx.ctx; +} + +struct doveadm_cmd_ver2 doveadm_sieve_cmd_put = { + .name = "sieve put", + .mail_cmd = cmd_sieve_put_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"[-a] <scriptname>", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('a',"activate",CMD_PARAM_BOOL,0) +DOVEADM_CMD_PARAM('\0',"scriptname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0',"file",CMD_PARAM_ISTREAM,CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c new file mode 100644 index 0000000..3cc53c7 --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd-rename.c @@ -0,0 +1,83 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "doveadm-mail.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "doveadm-sieve-cmd.h" + +struct doveadm_sieve_rename_cmd_context { + struct doveadm_sieve_cmd_context ctx; + + const char *oldname, *newname; +}; + +static int +cmd_sieve_rename_run(struct doveadm_sieve_cmd_context *_ctx) +{ + struct doveadm_sieve_rename_cmd_context *ctx = + (struct doveadm_sieve_rename_cmd_context *)_ctx; + struct sieve_storage *storage = _ctx->storage; + struct sieve_script *script; + enum sieve_error error; + int ret = 0; + + script = sieve_storage_open_script + (storage, ctx->oldname, NULL); + if ( script == NULL ) { + i_error("Failed to rename Sieve script: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + } else if ( sieve_script_rename(script, ctx->newname) < 0 ) { + i_error("Failed to rename Sieve script: %s", + sieve_storage_get_last_error(storage, &error)); + doveadm_sieve_cmd_failed_error(_ctx, error); + ret = -1; + } + + if ( script != NULL ) + sieve_script_unref(&script); + return ret; +} + +static void cmd_sieve_rename_init +(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct doveadm_sieve_rename_cmd_context *ctx = + (struct doveadm_sieve_rename_cmd_context *)_ctx; + + if ( str_array_length(args) != 2 ) + doveadm_mail_help_name("sieve rename"); + doveadm_sieve_cmd_scriptnames_check(args); + + ctx->oldname = p_strdup(ctx->ctx.ctx.pool, args[0]); + ctx->newname = p_strdup(ctx->ctx.ctx.pool, args[1]); +} + +static struct doveadm_mail_cmd_context * +cmd_sieve_rename_alloc(void) +{ + struct doveadm_sieve_rename_cmd_context *ctx; + + ctx = doveadm_sieve_cmd_alloc(struct doveadm_sieve_rename_cmd_context); + ctx->ctx.ctx.v.init = cmd_sieve_rename_init; + ctx->ctx.v.run = cmd_sieve_rename_run; + return &ctx->ctx.ctx; +} + +struct doveadm_cmd_ver2 doveadm_sieve_cmd_rename = { + .name = "sieve rename", + .mail_cmd = cmd_sieve_rename_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<oldname> <newname>", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0',"oldname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0',"newname",CMD_PARAM_STR,CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.c new file mode 100644 index 0000000..eb9318c --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.c @@ -0,0 +1,179 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "unichar.h" +#include "mail-storage.h" +#include "doveadm-mail.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "doveadm-sieve-cmd.h" + +void doveadm_sieve_cmd_failed_error +(struct doveadm_sieve_cmd_context *ctx, enum sieve_error error) +{ + struct doveadm_mail_cmd_context *mctx = &ctx->ctx; + int exit_code = 0; + + switch ( error ) { + case SIEVE_ERROR_NONE: + i_unreached(); + return; + case SIEVE_ERROR_TEMP_FAILURE: + exit_code = EX_TEMPFAIL; + break; + case SIEVE_ERROR_NOT_POSSIBLE: + case SIEVE_ERROR_EXISTS: + case SIEVE_ERROR_NOT_VALID: + case SIEVE_ERROR_ACTIVE: + exit_code = DOVEADM_EX_NOTPOSSIBLE; + break; + case SIEVE_ERROR_BAD_PARAMS: + exit_code = EX_USAGE; + break; + case SIEVE_ERROR_NO_PERMISSION: + exit_code = EX_NOPERM; + break; + case SIEVE_ERROR_NO_QUOTA: + exit_code = EX_CANTCREAT; + break; + case SIEVE_ERROR_NOT_FOUND: + exit_code = DOVEADM_EX_NOTFOUND; + break; + default: + i_unreached(); + } + /* tempfail overrides all other exit codes, otherwise use whatever + error happened first */ + if ( mctx->exit_code == 0 || exit_code == EX_TEMPFAIL ) + mctx->exit_code = exit_code; +} + +void doveadm_sieve_cmd_failed_storage +(struct doveadm_sieve_cmd_context *ctx, struct sieve_storage *storage) +{ + enum sieve_error error; + + (void)sieve_storage_get_last_error(storage, &error); + doveadm_sieve_cmd_failed_error(ctx, error); +} + +static const char *doveadm_sieve_cmd_get_setting +(void *context, const char *identifier) +{ + struct doveadm_sieve_cmd_context *ctx = + (struct doveadm_sieve_cmd_context *) context; + + return mail_user_plugin_getenv(ctx->ctx.cur_mail_user, identifier); +} + +static const struct sieve_callbacks sieve_callbacks = { + NULL, + doveadm_sieve_cmd_get_setting +}; + +static bool doveadm_sieve_cmd_parse_arg +(struct doveadm_mail_cmd_context *_ctx ATTR_UNUSED, + int c ATTR_UNUSED) +{ + return FALSE; +} + +void doveadm_sieve_cmd_scriptnames_check(const char *const args[]) +{ + unsigned int i; + + for (i = 0; args[i] != NULL; i++) { + if (!uni_utf8_str_is_valid(args[i])) { + i_fatal_status(EX_DATAERR, + "Sieve script name not valid UTF-8: %s", args[i]); + } + if ( !sieve_script_name_is_valid(args[i]) ) { + i_fatal_status(EX_DATAERR, + "Sieve script name not valid: %s", args[i]); + } + } +} + +static int +doveadm_sieve_cmd_run +(struct doveadm_mail_cmd_context *_ctx, + struct mail_user *user) +{ + struct doveadm_sieve_cmd_context *ctx = + (struct doveadm_sieve_cmd_context *)_ctx; + struct sieve_environment svenv; + enum sieve_error error; + int ret; + + memset((void*)&svenv, 0, sizeof(svenv)); + svenv.username = user->username; + (void)mail_user_get_home(user, &svenv.home_dir); + svenv.base_dir = user->set->base_dir; + svenv.flags = SIEVE_FLAG_HOME_RELATIVE; + + ctx->svinst = sieve_init + (&svenv, &sieve_callbacks, (void *)ctx, user->mail_debug); + + ctx->storage = sieve_storage_create_main + (ctx->svinst, user, SIEVE_STORAGE_FLAG_READWRITE, &error); + if ( ctx->storage == NULL ) { + switch ( error ) { + case SIEVE_ERROR_NOT_POSSIBLE: + error = SIEVE_ERROR_NOT_FOUND; + i_error("Failed to open Sieve storage: " + "Sieve is disabled for this user"); + break; + case SIEVE_ERROR_NOT_FOUND: + i_error("Failed to open Sieve storage: " + "User cannot manage personal Sieve scripts."); + break; + default: + i_error("Failed to open Sieve storage."); + } + doveadm_sieve_cmd_failed_error(ctx, error); + ret = -1; + + } else { + i_assert( ctx->v.run != NULL ); + ret = ctx->v.run(ctx); + sieve_storage_unref(&ctx->storage); + } + + sieve_deinit(&ctx->svinst); + return ret; +} + +struct doveadm_sieve_cmd_context * +doveadm_sieve_cmd_alloc_size(size_t size) +{ + struct doveadm_sieve_cmd_context *ctx; + + ctx = (struct doveadm_sieve_cmd_context *) + doveadm_mail_cmd_alloc_size(size); + ctx->ctx.getopt_args = "s"; + ctx->ctx.v.parse_arg = doveadm_sieve_cmd_parse_arg; + ctx->ctx.v.run = doveadm_sieve_cmd_run; + return ctx; +} + +static struct doveadm_cmd_ver2 *doveadm_sieve_commands[] = { + &doveadm_sieve_cmd_list, + &doveadm_sieve_cmd_get, + &doveadm_sieve_cmd_put, + &doveadm_sieve_cmd_delete, + &doveadm_sieve_cmd_activate, + &doveadm_sieve_cmd_deactivate, + &doveadm_sieve_cmd_rename +}; + +void doveadm_sieve_cmds_init(void) +{ + unsigned int i; + + for (i = 0; i < N_ELEMENTS(doveadm_sieve_commands); i++) + doveadm_cmd_register_ver2(doveadm_sieve_commands[i]); +} diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.h b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.h new file mode 100644 index 0000000..1296701 --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-cmd.h @@ -0,0 +1,43 @@ +#ifndef DOVEADM_SIEVE_CMD_H +#define DOVEADM_SIEVE_CMD_H + +struct doveadm_sieve_cmd_context; + +struct doveadm_sieve_cmd_vfuncs { + /* This is the main function which performs all the work for the + command. This is called once per each user. */ + int (*run)(struct doveadm_sieve_cmd_context *ctx); +}; + +struct doveadm_sieve_cmd_context { + struct doveadm_mail_cmd_context ctx; + + struct sieve_instance *svinst; + struct sieve_storage *storage; + + struct doveadm_sieve_cmd_vfuncs v; +}; + +void doveadm_sieve_cmd_failed_error +(struct doveadm_sieve_cmd_context *ctx, enum sieve_error error); +void doveadm_sieve_cmd_failed_storage +(struct doveadm_sieve_cmd_context *ctx, struct sieve_storage *storage); + +#define doveadm_sieve_cmd_alloc(type) \ + (type *)doveadm_sieve_cmd_alloc_size(sizeof(type)) +struct doveadm_sieve_cmd_context * +doveadm_sieve_cmd_alloc_size(size_t size); + +void doveadm_sieve_cmd_scriptnames_check(const char *const args[]); + +extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_list; +extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_get; +extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_put; +extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_delete; +extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_activate; +extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_deactivate; +extern struct doveadm_cmd_ver2 doveadm_sieve_cmd_rename; + +void doveadm_sieve_cmds_init(void); + +#endif diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.c new file mode 100644 index 0000000..0478b55 --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.c @@ -0,0 +1,24 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "doveadm-mail.h" + +#include "sieve.h" + +#include "doveadm-sieve-cmd.h" +#include "doveadm-sieve-plugin.h" + +const char *doveadm_sieve_plugin_version = DOVECOT_ABI_VERSION; + +void doveadm_sieve_plugin_init(struct module *module) +{ + doveadm_sieve_sync_init(module); + doveadm_sieve_cmds_init(); +} + +void doveadm_sieve_plugin_deinit(void) +{ + /* the hooks array is freed already */ + /*mail_storage_hooks_remove(&doveadm_sieve_mail_storage_hooks);*/ +} diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.h b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.h new file mode 100644 index 0000000..6e9446d --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-plugin.h @@ -0,0 +1,17 @@ +#ifndef DOVEADM_SIEVE_PLUGIN_H +#define DOVEADM_SIEVE_PLUGIN_H + +/* + * Plugin interface + */ + +void doveadm_sieve_plugin_init(struct module *module); +void doveadm_sieve_plugin_deinit(void); + +/* + * Replication + */ + +void doveadm_sieve_sync_init(struct module *module); + +#endif diff --git a/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-sync.c b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-sync.c new file mode 100644 index 0000000..c85a3fc --- /dev/null +++ b/pigeonhole/src/plugins/doveadm-sieve/doveadm-sieve-sync.c @@ -0,0 +1,746 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "ioloop.h" +#include "time-util.h" +#include "istream.h" +#include "istream-concat.h" +#include "mail-storage-private.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "doveadm-sieve-plugin.h" + +#define SIEVE_MAIL_CONTEXT(obj) \ + MODULE_CONTEXT_REQUIRE(obj, sieve_storage_module) +#define SIEVE_USER_CONTEXT(obj) \ + MODULE_CONTEXT_REQUIRE(obj, sieve_user_module) + +struct sieve_mail_user { + union mail_user_module_context module_ctx; + + struct sieve_instance *svinst; + struct sieve_storage *sieve_storage; +}; + +struct sieve_mailbox_attribute_iter { + struct mailbox_attribute_iter iter; + struct mailbox_attribute_iter *super; + + struct sieve_storage_list_context *sieve_list; + string_t *name; + + bool failed; + bool have_active; +}; + +static MODULE_CONTEXT_DEFINE_INIT(sieve_storage_module, + &mail_storage_module_register); +static MODULE_CONTEXT_DEFINE_INIT(sieve_user_module, + &mail_user_module_register); + +static const char * +mail_sieve_get_setting(void *context, const char *identifier) +{ + struct mail_user *mail_user = context; + + return mail_user_plugin_getenv(mail_user, identifier); +} + +static const struct sieve_callbacks mail_sieve_callbacks = { + NULL, + mail_sieve_get_setting +}; + +static void mail_sieve_user_deinit(struct mail_user *user) +{ + struct sieve_mail_user *suser = SIEVE_USER_CONTEXT(user); + + if ( suser->svinst != NULL ) { + if (suser->sieve_storage != NULL) + sieve_storage_unref(&suser->sieve_storage); + sieve_deinit(&suser->svinst); + } + + suser->module_ctx.super.deinit(user); +} + +static int +mail_sieve_user_init +(struct mail_user *user, struct sieve_storage **svstorage_r) +{ + struct sieve_mail_user *suser = SIEVE_USER_CONTEXT(user); + enum sieve_storage_flags storage_flags = + SIEVE_STORAGE_FLAG_READWRITE | + SIEVE_STORAGE_FLAG_SYNCHRONIZING; + struct sieve_environment svenv; + + if ( suser->svinst != NULL ) { + *svstorage_r = suser->sieve_storage; + return suser->sieve_storage != NULL ? 1 : 0; + } + + /* Delayed initialization of sieve storage until it's actually needed */ + i_zero(&svenv); + svenv.username = user->username; + (void)mail_user_get_home(user, &svenv.home_dir); + svenv.base_dir = user->set->base_dir; + svenv.flags = SIEVE_FLAG_HOME_RELATIVE; + + suser->svinst = sieve_init(&svenv, &mail_sieve_callbacks, + user, user->mail_debug); + suser->sieve_storage = sieve_storage_create_main + (suser->svinst, user, storage_flags, NULL); + + *svstorage_r = suser->sieve_storage; + return suser->sieve_storage != NULL ? 1 : 0; +} + +static int sieve_attribute_unset_script(struct mail_storage *storage, + struct sieve_storage *svstorage, + const char *scriptname) +{ + struct sieve_script *script; + const char *errstr; + enum sieve_error error; + int ret = 0; + + script = sieve_storage_open_script(svstorage, scriptname, NULL); + if (script == NULL) { + ret = -1; + } else { + ret = sieve_script_delete(script, TRUE); + sieve_script_unref(&script); + } + + if (ret < 0) { + errstr = sieve_storage_get_last_error(svstorage, &error); + if (error == SIEVE_ERROR_NOT_FOUND) { + /* already deleted, ignore */ + return 0; + } + mail_storage_set_critical(storage, + "Failed to delete Sieve script '%s': %s", scriptname, + errstr); + return -1; + } + return 0; +} + +static int +sieve_attribute_set_active(struct mail_storage *storage, + struct sieve_storage *svstorage, + const struct mail_attribute_value *value) +{ + const char *scriptname; + struct sieve_script *script; + time_t last_change = + (value->last_change == 0 ? ioloop_time : value->last_change); + int ret; + + if (mailbox_attribute_value_to_string(storage, value, &scriptname) < 0) + return -1; + + if (scriptname == NULL) { + /* don't affect non-link active script */ + if ((ret=sieve_storage_is_singular(svstorage)) != 0) { + if (ret < 0) { + mail_storage_set_internal_error(storage); + return -1; + } + return 0; + } + + /* deactivate current script */ + if (sieve_storage_deactivate(svstorage, last_change) < 0) { + mail_storage_set_critical(storage, + "Failed to deactivate Sieve: %s", + sieve_storage_get_last_error(svstorage, NULL)); + return -1; + } + return 0; + } + i_assert(scriptname[0] == MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_LINK); + scriptname++; + + /* activate specified script */ + script = sieve_storage_open_script(svstorage, scriptname, NULL); + ret = script == NULL ? -1 : + sieve_script_activate(script, last_change); + if (ret < 0) { + mail_storage_set_critical(storage, + "Failed to activate Sieve script '%s': %s", scriptname, + sieve_storage_get_last_error(svstorage, NULL)); + } + if (script != NULL) + sieve_script_unref(&script); + sieve_storage_set_modified(svstorage, last_change); + return ret; +} + +static int +sieve_attribute_unset_active_script(struct mail_storage *storage, + struct sieve_storage *svstorage, time_t last_change) +{ + int ret; + + if ((ret=sieve_storage_is_singular(svstorage)) != 0) { + if (ret < 0) + mail_storage_set_internal_error(storage); + return ret; + } + + if (sieve_storage_deactivate(svstorage, last_change) < 0) { + mail_storage_set_critical(storage, + "Failed to deactivate sieve: %s", + sieve_storage_get_last_error(svstorage, NULL)); + return -1; + } + return 0; +} + +static int +sieve_attribute_set_active_script(struct mail_storage *storage, + struct sieve_storage *svstorage, + const struct mail_attribute_value *value) +{ + struct istream *input; + time_t last_change = + (value->last_change == 0 ? ioloop_time : value->last_change); + + if (value->value != NULL) { + input = i_stream_create_from_data(value->value, strlen(value->value)); + } else if (value->value_stream != NULL) { + input = value->value_stream; + i_stream_ref(input); + } else { + return sieve_attribute_unset_active_script + (storage, svstorage, last_change); + } + /* skip over the 'S' type */ + i_stream_skip(input, 1); + + if (sieve_storage_save_as_active + (svstorage, input, last_change) < 0) { + mail_storage_set_critical(storage, + "Failed to save active sieve script: %s", + sieve_storage_get_last_error(svstorage, NULL)); + i_stream_unref(&input); + return -1; + } + + sieve_storage_set_modified(svstorage, last_change); + i_stream_unref(&input); + return 0; +} + +static int +sieve_attribute_set_default(struct mail_storage *storage, + struct sieve_storage *svstorage, + const struct mail_attribute_value *value) +{ + const unsigned char *data; + size_t size; + ssize_t ret; + char type; + + if (value->value != NULL) { + type = value->value[0]; + } else if (value->value_stream != NULL) { + ret = i_stream_read_more(value->value_stream, &data, &size); + if (ret == -1) { + mail_storage_set_critical(storage, "read(%s) failed: %m", + i_stream_get_name(value->value_stream)); + return -1; + } + i_assert(ret > 0); + type = data[0]; + } else { + type = MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT; + } + if (type == MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_LINK) + return sieve_attribute_set_active(storage, svstorage, value); + if (type == MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT) + return sieve_attribute_set_active_script(storage, svstorage, value); + mail_storage_set_error(storage, MAIL_ERROR_PARAMS, + "Invalid value for default sieve attribute"); + return -1; +} + +static int +sieve_attribute_set_sieve(struct mail_storage *storage, + const char *key, + const struct mail_attribute_value *value) +{ + struct sieve_storage *svstorage; + struct sieve_storage_save_context *save_ctx; + struct istream *input; + const char *scriptname; + int ret; + + if ((ret = mail_sieve_user_init(storage->user, &svstorage)) <= 0) { + if (ret == 0) { + mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND, + "Sieve not enabled for user"); + } + return -1; + } + + if (strcmp(key, MAILBOX_ATTRIBUTE_SIEVE_DEFAULT) == 0) + return sieve_attribute_set_default(storage, svstorage, value); + if (!str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES)) { + mail_storage_set_error(storage, MAIL_ERROR_NOTFOUND, + "Nonexistent sieve attribute"); + return -1; + } + scriptname = key + strlen(MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES); + + if (value->value != NULL) { + input = i_stream_create_from_data(value->value, + strlen(value->value)); + save_ctx = sieve_storage_save_init(svstorage, scriptname, input); + } else if (value->value_stream != NULL) { + input = value->value_stream; + i_stream_ref(input); + save_ctx = sieve_storage_save_init(svstorage, scriptname, input); + } else { + return sieve_attribute_unset_script(storage, svstorage, scriptname); + } + + if (save_ctx == NULL) { + /* save initialization failed */ + mail_storage_set_critical(storage, + "Failed to save sieve script '%s': %s", scriptname, + sieve_storage_get_last_error(svstorage, NULL)); + i_stream_unref(&input); + return -1; + } + + if (value->last_change != 0) + sieve_storage_save_set_mtime(save_ctx, value->last_change); + + ret = 0; + while (input->stream_errno == 0 && + !i_stream_read_eof(input)) { + if (sieve_storage_save_continue(save_ctx) < 0) { + mail_storage_set_critical(storage, + "Failed to save sieve script '%s': %s", scriptname, + sieve_storage_get_last_error(svstorage, NULL)); + ret = -1; + break; + } + } + if (input->stream_errno != 0) { + errno = input->stream_errno; + mail_storage_set_critical(storage, + "Saving sieve script: read(%s) failed: %m", + i_stream_get_name(input)); + ret = -1; + } + i_assert(input->eof || ret < 0); + if (ret == 0 && sieve_storage_save_finish(save_ctx) < 0) { + mail_storage_set_critical(storage, + "Failed to save sieve script '%s': %s", scriptname, + sieve_storage_get_last_error(svstorage, NULL)); + ret = -1; + } + if (ret < 0) + sieve_storage_save_cancel(&save_ctx); + else if (sieve_storage_save_commit(&save_ctx) < 0) { + mail_storage_set_critical(storage, + "Failed to save sieve script '%s': %s", scriptname, + sieve_storage_get_last_error(svstorage, NULL)); + ret = -1; + } + i_stream_unref(&input); + return ret; +} + +static int +sieve_attribute_set(struct mailbox_transaction_context *t, + enum mail_attribute_type type, const char *key, + const struct mail_attribute_value *value) +{ + struct mail_user *user = t->box->storage->user; + union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(t->box); + + if (t->box->storage->user->dsyncing && + type == MAIL_ATTRIBUTE_TYPE_PRIVATE && + str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_SIEVE)) { + time_t ts = + (value->last_change != 0 ? value->last_change : ioloop_time); + + if (sieve_attribute_set_sieve(t->box->storage, key, value) < 0) + return -1; + + if (user->mail_debug) { + const char *change; + if (value->last_change != 0) { + change = t_strflocaltime + ("(last change: %Y-%m-%d %H:%M:%S)", value->last_change); + } else { + change = t_strflocaltime + ("(time: %Y-%m-%d %H:%M:%S)", ioloop_time); + } + i_debug("doveadm-sieve: Assigned value for key `%s' %s", + key, change); + } + + /* FIXME: set value len to sieve script size / active name + length */ + if (value->value != NULL || value->value_stream != NULL) + mail_index_attribute_set(t->itrans, TRUE, key, ts, 0); + else + mail_index_attribute_unset(t->itrans, TRUE, key, ts); + return 0; + } + return sbox->super.attribute_set(t, type, key, value); +} + +static int +sieve_attribute_retrieve_script(struct mail_storage *storage, + struct sieve_storage *svstorage, struct sieve_script *script, + bool add_type_prefix, + struct mail_attribute_value *value_r, const char **errorstr_r) +{ + static char type = MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_SCRIPT; + struct istream *input, *inputs[3]; + const struct stat *st; + enum sieve_error error; + + if (script == NULL) + *errorstr_r = sieve_storage_get_last_error(svstorage, &error); + else if (sieve_script_get_stream(script, &input, &error) < 0) + sieve_script_unref(&script); + + if (script == NULL) { + if (error == SIEVE_ERROR_NOT_FOUND) { + /* already deleted, but return the last_change */ + (void)sieve_storage_get_last_change(svstorage, + &value_r->last_change); + return 0; + } + *errorstr_r = sieve_storage_get_last_error(svstorage, &error); + return -1; + } + if (i_stream_stat(input, FALSE, &st) < 0) { + mail_storage_set_critical(storage, + "stat(%s) failed: %m", i_stream_get_name(input)); + } else { + value_r->last_change = st->st_mtime; + } + if (!add_type_prefix) { + i_stream_ref(input); + value_r->value_stream = input; + } else { + inputs[0] = i_stream_create_from_data(&type, 1); + inputs[1] = input; + inputs[2] = NULL; + value_r->value_stream = i_stream_create_concat(inputs); + i_stream_unref(&inputs[0]); + } + sieve_script_unref(&script); + return 1; +} + +static int +sieve_attribute_get_active_script(struct mail_storage *storage, + struct sieve_storage *svstorage, + struct mail_attribute_value *value_r) +{ + struct sieve_script *script; + const char *errstr; + int ret; + + if ((ret=sieve_storage_is_singular(svstorage)) <= 0) { + if (ret == 0 && sieve_storage_active_script_get_last_change + (svstorage, &value_r->last_change) < 0) { + ret = -1; + } + if (ret < 0) + mail_storage_set_internal_error(storage); + return ret; + } + + if ((script=sieve_storage_active_script_open + (svstorage, NULL)) == NULL) + return 0; + + if ((ret=sieve_attribute_retrieve_script + (storage, svstorage, script, TRUE, value_r, &errstr)) < 0) { + mail_storage_set_critical(storage, + "Failed to access active sieve script: %s", errstr); + } + return ret; +} + +static int +sieve_attribute_get_default(struct mail_storage *storage, + struct sieve_storage *svstorage, + struct mail_attribute_value *value_r) +{ + const char *scriptname; + int ret; + + ret = sieve_storage_active_script_get_name(svstorage, &scriptname); + if (ret == 0) + return sieve_attribute_get_active_script(storage, svstorage, value_r); + + if (ret > 0) { + value_r->value = t_strdup_printf("%c%s", + MAILBOX_ATTRIBUTE_SIEVE_DEFAULT_LINK, scriptname); + if (sieve_storage_active_script_get_last_change + (svstorage, &value_r->last_change) < 0) + ret = -1; + } + if (ret < 0) + mail_storage_set_internal_error(storage); + return ret; +} + +static int +sieve_attribute_get_sieve(struct mail_storage *storage, const char *key, + struct mail_attribute_value *value_r) +{ + struct sieve_storage *svstorage; + struct sieve_script *script; + const char *scriptname, *errstr; + int ret; + + if ((ret = mail_sieve_user_init(storage->user, &svstorage)) <= 0) + return ret; + + if (strcmp(key, MAILBOX_ATTRIBUTE_SIEVE_DEFAULT) == 0) + return sieve_attribute_get_default(storage, svstorage, value_r); + if (!str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES)) + return 0; + if ((value_r->flags & MAIL_ATTRIBUTE_VALUE_FLAG_INT_STREAMS) == 0) { + mail_storage_set_error(storage, MAIL_ERROR_PARAMS, + "Sieve attributes are available only as streams"); + return -1; + } + scriptname = key + strlen(MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES); + script = sieve_storage_open_script(svstorage, scriptname, NULL); + if ((ret=sieve_attribute_retrieve_script + (storage, svstorage, script, FALSE, value_r, &errstr)) < 0) { + mail_storage_set_critical(storage, + "Failed to access sieve script '%s': %s", + scriptname, errstr); + } + return ret; +} + +static int +sieve_attribute_get(struct mailbox *box, + enum mail_attribute_type type, const char *key, + struct mail_attribute_value *value_r) +{ + union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(box); + struct mail_user *user = box->storage->user; + int ret; + + if (box->storage->user->dsyncing && + type == MAIL_ATTRIBUTE_TYPE_PRIVATE && + str_begins(key, MAILBOX_ATTRIBUTE_PREFIX_SIEVE)) { + + ret = sieve_attribute_get_sieve(box->storage, key, value_r); + if (ret >= 0 && user->mail_debug) { + struct tm *tm = localtime(&value_r->last_change); + char str[256]; + const char *timestamp = ""; + + if (strftime(str, sizeof(str), + " (last change: %Y-%m-%d %H:%M:%S)", tm) > 0) + timestamp = str; + + if (ret > 0) { + i_debug("doveadm-sieve: Retrieved value for key `%s'%s", + key, timestamp); + } else { + i_debug("doveadm-sieve: Value missing for key `%s'%s", + key, timestamp); + } + } + return ret; + } + return sbox->super.attribute_get(box, type, key, value_r); +} + +static int +sieve_attribute_iter_script_init(struct sieve_mailbox_attribute_iter *siter) +{ + struct mail_user *user = siter->iter.box->storage->user; + struct sieve_storage *svstorage; + int ret; + + if (user->mail_debug) + i_debug("doveadm-sieve: Iterating Sieve mailbox attributes"); + + if ((ret = mail_sieve_user_init(user, &svstorage)) <= 0) + return ret; + + siter->sieve_list = sieve_storage_list_init(svstorage); + if (siter->sieve_list == NULL) { + mail_storage_set_critical(siter->iter.box->storage, + "Failed to iterate sieve scripts: %s", + sieve_storage_get_last_error(svstorage, NULL)); + return -1; + } + siter->name = str_new(default_pool, 128); + str_append(siter->name, MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES); + return 0; +} + +static struct mailbox_attribute_iter * +sieve_attribute_iter_init(struct mailbox *box, enum mail_attribute_type type, + const char *prefix) +{ + union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(box); + struct sieve_mailbox_attribute_iter *siter; + + siter = i_new(struct sieve_mailbox_attribute_iter, 1); + siter->iter.box = box; + siter->super = sbox->super.attribute_iter_init(box, type, prefix); + + if (box->storage->user->dsyncing && + type == MAIL_ATTRIBUTE_TYPE_PRIVATE) { + if (sieve_attribute_iter_script_init(siter) < 0) + siter->failed = TRUE; + } + return &siter->iter; +} + +static const char * +sieve_attribute_iter_next_script(struct sieve_mailbox_attribute_iter *siter) +{ + struct mail_user *user = siter->iter.box->storage->user; + struct sieve_mail_user *suser = SIEVE_USER_CONTEXT(user); + struct sieve_storage *svstorage = suser->sieve_storage; + const char *scriptname; + bool active; + int ret; + + if (siter->sieve_list == NULL) + return NULL; + + /* Iterate through all scripts in sieve_dir */ + while ((scriptname = sieve_storage_list_next(siter->sieve_list, &active)) + != NULL) { + if (active) + siter->have_active = TRUE; + str_truncate(siter->name, strlen(MAILBOX_ATTRIBUTE_PREFIX_SIEVE_FILES)); + str_append(siter->name, scriptname); + return str_c(siter->name); + } + if (sieve_storage_list_deinit(&siter->sieve_list) < 0) { + mail_storage_set_critical(siter->iter.box->storage, + "Failed to iterate sieve scripts: %s", + sieve_storage_get_last_error(svstorage, NULL)); + siter->failed = TRUE; + return NULL; + } + + /* Check whether active script is a proper symlink or a regular file */ + if ((ret=sieve_storage_is_singular(svstorage)) < 0) { + mail_storage_set_critical(siter->iter.box->storage, + "Failed to iterate sieve scripts: %s", + sieve_storage_get_last_error(svstorage, NULL)); + return NULL; + } + + /* Regular file */ + if (ret > 0) + return MAILBOX_ATTRIBUTE_SIEVE_DEFAULT; + + /* Symlink or none active */ + return siter->have_active ? MAILBOX_ATTRIBUTE_SIEVE_DEFAULT : NULL; +} + +static const char * +sieve_attribute_iter_next(struct mailbox_attribute_iter *iter) +{ + struct sieve_mailbox_attribute_iter *siter = + (struct sieve_mailbox_attribute_iter *)iter; + union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(iter->box); + struct mail_user *user = iter->box->storage->user; + const char *key; + + if (siter->sieve_list != NULL) { + if ((key = sieve_attribute_iter_next_script(siter)) != NULL) { + if (user->mail_debug) { + i_debug("doveadm-sieve: Iterating Sieve mailbox attribute: %s", key); + } + return key; + } + } + return sbox->super.attribute_iter_next(siter->super); +} + +static int +sieve_attribute_iter_deinit(struct mailbox_attribute_iter *iter) +{ + struct sieve_mailbox_attribute_iter *siter = + (struct sieve_mailbox_attribute_iter *)iter; + union mailbox_module_context *sbox = SIEVE_MAIL_CONTEXT(iter->box); + int ret = siter->failed ? -1 : 0; + + if (siter->super != NULL) { + if (sbox->super.attribute_iter_deinit(siter->super) < 0) + ret = -1; + } + if (siter->sieve_list != NULL) + (void)sieve_storage_list_deinit(&siter->sieve_list); + if (siter->name != NULL) + str_free(&siter->name); + i_free(siter); + return ret; +} + +static void +sieve_mail_user_created(struct mail_user *user) +{ + struct sieve_mail_user *suser; + struct mail_user_vfuncs *v = user->vlast; + + suser = p_new(user->pool, struct sieve_mail_user, 1); + suser->module_ctx.super = *v; + user->vlast = &suser->module_ctx.super; + v->deinit = mail_sieve_user_deinit; + MODULE_CONTEXT_SET(user, sieve_user_module, suser); +} + +static void +sieve_mailbox_allocated(struct mailbox *box) +{ + struct mailbox_vfuncs *v = box->vlast; + union mailbox_module_context *sbox; + + /* attribute syncing is done via INBOX */ + if (!box->inbox_user) + return; + + sbox = p_new(box->pool, union mailbox_module_context, 1); + sbox->super = *v; + box->vlast = &sbox->super; + v->attribute_set = sieve_attribute_set; + v->attribute_get = sieve_attribute_get; + v->attribute_iter_init = sieve_attribute_iter_init; + v->attribute_iter_next = sieve_attribute_iter_next; + v->attribute_iter_deinit = sieve_attribute_iter_deinit; + MODULE_CONTEXT_SET_SELF(box, sieve_storage_module, sbox); +} + +static struct mail_storage_hooks doveadm_sieve_mail_storage_hooks = { + .mail_user_created = sieve_mail_user_created, + .mailbox_allocated = sieve_mailbox_allocated +}; + +void doveadm_sieve_sync_init(struct module *module) +{ + mail_storage_hooks_add_forced + (module, &doveadm_sieve_mail_storage_hooks); +} diff --git a/pigeonhole/src/plugins/imap-filter-sieve/Makefile.am b/pigeonhole/src/plugins/imap-filter-sieve/Makefile.am new file mode 100644 index 0000000..915e128 --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/Makefile.am @@ -0,0 +1,26 @@ +imap_moduledir = $(dovecot_moduledir) + +imap_module_LTLIBRARIES = lib95_imap_filter_sieve_plugin.la + +lib95_imap_filter_sieve_plugin_la_LDFLAGS = -module -avoid-version + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + $(LIBDOVECOT_IMAP_INCLUDE) \ + $(LIBDOVECOT_LDA_INCLUDE) \ + $(LIBDOVECOT_INCLUDE) \ + -DPKG_RUNDIR=\""$(rundir)"\" + +lib95_imap_filter_sieve_plugin_la_SOURCES = \ + cmd-filter.c \ + cmd-filter-sieve.c \ + imap-filter.c \ + imap-filter-sieve.c \ + imap-filter-sieve-plugin.c +lib95_imap_filter_sieve_plugin_la_LIBADD = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la + +noinst_HEADERS = \ + imap-filter.h \ + imap-filter-sieve.h \ + imap-filter-sieve-plugin.h diff --git a/pigeonhole/src/plugins/imap-filter-sieve/Makefile.in b/pigeonhole/src/plugins/imap-filter-sieve/Makefile.in new file mode 100644 index 0000000..b74a15b --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/Makefile.in @@ -0,0 +1,771 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 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/plugins/imap-filter-sieve +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 = +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)$(imap_moduledir)" +LTLIBRARIES = $(imap_module_LTLIBRARIES) +lib95_imap_filter_sieve_plugin_la_DEPENDENCIES = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la +am_lib95_imap_filter_sieve_plugin_la_OBJECTS = cmd-filter.lo \ + cmd-filter-sieve.lo imap-filter.lo imap-filter-sieve.lo \ + imap-filter-sieve-plugin.lo +lib95_imap_filter_sieve_plugin_la_OBJECTS = \ + $(am_lib95_imap_filter_sieve_plugin_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +lib95_imap_filter_sieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(lib95_imap_filter_sieve_plugin_la_LDFLAGS) $(LDFLAGS) -o $@ +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-filter-sieve.Plo \ + ./$(DEPDIR)/cmd-filter.Plo \ + ./$(DEPDIR)/imap-filter-sieve-plugin.Plo \ + ./$(DEPDIR)/imap-filter-sieve.Plo ./$(DEPDIR)/imap-filter.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 = $(lib95_imap_filter_sieve_plugin_la_SOURCES) +DIST_SOURCES = $(lib95_imap_filter_sieve_plugin_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@ +imap_moduledir = $(dovecot_moduledir) +imap_module_LTLIBRARIES = lib95_imap_filter_sieve_plugin.la +lib95_imap_filter_sieve_plugin_la_LDFLAGS = -module -avoid-version +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + $(LIBDOVECOT_IMAP_INCLUDE) \ + $(LIBDOVECOT_LDA_INCLUDE) \ + $(LIBDOVECOT_INCLUDE) \ + -DPKG_RUNDIR=\""$(rundir)"\" + +lib95_imap_filter_sieve_plugin_la_SOURCES = \ + cmd-filter.c \ + cmd-filter-sieve.c \ + imap-filter.c \ + imap-filter-sieve.c \ + imap-filter-sieve-plugin.c + +lib95_imap_filter_sieve_plugin_la_LIBADD = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la + +noinst_HEADERS = \ + imap-filter.h \ + imap-filter-sieve.h \ + imap-filter-sieve-plugin.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/plugins/imap-filter-sieve/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/imap-filter-sieve/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-imap_moduleLTLIBRARIES: $(imap_module_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(imap_module_LTLIBRARIES)'; test -n "$(imap_moduledir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(imap_moduledir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(imap_moduledir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imap_moduledir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imap_moduledir)"; \ + } + +uninstall-imap_moduleLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(imap_module_LTLIBRARIES)'; test -n "$(imap_moduledir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imap_moduledir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imap_moduledir)/$$f"; \ + done + +clean-imap_moduleLTLIBRARIES: + -test -z "$(imap_module_LTLIBRARIES)" || rm -f $(imap_module_LTLIBRARIES) + @list='$(imap_module_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +lib95_imap_filter_sieve_plugin.la: $(lib95_imap_filter_sieve_plugin_la_OBJECTS) $(lib95_imap_filter_sieve_plugin_la_DEPENDENCIES) $(EXTRA_lib95_imap_filter_sieve_plugin_la_DEPENDENCIES) + $(AM_V_CCLD)$(lib95_imap_filter_sieve_plugin_la_LINK) -rpath $(imap_moduledir) $(lib95_imap_filter_sieve_plugin_la_OBJECTS) $(lib95_imap_filter_sieve_plugin_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-filter-sieve.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-filter.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-filter-sieve-plugin.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-filter-sieve.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-filter.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: + for dir in "$(DESTDIR)$(imap_moduledir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-imap_moduleLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/cmd-filter-sieve.Plo + -rm -f ./$(DEPDIR)/cmd-filter.Plo + -rm -f ./$(DEPDIR)/imap-filter-sieve-plugin.Plo + -rm -f ./$(DEPDIR)/imap-filter-sieve.Plo + -rm -f ./$(DEPDIR)/imap-filter.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-imap_moduleLTLIBRARIES + +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)/cmd-filter-sieve.Plo + -rm -f ./$(DEPDIR)/cmd-filter.Plo + -rm -f ./$(DEPDIR)/imap-filter-sieve-plugin.Plo + -rm -f ./$(DEPDIR)/imap-filter-sieve.Plo + -rm -f ./$(DEPDIR)/imap-filter.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-imap_moduleLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-imap_moduleLTLIBRARIES clean-libtool \ + 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-imap_moduleLTLIBRARIES 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 uninstall-imap_moduleLTLIBRARIES + +.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/plugins/imap-filter-sieve/cmd-filter-sieve.c b/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c new file mode 100644 index 0000000..6b96bd3 --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter-sieve.c @@ -0,0 +1,403 @@ +/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */ + +#include "imap-common.h" +#include "str.h" +#include "istream.h" +#include "istream-seekable.h" +#include "ostream.h" +#include "imap-commands.h" + +#include "imap-filter.h" +#include "imap-filter-sieve.h" + +#define FILTER_MAX_INMEM_SIZE (1024*128) + +static int cmd_filter_sieve_compile_script(struct imap_filter_context *ctx) +{ + struct client_command_context *cmd = ctx->cmd; + struct imap_filter_sieve_context *sctx = ctx->sieve; + struct client *client = cmd->client; + string_t *errors = NULL; + bool have_warnings = FALSE; + int ret = 0; + + ret = imap_filter_sieve_compile(sctx, &errors, &have_warnings); + if (ret >= 0 && !have_warnings) + return 0; + + o_stream_nsend_str(client->output, + t_strdup_printf("* FILTER (TAG %s) " + "%s {%zu}\r\n", + cmd->tag, (ret < 0 ? "ERRORS" : "WARNINGS"), + str_len(errors))); + o_stream_nsend(client->output, + str_data(errors), str_len(errors)); + o_stream_nsend_str(client->output, "\r\n"); + + if (ret < 0) { + ctx->compile_failure = TRUE; + ctx->failed = TRUE; + return -1; + } + return 0; +} + +static bool cmd_filter_sieve_delivery(struct client_command_context *cmd) +{ + struct imap_filter_context *ctx = cmd->context; + struct client *client = cmd->client; + struct imap_filter_sieve_context *sctx = ctx->sieve; + enum mail_error error; + const char *error_string; + int ret; + + if (cmd->cancel) { + imap_filter_deinit(ctx); + return TRUE; + } + + i_assert(sctx->filter_type == IMAP_FILTER_SIEVE_TYPE_DELIVERY); + ret = imap_filter_sieve_open_personal(sctx, NULL, + &error, &error_string); + if (ret < 0) { + client_send_tagline( + cmd, imap_get_error_string(cmd, error_string, error)); + imap_filter_deinit(ctx); + return TRUE; + } + if (cmd_filter_sieve_compile_script(ctx) < 0) { + client_send_tagline(cmd, "NO Failed to compile Sieve script"); + client->input_skip_line = TRUE; + imap_filter_deinit(ctx); + return TRUE; + } + + imap_parser_reset(ctx->parser); + cmd->func = imap_filter_search; + return imap_filter_search(cmd); +} + +static int +cmd_filter_sieve_script_parse_name_arg(struct imap_filter_context *ctx) +{ + struct client_command_context *cmd = ctx->cmd; + const struct imap_arg *args; + const char *error; + enum imap_parser_error parse_error; + int ret; + + ret = imap_parser_read_args(ctx->parser, 1, 0, &args); + if (ret < 0) { + if (ret == -2) + return 0; + error = imap_parser_get_error(ctx->parser, &parse_error); + switch (parse_error) { + case IMAP_PARSE_ERROR_NONE: + i_unreached(); + case IMAP_PARSE_ERROR_LITERAL_TOO_BIG: + client_disconnect_with_error(ctx->cmd->client, error); + break; + default: + client_send_command_error(ctx->cmd, error); + break; + } + return -1; + } + + switch (args[0].type) { + case IMAP_ARG_EOL: + client_send_command_error(ctx->cmd, "Script name missing"); + return -1; + case IMAP_ARG_NIL: + case IMAP_ARG_LIST: + client_send_command_error( + ctx->cmd, "Script name must be an atom or a string"); + return -1; + case IMAP_ARG_ATOM: + case IMAP_ARG_STRING: + /* We have the value already */ + if (ctx->failed) + return 1; + ctx->script_name = p_strdup(cmd->pool, + imap_arg_as_astring(&args[0])); + break; + case IMAP_ARG_LITERAL: + case IMAP_ARG_LITERAL_SIZE: + case IMAP_ARG_LITERAL_SIZE_NONSYNC: + i_unreached(); + } + return 1; +} + +static bool +cmd_filter_sieve_script_parse_name(struct client_command_context *cmd) +{ + struct imap_filter_context *ctx = cmd->context; + struct client *client = cmd->client; + struct imap_filter_sieve_context *sctx = ctx->sieve; + enum mail_error error; + const char *error_string; + int ret; + + if (cmd->cancel) { + imap_filter_deinit(ctx); + return TRUE; + } + + if ((ret = cmd_filter_sieve_script_parse_name_arg(ctx)) == 0) + return FALSE; + if (ret < 0) { + /* Already sent the error to client */ + imap_filter_deinit(ctx); + return TRUE; + } + + switch (sctx->filter_type) { + case IMAP_FILTER_SIEVE_TYPE_PERSONAL: + ret = imap_filter_sieve_open_personal(sctx, ctx->script_name, + &error, &error_string); + break; + case IMAP_FILTER_SIEVE_TYPE_GLOBAL: + ret = imap_filter_sieve_open_global(sctx, ctx->script_name, + &error, &error_string); + break; + case IMAP_FILTER_SIEVE_TYPE_DELIVERY: + case IMAP_FILTER_SIEVE_TYPE_SCRIPT: + i_unreached(); + } + if (ret < 0) { + client_send_tagline( + cmd, imap_get_error_string(cmd, error_string, error)); + imap_filter_deinit(ctx); + return TRUE; + } + if (cmd_filter_sieve_compile_script(ctx) < 0) { + client_send_tagline(cmd, "NO Failed to compile Sieve script"); + client->input_skip_line = TRUE; + imap_filter_deinit(ctx); + return TRUE; + } + + imap_parser_reset(ctx->parser); + cmd->func = imap_filter_search; + return imap_filter_search(cmd); +} + +static void +cmd_filter_sieve_compile_input(struct imap_filter_context *ctx, + struct istream *input) +{ + struct imap_filter_sieve_context *sctx = ctx->sieve; + + imap_filter_sieve_open_input(sctx, input); + (void)cmd_filter_sieve_compile_script(ctx); +} + +static int cmd_filter_sieve_script_read_stream(struct imap_filter_context *ctx) +{ + struct istream *input = ctx->script_input; + const unsigned char *data; + size_t size; + int ret; + + while ((ret = i_stream_read_more(input, &data, &size)) > 0) + i_stream_skip(input, size); + if (ret == 0) + return 0; + + if (input->v_offset != ctx->script_len) { + /* Client disconnected */ + i_assert(input->eof); + return -1; + } + /* Finished reading the value */ + i_stream_seek(input, 0); + + if (ctx->failed) { + i_stream_unref(&ctx->script_input); + return 1; + } + + cmd_filter_sieve_compile_input(ctx, ctx->script_input); + i_stream_unref(&ctx->script_input); + return 1; +} + +static int +cmd_filter_sieve_script_parse_value_arg(struct imap_filter_context *ctx) +{ + const struct imap_arg *args; + const char *value, *error; + enum imap_parser_error parse_error; + struct istream *input, *inputs[2]; + string_t *path; + int ret; + + ret = imap_parser_read_args(ctx->parser, 1, + IMAP_PARSE_FLAG_LITERAL_SIZE | + IMAP_PARSE_FLAG_LITERAL8, &args); + if (ret < 0) { + if (ret == -2) + return 0; + error = imap_parser_get_error(ctx->parser, &parse_error); + switch (parse_error) { + case IMAP_PARSE_ERROR_NONE: + i_unreached(); + case IMAP_PARSE_ERROR_LITERAL_TOO_BIG: + client_disconnect_with_error(ctx->cmd->client, error); + break; + default: + client_send_command_error(ctx->cmd, error); + break; + } + return -1; + } + + switch (args[0].type) { + case IMAP_ARG_EOL: + client_send_command_error(ctx->cmd, "Script value missing"); + return -1; + case IMAP_ARG_NIL: + case IMAP_ARG_ATOM: + case IMAP_ARG_LIST: + client_send_command_error(ctx->cmd, + "Script value must be a string"); + return -1; + case IMAP_ARG_STRING: + /* We have the value already */ + if (ctx->failed) + return 1; + value = imap_arg_as_astring(&args[0]); + input = i_stream_create_from_data(value, strlen(value)); + cmd_filter_sieve_compile_input(ctx, input); + i_stream_unref(&input); + return 1; + case IMAP_ARG_LITERAL_SIZE: + o_stream_nsend(ctx->cmd->client->output, "+ OK\r\n", 6); + o_stream_uncork(ctx->cmd->client->output); + o_stream_cork(ctx->cmd->client->output); + /* Fall through */ + case IMAP_ARG_LITERAL_SIZE_NONSYNC: + ctx->script_len = imap_arg_as_literal_size(&args[0]); + + inputs[0] = i_stream_create_limit(ctx->cmd->client->input, + ctx->script_len); + inputs[1] = NULL; + + path = t_str_new(128); + mail_user_set_get_temp_prefix(path, + ctx->cmd->client->user->set); + ctx->script_input = i_stream_create_seekable_path( + inputs, FILTER_MAX_INMEM_SIZE, str_c(path)); + i_stream_set_name(ctx->script_input, + i_stream_get_name(inputs[0])); + i_stream_unref(&inputs[0]); + break; + case IMAP_ARG_LITERAL: + i_unreached(); + } + return cmd_filter_sieve_script_read_stream(ctx); +} + +static bool +cmd_filter_sieve_script_parse_value(struct client_command_context *cmd) +{ + struct imap_filter_context *ctx = cmd->context; + struct client *client = cmd->client; + int ret; + + if (cmd->cancel) { + imap_filter_deinit(ctx); + return TRUE; + } + + if (ctx->script_input != NULL) { + if ((ret = cmd_filter_sieve_script_read_stream(ctx)) == 0) + return FALSE; + } else { + if ((ret = cmd_filter_sieve_script_parse_value_arg(ctx)) == 0) + return FALSE; + } + + if (ret < 0) { + /* Already sent the error to client */ ; + imap_filter_deinit(ctx); + return TRUE; + } else if (ctx->compile_failure) { + client_send_tagline(cmd, "NO Failed to compile Sieve script"); + client->input_skip_line = TRUE; + imap_filter_deinit(ctx); + return TRUE; + } + + imap_parser_reset(ctx->parser); + cmd->func = imap_filter_search; + return imap_filter_search(cmd); +} + +bool cmd_filter_sieve(struct client_command_context *cmd) +{ + struct imap_filter_context *ctx = cmd->context; + struct client *client = cmd->client; + enum imap_filter_sieve_type type; + const struct imap_arg *args; + const char *sieve_type; + + if (!client_read_args(cmd, 2, 0, &args)) + return FALSE; + args++; + + /* sieve-type */ + if (IMAP_ARG_IS_EOL(args)) { + client_send_command_error( + cmd, "Missing SIEVE filter sub-type."); + return TRUE; + } + if (!imap_arg_get_atom(args, &sieve_type)) { + client_send_command_error( + cmd, "SIEVE filter sub-type is not an atom."); + return TRUE; + } + if (strcasecmp(sieve_type, "DELIVERY") == 0) { + type = IMAP_FILTER_SIEVE_TYPE_DELIVERY; + } else if (strcasecmp(sieve_type, "PERSONAL") == 0) { + type = IMAP_FILTER_SIEVE_TYPE_PERSONAL; + } else if (strcasecmp(sieve_type, "GLOBAL") == 0) { + type = IMAP_FILTER_SIEVE_TYPE_GLOBAL; + } else if (strcasecmp(sieve_type, "SCRIPT") == 0) { + type = IMAP_FILTER_SIEVE_TYPE_SCRIPT; + } else { + client_send_command_error(cmd, t_strdup_printf( + "Unknown SIEVE filter sub-type `%s'", + sieve_type)); + return TRUE; + } + + ctx->sieve = imap_filter_sieve_context_create(ctx, type); + + /* We support large scripts, so read the values from client + asynchronously the same way as APPEND does. */ + client->input_lock = cmd; + ctx->parser = imap_parser_create(client->input, client->output, + client->set->imap_max_line_length); + if (client->set->imap_literal_minus) + imap_parser_enable_literal_minus(ctx->parser); + o_stream_unset_flush_callback(client->output); + + switch (type) { + case IMAP_FILTER_SIEVE_TYPE_DELIVERY: + cmd->func = cmd_filter_sieve_delivery; + break; + case IMAP_FILTER_SIEVE_TYPE_PERSONAL: + cmd->func = cmd_filter_sieve_script_parse_name; + break; + case IMAP_FILTER_SIEVE_TYPE_GLOBAL: + cmd->func = cmd_filter_sieve_script_parse_name; + break; + case IMAP_FILTER_SIEVE_TYPE_SCRIPT: + cmd->func = cmd_filter_sieve_script_parse_value; + break; + } + cmd->context = ctx; + return cmd->func(cmd); +} diff --git a/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter.c b/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter.c new file mode 100644 index 0000000..2458047 --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/cmd-filter.c @@ -0,0 +1,57 @@ +/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */ + +#include "imap-common.h" + +#include "imap-filter.h" +#include "imap-filter-sieve.h" + +static bool +cmd_filter_parse_spec(struct imap_filter_context *ctx, + const struct imap_arg **_args) +{ + const struct imap_arg *args = *_args; + struct client_command_context *cmd = ctx->cmd; + const char *filter_type; + + /* filter-type */ + if (IMAP_ARG_IS_EOL(args)) { + client_send_command_error(cmd, + "Missing filter type."); + return TRUE; + } + if (!imap_arg_get_atom(args, &filter_type)) { + client_send_command_error(cmd, + "Filter type is not an atom."); + return TRUE; + } + if (strcasecmp(filter_type, "SIEVE") != 0) { + client_send_command_error(cmd, t_strdup_printf( + "Unknown filter type `%s'", filter_type)); + return TRUE; + } + + cmd->func = cmd_filter_sieve; + cmd->context = ctx; + return cmd_filter_sieve(cmd); +} + +bool cmd_filter(struct client_command_context *cmd) +{ + struct imap_filter_context *ctx; + const struct imap_arg *args; + + if (!client_read_args(cmd, 1, 0, &args)) + return FALSE; + + if (!client_verify_open_mailbox(cmd)) + return TRUE; + + ctx = p_new(cmd->pool, struct imap_filter_context, 1); + ctx->cmd = cmd; + + if (!cmd_filter_parse_spec(ctx, &args)) + return FALSE; + + imap_filter_context_free(ctx); + return TRUE; +} diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c new file mode 100644 index 0000000..3021dbe --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.c @@ -0,0 +1,56 @@ +/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */ + +#include "imap-common.h" +#include "str.h" + +#include "imap-filter-sieve.h" +#include "imap-filter-sieve-plugin.h" + +static struct module *imap_filter_sieve_module; +static imap_client_created_func_t *next_hook_client_created; + +/* + * Client + */ + +static void imap_filter_sieve_plugin_client_created(struct client **clientp) +{ + struct client *client = *clientp; + struct mail_user *user = client->user; + + if (mail_user_is_plugin_loaded(user, imap_filter_sieve_module)) { + client_add_capability(client, "FILTER=SIEVE"); + + imap_filter_sieve_client_created(client); + } + + if (next_hook_client_created != NULL) + next_hook_client_created(clientp); +} + +/* + * Plugin + */ + +const char *imap_filter_sieve_plugin_version = DOVECOT_ABI_VERSION; +const char imap_filter_sieve_plugin_binary_dependency[] = "imap"; + +void imap_filter_sieve_plugin_init(struct module *module) +{ + command_register("FILTER", cmd_filter, COMMAND_FLAG_USES_SEQS); + command_register("UID FILTER", cmd_filter, COMMAND_FLAG_BREAKS_SEQS); + + imap_filter_sieve_module = module; + next_hook_client_created = imap_client_created_hook_set( + imap_filter_sieve_plugin_client_created); + imap_filter_sieve_init(module); +} + +void imap_filter_sieve_plugin_deinit(void) +{ + command_unregister("FILTER"); + command_unregister("UID FILTER"); + + imap_filter_sieve_deinit(); + imap_client_created_hook_set(next_hook_client_created); +} diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.h b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.h new file mode 100644 index 0000000..59b4b11 --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve-plugin.h @@ -0,0 +1,16 @@ +/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file + */ + +#ifndef IMAP_FILTER_SIEVE_PLUGIN_H +#define IMAP_FILTER_SIEVE_PLUGIN_H + +struct module; + +extern const char imap_filter_sieve_plugin_binary_dependency[]; + +bool cmd_filter(struct client_command_context *cmd); + +void imap_filter_sieve_plugin_init(struct module *module); +void imap_filter_sieve_plugin_deinit(void); + +#endif diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.c b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.c new file mode 100644 index 0000000..62519f4 --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.c @@ -0,0 +1,1188 @@ +/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */ + +#include "imap-common.h" +#include "str.h" +#include "ioloop.h" +#include "time-util.h" +#include "module-context.h" +#include "message-address.h" +#include "mail-user.h" +#include "mail-duplicate.h" +#include "mail-storage-private.h" +#include "iostream-ssl.h" +#include "smtp-submit.h" +#include "sieve.h" +#include "sieve-storage.h" +#include "sieve-script.h" + +#include "imap-filter-sieve.h" + +#define DUPLICATE_DB_NAME "lda-dupes" + +#define IMAP_FILTER_SIEVE_USER_CONTEXT(obj) \ + MODULE_CONTEXT(obj, imap_filter_sieve_user_module) +#define IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(obj) \ + MODULE_CONTEXT_REQUIRE(obj, imap_filter_sieve_user_module) + +struct imap_filter_sieve_script { + struct sieve_script *script; + struct sieve_binary *binary; + + /* Compile failed once with this error; + don't try again for this transaction */ + enum sieve_error compile_error; + + /* Binary corrupt after recompile; don't recompile again */ + bool binary_corrupt:1; + /* Resource usage exceeded */ + bool rusage_exceeded:1; +}; + +struct imap_filter_sieve_user { + union mail_user_module_context module_ctx; + struct client *client; + + struct sieve_instance *svinst; + struct sieve_storage *storage; + struct sieve_storage *global_storage; + + struct mail_duplicate_db *dup_db; + + struct sieve_error_handler *master_ehandler; +}; + +static MODULE_CONTEXT_DEFINE_INIT(imap_filter_sieve_user_module, + &mail_user_module_register); + +/* + * + */ + +static const char * +imap_filter_sieve_get_setting(void *context, const char *identifier) +{ + struct imap_filter_sieve_user *ifsuser = context; + struct mail_user *user = ifsuser->client->user; + + return mail_user_plugin_getenv(user, identifier); +} + +static const struct sieve_callbacks imap_filter_sieve_callbacks = { + NULL, + imap_filter_sieve_get_setting +}; + +static struct sieve_instance * +imap_filter_sieve_get_svinst(struct imap_filter_sieve_context *sctx) +{ + struct mail_user *user = sctx->user; + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user); + struct sieve_environment svenv; + const struct mail_storage_settings *mail_set; + bool debug = user->mail_debug; + + if (ifsuser->svinst != NULL) + return ifsuser->svinst; + + mail_set = mail_user_set_get_storage_set(user); + + ifsuser->dup_db = mail_duplicate_db_init(user, DUPLICATE_DB_NAME); + + i_zero(&svenv); + svenv.username = user->username; + (void)mail_user_get_home(user, &svenv.home_dir); + svenv.hostname = mail_set->hostname; + svenv.base_dir = user->set->base_dir; + svenv.event_parent = ifsuser->client->event; + svenv.flags = SIEVE_FLAG_HOME_RELATIVE; + svenv.location = SIEVE_ENV_LOCATION_MS; + svenv.delivery_phase = SIEVE_DELIVERY_PHASE_POST; + + ifsuser->svinst = sieve_init(&svenv, &imap_filter_sieve_callbacks, + ifsuser, debug); + + ifsuser->master_ehandler = + sieve_master_ehandler_create(ifsuser->svinst, 0); + sieve_error_handler_accept_infolog(ifsuser->master_ehandler, TRUE); + sieve_error_handler_accept_debuglog(ifsuser->master_ehandler, debug); + + return ifsuser->svinst; +} + +static void +imap_filter_sieve_init_trace_log(struct imap_filter_sieve_context *sctx, + struct sieve_trace_config *trace_config_r, + struct sieve_trace_log **trace_log_r) +{ + struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx); + struct client_command_context *cmd = sctx->filter_context->cmd; + struct mail_user *user = sctx->user; + + if (sctx->trace_log_initialized) { + *trace_config_r = sctx->trace_config; + *trace_log_r = sctx->trace_log; + return; + } + sctx->trace_log_initialized = TRUE; + + if (sieve_trace_config_get(svinst, &sctx->trace_config) < 0 || + sieve_trace_log_open(svinst, &sctx->trace_log) < 0) { + i_zero(&sctx->trace_config); + sctx->trace_log = NULL; + + i_zero(trace_config_r); + *trace_log_r = NULL; + return; + } + + /* Write header for trace file */ + sieve_trace_log_printf(sctx->trace_log, + "Sieve trace log for IMAP FILTER=SIEVE:\n" + "\n" + " Username: %s\n", user->username); + if (user->session_id != NULL) { + sieve_trace_log_printf(sctx->trace_log, + " Session ID: %s\n", user->session_id); + } + sieve_trace_log_printf(sctx->trace_log, + " Mailbox: %s\n" + " Command: %s %s %s\n\n", + mailbox_get_vname(sctx->filter_context->box), + cmd->tag, cmd->name, + cmd->human_args != NULL ? cmd->human_args : ""); + + *trace_config_r = sctx->trace_config; + *trace_log_r = sctx->trace_log; +} + +static int +imap_filter_sieve_get_personal_storage(struct imap_filter_sieve_context *sctx, + struct sieve_storage **storage_r, + enum mail_error *error_code_r, + const char **error_r) +{ + struct mail_user *user = sctx->user; + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user); + enum sieve_storage_flags storage_flags = 0; + struct sieve_instance *svinst; + enum sieve_error error; + + *error_code_r = MAIL_ERROR_NONE; + *error_r = NULL; + + if (ifsuser->storage != NULL) { + *storage_r = ifsuser->storage; + return 0; + } + + // FIXME: limit interval between retries + + svinst = imap_filter_sieve_get_svinst(sctx); + ifsuser->storage = sieve_storage_create_main(svinst, user, + storage_flags, &error); + if (ifsuser->storage != NULL) { + *storage_r = ifsuser->storage; + return 0; + } + + switch (error) { + case SIEVE_ERROR_NOT_POSSIBLE: + *error_r = "Sieve processing is disabled for this user"; + *error_code_r = MAIL_ERROR_NOTPOSSIBLE; + break; + case SIEVE_ERROR_NOT_FOUND: + *error_r = "Sieve script storage not accessible"; + *error_code_r = MAIL_ERROR_NOTFOUND; + break; + default: + *error_r = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, + ioloop_time); + *error_code_r = MAIL_ERROR_TEMP; + break; + } + + return -1; +} + +static int +imap_filter_sieve_get_global_storage(struct imap_filter_sieve_context *sctx, + struct sieve_storage **storage_r, + enum mail_error *error_code_r, + const char **error_r) +{ + struct mail_user *user = sctx->user; + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user); + struct sieve_instance *svinst; + const char *location; + enum sieve_error error; + + *error_code_r = MAIL_ERROR_NONE; + *error_r = NULL; + + if (ifsuser->global_storage != NULL) { + *storage_r = ifsuser->global_storage; + return 0; + } + + svinst = imap_filter_sieve_get_svinst(sctx); + + location = mail_user_plugin_getenv(user, "sieve_global"); + if (location == NULL) { + e_info(sieve_get_event(svinst), + "include: sieve_global is unconfigured; " + "include of `:global' script is therefore not possible"); + *error_code_r = MAIL_ERROR_NOTFOUND; + *error_r = "No global Sieve scripts available"; + return -1; + } + ifsuser->global_storage = + sieve_storage_create(svinst, location, 0, &error); + if (ifsuser->global_storage != NULL) { + *storage_r = ifsuser->global_storage; + return 0; + } + + switch (error) { + case SIEVE_ERROR_NOT_POSSIBLE: + case SIEVE_ERROR_NOT_FOUND: + *error_r = "No global Sieve scripts available"; + *error_code_r = MAIL_ERROR_NOTFOUND; + break; + default: + *error_r = t_strflocaltime(MAIL_ERRSTR_CRITICAL_MSG_STAMP, + ioloop_time); + *error_code_r = MAIL_ERROR_TEMP; + break; + } + + return -1; +} + +/* + * + */ + +struct imap_filter_sieve_context * +imap_filter_sieve_context_create(struct imap_filter_context *ctx, + enum imap_filter_sieve_type type) +{ + struct client_command_context *cmd = ctx->cmd; + struct imap_filter_sieve_context *sctx; + + sctx = p_new(cmd->pool, struct imap_filter_sieve_context, 1); + sctx->pool = cmd->pool; + sctx->filter_context = ctx; + sctx->filter_type = type; + sctx->user = ctx->cmd->client->user; + + return sctx; +} + +void imap_filter_sieve_context_free(struct imap_filter_sieve_context **_sctx) +{ + struct imap_filter_sieve_context *sctx = *_sctx; + struct imap_filter_sieve_script *scripts; + unsigned int i; + + *_sctx = NULL; + + if (sctx == NULL) + return; + + scripts = sctx->scripts; + for (i = 0; i < sctx->scripts_count; i++) { + if (scripts[i].binary != NULL) + sieve_close(&scripts[i].binary); + if (scripts[i].script != NULL) + sieve_script_unref(&scripts[i].script); + } + + if (sctx->trace_log != NULL) + sieve_trace_log_free(&sctx->trace_log); + + str_free(&sctx->errors); +} + +/* + * Error handling + */ + +static struct sieve_error_handler * +imap_filter_sieve_create_error_handler(struct imap_filter_sieve_context *sctx) +{ + struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx); + + /* Prepare error handler */ + if (sctx->errors == NULL) + sctx->errors = str_new(default_pool, 1024); + else + str_truncate(sctx->errors, 0); + return sieve_strbuf_ehandler_create(svinst, sctx->errors, TRUE, + 10 /* client->set->_max_compile_errors */); +} + +/* + * + */ + +static struct sieve_binary * +imap_sieve_filter_open_script(struct imap_filter_sieve_context *sctx, + struct sieve_script *script, + enum sieve_compile_flags cpflags, + struct sieve_error_handler *user_ehandler, + bool recompile, enum sieve_error *error_r) +{ + struct mail_user *user = sctx->user; + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user); + struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx); + struct sieve_error_handler *ehandler; + struct sieve_binary *sbin; + const char *compile_name = "compile"; + + if (recompile) { + /* Warn */ + e_warning(sieve_get_event(svinst), + "Encountered corrupt binary: re-compiling script %s", + sieve_script_location(script)); + compile_name = "re-compile"; + } else { + e_debug(sieve_get_event(svinst), "Loading script %s", + sieve_script_location(script)); + } + + if (script == sctx->user_script) + ehandler = user_ehandler; + else + ehandler = ifsuser->master_ehandler; + sieve_error_handler_reset(ehandler); + + /* Load or compile the sieve script */ + if (recompile) { + sbin = sieve_compile_script(script, ehandler, cpflags, error_r); + } else { + sbin = sieve_open_script(script, ehandler, cpflags, error_r); + } + + /* Handle error */ + if (sbin == NULL) { + switch (*error_r) { + /* Script not found */ + case SIEVE_ERROR_NOT_FOUND: + e_debug(sieve_get_event(svinst), + "Script `%s' is missing for %s", + sieve_script_location(script), compile_name); + break; + /* Temporary failure */ + case SIEVE_ERROR_TEMP_FAILURE: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s " + "(temporary failure)", + sieve_script_location(script), compile_name); + break; + /* Compile failed */ + case SIEVE_ERROR_NOT_VALID: + if (script == sctx->user_script) + break; + e_error(sieve_get_event(svinst), + "Failed to %s script `%s'", + compile_name, sieve_script_location(script)); + break; + /* Cumulative resource limit exceeded */ + case SIEVE_ERROR_RESOURCE_LIMIT: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s " + "(cumulative resource limit exceeded)", + sieve_script_location(script), compile_name); + break; + /* Something else */ + default: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s", + sieve_script_location(script), compile_name); + break; + } + + return NULL; + } + + if (!recompile) + (void)sieve_save(sbin, FALSE, NULL); + return sbin; +} + +int imap_filter_sieve_compile(struct imap_filter_sieve_context *sctx, + string_t **errors_r, bool *have_warnings_r) +{ + struct imap_filter_sieve_script *scripts = sctx->scripts; + unsigned int count = sctx->scripts_count, i; + struct sieve_error_handler *ehandler; + enum sieve_error error; + int ret = 0; + + *errors_r = NULL; + *have_warnings_r = FALSE; + + /* Prepare error handler */ + ehandler = imap_filter_sieve_create_error_handler(sctx); + + for (i = 0; i < count; i++) { + struct sieve_script *script = scripts[i].script; + + i_assert(script != NULL); + + scripts[i].binary = + imap_sieve_filter_open_script(sctx, script, 0, ehandler, + FALSE, &error); + if (scripts[i].binary == NULL) { + if (error != SIEVE_ERROR_NOT_VALID) { + const char *errormsg = + sieve_script_get_last_error( + script, &error); + if (error != SIEVE_ERROR_NONE) { + str_truncate(sctx->errors, 0); + str_append(sctx->errors, errormsg); + } + } + ret = -1; + break; + } + } + + if (ret < 0 && str_len(sctx->errors) == 0) { + /* Failed, but no user error was logged: log a generic internal + error instead. */ + sieve_internal_error(ehandler, NULL, NULL); + } + + *have_warnings_r = (sieve_get_warnings(ehandler) > 0); + *errors_r = sctx->errors; + + sieve_error_handler_unref(&ehandler); + return ret; +} + +void imap_filter_sieve_open_input(struct imap_filter_sieve_context *sctx, + struct istream *input) +{ + struct sieve_instance *svinst; + struct sieve_script *script; + + svinst = imap_filter_sieve_get_svinst(sctx); + script = sieve_data_script_create_from_input(svinst, "script", input); + + sctx->user_script = script; + sctx->scripts = p_new(sctx->pool, struct imap_filter_sieve_script, 1); + sctx->scripts_count = 1; + sctx->scripts[0].script = script; +} + +int imap_filter_sieve_open_personal(struct imap_filter_sieve_context *sctx, + const char *name, + enum mail_error *error_code_r, + const char **error_r) +{ + struct sieve_storage *storage; + struct sieve_script *script; + enum sieve_error error; + + if (imap_filter_sieve_get_personal_storage(sctx, &storage, + error_code_r, error_r) < 0) + return -1; + + if (name == NULL) + script = sieve_storage_active_script_open(storage, NULL); + else + script = sieve_storage_open_script(storage, name, NULL); + if (script == NULL) { + *error_r = sieve_storage_get_last_error(storage, &error); + + switch (error) { + case SIEVE_ERROR_NOT_FOUND: + *error_code_r = MAIL_ERROR_NOTFOUND; + break; + case SIEVE_ERROR_NOT_POSSIBLE: + *error_code_r = MAIL_ERROR_NOTPOSSIBLE; + break; + default: + *error_code_r = MAIL_ERROR_TEMP; + } + return -1; + } + + sctx->user_script = script; + sctx->scripts = p_new(sctx->pool, struct imap_filter_sieve_script, 1); + sctx->scripts_count = 1; + sctx->scripts[0].script = script; + return 0; +} + +int imap_filter_sieve_open_global(struct imap_filter_sieve_context *sctx, + const char *name, + enum mail_error *error_code_r, + const char **error_r) +{ + struct sieve_storage *storage; + struct sieve_script *script; + enum sieve_error error; + + if (imap_filter_sieve_get_global_storage(sctx, &storage, + error_code_r, error_r) < 0) + return -1; + + script = sieve_storage_open_script(storage, name, NULL); + if (script == NULL) { + *error_r = sieve_storage_get_last_error(storage, &error); + + switch (error) { + case SIEVE_ERROR_NOT_FOUND: + *error_code_r = MAIL_ERROR_NOTFOUND; + break; + case SIEVE_ERROR_NOT_POSSIBLE: + *error_code_r = MAIL_ERROR_NOTPOSSIBLE; + break; + default: + *error_code_r = MAIL_ERROR_TEMP; + } + return -1; + } + + sctx->user_script = script; + sctx->scripts = p_new(sctx->pool, struct imap_filter_sieve_script, 1); + sctx->scripts_count = 1; + sctx->scripts[0].script = script; + return 0; +} + +/* + * Mail transmission + */ + +static void * +imap_filter_sieve_smtp_start(const struct sieve_script_env *senv, + const struct smtp_address *mail_from) +{ + struct imap_filter_sieve_context *sctx = senv->script_context; + struct mail_user *user = sctx->user; + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user); + const struct smtp_submit_settings *smtp_set = ifsuser->client->smtp_set; + struct ssl_iostream_settings ssl_set; + struct smtp_submit_input submit_input; + + i_zero(&ssl_set); + mail_user_init_ssl_client_settings(user, &ssl_set); + + i_zero(&submit_input); + submit_input.ssl = &ssl_set; + + return (void *)smtp_submit_init_simple(&submit_input, smtp_set, + mail_from); +} + +static void +imap_filter_sieve_smtp_add_rcpt(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle, + const struct smtp_address *rcpt_to) +{ + struct smtp_submit *smtp_submit = handle; + + smtp_submit_add_rcpt(smtp_submit, rcpt_to); +} + +static struct ostream * +imap_filter_sieve_smtp_send(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle) +{ + struct smtp_submit *smtp_submit = handle; + + return smtp_submit_send(smtp_submit); +} + +static void +imap_filter_sieve_smtp_abort(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle) +{ + struct smtp_submit *smtp_submit = handle; + + smtp_submit_deinit(&smtp_submit); +} + +static int +imap_filter_sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle, const char **error_r) +{ + struct smtp_submit *smtp_submit = handle; + int ret; + + ret = smtp_submit_run(smtp_submit, error_r); + smtp_submit_deinit(&smtp_submit); + return ret; +} + +/* + * Duplicate checking + */ + +static void * +imap_filter_sieve_duplicate_transaction_begin( + const struct sieve_script_env *senv) +{ + struct imap_filter_sieve_context *sctx = senv->script_context; + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(sctx->user); + + return mail_duplicate_transaction_begin(ifsuser->dup_db); +} + +static void imap_filter_sieve_duplicate_transaction_commit(void **_dup_trans) +{ + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + + mail_duplicate_transaction_commit(&dup_trans); +} + +static void imap_filter_sieve_duplicate_transaction_rollback(void **_dup_trans) +{ + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + + mail_duplicate_transaction_rollback(&dup_trans); +} + +static enum sieve_duplicate_check_result +imap_filter_sieve_duplicate_check(void *_dup_trans, + const struct sieve_script_env *senv, + const void *id, size_t id_size) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + switch (mail_duplicate_check(dup_trans, id, id_size, + senv->user->username)) { + case MAIL_DUPLICATE_CHECK_RESULT_EXISTS: + return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS; + case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND: + return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND; + case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK: + case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT: + return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE; + case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR: + case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS: + break; + } + return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE; +} + +static void +imap_filter_sieve_duplicate_mark(void *_dup_trans, + const struct sieve_script_env *senv, + const void *id, size_t id_size, time_t time) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time); +} + +/* + * Result logging + */ + +static const char * +imap_filter_sieve_result_amend_log_message(const struct sieve_script_env *senv, + enum log_type log_type ATTR_UNUSED, + const char *message) +{ + struct imap_filter_sieve_context *sctx = senv->script_context; + string_t *str; + + if (sctx->mail == NULL) + return message; + + str = t_str_new(256); + str_printfa(str, "uid=%u: ", sctx->mail->uid); + str_append(str, message); + return str_c(str); +} + +/* + * + */ + +static int +imap_sieve_filter_handle_exec_status(struct imap_filter_sieve_context *sctx, + struct sieve_script *script, int status, + struct sieve_exec_status *estatus, + bool *fatal_r) +{ + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(sctx->user); + struct sieve_instance *svinst = ifsuser->svinst; + enum log_type log_level, user_log_level; + enum mail_error mail_error = MAIL_ERROR_NONE; + int ret = -1; + + *fatal_r = FALSE; + + log_level = user_log_level = LOG_TYPE_ERROR; + + if (estatus->last_storage != NULL && estatus->store_failed) { + (void)mail_storage_get_last_error(estatus->last_storage, + &mail_error); + + /* Don't bother administrator too much with benign errors */ + if (mail_error == MAIL_ERROR_NOQUOTA) { + log_level = LOG_TYPE_INFO; + user_log_level = LOG_TYPE_INFO; + } + } + + switch (status) { + case SIEVE_EXEC_FAILURE: + e_log(sieve_get_event(svinst), user_log_level, + "Execution of script %s failed", + sieve_script_location(script)); + ret = -1; + break; + case SIEVE_EXEC_TEMP_FAILURE: + e_log(sieve_get_event(svinst), log_level, + "Execution of script %s was aborted " + "due to temporary failure", + sieve_script_location(script)); + *fatal_r = TRUE; + ret = -1; + break; + case SIEVE_EXEC_BIN_CORRUPT: + e_error(sieve_get_event(svinst), + "!!BUG!!: Binary compiled from %s is still corrupt; " + "bailing out and reverting to default action", + sieve_script_location(script)); + *fatal_r = TRUE; + ret = -1; + break; + case SIEVE_EXEC_RESOURCE_LIMIT: + e_error(sieve_get_event(svinst), + "Execution of script %s was aborted " + "due to excessive resource usage", + sieve_script_location(script)); + *fatal_r = TRUE; + ret = -1; + break; + case SIEVE_EXEC_KEEP_FAILED: + e_log(sieve_get_event(svinst), log_level, + "Execution of script %s failed " + "with unsuccessful implicit keep", + sieve_script_location(script)); + ret = -1; + break; + case SIEVE_EXEC_OK: + ret = (estatus->keep_original ? 0 : 1); + break; + } + + return ret; +} + +static int +imap_sieve_filter_run_scripts(struct imap_filter_sieve_context *sctx, + struct sieve_error_handler *user_ehandler, + const struct sieve_message_data *msgdata, + const struct sieve_script_env *scriptenv, + bool *fatal_r) +{ + struct mail_user *user = sctx->user; + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user); + struct sieve_instance *svinst = ifsuser->svinst; + struct imap_filter_sieve_script *scripts = sctx->scripts; + unsigned int count = sctx->scripts_count; + struct sieve_resource_usage *rusage = + &scriptenv->exec_status->resource_usage; + struct sieve_multiscript *mscript; + struct sieve_error_handler *ehandler; + struct sieve_script *last_script = NULL; + bool user_script = FALSE, more = TRUE, rusage_exceeded = FALSE; + enum sieve_compile_flags cpflags; + enum sieve_execute_flags exflags; + enum sieve_error compile_error = SIEVE_ERROR_NONE; + unsigned int i; + int ret; + + *fatal_r = FALSE; + + /* Start execution */ + mscript = sieve_multiscript_start_execute(svinst, msgdata, scriptenv); + + /* Execute scripts */ + for (i = 0; i < count && more; i++) { + struct sieve_script *script = scripts[i].script; + struct sieve_binary *sbin = scripts[i].binary; + int mstatus; + + if (sbin == NULL) { + e_debug(sieve_get_event(svinst), + "Skipping script from `%s'", + sieve_script_location(script)); + continue; + } + + cpflags = 0; + exflags = SIEVE_EXECUTE_FLAG_SKIP_RESPONSES; + + user_script = (script == sctx->user_script); + last_script = script; + + if (scripts[i].rusage_exceeded) { + rusage_exceeded = TRUE; + break; + } + + sieve_resource_usage_init(rusage); + if (user_script) { + cpflags |= SIEVE_COMPILE_FLAG_NOGLOBAL; + exflags |= SIEVE_EXECUTE_FLAG_NOGLOBAL; + ehandler = user_ehandler; + } else { + ehandler = ifsuser->master_ehandler; + } + + /* Execute */ + e_debug(sieve_get_event(svinst), + "Executing script from `%s'", + sieve_get_source(sbin)); + more = sieve_multiscript_run(mscript, + sbin, ehandler, ehandler, exflags); + + mstatus = sieve_multiscript_status(mscript); + if (!more && mstatus == SIEVE_EXEC_BIN_CORRUPT && + !scripts[i].binary_corrupt && sieve_is_loaded(sbin)) { + /* Close corrupt script */ + sieve_close(&sbin); + + /* Recompile */ + scripts[i].binary = sbin = + imap_sieve_filter_open_script( + sctx, script, cpflags, user_ehandler, + FALSE, &compile_error); + if (sbin == NULL) { + scripts[i].compile_error = compile_error; + break; + } + + /* Execute again */ + more = sieve_multiscript_run(mscript, sbin, + ehandler, ehandler, + exflags); + + /* Save new version */ + + mstatus = sieve_multiscript_status(mscript); + if (mstatus == SIEVE_EXEC_BIN_CORRUPT) + scripts[i].binary_corrupt = TRUE; + else if (more) + (void)sieve_save(sbin, FALSE, NULL); + } + + if (user_script && !sieve_record_resource_usage(sbin, rusage)) { + rusage_exceeded = ((i + 1) < count && more); + scripts[i].rusage_exceeded = TRUE; + break; + } + } + + /* Finish execution */ + exflags = SIEVE_EXECUTE_FLAG_SKIP_RESPONSES; + ehandler = (user_ehandler != NULL ? + user_ehandler : ifsuser->master_ehandler); + if (compile_error == SIEVE_ERROR_TEMP_FAILURE) { + ret = sieve_multiscript_finish(&mscript, ehandler, exflags, + SIEVE_EXEC_TEMP_FAILURE); + } else if (rusage_exceeded) { + i_assert(last_script != NULL); + (void)sieve_multiscript_finish(&mscript, ehandler, exflags, + SIEVE_EXEC_TEMP_FAILURE); + sieve_error(ehandler, sieve_script_name(last_script), + "cumulative resource usage limit exceeded"); + ret = SIEVE_EXEC_RESOURCE_LIMIT; + } else { + ret = sieve_multiscript_finish(&mscript, ehandler, exflags, + SIEVE_EXEC_OK); + } + + /* Don't log additional messages about compile failure */ + if (compile_error != SIEVE_ERROR_NONE && + ret == SIEVE_EXEC_FAILURE) { + e_info(sieve_get_event(svinst), + "Aborted script execution sequence " + "with successful implicit keep"); + return 0; + } + + if (last_script == NULL && ret == SIEVE_EXEC_OK) + return 0; + i_assert(last_script != NULL); /* at least one script is executed */ + return imap_sieve_filter_handle_exec_status(sctx, last_script, ret, + scriptenv->exec_status, + fatal_r); +} + +static int +parse_address(const char *address, const struct smtp_address **addr_r) +{ + struct message_address *msg_addr; + struct smtp_address *smtp_addr; + + if (message_address_parse_path(pool_datastack_create(), + (const unsigned char *)address, + strlen(address), &msg_addr) < 0) { + *addr_r = NULL; + return -1; + } + if (smtp_address_create_from_msg_temp(msg_addr, &smtp_addr) < 0) { + *addr_r = NULL; + return -1; + } + + *addr_r = smtp_addr; + return 1; +} + +int imap_sieve_filter_run_init(struct imap_filter_sieve_context *sctx) +{ + struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx); + struct sieve_script_env *scriptenv = &sctx->scriptenv; + struct mail_user *user = sctx->user; + const char *error; + + if (sieve_script_env_init(scriptenv, user, &error) < 0) { + e_error(sieve_get_event(svinst), + "Failed to initialize script execution: %s", + error); + return -1; + } + + scriptenv->smtp_start = imap_filter_sieve_smtp_start; + scriptenv->smtp_add_rcpt = imap_filter_sieve_smtp_add_rcpt; + scriptenv->smtp_send = imap_filter_sieve_smtp_send; + scriptenv->smtp_abort = imap_filter_sieve_smtp_abort; + scriptenv->smtp_finish = imap_filter_sieve_smtp_finish; + scriptenv->duplicate_transaction_begin = + imap_filter_sieve_duplicate_transaction_begin; + scriptenv->duplicate_transaction_commit = + imap_filter_sieve_duplicate_transaction_commit; + scriptenv->duplicate_transaction_rollback = + imap_filter_sieve_duplicate_transaction_rollback; + scriptenv->duplicate_mark = imap_filter_sieve_duplicate_mark; + scriptenv->duplicate_check = imap_filter_sieve_duplicate_check; + scriptenv->script_context = sctx; + return 0; +} + +static void +imap_sieve_filter_get_msgdata(struct imap_filter_sieve_context *sctx, + struct mail *mail, + struct sieve_message_data *msgdata_r) +{ + struct sieve_instance *svinst = imap_filter_sieve_get_svinst(sctx); + struct mail_user *user = sctx->user; + const char *address, *error; + const struct smtp_address *mail_from, *rcpt_to; + struct smtp_address *user_addr; + int ret; + + mail_from = NULL; + if ((ret = mail_get_special(mail, MAIL_FETCH_FROM_ENVELOPE, + &address)) > 0 && + (ret = parse_address(address, &mail_from)) < 0) { + e_warning(sieve_get_event(svinst), + "Failed to parse message FROM_ENVELOPE"); + } + if (ret <= 0 && + mail_get_first_header(mail, "Return-Path", + &address) > 0 && + parse_address(address, &mail_from) < 0) { + e_info(sieve_get_event(svinst), + "Failed to parse Return-Path header"); + } + + rcpt_to = NULL; + if (mail_get_first_header(mail, "Delivered-To", + &address) > 0 && + parse_address(address, &rcpt_to) < 0) { + e_info(sieve_get_event(svinst), + "Failed to parse Delivered-To header"); + } + if (rcpt_to == NULL) { + if (svinst->user_email != NULL) + rcpt_to = svinst->user_email; + else if (smtp_address_parse_username(sctx->pool, user->username, + &user_addr, &error) < 0) { + e_warning(sieve_get_event(svinst), + "Cannot obtain SMTP address from username `%s': %s", + user->username, error); + } else { + if (user_addr->domain == NULL) + user_addr->domain = svinst->domainname; + rcpt_to = user_addr; + } + } + + // FIXME: maybe parse top Received header. + + i_zero(msgdata_r); + msgdata_r->mail = mail; + msgdata_r->envelope.mail_from = mail_from; + msgdata_r->envelope.rcpt_to = rcpt_to; + msgdata_r->auth_user = user->username; + (void)mail_get_message_id(mail, &msgdata_r->id); +} + +int imap_sieve_filter_run_mail(struct imap_filter_sieve_context *sctx, + struct mail *mail, string_t **errors_r, + bool *have_warnings_r, bool *have_changes_r, + bool *fatal_r) +{ + struct sieve_error_handler *user_ehandler; + struct sieve_message_data msgdata; + struct sieve_script_env *scriptenv = &sctx->scriptenv; + struct sieve_exec_status estatus; + struct sieve_trace_config trace_config; + struct sieve_trace_log *trace_log; + int ret; + + *errors_r = NULL; + *have_warnings_r = FALSE; + *have_changes_r = FALSE; + i_zero(&estatus); + + sctx->mail = mail; + + /* Prepare error handler */ + user_ehandler = imap_filter_sieve_create_error_handler(sctx); + + /* Initialize trace logging */ + imap_filter_sieve_init_trace_log(sctx, &trace_config, &trace_log); + + T_BEGIN { + if (trace_log != NULL) { + /* Write trace header for message */ + sieve_trace_log_printf(trace_log, + "Filtering message:\n" + "\n" + " UID: %u\n", mail->uid); + } + + /* Collect necessary message data */ + + imap_sieve_filter_get_msgdata(sctx, mail, &msgdata); + + /* Complete script execution environment */ + + scriptenv->default_mailbox = mailbox_get_vname(mail->box); + scriptenv->result_amend_log_message = + imap_filter_sieve_result_amend_log_message; + scriptenv->trace_log = trace_log; + scriptenv->trace_config = trace_config; + scriptenv->script_context = sctx; + + scriptenv->exec_status = &estatus; + + /* Execute script(s) */ + + ret = imap_sieve_filter_run_scripts(sctx, user_ehandler, + &msgdata, scriptenv, + fatal_r); + } T_END; + + if (ret < 0 && str_len(sctx->errors) == 0) { + /* Failed, but no user error was logged: log a generic internal + error instead. */ + sieve_internal_error(user_ehandler, NULL, NULL); + } + + *have_warnings_r = (sieve_get_warnings(user_ehandler) > 0); + *have_changes_r = estatus.significant_action_executed; + *errors_r = sctx->errors; + + sieve_error_handler_unref(&user_ehandler); + + sctx->mail = NULL; + + return ret; +} + +/* + * User + */ + +static void imap_filter_sieve_user_deinit(struct mail_user *user) +{ + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(user); + + sieve_error_handler_unref(&ifsuser->master_ehandler); + + if (ifsuser->storage != NULL) + sieve_storage_unref(&ifsuser->storage); + if (ifsuser->global_storage != NULL) + sieve_storage_unref(&ifsuser->global_storage); + if (ifsuser->svinst != NULL) + sieve_deinit(&ifsuser->svinst); + if (ifsuser->dup_db != NULL) + mail_duplicate_db_deinit(&ifsuser->dup_db); + + ifsuser->module_ctx.super.deinit(user); +} + +static void imap_filter_sieve_user_created(struct mail_user *user) +{ + struct imap_filter_sieve_user *ifsuser; + struct mail_user_vfuncs *v = user->vlast; + + ifsuser = p_new(user->pool, struct imap_filter_sieve_user, 1); + ifsuser->module_ctx.super = *v; + user->vlast = &ifsuser->module_ctx.super; + v->deinit = imap_filter_sieve_user_deinit; + MODULE_CONTEXT_SET(user, imap_filter_sieve_user_module, ifsuser); +} + +/* + * Hooks + */ + +static struct mail_storage_hooks imap_filter_sieve_mail_storage_hooks = { + .mail_user_created = imap_filter_sieve_user_created, +}; + +/* + * Client + */ + +void imap_filter_sieve_client_created(struct client *client) +{ + struct imap_filter_sieve_user *ifsuser = + IMAP_FILTER_SIEVE_USER_CONTEXT_REQUIRE(client->user); + + ifsuser->client = client; +} + +/* + * + */ + +void imap_filter_sieve_init(struct module *module) +{ + mail_storage_hooks_add(module, &imap_filter_sieve_mail_storage_hooks); +} + +void imap_filter_sieve_deinit(void) +{ + mail_storage_hooks_remove(&imap_filter_sieve_mail_storage_hooks); +} + + diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.h b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.h new file mode 100644 index 0000000..c06cbdb --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter-sieve.h @@ -0,0 +1,97 @@ +#ifndef IMAP_FILTER_SIEVE_H +#define IMAP_FILTER_SIEVE_H + +#include "sieve.h" +#include "imap-filter.h" + +struct imap_filter_sieve_script; +struct imap_filter_sieve_context; + +enum imap_filter_sieve_type { + IMAP_FILTER_SIEVE_TYPE_DELIVERY, + IMAP_FILTER_SIEVE_TYPE_PERSONAL, + IMAP_FILTER_SIEVE_TYPE_GLOBAL, + IMAP_FILTER_SIEVE_TYPE_SCRIPT, +}; + +struct imap_filter_sieve_context { + pool_t pool; + + struct imap_filter_context *filter_context; + enum imap_filter_sieve_type filter_type; + + struct mail_user *user; + + struct sieve_script *user_script; + struct imap_filter_sieve_script *scripts; + unsigned int scripts_count; + + struct mail *mail; + + struct sieve_script_env scriptenv; + struct sieve_trace_config trace_config; + struct sieve_trace_log *trace_log; + + string_t *errors; + + bool warnings:1; + bool trace_log_initialized:1; +}; + +/* + * FILTER Command + */ + +bool cmd_filter_sieve(struct client_command_context *cmd); + +/* + * Context + */ + +struct imap_filter_sieve_context * +imap_filter_sieve_context_create(struct imap_filter_context *ctx, + enum imap_filter_sieve_type type); +void imap_filter_sieve_context_free(struct imap_filter_sieve_context **_sctx); + +/* + * Compile + */ + +int imap_filter_sieve_compile(struct imap_filter_sieve_context *sctx, + string_t **errors_r, bool *have_warnings_r); + +/* + * Open + */ + +void imap_filter_sieve_open_input(struct imap_filter_sieve_context *sctx, + struct istream *input); +int imap_filter_sieve_open_personal(struct imap_filter_sieve_context *sctx, + const char *name, + enum mail_error *error_code_r, + const char **error_r) ATTR_NULL(2); +int imap_filter_sieve_open_global(struct imap_filter_sieve_context *sctx, + const char *name, + enum mail_error *error_code_r, + const char **error_r); + +/* + * Run + */ + +int imap_sieve_filter_run_init(struct imap_filter_sieve_context *sctx); +int imap_sieve_filter_run_mail(struct imap_filter_sieve_context *sctx, + struct mail *mail, string_t **errors_r, + bool *have_warnings_r, bool *have_changes_r, + bool *fatal_r); + +/* + * + */ + +void imap_filter_sieve_client_created(struct client *client); + +void imap_filter_sieve_init(struct module *module); +void imap_filter_sieve_deinit(void); + +#endif diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.c b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.c new file mode 100644 index 0000000..fd7d758 --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.c @@ -0,0 +1,273 @@ +/* Copyright (c) 2017-2018 Pigeonhole authors, see the included COPYING file */ + +#include "imap-common.h" +#include "str.h" +#include "ostream.h" +#include "time-util.h" +#include "imap-resp-code.h" +#include "imap-search-args.h" + +#include "imap-filter.h" +#include "imap-filter-sieve.h" + +static void imap_filter_args_check(struct imap_filter_context *ctx, + const struct mail_search_arg *sargs) +{ + for (; sargs != NULL; sargs = sargs->next) { + switch (sargs->type) { + case SEARCH_SEQSET: + ctx->have_seqsets = TRUE; + break; + case SEARCH_MODSEQ: + ctx->have_modseqs = TRUE; + break; + case SEARCH_OR: + case SEARCH_SUB: + imap_filter_args_check(ctx, sargs->value.subargs); + break; + default: + break; + } + } +} + +static bool +imap_filter_mail(struct client_command_context *cmd, struct mail *mail) +{ + struct imap_filter_context *ctx = cmd->context; + struct client *client = cmd->client; + string_t *errors = NULL; + bool have_warnings = FALSE, have_changes = FALSE, fatal = FALSE; + string_t *reply = t_str_new(128); + int ret; + + ret = imap_sieve_filter_run_mail(ctx->sieve, mail, &errors, + &have_warnings, &have_changes, &fatal); + + str_printfa(reply, "* %u FILTERED (TAG %s) UID %u ", + mail->seq, cmd->tag, mail->uid); + if (ret < 0 || have_warnings) { + str_printfa(reply, "%s {%zu}\r\n", + (ret < 0 ? "ERRORS" : "WARNINGS"), + str_len(errors)); + str_append_str(reply, errors); + str_append(reply, "\r\n"); + } else if (have_changes || ret > 0) { + str_append(reply, "OK\r\n"); + } else { + str_truncate(reply, 0); + } + if (str_len(reply) > 0) + o_stream_nsend(client->output, str_data(reply), str_len(reply)); + + /* Handle the result */ + if (ret < 0) { + /* Sieve error; keep */ + } else { + if (ret > 0) { + /* Discard */ + mail_update_flags(mail, MODIFY_ADD, MAIL_DELETED); + } + } + + return !fatal; +} + +static bool imap_filter_more(struct client_command_context *cmd) +{ + struct imap_filter_context *ctx = cmd->context; + struct mail *mail; + enum mailbox_sync_flags sync_flags; + const char *ok_reply; + bool tryagain, lost_data; + + if (cmd->cancel) { + (void)imap_filter_deinit(ctx); + return TRUE; + } + + while (mailbox_search_next_nonblock(ctx->search_ctx, + &mail, &tryagain)) { + bool ret; + T_BEGIN { + ret = imap_filter_mail(cmd, mail); + } T_END; + if (!ret) + break; + } + if (tryagain) + return FALSE; + + lost_data = mailbox_search_seen_lost_data(ctx->search_ctx); + if (imap_filter_deinit(ctx) < 0) { + client_send_box_error(cmd, cmd->client->mailbox); + return TRUE; + } + + sync_flags = MAILBOX_SYNC_FLAG_FAST; + if (!cmd->uid || ctx->have_seqsets) + sync_flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES; + ok_reply = t_strdup_printf("OK %sFilter completed", + lost_data ? "["IMAP_RESP_CODE_EXPUNGEISSUED"] " : ""); + return cmd_sync(cmd, sync_flags, 0, ok_reply); +} + +static void imap_filter_more_callback(struct client_command_context *cmd) +{ + struct client *client = cmd->client; + bool finished; + + o_stream_cork(client->output); + finished = command_exec(cmd); + o_stream_uncork(client->output); + + if (!finished) + (void)client_handle_unfinished_cmd(cmd); + else + client_command_free(&cmd); + cmd_sync_delayed(client); + + if (client->disconnected) + client_destroy(client, NULL); + else + client_continue_pending_input(client); +} + +static bool +imap_filter_start(struct imap_filter_context *ctx, + struct mail_search_args *sargs) +{ + struct client_command_context *cmd = ctx->cmd; + + imap_filter_args_check(ctx, sargs->args); + + if (ctx->have_modseqs) + (void)client_enable(cmd->client, MAILBOX_FEATURE_CONDSTORE); + + ctx->box = cmd->client->mailbox; + ctx->trans = mailbox_transaction_begin(ctx->box, 0, + imap_client_command_get_reason(cmd)); + ctx->sargs = sargs; + ctx->search_ctx = mailbox_search_init(ctx->trans, sargs, NULL, 0, NULL); + + if (imap_sieve_filter_run_init(ctx->sieve) < 0) { + const char *error = t_strflocaltime( + MAIL_ERRSTR_CRITICAL_MSG_STAMP, ioloop_time); + + o_stream_nsend_str(cmd->client->output, + t_strdup_printf("* FILTER (TAG %s) " + "ERRORS {%zu}\r\n%s\r\n", + cmd->tag, strlen(error), error)); + client_send_tagline(cmd, + "NO Failed to initialize script execution"); + (void)imap_filter_deinit(ctx); + return TRUE; + } + + cmd->func = imap_filter_more; + cmd->context = ctx; + + if (imap_filter_more(cmd)) + return TRUE; + + /* we may have moved onto syncing by now */ + if (cmd->func == imap_filter_more) { + ctx->to = timeout_add(0, imap_filter_more_callback, cmd); + cmd->state = CLIENT_COMMAND_STATE_WAIT_EXTERNAL; + } + return FALSE; +} + +static bool +imap_filter_parse_search(struct imap_filter_context *ctx, + const struct imap_arg *args) +{ + struct client_command_context *cmd = ctx->cmd; + struct mail_search_args *sargs; + const char *charset; + int ret; + + if (imap_arg_atom_equals(args, "CHARSET")) { + /* CHARSET specified */ + if (!imap_arg_get_astring(&args[1], &charset)) { + client_send_command_error(cmd, + "Invalid charset argument."); + imap_filter_context_free(ctx); + return TRUE; + } + args += 2; + } else { + charset = "UTF-8"; + } + + ret = imap_search_args_build(cmd, args, charset, &sargs); + if (ret <= 0) { + imap_filter_context_free(ctx); + return ret < 0; + } + + return imap_filter_start(ctx, sargs); +} + +bool imap_filter_search(struct client_command_context *cmd) +{ + struct imap_filter_context *ctx = cmd->context; + const struct imap_arg *args; + const char *error; + enum imap_parser_error parse_error; + int ret; + + ret = imap_parser_read_args(ctx->parser, 0, 0, &args); + if (ret < 0) { + if (ret == -2) + return FALSE; + error = imap_parser_get_error(ctx->parser, &parse_error); + switch (parse_error) { + case IMAP_PARSE_ERROR_NONE: + i_unreached(); + case IMAP_PARSE_ERROR_LITERAL_TOO_BIG: + client_disconnect_with_error(ctx->cmd->client, error); + break; + default: + client_send_command_error(ctx->cmd, error); + break; + } + return TRUE; + } + return imap_filter_parse_search(ctx, args); +} + +int imap_filter_deinit(struct imap_filter_context *ctx) +{ + int ret = 0; + + o_stream_set_flush_callback(ctx->cmd->client->output, + client_output, ctx->cmd->client); + ctx->cmd->client->input_lock = NULL; + imap_parser_unref(&ctx->parser); + + if (ctx->search_ctx != NULL && + mailbox_search_deinit(&ctx->search_ctx) < 0) + ret = -1; + + if (ctx->trans != NULL) + (void)mailbox_transaction_commit(&ctx->trans); + + timeout_remove(&ctx->to); + if (ctx->sargs != NULL) { + mail_search_args_deinit(ctx->sargs); + mail_search_args_unref(&ctx->sargs); + } + imap_filter_context_free(ctx); + + ctx->cmd->context = NULL; + return ret; +} + +void imap_filter_context_free(struct imap_filter_context *ctx) +{ + imap_filter_sieve_context_free(&ctx->sieve); +} + + + diff --git a/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.h b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.h new file mode 100644 index 0000000..d504704 --- /dev/null +++ b/pigeonhole/src/plugins/imap-filter-sieve/imap-filter.h @@ -0,0 +1,43 @@ +#ifndef IMAP_FILTER_H +#define IMAP_FILTER_H + +struct mail_duplicate_db; + +struct sieve_script; +struct sieve_storage; +struct sieve_binary; + +struct imap_filter_context { + struct client_command_context *cmd; + struct mailbox *box; + struct mailbox_transaction_context *trans; + struct mail_search_context *search_ctx; + + struct imap_parser *parser; + + struct imap_filter_sieve_context *sieve; + const char *script_name; + uoff_t script_len; + struct istream *script_input; + + struct mail_search_args *sargs; + + struct timeout *to; + + bool failed:1; + bool compile_failure:1; + bool have_seqsets:1; + bool have_modseqs:1; +}; + +bool imap_filter_search(struct client_command_context *cmd); + +int imap_filter_deinit(struct imap_filter_context *ctx); + +void imap_filter_context_free(struct imap_filter_context *ctx); + +/* Commands */ + +bool cmd_filter(struct client_command_context *cmd); + +#endif diff --git a/pigeonhole/src/plugins/imapsieve/Makefile.am b/pigeonhole/src/plugins/imapsieve/Makefile.am new file mode 100644 index 0000000..1fea23e --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/Makefile.am @@ -0,0 +1,40 @@ +imap_moduledir = $(dovecot_moduledir) +sieve_plugindir = $(dovecot_moduledir)/sieve + +imap_module_LTLIBRARIES = lib95_imap_sieve_plugin.la +sieve_plugin_LTLIBRARIES = lib90_sieve_imapsieve_plugin.la + +lib95_imap_sieve_plugin_la_LDFLAGS = -module -avoid-version +lib90_sieve_imapsieve_plugin_la_LDFLAGS = -module -avoid-version + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + -I$(top_srcdir)/src/lib-sieve/util \ + -I$(top_srcdir)/src/lib-sieve/plugins/environment \ + $(LIBDOVECOT_IMAP_INCLUDE) \ + $(LIBDOVECOT_LDA_INCLUDE) \ + $(LIBDOVECOT_INCLUDE) \ + -DPKG_RUNDIR=\""$(rundir)"\" + +lib95_imap_sieve_plugin_la_SOURCES = \ + ext-imapsieve.c \ + ext-imapsieve-environment.c \ + imap-sieve.c \ + imap-sieve-storage.c \ + imap-sieve-plugin.c +lib95_imap_sieve_plugin_la_LIBADD = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la + +lib90_sieve_imapsieve_plugin_la_SOURCES = \ + ext-imapsieve.c \ + sieve-imapsieve-plugin.c +lib90_sieve_imapsieve_plugin_la_CPPFLAGS = \ + ${AM_CPPFLAGS} \ + -D__IMAPSIEVE_DUMMY + +noinst_HEADERS = \ + ext-imapsieve-common.h \ + imap-sieve.h \ + imap-sieve-storage.h \ + imap-sieve-plugin.h \ + sieve-imapsieve-plugin.h diff --git a/pigeonhole/src/plugins/imapsieve/Makefile.in b/pigeonhole/src/plugins/imapsieve/Makefile.in new file mode 100644 index 0000000..648975b --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/Makefile.in @@ -0,0 +1,864 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 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/plugins/imapsieve +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 = +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)$(imap_moduledir)" \ + "$(DESTDIR)$(sieve_plugindir)" +LTLIBRARIES = $(imap_module_LTLIBRARIES) $(sieve_plugin_LTLIBRARIES) +lib90_sieve_imapsieve_plugin_la_LIBADD = +am_lib90_sieve_imapsieve_plugin_la_OBJECTS = \ + lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo \ + lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo +lib90_sieve_imapsieve_plugin_la_OBJECTS = \ + $(am_lib90_sieve_imapsieve_plugin_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +lib90_sieve_imapsieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) \ + $(lib90_sieve_imapsieve_plugin_la_LDFLAGS) $(LDFLAGS) -o $@ +lib95_imap_sieve_plugin_la_DEPENDENCIES = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la +am_lib95_imap_sieve_plugin_la_OBJECTS = ext-imapsieve.lo \ + ext-imapsieve-environment.lo imap-sieve.lo \ + imap-sieve-storage.lo imap-sieve-plugin.lo +lib95_imap_sieve_plugin_la_OBJECTS = \ + $(am_lib95_imap_sieve_plugin_la_OBJECTS) +lib95_imap_sieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(lib95_imap_sieve_plugin_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +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)/ext-imapsieve-environment.Plo \ + ./$(DEPDIR)/ext-imapsieve.Plo \ + ./$(DEPDIR)/imap-sieve-plugin.Plo \ + ./$(DEPDIR)/imap-sieve-storage.Plo ./$(DEPDIR)/imap-sieve.Plo \ + ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo \ + ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.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 = $(lib90_sieve_imapsieve_plugin_la_SOURCES) \ + $(lib95_imap_sieve_plugin_la_SOURCES) +DIST_SOURCES = $(lib90_sieve_imapsieve_plugin_la_SOURCES) \ + $(lib95_imap_sieve_plugin_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@ +imap_moduledir = $(dovecot_moduledir) +sieve_plugindir = $(dovecot_moduledir)/sieve +imap_module_LTLIBRARIES = lib95_imap_sieve_plugin.la +sieve_plugin_LTLIBRARIES = lib90_sieve_imapsieve_plugin.la +lib95_imap_sieve_plugin_la_LDFLAGS = -module -avoid-version +lib90_sieve_imapsieve_plugin_la_LDFLAGS = -module -avoid-version +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + -I$(top_srcdir)/src/lib-sieve/util \ + -I$(top_srcdir)/src/lib-sieve/plugins/environment \ + $(LIBDOVECOT_IMAP_INCLUDE) \ + $(LIBDOVECOT_LDA_INCLUDE) \ + $(LIBDOVECOT_INCLUDE) \ + -DPKG_RUNDIR=\""$(rundir)"\" + +lib95_imap_sieve_plugin_la_SOURCES = \ + ext-imapsieve.c \ + ext-imapsieve-environment.c \ + imap-sieve.c \ + imap-sieve-storage.c \ + imap-sieve-plugin.c + +lib95_imap_sieve_plugin_la_LIBADD = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la + +lib90_sieve_imapsieve_plugin_la_SOURCES = \ + ext-imapsieve.c \ + sieve-imapsieve-plugin.c + +lib90_sieve_imapsieve_plugin_la_CPPFLAGS = \ + ${AM_CPPFLAGS} \ + -D__IMAPSIEVE_DUMMY + +noinst_HEADERS = \ + ext-imapsieve-common.h \ + imap-sieve.h \ + imap-sieve-storage.h \ + imap-sieve-plugin.h \ + sieve-imapsieve-plugin.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/plugins/imapsieve/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/imapsieve/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-imap_moduleLTLIBRARIES: $(imap_module_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(imap_module_LTLIBRARIES)'; test -n "$(imap_moduledir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(imap_moduledir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(imap_moduledir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(imap_moduledir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(imap_moduledir)"; \ + } + +uninstall-imap_moduleLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(imap_module_LTLIBRARIES)'; test -n "$(imap_moduledir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(imap_moduledir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(imap_moduledir)/$$f"; \ + done + +clean-imap_moduleLTLIBRARIES: + -test -z "$(imap_module_LTLIBRARIES)" || rm -f $(imap_module_LTLIBRARIES) + @list='$(imap_module_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-sieve_pluginLTLIBRARIES: $(sieve_plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(sieve_plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sieve_plugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(sieve_plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(sieve_plugindir)"; \ + } + +uninstall-sieve_pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(sieve_plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(sieve_plugindir)/$$f"; \ + done + +clean-sieve_pluginLTLIBRARIES: + -test -z "$(sieve_plugin_LTLIBRARIES)" || rm -f $(sieve_plugin_LTLIBRARIES) + @list='$(sieve_plugin_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}; \ + } + +lib90_sieve_imapsieve_plugin.la: $(lib90_sieve_imapsieve_plugin_la_OBJECTS) $(lib90_sieve_imapsieve_plugin_la_DEPENDENCIES) $(EXTRA_lib90_sieve_imapsieve_plugin_la_DEPENDENCIES) + $(AM_V_CCLD)$(lib90_sieve_imapsieve_plugin_la_LINK) -rpath $(sieve_plugindir) $(lib90_sieve_imapsieve_plugin_la_OBJECTS) $(lib90_sieve_imapsieve_plugin_la_LIBADD) $(LIBS) + +lib95_imap_sieve_plugin.la: $(lib95_imap_sieve_plugin_la_OBJECTS) $(lib95_imap_sieve_plugin_la_DEPENDENCIES) $(EXTRA_lib95_imap_sieve_plugin_la_DEPENDENCIES) + $(AM_V_CCLD)$(lib95_imap_sieve_plugin_la_LINK) -rpath $(imap_moduledir) $(lib95_imap_sieve_plugin_la_OBJECTS) $(lib95_imap_sieve_plugin_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imapsieve-environment.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imapsieve.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-sieve-plugin.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-sieve-storage.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/imap-sieve.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.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 $@ $< + +lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo: ext-imapsieve.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib90_sieve_imapsieve_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo -MD -MP -MF $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Tpo -c -o lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo `test -f 'ext-imapsieve.c' || echo '$(srcdir)/'`ext-imapsieve.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Tpo $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ext-imapsieve.c' object='lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib90_sieve_imapsieve_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib90_sieve_imapsieve_plugin_la-ext-imapsieve.lo `test -f 'ext-imapsieve.c' || echo '$(srcdir)/'`ext-imapsieve.c + +lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo: sieve-imapsieve-plugin.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib90_sieve_imapsieve_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo -MD -MP -MF $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Tpo -c -o lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo `test -f 'sieve-imapsieve-plugin.c' || echo '$(srcdir)/'`sieve-imapsieve-plugin.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Tpo $(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sieve-imapsieve-plugin.c' object='lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(lib90_sieve_imapsieve_plugin_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.lo `test -f 'sieve-imapsieve-plugin.c' || echo '$(srcdir)/'`sieve-imapsieve-plugin.c + +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: + for dir in "$(DESTDIR)$(imap_moduledir)" "$(DESTDIR)$(sieve_plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-imap_moduleLTLIBRARIES clean-libtool \ + clean-sieve_pluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/ext-imapsieve-environment.Plo + -rm -f ./$(DEPDIR)/ext-imapsieve.Plo + -rm -f ./$(DEPDIR)/imap-sieve-plugin.Plo + -rm -f ./$(DEPDIR)/imap-sieve-storage.Plo + -rm -f ./$(DEPDIR)/imap-sieve.Plo + -rm -f ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo + -rm -f ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.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-imap_moduleLTLIBRARIES \ + install-sieve_pluginLTLIBRARIES + +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)/ext-imapsieve-environment.Plo + -rm -f ./$(DEPDIR)/ext-imapsieve.Plo + -rm -f ./$(DEPDIR)/imap-sieve-plugin.Plo + -rm -f ./$(DEPDIR)/imap-sieve-storage.Plo + -rm -f ./$(DEPDIR)/imap-sieve.Plo + -rm -f ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-ext-imapsieve.Plo + -rm -f ./$(DEPDIR)/lib90_sieve_imapsieve_plugin_la-sieve-imapsieve-plugin.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-imap_moduleLTLIBRARIES \ + uninstall-sieve_pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-imap_moduleLTLIBRARIES clean-libtool \ + clean-sieve_pluginLTLIBRARIES 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-imap_moduleLTLIBRARIES install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-sieve_pluginLTLIBRARIES install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am \ + uninstall-imap_moduleLTLIBRARIES \ + uninstall-sieve_pluginLTLIBRARIES + +.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/plugins/imapsieve/ext-imapsieve-common.h b/pigeonhole/src/plugins/imapsieve/ext-imapsieve-common.h new file mode 100644 index 0000000..d3e69cd --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/ext-imapsieve-common.h @@ -0,0 +1,29 @@ +#ifndef EXT_IMAPSIEVE_COMMON_H +#define EXT_IMAPSIEVE_COMMON_H + +#include "sieve-extensions.h" + +#include "imap-sieve.h" + +/* + * Extensions + */ + +extern const struct sieve_extension_def imapsieve_extension; +extern const struct sieve_extension_def imapsieve_extension_dummy; + +extern const struct sieve_extension_def vnd_imapsieve_extension; +extern const struct sieve_extension_def vnd_imapsieve_extension_dummy; + +/* + * Environment items + */ + +void ext_imapsieve_environment_items_register + (const struct sieve_extension *ext, + const struct sieve_runtime_env *renv); +void ext_imapsieve_environment_vendor_items_register + (const struct sieve_extension *ext, + const struct sieve_runtime_env *renv); + +#endif diff --git a/pigeonhole/src/plugins/imapsieve/ext-imapsieve-environment.c b/pigeonhole/src/plugins/imapsieve/ext-imapsieve-environment.c new file mode 100644 index 0000000..2b61cd4 --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/ext-imapsieve-environment.c @@ -0,0 +1,184 @@ +/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "array.h" +#include "mail-storage.h" + +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-runtime.h" + +#include "sieve-ext-environment.h" + +#include "ext-imapsieve-common.h" + +/* + * Environment items + */ + +/* imap.user */ + +static const char * +envit_imap_user_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + + return eenv->svinst->username; +} + +const struct sieve_environment_item imap_user_env_item = { + .name = "imap.user", + .get_value = envit_imap_user_get_value +}; + +/* imap.email */ + +static const char * +envit_imap_email_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct smtp_address *user_email = + sieve_get_user_email(eenv->svinst); + + if (user_email == NULL) + return NULL; + return smtp_address_encode(user_email); +} + +const struct sieve_environment_item imap_email_env_item = { + .name = "imap.email", + .get_value = envit_imap_email_get_value +}; + +/* imap.cause */ + +static const char * +envit_imap_cause_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_script_env *senv = eenv->scriptenv; + struct imap_sieve_context *isctx = + (struct imap_sieve_context *)senv->script_context; + + return isctx->event.cause; +} + +const struct sieve_environment_item imap_cause_env_item = { + .name = "imap.cause", + .get_value = envit_imap_cause_get_value +}; + +/* imap.mailbox */ + +static const char * +envit_imap_mailbox_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_message_data *msgdata = eenv->msgdata; + + return mailbox_get_vname(msgdata->mail->box); +} + +const struct sieve_environment_item imap_mailbox_env_item = { + .name = "imap.mailbox", + .get_value = envit_imap_mailbox_get_value +}; + + +/* imap.changedflags */ + +static const char * +envit_imap_changedflags_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_script_env *senv = eenv->scriptenv; + struct imap_sieve_context *isctx = + (struct imap_sieve_context *)senv->script_context; + + return isctx->event.changed_flags; +} + +const struct sieve_environment_item imap_changedflags_env_item = { + .name = "imap.changedflags", + .get_value = envit_imap_changedflags_get_value +}; + +/* vnd.dovecot.mailbox-from */ + +static const char * +envit_vnd_mailbox_from_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_script_env *senv = eenv->scriptenv; + struct imap_sieve_context *isctx = + (struct imap_sieve_context *)senv->script_context; + + return mailbox_get_vname(isctx->event.src_mailbox); +} + +const struct sieve_environment_item vnd_mailbox_from_env_item = { + .name = "vnd.dovecot.mailbox-from", + .get_value = envit_vnd_mailbox_from_get_value +}; + +/* vnd.dovecot.mailbox-to */ + +static const char * +envit_vnd_mailbox_to_get_value(const struct sieve_runtime_env *renv, + const char *name ATTR_UNUSED) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_script_env *senv = eenv->scriptenv; + struct imap_sieve_context *isctx = + (struct imap_sieve_context *)senv->script_context; + + return mailbox_get_vname(isctx->event.dest_mailbox); +} + +const struct sieve_environment_item vnd_mailbox_to_env_item = { + .name = "vnd.dovecot.mailbox-to", + .get_value = envit_vnd_mailbox_to_get_value +}; + +/* + * Register + */ + +void ext_imapsieve_environment_items_register( + const struct sieve_extension *ext, const struct sieve_runtime_env *renv) +{ + const struct sieve_extension *env_ext = + (const struct sieve_extension *)ext->context; + + sieve_environment_item_register(env_ext, renv->interp, + &imap_user_env_item); + sieve_environment_item_register(env_ext, renv->interp, + &imap_email_env_item); + sieve_environment_item_register(env_ext, renv->interp, + &imap_cause_env_item); + sieve_environment_item_register(env_ext, renv->interp, + &imap_mailbox_env_item); + sieve_environment_item_register(env_ext, renv->interp, + &imap_changedflags_env_item); +} + +void ext_imapsieve_environment_vendor_items_register +(const struct sieve_extension *ext, const struct sieve_runtime_env *renv) +{ + const struct sieve_extension *env_ext = + (const struct sieve_extension *)ext->context; + + sieve_environment_item_register(env_ext, renv->interp, + &vnd_mailbox_from_env_item); + sieve_environment_item_register(env_ext, renv->interp, + &vnd_mailbox_to_env_item); +} diff --git a/pigeonhole/src/plugins/imapsieve/ext-imapsieve.c b/pigeonhole/src/plugins/imapsieve/ext-imapsieve.c new file mode 100644 index 0000000..64dfc07 --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/ext-imapsieve.c @@ -0,0 +1,168 @@ +/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file + */ + +/* Extension imapsieve + * ------------------- + * + * Authors: Stephan Bosch + * Specification: RFC 6785 + * Implementation: full + * Status: experimental + * + */ + +#include "lib.h" + +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-binary.h" + +#include "sieve-validator.h" +#include "sieve-interpreter.h" + +#include "sieve-ext-environment.h" + +#include "ext-imapsieve-common.h" + +/* + * Extension + */ + +static bool ext_imapsieve_load + (const struct sieve_extension *ext, void **context); +static bool ext_vnd_imapsieve_load + (const struct sieve_extension *ext, void **context); +static bool ext_vnd_imapsieve_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); + +static bool ext_imapsieve_interpreter_load + (const struct sieve_extension *ext, + const struct sieve_runtime_env *renv, + sieve_size_t *address ATTR_UNUSED); + +#ifdef __IMAPSIEVE_DUMMY +const struct sieve_extension_def imapsieve_extension_dummy = { +#else +const struct sieve_extension_def imapsieve_extension = { +#endif + .name = "imapsieve", + .load = ext_imapsieve_load, + .interpreter_load = ext_imapsieve_interpreter_load +}; + +#ifdef __IMAPSIEVE_DUMMY +const struct sieve_extension_def vnd_imapsieve_extension_dummy = { +#else +const struct sieve_extension_def vnd_imapsieve_extension = { +#endif + .name = "vnd.dovecot.imapsieve", + .load = ext_vnd_imapsieve_load, + .interpreter_load = ext_imapsieve_interpreter_load, + .validator_load = ext_vnd_imapsieve_validator_load +}; + +/* + * Context + */ + +static bool ext_imapsieve_load +(const struct sieve_extension *ext, void **context) +{ + *context = (void*) + sieve_ext_environment_require_extension(ext->svinst); + return TRUE; +} + +static bool ext_vnd_imapsieve_load +(const struct sieve_extension *ext, void **context) +{ + *context = (void*)sieve_extension_require +#ifdef __IMAPSIEVE_DUMMY + (ext->svinst, &imapsieve_extension_dummy, TRUE); +#else + (ext->svinst, &imapsieve_extension, TRUE); +#endif + return TRUE; +} + +/* + * Validator + */ + +static bool ext_vnd_imapsieve_validator_load +(const struct sieve_extension *ext ATTR_UNUSED, + struct sieve_validator *valdtr) +{ + const struct sieve_extension *ims_ext; + + /* Load environment extension implicitly */ + + ims_ext = sieve_validator_extension_load_implicit +#ifdef __IMAPSIEVE_DUMMY + (valdtr, imapsieve_extension_dummy.name); +#else + (valdtr, imapsieve_extension.name); +#endif + if ( ims_ext == NULL ) + return FALSE; + + return TRUE; +} + +/* + * Interpreter + */ + +static int ext_imapsieve_interpreter_run + (const struct sieve_extension *this_ext, + const struct sieve_runtime_env *renv, + void *context, bool deferred); + +const struct sieve_interpreter_extension +imapsieve_interpreter_extension = { +#ifdef __IMAPSIEVE_DUMMY + .ext_def = &imapsieve_extension_dummy, +#else + .ext_def = &imapsieve_extension, +#endif + .run = ext_imapsieve_interpreter_run +}; + +static bool ext_imapsieve_interpreter_load +(const struct sieve_extension *ext ATTR_UNUSED, + const struct sieve_runtime_env *renv, + sieve_size_t *address ATTR_UNUSED) +{ + sieve_interpreter_extension_register(renv->interp, + ext, &imapsieve_interpreter_extension, NULL); + return TRUE; +} + +#ifdef __IMAPSIEVE_DUMMY +static int ext_imapsieve_interpreter_run +(const struct sieve_extension *ext ATTR_UNUSED, + const struct sieve_runtime_env *renv, + void *context ATTR_UNUSED, bool deferred) +{ + if ( !deferred ) { + sieve_runtime_error(renv, NULL, + "the imapsieve extension cannot be used outside IMAP"); + } + return SIEVE_EXEC_FAILURE; +} +#else +static int ext_imapsieve_interpreter_run +(const struct sieve_extension *ext, + const struct sieve_runtime_env *renv, + void *context ATTR_UNUSED, bool deferred ATTR_UNUSED) +{ + if (ext->def == &vnd_imapsieve_extension) { + const struct sieve_extension *ims_ext = + (const struct sieve_extension *)ext->context; + ext_imapsieve_environment_vendor_items_register(ims_ext, renv); + } else { + ext_imapsieve_environment_items_register(ext, renv); + } + return SIEVE_EXEC_OK; +} +#endif diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.c b/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.c new file mode 100644 index 0000000..0c9b52e --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.c @@ -0,0 +1,60 @@ +/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file */ + +#include "imap-common.h" +#include "str.h" + +#include "imap-sieve.h" +#include "imap-sieve-storage.h" + +#include "imap-sieve-plugin.h" + +static struct module *imap_sieve_module; +static imap_client_created_func_t *next_hook_client_created; + +/* + * Client + */ + +static void imap_sieve_client_created(struct client **clientp) +{ + struct client *client = *clientp; + struct mail_user *user = client->user; + const char *url = NULL; + + if (mail_user_is_plugin_loaded(user, imap_sieve_module)) { + url = mail_user_plugin_getenv(user, "imapsieve_url"); + // FIXME: parse the URL and report error if it is bad + if (url != NULL && strncasecmp(url, "sieve:", 6) == 0) { + client_add_capability(client, t_strconcat( + "IMAPSIEVE=", url, NULL)); + } else { + url = NULL; + } + + imap_sieve_storage_client_created(client, (url != NULL)); + } + + if (next_hook_client_created != NULL) + next_hook_client_created(clientp); +} + +/* + * Plugin + */ + +const char *imap_sieve_plugin_version = DOVECOT_ABI_VERSION; +const char imap_sieve_plugin_binary_dependency[] = "imap"; + +void imap_sieve_plugin_init(struct module *module) +{ + imap_sieve_module = module; + next_hook_client_created = + imap_client_created_hook_set(imap_sieve_client_created); + imap_sieve_storage_init(module); +} + +void imap_sieve_plugin_deinit(void) +{ + imap_sieve_storage_deinit(); + imap_client_created_hook_set(next_hook_client_created); +} diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.h b/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.h new file mode 100644 index 0000000..0271710 --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.h @@ -0,0 +1,11 @@ +#ifndef IMAP_SIEVE_PLUGIN_H +#define IMAP_SIEVE_PLUGIN_H + +struct module; + +extern const char imap_sieve_plugin_binary_dependency[]; + +void imap_sieve_plugin_init(struct module *module); +void imap_sieve_plugin_deinit(void); + +#endif diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.c b/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.c new file mode 100644 index 0000000..f8e5efe --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.c @@ -0,0 +1,1273 @@ +/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file */ + +#include "imap-common.h" +#include "array.h" +#include "hash.h" +#include "str.h" +#include "istream.h" +#include "ostream.h" +#include "module-context.h" +#include "mail-user.h" +#include "mail-storage-private.h" +#include "mailbox-attribute.h" +#include "mailbox-list-private.h" +#include "imap-match.h" +#include "imap-util.h" + +#include "imap-sieve.h" +#include "imap-sieve-storage.h" + +#define MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT "imapsieve/script" +#define MAIL_SERVER_ATTRIBUTE_IMAPSIEVE_SCRIPT "imapsieve/script" + +#define IMAP_SIEVE_USER_CONTEXT(obj) \ + MODULE_CONTEXT(obj, imap_sieve_user_module) +#define IMAP_SIEVE_USER_CONTEXT_REQUIRE(obj) \ + MODULE_CONTEXT_REQUIRE(obj, imap_sieve_user_module) +#define IMAP_SIEVE_CONTEXT(obj) \ + MODULE_CONTEXT(obj, imap_sieve_storage_module) +#define IMAP_SIEVE_CONTEXT_REQUIRE(obj) \ + MODULE_CONTEXT_REQUIRE(obj, imap_sieve_storage_module) +#define IMAP_SIEVE_MAIL_CONTEXT(obj) \ + MODULE_CONTEXT_REQUIRE(obj, imap_sieve_mail_module) + +struct imap_sieve_mailbox_rule; +struct imap_sieve_user; +struct imap_sieve_mailbox_event; +struct imap_sieve_mailbox_transaction; +struct imap_sieve_mail; + +enum imap_sieve_command { + IMAP_SIEVE_CMD_NONE = 0, + IMAP_SIEVE_CMD_APPEND, + IMAP_SIEVE_CMD_COPY, + IMAP_SIEVE_CMD_MOVE, + IMAP_SIEVE_CMD_STORE, + IMAP_SIEVE_CMD_OTHER +}; + +ARRAY_DEFINE_TYPE(imap_sieve_mailbox_rule, + struct imap_sieve_mailbox_rule *); +ARRAY_DEFINE_TYPE(imap_sieve_mailbox_event, + struct imap_sieve_mailbox_event); + +HASH_TABLE_DEFINE_TYPE(imap_sieve_mailbox_rule, + struct imap_sieve_mailbox_rule *, + struct imap_sieve_mailbox_rule *); + +struct imap_sieve_mailbox_rule { + unsigned int index; + const char *mailbox; + const char *from; + const char *const *causes; + const char *before, *after; + const char *copy_source_after; +}; + +struct imap_sieve_user { + union mail_user_module_context module_ctx; + struct client *client; + struct imap_sieve *isieve; + + enum imap_sieve_command cur_cmd; + + HASH_TABLE_TYPE(imap_sieve_mailbox_rule) mbox_rules; + ARRAY_TYPE(imap_sieve_mailbox_rule) mbox_patterns; + + bool sieve_active:1; + bool user_script:1; + bool expunge_discarded:1; +}; + +struct imap_sieve_mailbox_event { + uint32_t dest_mail_uid, src_mail_uid; + unsigned int save_seq; + + const char *changed_flags; +}; + +struct imap_sieve_mailbox_transaction { + pool_t pool; + + union mailbox_transaction_module_context module_ctx; + + struct mailbox *src_box; + struct mailbox_transaction_context *src_mail_trans; + + ARRAY_TYPE(imap_sieve_mailbox_event) events; +}; + +struct imap_sieve_mail { + union mail_module_context module_ctx; + + string_t *flags; +}; + +static MODULE_CONTEXT_DEFINE_INIT(imap_sieve_user_module, + &mail_user_module_register); +static MODULE_CONTEXT_DEFINE_INIT(imap_sieve_storage_module, + &mail_storage_module_register); +static MODULE_CONTEXT_DEFINE_INIT(imap_sieve_mail_module, + &mail_module_register); + +static void +imap_sieve_mailbox_rules_get(struct mail_user *user, + struct mailbox *dst_box, struct mailbox *src_box, + const char *cause, + ARRAY_TYPE(imap_sieve_mailbox_rule) *rules); + +/* + * Logging + */ + +static inline void +imap_sieve_debug(struct mail_user *user, + const char *format, ...) ATTR_FORMAT(2, 3); +static inline void +imap_sieve_debug(struct mail_user *user, + const char *format, ...) +{ + va_list args; + + if (user->mail_debug) { + va_start(args, format); + i_debug("imapsieve: %s", + t_strdup_vprintf(format, args)); + va_end(args); + } +} + +static inline void +imap_sieve_warning(struct mail_user *user ATTR_UNUSED, + const char *format, ...) ATTR_FORMAT(2, 3); +static inline void +imap_sieve_warning(struct mail_user *user ATTR_UNUSED, + const char *format, ...) +{ + va_list args; + + va_start(args, format); + i_warning("imapsieve: %s", + t_strdup_vprintf(format, args)); + va_end(args); +} + +static inline void +imap_sieve_mailbox_debug(struct mailbox *box, + const char *format, ...) ATTR_FORMAT(2, 3); +static inline void +imap_sieve_mailbox_debug(struct mailbox *box, + const char *format, ...) +{ + va_list args; + + if (box->storage->user->mail_debug) { + va_start(args, format); + i_debug("imapsieve: mailbox %s: %s", + mailbox_get_vname(box), + t_strdup_vprintf(format, args)); + va_end(args); + } +} + +static inline void +imap_sieve_mailbox_warning(struct mailbox *box, + const char *format, ...) ATTR_FORMAT(2, 3); +static inline void +imap_sieve_mailbox_warning(struct mailbox *box, + const char *format, ...) +{ + va_list args; + + va_start(args, format); + i_warning("imapsieve: mailbox %s: %s", + mailbox_get_vname(box), + t_strdup_vprintf(format, args)); + va_end(args); +} + +static inline void +imap_sieve_mailbox_error(struct mailbox *box, + const char *format, ...) ATTR_FORMAT(2, 3); +static inline void +imap_sieve_mailbox_error(struct mailbox *box, + const char *format, ...) +{ + va_list args; + + va_start(args, format); + i_error("imapsieve: mailbox %s: %s", + mailbox_get_vname(box), + t_strdup_vprintf(format, args)); + va_end(args); +} + +/* + * Events + */ + +static int imap_sieve_mailbox_get_script_real +(struct mailbox *box, + const char **script_name_r) +{ + struct mail_user *user = box->storage->user; + struct mail_attribute_value value; + int ret; + + *script_name_r = NULL; + + /* get the name of the Sieve script from mailbox METADATA */ + if ((ret=mailbox_attribute_get(box, MAIL_ATTRIBUTE_TYPE_SHARED, + MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT, &value)) < 0) { + imap_sieve_mailbox_error(box, + "Failed to read /shared/" + MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT" " + "mailbox attribute: %s", + mailbox_get_last_internal_error(box, NULL)); + return -1; + } + + if (ret > 0) { + imap_sieve_mailbox_debug(box, + "Mailbox attribute /shared/" + MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT" " + "points to Sieve script `%s'", value.value); + + /* if not found, get the name of the Sieve script from + server METADATA */ + } else { + struct mail_namespace *ns; + struct mailbox *inbox; + + imap_sieve_mailbox_debug(box, + "Mailbox attribute /shared/" + MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT" " + "not found"); + + ns = mail_namespace_find_inbox(user->namespaces); + inbox = mailbox_alloc(ns->list, "INBOX", + MAILBOX_FLAG_READONLY); + ret = mailbox_attribute_get(inbox, + MAIL_ATTRIBUTE_TYPE_SHARED, + MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER + MAILBOX_ATTRIBUTE_IMAPSIEVE_SCRIPT, &value); + + if (ret <= 0) { + if (ret < 0) { + imap_sieve_mailbox_error(box, + "Failed to read /shared/" + MAIL_SERVER_ATTRIBUTE_IMAPSIEVE_SCRIPT" " + "server attribute: %s", + mailbox_get_last_internal_error(inbox, NULL)); + } else if (ret == 0) { + imap_sieve_mailbox_debug(box, + "Server attribute /shared/" + MAIL_SERVER_ATTRIBUTE_IMAPSIEVE_SCRIPT" " + "not found"); + } + mailbox_free(&inbox); + return ret; + } + mailbox_free(&inbox); + + imap_sieve_mailbox_debug(box, + "Server attribute /shared/" + MAIL_SERVER_ATTRIBUTE_IMAPSIEVE_SCRIPT" " + "points to Sieve script `%s'", value.value); + } + + *script_name_r = value.value; + return 1; +} + +static int imap_sieve_mailbox_get_script +(struct mailbox *box, const char **script_name_r) +{ + int ret; + + ret = imap_sieve_mailbox_get_script_real + (box, script_name_r); + return ret; +} + +static struct imap_sieve_mailbox_event * +imap_sieve_create_mailbox_event +(struct mailbox_transaction_context *t, struct mail *dest_mail) +{ + struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT_REQUIRE(t); + struct imap_sieve_mailbox_event *event; + + if (!array_is_created(&ismt->events)) + i_array_init(&ismt->events, 64); + + event = array_append_space(&ismt->events); + event->save_seq = t->save_count; + event->dest_mail_uid = dest_mail->uid; + return event; +} + +static void imap_sieve_add_mailbox_event +(struct mailbox_transaction_context *t, + struct mail *dest_mail, struct mailbox *src_box, + const char *changed_flags) +{ + struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT_REQUIRE(t); + struct imap_sieve_mailbox_event *event; + + i_assert(ismt->src_box == NULL || ismt->src_box == src_box); + ismt->src_box = src_box; + + event = imap_sieve_create_mailbox_event(t, dest_mail); + event->changed_flags = p_strdup(ismt->pool, changed_flags); +} + +static void imap_sieve_add_mailbox_copy_event +(struct mailbox_transaction_context *t, + struct mail *dest_mail, struct mail *src_mail) +{ + struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT_REQUIRE(t); + struct imap_sieve_mailbox_event *event; + + i_assert(ismt->src_box == NULL || ismt->src_box == src_mail->box); + i_assert(ismt->src_mail_trans == NULL || + ismt->src_mail_trans == src_mail->transaction); + + ismt->src_box = src_mail->box; + ismt->src_mail_trans = src_mail->transaction; + + event = imap_sieve_create_mailbox_event(t, dest_mail); + event->src_mail_uid = src_mail->uid; +} + +/* + * Mail + */ + +static void +imap_sieve_mail_update_flags(struct mail *_mail, + enum modify_type modify_type, enum mail_flags flags) +{ + struct mail_private *mail = (struct mail_private *)_mail; + struct imap_sieve_mail *ismail = IMAP_SIEVE_MAIL_CONTEXT(mail); + enum mail_flags old_flags, new_flags, changed_flags; + + old_flags = mail_get_flags(_mail); + ismail->module_ctx.super.update_flags(_mail, modify_type, flags); + new_flags = mail_get_flags(_mail); + + changed_flags = old_flags ^ new_flags; + if (changed_flags == 0) + return; + + if (ismail->flags == NULL) + ismail->flags = str_new(default_pool, 64); + imap_write_flags(ismail->flags, changed_flags, NULL); +} + +static void +imap_sieve_mail_update_keywords(struct mail *_mail, + enum modify_type modify_type, struct mail_keywords *keywords) +{ + struct mail_private *mail = (struct mail_private *)_mail; + struct imap_sieve_mail *ismail = IMAP_SIEVE_MAIL_CONTEXT(mail); + const char *const *old_keywords, *const *new_keywords; + unsigned int i, j; + + old_keywords = mail_get_keywords(_mail); + ismail->module_ctx.super.update_keywords(_mail, modify_type, keywords); + new_keywords = mail_get_keywords(_mail); + + if (ismail->flags == NULL) + ismail->flags = str_new(default_pool, 64); + + /* Removed flags */ + for (i = 0; old_keywords[i] != NULL; i++) { + for (j = 0; new_keywords[j] != NULL; j++) { + if (strcmp(old_keywords[i], new_keywords[j]) == 0) + break; + } + if (new_keywords[j] == NULL) { + if (str_len(ismail->flags) > 0) + str_append_c(ismail->flags, ' '); + str_append(ismail->flags, old_keywords[i]); + } + } + + /* Added flags */ + for (i = 0; new_keywords[i] != NULL; i++) { + for (j = 0; old_keywords[j] != NULL; j++) { + if (strcmp(new_keywords[i], old_keywords[j]) == 0) + break; + } + if (old_keywords[j] == NULL) { + if (str_len(ismail->flags) > 0) + str_append_c(ismail->flags, ' '); + str_append(ismail->flags, new_keywords[i]); + } + } +} + +static void imap_sieve_mail_close(struct mail *_mail) +{ + struct mail_private *mail = (struct mail_private *)_mail; + struct mailbox_transaction_context *t = _mail->transaction; + struct imap_sieve_mail *ismail = IMAP_SIEVE_MAIL_CONTEXT(mail); + + if (ismail->flags != NULL && str_len(ismail->flags) > 0) { + if (!_mail->expunged) { + imap_sieve_mailbox_debug(_mail->box, + "FLAG event (changed flags: %s)", + str_c(ismail->flags)); + + imap_sieve_add_mailbox_event(t, + _mail, _mail->box, str_c(ismail->flags)); + } + str_truncate(ismail->flags, 0); + } + + ismail->module_ctx.super.close(_mail); +} + +static void imap_sieve_mail_free(struct mail *_mail) +{ + struct mail_private *mail = (struct mail_private *)_mail; + struct imap_sieve_mail *ismail = IMAP_SIEVE_MAIL_CONTEXT(mail); + string_t *flags = ismail->flags; + + ismail->module_ctx.super.free(_mail); + + if (flags != NULL) + str_free(&flags); +} + +static void imap_sieve_mail_allocated(struct mail *_mail) +{ + struct mail_private *mail = (struct mail_private *)_mail; + struct imap_sieve_mailbox_transaction *ismt = + IMAP_SIEVE_CONTEXT(_mail->transaction); + struct mail_user *user = _mail->box->storage->user; + struct imap_sieve_user *isuser = + IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + struct mail_vfuncs *v = mail->vlast; + struct imap_sieve_mail *ismail; + + if (ismt == NULL || isuser->sieve_active) + return; + + ismail = p_new(mail->pool, struct imap_sieve_mail, 1); + ismail->module_ctx.super = *v; + mail->vlast = &ismail->module_ctx.super; + + v->close = imap_sieve_mail_close; + v->free = imap_sieve_mail_free; + v->update_flags = imap_sieve_mail_update_flags; + v->update_keywords = imap_sieve_mail_update_keywords; + MODULE_CONTEXT_SET(mail, imap_sieve_mail_module, ismail); +} + +/* + * Save/copy + */ + +static int +imap_sieve_mailbox_copy(struct mail_save_context *ctx, struct mail *mail) +{ + struct mailbox_transaction_context *t = ctx->transaction; + struct mail_storage *storage = t->box->storage; + struct mail_user *user = storage->user; + struct imap_sieve_user *isuser = + IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + union mailbox_module_context *lbox = + IMAP_SIEVE_CONTEXT_REQUIRE(t->box); + struct imap_sieve_mailbox_transaction *ismt = + IMAP_SIEVE_CONTEXT(t); + + if (lbox->super.copy(ctx, mail) < 0) + return -1; + + if (ismt != NULL && !isuser->sieve_active && + !ctx->dest_mail->expunged && + (isuser->cur_cmd == IMAP_SIEVE_CMD_COPY || + isuser->cur_cmd == IMAP_SIEVE_CMD_MOVE)) { + imap_sieve_mailbox_debug(t->box, "%s event", + (isuser->cur_cmd == IMAP_SIEVE_CMD_COPY ? + "COPY" : "MOVE")); + imap_sieve_add_mailbox_copy_event(t, ctx->dest_mail, + ctx->copy_src_mail); + } + + return 0; +} + +static int +imap_sieve_mailbox_save_finish(struct mail_save_context *ctx) +{ + struct mailbox_transaction_context *t = ctx->transaction; + struct mailbox *box = t->box; + struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT(t); + union mailbox_module_context *lbox = IMAP_SIEVE_CONTEXT_REQUIRE(box); + struct mail_user *user = box->storage->user; + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + struct mail *dest_mail = ctx->copying_via_save ? NULL : ctx->dest_mail; + + if (lbox->super.save_finish(ctx) < 0) + return -1; + + if (ismt != NULL && !isuser->sieve_active && + dest_mail != NULL && !dest_mail->expunged && + isuser->cur_cmd == IMAP_SIEVE_CMD_APPEND) { + + imap_sieve_mailbox_debug(t->box, "APPEND event"); + imap_sieve_add_mailbox_event(t, dest_mail, box, NULL); + } + return 0; +} + +/* + * Mailbox + */ + +static struct mailbox_transaction_context * +imap_sieve_mailbox_transaction_begin(struct mailbox *box, + enum mailbox_transaction_flags flags, + const char *reason) +{ + union mailbox_module_context *lbox = IMAP_SIEVE_CONTEXT_REQUIRE(box); + struct mail_user *user = box->storage->user; + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT(user); + struct mailbox_transaction_context *t; + struct imap_sieve_mailbox_transaction *ismt; + pool_t pool; + + /* commence parent transaction */ + t = lbox->super.transaction_begin(box, flags, reason); + + if (isuser == NULL || isuser->sieve_active || + isuser->cur_cmd == IMAP_SIEVE_CMD_NONE) + return t; + + i_assert(isuser->client != NULL); + + pool = pool_alloconly_create("imap_sieve_mailbox_transaction", 1024); + ismt = p_new(pool, struct imap_sieve_mailbox_transaction, 1); + ismt->pool = pool; + MODULE_CONTEXT_SET(t, imap_sieve_storage_module, ismt); + + return t; +} + +static void +imap_sieve_mailbox_transaction_free +(struct imap_sieve_mailbox_transaction *ismt) +{ + if (array_is_created(&ismt->events)) + array_free(&ismt->events); + pool_unref(&ismt->pool); +} + +static void +imap_sieve_mailbox_run_copy_source( + struct imap_sieve_mailbox_transaction *ismt, + struct imap_sieve_run *isrun, + const struct imap_sieve_mailbox_event *mevent, + struct mail **src_mail, bool *fatal_r) +{ + struct mailbox *src_box = ismt->src_box; + int ret; + + *fatal_r = FALSE; + + if (isrun == NULL) + return; + + i_assert(ismt->src_mail_trans->box == src_box); + i_assert(mevent->src_mail_uid > 0); + + if (*src_mail == NULL) + *src_mail = mail_alloc(ismt->src_mail_trans, 0, NULL); + + /* Select source message */ + if (!mail_set_uid(*src_mail, mevent->src_mail_uid)) { + imap_sieve_mailbox_warning(src_box, + "Failed to find source message for Sieve event " + "(UID=%llu)", (unsigned long long)mevent->src_mail_uid); + return; + } + + imap_sieve_mailbox_debug(src_box, + "Running copy_source_after scripts."); + + /* Run scripts for source mail */ + ret = imap_sieve_run_mail(isrun, *src_mail, NULL, fatal_r); + if (ret > 0) { + /* Discard */ + mail_update_flags(*src_mail, MODIFY_ADD, MAIL_DELETED); + } +} + +static int +imap_sieve_mailbox_transaction_run( + struct imap_sieve_mailbox_transaction *ismt, + struct mailbox *dest_box, + struct mail_transaction_commit_changes *changes) +{ + static const char *wanted_headers[] = { + "From", "To", "Message-ID", "Subject", "Return-Path", + NULL + }; + struct mailbox *src_box = ismt->src_box; + struct mail_user *user = dest_box->storage->user; + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + const struct imap_sieve_mailbox_event *mevent; + struct mailbox_header_lookup_ctx *headers_ctx; + struct mailbox_transaction_context *st; + struct mailbox *sbox; + struct imap_sieve_run *isrun, *isrun_src; + struct seq_range_iter siter; + const char *cause, *script_name = NULL; + bool can_discard; + struct mail *mail, *src_mail = NULL; + int ret; + + if (ismt == NULL || !array_is_created(&ismt->events)) { + /* Nothing to do */ + return 0; + } + + i_assert(isuser->client != NULL); + + /* Get user script for this mailbox */ + if (isuser->user_script && imap_sieve_mailbox_get_script + (dest_box, &script_name) < 0) { + return 0; // FIXME: some errors may warrant -1 + } + + /* Make sure IMAPSIEVE is initialized for this user */ + if (isuser->isieve == NULL) + isuser->isieve = imap_sieve_init(isuser->client); + + can_discard = FALSE; + switch (isuser->cur_cmd) { + case IMAP_SIEVE_CMD_APPEND: + cause = "APPEND"; + can_discard = TRUE; + break; + case IMAP_SIEVE_CMD_COPY: + case IMAP_SIEVE_CMD_MOVE: + cause = "COPY"; + can_discard = TRUE; + break; + case IMAP_SIEVE_CMD_STORE: + case IMAP_SIEVE_CMD_OTHER: + cause = "FLAG"; + break; + default: + i_unreached(); + } + + /* Initialize execution */ + T_BEGIN { + ARRAY_TYPE(imap_sieve_mailbox_rule) mbrules; + ARRAY_TYPE(const_string) scripts_before, scripts_after; + ARRAY_TYPE(const_string) scripts_copy_source; + struct imap_sieve_mailbox_rule *rule; + + /* Find matching rules */ + t_array_init(&mbrules, 16); + imap_sieve_mailbox_rules_get + (user, dest_box, src_box, cause, &mbrules); + + /* Apply all matched rules */ + t_array_init(&scripts_before, 8); + t_array_init(&scripts_after, 8); + t_array_init(&scripts_copy_source, 4); + array_foreach_elem(&mbrules, rule) { + if (rule->before != NULL) + array_append(&scripts_before, &rule->before, 1); + if (rule->after != NULL) + array_append(&scripts_after, &rule->after, 1); + if (rule->copy_source_after != NULL) + array_append(&scripts_copy_source, &rule->copy_source_after, 1); + } + (void)array_append_space(&scripts_before); + (void)array_append_space(&scripts_after); + + /* Initialize */ + ret = imap_sieve_run_init + (isuser->isieve, dest_box, src_box, cause, script_name, + array_idx(&scripts_before, 0), + array_idx(&scripts_after, 0), &isrun); + + /* Initialize source script execution */ + isrun_src = NULL; + if (ret > 0 && ismt->src_mail_trans != NULL && + isuser->cur_cmd == IMAP_SIEVE_CMD_COPY && + array_count(&scripts_copy_source) > 0) { + const char *no_scripts = NULL; + + (void)array_append_space(&scripts_copy_source); + if (imap_sieve_run_init(isuser->isieve, + dest_box, src_box, cause, NULL, + &no_scripts, array_idx(&scripts_copy_source, 0), + &isrun_src) <= 0) + isrun_src = NULL; + } + } T_END; + + if (ret <= 0) { + // FIXME: temp fail should be handled properly + return 0; + } + + /* Get synchronized view on the destination mailbox */ + sbox = mailbox_alloc(dest_box->list, dest_box->vname, 0); + if (mailbox_sync(sbox, 0) < 0) { + mailbox_free(&sbox); + imap_sieve_run_deinit(&isrun); + if (isrun_src != NULL) + imap_sieve_run_deinit(&isrun_src); + return -1; + } + + /* Create transaction for event messages */ + st = mailbox_transaction_begin(sbox, 0, __func__); + headers_ctx = mailbox_header_lookup_init(sbox, wanted_headers); + mail = mail_alloc(st, 0, headers_ctx); + mailbox_header_lookup_unref(&headers_ctx); + + /* Iterate through all events */ + seq_range_array_iter_init(&siter, &changes->saved_uids); + array_foreach(&ismt->events, mevent) { + uint32_t uid; + bool fatal; + + /* Determine UID for saved message */ + if (mevent->dest_mail_uid > 0) + uid = mevent->dest_mail_uid; + else if (!seq_range_array_iter_nth(&siter, mevent->save_seq, + &uid)) { + /* already gone for some reason */ + imap_sieve_mailbox_debug( + sbox, "Message for Sieve event gone"); + continue; + } + + /* Select event message */ + i_assert(uid > 0); + if (!mail_set_uid(mail, uid) || mail->expunged) { + /* already gone for some reason */ + imap_sieve_mailbox_debug(sbox, + "Message for Sieve event gone (UID=%llu)", + (unsigned long long)uid); + continue; + } + + /* Run scripts for this mail */ + ret = imap_sieve_run_mail(isrun, mail, mevent->changed_flags, + &fatal); + if (fatal) + break; + + /* Handle the result */ + if (ret < 0) { + /* Sieve error; keep */ + } else { + if (ret <= 0 || !can_discard) { + /* Keep */ + } else if (!isuser->expunge_discarded) { + /* Mark as \Deleted */ + mail_update_flags(mail, + MODIFY_ADD, MAIL_DELETED); + } else { + /* Expunge */ + mail_expunge(mail); + } + + imap_sieve_mailbox_run_copy_source( + ismt, isrun_src, mevent, &src_mail, &fatal); + if (fatal) + break; + } + } + + /* Cleanup */ + mail_free(&mail); + ret = mailbox_transaction_commit(&st); + if (src_mail != NULL) + mail_free(&src_mail); + imap_sieve_run_deinit(&isrun); + if (isrun_src != NULL) + imap_sieve_run_deinit(&isrun_src); + mailbox_free(&sbox); + return ret; +} + +static int +imap_sieve_mailbox_transaction_commit( + struct mailbox_transaction_context *t, + struct mail_transaction_commit_changes *changes_r) +{ + struct mailbox *box = t->box; + struct mail_user *user = box->storage->user; + struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT(t); + union mailbox_module_context *lbox = IMAP_SIEVE_CONTEXT_REQUIRE(t->box); + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + int ret = 0; + + if ((lbox->super.transaction_commit(t, changes_r)) < 0) + ret = -1; + else if (ismt != NULL) { + isuser->sieve_active = TRUE; + if (imap_sieve_mailbox_transaction_run + (ismt, box, changes_r) < 0) + ret = -1; + isuser->sieve_active = FALSE; + } + + if (ismt != NULL) + imap_sieve_mailbox_transaction_free(ismt); + return ret; +} + +static void +imap_sieve_mailbox_transaction_rollback( + struct mailbox_transaction_context *t) +{ + struct imap_sieve_mailbox_transaction *ismt = IMAP_SIEVE_CONTEXT(t); + union mailbox_module_context *lbox = IMAP_SIEVE_CONTEXT_REQUIRE(t->box); + + lbox->super.transaction_rollback(t); + + if (ismt != NULL) + imap_sieve_mailbox_transaction_free(ismt); +} + +static void imap_sieve_mailbox_allocated(struct mailbox *box) +{ + struct mail_user *user = box->storage->user; + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + struct mailbox_vfuncs *v = box->vlast; + union mailbox_module_context *lbox; + + if (isuser->client == NULL || isuser->sieve_active || + (box->flags & MAILBOX_FLAG_READONLY) != 0) + return; + + lbox = p_new(box->pool, union mailbox_module_context, 1); + lbox->super = *v; + box->vlast = &lbox->super; + + v->copy = imap_sieve_mailbox_copy; + v->save_finish = imap_sieve_mailbox_save_finish; + v->transaction_begin = imap_sieve_mailbox_transaction_begin; + v->transaction_commit = imap_sieve_mailbox_transaction_commit; + v->transaction_rollback = imap_sieve_mailbox_transaction_rollback; + MODULE_CONTEXT_SET_SELF(box, imap_sieve_storage_module, lbox); +} + +/* + * Mailbox rules + */ + +static unsigned int imap_sieve_mailbox_rule_hash +(const struct imap_sieve_mailbox_rule *rule) +{ + unsigned int hash = str_hash(rule->mailbox); + + if (rule->from != NULL) + hash += str_hash(rule->from); + return hash; +} + +static int imap_sieve_mailbox_rule_cmp +(const struct imap_sieve_mailbox_rule *rule1, + const struct imap_sieve_mailbox_rule *rule2) +{ + int ret; + + if ((ret=strcmp(rule1->mailbox, rule2->mailbox)) != 0) + return ret; + return null_strcmp(rule1->from, rule2->from); +} + +static bool rule_pattern_has_wildcards(const char *pattern) +{ + for (; *pattern != '\0'; pattern++) { + if (*pattern == '%' || *pattern == '*') + return TRUE; + } + return FALSE; +} + +static void +imap_sieve_mailbox_rules_init(struct mail_user *user) +{ + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + string_t *identifier; + unsigned int i = 0; + size_t prefix_len; + + if (hash_table_is_created(isuser->mbox_rules)) + return; + + hash_table_create(&isuser->mbox_rules, default_pool, 0, + imap_sieve_mailbox_rule_hash, imap_sieve_mailbox_rule_cmp); + i_array_init(&isuser->mbox_patterns, 8); + + identifier = t_str_new(256); + str_append(identifier, "imapsieve_mailbox"); + prefix_len = str_len(identifier); + + for (i = 1; ; i++) { + struct imap_sieve_mailbox_rule *mbrule; + const char *setval; + size_t id_len; + + str_truncate(identifier, prefix_len); + str_printfa(identifier, "%u", i); + id_len = str_len(identifier); + + str_append(identifier, "_name"); + setval = mail_user_plugin_getenv + (user, str_c(identifier)); + if (setval == NULL || *setval == '\0') + break; + setval = t_str_trim(setval, "\t "); + if (strcasecmp(setval, "INBOX") == 0) + setval = t_str_ucase(setval); + + mbrule = p_new(user->pool, + struct imap_sieve_mailbox_rule, 1); + mbrule->index = i; + mbrule->mailbox = p_strdup(user->pool, setval); + + str_truncate(identifier, id_len); + str_append(identifier, "_from"); + setval = mail_user_plugin_getenv(user, str_c(identifier)); + if (setval != NULL && *setval != '\0') { + setval = t_str_trim(setval, "\t "); + if (strcasecmp(setval, "INBOX") == 0) + setval = t_str_ucase(setval); + mbrule->from = p_strdup(user->pool, setval); + if (strcmp(mbrule->from, "*") == 0) + mbrule->from = NULL; + } + + if ((strcmp(mbrule->mailbox, "*") == 0 || + !rule_pattern_has_wildcards(mbrule->mailbox)) && + (mbrule->from == NULL || + !rule_pattern_has_wildcards(mbrule->from)) && + hash_table_lookup(isuser->mbox_rules, mbrule) != NULL) { + imap_sieve_warning(user, + "Duplicate static mailbox rule [%u] for mailbox `%s' " + "(skipped)", i, mbrule->mailbox); + continue; + } + + str_truncate(identifier, id_len); + str_append(identifier, "_causes"); + setval = mail_user_plugin_getenv(user, str_c(identifier)); + if (setval != NULL && *setval != '\0') { + const char *const *cause; + + mbrule->causes = (const char *const *) + p_strsplit_spaces(user->pool, setval, " \t,"); + + for (cause = mbrule->causes; *cause != NULL; cause++) { + if (!imap_sieve_event_cause_valid(*cause)) + break; + } + if (*cause != NULL) { + imap_sieve_warning(user, + "Static mailbox rule [%u] has invalid event cause `%s' " + "(skipped)", i, *cause); + continue; + } + } + + str_truncate(identifier, id_len); + str_append(identifier, "_before"); + setval = mail_user_plugin_getenv(user, str_c(identifier)); + mbrule->before = p_strdup_empty(user->pool, setval); + + str_truncate(identifier, id_len); + str_append(identifier, "_after"); + setval = mail_user_plugin_getenv(user, str_c(identifier)); + mbrule->after = p_strdup_empty(user->pool, setval); + + str_truncate(identifier, id_len); + str_append(identifier, "_copy_source_after"); + setval = mail_user_plugin_getenv(user, str_c(identifier)); + mbrule->copy_source_after = p_strdup_empty(user->pool, setval); + + if (user->mail_debug) { + imap_sieve_debug(user, "Static mailbox rule [%u]: " + "mailbox=`%s' from=`%s' causes=(%s) => " + "before=%s after=%s%s", + mbrule->index, mbrule->mailbox, + (mbrule->from == NULL ? "*" : mbrule->from), + t_strarray_join(mbrule->causes, " "), + (mbrule->before == NULL ? "(none)" : + t_strconcat("`", mbrule->before, "'", NULL)), + (mbrule->after == NULL ? "(none)" : + t_strconcat("`", mbrule->after, "'", NULL)), + (mbrule->copy_source_after == NULL ? "": + t_strconcat(" copy_source_after=`", + mbrule->copy_source_after, "'", NULL))); + } + + if ((strcmp(mbrule->mailbox, "*") == 0 || + !rule_pattern_has_wildcards(mbrule->mailbox)) && + (mbrule->from == NULL || + !rule_pattern_has_wildcards(mbrule->from))) { + hash_table_insert(isuser->mbox_rules, mbrule, mbrule); + } else { + array_append(&isuser->mbox_patterns, &mbrule, 1); + } + } + + if (i == 0) + imap_sieve_debug(user, "No static mailbox rules"); +} + +static bool +imap_sieve_mailbox_rule_match_cause +(struct imap_sieve_mailbox_rule *rule, const char *cause) +{ + const char *const *cp; + + if (rule->causes == NULL || *rule->causes == NULL) + return TRUE; + + for (cp = rule->causes; *cp != NULL; cp++) { + if (strcasecmp(cause, *cp) == 0) + return TRUE; + } + return FALSE; +} + +static void +imap_sieve_mailbox_rules_match_patterns(struct mail_user *user, + struct mailbox *dst_box, struct mailbox *src_box, + const char *cause, + ARRAY_TYPE(imap_sieve_mailbox_rule) *rules) +{ + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + struct imap_sieve_mailbox_rule *rule; + struct mail_namespace *dst_ns, *src_ns; + + if (array_count(&isuser->mbox_patterns) == 0) + return; + + dst_ns = mailbox_get_namespace(dst_box); + src_ns = (src_box == NULL ? NULL : + mailbox_get_namespace(src_box)); + + array_foreach_elem(&isuser->mbox_patterns, rule) { + struct imap_match_glob *glob; + + if (src_ns == NULL && rule->from != NULL) + continue; + if (!imap_sieve_mailbox_rule_match_cause(rule, cause)) + continue; + + if (strcmp(rule->mailbox, "*") != 0) { + glob = imap_match_init(pool_datastack_create(), + rule->mailbox, TRUE, mail_namespace_get_sep(dst_ns)); + if (imap_match(glob, mailbox_get_vname(dst_box)) + != IMAP_MATCH_YES) + continue; + } + if (rule->from != NULL) { + glob = imap_match_init(pool_datastack_create(), + rule->from, TRUE, mail_namespace_get_sep(src_ns)); + if (imap_match(glob, mailbox_get_vname(src_box)) + != IMAP_MATCH_YES) + continue; + } + + imap_sieve_debug(user, + "Matched static mailbox rule [%u]", + rule->index); + array_append(rules, &rule, 1); + } +} + +static void +imap_sieve_mailbox_rules_match(struct mail_user *user, + const char *dst_box, const char *src_box, + const char *cause, + ARRAY_TYPE(imap_sieve_mailbox_rule) *rules) +{ + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + struct imap_sieve_mailbox_rule lookup_rule; + struct imap_sieve_mailbox_rule *rule; + + i_zero(&lookup_rule); + lookup_rule.mailbox = dst_box; + lookup_rule.from = src_box; + rule = hash_table_lookup(isuser->mbox_rules, &lookup_rule); + + if (rule != NULL && + imap_sieve_mailbox_rule_match_cause(rule, cause)) { + struct imap_sieve_mailbox_rule *const *rule_idx; + unsigned int insert_idx = array_count(rules); + + /* Insert sorted by rule index */ + array_foreach(rules, rule_idx) { + if (rule->index < (*rule_idx)->index) { + insert_idx = array_foreach_idx(rules, rule_idx); + break; + } + } + array_insert(rules, insert_idx, &rule, 1); + + imap_sieve_debug(user, + "Matched static mailbox rule [%u]", + rule->index); + } +} + +static void +imap_sieve_mailbox_rules_get(struct mail_user *user, + struct mailbox *dst_box, struct mailbox *src_box, + const char *cause, + ARRAY_TYPE(imap_sieve_mailbox_rule) *rules) +{ + const char *dst_name, *src_name; + + imap_sieve_mailbox_rules_init(user); + + imap_sieve_mailbox_rules_match_patterns + (user, dst_box, src_box, cause, rules); + + dst_name = mailbox_get_vname(dst_box); + src_name = (src_box == NULL ? NULL : + mailbox_get_vname(src_box)); + + imap_sieve_mailbox_rules_match + (user, dst_name, src_name, cause, rules); + imap_sieve_mailbox_rules_match + (user, "*", src_name, cause, rules); + if (src_name != NULL) { + imap_sieve_mailbox_rules_match + (user, dst_name, NULL, cause, rules); + imap_sieve_mailbox_rules_match + (user, "*", NULL, cause, rules); + } +} + +/* + * User + */ + +static void imap_sieve_user_deinit(struct mail_user *user) +{ + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + + if (isuser->isieve != NULL) + imap_sieve_deinit(&isuser->isieve); + + hash_table_destroy(&isuser->mbox_rules); + if (array_is_created(&isuser->mbox_patterns)) + array_free(&isuser->mbox_patterns); + + isuser->module_ctx.super.deinit(user); +} + +static void imap_sieve_user_created(struct mail_user *user) +{ + struct imap_sieve_user *isuser; + struct mail_user_vfuncs *v = user->vlast; + + isuser = p_new(user->pool, struct imap_sieve_user, 1); + isuser->module_ctx.super = *v; + user->vlast = &isuser->module_ctx.super; + v->deinit = imap_sieve_user_deinit; + MODULE_CONTEXT_SET(user, imap_sieve_user_module, isuser); +} + +/* + * Hooks + */ + +static struct mail_storage_hooks imap_sieve_mail_storage_hooks = { + .mail_user_created = imap_sieve_user_created, + .mailbox_allocated = imap_sieve_mailbox_allocated, + .mail_allocated = imap_sieve_mail_allocated +}; + +/* + * Commands + */ + +static void imap_sieve_command_pre(struct client_command_context *cmd) +{ + struct client *client = cmd->client; + struct mail_user *user = client->user; + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT(user); + + if (isuser == NULL) + return; + + if (strcasecmp(cmd->name, "APPEND") == 0) { + isuser->cur_cmd = IMAP_SIEVE_CMD_APPEND; + } else if (strcasecmp(cmd->name, "COPY") == 0 || + strcasecmp(cmd->name, "UID COPY") == 0) { + isuser->cur_cmd = IMAP_SIEVE_CMD_COPY; + } else if (strcasecmp(cmd->name, "MOVE") == 0 || + strcasecmp(cmd->name, "UID MOVE") == 0) { + isuser->cur_cmd = IMAP_SIEVE_CMD_MOVE; + } else if (strcasecmp(cmd->name, "STORE") == 0 || + strcasecmp(cmd->name, "UID STORE") == 0) { + isuser->cur_cmd = IMAP_SIEVE_CMD_STORE; + } else { + isuser->cur_cmd = IMAP_SIEVE_CMD_OTHER; + } +} + +static void imap_sieve_command_post(struct client_command_context *cmd) +{ + struct client *client = cmd->client; + struct mail_user *user = client->user; + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT(user); + + if (isuser == NULL) + return; + isuser->cur_cmd = IMAP_SIEVE_CMD_NONE; +} + +/* + * Client + */ + +void imap_sieve_storage_client_created(struct client *client, + bool user_script) +{ + struct mail_user *user = client->user; + struct imap_sieve_user *isuser = IMAP_SIEVE_USER_CONTEXT_REQUIRE(user); + const char *set; + + isuser->client = client; + isuser->user_script = user_script; + + set = mail_user_plugin_getenv(user, "imapsieve_expunge_discarded"); + isuser->expunge_discarded = + (set != NULL && strcasecmp(set, "yes") == 0); +} + +/* + * + */ + +void imap_sieve_storage_init(struct module *module) +{ + command_hook_register(imap_sieve_command_pre, imap_sieve_command_post); + mail_storage_hooks_add(module, &imap_sieve_mail_storage_hooks); +} + +void imap_sieve_storage_deinit(void) +{ + mail_storage_hooks_remove(&imap_sieve_mail_storage_hooks); + command_hook_unregister(imap_sieve_command_pre, imap_sieve_command_post); +} diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.h b/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.h new file mode 100644 index 0000000..f96860f --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/imap-sieve-storage.h @@ -0,0 +1,10 @@ +#ifndef IMAP_SIEVE_STORAGE_H +#define IMAP_SIEVE_STORAGE_H + +void imap_sieve_storage_init(struct module *module); +void imap_sieve_storage_deinit(void); + +void imap_sieve_storage_client_created(struct client *client, + bool user_script); + +#endif diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve.c b/pigeonhole/src/plugins/imapsieve/imap-sieve.c new file mode 100644 index 0000000..e6cc24a --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/imap-sieve.c @@ -0,0 +1,940 @@ +/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "home-expand.h" +#include "smtp-address.h" +#include "smtp-submit.h" +#include "mail-storage.h" +#include "mail-user.h" +#include "mail-duplicate.h" +#include "iostream-ssl.h" +#include "imap-client.h" +#include "imap-settings.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "ext-imapsieve-common.h" + +#include "imap-sieve.h" + +/* + * Configuration + */ + +#define DUPLICATE_DB_NAME "lda-dupes" +#define IMAP_SIEVE_MAX_USER_ERRORS 30 + +/* + * IMAP Sieve + */ + +struct imap_sieve { + pool_t pool; + struct client *client; + const char *home_dir; + + struct sieve_instance *svinst; + struct sieve_storage *storage; + + const struct sieve_extension *ext_imapsieve; + const struct sieve_extension *ext_vnd_imapsieve; + + struct mail_duplicate_db *dup_db; + + struct sieve_error_handler *master_ehandler; +}; + +static const char * +mail_sieve_get_setting(void *context, const char *identifier) +{ + struct imap_sieve *isieve = context; + struct mail_user *user = isieve->client->user; + + return mail_user_plugin_getenv(user, identifier); +} + +static const struct sieve_callbacks mail_sieve_callbacks = { + NULL, + mail_sieve_get_setting +}; + +struct imap_sieve *imap_sieve_init(struct client *client) +{ + struct sieve_environment svenv; + struct imap_sieve *isieve; + struct mail_user *user = client->user; + const struct mail_storage_settings *mail_set = + mail_user_set_get_storage_set(user); + bool debug = user->mail_debug; + pool_t pool; + + pool = pool_alloconly_create("imap_sieve", 256); + isieve = p_new(pool, struct imap_sieve, 1); + isieve->pool = pool; + isieve->client = client; + + isieve->dup_db = mail_duplicate_db_init(user, DUPLICATE_DB_NAME); + + i_zero(&svenv); + svenv.username = user->username; + (void)mail_user_get_home(user, &svenv.home_dir); + svenv.hostname = mail_set->hostname; + svenv.base_dir = user->set->base_dir; + svenv.event_parent = client->event; + svenv.flags = SIEVE_FLAG_HOME_RELATIVE; + svenv.location = SIEVE_ENV_LOCATION_MS; + svenv.delivery_phase = SIEVE_DELIVERY_PHASE_POST; + + isieve->home_dir = p_strdup(pool, svenv.home_dir); + + isieve->svinst = sieve_init(&svenv, &mail_sieve_callbacks, isieve, + debug); + + isieve->ext_imapsieve = sieve_extension_replace( + isieve->svinst, &imapsieve_extension, TRUE); + isieve->ext_vnd_imapsieve = sieve_extension_replace( + isieve->svinst, &vnd_imapsieve_extension, TRUE); + + isieve->master_ehandler = + sieve_master_ehandler_create(isieve->svinst, 0); + sieve_error_handler_accept_infolog(isieve->master_ehandler, TRUE); + sieve_error_handler_accept_debuglog(isieve->master_ehandler, debug); + + return isieve; +} + +void imap_sieve_deinit(struct imap_sieve **_isieve) +{ + struct imap_sieve *isieve = *_isieve; + + *_isieve = NULL; + + sieve_error_handler_unref(&isieve->master_ehandler); + + if (isieve->storage != NULL) + sieve_storage_unref(&isieve->storage); + sieve_extension_unregister(isieve->ext_imapsieve); + sieve_extension_unregister(isieve->ext_vnd_imapsieve); + sieve_deinit(&isieve->svinst); + + mail_duplicate_db_deinit(&isieve->dup_db); + + pool_unref(&isieve->pool); +} + +static int +imap_sieve_get_storage(struct imap_sieve *isieve, + struct sieve_storage **storage_r) +{ + enum sieve_storage_flags storage_flags = 0; + struct mail_user *user = isieve->client->user; + enum sieve_error error; + + if (isieve->storage != NULL) { + *storage_r = isieve->storage; + return 1; + } + + // FIXME: limit interval between retries + + isieve->storage = sieve_storage_create_main(isieve->svinst, user, + storage_flags, &error); + if (isieve->storage == NULL) { + if (error == SIEVE_ERROR_TEMP_FAILURE) + return -1; + return 0; + } + *storage_r = isieve->storage; + return 1; +} + +/* + * Mail transmission + */ + +static void * +imap_sieve_smtp_start(const struct sieve_script_env *senv, + const struct smtp_address *mail_from) +{ + struct imap_sieve_context *isctx = senv->script_context; + struct imap_sieve *isieve = isctx->isieve; + struct mail_user *user = isieve->client->user; + const struct smtp_submit_settings *smtp_set = isieve->client->smtp_set; + struct ssl_iostream_settings ssl_set; + struct smtp_submit_input submit_input; + + i_zero(&ssl_set); + mail_user_init_ssl_client_settings(user, &ssl_set); + + i_zero(&submit_input); + submit_input.ssl = &ssl_set; + + return smtp_submit_init_simple(&submit_input, smtp_set, mail_from); +} + +static void +imap_sieve_smtp_add_rcpt(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle, const struct smtp_address *rcpt_to) +{ + struct smtp_submit *smtp_submit = handle; + + smtp_submit_add_rcpt(smtp_submit, rcpt_to); +} + +static struct ostream * +imap_sieve_smtp_send(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle) +{ + struct smtp_submit *smtp_submit = handle; + + return smtp_submit_send(smtp_submit); +} + +static void +imap_sieve_smtp_abort(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle) +{ + struct smtp_submit *smtp_submit = handle; + + smtp_submit_deinit(&smtp_submit); +} + +static int +imap_sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle, const char **error_r) +{ + struct smtp_submit *smtp_submit = handle; + int ret; + + ret = smtp_submit_run(smtp_submit, error_r); + smtp_submit_deinit(&smtp_submit); + return ret; +} + +/* + * Duplicate checking + */ + +static void * +imap_sieve_duplicate_transaction_begin(const struct sieve_script_env *senv) +{ + struct imap_sieve_context *isctx = senv->script_context; + + return mail_duplicate_transaction_begin(isctx->isieve->dup_db); +} + +static void imap_sieve_duplicate_transaction_commit(void **_dup_trans) +{ + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + mail_duplicate_transaction_commit(&dup_trans); +} + +static void imap_sieve_duplicate_transaction_rollback(void **_dup_trans) +{ + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + mail_duplicate_transaction_rollback(&dup_trans); +} + +static enum sieve_duplicate_check_result +imap_sieve_duplicate_check(void *_dup_trans, + const struct sieve_script_env *senv, + const void *id, size_t id_size) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + switch (mail_duplicate_check(dup_trans, id, id_size, + senv->user->username)) { + case MAIL_DUPLICATE_CHECK_RESULT_EXISTS: + return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS; + case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND: + return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND; + case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK: + case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT: + return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE; + case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR: + case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS: + break; + } + return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE; +} + +static void +imap_sieve_duplicate_mark(void *_dup_trans, const struct sieve_script_env *senv, + const void *id, size_t id_size, time_t time) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time); +} + +/* + * Result logging + */ + +static const char * +imap_sieve_result_amend_log_message(const struct sieve_script_env *senv, + enum log_type log_type ATTR_UNUSED, + const char *message) +{ + struct imap_sieve_context *isctx = senv->script_context; + string_t *str; + + if (isctx->mail == NULL) + return message; + + str = t_str_new(256); + str_printfa(str, "uid=%u: ", isctx->mail->uid); + str_append(str, message); + return str_c(str); +} + +/* + * IMAP Sieve run + */ + +struct imap_sieve_run_script { + struct sieve_script *script; + struct sieve_binary *binary; + + /* Compile failed once with this error; + don't try again for this transaction */ + enum sieve_error compile_error; + + /* Binary corrupt after recompile; don't recompile again */ + bool binary_corrupt:1; + /* Resource usage exceeded */ + bool rusage_exceeded:1; +}; + +struct imap_sieve_run { + pool_t pool; + struct imap_sieve *isieve; + struct mailbox *dest_mailbox, *src_mailbox; + char *cause; + + struct sieve_error_handler *user_ehandler; + char *userlog; + + struct sieve_trace_config trace_config; + struct sieve_trace_log *trace_log; + + struct sieve_script *user_script; + struct imap_sieve_run_script *scripts; + unsigned int scripts_count; + + bool trace_log_initialized:1; +}; + +static void +imap_sieve_run_init_user_log(struct imap_sieve_run *isrun) +{ + struct imap_sieve *isieve = isrun->isieve; + struct sieve_instance *svinst = isieve->svinst; + const char *log_path; + + log_path = sieve_user_get_log_path(svinst, isrun->user_script); + if (log_path != NULL) { + isrun->userlog = p_strdup(isrun->pool, log_path); + isrun->user_ehandler = sieve_logfile_ehandler_create( + svinst, log_path, IMAP_SIEVE_MAX_USER_ERRORS); + } +} + +static void +imap_sieve_run_init_trace_log(struct imap_sieve_run *isrun, + struct sieve_trace_config *trace_config_r, + struct sieve_trace_log **trace_log_r) +{ + struct imap_sieve *isieve = isrun->isieve; + struct sieve_instance *svinst = isieve->svinst; + struct mail_user *user = isieve->client->user; + + if (isrun->trace_log_initialized) { + *trace_config_r = isrun->trace_config; + *trace_log_r = isrun->trace_log; + return; + } + isrun->trace_log_initialized = TRUE; + + if (sieve_trace_config_get(svinst, &isrun->trace_config) < 0 || + sieve_trace_log_open(svinst, &isrun->trace_log) < 0) { + i_zero(&isrun->trace_config); + isrun->trace_log = NULL; + + i_zero(trace_config_r); + *trace_log_r = NULL; + return; + } + + /* Write header for trace file */ + sieve_trace_log_printf(isrun->trace_log, + "Sieve trace log for IMAPSIEVE:\n" + "\n" + " Username: %s\n", user->username); + if (user->session_id != NULL) { + sieve_trace_log_printf(isrun->trace_log, + " Session ID: %s\n", user->session_id); + } + if (isrun->src_mailbox != NULL) { + sieve_trace_log_printf(isrun->trace_log, + " Source mailbox: %s\n", + mailbox_get_vname(isrun->src_mailbox)); + } + + sieve_trace_log_printf(isrun->trace_log, + " Destination mailbox: %s\n" + " Cause: %s\n\n", + mailbox_get_vname(isrun->dest_mailbox), + isrun->cause); + + *trace_config_r = isrun->trace_config; + *trace_log_r = isrun->trace_log; +} + +int imap_sieve_run_init(struct imap_sieve *isieve, + struct mailbox *dest_mailbox, + struct mailbox *src_mailbox, + const char *cause, const char *script_name, + const char *const *scripts_before, + const char *const *scripts_after, + struct imap_sieve_run **isrun_r) +{ + struct sieve_instance *svinst = isieve->svinst; + struct imap_sieve_run *isrun; + struct sieve_storage *storage; + struct imap_sieve_run_script *scripts; + struct sieve_script *user_script; + const char *const *sp; + enum sieve_error error; + pool_t pool; + unsigned int max_len, count; + int ret; + + /* Determine how many scripts we may run for this event */ + max_len = 0; + if (scripts_before != NULL) + max_len += str_array_length(scripts_before); + if (script_name != NULL) + max_len++; + if (scripts_after != NULL) + max_len += str_array_length(scripts_after); + if (max_len == 0) + return 0; + + /* Get storage for user script */ + storage = NULL; + if (script_name != NULL && *script_name != '\0' && + (ret = imap_sieve_get_storage(isieve, &storage)) < 0) + return ret; + + /* Open all scripts */ + count = 0; + pool = pool_alloconly_create("imap_sieve_run", 256); + scripts = p_new(pool, struct imap_sieve_run_script, max_len); + + /* Admin scripts before user script */ + if (scripts_before != NULL) { + for (sp = scripts_before; *sp != NULL; sp++) { + i_assert(count < max_len); + scripts[count].script = + sieve_script_create_open(svinst, *sp, NULL, + &error); + if (scripts[count].script != NULL) + count++; + else if (error == SIEVE_ERROR_TEMP_FAILURE) + return -1; + } + } + + /* The user script */ + user_script = NULL; + if (storage != NULL) { + i_assert(count < max_len); + scripts[count].script = + sieve_storage_open_script(storage, script_name, &error); + if (scripts[count].script != NULL) { + user_script = scripts[count].script; + count++; + } else if (error == SIEVE_ERROR_TEMP_FAILURE) { + return -1; + } + } + + /* Admin scripts after user script */ + if (scripts_after != NULL) { + for (sp = scripts_after; *sp != NULL; sp++) { + i_assert(count < max_len); + scripts[count].script = + sieve_script_create_open(svinst, *sp, NULL, + &error); + if (scripts[count].script != NULL) + count++; + else if (error == SIEVE_ERROR_TEMP_FAILURE) + return -1; + } + } + + if (count == 0) { + /* None of the scripts could be opened */ + pool_unref(&pool); + return 0; + } + + /* Initialize */ + isrun = p_new(pool, struct imap_sieve_run, 1); + isrun->pool = pool; + isrun->isieve = isieve; + isrun->dest_mailbox = dest_mailbox; + isrun->src_mailbox = src_mailbox; + isrun->cause = p_strdup(pool, cause); + isrun->user_script = user_script; + isrun->scripts = scripts; + isrun->scripts_count = count; + + imap_sieve_run_init_user_log(isrun); + + *isrun_r = isrun; + return 1; +} + +void imap_sieve_run_deinit(struct imap_sieve_run **_isrun) +{ + struct imap_sieve_run *isrun = *_isrun; + unsigned int i; + + *_isrun = NULL; + + for (i = 0; i < isrun->scripts_count; i++) { + if (isrun->scripts[i].binary != NULL) + sieve_close(&isrun->scripts[i].binary); + if (isrun->scripts[i].script != NULL) + sieve_script_unref(&isrun->scripts[i].script); + } + if (isrun->user_ehandler != NULL) + sieve_error_handler_unref(&isrun->user_ehandler); + if (isrun->trace_log != NULL) + sieve_trace_log_free(&isrun->trace_log); + + pool_unref(&isrun->pool); +} + +static struct sieve_binary * +imap_sieve_run_open_script(struct imap_sieve_run *isrun, + struct sieve_script *script, + enum sieve_compile_flags cpflags, + bool recompile, enum sieve_error *error_r) +{ + struct imap_sieve *isieve = isrun->isieve; + struct sieve_instance *svinst = isieve->svinst; + struct sieve_error_handler *ehandler; + struct sieve_binary *sbin; + const char *compile_name = "compile"; + + if (recompile) { + /* Warn */ + e_warning(sieve_get_event(svinst), + "Encountered corrupt binary: re-compiling script %s", + sieve_script_location(script)); + compile_name = "re-compile"; + } else { + e_debug(sieve_get_event(svinst), + "Loading script %s", sieve_script_location(script)); + } + + if (script == isrun->user_script) + ehandler = isrun->user_ehandler; + else + ehandler = isieve->master_ehandler; + sieve_error_handler_reset(ehandler); + + /* Load or compile the sieve script */ + if (recompile) { + sbin = sieve_compile_script(script, ehandler, cpflags, error_r); + } else { + sbin = sieve_open_script(script, ehandler, cpflags, error_r); + } + + /* Handle error */ + if (sbin == NULL) { + switch (*error_r) { + /* Script not found */ + case SIEVE_ERROR_NOT_FOUND: + e_debug(sieve_get_event(svinst), + "Script `%s' is missing for %s", + sieve_script_location(script), compile_name); + break; + /* Temporary failure */ + case SIEVE_ERROR_TEMP_FAILURE: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s " + "(temporary failure)", + sieve_script_location(script), compile_name); + break; + /* Compile failed */ + case SIEVE_ERROR_NOT_VALID: + if (script == isrun->user_script && + isrun->userlog != NULL ) { + e_info(sieve_get_event(svinst), + "Failed to %s script `%s' " + "(view user logfile `%s' for more information)", + compile_name, sieve_script_location(script), + isrun->userlog); + break; + } + e_error(sieve_get_event(svinst), + "Failed to %s script `%s'", + compile_name, sieve_script_location(script)); + break; + /* Cumulative resource limit exceeded */ + case SIEVE_ERROR_RESOURCE_LIMIT: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s " + "(cumulative resource limit exceeded)", + sieve_script_location(script), compile_name); + break; + /* Something else */ + default: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s", + sieve_script_location(script), compile_name); + break; + } + + return NULL; + } + + if (!recompile) + (void)sieve_save(sbin, FALSE, NULL); + return sbin; +} + +static int +imap_sieve_handle_exec_status(struct imap_sieve_run *isrun, + struct sieve_script *script, int status, + struct sieve_exec_status *estatus, bool *fatal_r) + ATTR_NULL(2) +{ + struct imap_sieve *isieve = isrun->isieve; + struct sieve_instance *svinst = isieve->svinst; + const char *userlog_notice = ""; + enum log_type log_level, user_log_level; + enum mail_error mail_error = MAIL_ERROR_NONE; + int ret = -1; + + *fatal_r = FALSE; + + log_level = user_log_level = LOG_TYPE_ERROR; + + if (estatus->last_storage != NULL && estatus->store_failed) { + mail_storage_get_last_error(estatus->last_storage, &mail_error); + + /* Don't bother administrator too much with benign errors */ + if (mail_error == MAIL_ERROR_NOQUOTA) { + log_level = LOG_TYPE_INFO; + user_log_level = LOG_TYPE_INFO; + } + } + + if (script == isrun->user_script && isrun->userlog != NULL) { + userlog_notice = t_strdup_printf( + " (user logfile %s may reveal additional details)", + isrun->userlog); + user_log_level = LOG_TYPE_INFO; + } + + switch (status) { + case SIEVE_EXEC_FAILURE: + e_log(sieve_get_event(svinst), user_log_level, + "Execution of script %s failed%s", + sieve_script_location(script), userlog_notice); + ret = 0; + break; + case SIEVE_EXEC_TEMP_FAILURE: + e_log(sieve_get_event(svinst), log_level, + "Execution of script %s was aborted " + "due to temporary failure%s", + sieve_script_location(script), userlog_notice); + *fatal_r = TRUE; + ret = -1; + break; + case SIEVE_EXEC_BIN_CORRUPT: + e_error(sieve_get_event(svinst), + "!!BUG!!: Binary compiled from %s is still corrupt; " + "bailing out and reverting to default action", + sieve_script_location(script)); + *fatal_r = TRUE; + ret = -1; + break; + case SIEVE_EXEC_RESOURCE_LIMIT: + e_error(sieve_get_event(svinst), + "Execution of script %s was aborted " + "due to excessive resource usage", + sieve_script_location(script)); + *fatal_r = TRUE; + ret = -1; + break; + case SIEVE_EXEC_KEEP_FAILED: + e_log(sieve_get_event(svinst), log_level, + "Execution of script %s failed " + "with unsuccessful implicit keep%s", + sieve_script_location(script), userlog_notice); + ret = 0; + break; + case SIEVE_EXEC_OK: + ret = (estatus->keep_original ? 0 : 1); + break; + } + + return ret; +} + +static int +imap_sieve_run_scripts(struct imap_sieve_run *isrun, + const struct sieve_message_data *msgdata, + const struct sieve_script_env *scriptenv, bool *fatal_r) +{ + struct imap_sieve *isieve = isrun->isieve; + struct sieve_instance *svinst = isieve->svinst; + struct imap_sieve_run_script *scripts = isrun->scripts; + unsigned int count = isrun->scripts_count; + struct sieve_resource_usage *rusage = + &scriptenv->exec_status->resource_usage; + struct sieve_multiscript *mscript; + struct sieve_error_handler *ehandler; + struct sieve_script *last_script = NULL; + bool user_script = FALSE, more = TRUE, rusage_exceeded = FALSE; + enum sieve_compile_flags cpflags; + enum sieve_execute_flags exflags; + enum sieve_error compile_error = SIEVE_ERROR_NONE; + unsigned int i; + int ret; + + *fatal_r = FALSE; + + /* Start execution */ + mscript = sieve_multiscript_start_execute(svinst, msgdata, scriptenv); + + /* Execute scripts */ + for (i = 0; i < count && more; i++) { + struct sieve_script *script = scripts[i].script; + struct sieve_binary *sbin = scripts[i].binary; + int mstatus; + + cpflags = 0; + exflags = SIEVE_EXECUTE_FLAG_NO_ENVELOPE | + SIEVE_EXECUTE_FLAG_SKIP_RESPONSES; + + user_script = (script == isrun->user_script); + last_script = script; + + if (scripts[i].rusage_exceeded) { + rusage_exceeded = TRUE; + break; + } + + sieve_resource_usage_init(rusage); + if (user_script) { + cpflags |= SIEVE_COMPILE_FLAG_NOGLOBAL; + exflags |= SIEVE_EXECUTE_FLAG_NOGLOBAL; + ehandler = isrun->user_ehandler; + } else { + cpflags |= SIEVE_COMPILE_FLAG_NO_ENVELOPE; + ehandler = isieve->master_ehandler; + } + + /* Open */ + if (sbin == NULL) { + e_debug(sieve_get_event(svinst), + "Opening script %d of %d from `%s'", + i+1, count, sieve_script_location(script)); + + /* Already known to fail */ + if (scripts[i].compile_error != SIEVE_ERROR_NONE) { + compile_error = scripts[i].compile_error; + break; + } + + /* Try to open/compile binary */ + scripts[i].binary = sbin = imap_sieve_run_open_script( + isrun, script, cpflags, FALSE, &compile_error); + if (sbin == NULL) { + scripts[i].compile_error = compile_error; + break; + } + } + + /* Execute */ + e_debug(sieve_get_event(svinst), + "Executing script from `%s'", + sieve_get_source(sbin)); + more = sieve_multiscript_run(mscript, sbin, ehandler, ehandler, + exflags); + + mstatus = sieve_multiscript_status(mscript); + if (!more && mstatus == SIEVE_EXEC_BIN_CORRUPT && + !scripts[i].binary_corrupt && sieve_is_loaded(sbin)) { + /* Close corrupt script */ + sieve_close(&sbin); + + /* Recompile */ + scripts[i].binary = sbin = + imap_sieve_run_open_script( + isrun, script, cpflags, FALSE, + &compile_error); + if (sbin == NULL) { + scripts[i].compile_error = compile_error; + break; + } + + /* Execute again */ + more = sieve_multiscript_run(mscript, sbin, + ehandler, ehandler, + exflags); + + /* Save new version */ + + mstatus = sieve_multiscript_status(mscript); + if (mstatus == SIEVE_EXEC_BIN_CORRUPT) + scripts[i].binary_corrupt = TRUE; + else if (more) + (void)sieve_save(sbin, FALSE, NULL); + } + + if (user_script && !sieve_record_resource_usage(sbin, rusage)) { + rusage_exceeded = ((i + 1) < count && more); + scripts[i].rusage_exceeded = TRUE; + break; + } + } + + /* Finish execution */ + exflags = SIEVE_EXECUTE_FLAG_NO_ENVELOPE | + SIEVE_EXECUTE_FLAG_SKIP_RESPONSES; + ehandler = (isrun->user_ehandler != NULL ? + isrun->user_ehandler : isieve->master_ehandler); + if (compile_error == SIEVE_ERROR_TEMP_FAILURE) { + ret = sieve_multiscript_finish(&mscript, ehandler, exflags, + SIEVE_EXEC_TEMP_FAILURE); + } else if (rusage_exceeded) { + i_assert(last_script != NULL); + (void)sieve_multiscript_finish(&mscript, ehandler, exflags, + SIEVE_EXEC_TEMP_FAILURE); + sieve_error(ehandler, sieve_script_name(last_script), + "cumulative resource usage limit exceeded"); + ret = SIEVE_EXEC_RESOURCE_LIMIT; + } else { + ret = sieve_multiscript_finish(&mscript, ehandler, exflags, + SIEVE_EXEC_OK); + } + + /* Don't log additional messages about compile failure */ + if (compile_error != SIEVE_ERROR_NONE && ret == SIEVE_EXEC_FAILURE) { + e_info(sieve_get_event(svinst), + "Aborted script execution sequence " + "with successful implicit keep"); + return 1; + } + + if (last_script == NULL && ret == SIEVE_EXEC_OK) + return 0; + return imap_sieve_handle_exec_status(isrun, last_script, ret, + scriptenv->exec_status, fatal_r); +} + +int imap_sieve_run_mail(struct imap_sieve_run *isrun, struct mail *mail, + const char *changed_flags, bool *fatal_r) +{ + struct imap_sieve *isieve = isrun->isieve; + struct sieve_instance *svinst = isieve->svinst; + struct mail_user *user = isieve->client->user; + struct sieve_message_data msgdata; + struct sieve_script_env scriptenv; + struct sieve_exec_status estatus; + struct imap_sieve_context context; + struct sieve_trace_config trace_config; + struct sieve_trace_log *trace_log; + const char *error; + int ret; + + *fatal_r = FALSE; + + i_zero(&context); + context.event.dest_mailbox = isrun->dest_mailbox; + context.event.src_mailbox = isrun->src_mailbox; + context.event.cause = isrun->cause; + context.event.changed_flags = changed_flags; + context.mail = mail; + context.isieve = isieve; + + /* Initialize trace logging */ + imap_sieve_run_init_trace_log(isrun, &trace_config, &trace_log); + + T_BEGIN { + if (trace_log != NULL) { + /* Write trace header for message */ + sieve_trace_log_printf(trace_log, + "Filtering message:\n" + "\n" + " UID: %u\n", mail->uid); + if (changed_flags != NULL && *changed_flags != '\0') { + sieve_trace_log_printf(trace_log, + " Changed flags: %s\n", changed_flags); + } + } + + /* Collect necessary message data */ + + i_zero(&msgdata); + msgdata.mail = mail; + msgdata.auth_user = user->username; + (void)mail_get_message_id(msgdata.mail, &msgdata.id); + + /* Compose script execution environment */ + + if (sieve_script_env_init(&scriptenv, user, &error) < 0) { + e_error(sieve_get_event(svinst), + "Failed to initialize script execution: %s", + error); + ret = -1; + } else { + scriptenv.default_mailbox = + mailbox_get_vname(mail->box); + scriptenv.smtp_start = imap_sieve_smtp_start; + scriptenv.smtp_add_rcpt = imap_sieve_smtp_add_rcpt; + scriptenv.smtp_send = imap_sieve_smtp_send; + scriptenv.smtp_abort = imap_sieve_smtp_abort; + scriptenv.smtp_finish = imap_sieve_smtp_finish; + scriptenv.duplicate_transaction_begin = + imap_sieve_duplicate_transaction_begin; + scriptenv.duplicate_transaction_commit = + imap_sieve_duplicate_transaction_commit; + scriptenv.duplicate_transaction_rollback = + imap_sieve_duplicate_transaction_rollback; + scriptenv.duplicate_mark = imap_sieve_duplicate_mark; + scriptenv.duplicate_check = imap_sieve_duplicate_check; + scriptenv.result_amend_log_message = + imap_sieve_result_amend_log_message; + scriptenv.trace_log = trace_log; + scriptenv.trace_config = trace_config; + scriptenv.script_context = &context; + + i_zero(&estatus); + scriptenv.exec_status = &estatus; + + /* Execute script(s) */ + + ret = imap_sieve_run_scripts(isrun, &msgdata, + &scriptenv, fatal_r); + } + } T_END; + + return ret; +} diff --git a/pigeonhole/src/plugins/imapsieve/imap-sieve.h b/pigeonhole/src/plugins/imapsieve/imap-sieve.h new file mode 100644 index 0000000..12d0ac7 --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/imap-sieve.h @@ -0,0 +1,59 @@ +#ifndef IMAP_SIEVE_H +#define IMAP_SIEVE_H + +struct client; + +/* + * IMAP event + */ + +struct imap_sieve_event { + struct mailbox *dest_mailbox, *src_mailbox; + const char *cause; + const char *changed_flags; +}; + +struct imap_sieve_context { + struct imap_sieve_event event; + struct mail *mail; + + struct imap_sieve *isieve; +}; + +static inline bool +imap_sieve_event_cause_valid(const char *cause) +{ + return (strcasecmp(cause, "APPEND") == 0 || + strcasecmp(cause, "COPY") == 0 || + strcasecmp(cause, "FLAG") == 0); +} + +/* + * IMAP Sieve + */ + +struct imap_sieve; + +struct imap_sieve *imap_sieve_init(struct client *client); +void imap_sieve_deinit(struct imap_sieve **_isieve); + +/* + * IMAP Sieve run + */ + +struct imap_sieve_run; + +int imap_sieve_run_init(struct imap_sieve *isieve, struct mailbox *dest_mailbox, + struct mailbox *src_mailbox, const char *cause, + const char *script_name, + const char *const *scripts_before, + const char *const *scripts_after, + struct imap_sieve_run **isrun_r) + ATTR_NULL(4, 5, 6); + +int imap_sieve_run_mail(struct imap_sieve_run *isrun, struct mail *mail, + const char *changed_flags, bool *fatal_r); + +void imap_sieve_run_deinit(struct imap_sieve_run **_isrun); + +#endif diff --git a/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.c b/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.c new file mode 100644 index 0000000..12611b3 --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.c @@ -0,0 +1,62 @@ +/* Copyright (c) 2016-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "sieve.h" +#include "sieve-error.h" +#include "sieve-extensions.h" + +#include "ext-imapsieve-common.h" + +#include "sieve-imapsieve-plugin.h" + +/* + * Sieve plugin interface + */ + +struct _plugin_context { + const struct sieve_extension *ext_imapsieve; + const struct sieve_extension *ext_vnd_imapsieve; +}; + +const char *sieve_imapsieve_plugin_version = PIGEONHOLE_ABI_VERSION; + +void sieve_imapsieve_plugin_load +(struct sieve_instance *svinst, void **context) +{ + struct _plugin_context *pctx = i_new(struct _plugin_context, 1); + + pctx->ext_imapsieve = sieve_extension_register + (svinst, &imapsieve_extension_dummy, TRUE); + pctx->ext_vnd_imapsieve = sieve_extension_register + (svinst, &vnd_imapsieve_extension_dummy, TRUE); + + e_debug(sieve_get_event(svinst), + "Sieve imapsieve plugin for %s version %s loaded", + PIGEONHOLE_NAME, PIGEONHOLE_VERSION_FULL); + + *context = (void *)pctx; +} + +void sieve_imapsieve_plugin_unload +(struct sieve_instance *svinst ATTR_UNUSED, void *context) +{ + struct _plugin_context *pctx = (struct _plugin_context *)context; + + sieve_extension_unregister(pctx->ext_imapsieve); + sieve_extension_unregister(pctx->ext_vnd_imapsieve); + + i_free(pctx);} + +/* + * Module interface + */ + +void sieve_imapsieve_plugin_init(void) +{ + /* Nothing */ +} + +void sieve_imapsieve_plugin_deinit(void) +{ + /* Nothing */ +} diff --git a/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.h b/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.h new file mode 100644 index 0000000..fcf9777 --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.h @@ -0,0 +1,20 @@ +#ifndef SIEVE_IMAPSIEVE_PLUGIN_H +#define SIEVE_IMAPSIEVE_PLUGIN_H + +/* + * Plugin interface + */ + +void sieve_imapsieve_plugin_load + (struct sieve_instance *svinst, void **context); +void sieve_imapsieve_plugin_unload + (struct sieve_instance *svinst, void *context); + +/* + * Module interface + */ + +void sieve_imapsieve_plugin_init(void); +void sieve_imapsieve_plugin_deinit(void); + +#endif diff --git a/pigeonhole/src/plugins/lda-sieve/Makefile.am b/pigeonhole/src/plugins/lda-sieve/Makefile.am new file mode 100644 index 0000000..7c2797a --- /dev/null +++ b/pigeonhole/src/plugins/lda-sieve/Makefile.am @@ -0,0 +1,19 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + $(LIBDOVECOT_INCLUDE) \ + $(LIBDOVECOT_DICT_INCLUDE) \ + $(LIBDOVECOT_SMTP_INCLUDE) \ + $(LIBDOVECOT_LDA_INCLUDE) + +lib90_sieve_plugin_la_LDFLAGS = -module -avoid-version + +dovecot_module_LTLIBRARIES = lib90_sieve_plugin.la + +lib90_sieve_plugin_la_LIBADD = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la + +lib90_sieve_plugin_la_SOURCES = \ + lda-sieve-plugin.c + +noinst_HEADERS = \ + lda-sieve-plugin.h diff --git a/pigeonhole/src/plugins/lda-sieve/Makefile.in b/pigeonhole/src/plugins/lda-sieve/Makefile.in new file mode 100644 index 0000000..6f0fba0 --- /dev/null +++ b/pigeonhole/src/plugins/lda-sieve/Makefile.in @@ -0,0 +1,746 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 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/plugins/lda-sieve +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 = +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)$(dovecot_moduledir)" +LTLIBRARIES = $(dovecot_module_LTLIBRARIES) +lib90_sieve_plugin_la_DEPENDENCIES = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la +am_lib90_sieve_plugin_la_OBJECTS = lda-sieve-plugin.lo +lib90_sieve_plugin_la_OBJECTS = $(am_lib90_sieve_plugin_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +lib90_sieve_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(lib90_sieve_plugin_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +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)/lda-sieve-plugin.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 = $(lib90_sieve_plugin_la_SOURCES) +DIST_SOURCES = $(lib90_sieve_plugin_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@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + $(LIBDOVECOT_INCLUDE) \ + $(LIBDOVECOT_DICT_INCLUDE) \ + $(LIBDOVECOT_SMTP_INCLUDE) \ + $(LIBDOVECOT_LDA_INCLUDE) + +lib90_sieve_plugin_la_LDFLAGS = -module -avoid-version +dovecot_module_LTLIBRARIES = lib90_sieve_plugin.la +lib90_sieve_plugin_la_LIBADD = \ + $(top_builddir)/src/lib-sieve/libdovecot-sieve.la + +lib90_sieve_plugin_la_SOURCES = \ + lda-sieve-plugin.c + +noinst_HEADERS = \ + lda-sieve-plugin.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/plugins/lda-sieve/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/lda-sieve/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-dovecot_moduleLTLIBRARIES: $(dovecot_module_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(dovecot_module_LTLIBRARIES)'; test -n "$(dovecot_moduledir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(dovecot_moduledir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dovecot_moduledir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(dovecot_moduledir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(dovecot_moduledir)"; \ + } + +uninstall-dovecot_moduleLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(dovecot_module_LTLIBRARIES)'; test -n "$(dovecot_moduledir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(dovecot_moduledir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(dovecot_moduledir)/$$f"; \ + done + +clean-dovecot_moduleLTLIBRARIES: + -test -z "$(dovecot_module_LTLIBRARIES)" || rm -f $(dovecot_module_LTLIBRARIES) + @list='$(dovecot_module_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +lib90_sieve_plugin.la: $(lib90_sieve_plugin_la_OBJECTS) $(lib90_sieve_plugin_la_DEPENDENCIES) $(EXTRA_lib90_sieve_plugin_la_DEPENDENCIES) + $(AM_V_CCLD)$(lib90_sieve_plugin_la_LINK) -rpath $(dovecot_moduledir) $(lib90_sieve_plugin_la_OBJECTS) $(lib90_sieve_plugin_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lda-sieve-plugin.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: + for dir in "$(DESTDIR)$(dovecot_moduledir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-dovecot_moduleLTLIBRARIES clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/lda-sieve-plugin.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-dovecot_moduleLTLIBRARIES + +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)/lda-sieve-plugin.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dovecot_moduleLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-dovecot_moduleLTLIBRARIES clean-generic clean-libtool \ + 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-dovecot_moduleLTLIBRARIES \ + 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 uninstall-dovecot_moduleLTLIBRARIES + +.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/plugins/lda-sieve/lda-sieve-plugin.c b/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.c new file mode 100644 index 0000000..4e79c1f --- /dev/null +++ b/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.c @@ -0,0 +1,1128 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "array.h" +#include "home-expand.h" +#include "var-expand.h" +#include "eacces-error.h" +#include "smtp-address.h" +#include "smtp-submit.h" +#include "mail-storage.h" +#include "mail-deliver.h" +#include "mail-user.h" +#include "mail-duplicate.h" +#include "smtp-submit.h" +#include "mail-send.h" +#include "iostream-ssl.h" +#include "lda-settings.h" + +#include "sieve.h" +#include "sieve-script.h" +#include "sieve-storage.h" + +#include "lda-sieve-plugin.h" + +#include <sys/stat.h> +#include <dirent.h> + +/* + * Configuration + */ + +#define LDA_SIEVE_DEFAULT_LOCATION "~/.dovecot.sieve" + +#define LDA_SIEVE_MAX_USER_ERRORS 30 + +/* + * Global variables + */ + +static deliver_mail_func_t *next_deliver_mail; + +/* + * Settings handling + */ + +static const char * +lda_sieve_get_setting(void *context, const char *identifier) +{ + struct mail_deliver_context *mdctx = + (struct mail_deliver_context *)context; + const char *value = NULL; + + if (mdctx == NULL) + return NULL; + + if (mdctx->rcpt_user == NULL || + (value = mail_user_plugin_getenv( + mdctx->rcpt_user, identifier)) == NULL) { + if (strcmp(identifier, "recipient_delimiter") == 0) + value = mdctx->set->recipient_delimiter; + } + + return value; +} + +static const struct sieve_callbacks lda_sieve_callbacks = { + NULL, + lda_sieve_get_setting +}; + +/* + * Mail transmission + */ + +static void * +lda_sieve_smtp_start(const struct sieve_script_env *senv, + const struct smtp_address *mail_from) +{ + struct mail_deliver_context *dctx = + (struct mail_deliver_context *)senv->script_context; + struct mail_user *user = dctx->rcpt_user; + struct ssl_iostream_settings ssl_set; + struct smtp_submit_input submit_input; + + i_zero(&ssl_set); + mail_user_init_ssl_client_settings(user, &ssl_set); + + i_zero(&submit_input); + submit_input.ssl = &ssl_set; + + return (void *)smtp_submit_init_simple(&submit_input, dctx->smtp_set, + mail_from); +} + +static void +lda_sieve_smtp_add_rcpt(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle, const struct smtp_address *rcpt_to) +{ + struct smtp_submit *smtp_submit = (struct smtp_submit *) handle; + + smtp_submit_add_rcpt(smtp_submit, rcpt_to); +} + +static struct ostream * +lda_sieve_smtp_send(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle) +{ + struct smtp_submit *smtp_submit = (struct smtp_submit *) handle; + + return smtp_submit_send(smtp_submit); +} + +static void +lda_sieve_smtp_abort(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle) +{ + struct smtp_submit *smtp_submit = (struct smtp_submit *) handle; + + smtp_submit_deinit(&smtp_submit); +} + +static int +lda_sieve_smtp_finish(const struct sieve_script_env *senv ATTR_UNUSED, + void *handle, const char **error_r) +{ + struct smtp_submit *smtp_submit = (struct smtp_submit *) handle; + int ret; + + ret = smtp_submit_run(smtp_submit, error_r); + smtp_submit_deinit(&smtp_submit); + return ret; +} + +static int +lda_sieve_reject_mail(const struct sieve_script_env *senv, + const struct smtp_address *recipient, + const char *reason) +{ + struct mail_deliver_context *dctx = + (struct mail_deliver_context *)senv->script_context; + + return mail_send_rejection(dctx, recipient, reason); +} + +/* + * Duplicate checking + */ + +static void * +lda_sieve_duplicate_transaction_begin(const struct sieve_script_env *senv) +{ + struct mail_deliver_context *dctx = + (struct mail_deliver_context *)senv->script_context; + + return mail_duplicate_transaction_begin(dctx->dup_db); +} + +static void lda_sieve_duplicate_transaction_commit(void **_dup_trans) +{ + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + mail_duplicate_transaction_commit(&dup_trans); +} + +static void lda_sieve_duplicate_transaction_rollback(void **_dup_trans) +{ + struct mail_duplicate_transaction *dup_trans = *_dup_trans; + + *_dup_trans = NULL; + mail_duplicate_transaction_rollback(&dup_trans); +} + +static enum sieve_duplicate_check_result +lda_sieve_duplicate_check(void *_dup_trans, const struct sieve_script_env *senv, + const void *id, size_t id_size) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + switch (mail_duplicate_check(dup_trans, id, id_size, + senv->user->username)) { + case MAIL_DUPLICATE_CHECK_RESULT_EXISTS: + return SIEVE_DUPLICATE_CHECK_RESULT_EXISTS; + case MAIL_DUPLICATE_CHECK_RESULT_NOT_FOUND: + return SIEVE_DUPLICATE_CHECK_RESULT_NOT_FOUND; + case MAIL_DUPLICATE_CHECK_RESULT_DEADLOCK: + case MAIL_DUPLICATE_CHECK_RESULT_LOCK_TIMEOUT: + return SIEVE_DUPLICATE_CHECK_RESULT_TEMP_FAILURE; + case MAIL_DUPLICATE_CHECK_RESULT_IO_ERROR: + case MAIL_DUPLICATE_CHECK_RESULT_TOO_MANY_LOCKS: + break; + } + return SIEVE_DUPLICATE_CHECK_RESULT_FAILURE; +} + +static void +lda_sieve_duplicate_mark(void *_dup_trans, const struct sieve_script_env *senv, + const void *id, size_t id_size, time_t time) +{ + struct mail_duplicate_transaction *dup_trans = _dup_trans; + + mail_duplicate_mark(dup_trans, id, id_size, senv->user->username, time); +} + +/* + * Result logging + */ + +static const char * +lda_sieve_result_amend_log_message(const struct sieve_script_env *senv, + enum log_type log_type ATTR_UNUSED, + const char *message) +{ + struct mail_deliver_context *mdctx = senv->script_context; + const struct var_expand_table *table; + string_t *str; + const char *error; + + table = mail_deliver_ctx_get_log_var_expand_table(mdctx, message); + + str = t_str_new(256); + if (var_expand(str, mdctx->set->deliver_log_format, + table, &error) <= 0) { + e_error(mdctx->event, + "Failed to expand deliver_log_format=%s: %s", + mdctx->set->deliver_log_format, error); + } + return str_c(str); +} + +/* + * Plugin implementation + */ + +struct lda_sieve_run_context { + struct sieve_instance *svinst; + + struct mail_deliver_context *mdctx; + const char *home_dir; + + struct sieve_script **scripts; + unsigned int script_count; + + struct sieve_script *user_script; + struct sieve_script *main_script; + struct sieve_script *discard_script; + + const struct sieve_message_data *msgdata; + const struct sieve_script_env *scriptenv; + + struct sieve_error_handler *user_ehandler; + struct sieve_error_handler *master_ehandler; + struct sieve_error_handler *action_ehandler; + const char *userlog; +}; + +static int +lda_sieve_get_personal_storage(struct sieve_instance *svinst, + struct mail_user *user, + struct sieve_storage **storage_r, + enum sieve_error *error_r) +{ + *storage_r = sieve_storage_create_main(svinst, user, 0, error_r); + if (*storage_r == NULL) { + switch (*error_r) { + case SIEVE_ERROR_NOT_POSSIBLE: + case SIEVE_ERROR_NOT_FOUND: + break; + case SIEVE_ERROR_TEMP_FAILURE: + e_error(sieve_get_event(svinst), + "Failed to access user's personal storage " + "(temporary failure)"); + return -1; + default: + e_error(sieve_get_event(svinst), + "Failed to access user's personal storage"); + break; + } + return 0; + } + return 1; +} + +static int +lda_sieve_multiscript_get_scripts(struct sieve_instance *svinst, + const char *label, const char *location, + ARRAY_TYPE(sieve_script) *scripts, + enum sieve_error *error_r) +{ + struct sieve_script_sequence *seq; + struct sieve_script *script; + bool finished = FALSE; + int ret = 1; + + seq = sieve_script_sequence_create(svinst, location, error_r); + if (seq == NULL) + return (*error_r == SIEVE_ERROR_NOT_FOUND ? 0 : -1); + + while (ret > 0 && !finished) { + script = sieve_script_sequence_next(seq, error_r); + if (script == NULL) { + switch (*error_r) { + case SIEVE_ERROR_NONE: + finished = TRUE; + break; + case SIEVE_ERROR_TEMP_FAILURE: + e_error(sieve_get_event(svinst), + "Failed to access %s script from `%s' " + "(temporary failure)", + label, location); + ret = -1; + default: + break; + } + continue; + } + + array_append(scripts, &script, 1); + } + + sieve_script_sequence_free(&seq); + return ret; +} + +static void +lda_sieve_binary_save(struct lda_sieve_run_context *srctx, + struct sieve_binary *sbin, struct sieve_script *script) +{ + enum sieve_error error; + + /* Save binary when compiled */ + if (sieve_save(sbin, FALSE, &error) < 0 && + error == SIEVE_ERROR_NO_PERMISSION && + script != srctx->user_script) { + /* Cannot save binary for global script */ + e_error(sieve_get_event(srctx->svinst), + "The LDA Sieve plugin does not have permission " + "to save global Sieve script binaries; " + "global Sieve scripts like `%s' need to be " + "pre-compiled using the sievec tool", + sieve_script_location(script)); + } +} + +static struct +sieve_binary *lda_sieve_open(struct lda_sieve_run_context *srctx, + struct sieve_script *script, + enum sieve_compile_flags cpflags, bool recompile, + enum sieve_error *error_r) +{ + struct sieve_instance *svinst = srctx->svinst; + struct sieve_error_handler *ehandler; + struct sieve_binary *sbin; + const char *compile_name = "compile"; + + if (recompile) { + /* Warn */ + e_warning(sieve_get_event(svinst), + "Encountered corrupt binary: re-compiling script %s", + sieve_script_location(script)); + compile_name = "re-compile"; + } else { + e_debug(sieve_get_event(svinst), + "Loading script %s", sieve_script_location(script)); + } + + if (script == srctx->user_script) + ehandler = srctx->user_ehandler; + else + ehandler = srctx->master_ehandler; + + sieve_error_handler_reset(ehandler); + + if (recompile) + sbin = sieve_compile_script(script, ehandler, cpflags, error_r); + else + sbin = sieve_open_script(script, ehandler, cpflags, error_r); + + /* Load or compile the sieve script */ + if (sbin == NULL) { + switch (*error_r) { + /* Script not found */ + case SIEVE_ERROR_NOT_FOUND: + e_debug(sieve_get_event(svinst), + "Script `%s' is missing for %s", + sieve_script_location(script), + compile_name); + break; + /* Temporary failure */ + case SIEVE_ERROR_TEMP_FAILURE: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s " + "(temporary failure)", + sieve_script_location(script), compile_name); + break; + /* Compile failed */ + case SIEVE_ERROR_NOT_VALID: + if (script == srctx->user_script && + srctx->userlog != NULL ) { + e_info(sieve_get_event(svinst), + "Failed to %s script `%s' " + "(view user logfile `%s' for more information)", + compile_name, + sieve_script_location(script), + srctx->userlog); + break; + } + e_error(sieve_get_event(svinst), + "Failed to %s script `%s'", + compile_name, sieve_script_location(script)); + break; + /* Cumulative resource limit exceeded */ + case SIEVE_ERROR_RESOURCE_LIMIT: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s " + "(cumulative resource limit exceeded)", + sieve_script_location(script), compile_name); + break; + /* Something else */ + default: + e_error(sieve_get_event(svinst), + "Failed to open script `%s' for %s", + sieve_script_location(script), compile_name); + break; + } + + return NULL; + } + + if (!recompile) + lda_sieve_binary_save(srctx, sbin, script); + return sbin; +} + +static int +lda_sieve_handle_exec_status(struct lda_sieve_run_context *srctx, + struct sieve_script *script, int status) +{ + struct sieve_instance *svinst = srctx->svinst; + struct mail_deliver_context *mdctx = srctx->mdctx; + struct sieve_exec_status *estatus = srctx->scriptenv->exec_status; + const char *userlog_notice = ""; + enum log_type log_level, user_log_level; + enum mail_error mail_error = MAIL_ERROR_NONE; + int ret; + + log_level = user_log_level = LOG_TYPE_ERROR; + + if (estatus != NULL && estatus->last_storage != NULL && + estatus->store_failed) { + mail_storage_get_last_error(estatus->last_storage, &mail_error); + + /* Don't bother administrator too much with benign errors */ + if (mail_error == MAIL_ERROR_NOQUOTA) { + log_level = LOG_TYPE_INFO; + user_log_level = LOG_TYPE_INFO; + } + } + + if (script == srctx->user_script && srctx->userlog != NULL) { + userlog_notice = t_strdup_printf( + " (user logfile %s may reveal additional details)", + srctx->userlog); + user_log_level = LOG_TYPE_INFO; + } + + switch (status) { + case SIEVE_EXEC_FAILURE: + e_log(sieve_get_event(svinst), user_log_level, + "Execution of script %s failed, " + "but implicit keep was successful%s", + sieve_script_location(script), userlog_notice); + ret = 1; + break; + case SIEVE_EXEC_TEMP_FAILURE: + e_log(sieve_get_event(svinst), log_level, + "Execution of script %s was aborted due to temporary failure%s", + sieve_script_location(script), userlog_notice); + if (mail_error != MAIL_ERROR_TEMP && + mdctx->tempfail_error == NULL) { + mdctx->tempfail_error = + "Execution of Sieve filters was aborted due to temporary failure"; + } + ret = -1; + break; + case SIEVE_EXEC_BIN_CORRUPT: + e_error(sieve_get_event(svinst), + "!!BUG!!: Binary compiled from %s is still corrupt; " + "bailing out and reverting to default delivery", + sieve_script_location(script)); + ret = -1; + break; + case SIEVE_EXEC_RESOURCE_LIMIT: + e_error(sieve_get_event(svinst), + "Execution of script %s was aborted " + "due to excessive resource usage", + sieve_script_location(script)); + ret = -1; + break; + case SIEVE_EXEC_KEEP_FAILED: + e_log(sieve_get_event(svinst), log_level, + "Execution of script %s failed with unsuccessful implicit keep%s", + sieve_script_location(script), userlog_notice); + ret = -1; + break; + default: + ret = status > 0 ? 1 : -1; + break; + } + + return ret; +} + +static int +lda_sieve_execute_script(struct lda_sieve_run_context *srctx, + struct sieve_multiscript *mscript, + struct sieve_script *script, + unsigned int index, bool discard_script, + enum sieve_error *error_r) +{ + struct sieve_instance *svinst = srctx->svinst; + struct sieve_error_handler *exec_ehandler; + struct sieve_binary *sbin = NULL; + enum sieve_compile_flags cpflags = 0; + enum sieve_execute_flags exflags = SIEVE_EXECUTE_FLAG_LOG_RESULT; + struct sieve_resource_usage *rusage = + &srctx->scriptenv->exec_status->resource_usage; + bool user_script; + int mstatus, ret; + + *error_r = SIEVE_ERROR_NONE; + + user_script = (script == srctx->user_script); + + sieve_resource_usage_init(rusage); + if (user_script) { + cpflags |= SIEVE_COMPILE_FLAG_NOGLOBAL; + exflags |= SIEVE_EXECUTE_FLAG_NOGLOBAL; + exec_ehandler = srctx->user_ehandler; + } else { + exec_ehandler = srctx->master_ehandler; + } + + /* Open */ + + if (!discard_script) { + e_debug(sieve_get_event(svinst), + "Opening script %d of %d from `%s'", + index, srctx->script_count, + sieve_script_location(script)); + } else { + e_debug(sieve_get_event(svinst), + "Opening discard script from `%s'", + sieve_script_location(script)); + } + + sbin = lda_sieve_open(srctx, script, cpflags, FALSE, error_r); + if (sbin == NULL) + return 0; + + /* Execute */ + + e_debug(sieve_get_event(svinst), + "Executing script from `%s'", + sieve_get_source(sbin)); + + if (!discard_script) { + ret = (sieve_multiscript_run(mscript, sbin, exec_ehandler, + exec_ehandler, exflags) ? 1 : 0); + } else { + sieve_multiscript_run_discard(mscript, sbin, exec_ehandler, + exec_ehandler, exflags); + ret = 0; + } + + mstatus = sieve_multiscript_status(mscript); + if (ret == 0 && mstatus == SIEVE_EXEC_BIN_CORRUPT && + sieve_is_loaded(sbin)) { + /* Close corrupt script */ + + sieve_close(&sbin); + + /* Recompile */ + + sbin = lda_sieve_open(srctx, script, cpflags, TRUE, + error_r); + if (sbin == NULL) + return 0; + + /* Execute again */ + + if (!discard_script) { + ret = (sieve_multiscript_run( + mscript, sbin, exec_ehandler, + exec_ehandler, exflags) ? 1 : 0); + } else { + sieve_multiscript_run_discard( + mscript, sbin, exec_ehandler, + exec_ehandler, exflags); + } + + /* Save new version */ + + mstatus = sieve_multiscript_status(mscript); + if (mstatus != SIEVE_EXEC_BIN_CORRUPT) + lda_sieve_binary_save(srctx, sbin, script); + } + if (ret == 0 && mstatus == SIEVE_EXEC_RESOURCE_LIMIT) + ret = -1; + + if (user_script) + (void)sieve_record_resource_usage(sbin, rusage); + + sieve_close(&sbin); + + return ret; +} + +static int lda_sieve_execute_scripts(struct lda_sieve_run_context *srctx) +{ + struct sieve_instance *svinst = srctx->svinst; + struct sieve_multiscript *mscript; + struct sieve_error_handler *exec_ehandler; + struct sieve_script *script, *last_script = NULL; + enum sieve_execute_flags exflags = SIEVE_EXECUTE_FLAG_LOG_RESULT; + bool discard_script; + enum sieve_error error; + unsigned int i; + int ret; + + i_assert(srctx->script_count > 0); + + /* Start execution */ + + mscript = sieve_multiscript_start_execute(svinst, srctx->msgdata, + srctx->scriptenv); + + /* Execute scripts */ + + i = 0; + discard_script = FALSE; + error = SIEVE_ERROR_NONE; + for (;;) { + if (!discard_script) { + /* normal script sequence */ + i_assert(i < srctx->script_count); + script = srctx->scripts[i]; + i++; + } else { + /* discard script */ + script = srctx->discard_script; + } + + i_assert(script != NULL); + last_script = script; + + ret = lda_sieve_execute_script(srctx, mscript, script, i, + discard_script, &error); + if (ret < 0) + break; + if (error == SIEVE_ERROR_NOT_FOUND) { + /* skip scripts which finally turn out not to exist */ + ret = 1; + } + + if (discard_script) { + /* Executed discard script, which is always final */ + break; + } else if (ret > 0) { + /* The "keep" action is applied; execute next script */ + i_assert(i <= srctx->script_count); + if (i == srctx->script_count) { + /* End of normal script sequence */ + break; + } + } else if (error != SIEVE_ERROR_NONE) { + break; + } else if (sieve_multiscript_will_discard(mscript) && + srctx->discard_script != NULL) { + /* Mail is set to be discarded, but we have a discard script. */ + discard_script = TRUE; + } else { + break; + } + } + + /* Finish execution */ + exec_ehandler = (srctx->user_ehandler != NULL ? + srctx->user_ehandler : srctx->master_ehandler); + ret = sieve_multiscript_finish(&mscript, exec_ehandler, exflags, + (error == SIEVE_ERROR_TEMP_FAILURE ? + SIEVE_EXEC_TEMP_FAILURE : + SIEVE_EXEC_OK)); + + /* Don't log additional messages about compile failure */ + if (error != SIEVE_ERROR_NONE && ret == SIEVE_EXEC_FAILURE) { + e_info(sieve_get_event(svinst), + "Aborted script execution sequence with successful implicit keep"); + return 1; + } + + return lda_sieve_handle_exec_status(srctx, last_script, ret); +} + +static int lda_sieve_find_scripts(struct lda_sieve_run_context *srctx) +{ + struct mail_deliver_context *mdctx = srctx->mdctx; + struct sieve_instance *svinst = srctx->svinst; + struct sieve_storage *main_storage; + const char *sieve_before, *sieve_after, *sieve_discard; + const char *setting_name; + enum sieve_error error; + ARRAY_TYPE(sieve_script) script_sequence; + struct sieve_script *const *scripts; + unsigned int after_index, count, i; + int ret = 1; + + /* Find the personal script to execute */ + + ret = lda_sieve_get_personal_storage(svinst, mdctx->rcpt_user, + &main_storage, &error); + if (ret == 0 && error == SIEVE_ERROR_NOT_POSSIBLE) + return 0; + if (ret > 0) { + srctx->main_script = + sieve_storage_active_script_open(main_storage, &error); + + if (srctx->main_script == NULL) { + switch (error) { + case SIEVE_ERROR_NOT_FOUND: + e_debug(sieve_get_event(svinst), + "User has no active script in storage `%s'", + sieve_storage_location(main_storage)); + break; + case SIEVE_ERROR_TEMP_FAILURE: + e_error(sieve_get_event(svinst), + "Failed to access active Sieve script in user storage `%s' " + "(temporary failure)", + sieve_storage_location(main_storage)); + ret = -1; + break; + default: + e_error(sieve_get_event(svinst), + "Failed to access active Sieve script in user storage `%s'", + sieve_storage_location(main_storage)); + break; + } + } else if (!sieve_script_is_default(srctx->main_script)) { + srctx->user_script = srctx->main_script; + } + sieve_storage_unref(&main_storage); + } + + if (ret >= 0 && srctx->main_script == NULL) { + e_debug(sieve_get_event(svinst), + "User has no personal script"); + } + + /* Compose script array */ + + t_array_init(&script_sequence, 16); + + /* before */ + if (ret >= 0) { + i = 2; + setting_name = "sieve_before"; + sieve_before = mail_user_plugin_getenv( + mdctx->rcpt_user, setting_name); + while (ret >= 0 && + sieve_before != NULL && *sieve_before != '\0') { + ret = lda_sieve_multiscript_get_scripts( + svinst, setting_name, sieve_before, + &script_sequence, &error); + if (ret < 0 && error == SIEVE_ERROR_TEMP_FAILURE) { + ret = -1; + break; + } else if (ret == 0) { + e_debug(sieve_get_event(svinst), + "Location for %s not found: %s", + setting_name, sieve_before); + } + ret = 0; + setting_name = t_strdup_printf("sieve_before%u", i++); + sieve_before = mail_user_plugin_getenv( + mdctx->rcpt_user, setting_name); + } + + if (ret >= 0) { + scripts = array_get(&script_sequence, &count); + for (i = 0; i < count; i ++) { + e_debug(sieve_get_event(svinst), + "Executed before user's personal Sieve script(%d): %s", + i+1, sieve_script_location(scripts[i])); + } + } + } + + /* main */ + if (srctx->main_script != NULL) { + array_append(&script_sequence, &srctx->main_script, 1); + + if (ret >= 0) { + e_debug(sieve_get_event(svinst), + "Using the following location for user's Sieve script: %s", + sieve_script_location(srctx->main_script)); + } + } + + after_index = array_count(&script_sequence); + + /* after */ + if (ret >= 0) { + i = 2; + setting_name = "sieve_after"; + sieve_after = mail_user_plugin_getenv(mdctx->rcpt_user, setting_name); + while (sieve_after != NULL && *sieve_after != '\0') { + ret = lda_sieve_multiscript_get_scripts( + svinst, setting_name, sieve_after, + &script_sequence, &error); + if (ret < 0 && error == SIEVE_ERROR_TEMP_FAILURE) { + ret = -1; + break; + } else if (ret == 0) { + e_debug(sieve_get_event(svinst), + "Location for %s not found: %s", + setting_name, sieve_after); + } + ret = 0; + setting_name = t_strdup_printf("sieve_after%u", i++); + sieve_after = mail_user_plugin_getenv( + mdctx->rcpt_user, setting_name); + } + + if (ret >= 0) { + scripts = array_get(&script_sequence, &count); + for ( i = after_index; i < count; i ++ ) { + e_debug(sieve_get_event(svinst), + "executed after user's Sieve script(%d): %s", + i+1, sieve_script_location(scripts[i])); + } + } + } + + /* discard */ + sieve_discard = mail_user_plugin_getenv( + mdctx->rcpt_user, "sieve_discard"); + if (sieve_discard != NULL && *sieve_discard != '\0') { + srctx->discard_script = sieve_script_create_open( + svinst, sieve_discard, NULL, &error); + if (srctx->discard_script == NULL) { + switch (error) { + case SIEVE_ERROR_NOT_FOUND: + e_debug(sieve_get_event(svinst), + "Location for sieve_discard not found: %s", + sieve_discard); + break; + case SIEVE_ERROR_TEMP_FAILURE: + ret = -1; + break; + default: + break; + } + } + } + + if (ret < 0) { + mdctx->tempfail_error = + "Temporarily unable to access necessary Sieve scripts"; + } + srctx->scripts = + array_get_modifiable(&script_sequence, &srctx->script_count); + return ret; +} + +static void +lda_sieve_free_scripts(struct lda_sieve_run_context *srctx) +{ + unsigned int i; + + for (i = 0; i < srctx->script_count; i++) + sieve_script_unref(&srctx->scripts[i]); + if (srctx->discard_script != NULL) + sieve_script_unref(&srctx->discard_script); +} + +static void +lda_sieve_init_trace_log(struct lda_sieve_run_context *srctx, + const struct smtp_address *mail_from, + struct sieve_trace_config *trace_config_r, + struct sieve_trace_log **trace_log_r) +{ + struct mail_deliver_context *mdctx = srctx->mdctx; + struct sieve_instance *svinst = srctx->svinst; + struct sieve_trace_log *trace_log = NULL; + + if (sieve_trace_config_get(svinst, trace_config_r) < 0 || + sieve_trace_log_open(svinst, &trace_log) < 0) { + i_zero(trace_config_r); + *trace_log_r = NULL; + return; + } + + /* Write header for trace file */ + sieve_trace_log_printf(trace_log, + "Sieve trace log for message delivery:\n" + "\n" + " Username: %s\n", mdctx->rcpt_user->username); + if (mdctx->rcpt_user->session_id != NULL) { + sieve_trace_log_printf(trace_log, + " Session ID: %s\n", + mdctx->rcpt_user->session_id); + } + sieve_trace_log_printf(trace_log, + " Sender: %s\n" + " Final recipient: %s\n" + " Default mailbox: %s\n\n", + smtp_address_encode_path(mail_from), + smtp_address_encode_path(mdctx->rcpt_to), + (mdctx->rcpt_default_mailbox != NULL ? + mdctx->rcpt_default_mailbox : "INBOX")); + + *trace_log_r = trace_log; +} + +static int +lda_sieve_execute(struct lda_sieve_run_context *srctx, + struct mail_storage **storage_r) +{ + struct mail_deliver_context *mdctx = srctx->mdctx; + struct sieve_instance *svinst = srctx->svinst; + struct sieve_message_data msgdata; + struct sieve_script_env scriptenv; + struct sieve_exec_status estatus; + struct sieve_trace_config trace_config; + const struct smtp_address *mail_from; + struct sieve_trace_log *trace_log; + const char *error; + int ret; + + /* Check whether there are any scripts to execute at all */ + + if (srctx->script_count == 0) { + e_debug(sieve_get_event(svinst), + "No scripts to execute: " + "reverting to default delivery."); + + /* No error, but no delivery by this plugin either. A return + value of <= 0 for a deliver plugin is is considered a + failure. In deliver itself, saved_mail and tried_default_save + remain unset, meaning that deliver will then attempt the + default delivery. We return 0 to signify the lack of a real + error. + */ + return 0; + } + + /* Initialize user error handler */ + + if (srctx->user_script != NULL) { + const char *log_path = + sieve_user_get_log_path(svinst, srctx->user_script); + + if (log_path != NULL) { + srctx->userlog = log_path; + srctx->user_ehandler = sieve_logfile_ehandler_create( + svinst, srctx->userlog, + LDA_SIEVE_MAX_USER_ERRORS); + } + } + + /* Determine return address */ + + mail_from = mail_deliver_get_return_address(mdctx); + + /* Initialize trace logging */ + + lda_sieve_init_trace_log(srctx, mail_from, &trace_config, &trace_log); + + /* Collect necessary message data */ + + i_zero(&msgdata); + + msgdata.mail = mdctx->src_mail; + msgdata.auth_user = mdctx->rcpt_user->username; + msgdata.envelope.mail_from = mail_from; + msgdata.envelope.mail_params = &mdctx->mail_params; + msgdata.envelope.rcpt_to = mdctx->rcpt_to; + msgdata.envelope.rcpt_params = &mdctx->rcpt_params; + (void)mail_get_message_id(msgdata.mail, &msgdata.id); + + srctx->msgdata = &msgdata; + + /* Compose script execution environment */ + + if (sieve_script_env_init(&scriptenv, mdctx->rcpt_user, &error) < 0) { + e_error(sieve_get_event(svinst), + "Failed to initialize script execution: %s", error); + if (trace_log != NULL) + sieve_trace_log_free(&trace_log); + return -1; + } + + scriptenv.default_mailbox = mdctx->rcpt_default_mailbox; + scriptenv.mailbox_autocreate = mdctx->set->lda_mailbox_autocreate; + scriptenv.mailbox_autosubscribe = mdctx->set->lda_mailbox_autosubscribe; + scriptenv.smtp_start = lda_sieve_smtp_start; + scriptenv.smtp_add_rcpt = lda_sieve_smtp_add_rcpt; + scriptenv.smtp_send = lda_sieve_smtp_send; + scriptenv.smtp_abort = lda_sieve_smtp_abort; + scriptenv.smtp_finish = lda_sieve_smtp_finish; + scriptenv.duplicate_transaction_begin = + lda_sieve_duplicate_transaction_begin; + scriptenv.duplicate_transaction_commit = + lda_sieve_duplicate_transaction_commit; + scriptenv.duplicate_transaction_rollback = + lda_sieve_duplicate_transaction_rollback; + scriptenv.duplicate_mark = lda_sieve_duplicate_mark; + scriptenv.duplicate_check = lda_sieve_duplicate_check; + scriptenv.reject_mail = lda_sieve_reject_mail; + scriptenv.result_amend_log_message = lda_sieve_result_amend_log_message; + scriptenv.script_context = (void *) mdctx; + scriptenv.trace_log = trace_log; + scriptenv.trace_config = trace_config; + + i_zero(&estatus); + scriptenv.exec_status = &estatus; + + srctx->scriptenv = &scriptenv; + + /* Execute script(s) */ + + ret = lda_sieve_execute_scripts(srctx); + + /* Record status */ + + mdctx->tried_default_save = estatus.tried_default_save; + *storage_r = estatus.last_storage; + + if (trace_log != NULL) + sieve_trace_log_free(&trace_log); + + return ret; +} + +static int +lda_sieve_deliver_mail(struct mail_deliver_context *mdctx, + struct mail_storage **storage_r) +{ + struct lda_sieve_run_context srctx; + const struct mail_storage_settings *mail_set = + mail_user_set_get_storage_set(mdctx->rcpt_user); + bool debug = mdctx->rcpt_user->mail_debug; + struct sieve_environment svenv; + int ret = 0; + + /* Initialize run context */ + + i_zero(&srctx); + srctx.mdctx = mdctx; + (void)mail_user_get_home(mdctx->rcpt_user, &srctx.home_dir); + + /* Initialize Sieve engine */ + + memset((void*)&svenv, 0, sizeof(svenv)); + svenv.username = mdctx->rcpt_user->username; + svenv.home_dir = srctx.home_dir; + svenv.hostname = mail_set->hostname; + svenv.base_dir = mdctx->rcpt_user->set->base_dir; + svenv.temp_dir = mdctx->rcpt_user->set->mail_temp_dir; + svenv.event_parent = mdctx->event; + svenv.flags = SIEVE_FLAG_HOME_RELATIVE; + svenv.location = SIEVE_ENV_LOCATION_MDA; + svenv.delivery_phase = SIEVE_DELIVERY_PHASE_DURING; + + srctx.svinst = sieve_init(&svenv, &lda_sieve_callbacks, mdctx, debug); + + /* Initialize master error handler */ + + srctx.master_ehandler = sieve_master_ehandler_create(srctx.svinst, 0); + + sieve_error_handler_accept_infolog(srctx.master_ehandler, TRUE); + sieve_error_handler_accept_debuglog(srctx.master_ehandler, debug); + + *storage_r = NULL; + + /* Find Sieve scripts and run them */ + + T_BEGIN { + if (lda_sieve_find_scripts(&srctx) < 0) + ret = -1; + else if (srctx.scripts == NULL) + ret = 0; + else + ret = lda_sieve_execute(&srctx, storage_r); + + lda_sieve_free_scripts(&srctx); + } T_END; + + /* Clean up */ + + if (srctx.user_ehandler != NULL) + sieve_error_handler_unref(&srctx.user_ehandler); + sieve_error_handler_unref(&srctx.master_ehandler); + sieve_deinit(&srctx.svinst); + + return ret; +} + +/* + * Plugin interface + */ + +const char *sieve_plugin_version = DOVECOT_ABI_VERSION; +const char sieve_plugin_binary_dependency[] = "lda lmtp"; + +void sieve_plugin_init(void) +{ + /* Hook into the delivery process */ + next_deliver_mail = mail_deliver_hook_set(lda_sieve_deliver_mail); +} + +void sieve_plugin_deinit(void) +{ + /* Remove hook */ + mail_deliver_hook_set(next_deliver_mail); +} diff --git a/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.h b/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.h new file mode 100644 index 0000000..2357097 --- /dev/null +++ b/pigeonhole/src/plugins/lda-sieve/lda-sieve-plugin.h @@ -0,0 +1,11 @@ +#ifndef LDA_SIEVE_PLUGIN_H +#define LDA_SIEVE_PLUGIN_H + +/* + * Plugin interface + */ + +void sieve_plugin_init(void); +void sieve_plugin_deinit(void); + +#endif diff --git a/pigeonhole/src/plugins/settings/Makefile.am b/pigeonhole/src/plugins/settings/Makefile.am new file mode 100644 index 0000000..49537e1 --- /dev/null +++ b/pigeonhole/src/plugins/settings/Makefile.am @@ -0,0 +1,12 @@ +settingsdir = $(dovecot_moduledir)/settings + +AM_CPPFLAGS = \ + $(LIBDOVECOT_INCLUDE) + +libpigeonhole_settings_la_LDFLAGS = -module -avoid-version + +settings_LTLIBRARIES = \ + libpigeonhole_settings.la + +libpigeonhole_settings_la_SOURCES = \ + pigeonhole-settings.c diff --git a/pigeonhole/src/plugins/settings/Makefile.in b/pigeonhole/src/plugins/settings/Makefile.in new file mode 100644 index 0000000..ee34c03 --- /dev/null +++ b/pigeonhole/src/plugins/settings/Makefile.in @@ -0,0 +1,737 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 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/plugins/settings +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 $(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 = +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)$(settingsdir)" +LTLIBRARIES = $(settings_LTLIBRARIES) +libpigeonhole_settings_la_LIBADD = +am_libpigeonhole_settings_la_OBJECTS = pigeonhole-settings.lo +libpigeonhole_settings_la_OBJECTS = \ + $(am_libpigeonhole_settings_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 = +libpigeonhole_settings_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libpigeonhole_settings_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +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)/pigeonhole-settings.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 = $(libpigeonhole_settings_la_SOURCES) +DIST_SOURCES = $(libpigeonhole_settings_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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@ +settingsdir = $(dovecot_moduledir)/settings +AM_CPPFLAGS = \ + $(LIBDOVECOT_INCLUDE) + +libpigeonhole_settings_la_LDFLAGS = -module -avoid-version +settings_LTLIBRARIES = \ + libpigeonhole_settings.la + +libpigeonhole_settings_la_SOURCES = \ + pigeonhole-settings.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/plugins/settings/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/settings/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-settingsLTLIBRARIES: $(settings_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(settings_LTLIBRARIES)'; test -n "$(settingsdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(settingsdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(settingsdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(settingsdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(settingsdir)"; \ + } + +uninstall-settingsLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(settings_LTLIBRARIES)'; test -n "$(settingsdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(settingsdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(settingsdir)/$$f"; \ + done + +clean-settingsLTLIBRARIES: + -test -z "$(settings_LTLIBRARIES)" || rm -f $(settings_LTLIBRARIES) + @list='$(settings_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}; \ + } + +libpigeonhole_settings.la: $(libpigeonhole_settings_la_OBJECTS) $(libpigeonhole_settings_la_DEPENDENCIES) $(EXTRA_libpigeonhole_settings_la_DEPENDENCIES) + $(AM_V_CCLD)$(libpigeonhole_settings_la_LINK) -rpath $(settingsdir) $(libpigeonhole_settings_la_OBJECTS) $(libpigeonhole_settings_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pigeonhole-settings.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) +installdirs: + for dir in "$(DESTDIR)$(settingsdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-settingsLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/pigeonhole-settings.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-settingsLTLIBRARIES + +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)/pigeonhole-settings.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-settingsLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-settingsLTLIBRARIES \ + 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-settingsLTLIBRARIES install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am \ + uninstall-settingsLTLIBRARIES + +.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/plugins/settings/pigeonhole-settings.c b/pigeonhole/src/plugins/settings/pigeonhole-settings.c new file mode 100644 index 0000000..21f8e85 --- /dev/null +++ b/pigeonhole/src/plugins/settings/pigeonhole-settings.c @@ -0,0 +1,13 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "pigeonhole-config.h" +#include "pigeonhole-version.h" + +/* This is currently just a dummy plugin that adds a Pigeonhole + * version banner the doveconf output. + */ + +const char *pigeonhole_settings_version = DOVECOT_ABI_VERSION; +const char *pigeonhole_settings_doveconf_banner = "Pigeonhole version "PIGEONHOLE_VERSION_FULL; diff --git a/pigeonhole/src/plugins/sieve-extprograms/Makefile.am b/pigeonhole/src/plugins/sieve-extprograms/Makefile.am new file mode 100644 index 0000000..ab7844f --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/Makefile.am @@ -0,0 +1,34 @@ +sieve_plugindir = $(dovecot_moduledir)/sieve + +sieve_plugin_LTLIBRARIES = lib90_sieve_extprograms_plugin.la + +lib90_sieve_extprograms_plugin_la_LDFLAGS = -module -avoid-version + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + -I$(top_srcdir)/src/lib-sieve/util \ + -I$(top_srcdir)/src/lib-sieve/plugins/copy \ + -I$(top_srcdir)/src/lib-sieve/plugins/variables \ + $(LIBDOVECOT_INCLUDE) \ + -DPKG_RUNDIR=\""$(rundir)"\" + +commands = \ + cmd-pipe.c \ + cmd-filter.c \ + cmd-execute.c + +extensions = \ + ext-pipe.c \ + ext-filter.c \ + ext-execute.c + +lib90_sieve_extprograms_plugin_la_SOURCES = \ + $(commands) \ + $(extensions) \ + sieve-extprograms-common.c \ + sieve-extprograms-plugin.c + +noinst_HEADERS = \ + sieve-extprograms-common.h \ + sieve-extprograms-plugin.h + diff --git a/pigeonhole/src/plugins/sieve-extprograms/Makefile.in b/pigeonhole/src/plugins/sieve-extprograms/Makefile.in new file mode 100644 index 0000000..e35da7b --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/Makefile.in @@ -0,0 +1,790 @@ +# Makefile.in generated by automake 1.16.3 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 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/plugins/sieve-extprograms +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 = +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)$(sieve_plugindir)" +LTLIBRARIES = $(sieve_plugin_LTLIBRARIES) +lib90_sieve_extprograms_plugin_la_LIBADD = +am__objects_1 = cmd-pipe.lo cmd-filter.lo cmd-execute.lo +am__objects_2 = ext-pipe.lo ext-filter.lo ext-execute.lo +am_lib90_sieve_extprograms_plugin_la_OBJECTS = $(am__objects_1) \ + $(am__objects_2) sieve-extprograms-common.lo \ + sieve-extprograms-plugin.lo +lib90_sieve_extprograms_plugin_la_OBJECTS = \ + $(am_lib90_sieve_extprograms_plugin_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +lib90_sieve_extprograms_plugin_la_LINK = $(LIBTOOL) $(AM_V_lt) \ + --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ + $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(lib90_sieve_extprograms_plugin_la_LDFLAGS) $(LDFLAGS) -o $@ +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-execute.Plo \ + ./$(DEPDIR)/cmd-filter.Plo ./$(DEPDIR)/cmd-pipe.Plo \ + ./$(DEPDIR)/ext-execute.Plo ./$(DEPDIR)/ext-filter.Plo \ + ./$(DEPDIR)/ext-pipe.Plo \ + ./$(DEPDIR)/sieve-extprograms-common.Plo \ + ./$(DEPDIR)/sieve-extprograms-plugin.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 = $(lib90_sieve_extprograms_plugin_la_SOURCES) +DIST_SOURCES = $(lib90_sieve_extprograms_plugin_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@ +sieve_plugindir = $(dovecot_moduledir)/sieve +sieve_plugin_LTLIBRARIES = lib90_sieve_extprograms_plugin.la +lib90_sieve_extprograms_plugin_la_LDFLAGS = -module -avoid-version +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-sieve \ + -I$(top_srcdir)/src/lib-sieve/util \ + -I$(top_srcdir)/src/lib-sieve/plugins/copy \ + -I$(top_srcdir)/src/lib-sieve/plugins/variables \ + $(LIBDOVECOT_INCLUDE) \ + -DPKG_RUNDIR=\""$(rundir)"\" + +commands = \ + cmd-pipe.c \ + cmd-filter.c \ + cmd-execute.c + +extensions = \ + ext-pipe.c \ + ext-filter.c \ + ext-execute.c + +lib90_sieve_extprograms_plugin_la_SOURCES = \ + $(commands) \ + $(extensions) \ + sieve-extprograms-common.c \ + sieve-extprograms-plugin.c + +noinst_HEADERS = \ + sieve-extprograms-common.h \ + sieve-extprograms-plugin.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/plugins/sieve-extprograms/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/plugins/sieve-extprograms/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +install-sieve_pluginLTLIBRARIES: $(sieve_plugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(sieve_plugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sieve_plugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(sieve_plugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(sieve_plugindir)"; \ + } + +uninstall-sieve_pluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(sieve_plugin_LTLIBRARIES)'; test -n "$(sieve_plugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(sieve_plugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(sieve_plugindir)/$$f"; \ + done + +clean-sieve_pluginLTLIBRARIES: + -test -z "$(sieve_plugin_LTLIBRARIES)" || rm -f $(sieve_plugin_LTLIBRARIES) + @list='$(sieve_plugin_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}; \ + } + +lib90_sieve_extprograms_plugin.la: $(lib90_sieve_extprograms_plugin_la_OBJECTS) $(lib90_sieve_extprograms_plugin_la_DEPENDENCIES) $(EXTRA_lib90_sieve_extprograms_plugin_la_DEPENDENCIES) + $(AM_V_CCLD)$(lib90_sieve_extprograms_plugin_la_LINK) -rpath $(sieve_plugindir) $(lib90_sieve_extprograms_plugin_la_OBJECTS) $(lib90_sieve_extprograms_plugin_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-execute.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-filter.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-pipe.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-execute.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-filter.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-pipe.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-extprograms-common.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sieve-extprograms-plugin.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: + for dir in "$(DESTDIR)$(sieve_plugindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-sieve_pluginLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/cmd-execute.Plo + -rm -f ./$(DEPDIR)/cmd-filter.Plo + -rm -f ./$(DEPDIR)/cmd-pipe.Plo + -rm -f ./$(DEPDIR)/ext-execute.Plo + -rm -f ./$(DEPDIR)/ext-filter.Plo + -rm -f ./$(DEPDIR)/ext-pipe.Plo + -rm -f ./$(DEPDIR)/sieve-extprograms-common.Plo + -rm -f ./$(DEPDIR)/sieve-extprograms-plugin.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-sieve_pluginLTLIBRARIES + +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)/cmd-execute.Plo + -rm -f ./$(DEPDIR)/cmd-filter.Plo + -rm -f ./$(DEPDIR)/cmd-pipe.Plo + -rm -f ./$(DEPDIR)/ext-execute.Plo + -rm -f ./$(DEPDIR)/ext-filter.Plo + -rm -f ./$(DEPDIR)/ext-pipe.Plo + -rm -f ./$(DEPDIR)/sieve-extprograms-common.Plo + -rm -f ./$(DEPDIR)/sieve-extprograms-plugin.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-sieve_pluginLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-sieve_pluginLTLIBRARIES \ + 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-sieve_pluginLTLIBRARIES install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am \ + uninstall-sieve_pluginLTLIBRARIES + +.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/plugins/sieve-extprograms/cmd-execute.c b/pigeonhole/src/plugins/sieve-extprograms/cmd-execute.c new file mode 100644 index 0000000..79f6663 --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/cmd-execute.c @@ -0,0 +1,488 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "array.h" +#include "buffer.h" +#include "str.h" +#include "str-sanitize.h" +#include "istream.h" +#include "ostream.h" + +#include "sieve-common.h" +#include "sieve-stringlist.h" +#include "sieve-binary.h" +#include "sieve-code.h" +#include "sieve-message.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 "sieve-ext-variables.h" + +#include "sieve-extprograms-common.h" + +/* Execute command + * + * Syntax: + * "execute" [":input" <input-data: string> / ":pipe"] + * [":output" <varname: string>] + * <program-name: string> [<arguments: string-list>] + * + */ + +static bool +cmd_execute_registered(struct sieve_validator *valdtr, + const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg); +static bool +cmd_execute_generate(const struct sieve_codegen_env *cgenv, + struct sieve_command *ctx); + +const struct sieve_command_def sieve_cmd_execute = { + .identifier = "execute", + .type = SCT_HYBRID, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .registered = cmd_execute_registered, + .validate = sieve_extprogram_command_validate, + .generate = cmd_execute_generate, +}; + +/* + * Tagged arguments + */ + +static bool +cmd_execute_validate_input_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd); +static bool +cmd_execute_generate_input_tag(const struct sieve_codegen_env *cgenv, + struct sieve_ast_argument *arg, + struct sieve_command *cmd); + +static bool +cmd_execute_validate_output_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd); + +static const struct sieve_argument_def execute_input_tag = { + .identifier = "input", + .validate = cmd_execute_validate_input_tag, + .generate = cmd_execute_generate_input_tag +}; + +static const struct sieve_argument_def execute_pipe_tag = { + .identifier = "pipe", + .validate = cmd_execute_validate_input_tag, + .generate = cmd_execute_generate_input_tag +}; + +static const struct sieve_argument_def execute_output_tag = { + .identifier = "output", + .validate = cmd_execute_validate_output_tag, +}; + + +/* + * Execute operation + */ + +static bool +cmd_execute_operation_dump(const struct sieve_dumptime_env *denv, + sieve_size_t *address); +static int +cmd_execute_operation_execute(const struct sieve_runtime_env *renv, + sieve_size_t *address); + +const struct sieve_operation_def sieve_opr_execute = { + .mnemonic = "EXECUTE", + .ext_def = &sieve_ext_vnd_execute, + .dump = cmd_execute_operation_dump, + .execute = cmd_execute_operation_execute +}; + +/* Codes for optional operands */ + +enum cmd_execute_optional { + OPT_END, + OPT_INPUT, + OPT_OUTPUT +}; + +/* + * Tag validation + */ + +static bool +cmd_execute_validate_input_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct sieve_ast_argument *tag = *arg; + + if ((bool)cmd->data) { + sieve_argument_validate_error( + valdtr, *arg, + "multiple :input or :pipe arguments specified for the %s %s", + sieve_command_identifier(cmd), + sieve_command_type_name(cmd)); + return FALSE; + } + + cmd->data = (void *)TRUE; + + /* Skip tag */ + *arg = sieve_ast_argument_next(*arg); + + if (sieve_argument_is(tag, execute_input_tag)) { + /* Check syntax: + * :input <input-data: string> + */ + if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, + 0, SAAT_STRING, FALSE)) + return FALSE; + + /* Assign tag parameters */ + tag->parameters = *arg; + *arg = sieve_ast_arguments_detach(*arg,1); + } + + return TRUE; +} + +static bool +cmd_execute_validate_output_tag(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + struct sieve_ast_argument *tag = *arg; + struct sieve_extprograms_config *ext_config = + (struct sieve_extprograms_config *)cmd->ext->context; + + if (ext_config == NULL || ext_config->var_ext == NULL || + !sieve_ext_variables_is_active(ext_config->var_ext, valdtr)) { + sieve_argument_validate_error( + valdtr,*arg, + "the %s %s only allows for the specification of an " + ":output argument when the variables extension is active", + sieve_command_identifier(cmd), + sieve_command_type_name(cmd)); + return FALSE; + } + + /* Detach the tag itself */ + *arg = sieve_ast_arguments_detach(*arg, 1); + + if (!sieve_variable_argument_activate(ext_config->var_ext, + ext_config->var_ext, valdtr, + cmd, *arg, TRUE)) + return FALSE; + + (*arg)->argument->id_code = tag->argument->id_code; + + /* Skip parameter */ + *arg = sieve_ast_argument_next(*arg); + + return TRUE; +} + +/* + * Command registration + */ + +static bool +cmd_execute_registered(struct sieve_validator *valdtr, + const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg) +{ + sieve_validator_register_tag(valdtr, cmd_reg, ext, + &execute_input_tag, OPT_INPUT); + sieve_validator_register_tag(valdtr, cmd_reg, ext, + &execute_pipe_tag, OPT_INPUT); + sieve_validator_register_tag(valdtr, cmd_reg, ext, + &execute_output_tag, OPT_OUTPUT); + return TRUE; +} + +/* + * Code generation + */ + +static bool +cmd_execute_generate_input_tag(const struct sieve_codegen_env *cgenv, + struct sieve_ast_argument *arg, + struct sieve_command *cmd) +{ + if (arg->parameters == NULL) { + sieve_opr_omitted_emit(cgenv->sblock); + return TRUE; + } + + return sieve_generate_argument_parameters(cgenv, cmd, arg); +} + +static bool +cmd_execute_generate(const struct sieve_codegen_env *cgenv, + struct sieve_command *cmd) +{ + sieve_operation_emit(cgenv->sblock, cmd->ext, &sieve_opr_execute); + + /* Emit is_test flag */ + sieve_binary_emit_byte(cgenv->sblock, + (uint8_t)(cmd->ast_node->type == SAT_TEST ? + 1 : 0)); + + /* Generate arguments */ + if (!sieve_generate_arguments(cgenv, cmd, NULL)) + return FALSE; + + /* Emit a placeholder when the <arguments> argument is missing */ + if (sieve_ast_argument_next(cmd->first_positional) == NULL) + sieve_opr_omitted_emit(cgenv->sblock); + + return TRUE; +} + +/* + * Code dump + */ + +static bool +cmd_execute_operation_dump(const struct sieve_dumptime_env *denv, + sieve_size_t *address) +{ + int opt_code = 0; + unsigned int is_test = 0; + + /* Read is_test flag */ + if (!sieve_binary_read_byte(denv->sblock, address, &is_test)) + return FALSE; + + sieve_code_dumpf(denv, "EXECUTE (%s)", + (is_test > 0 ? "test" : "command")); + sieve_code_descend(denv); + + /* Dump optional operands */ + for (;;) { + int opt; + bool opok = TRUE; + + if ((opt = sieve_action_opr_optional_dump(denv, address, + &opt_code)) < 0) + return FALSE; + + if (opt == 0) + break; + + switch (opt_code) { + case OPT_INPUT: + opok = sieve_opr_string_dump_ex(denv, address, + "input", "PIPE"); + break; + case OPT_OUTPUT: + opok = sieve_opr_string_dump(denv, address, "output"); + break; + default: + return FALSE; + } + + if (!opok) + return FALSE; + } + + if (!sieve_opr_string_dump(denv, address, "program-name")) + return FALSE; + + return sieve_opr_stringlist_dump_ex(denv, address, "arguments", ""); +} + +/* + * Code execution + */ + +static int +cmd_execute_operation_execute(const struct sieve_runtime_env *renv, + sieve_size_t *address) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_extension *this_ext = renv->oprtn->ext; + struct sieve_side_effects_list *slist = NULL; + int opt_code = 0; + unsigned int is_test = 0; + struct sieve_stringlist *args_list = NULL; + string_t *pname = NULL, *input = NULL; + struct sieve_variable_storage *var_storage = NULL; + unsigned int var_index; + bool have_input = FALSE; + const char *program_name = NULL; + const char *const *args = NULL; + enum sieve_error error = SIEVE_ERROR_NONE; + buffer_t *outbuf = NULL; + struct sieve_extprogram *sprog = NULL; + int ret; + + /* + * Read operands + */ + + /* The is_test flag */ + if (!sieve_binary_read_byte(renv->sblock, address, &is_test)) { + sieve_runtime_trace_error(renv, "invalid is_test flag"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + /* Optional operands */ + + for (;;) { + int opt; + + if ((opt = sieve_action_opr_optional_read( + renv, address, &opt_code, &ret, &slist)) < 0) + return ret; + + if (opt == 0) + break; + + switch (opt_code) { + case OPT_INPUT: + ret = sieve_opr_string_read_ex(renv, address, "input", + TRUE, &input, NULL); + have_input = TRUE; + break; + case OPT_OUTPUT: + ret = sieve_variable_operand_read( + renv, address, "output", &var_storage, + &var_index); + break; + default: + sieve_runtime_trace_error( + renv, "unknown optional operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + if (ret <= 0) + return ret; + } + + /* Fixed operands */ + + if ((ret = sieve_extprogram_command_read_operands( + renv, address, &pname, &args_list)) <= 0) + return ret; + + program_name = str_c(pname); + if (args_list != NULL && + sieve_stringlist_read_all(args_list, pool_datastack_create(), + &args) < 0) { + sieve_runtime_trace_error(renv, "failed to read args operand"); + return args_list->exec_status; + } + + /* + * Perform operation + */ + + /* Trace */ + + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "execute action"); + sieve_runtime_trace_descend(renv); + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, + "execute program `%s'", + str_sanitize(program_name, 128)); + + sprog = sieve_extprogram_create(this_ext, eenv->scriptenv, + eenv->msgdata, "execute", + program_name, args, &error); + if (sprog != NULL) { + if (var_storage != NULL) { + // FIXME: limit output size + struct ostream *outdata; + + outbuf = buffer_create_dynamic(default_pool, 1024); + outdata = o_stream_create_buffer(outbuf); + sieve_extprogram_set_output(sprog, outdata); + o_stream_unref(&outdata); + } + + if (input == NULL && have_input) { + struct mail *mail = sieve_message_get_mail(renv->msgctx); + + if (sieve_extprogram_set_input_mail(sprog, mail) < 0) { + sieve_extprogram_destroy(&sprog); + if (outbuf != NULL) + buffer_free(&outbuf); + return sieve_runtime_mail_error( + renv, mail, "execute action: " + "failed to read input message"); + } + ret = 1; + } else if (input != NULL) { + struct istream *indata = + i_stream_create_from_data(str_data(input), + str_len(input)); + sieve_extprogram_set_input(sprog, indata); + i_stream_unref(&indata); + ret = 1; + } + + if (ret >= 0) + ret = sieve_extprogram_run(sprog); + sieve_extprogram_destroy(&sprog); + } else { + ret = -1; + } + + if (ret > 0) { + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, + "executed program successfully"); + + if (var_storage != NULL) { + string_t *var; + + if (sieve_variable_get_modifiable(var_storage, + var_index, &var)) { + str_truncate(var, 0); + str_append_str(var, outbuf); + + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, + "assigned output variable"); + } // FIXME: handle failure + } + + } else if (ret < 0) { + if (error == SIEVE_ERROR_NOT_FOUND) { + sieve_runtime_error( + renv, NULL, + "execute action: program `%s' not found", + str_sanitize(program_name, 80)); + } else { + sieve_extprogram_exec_error( + renv->ehandler, + sieve_runtime_get_full_command_location(renv), + "execute action: failed to execute to program `%s'", + str_sanitize(program_name, 80)); + } + } else { + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, + "execute action: " + "program indicated false result"); + } + + if (outbuf != NULL) + buffer_free(&outbuf); + + if (is_test > 0) { + sieve_interpreter_set_test_result(renv->interp, (ret > 0)); + return SIEVE_EXEC_OK; + } + return (ret >= 0 ? SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE); +} diff --git a/pigeonhole/src/plugins/sieve-extprograms/cmd-filter.c b/pigeonhole/src/plugins/sieve-extprograms/cmd-filter.c new file mode 100644 index 0000000..7118ff1 --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/cmd-filter.c @@ -0,0 +1,254 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "array.h" +#include "buffer.h" +#include "str.h" +#include "str-sanitize.h" +#include "istream.h" +#include "ostream.h" +#include "safe-mkstemp.h" +#include "mail-user.h" + +#include "sieve-common.h" +#include "sieve-stringlist.h" +#include "sieve-binary.h" +#include "sieve-code.h" +#include "sieve-message.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 "sieve-ext-variables.h" + +#include "sieve-extprograms-common.h" + +/* Filter command + * + * Syntax: + * "filter" <program-name: string> [<arguments: string-list>] + * + */ + +static bool +cmd_filter_generate(const struct sieve_codegen_env *cgenv, + struct sieve_command *ctx); + +const struct sieve_command_def sieve_cmd_filter = { + .identifier = "filter", + .type = SCT_HYBRID, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = sieve_extprogram_command_validate, + .generate = cmd_filter_generate +}; + +/* + * Filter operation + */ + +static bool +cmd_filter_operation_dump(const struct sieve_dumptime_env *denv, + sieve_size_t *address); +static int +cmd_filter_operation_execute(const struct sieve_runtime_env *renv, + sieve_size_t *address); + +const struct sieve_operation_def sieve_opr_filter = { + .mnemonic = "FILTER", + .ext_def = &sieve_ext_vnd_filter, + .dump = cmd_filter_operation_dump, + .execute = cmd_filter_operation_execute +}; + +/* + * Code generation + */ + +static bool +cmd_filter_generate(const struct sieve_codegen_env *cgenv, + struct sieve_command *cmd) +{ + sieve_operation_emit(cgenv->sblock, cmd->ext, &sieve_opr_filter); + + /* Emit is_test flag */ + sieve_binary_emit_byte(cgenv->sblock, + (uint8_t)(cmd->ast_node->type == SAT_TEST ? + 1 : 0)); + + /* Generate arguments */ + if (!sieve_generate_arguments(cgenv, cmd, NULL)) + return FALSE; + + /* Emit a placeholder when the <arguments> argument is missing */ + if (sieve_ast_argument_next(cmd->first_positional) == NULL) + sieve_opr_omitted_emit(cgenv->sblock); + return TRUE; +} + +/* + * Code dump + */ + +static bool +cmd_filter_operation_dump(const struct sieve_dumptime_env *denv, + sieve_size_t *address) +{ + unsigned int is_test = 0; + + /* Read is_test flag */ + if (!sieve_binary_read_byte(denv->sblock, address, &is_test)) + return FALSE; + + sieve_code_dumpf(denv, "FILTER (%s)", + (is_test > 0 ? "test" : "command")); + sieve_code_descend(denv); + + /* Dump optional operands */ + if (sieve_action_opr_optional_dump(denv, address, NULL) != 0) + return FALSE; + + if (!sieve_opr_string_dump(denv, address, "program-name")) + return FALSE; + + return sieve_opr_stringlist_dump_ex(denv, address, "arguments", ""); +} + +/* + * Code execution + */ + +static int +cmd_filter_operation_execute(const struct sieve_runtime_env *renv, + sieve_size_t *address) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + const struct sieve_extension *this_ext = renv->oprtn->ext; + unsigned int is_test = 0; + struct sieve_stringlist *args_list = NULL; + enum sieve_error error = SIEVE_ERROR_NONE; + string_t *pname = NULL; + const char *program_name = NULL; + const char *const *args = NULL; + struct istream *newmsg = NULL; + struct sieve_extprogram *sprog; + int ret; + + /* + * Read operands + */ + + /* The is_test flag */ + + if (!sieve_binary_read_byte(renv->sblock, address, &is_test)) { + sieve_runtime_trace_error(renv, "invalid is_test flag"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + /* Optional operands */ + + if (sieve_action_opr_optional_read(renv, address, NULL, + &ret, NULL) != 0) + return ret; + + /* Fixed operands */ + + if ((ret = sieve_extprogram_command_read_operands(renv, address, &pname, + &args_list)) <= 0) + return ret; + + program_name = str_c(pname); + if (args_list != NULL && + sieve_stringlist_read_all(args_list, pool_datastack_create(), + &args) < 0) { + sieve_runtime_trace_error(renv, "failed to read args operand"); + return args_list->exec_status; + } + + /* + * Perform operation + */ + + /* Trace */ + + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "filter action"); + sieve_runtime_trace_descend(renv); + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, + "execute program `%s'", str_sanitize(program_name, 128)); + + sprog = sieve_extprogram_create(this_ext, eenv->scriptenv, + eenv->msgdata, "filter", + program_name, args, &error); + if (sprog != NULL) { + struct mail *mail = sieve_message_get_mail(renv->msgctx); + + if (sieve_extprogram_set_input_mail(sprog, mail) < 0) { + sieve_extprogram_destroy(&sprog); + return sieve_runtime_mail_error( + renv, mail, + "filter action: failed to read input message"); + } + sieve_extprogram_set_output_seekable(sprog); + ret = sieve_extprogram_run(sprog); + } else { + ret = -1; + } + + if (ret > 0) + newmsg = sieve_extprogram_get_output_seekable(sprog); + if (sprog != NULL) + sieve_extprogram_destroy(&sprog); + + if (ret > 0 && newmsg != NULL) { + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, + "executed program successfully"); + + i_stream_set_name(newmsg, t_strdup_printf("filter %s output", + program_name)); + newmsg->blocking = TRUE; + if ((ret = sieve_message_substitute(renv->msgctx, + newmsg)) >= 0) { + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, + "changed message"); + } else { + sieve_runtime_critical(renv, NULL, "filter action", + "filter action: " + "failed to substitute message"); + } + + i_stream_unref(&newmsg); + } else if (ret < 0) { + if (error == SIEVE_ERROR_NOT_FOUND) { + sieve_runtime_error(renv, NULL, "filter action: " + "program `%s' not found", + str_sanitize(program_name, 80)); + } else { + sieve_extprogram_exec_error( + renv->ehandler, + sieve_runtime_get_full_command_location(renv), + "filter action: " + "failed to execute to program `%s'", + str_sanitize(program_name, 80)); + } + + } else { + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "filter action: " + "program indicated false result"); + } + + if (is_test > 0) { + sieve_interpreter_set_test_result(renv->interp, (ret > 0)); + + return SIEVE_EXEC_OK; + } + + return (ret >= 0 ? SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE); +} diff --git a/pigeonhole/src/plugins/sieve-extprograms/cmd-pipe.c b/pigeonhole/src/plugins/sieve-extprograms/cmd-pipe.c new file mode 100644 index 0000000..f5a5c34 --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/cmd-pipe.c @@ -0,0 +1,457 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "array.h" +#include "str.h" +#include "str-sanitize.h" + +#include "sieve-common.h" +#include "sieve-stringlist.h" +#include "sieve-code.h" +#include "sieve-message.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 "sieve-extprograms-common.h" + +/* Pipe command + * + * Syntax: + * pipe [":copy"] [":try"] <program-name: string> [<arguments: string-list>] + * + */ + +static bool +cmd_pipe_registered(struct sieve_validator *valdtr, + const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg); +static bool +cmd_pipe_generate(const struct sieve_codegen_env *cgenv, + struct sieve_command *ctx); + +const struct sieve_command_def sieve_cmd_pipe = { + .identifier = "pipe", + .type = SCT_COMMAND, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .registered = cmd_pipe_registered, + .validate = sieve_extprogram_command_validate, + .generate = cmd_pipe_generate, +}; + +/* + * Tagged arguments + */ + +static const struct sieve_argument_def pipe_try_tag = { + .identifier = "try", +}; + +/* + * Pipe operation + */ + +static bool +cmd_pipe_operation_dump(const struct sieve_dumptime_env *denv, + sieve_size_t *address); +static int +cmd_pipe_operation_execute(const struct sieve_runtime_env *renv, + sieve_size_t *address); + +const struct sieve_operation_def sieve_opr_pipe = { + .mnemonic = "PIPE", + .ext_def = &sieve_ext_vnd_pipe, + .dump = cmd_pipe_operation_dump, + .execute = cmd_pipe_operation_execute, +}; + +/* Codes for optional operands */ + +enum cmd_pipe_optional { + OPT_END, + OPT_TRY, +}; + +/* + * Pipe action + */ + +/* Forward declarations */ + +static int +act_pipe_check_duplicate(const struct sieve_runtime_env *renv, + const struct sieve_action *act, + const struct sieve_action *act_other); +static void +act_pipe_print(const struct sieve_action *action, + const struct sieve_result_print_env *rpenv, + bool *keep); +static int +act_pipe_start(const struct sieve_action_exec_env *aenv, void **tr_context); +static int +act_pipe_execute(const struct sieve_action_exec_env *aenv, + void *tr_context, bool *keep); +static int +act_pipe_commit(const struct sieve_action_exec_env *aenv, + void *tr_context); +static void +act_pipe_rollback(const struct sieve_action_exec_env *aenv, + void *tr_context, bool success); + +/* Action object */ + +const struct sieve_action_def act_pipe = { + .name = "pipe", + .flags = SIEVE_ACTFLAG_TRIES_DELIVER, + .check_duplicate = act_pipe_check_duplicate, + .print = act_pipe_print, + .start = act_pipe_start, + .execute = act_pipe_execute, + .commit = act_pipe_commit, + .rollback = act_pipe_rollback, +}; + +/* Action context information */ + +struct ext_pipe_action { + const char *program_name; + const char * const *args; + bool try; +}; + +/* + * Command registration + */ + +static bool +cmd_pipe_registered(struct sieve_validator *valdtr, + const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg) +{ + sieve_validator_register_tag(valdtr, cmd_reg, ext, + &pipe_try_tag, OPT_TRY); + return TRUE; +} + +/* + * Code generation + */ + +static bool +cmd_pipe_generate(const struct sieve_codegen_env *cgenv, + struct sieve_command *cmd) +{ + sieve_operation_emit(cgenv->sblock, cmd->ext, &sieve_opr_pipe); + + /* Generate arguments */ + if (!sieve_generate_arguments(cgenv, cmd, NULL)) + return FALSE; + + /* Emit a placeholder when the <arguments> argument is missing */ + if (sieve_ast_argument_next(cmd->first_positional) == NULL) + sieve_opr_omitted_emit(cgenv->sblock); + return TRUE; +} + +/* + * Code dump + */ + +static bool +cmd_pipe_operation_dump(const struct sieve_dumptime_env *denv, + sieve_size_t *address) +{ + int opt_code = 0; + + sieve_code_dumpf(denv, "PIPE"); + sieve_code_descend(denv); + + /* Dump optional operands */ + for (;;) { + int opt; + + if ((opt = sieve_action_opr_optional_dump(denv, address, + &opt_code)) < 0) + return FALSE; + + if (opt == 0) + break; + + switch (opt_code) { + case OPT_TRY: + sieve_code_dumpf(denv, "try"); + break; + default: + return FALSE; + } + } + + if (!sieve_opr_string_dump(denv, address, "program-name")) + return FALSE; + + return sieve_opr_stringlist_dump_ex(denv, address, "arguments", ""); +} + +/* + * Code execution + */ + +static int +cmd_pipe_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 ext_pipe_action *act; + pool_t pool; + int opt_code = 0; + struct sieve_stringlist *args_list = NULL; + string_t *pname = NULL; + bool try = FALSE; + int ret; + + /* + * Read operands + */ + + /* Optional operands */ + + for (;;) { + int opt; + + if ((opt = sieve_action_opr_optional_read(renv, address, + &opt_code, &ret, + &slist)) < 0) + return ret; + + if (opt == 0) + break; + + switch (opt_code) { + case OPT_TRY: + try = TRUE; + break; + default: + sieve_runtime_trace_error( + renv, "unknown optional operand"); + return SIEVE_EXEC_BIN_CORRUPT; + } + } + + /* Fixed operands */ + + if ((ret = sieve_extprogram_command_read_operands(renv, address, &pname, + &args_list)) <= 0) + return ret; + + /* + * Perform operation + */ + + /* Trace */ + + sieve_runtime_trace(renv, SIEVE_TRLVL_ACTIONS, "pipe action"); + + /* Compose action */ + + pool = sieve_result_pool(renv->result); + act = p_new(pool, struct ext_pipe_action, 1); + + if (args_list != NULL && + sieve_stringlist_read_all(args_list, pool, &act->args) < 0) { + sieve_runtime_trace_error(renv, "failed to read args operand"); + return args_list->exec_status; + } + + act->program_name = p_strdup(pool, str_c(pname)); + act->try = try; + + if (sieve_result_add_action(renv, this_ext, "pipe", &act_pipe, slist, + (void *)act, 0, TRUE) < 0) + return SIEVE_EXEC_FAILURE; + return SIEVE_EXEC_OK; +} + +/* + * Action + */ + +/* Runtime verification */ + +static int +act_pipe_check_duplicate(const struct sieve_runtime_env *renv ATTR_UNUSED, + const struct sieve_action *act, + const struct sieve_action *act_other) +{ + struct ext_pipe_action *new_act, *old_act; + + if (act->context == NULL || act_other->context == NULL) + return 0; + + new_act = (struct ext_pipe_action *) act->context; + old_act = (struct ext_pipe_action *) act_other->context; + + if (strcmp(new_act->program_name, old_act->program_name) == 0) { + sieve_runtime_error(renv, act->location, + "duplicate pipe \"%s\" action not allowed " + "(previously triggered one was here: %s)", + new_act->program_name, act_other->location); + return -1; + } + + return 0; +} + +/* Result printing */ + +static void +act_pipe_print(const struct sieve_action *action, + const struct sieve_result_print_env *rpenv, + bool *keep ATTR_UNUSED) +{ + const struct ext_pipe_action *act = + (const struct ext_pipe_action *)action->context; + + sieve_result_action_printf( + rpenv, "pipe message to external program '%s':", + act->program_name); + + /* Print main method parameters */ + + sieve_result_printf( + rpenv, " => try : %s\n", + (act->try ? "yes" : "no")); + + /* FIXME: print args */ + + /* Finish output with an empty line */ + sieve_result_printf(rpenv, "\n"); +} + +/* Result execution */ + +struct act_pipe_transaction { + struct sieve_extprogram *sprog; +}; + +static int +act_pipe_start(const struct sieve_action_exec_env *aenv, void **tr_context) +{ + struct act_pipe_transaction *trans; + pool_t pool = sieve_result_pool(aenv->result); + + /* Create transaction context */ + trans = p_new(pool, struct act_pipe_transaction, 1); + *tr_context = (void *)trans; + + return SIEVE_EXEC_OK; +} + +static int +act_pipe_execute(const struct sieve_action_exec_env *aenv, + void *tr_context, bool *keep) +{ + const struct sieve_action *action = aenv->action; + const struct sieve_execute_env *eenv = aenv->exec_env; + const struct ext_pipe_action *act = + (const struct ext_pipe_action *)action->context; + struct act_pipe_transaction *trans = tr_context; + struct mail *mail = (action->mail != NULL ? + action->mail : + sieve_message_get_mail(aenv->msgctx)); + enum sieve_error error = SIEVE_ERROR_NONE; + + trans->sprog = sieve_extprogram_create(action->ext, eenv->scriptenv, + eenv->msgdata, "pipe", + act->program_name, act->args, + &error); + if (trans->sprog != NULL) { + if (sieve_extprogram_set_input_mail(trans->sprog, mail) < 0) { + sieve_extprogram_destroy(&trans->sprog); + return sieve_result_mail_error( + aenv, mail, "failed to read input message"); + } + } + + *keep = FALSE; + return SIEVE_EXEC_OK; +} + +static int +act_pipe_commit(const struct sieve_action_exec_env *aenv, + void *tr_context ATTR_UNUSED) +{ + const struct sieve_action *action = aenv->action; + const struct sieve_execute_env *eenv = aenv->exec_env; + const struct ext_pipe_action *act = + (const struct ext_pipe_action *)action->context; + struct act_pipe_transaction *trans = tr_context; + enum sieve_error error = SIEVE_ERROR_NONE; + int ret; + + if (trans->sprog != NULL) { + ret = sieve_extprogram_run(trans->sprog); + sieve_extprogram_destroy(&trans->sprog); + } else { + ret = -1; + } + + if (ret > 0) { + struct event_passthrough *e = + sieve_action_create_finish_event(aenv)-> + add_str("pipe_program", + str_sanitize(act->program_name, 256)); + + sieve_result_event_log(aenv, e->event(), + "piped message to program `%s'", + str_sanitize(act->program_name, 128)); + + /* Indicate that message was successfully 'forwarded' */ + eenv->exec_status->message_forwarded = TRUE; + } else { + if (ret < 0) { + if (error == SIEVE_ERROR_NOT_FOUND) { + sieve_result_error( + aenv, + "failed to pipe message to program: " + "program `%s' not found", + str_sanitize(act->program_name, 80)); + } else { + sieve_extprogram_exec_error( + aenv->ehandler, NULL, + "failed to pipe message to program `%s'", + str_sanitize(act->program_name, 80)); + } + } else { + sieve_extprogram_exec_error( + aenv->ehandler, NULL, + "failed to execute to program `%s'", + str_sanitize(act->program_name, 80)); + } + + if (act->try) + return SIEVE_EXEC_OK; + return SIEVE_EXEC_FAILURE; + } + + return SIEVE_EXEC_OK; +} + +static void +act_pipe_rollback(const struct sieve_action_exec_env *aenv ATTR_UNUSED, + void *tr_context, bool success ATTR_UNUSED) +{ + struct act_pipe_transaction *trans = tr_context; + + if (trans->sprog != NULL) + sieve_extprogram_destroy(&trans->sprog); +} diff --git a/pigeonhole/src/plugins/sieve-extprograms/ext-execute.c b/pigeonhole/src/plugins/sieve-extprograms/ext-execute.c new file mode 100644 index 0000000..055ee88 --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/ext-execute.c @@ -0,0 +1,80 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +/* Extension vnd.dovecot.execute + * ----------------------------- + * + * Authors: Stephan Bosch + * Specification: vendor-defined; spec-bosch-sieve-extprograms + * Implementation: full + * Status: experimental + * + */ + +#include "lib.h" + +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-binary.h" + +#include "sieve-validator.h" +#include "sieve-interpreter.h" + +#include "sieve-ext-copy.h" + +#include "sieve-extprograms-common.h" + +/* + * Extension + */ + +static bool ext_execute_load(const struct sieve_extension *ext, void **context); +static void ext_execute_unload(const struct sieve_extension *ext); +static bool ext_execute_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); + +const struct sieve_extension_def sieve_ext_vnd_execute = { + .name = "vnd.dovecot.execute", + .load = ext_execute_load, + .unload = ext_execute_unload, + .validator_load = ext_execute_validator_load, + SIEVE_EXT_DEFINE_OPERATION(sieve_opr_execute) +}; + +/* + * Context + */ + +static bool ext_execute_load(const struct sieve_extension *ext, void **context) +{ + if ( *context != NULL ) { + ext_execute_unload(ext); + *context = NULL; + } + + *context = (void *)sieve_extprograms_config_init(ext); + return TRUE; +} + +static void ext_execute_unload(const struct sieve_extension *ext) +{ + struct sieve_extprograms_config *ext_config = + (struct sieve_extprograms_config *)ext->context; + + if ( ext_config == NULL ) return; + + sieve_extprograms_config_deinit(&ext_config); +} + +/* + * Validation + */ + +static bool ext_execute_validator_load +(const struct sieve_extension *ext, struct sieve_validator *valdtr) +{ + /* Register commands */ + sieve_validator_register_command(valdtr, ext, &sieve_cmd_execute); + + return TRUE; +} diff --git a/pigeonhole/src/plugins/sieve-extprograms/ext-filter.c b/pigeonhole/src/plugins/sieve-extprograms/ext-filter.c new file mode 100644 index 0000000..af1f8f1 --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/ext-filter.c @@ -0,0 +1,80 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +/* Extension vnd.dovecot.filter + * ----------------------------- + * + * Authors: Stephan Bosch + * Specification: vendor-defined; spec-bosch-sieve-extprograms + * Implementation: full + * Status: experimental + * + */ + +#include "lib.h" + +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-binary.h" + +#include "sieve-validator.h" +#include "sieve-interpreter.h" + +#include "sieve-ext-copy.h" + +#include "sieve-extprograms-common.h" + +/* + * Extension + */ + +static bool ext_filter_load(const struct sieve_extension *ext, void **context); +static void ext_filter_unload(const struct sieve_extension *ext); +static bool ext_filter_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); + +const struct sieve_extension_def sieve_ext_vnd_filter = { + .name = "vnd.dovecot.filter", + .load = ext_filter_load, + .unload = ext_filter_unload, + .validator_load = ext_filter_validator_load, + SIEVE_EXT_DEFINE_OPERATION(sieve_opr_filter), +}; + +/* + * Context + */ + +static bool ext_filter_load(const struct sieve_extension *ext, void **context) +{ + if ( *context != NULL ) { + ext_filter_unload(ext); + *context = NULL; + } + + *context = (void *)sieve_extprograms_config_init(ext); + return TRUE; +} + +static void ext_filter_unload(const struct sieve_extension *ext) +{ + struct sieve_extprograms_config *ext_config = + (struct sieve_extprograms_config *)ext->context; + + if ( ext_config == NULL ) return; + + sieve_extprograms_config_deinit(&ext_config); +} + +/* + * Validation + */ + +static bool ext_filter_validator_load +(const struct sieve_extension *ext, struct sieve_validator *valdtr) +{ + /* Register commands */ + sieve_validator_register_command(valdtr, ext, &sieve_cmd_filter); + + return TRUE; +} diff --git a/pigeonhole/src/plugins/sieve-extprograms/ext-pipe.c b/pigeonhole/src/plugins/sieve-extprograms/ext-pipe.c new file mode 100644 index 0000000..5da7d36 --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/ext-pipe.c @@ -0,0 +1,114 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +/* Extension vnd.dovecot.pipe + * ----------------------------- + * + * Authors: Stephan Bosch + * Specification: vendor-define; spec-bosch-sieve-extprograms + * Implementation: full + * Status: experimental + * + */ + +#include "lib.h" + +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-binary.h" + +#include "sieve-validator.h" +#include "sieve-interpreter.h" + +#include "sieve-ext-copy.h" + +#include "sieve-extprograms-common.h" + +/* + * Extension + */ + +static bool ext_pipe_load(const struct sieve_extension *ext, void **context); +static void ext_pipe_unload(const struct sieve_extension *ext); +static bool ext_pipe_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); + +const struct sieve_extension_def sieve_ext_vnd_pipe = { + .name = "vnd.dovecot.pipe", + .load = ext_pipe_load, + .unload = ext_pipe_unload, + .validator_load = ext_pipe_validator_load, + SIEVE_EXT_DEFINE_OPERATION(sieve_opr_pipe), +}; + +/* + * Context + */ + +static bool ext_pipe_load(const struct sieve_extension *ext, void **context) +{ + if ( *context != NULL ) { + ext_pipe_unload(ext); + *context = NULL; + } + + *context = (void *)sieve_extprograms_config_init(ext); + return TRUE; +} + +static void ext_pipe_unload(const struct sieve_extension *ext) +{ + struct sieve_extprograms_config *ext_config = + (struct sieve_extprograms_config *)ext->context; + + if ( ext_config == NULL ) return; + + sieve_extprograms_config_deinit(&ext_config); +} + +/* + * Validation + */ + +static bool ext_pipe_validator_validate + (const struct sieve_extension *ext, + struct sieve_validator *valdtr, void *context, + struct sieve_ast_argument *require_arg, + bool required); + +static const struct sieve_validator_extension pipe_validator_extension = { + .ext = &sieve_ext_vnd_pipe, + .validate = ext_pipe_validator_validate +}; + +static bool ext_pipe_validator_load +(const struct sieve_extension *ext, struct sieve_validator *valdtr) +{ + /* Register commands */ + sieve_validator_register_command(valdtr, ext, &sieve_cmd_pipe); + + /* Register extension to validator */ + sieve_validator_extension_register + (valdtr, ext, &pipe_validator_extension, NULL); + + return TRUE; +} + +static bool ext_pipe_validator_validate +(const struct sieve_extension *ext, + struct sieve_validator *valdtr, void *context ATTR_UNUSED, + struct sieve_ast_argument *require_arg ATTR_UNUSED, + bool required ATTR_UNUSED) +{ + struct sieve_extprograms_config *ext_config = + (struct sieve_extprograms_config *) ext->context; + + if ( ext_config != NULL && ext_config->copy_ext != NULL ) { + /* Register :copy command tag */ + sieve_ext_copy_register_tag(valdtr, + ext_config->copy_ext, sieve_cmd_pipe.identifier); + } + return TRUE; +} + + diff --git a/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.c b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.c new file mode 100644 index 0000000..3c9ff23 --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.c @@ -0,0 +1,648 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "lib-signals.h" +#include "str.h" +#include "strfuncs.h" +#include "str-sanitize.h" +#include "unichar.h" +#include "array.h" +#include "eacces-error.h" +#include "smtp-params.h" +#include "istream.h" +#include "istream-crlf.h" +#include "istream-header-filter.h" +#include "ostream.h" +#include "mail-user.h" +#include "mail-storage.h" + +#include "program-client.h" + +#include "sieve-common.h" +#include "sieve-settings.h" +#include "sieve-error.h" +#include "sieve-extensions.h" +#include "sieve-ast.h" +#include "sieve-commands.h" +#include "sieve-stringlist.h" +#include "sieve-code.h" +#include "sieve-actions.h" +#include "sieve-validator.h" +#include "sieve-runtime.h" +#include "sieve-interpreter.h" + +#include "sieve-ext-copy.h" +#include "sieve-ext-variables.h" + +#include "sieve-extprograms-common.h" + +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/socket.h> + +/* + * Limits + */ + +#define SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN 128 +#define SIEVE_EXTPROGRAMS_MAX_PROGRAM_ARG_LEN 1024 + +#define SIEVE_EXTPROGRAMS_DEFAULT_EXEC_TIMEOUT_SECS 10 +#define SIEVE_EXTPROGRAMS_CONNECT_TIMEOUT_MSECS 5 + +/* + * Pipe Extension Context + */ + +struct sieve_extprograms_config *sieve_extprograms_config_init +(const struct sieve_extension *ext) +{ + struct sieve_instance *svinst = ext->svinst; + struct sieve_extprograms_config *ext_config; + const char *extname = sieve_extension_name(ext); + const char *bin_dir, *socket_dir, *input_eol; + sieve_number_t execute_timeout; + + extname = strrchr(extname, '.'); + i_assert(extname != NULL); + extname++; + + bin_dir = sieve_setting_get + (svinst, t_strdup_printf("sieve_%s_bin_dir", extname)); + socket_dir = sieve_setting_get + (svinst, t_strdup_printf("sieve_%s_socket_dir", extname)); + input_eol = sieve_setting_get + (svinst, t_strdup_printf("sieve_%s_input_eol", extname)); + + ext_config = i_new(struct sieve_extprograms_config, 1); + ext_config->execute_timeout = + SIEVE_EXTPROGRAMS_DEFAULT_EXEC_TIMEOUT_SECS; + + if ( bin_dir == NULL && socket_dir == NULL ) { + e_debug(svinst->event, "%s extension: " + "no bin or socket directory specified; extension is unconfigured " + "(both sieve_%s_bin_dir and sieve_%s_socket_dir are not set)", + sieve_extension_name(ext), extname, extname); + } else { + ext_config->bin_dir = i_strdup(bin_dir); + ext_config->socket_dir = i_strdup(socket_dir); + + if (sieve_setting_get_duration_value + (svinst, t_strdup_printf("sieve_%s_exec_timeout", extname), + &execute_timeout)) { + ext_config->execute_timeout = execute_timeout; + } + + ext_config->default_input_eol = SIEVE_EXTPROGRAMS_EOL_CRLF; + if (input_eol != NULL && strcasecmp(input_eol, "lf") == 0) + ext_config->default_input_eol = SIEVE_EXTPROGRAMS_EOL_LF; + } + + if ( sieve_extension_is(ext, sieve_ext_vnd_pipe) ) + ext_config->copy_ext = sieve_ext_copy_get_extension(ext->svinst); + if ( sieve_extension_is(ext, sieve_ext_vnd_execute) ) + ext_config->var_ext = sieve_ext_variables_get_extension(ext->svinst); + return ext_config; +} + +void sieve_extprograms_config_deinit +(struct sieve_extprograms_config **ext_config) +{ + if ( *ext_config == NULL ) + return; + + i_free((*ext_config)->bin_dir); + i_free((*ext_config)->socket_dir); + i_free((*ext_config)); + + *ext_config = NULL; +} + +/* + * Program name and arguments + */ + +bool sieve_extprogram_name_is_valid(string_t *name) +{ + ARRAY_TYPE(unichars) uni_name; + unsigned int count, i; + const unichar_t *name_chars; + size_t namelen = str_len(name); + + /* Check minimum length */ + if ( namelen == 0 ) + return FALSE; + + /* Check worst-case maximum length */ + if ( namelen > SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN * 4 ) + return FALSE; + + /* Intialize array for unicode characters */ + t_array_init(&uni_name, namelen * 4); + + /* Convert UTF-8 to UCS4/UTF-32 */ + if ( uni_utf8_to_ucs4_n(str_data(name), namelen, &uni_name) < 0 ) + return FALSE; + name_chars = array_get(&uni_name, &count); + + /* Check true maximum length */ + if ( count > SIEVE_EXTPROGRAMS_MAX_PROGRAM_NAME_LEN ) + return FALSE; + + /* Scan name for invalid characters + * FIXME: compliance with Net-Unicode Definition (Section 2 of + * RFC 5198) is not checked fully and no normalization + * is performed. + */ + for ( i = 0; i < count; i++ ) { + + /* 0000-001F; [CONTROL CHARACTERS] */ + if ( name_chars[i] <= 0x001f ) + return FALSE; + + /* 002F; SLASH */ + if ( name_chars[i] == 0x002f ) + return FALSE; + + /* 007F; DELETE */ + if ( name_chars[i] == 0x007f ) + return FALSE; + + /* 0080-009F; [CONTROL CHARACTERS] */ + if ( name_chars[i] >= 0x0080 && name_chars[i] <= 0x009f ) + return FALSE; + + /* 00FF */ + if ( name_chars[i] == 0x00ff ) + return FALSE; + + /* 2028; LINE SEPARATOR */ + /* 2029; PARAGRAPH SEPARATOR */ + if ( name_chars[i] == 0x2028 || name_chars[i] == 0x2029 ) + return FALSE; + } + + return TRUE; +} + +bool sieve_extprogram_arg_is_valid(string_t *arg) +{ + const unsigned char *chars; + unsigned int i; + + /* Check maximum length */ + if ( str_len(arg) > SIEVE_EXTPROGRAMS_MAX_PROGRAM_ARG_LEN ) + return FALSE; + + /* Check invalid characters */ + chars = str_data(arg); + for ( i = 0; i < str_len(arg); i++ ) { + /* 0010; CR */ + if ( chars[i] == 0x0D ) + return FALSE; + + /* 0010; LF */ + if ( chars[i] == 0x0A ) + return FALSE; + } + + return TRUE; +} + +/* + * Command validation + */ + +struct _arg_validate_context { + struct sieve_validator *valdtr; + struct sieve_command *cmd; +}; + +static int _arg_validate +(void *context, struct sieve_ast_argument *item) +{ + struct _arg_validate_context *actx = (struct _arg_validate_context *) context; + + if ( sieve_argument_is_string_literal(item) ) { + string_t *arg = sieve_ast_argument_str(item); + + if ( !sieve_extprogram_arg_is_valid(arg) ) { + sieve_argument_validate_error(actx->valdtr, item, + "%s %s: specified external program argument `%s' is invalid", + sieve_command_identifier(actx->cmd), sieve_command_type_name(actx->cmd), + str_sanitize(str_c(arg), 128)); + + return -1; + } + } + + return 1; +} + +bool sieve_extprogram_command_validate +(struct sieve_validator *valdtr, struct sieve_command *cmd) +{ + struct sieve_ast_argument *arg = cmd->first_positional; + struct sieve_ast_argument *stritem; + struct _arg_validate_context actx; + string_t *program_name; + + if ( arg == NULL ) { + sieve_command_validate_error(valdtr, cmd, + "the %s %s expects at least one positional argument, but none was found", + sieve_command_identifier(cmd), sieve_command_type_name(cmd)); + return FALSE; + } + + /* <program-name: string> argument */ + + if ( !sieve_validate_positional_argument + (valdtr, cmd, arg, "program-name", 1, SAAT_STRING) ) { + return FALSE; + } + + if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) ) + return FALSE; + + /* Variables are not allowed */ + if ( !sieve_argument_is_string_literal(arg) ) { + sieve_argument_validate_error(valdtr, arg, + "the %s %s requires a constant string " + "for its program-name argument", + sieve_command_identifier(cmd), sieve_command_type_name(cmd)); + return FALSE; + } + + /* Check program name */ + program_name = sieve_ast_argument_str(arg); + if ( !sieve_extprogram_name_is_valid(program_name) ) { + sieve_argument_validate_error(valdtr, arg, + "%s %s: invalid program name '%s'", + sieve_command_identifier(cmd), sieve_command_type_name(cmd), + str_sanitize(str_c(program_name), 80)); + return FALSE; + } + + /* Optional <arguments: string-list> argument */ + + arg = sieve_ast_argument_next(arg); + if ( arg == NULL ) + return TRUE; + + if ( !sieve_validate_positional_argument + (valdtr, cmd, arg, "arguments", 2, SAAT_STRING_LIST) ) { + return FALSE; + } + + if ( !sieve_validator_argument_activate(valdtr, cmd, arg, FALSE) ) + return FALSE; + + /* Check arguments */ + actx.valdtr = valdtr; + actx.cmd = cmd; + stritem = arg; + if ( sieve_ast_stringlist_map + (&stritem, (void *)&actx, _arg_validate) <= 0 ) { + return FALSE; + } + + if ( sieve_ast_argument_next(arg) != NULL ) { + sieve_command_validate_error(valdtr, cmd, + "the %s %s expects at most two positional arguments, but more were found", + sieve_command_identifier(cmd), sieve_command_type_name(cmd)); + return FALSE; + } + + return TRUE; +} + +/* + * Common command operands + */ + +int sieve_extprogram_command_read_operands +(const struct sieve_runtime_env *renv, sieve_size_t *address, + string_t **pname_r, struct sieve_stringlist **args_list_r) +{ + string_t *arg; + int ret; + + /* + * Read fixed operands + */ + + if ( (ret=sieve_opr_string_read + (renv, address, "program-name", pname_r)) <= 0 ) + return ret; + + if ( (ret=sieve_opr_stringlist_read_ex + (renv, address, "arguments", TRUE, args_list_r)) <= 0 ) + return ret; + + /* + * Check operands + */ + + arg = NULL; + while ( *args_list_r != NULL && + (ret=sieve_stringlist_next_item(*args_list_r, &arg)) > 0 ) { + if ( !sieve_extprogram_arg_is_valid(arg) ) { + sieve_runtime_error(renv, NULL, + "specified :args item `%s' is invalid", + str_sanitize(str_c(arg), 128)); + return SIEVE_EXEC_FAILURE; + } + } + + if ( ret < 0 ) { + sieve_runtime_trace_error(renv, "invalid args-list item"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + return SIEVE_EXEC_OK; +} + +/* + * Running external programs + */ + +struct sieve_extprogram { + struct sieve_instance *svinst; + const struct sieve_extprograms_config *ext_config; + + const struct sieve_script_env *scriptenv; + struct program_client_settings set; + struct program_client *program_client; +}; + +void sieve_extprogram_exec_error +(struct sieve_error_handler *ehandler, const char *location, + const char *fmt, ...) +{ + char str[256]; + struct tm *tm; + const char *timestamp; + + tm = localtime(&ioloop_time); + + timestamp = + ( strftime(str, sizeof(str), " [%Y-%m-%d %H:%M:%S]", tm) > 0 ? str : "" ); + + va_list args; + va_start(args, fmt); + + T_BEGIN { + sieve_error(ehandler, location, + "%s: refer to server log for more information.%s", + t_strdup_vprintf(fmt, args), timestamp); + } T_END; + + va_end(args); +} + +/* API */ + +struct sieve_extprogram *sieve_extprogram_create +(const struct sieve_extension *ext, const struct sieve_script_env *senv, + const struct sieve_message_data *msgdata, const char *action, + const char *program_name, const char * const *args, + enum sieve_error *error_r) +{ + struct sieve_instance *svinst = ext->svinst; + struct sieve_extprograms_config *ext_config = + (struct sieve_extprograms_config *) ext->context; + const struct smtp_address *sender, *recipient, *orig_recipient; + struct sieve_extprogram *sprog; + const char *path = NULL; + struct stat st; + bool fork = FALSE; + + e_debug(svinst->event, "action %s: " + "running program: %s", action, program_name); + + if ( ext_config == NULL || + (ext_config->bin_dir == NULL && ext_config->socket_dir == NULL) ) { + e_error(svinst->event, "action %s: " + "failed to execute program `%s': " + "vnd.dovecot.%s extension is unconfigured", + action, program_name, action); + *error_r = SIEVE_ERROR_NOT_FOUND; + return NULL; + } + + /* Try socket first */ + if ( ext_config->socket_dir != NULL ) { + path = t_strconcat(senv->user->set->base_dir, "/", + ext_config->socket_dir, "/", program_name, NULL); + if ( stat(path, &st) < 0 ) { + switch ( errno ) { + case ENOENT: + e_debug(svinst->event, "action %s: " + "socket path `%s' for program `%s' not found", + action, path, program_name); + break; + case EACCES: + e_error(svinst->event, "action %s: " + "failed to stat socket: %s", + action, eacces_error_get("stat", path)); + *error_r = SIEVE_ERROR_NO_PERMISSION; + return NULL; + default: + e_error(svinst->event, "action %s: " + "failed to stat socket `%s': %m", + action, path); + *error_r = SIEVE_ERROR_TEMP_FAILURE; + return NULL; + } + path = NULL; + } else if ( !S_ISSOCK(st.st_mode) ) { + e_error(svinst->event, "action %s: " + "socket path `%s' for program `%s' is not a socket", + action, path, program_name); + *error_r = SIEVE_ERROR_NOT_POSSIBLE; + return NULL; + } + } + + /* Try executable next */ + if ( path == NULL && ext_config->bin_dir != NULL ) { + fork = TRUE; + path = t_strconcat(ext_config->bin_dir, "/", program_name, NULL); + if ( stat(path, &st) < 0 ) { + switch ( errno ) { + case ENOENT: + e_debug(svinst->event, "action %s: " + "executable path `%s' for program `%s' not found", + action, path, program_name); + *error_r = SIEVE_ERROR_NOT_FOUND; + break; + case EACCES: + e_error(svinst->event, "action %s: " + "failed to stat program: %s", + action, eacces_error_get("stat", path)); + *error_r = SIEVE_ERROR_NO_PERMISSION; + break; + default: + e_error(svinst->event, "action %s: " + "failed to stat program `%s': %m", + action, path); + *error_r = SIEVE_ERROR_TEMP_FAILURE; + break; + } + + return NULL; + } else if ( !S_ISREG(st.st_mode) ) { + e_error(svinst->event, "action %s: " + "executable `%s' for program `%s' is not a regular file", + action, path, program_name); + *error_r = SIEVE_ERROR_NOT_POSSIBLE; + return NULL; + } else if ( (st.st_mode & S_IWOTH) != 0 ) { + e_error(svinst->event, "action %s: " + "executable `%s' for program `%s' is world-writable", + action, path, program_name); + *error_r = SIEVE_ERROR_NO_PERMISSION; + return NULL; + } + } + + /* None found ? */ + if ( path == NULL ) { + e_error(svinst->event, "action %s: " + "program `%s' not found", action, program_name); + *error_r = SIEVE_ERROR_NOT_FOUND; + return NULL; + } + + sprog = i_new(struct sieve_extprogram, 1); + sprog->svinst = ext->svinst; + sprog->ext_config = ext_config; + sprog->scriptenv = senv; + + sprog->set.client_connect_timeout_msecs = + SIEVE_EXTPROGRAMS_CONNECT_TIMEOUT_MSECS; + sprog->set.input_idle_timeout_msecs = + ext_config->execute_timeout * 1000; + restrict_access_init(&sprog->set.restrict_set); + if (senv->user->uid != 0) + sprog->set.restrict_set.uid = senv->user->uid; + if (senv->user->gid != 0) + sprog->set.restrict_set.gid = senv->user->gid; + sprog->set.debug = svinst->debug; + + if ( fork ) { + sprog->program_client = + program_client_local_create(path, args, &sprog->set); + } else { + sprog->program_client = + program_client_unix_create(path, args, &sprog->set, FALSE); + } + + if ( svinst->username != NULL ) + program_client_set_env(sprog->program_client, "USER", svinst->username); + if ( svinst->home_dir != NULL ) + program_client_set_env(sprog->program_client, "HOME", svinst->home_dir); + if ( svinst->hostname != NULL ) + program_client_set_env(sprog->program_client, "HOST", svinst->hostname); + + sender = msgdata->envelope.mail_from; + recipient = msgdata->envelope.rcpt_to; + orig_recipient = NULL; + if ( msgdata->envelope.rcpt_params != NULL ) + orig_recipient = msgdata->envelope.rcpt_params->orcpt.addr; + + if ( !smtp_address_isnull(sender) ) { + program_client_set_env(sprog->program_client, "SENDER", + smtp_address_encode(sender)); + } + if ( !smtp_address_isnull(recipient) ) { + program_client_set_env(sprog->program_client, "RECIPIENT", + smtp_address_encode(recipient)); + } + if ( !smtp_address_isnull(orig_recipient) ) { + program_client_set_env(sprog->program_client, "ORIG_RECIPIENT", + smtp_address_encode(orig_recipient)); + } + + return sprog; +} + +void sieve_extprogram_destroy(struct sieve_extprogram **_sprog) +{ + struct sieve_extprogram *sprog = *_sprog; + + program_client_destroy(&sprog->program_client); + i_free(sprog); + *_sprog = NULL; +} + +/* I/0 */ + +void sieve_extprogram_set_output +(struct sieve_extprogram *sprog, struct ostream *output) +{ + program_client_set_output(sprog->program_client, output); +} + +void sieve_extprogram_set_input +(struct sieve_extprogram *sprog, struct istream *input) +{ + switch (sprog->ext_config->default_input_eol) { + case SIEVE_EXTPROGRAMS_EOL_LF: + input = i_stream_create_lf(input); + break; + case SIEVE_EXTPROGRAMS_EOL_CRLF: + input = i_stream_create_crlf(input); + break; + default: + i_unreached(); + } + + program_client_set_input(sprog->program_client, input); + + i_stream_unref(&input); +} + +void sieve_extprogram_set_output_seekable +(struct sieve_extprogram *sprog) +{ + string_t *prefix; + prefix = t_str_new(128); + mail_user_set_get_temp_prefix(prefix, sprog->scriptenv->user->set); + + program_client_set_output_seekable(sprog->program_client, str_c(prefix)); +} + +struct istream *sieve_extprogram_get_output_seekable +(struct sieve_extprogram *sprog) +{ + return program_client_get_output_seekable(sprog->program_client); +} + +int sieve_extprogram_set_input_mail +(struct sieve_extprogram *sprog, struct mail *mail) +{ + struct istream *input; + + if (mail_get_stream(mail, NULL, NULL, &input) < 0) + return -1; + + sieve_extprogram_set_input(sprog, input); + return 1; +} + +int sieve_extprogram_run(struct sieve_extprogram *sprog) +{ + switch (program_client_run(sprog->program_client)) { + case PROGRAM_CLIENT_EXIT_STATUS_INTERNAL_FAILURE: + return -1; + case PROGRAM_CLIENT_EXIT_STATUS_FAILURE: + return 0; + case PROGRAM_CLIENT_EXIT_STATUS_SUCCESS: + return 1; + } + i_unreached(); +} + diff --git a/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.h b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.h new file mode 100644 index 0000000..063c02b --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-common.h @@ -0,0 +1,107 @@ +#ifndef SIEVE_EXTPROGRAMS_COMMON_H +#define SIEVE_EXTPROGRAMS_COMMON_H + +#include "sieve-common.h" + +/* + * Extension configuration + */ + +enum sieve_extprograms_eol { + SIEVE_EXTPROGRAMS_EOL_CRLF = 0, + SIEVE_EXTPROGRAMS_EOL_LF +}; + +struct sieve_extprograms_config { + const struct sieve_extension *copy_ext; + const struct sieve_extension *var_ext; + + char *socket_dir; + char *bin_dir; + + enum sieve_extprograms_eol default_input_eol; + + unsigned int execute_timeout; +}; + +struct sieve_extprograms_config *sieve_extprograms_config_init + (const struct sieve_extension *ext); +void sieve_extprograms_config_deinit + (struct sieve_extprograms_config **ext_config); + +/* + * Extensions + */ + +extern const struct sieve_extension_def sieve_ext_vnd_pipe; +extern const struct sieve_extension_def sieve_ext_vnd_filter; +extern const struct sieve_extension_def sieve_ext_vnd_execute; + +/* + * Commands + */ + +extern const struct sieve_command_def sieve_cmd_pipe; +extern const struct sieve_command_def sieve_cmd_filter; +extern const struct sieve_command_def sieve_cmd_execute; + +/* + * Operations + */ + +extern const struct sieve_operation_def sieve_opr_pipe; +extern const struct sieve_operation_def sieve_opr_filter; +extern const struct sieve_operation_def sieve_opr_execute; + +/* + * Program name and arguments + */ + +bool sieve_extprogram_arg_is_valid(string_t *arg); +bool sieve_extprogram_name_is_valid(string_t *name); + +/* + * Command validation + */ + +bool sieve_extprogram_command_validate + (struct sieve_validator *valdtr, struct sieve_command *cmd); + +/* + * Common command operands + */ + +int sieve_extprogram_command_read_operands + (const struct sieve_runtime_env *renv, sieve_size_t *address, + string_t **pname_r, struct sieve_stringlist **args_list_r); + +/* + * Running external programs + */ + +void sieve_extprogram_exec_error + (struct sieve_error_handler *ehandler, const char *location, + const char *fmt, ...) ATTR_FORMAT(3, 4); + +struct sieve_extprogram *sieve_extprogram_create + (const struct sieve_extension *ext, const struct sieve_script_env *senv, + const struct sieve_message_data *msgdata, const char *action, + const char *program_name, const char * const *args, + enum sieve_error *error_r); +void sieve_extprogram_destroy(struct sieve_extprogram **_sprog); + +void sieve_extprogram_set_output + (struct sieve_extprogram *sprog, struct ostream *output); +void sieve_extprogram_set_output_seekable + (struct sieve_extprogram *sprog); +struct istream *sieve_extprogram_get_output_seekable + (struct sieve_extprogram *sprog); + +void sieve_extprogram_set_input + (struct sieve_extprogram *sprog, struct istream *input); +int sieve_extprogram_set_input_mail + (struct sieve_extprogram *sprog, struct mail *mail); + +int sieve_extprogram_run(struct sieve_extprogram *sprog); + +#endif diff --git a/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.c b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.c new file mode 100644 index 0000000..bf17a80 --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.c @@ -0,0 +1,68 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "sieve-common.h" +#include "sieve-error.h" +#include "sieve-extensions.h" + +#include "sieve-extprograms-common.h" +#include "sieve-extprograms-plugin.h" + +/* + * Sieve plugin interface + */ + +struct _plugin_context { + const struct sieve_extension *ext_pipe; + const struct sieve_extension *ext_filter; + const struct sieve_extension *ext_execute; +}; + +const char *sieve_extprograms_plugin_version = PIGEONHOLE_ABI_VERSION; + +void sieve_extprograms_plugin_load +(struct sieve_instance *svinst, void **context) +{ + struct _plugin_context *pctx = i_new(struct _plugin_context, 1); + + pctx->ext_pipe = sieve_extension_register + (svinst, &sieve_ext_vnd_pipe, FALSE); + pctx->ext_filter = sieve_extension_register + (svinst, &sieve_ext_vnd_filter, FALSE); + pctx->ext_execute = sieve_extension_register + (svinst, &sieve_ext_vnd_execute, FALSE); + + if ( svinst->debug ) { + e_debug(svinst->event, + "Sieve Extprograms plugin for %s version %s loaded", + PIGEONHOLE_NAME, PIGEONHOLE_VERSION_FULL); + } + + *context = (void *)pctx; +} + +void sieve_extprograms_plugin_unload +(struct sieve_instance *svinst ATTR_UNUSED, void *context) +{ + struct _plugin_context *pctx = (struct _plugin_context *)context; + + sieve_extension_unregister(pctx->ext_pipe); + sieve_extension_unregister(pctx->ext_filter); + sieve_extension_unregister(pctx->ext_execute); + + i_free(pctx); +} + +/* + * Module interface + */ + +void sieve_extprograms_plugin_init(void) +{ + /* Nothing */ +} + +void sieve_extprograms_plugin_deinit(void) +{ + /* Nothing */ +} diff --git a/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.h b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.h new file mode 100644 index 0000000..20fa55a --- /dev/null +++ b/pigeonhole/src/plugins/sieve-extprograms/sieve-extprograms-plugin.h @@ -0,0 +1,20 @@ +#ifndef SIEVE_EXTPROGRAMS_PLUGIN_H +#define SIEVE_EXTPROGRAMS_PLUGIN_H + +/* + * Plugin interface + */ + +void sieve_extprograms_plugin_load + (struct sieve_instance *svinst, void **context); +void sieve_extprograms_plugin_unload + (struct sieve_instance *svinst, void *context); + +/* + * Module interface + */ + +void sieve_extprograms_plugin_init(void); +void sieve_extprograms_plugin_deinit(void); + +#endif |