diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /pigeonhole/src/plugins/imapsieve | |
parent | Initial commit. (diff) | |
download | dovecot-upstream.tar.xz dovecot-upstream.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'pigeonhole/src/plugins/imapsieve')
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/Makefile.am | 40 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/Makefile.in | 864 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/ext-imapsieve-common.h | 29 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/ext-imapsieve-environment.c | 184 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/ext-imapsieve.c | 168 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.c | 60 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/imap-sieve-plugin.h | 11 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/imap-sieve-storage.c | 1273 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/imap-sieve-storage.h | 10 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/imap-sieve.c | 940 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/imap-sieve.h | 59 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.c | 62 | ||||
-rw-r--r-- | pigeonhole/src/plugins/imapsieve/sieve-imapsieve-plugin.h | 20 |
13 files changed, 3720 insertions, 0 deletions
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..833d2b7 --- /dev/null +++ b/pigeonhole/src/plugins/imapsieve/Makefile.in @@ -0,0 +1,864 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/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 |