diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/imap4flags')
10 files changed, 2923 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.am b/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.am new file mode 100644 index 0000000..e5390d4 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.am @@ -0,0 +1,33 @@ +noinst_LTLIBRARIES = libsieve_ext_imap4flags.la + +AM_CPPFLAGS = \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../variables \ + $(LIBDOVECOT_INCLUDE) + +commands = \ + cmd-flag.c + +tests = \ + tst-hasflag.c + +tags = \ + tag-flags.c + +libsieve_ext_imap4flags_la_SOURCES = \ + ext-imap4flags-common.c \ + $(commands) \ + $(tests) \ + $(tags) \ + ext-imap4flags.c \ + ext-imapflags.c + +public_headers = \ + sieve-ext-imap4flags.h + +headers = \ + ext-imap4flags-common.h + +pkginc_libdir=$(dovecot_pkgincludedir)/sieve +pkginc_lib_HEADERS = $(public_headers) +noinst_HEADERS = $(headers) diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.in b/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.in new file mode 100644 index 0000000..3fcd3d4 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/Makefile.in @@ -0,0 +1,776 @@ +# Makefile.in generated by automake 1.16.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2018 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/lib-sieve/plugins/imap4flags +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/dovecot.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(pkginc_lib_HEADERS) $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/dummy-config.h \ + $(top_builddir)/pigeonhole-config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libsieve_ext_imap4flags_la_LIBADD = +am__objects_1 = cmd-flag.lo +am__objects_2 = tst-hasflag.lo +am__objects_3 = tag-flags.lo +am_libsieve_ext_imap4flags_la_OBJECTS = ext-imap4flags-common.lo \ + $(am__objects_1) $(am__objects_2) $(am__objects_3) \ + ext-imap4flags.lo ext-imapflags.lo +libsieve_ext_imap4flags_la_OBJECTS = \ + $(am_libsieve_ext_imap4flags_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/cmd-flag.Plo \ + ./$(DEPDIR)/ext-imap4flags-common.Plo \ + ./$(DEPDIR)/ext-imap4flags.Plo ./$(DEPDIR)/ext-imapflags.Plo \ + ./$(DEPDIR)/tag-flags.Plo ./$(DEPDIR)/tst-hasflag.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libsieve_ext_imap4flags_la_SOURCES) +DIST_SOURCES = $(libsieve_ext_imap4flags_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(pkginc_libdir)" +HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINARY_CFLAGS = @BINARY_CFLAGS@ +BINARY_LDFLAGS = @BINARY_LDFLAGS@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@ +DLLTOOL = @DLLTOOL@ +DOVECOT_BINARY_CFLAGS = @DOVECOT_BINARY_CFLAGS@ +DOVECOT_BINARY_LDFLAGS = @DOVECOT_BINARY_LDFLAGS@ +DOVECOT_CFLAGS = @DOVECOT_CFLAGS@ +DOVECOT_COMPRESS_LIBS = @DOVECOT_COMPRESS_LIBS@ +DOVECOT_INSTALLED = @DOVECOT_INSTALLED@ +DOVECOT_LIBS = @DOVECOT_LIBS@ +DOVECOT_LUA_CFLAGS = @DOVECOT_LUA_CFLAGS@ +DOVECOT_LUA_LIBS = @DOVECOT_LUA_LIBS@ +DOVECOT_SQL_LIBS = @DOVECOT_SQL_LIBS@ +DOVECOT_SSL_LIBS = @DOVECOT_SSL_LIBS@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDAP_LIBS = @LDAP_LIBS@ +LDFLAGS = @LDFLAGS@ +LIBDOVECOT = @LIBDOVECOT@ +LIBDOVECOT_ACL_INCLUDE = @LIBDOVECOT_ACL_INCLUDE@ +LIBDOVECOT_AUTH_INCLUDE = @LIBDOVECOT_AUTH_INCLUDE@ +LIBDOVECOT_COMPRESS = @LIBDOVECOT_COMPRESS@ +LIBDOVECOT_COMPRESS_DEPS = @LIBDOVECOT_COMPRESS_DEPS@ +LIBDOVECOT_CONFIG_INCLUDE = @LIBDOVECOT_CONFIG_INCLUDE@ +LIBDOVECOT_DEPS = @LIBDOVECOT_DEPS@ +LIBDOVECOT_DOVEADM_INCLUDE = @LIBDOVECOT_DOVEADM_INCLUDE@ +LIBDOVECOT_DSYNC = @LIBDOVECOT_DSYNC@ +LIBDOVECOT_DSYNC_DEPS = @LIBDOVECOT_DSYNC_DEPS@ +LIBDOVECOT_DSYNC_INCLUDE = @LIBDOVECOT_DSYNC_INCLUDE@ +LIBDOVECOT_FTS_INCLUDE = @LIBDOVECOT_FTS_INCLUDE@ +LIBDOVECOT_IMAPC_INCLUDE = @LIBDOVECOT_IMAPC_INCLUDE@ +LIBDOVECOT_IMAP_INCLUDE = @LIBDOVECOT_IMAP_INCLUDE@ +LIBDOVECOT_IMAP_LOGIN_INCLUDE = @LIBDOVECOT_IMAP_LOGIN_INCLUDE@ +LIBDOVECOT_INCLUDE = @LIBDOVECOT_INCLUDE@ +LIBDOVECOT_LDA = @LIBDOVECOT_LDA@ +LIBDOVECOT_LDA_DEPS = @LIBDOVECOT_LDA_DEPS@ +LIBDOVECOT_LDA_INCLUDE = @LIBDOVECOT_LDA_INCLUDE@ +LIBDOVECOT_LIBFTS = @LIBDOVECOT_LIBFTS@ +LIBDOVECOT_LIBFTS_DEPS = @LIBDOVECOT_LIBFTS_DEPS@ +LIBDOVECOT_LIBFTS_INCLUDE = @LIBDOVECOT_LIBFTS_INCLUDE@ +LIBDOVECOT_LMTP_INCLUDE = @LIBDOVECOT_LMTP_INCLUDE@ +LIBDOVECOT_LOGIN = @LIBDOVECOT_LOGIN@ +LIBDOVECOT_LOGIN_DEPS = @LIBDOVECOT_LOGIN_DEPS@ +LIBDOVECOT_LOGIN_INCLUDE = @LIBDOVECOT_LOGIN_INCLUDE@ +LIBDOVECOT_LUA = @LIBDOVECOT_LUA@ +LIBDOVECOT_LUA_DEPS = @LIBDOVECOT_LUA_DEPS@ +LIBDOVECOT_LUA_INCLUDE = @LIBDOVECOT_LUA_INCLUDE@ +LIBDOVECOT_NOTIFY_INCLUDE = @LIBDOVECOT_NOTIFY_INCLUDE@ +LIBDOVECOT_POP3_INCLUDE = @LIBDOVECOT_POP3_INCLUDE@ +LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE = @LIBDOVECOT_PUSH_NOTIFICATION_INCLUDE@ +LIBDOVECOT_SERVICE_INCLUDE = @LIBDOVECOT_SERVICE_INCLUDE@ +LIBDOVECOT_SQL = @LIBDOVECOT_SQL@ +LIBDOVECOT_SQL_DEPS = @LIBDOVECOT_SQL_DEPS@ +LIBDOVECOT_SQL_INCLUDE = @LIBDOVECOT_SQL_INCLUDE@ +LIBDOVECOT_SSL = @LIBDOVECOT_SSL@ +LIBDOVECOT_SSL_DEPS = @LIBDOVECOT_SSL_DEPS@ +LIBDOVECOT_STORAGE = @LIBDOVECOT_STORAGE@ +LIBDOVECOT_STORAGE_DEPS = @LIBDOVECOT_STORAGE_DEPS@ +LIBDOVECOT_STORAGE_INCLUDE = @LIBDOVECOT_STORAGE_INCLUDE@ +LIBDOVECOT_SUBMISSION_INCLUDE = @LIBDOVECOT_SUBMISSION_INCLUDE@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PIE_CFLAGS = @PIE_CFLAGS@ +PIE_LDFLAGS = @PIE_LDFLAGS@ +RANLIB = @RANLIB@ +RELRO_LDFLAGS = @RELRO_LDFLAGS@ +RUN_TEST = @RUN_TEST@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VALGRIND = @VALGRIND@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dovecot_docdir = @dovecot_docdir@ +dovecot_installed_moduledir = @dovecot_installed_moduledir@ +dovecot_moduledir = @dovecot_moduledir@ +dovecot_pkgincludedir = @dovecot_pkgincludedir@ +dovecot_pkglibdir = @dovecot_pkglibdir@ +dovecot_pkglibexecdir = @dovecot_pkglibexecdir@ +dovecot_statedir = @dovecot_statedir@ +dovecotdir = @dovecotdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +moduledir = @moduledir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sieve_docdir = @sieve_docdir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LTLIBRARIES = libsieve_ext_imap4flags.la +AM_CPPFLAGS = \ + -I$(srcdir)/../.. \ + -I$(srcdir)/../variables \ + $(LIBDOVECOT_INCLUDE) + +commands = \ + cmd-flag.c + +tests = \ + tst-hasflag.c + +tags = \ + tag-flags.c + +libsieve_ext_imap4flags_la_SOURCES = \ + ext-imap4flags-common.c \ + $(commands) \ + $(tests) \ + $(tags) \ + ext-imap4flags.c \ + ext-imapflags.c + +public_headers = \ + sieve-ext-imap4flags.h + +headers = \ + ext-imap4flags-common.h + +pkginc_libdir = $(dovecot_pkgincludedir)/sieve +pkginc_lib_HEADERS = $(public_headers) +noinst_HEADERS = $(headers) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/lib-sieve/plugins/imap4flags/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/lib-sieve/plugins/imap4flags/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libsieve_ext_imap4flags.la: $(libsieve_ext_imap4flags_la_OBJECTS) $(libsieve_ext_imap4flags_la_DEPENDENCIES) $(EXTRA_libsieve_ext_imap4flags_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libsieve_ext_imap4flags_la_OBJECTS) $(libsieve_ext_imap4flags_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmd-flag.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imap4flags-common.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imap4flags.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ext-imapflags.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag-flags.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tst-hasflag.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-pkginc_libHEADERS: $(pkginc_lib_HEADERS) + @$(NORMAL_INSTALL) + @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkginc_libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \ + done + +uninstall-pkginc_libHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkginc_libdir)'; $(am__uninstall_files_from_dir) + +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)$(pkginc_libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/cmd-flag.Plo + -rm -f ./$(DEPDIR)/ext-imap4flags-common.Plo + -rm -f ./$(DEPDIR)/ext-imap4flags.Plo + -rm -f ./$(DEPDIR)/ext-imapflags.Plo + -rm -f ./$(DEPDIR)/tag-flags.Plo + -rm -f ./$(DEPDIR)/tst-hasflag.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-pkginc_libHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/cmd-flag.Plo + -rm -f ./$(DEPDIR)/ext-imap4flags-common.Plo + -rm -f ./$(DEPDIR)/ext-imap4flags.Plo + -rm -f ./$(DEPDIR)/ext-imapflags.Plo + -rm -f ./$(DEPDIR)/tag-flags.Plo + -rm -f ./$(DEPDIR)/tst-hasflag.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-pkginc_libHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-pkginc_libHEADERS install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am uninstall-pkginc_libHEADERS + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c new file mode 100644 index 0000000..2645669 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/cmd-flag.c @@ -0,0 +1,251 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" + +#include "sieve-code.h" +#include "sieve-stringlist.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "ext-imap4flags-common.h" + +/* + * Commands + */ + +/* Forward declarations */ + +static bool cmd_flag_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx); + +/* Setflag command + * + * Syntax: + * setflag [<variablename: string>] <list-of-flags: string-list> + */ + +const struct sieve_command_def cmd_setflag = { + .identifier = "setflag", + .type = SCT_COMMAND, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = ext_imap4flags_command_validate, + .generate = cmd_flag_generate +}; + +/* Addflag command + * + * Syntax: + * addflag [<variablename: string>] <list-of-flags: string-list> + */ + +const struct sieve_command_def cmd_addflag = { + .identifier = "addflag", + .type = SCT_COMMAND, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = ext_imap4flags_command_validate, + .generate = cmd_flag_generate +}; + + +/* Removeflag command + * + * Syntax: + * removeflag [<variablename: string>] <list-of-flags: string-list> + */ + +const struct sieve_command_def cmd_removeflag = { + .identifier = "removeflag", + .type = SCT_COMMAND, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = ext_imap4flags_command_validate, + .generate = cmd_flag_generate +}; + +/* + * Operations + */ + +/* Forward declarations */ + +bool cmd_flag_operation_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int cmd_flag_operation_execute + (const struct sieve_runtime_env *renv, sieve_size_t *address); + +/* Setflag operation */ + +const struct sieve_operation_def setflag_operation = { + .mnemonic = "SETFLAG", + .ext_def = &imap4flags_extension, + .code = EXT_IMAP4FLAGS_OPERATION_SETFLAG, + .dump = cmd_flag_operation_dump, + .execute = cmd_flag_operation_execute +}; + +/* Addflag operation */ + +const struct sieve_operation_def addflag_operation = { + .mnemonic = "ADDFLAG", + .ext_def = &imap4flags_extension, + .code = EXT_IMAP4FLAGS_OPERATION_ADDFLAG, + .dump = cmd_flag_operation_dump, + .execute = cmd_flag_operation_execute +}; + +/* Removeflag operation */ + +const struct sieve_operation_def removeflag_operation = { + .mnemonic = "REMOVEFLAG", + .ext_def = &imap4flags_extension, + .code = EXT_IMAP4FLAGS_OPERATION_REMOVEFLAG, + .dump = cmd_flag_operation_dump, + .execute = cmd_flag_operation_execute +}; + +/* + * Code generation + */ + +static bool cmd_flag_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) +{ + struct sieve_ast_argument *arg1, *arg2; + + /* Emit operation */ + if ( sieve_command_is(cmd, cmd_setflag) ) + sieve_operation_emit(cgenv->sblock, cmd->ext, &setflag_operation); + else if ( sieve_command_is(cmd, cmd_addflag) ) + sieve_operation_emit(cgenv->sblock, cmd->ext, &addflag_operation); + else if ( sieve_command_is(cmd, cmd_removeflag) ) + sieve_operation_emit(cgenv->sblock, cmd->ext, &removeflag_operation); + + arg1 = cmd->first_positional; + arg2 = sieve_ast_argument_next(arg1); + + if ( arg2 == NULL ) { + /* No variable */ + sieve_opr_omitted_emit(cgenv->sblock); + if ( !sieve_generate_argument(cgenv, arg1, cmd) ) + return FALSE; + } else { + /* Full command */ + if ( !sieve_generate_argument(cgenv, arg1, cmd) ) + return FALSE; + if ( !sieve_generate_argument(cgenv, arg2, cmd) ) + return FALSE; + } + return TRUE; +} + +/* + * Code dump + */ + +bool cmd_flag_operation_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + struct sieve_operand oprnd; + + sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(denv->oprtn)); + sieve_code_descend(denv); + + sieve_code_mark(denv); + if ( !sieve_operand_read(denv->sblock, address, NULL, &oprnd) ) { + sieve_code_dumpf(denv, "ERROR: INVALID OPERAND"); + return FALSE; + } + + if ( !sieve_operand_is_omitted(&oprnd) ) { + return + sieve_opr_string_dump_data(denv, &oprnd, address, "variable name") && + sieve_opr_stringlist_dump(denv, address, "list of flags"); + } + + return + sieve_opr_stringlist_dump(denv, address, "list of flags"); +} + +/* + * Code execution + */ + +static int cmd_flag_operation_execute +(const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + const struct sieve_operation *op = renv->oprtn; + struct sieve_operand oprnd; + struct sieve_stringlist *flag_list; + struct sieve_variable_storage *storage; + unsigned int var_index; + ext_imapflag_flag_operation_t flag_op; + int ret; + + /* + * Read operands + */ + + /* Read bare operand (two types possible) */ + if ( (ret=sieve_operand_runtime_read + (renv, address, NULL, &oprnd)) <= 0 ) + return ret; + + /* Variable operand (optional) */ + if ( !sieve_operand_is_omitted(&oprnd) ) { + /* Read the variable operand */ + if ( (ret=sieve_variable_operand_read_data + (renv, &oprnd, address, "variable", &storage, &var_index)) <= 0 ) + return ret; + + /* Read flag list */ + if ( (ret=sieve_opr_stringlist_read(renv, address, "flag-list", &flag_list)) + <= 0 ) + return ret; + + /* Flag-list operand */ + } else { + storage = NULL; + var_index = 0; + + /* Read flag list */ + if ( (ret=sieve_opr_stringlist_read(renv, address, + "flag-list", &flag_list)) <= 0 ) + return ret; + } + + /* + * Perform operation + */ + + /* Determine what to do */ + + if ( sieve_operation_is(op, setflag_operation) ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "setflag command"); + flag_op = sieve_ext_imap4flags_set_flags; + } else if ( sieve_operation_is(op, addflag_operation) ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "addflag command"); + flag_op = sieve_ext_imap4flags_add_flags; + } else if ( sieve_operation_is(op, removeflag_operation) ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, "removeflag command"); + flag_op = sieve_ext_imap4flags_remove_flags; + } else { + i_unreached(); + } + + sieve_runtime_trace_descend(renv); + + /* Perform requested operation */ + return flag_op(renv, op->ext, storage, var_index, flag_list); +} diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c new file mode 100644 index 0000000..3c364b8 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.c @@ -0,0 +1,733 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "str-sanitize.h" +#include "mail-storage.h" +#include "imap-arg.h" + +#include "sieve-common.h" +#include "sieve-commands.h" +#include "sieve-code.h" +#include "sieve-stringlist.h" +#include "sieve-actions.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-result.h" +#include "sieve-dump.h" + +#include "sieve-ext-variables.h" + +#include "ext-imap4flags-common.h" + +/* + * Tagged arguments + */ + +extern const struct sieve_argument_def tag_flags; +extern const struct sieve_argument_def tag_flags_implicit; + +/* + * Common command functions + */ + +bool ext_imap4flags_command_validate +(struct sieve_validator *valdtr, struct sieve_command *cmd) +{ + struct sieve_ast_argument *arg = cmd->first_positional; + struct sieve_ast_argument *arg2; + const struct sieve_extension *var_ext; + + /* Check arguments */ + + if ( arg == NULL ) { + sieve_command_validate_error(valdtr, cmd, + "the %s %s expects at least one argument, but none was found", + sieve_command_identifier(cmd), sieve_command_type_name(cmd)); + return FALSE; + } + + if ( sieve_ast_argument_type(arg) != SAAT_STRING && + sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) + { + sieve_argument_validate_error(valdtr, arg, + "the %s %s expects either a string (variable name) or " + "a string-list (list of flags) as first argument, but %s was found", + sieve_command_identifier(cmd), sieve_command_type_name(cmd), + sieve_ast_argument_name(arg)); + return FALSE; + } + + arg2 = sieve_ast_argument_next(arg); + if ( arg2 != NULL ) { + /* First, check syntax sanity */ + + if ( sieve_ast_argument_type(arg) != SAAT_STRING ) + { + if ( sieve_command_is(cmd, tst_hasflag) ) { + if ( sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) { + sieve_argument_validate_error(valdtr, arg, + "if a second argument is specified for the hasflag, the first " + "must be a string-list (variable-list), but %s was found", + sieve_ast_argument_name(arg)); + return FALSE; + } + } else { + sieve_argument_validate_error(valdtr, arg, + "if a second argument is specified for the %s %s, the first " + "must be a string (variable name), but %s was found", + sieve_command_identifier(cmd), sieve_command_type_name(cmd), + sieve_ast_argument_name(arg)); + return FALSE; + } + } + + /* Then, check whether the second argument is permitted */ + + var_ext = sieve_ext_variables_get_extension(cmd->ext->svinst); + + if ( var_ext == NULL || !sieve_ext_variables_is_active(var_ext, valdtr) ) + { + sieve_argument_validate_error(valdtr,arg, + "the %s %s only allows for the specification of a " + "variable name when the variables extension is active", + sieve_command_identifier(cmd), sieve_command_type_name(cmd)); + return FALSE; + } + + if ( !sieve_variable_argument_activate(var_ext, var_ext, + valdtr, cmd, arg, !sieve_command_is(cmd, tst_hasflag) ) ) + return FALSE; + + if ( sieve_ast_argument_type(arg2) != SAAT_STRING && + sieve_ast_argument_type(arg2) != SAAT_STRING_LIST ) + { + sieve_argument_validate_error(valdtr, arg2, + "the %s %s expects a string list (list of flags) as " + "second argument when two arguments are specified, " + "but %s was found", + sieve_command_identifier(cmd), sieve_command_type_name(cmd), + sieve_ast_argument_name(arg2)); + return FALSE; + } + } else + arg2 = arg; + + if ( !sieve_validator_argument_activate(valdtr, cmd, arg2, FALSE) ) + return FALSE; + + if ( !sieve_command_is(cmd, tst_hasflag) && + sieve_argument_is_string_literal(arg2) ) { + struct ext_imap4flags_iter fiter; + const char *flag; + + /* Warn the user about validity of verifiable flags */ + ext_imap4flags_iter_init(&fiter, sieve_ast_argument_str(arg)); + + while ( (flag=ext_imap4flags_iter_get_flag(&fiter)) != NULL ) { + if ( !sieve_ext_imap4flags_flag_is_valid(flag) ) { + sieve_argument_validate_warning(valdtr, arg, + "IMAP flag '%s' specified for the %s command is invalid " + "and will be ignored (only first invalid is reported)", + str_sanitize(flag, 64), sieve_command_identifier(cmd)); + break; + } + } + } + + return TRUE; +} + +/* + * Flags tag registration + */ + +void ext_imap4flags_attach_flags_tag +(struct sieve_validator *valdtr, const struct sieve_extension *ext, + const char *command) +{ + /* Register :flags tag with the command and we don't care whether it is + * registered or even whether it will be registered at all. The validator + * handles either situation gracefully + */ + + /* Tag specified by user */ + sieve_validator_register_external_tag + (valdtr, command, ext, &tag_flags, SIEVE_OPT_SIDE_EFFECT); +} + +void sieve_ext_imap4flags_register_side_effect +(struct sieve_validator *valdtr, const struct sieve_extension *flg_ext, + const char *command) +{ + /* Implicit tag if none is specified */ + sieve_validator_register_persistent_tag + (valdtr, command, flg_ext, &tag_flags_implicit); +} + + +/* + * Result context + */ + +struct ext_imap4flags_result_context { + string_t *internal_flags; +}; + +static void _get_initial_flags +(struct sieve_result *result, string_t *flags) +{ + const struct sieve_message_data *msgdata = + sieve_result_get_message_data(result); + enum mail_flags mail_flags; + const char *const *mail_keywords; + + mail_flags = mail_get_flags(msgdata->mail); + mail_keywords = mail_get_keywords(msgdata->mail); + + if ( (mail_flags & MAIL_FLAGGED) > 0 ) + str_printfa(flags, " \\flagged"); + + if ( (mail_flags & MAIL_ANSWERED) > 0 ) + str_printfa(flags, " \\answered"); + + if ( (mail_flags & MAIL_DELETED) > 0 ) + str_printfa(flags, " \\deleted"); + + if ( (mail_flags & MAIL_SEEN) > 0 ) + str_printfa(flags, " \\seen"); + + if ( (mail_flags & MAIL_DRAFT) > 0 ) + str_printfa(flags, " \\draft"); + + while ( *mail_keywords != NULL ) { + str_printfa(flags, " %s", *mail_keywords); + mail_keywords++; + } +} + +static inline struct ext_imap4flags_result_context *_get_result_context +(const struct sieve_extension *this_ext, struct sieve_result *result) +{ + struct ext_imap4flags_result_context *rctx = + (struct ext_imap4flags_result_context *) + sieve_result_extension_get_context(result, this_ext); + + if ( rctx == NULL ) { + pool_t pool = sieve_result_pool(result); + + rctx =p_new(pool, struct ext_imap4flags_result_context, 1); + rctx->internal_flags = str_new(pool, 32); + _get_initial_flags(result, rctx->internal_flags); + + sieve_result_extension_set_context + (result, this_ext, rctx); + } + + return rctx; +} + +static string_t *_get_flags_string +(const struct sieve_extension *this_ext, struct sieve_result *result) +{ + struct ext_imap4flags_result_context *ctx = + _get_result_context(this_ext, result); + + return ctx->internal_flags; +} + +/* + * Runtime initialization + */ + +static int ext_imap4flags_runtime_init +(const struct sieve_extension *ext, + const struct sieve_runtime_env *renv, + void *context ATTR_UNUSED, bool deferred ATTR_UNUSED) +{ + sieve_result_add_implicit_side_effect + (renv->result, NULL, TRUE, ext, &flags_side_effect, NULL); + return SIEVE_EXEC_OK; +} + +const struct sieve_interpreter_extension +imap4flags_interpreter_extension = { + .ext_def = &imap4flags_extension, + .run = ext_imap4flags_runtime_init +}; + +/* + * Flag handling + */ + +/* FIXME: This currently accepts a potentially unlimited number of + * flags, making the internal or variable flag list indefinitely long + */ + +bool sieve_ext_imap4flags_flag_is_valid(const char *flag) +{ + if ( *flag == '\0' ) + return FALSE; + + if ( *flag == '\\' ) { + /* System flag */ + const char *atom = t_str_ucase(flag); + + if ( + (strcmp(atom, "\\ANSWERED") != 0) && + (strcmp(atom, "\\FLAGGED") != 0) && + (strcmp(atom, "\\DELETED") != 0) && + (strcmp(atom, "\\SEEN") != 0) && + (strcmp(atom, "\\DRAFT") != 0) ) + { + return FALSE; + } + } else { + const char *p; + + /* Custom keyword: + * + * Syntax (IMAP4rev1, RFC 3501, Section 9. Formal Syntax) : + * flag-keyword = atom + * atom = 1*ATOM-CHAR + */ + p = flag; + while ( *p != '\0' ) { + if ( !IS_ATOM_CHAR(*p) ) + return FALSE; + p++; + } + } + + return TRUE; +} + +/* Flag iterator */ + +static void ext_imap4flags_iter_clear +(struct ext_imap4flags_iter *iter) +{ + i_zero(iter); +} + +void ext_imap4flags_iter_init +(struct ext_imap4flags_iter *iter, string_t *flags_list) +{ + ext_imap4flags_iter_clear(iter); + iter->flags_list = flags_list; +} + +static string_t *ext_imap4flags_iter_get_flag_str +(struct ext_imap4flags_iter *iter) +{ + unsigned int len; + const unsigned char *fp; + const unsigned char *fbegin; + const unsigned char *fstart; + const unsigned char *fend; + + /* Return if not initialized */ + if ( iter->flags_list == NULL ) return NULL; + + /* Return if no more flags are available */ + len = str_len(iter->flags_list); + if ( iter->offset >= len ) return NULL; + + /* Mark string boundries */ + fbegin = str_data(iter->flags_list); + fend = fbegin + len; + + /* Start of this flag */ + fstart = fbegin + iter->offset; + + /* Scan for next flag */ + fp = fstart; + for (;;) { + /* Have we reached the end or a flag boundary? */ + if ( fp >= fend || *fp == ' ' ) { + /* Did we scan more than nothing ? */ + if ( fp > fstart ) { + /* Return flag */ + string_t *flag = t_str_new(fp-fstart+1); + str_append_data(flag, fstart, fp-fstart); + + iter->last = fstart - fbegin; + iter->offset = fp - fbegin; + + return flag; + } + + fstart = fp + 1; + } + + if ( fp >= fend ) break; + + fp++; + } + + iter->last = fstart - fbegin; + iter->offset = fp - fbegin; + return NULL; +} + +const char *ext_imap4flags_iter_get_flag +(struct ext_imap4flags_iter *iter) +{ + string_t *flag = ext_imap4flags_iter_get_flag_str(iter); + + if ( flag == NULL ) return NULL; + + return str_c(flag); +} + +static void ext_imap4flags_iter_delete_last +(struct ext_imap4flags_iter *iter) +{ + iter->offset++; + if ( iter->offset > str_len(iter->flags_list) ) + iter->offset = str_len(iter->flags_list); + if ( iter->offset == str_len(iter->flags_list) && iter->last > 0 ) + iter->last--; + + str_delete(iter->flags_list, iter->last, iter->offset - iter->last); + + iter->offset = iter->last; +} + +/* Flag operations */ + +static string_t *ext_imap4flags_get_flag_variable +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index) + ATTR_NULL(2); + +static bool flags_list_flag_exists +(string_t *flags_list, const char *flag) +{ + const char *flg; + struct ext_imap4flags_iter flit; + + ext_imap4flags_iter_init(&flit, flags_list); + + while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) { + if ( strcasecmp(flg, flag) == 0 ) + return TRUE; + } + + return FALSE; +} + +static void flags_list_flag_delete +(string_t *flags_list, const char *flag) +{ + const char *flg; + struct ext_imap4flags_iter flit; + + ext_imap4flags_iter_init(&flit, flags_list); + + while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) { + if ( strcasecmp(flg, flag) == 0 ) { + ext_imap4flags_iter_delete_last(&flit); + } + } +} + +static void flags_list_add_flags +(string_t *flags_list, string_t *flags) +{ + const char *flg; + struct ext_imap4flags_iter flit; + + ext_imap4flags_iter_init(&flit, flags); + + while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) { + if ( sieve_ext_imap4flags_flag_is_valid(flg) && + !flags_list_flag_exists(flags_list, flg) ) { + if ( str_len(flags_list) != 0 ) + str_append_c(flags_list, ' '); + str_append(flags_list, flg); + } + } +} + +static void flags_list_remove_flags +(string_t *flags_list, string_t *flags) +{ + const char *flg; + struct ext_imap4flags_iter flit; + + ext_imap4flags_iter_init(&flit, flags); + + while ( (flg=ext_imap4flags_iter_get_flag(&flit)) != NULL ) { + flags_list_flag_delete(flags_list, flg); + } +} + +static void flags_list_set_flags +(string_t *flags_list, string_t *flags) +{ + str_truncate(flags_list, 0); + flags_list_add_flags(flags_list, flags); +} + +static void flags_list_clear_flags +(string_t *flags_list) +{ + str_truncate(flags_list, 0); +} + +static string_t *ext_imap4flags_get_flag_variable +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index) +{ + string_t *flags; + + if ( storage != NULL ) { + if ( sieve_runtime_trace_active(renv, SIEVE_TRLVL_COMMANDS) ) { + const char *var_name, *var_id; + + (void)sieve_variable_get_identifier(storage, var_index, &var_name); + var_id = sieve_variable_get_varid(storage, var_index); + + sieve_runtime_trace(renv, 0, "update variable `%s' [%s]", + var_name, var_id); + } + + if ( !sieve_variable_get_modifiable(storage, var_index, &flags) ) + return NULL; + } else { + i_assert( sieve_extension_is(flg_ext, imap4flags_extension) ); + flags = _get_flags_string(flg_ext, renv->result); + } + + return flags; +} + +int sieve_ext_imap4flags_set_flags +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index, + struct sieve_stringlist *flags) +{ + string_t *cur_flags = ext_imap4flags_get_flag_variable + (renv, flg_ext, storage, var_index); + + if ( cur_flags != NULL ) { + string_t *flags_item; + int ret; + + flags_list_clear_flags(cur_flags); + while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, + "set flags `%s'", str_c(flags_item)); + + flags_list_add_flags(cur_flags, flags_item); + } + + if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT; + + return SIEVE_EXEC_OK; + } + + return SIEVE_EXEC_BIN_CORRUPT; +} + +int sieve_ext_imap4flags_add_flags +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index, + struct sieve_stringlist *flags) +{ + string_t *cur_flags = ext_imap4flags_get_flag_variable + (renv, flg_ext, storage, var_index); + + if ( cur_flags != NULL ) { + string_t *flags_item; + int ret; + + while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, + "add flags `%s'", str_c(flags_item)); + + flags_list_add_flags(cur_flags, flags_item); + } + + if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT; + + return SIEVE_EXEC_OK; + } + + return SIEVE_EXEC_BIN_CORRUPT; +} + +int sieve_ext_imap4flags_remove_flags +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index, + struct sieve_stringlist *flags) +{ + string_t *cur_flags = ext_imap4flags_get_flag_variable + (renv, flg_ext, storage, var_index); + + if ( cur_flags != NULL ) { + string_t *flags_item; + int ret; + + while ( (ret=sieve_stringlist_next_item(flags, &flags_item)) > 0 ) { + sieve_runtime_trace(renv, SIEVE_TRLVL_COMMANDS, + "remove flags `%s'", str_c(flags_item)); + + flags_list_remove_flags(cur_flags, flags_item); + } + + if ( ret < 0 ) return SIEVE_EXEC_BIN_CORRUPT; + + return SIEVE_EXEC_OK; + } + + return SIEVE_EXEC_BIN_CORRUPT; +} + +/* Flag stringlist */ + +static int ext_imap4flags_stringlist_next_item + (struct sieve_stringlist *_strlist, string_t **str_r); +static void ext_imap4flags_stringlist_reset + (struct sieve_stringlist *_strlist); + +struct ext_imap4flags_stringlist { + struct sieve_stringlist strlist; + + struct sieve_stringlist *flags_list; + string_t *flags_string; + struct ext_imap4flags_iter flit; + + bool normalize:1; +}; + +static struct sieve_stringlist *ext_imap4flags_stringlist_create +(const struct sieve_runtime_env *renv, struct sieve_stringlist *flags_list, + bool normalize) +{ + struct ext_imap4flags_stringlist *strlist; + + strlist = t_new(struct ext_imap4flags_stringlist, 1); + strlist->strlist.exec_status = SIEVE_EXEC_OK; + strlist->strlist.runenv = renv; + strlist->strlist.next_item = ext_imap4flags_stringlist_next_item; + strlist->strlist.reset = ext_imap4flags_stringlist_reset; + strlist->normalize = normalize; + + strlist->flags_list = flags_list; + + return &strlist->strlist; +} + +static struct sieve_stringlist *ext_imap4flags_stringlist_create_single +(const struct sieve_runtime_env *renv, string_t *flags_string, bool normalize) +{ + struct ext_imap4flags_stringlist *strlist; + + strlist = t_new(struct ext_imap4flags_stringlist, 1); + strlist->strlist.exec_status = SIEVE_EXEC_OK; + strlist->strlist.runenv = renv; + strlist->strlist.next_item = ext_imap4flags_stringlist_next_item; + strlist->strlist.reset = ext_imap4flags_stringlist_reset; + strlist->normalize = normalize; + + if ( normalize ) { + strlist->flags_string = t_str_new(256); + flags_list_set_flags(strlist->flags_string, flags_string); + } else { + strlist->flags_string = flags_string; + } + + ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string); + + return &strlist->strlist; +} + +static int ext_imap4flags_stringlist_next_item +(struct sieve_stringlist *_strlist, string_t **str_r) +{ + struct ext_imap4flags_stringlist *strlist = + (struct ext_imap4flags_stringlist *)_strlist; + + while ( (*str_r=ext_imap4flags_iter_get_flag_str(&strlist->flit)) == NULL ) { + int ret; + + if ( strlist->flags_list == NULL ) + return 0; + + if ( (ret=sieve_stringlist_next_item + (strlist->flags_list, &strlist->flags_string)) <= 0 ) + return ret; + + if ( strlist->flags_string == NULL ) + return -1; + + if ( strlist->normalize ) { + string_t *flags_string = t_str_new(256); + + flags_list_set_flags(flags_string, strlist->flags_string); + strlist->flags_string = flags_string; + } + + ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string); + } + + return 1; +} + +static void ext_imap4flags_stringlist_reset +(struct sieve_stringlist *_strlist) +{ + struct ext_imap4flags_stringlist *strlist = + (struct ext_imap4flags_stringlist *)_strlist; + + if ( strlist->flags_list != NULL ) { + sieve_stringlist_reset(strlist->flags_list); + ext_imap4flags_iter_clear(&strlist->flit); + } else { + ext_imap4flags_iter_init(&strlist->flit, strlist->flags_string); + } +} + +/* Flag access */ + +struct sieve_stringlist *sieve_ext_imap4flags_get_flags +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_stringlist *flags_list) +{ + if ( flags_list == NULL ) { + i_assert( sieve_extension_is(flg_ext, imap4flags_extension) ); + return ext_imap4flags_stringlist_create_single + (renv, _get_flags_string(flg_ext, renv->result), FALSE); + } + + return ext_imap4flags_stringlist_create(renv, flags_list, TRUE); +} + +void ext_imap4flags_get_implicit_flags_init +(struct ext_imap4flags_iter *iter, const struct sieve_extension *this_ext, + struct sieve_result *result) +{ + string_t *cur_flags = _get_flags_string(this_ext, result); + + ext_imap4flags_iter_init(iter, cur_flags); +} + + + + + diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h new file mode 100644 index 0000000..4bedb85 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags-common.h @@ -0,0 +1,97 @@ +#ifndef EXT_IMAP4FLAGS_COMMON_H +#define EXT_IMAP4FLAGS_COMMON_H + +#include "lib.h" + +#include "sieve-common.h" +#include "sieve-ext-variables.h" + +#include "sieve-ext-imap4flags.h" + +/* + * Side effect + */ + +extern const struct sieve_side_effect_def flags_side_effect; + +/* + * Operands + */ + +extern const struct sieve_operand_def flags_side_effect_operand; + +/* + * Operations + */ + +enum ext_imap4flags_opcode { + EXT_IMAP4FLAGS_OPERATION_SETFLAG, + EXT_IMAP4FLAGS_OPERATION_ADDFLAG, + EXT_IMAP4FLAGS_OPERATION_REMOVEFLAG, + EXT_IMAP4FLAGS_OPERATION_HASFLAG +}; + +extern const struct sieve_operation_def setflag_operation; +extern const struct sieve_operation_def addflag_operation; +extern const struct sieve_operation_def removeflag_operation; +extern const struct sieve_operation_def hasflag_operation; + +/* + * Commands + */ + +extern const struct sieve_command_def cmd_setflag; +extern const struct sieve_command_def cmd_addflag; +extern const struct sieve_command_def cmd_removeflag; + +extern const struct sieve_command_def tst_hasflag; + +/* + * Common command functions + */ + +bool ext_imap4flags_command_validate + (struct sieve_validator *valdtr, struct sieve_command *cmd); + +/* + * Flags tagged argument + */ + +void ext_imap4flags_attach_flags_tag + (struct sieve_validator *valdtr, const struct sieve_extension *ext, + const char *command); + +/* + * Flag management + */ + +struct ext_imap4flags_iter { + string_t *flags_list; + unsigned int offset; + unsigned int last; +}; + +void ext_imap4flags_iter_init + (struct ext_imap4flags_iter *iter, string_t *flags_list); + +const char *ext_imap4flags_iter_get_flag + (struct ext_imap4flags_iter *iter); + +/* Flag operations */ + +typedef int (*ext_imapflag_flag_operation_t) + (const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index, struct sieve_stringlist *flags) + ATTR_NULL(2); + +/* Flags access */ + +void ext_imap4flags_get_implicit_flags_init + (struct ext_imap4flags_iter *iter, const struct sieve_extension *this_ext, + struct sieve_result *result); + + +#endif + diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c new file mode 100644 index 0000000..23230c1 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imap4flags.c @@ -0,0 +1,96 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +/* Extension imap4flags + * -------------------- + * + * Authors: Stephan Bosch + * Specification: RFC 5232 + * Implementation: full + * Status: testing + * + */ + +#include "lib.h" +#include "mempool.h" +#include "str.h" + +#include "sieve-common.h" + +#include "sieve-code.h" +#include "sieve-extensions.h" +#include "sieve-actions.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" + +#include "ext-imap4flags-common.h" + +/* + * Operations + */ + +const struct sieve_operation_def *imap4flags_operations[] = { + &setflag_operation, + &addflag_operation, + &removeflag_operation, + &hasflag_operation +}; + +/* + * Extension + */ + +static bool ext_imap4flags_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); +static bool ext_imap4flags_interpreter_load + (const struct sieve_extension *ext, const struct sieve_runtime_env *renv, + sieve_size_t *address); + +const struct sieve_extension_def imap4flags_extension = { + .name = "imap4flags", + .version = 1, + .validator_load = ext_imap4flags_validator_load, + .interpreter_load = ext_imap4flags_interpreter_load, + SIEVE_EXT_DEFINE_OPERATIONS(imap4flags_operations), + SIEVE_EXT_DEFINE_OPERAND(flags_side_effect_operand) +}; + +static bool ext_imap4flags_validator_load +(const struct sieve_extension *ext, struct sieve_validator *valdtr) +{ + /* Register commands */ + sieve_validator_register_command(valdtr, ext, &cmd_setflag); + sieve_validator_register_command(valdtr, ext, &cmd_addflag); + sieve_validator_register_command(valdtr, ext, &cmd_removeflag); + sieve_validator_register_command(valdtr, ext, &tst_hasflag); + + /* Attach :flags tag to keep and fileinto commands */ + ext_imap4flags_attach_flags_tag(valdtr, ext, "keep"); + ext_imap4flags_attach_flags_tag(valdtr, ext, "fileinto"); + + /* Attach flags side-effect to keep and fileinto actions */ + sieve_ext_imap4flags_register_side_effect(valdtr, ext, "keep"); + sieve_ext_imap4flags_register_side_effect(valdtr, ext, "fileinto"); + + return TRUE; +} + +void sieve_ext_imap4flags_interpreter_load +(const struct sieve_extension *ext, const struct sieve_runtime_env *renv) +{ + sieve_interpreter_extension_register + (renv->interp, ext, &imap4flags_interpreter_extension, NULL); +} + +static bool ext_imap4flags_interpreter_load +(const struct sieve_extension *ext, const struct sieve_runtime_env *renv, + sieve_size_t *address ATTR_UNUSED) +{ + sieve_ext_imap4flags_interpreter_load(ext, renv); + return TRUE; +} + + + diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imapflags.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imapflags.c new file mode 100644 index 0000000..ba99035 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/ext-imapflags.c @@ -0,0 +1,213 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +/* Extension imapflags + * -------------------- + * + * Authors: Stephan Bosch + * Specification: draft-melnikov-sieve-imapflags-03.txt + * Implementation: full, but deprecated; provided for backwards compatibility + * Status: testing + * + */ + +#include "lib.h" +#include "mempool.h" +#include "str.h" + +#include "sieve-common.h" + +#include "sieve-ast.h" +#include "sieve-code.h" +#include "sieve-extensions.h" +#include "sieve-actions.h" +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" + +#include "ext-imap4flags-common.h" + +/* + * Commands + */ + +static bool cmd_mark_validate + (struct sieve_validator *valdtr, struct sieve_command *cmd); + +/* Mark command + * + * Syntax: + * mark + */ + +static const struct sieve_command_def cmd_mark = { + .identifier = "mark", + .type = SCT_COMMAND, + .positional_args = 0, + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = cmd_mark_validate +}; + +/* Unmark command + * + * Syntax: + * unmark + */ +static const struct sieve_command_def cmd_unmark = { + .identifier = "unmark", + .type = SCT_COMMAND, + .positional_args = 0, + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .validate = cmd_mark_validate +}; + +/* + * Extension + */ + +static bool ext_imapflags_load + (const struct sieve_extension *ext, void **context); +static bool ext_imapflags_validator_load + (const struct sieve_extension *ext, struct sieve_validator *valdtr); +static bool ext_imapflags_interpreter_load + (const struct sieve_extension *ext, const struct sieve_runtime_env *renv, + sieve_size_t *address); + +const struct sieve_extension_def imapflags_extension = { + .name = "imapflags", + .load = ext_imapflags_load, + .validator_load = ext_imapflags_validator_load, + .interpreter_load = ext_imapflags_interpreter_load +}; + +static bool ext_imapflags_load +(const struct sieve_extension *ext, void **context) +{ + if ( *context == NULL ) { + /* Make sure real extension is registered, it is needed by the binary */ + *context = (void *) + sieve_extension_require(ext->svinst, &imap4flags_extension, FALSE); + } + + return TRUE; +} + +/* + * Validator + */ + +static bool ext_imapflags_validator_check_conflict + (const struct sieve_extension *ext, + struct sieve_validator *valdtr, void *context, + struct sieve_ast_argument *require_arg, + const struct sieve_extension *other_ext, + bool required); +static bool ext_imapflags_validator_validate + (const struct sieve_extension *ext, + struct sieve_validator *valdtr, void *context, + struct sieve_ast_argument *require_arg, + bool required); + +const struct sieve_validator_extension +imapflags_validator_extension = { + .ext = &imapflags_extension, + .check_conflict = ext_imapflags_validator_check_conflict, + .validate = ext_imapflags_validator_validate +}; + +static bool ext_imapflags_validator_load +(const struct sieve_extension *ext, struct sieve_validator *valdtr) +{ + sieve_validator_extension_register + (valdtr, ext, &imapflags_validator_extension, NULL); + + return TRUE; +} + +static bool ext_imapflags_validator_check_conflict +(const struct sieve_extension *ext, + struct sieve_validator *valdtr, void *context ATTR_UNUSED, + struct sieve_ast_argument *require_arg, + const struct sieve_extension *ext_other, + bool required ATTR_UNUSED) +{ + const struct sieve_extension *master_ext = + (const struct sieve_extension *) ext->context; + + if ( ext_other == master_ext ) { + sieve_argument_validate_error(valdtr, require_arg, + "the (deprecated) imapflags extension cannot be used " + "together with the imap4flags extension"); + return FALSE; + } + + return TRUE; +} + +static bool ext_imapflags_validator_validate +(const struct sieve_extension *ext, + struct sieve_validator *valdtr, void *context ATTR_UNUSED, + struct sieve_ast_argument *require_arg ATTR_UNUSED, + bool required ATTR_UNUSED) +{ + const struct sieve_extension *master_ext = + (const struct sieve_extension *) ext->context; + + /* No conflicts */ + + /* Register commands */ + sieve_validator_register_command(valdtr, master_ext, &cmd_setflag); + sieve_validator_register_command(valdtr, master_ext, &cmd_addflag); + sieve_validator_register_command(valdtr, master_ext, &cmd_removeflag); + + sieve_validator_register_command(valdtr, master_ext, &cmd_mark); + sieve_validator_register_command(valdtr, master_ext, &cmd_unmark); + + /* Attach flags side-effect to keep and fileinto actions */ + sieve_ext_imap4flags_register_side_effect(valdtr, master_ext, "keep"); + sieve_ext_imap4flags_register_side_effect(valdtr, master_ext, "fileinto"); + + return TRUE; +} + +/* + * Interpreter + */ + +static bool ext_imapflags_interpreter_load +(const struct sieve_extension *ext, const struct sieve_runtime_env *renv, + sieve_size_t *address ATTR_UNUSED) +{ + const struct sieve_extension *master_ext = + (const struct sieve_extension *) ext->context; + + sieve_ext_imap4flags_interpreter_load(master_ext, renv); + return TRUE; +} + +/* + * Command validation + */ + +static bool cmd_mark_validate +(struct sieve_validator *valdtr, struct sieve_command *cmd) +{ + if ( sieve_command_is(cmd, cmd_mark) ) + cmd->def = &cmd_addflag; + else + cmd->def = &cmd_removeflag; + + cmd->first_positional = sieve_ast_argument_cstring_create + (cmd->ast_node, "\\flagged", cmd->ast_node->source_line); + + if ( !sieve_validator_argument_activate + (valdtr, cmd, cmd->first_positional, FALSE) ) + return FALSE; + + return TRUE; +} diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h b/pigeonhole/src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h new file mode 100644 index 0000000..b38a3c8 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/sieve-ext-imap4flags.h @@ -0,0 +1,74 @@ +#ifndef SIEVE_EXT_IMAP4FLAGS_H +#define SIEVE_EXT_IMAP4FLAGS_H + +struct sieve_variable_storage; + +/* + * Imap4flags extension + */ + +/* FIXME: this is not suitable for future plugin support */ + +extern const struct sieve_extension_def imap4flags_extension; +extern const struct sieve_interpreter_extension + imap4flags_interpreter_extension; + +static inline const struct sieve_extension * +sieve_ext_imap4flags_require_extension +(struct sieve_instance *svinst) +{ + return sieve_extension_require + (svinst, &imap4flags_extension, TRUE); +} + +void sieve_ext_imap4flags_interpreter_load +(const struct sieve_extension *ext, + const struct sieve_runtime_env *renv); + +/* + * Action side-effect + */ + +void sieve_ext_imap4flags_register_side_effect +(struct sieve_validator *valdtr, const struct sieve_extension *flg_ext, + const char *command); + +/* + * Flag syntax + */ + +bool sieve_ext_imap4flags_flag_is_valid(const char *flag); + +/* + * Flag manipulation + */ + +int sieve_ext_imap4flags_set_flags +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index, + struct sieve_stringlist *flags) ATTR_NULL(3); +int sieve_ext_imap4flags_add_flags +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index, + struct sieve_stringlist *flags) ATTR_NULL(3); +int sieve_ext_imap4flags_remove_flags +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_variable_storage *storage, + unsigned int var_index, + struct sieve_stringlist *flags) ATTR_NULL(3); + +/* + * Flag retrieval + */ + +struct sieve_stringlist *sieve_ext_imap4flags_get_flags +(const struct sieve_runtime_env *renv, + const struct sieve_extension *flg_ext, + struct sieve_stringlist *flags_list); + +#endif diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/tag-flags.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/tag-flags.c new file mode 100644 index 0000000..331063d --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/tag-flags.c @@ -0,0 +1,402 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str-sanitize.h" +#include "array.h" +#include "mail-storage.h" + +#include "sieve-code.h" +#include "sieve-stringlist.h" +#include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-result.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-actions.h" +#include "sieve-dump.h" + +#include "ext-imap4flags-common.h" + +#include <ctype.h> + +/* + * Flags tagged argument + */ + +static bool +tag_flags_validate(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, struct sieve_command *cmd); +static bool +tag_flags_validate_persistent(struct sieve_validator *valdtr, + struct sieve_command *cmd, + const struct sieve_extension *ext); +static bool +tag_flags_generate(const struct sieve_codegen_env *cgenv, + struct sieve_ast_argument *arg, struct sieve_command *cmd); + +const struct sieve_argument_def tag_flags = { + .identifier = "flags", + .validate = tag_flags_validate, + .generate = tag_flags_generate, +}; + +const struct sieve_argument_def tag_flags_implicit = { + .identifier = "flags-implicit", + .validate_persistent = tag_flags_validate_persistent, + .generate = tag_flags_generate, +}; + +/* + * Side effect + */ + +static bool +seff_flags_dump_context(const struct sieve_side_effect *seffect, + const struct sieve_dumptime_env *denv, + sieve_size_t *address); +static int +seff_flags_read_context(const struct sieve_side_effect *seffect, + const struct sieve_runtime_env *renv, + sieve_size_t *address, void **context); + +static int +seff_flags_merge(const struct sieve_runtime_env *renv, + const struct sieve_action *action, + const struct sieve_side_effect *old_seffect, + const struct sieve_side_effect *new_seffect, + void **old_context); + +static void +seff_flags_print(const struct sieve_side_effect *seffect, + const struct sieve_action *action, + const struct sieve_result_print_env *rpenv, bool *keep); + +static int +seff_flags_pre_execute(const struct sieve_side_effect *seffect, + const struct sieve_action_exec_env *aenv, + void *tr_context, void **se_tr_context); + +const struct sieve_side_effect_def flags_side_effect = { + SIEVE_OBJECT("flags", &flags_side_effect_operand, 0), + .to_action = &act_store, + .dump_context = seff_flags_dump_context, + .read_context = seff_flags_read_context, + .merge = seff_flags_merge, + .print = seff_flags_print, + .pre_execute = seff_flags_pre_execute, +}; + +/* + * Operand + */ + +static const struct sieve_extension_objects ext_side_effects = + SIEVE_EXT_DEFINE_SIDE_EFFECT(flags_side_effect); + +const struct sieve_operand_def flags_side_effect_operand = { + .name = "flags operand", + .ext_def = &imap4flags_extension, + .class = &sieve_side_effect_operand_class, + .interface = &ext_side_effects, +}; + +/* + * Tag validation + */ + +static bool +tag_flags_validate_persistent(struct sieve_validator *valdtr ATTR_UNUSED, + struct sieve_command *cmd, + const struct sieve_extension *ext) +{ + if (sieve_command_find_argument(cmd, &tag_flags) == NULL) + sieve_command_add_dynamic_tag(cmd, ext, &tag_flags_implicit, + -1); + return TRUE; +} + +static bool +tag_flags_validate(struct sieve_validator *valdtr, + struct sieve_ast_argument **arg, struct sieve_command *cmd) +{ + struct sieve_ast_argument *tag = *arg; + + /* Detach the tag itself */ + *arg = sieve_ast_argument_next(*arg); + + /* Check syntax: + * :flags <list-of-flags: string-list> + */ + if (!sieve_validate_tag_parameter(valdtr, cmd, tag, *arg, NULL, 0, + SAAT_STRING_LIST, FALSE)) + return FALSE; + + tag->parameters = *arg; + + /* Detach parameter */ + *arg = sieve_ast_arguments_detach(*arg,1); + return TRUE; +} + +/* + * Code generation + */ + +static bool +tag_flags_generate(const struct sieve_codegen_env *cgenv, + struct sieve_ast_argument *arg, struct sieve_command *cmd) +{ + struct sieve_ast_argument *param; + + if (sieve_ast_argument_type(arg) != SAAT_TAG) + return FALSE; + + sieve_opr_side_effect_emit(cgenv->sblock, arg->argument->ext, + &flags_side_effect); + + if (sieve_argument_is(arg, tag_flags)) { + /* Explicit :flags tag */ + param = arg->parameters; + + /* Call the generation function for the argument */ + if (param->argument != NULL && param->argument->def != NULL && + param->argument->def->generate != NULL && + !param->argument->def->generate(cgenv, param, cmd)) + return FALSE; + } else if (sieve_argument_is(arg, tag_flags_implicit)) { + /* Implicit flags */ + sieve_opr_omitted_emit(cgenv->sblock); + } else { + /* Something else?! */ + i_unreached(); + } + return TRUE; +} + +/* + * Side effect implementation + */ + +/* Context data */ + +struct seff_flags_context { + ARRAY(const char *) keywords; + enum mail_flags flags; +}; + +/* Context coding */ + +static bool +seff_flags_dump_context(const struct sieve_side_effect *seffect ATTR_UNUSED, + const struct sieve_dumptime_env *denv, + sieve_size_t *address) +{ + return sieve_opr_stringlist_dump_ex(denv, address, "flags", "INTERNAL"); +} + +static struct seff_flags_context * +seff_flags_get_implicit_context(const struct sieve_extension *this_ext, + struct sieve_result *result) +{ + pool_t pool = sieve_result_pool(result); + struct seff_flags_context *ctx; + const char *flag; + struct ext_imap4flags_iter flit; + + ctx = p_new(pool, struct seff_flags_context, 1); + p_array_init(&ctx->keywords, pool, 2); + + T_BEGIN { + /* Unpack */ + ext_imap4flags_get_implicit_flags_init(&flit, this_ext, result); + while ((flag = ext_imap4flags_iter_get_flag(&flit)) != NULL) { + if (flag != NULL && *flag != '\\') { + /* keyword */ + const char *keyword = p_strdup(pool, flag); + array_append(&ctx->keywords, &keyword, 1); + } else { + /* system flag */ + if (flag == NULL || + strcasecmp(flag, "\\flagged") == 0) + ctx->flags |= MAIL_FLAGGED; + else if (strcasecmp(flag, "\\answered") == 0) + ctx->flags |= MAIL_ANSWERED; + else if (strcasecmp(flag, "\\deleted") == 0) + ctx->flags |= MAIL_DELETED; + else if (strcasecmp(flag, "\\seen") == 0) + ctx->flags |= MAIL_SEEN; + else if (strcasecmp(flag, "\\draft") == 0) + ctx->flags |= MAIL_DRAFT; + } + } + } T_END; + + return ctx; +} + +static int +seff_flags_do_read_context(const struct sieve_side_effect *seffect, + const struct sieve_runtime_env *renv, + sieve_size_t *address, void **se_context) +{ + pool_t pool = sieve_result_pool(renv->result); + struct seff_flags_context *ctx; + string_t *flags_item; + struct sieve_stringlist *flag_list = NULL; + int ret; + + ret = sieve_opr_stringlist_read_ex(renv, address, "flags", TRUE, + &flag_list); + if (ret <= 0) + return ret; + + if (flag_list == NULL) { + /* Flag list is omitted, use current value of internal + * variable to construct side effect context. + */ + *se_context = seff_flags_get_implicit_context( + SIEVE_OBJECT_EXTENSION(seffect), renv->result); + return SIEVE_EXEC_OK; + } + + ctx = p_new(pool, struct seff_flags_context, 1); + p_array_init(&ctx->keywords, pool, 2); + + /* Unpack */ + flags_item = NULL; + while ((ret = sieve_stringlist_next_item(flag_list, &flags_item)) > 0) { + const char *flag; + struct ext_imap4flags_iter flit; + + ext_imap4flags_iter_init(&flit, flags_item); + + while ((flag = ext_imap4flags_iter_get_flag(&flit)) != NULL) { + if (flag != NULL && *flag != '\\') { + /* keyword */ + const char *keyword = p_strdup(pool, flag); + + /* FIXME: should check for duplicates (cannot + trust variables) */ + array_append(&ctx->keywords, &keyword, 1); + } else { + /* system flag */ + if (flag == NULL || + strcasecmp(flag, "\\flagged") == 0) + ctx->flags |= MAIL_FLAGGED; + else if (strcasecmp(flag, "\\answered") == 0) + ctx->flags |= MAIL_ANSWERED; + else if (strcasecmp(flag, "\\deleted") == 0) + ctx->flags |= MAIL_DELETED; + else if (strcasecmp(flag, "\\seen") == 0) + ctx->flags |= MAIL_SEEN; + else if (strcasecmp(flag, "\\draft") == 0) + ctx->flags |= MAIL_DRAFT; + } + } + } + + if (ret < 0) + return flag_list->exec_status; + + *se_context = (void *)ctx; + return SIEVE_EXEC_OK; +} + +static int +seff_flags_read_context(const struct sieve_side_effect *seffect, + const struct sieve_runtime_env *renv, + sieve_size_t *address, void **se_context) +{ + int ret; + + T_BEGIN { + ret = seff_flags_do_read_context(seffect, renv, address, + se_context); + } T_END; + + return ret; +} + +/* Result verification */ + +static int +seff_flags_merge(const struct sieve_runtime_env *renv ATTR_UNUSED, + const struct sieve_action *action ATTR_UNUSED, + const struct sieve_side_effect *old_seffect ATTR_UNUSED, + const struct sieve_side_effect *new_seffect, + void **old_context) +{ + if (new_seffect != NULL) + *old_context = new_seffect->context; + return 1; +} + +/* Result printing */ + +static void +seff_flags_print(const struct sieve_side_effect *seffect, + const struct sieve_action *action ATTR_UNUSED, + const struct sieve_result_print_env *rpenv, + bool *keep ATTR_UNUSED) +{ + struct sieve_result *result = rpenv->result; + struct seff_flags_context *ctx = + (struct seff_flags_context *)seffect->context; + unsigned int i; + + if (ctx == NULL) { + ctx = seff_flags_get_implicit_context( + SIEVE_OBJECT_EXTENSION(seffect), result); + } + + if (ctx->flags != 0 || array_count(&ctx->keywords) > 0) { + T_BEGIN { + string_t *flags = t_str_new(128); + + if ((ctx->flags & MAIL_FLAGGED) > 0) + str_printfa(flags, " \\flagged"); + if ((ctx->flags & MAIL_ANSWERED) > 0) + str_printfa(flags, " \\answered"); + if ((ctx->flags & MAIL_DELETED) > 0) + str_printfa(flags, " \\deleted"); + if ((ctx->flags & MAIL_SEEN) > 0) + str_printfa(flags, " \\seen"); + if ((ctx->flags & MAIL_DRAFT) > 0) + str_printfa(flags, " \\draft"); + + for (i = 0; i < array_count(&ctx->keywords); i++) { + const char *const *keyword = + array_idx(&ctx->keywords, i); + str_printfa(flags, " %s", + str_sanitize(*keyword, 64)); + } + + sieve_result_seffect_printf(rpenv, "add IMAP flags:%s", + str_c(flags)); + } T_END; + } +} + +/* Result execution */ + +static int +seff_flags_pre_execute(const struct sieve_side_effect *seffect, + const struct sieve_action_exec_env *aenv, + void *tr_context, void **se_tr_context ATTR_UNUSED) +{ + struct seff_flags_context *ctx = seffect->context; + const char *const *keywords; + + if (ctx == NULL) { + ctx = seff_flags_get_implicit_context( + SIEVE_OBJECT_EXTENSION(seffect), aenv->result); + } + + (void)array_append_space(&ctx->keywords); + keywords = array_idx(&ctx->keywords, 0); + + sieve_act_store_add_flags(aenv, tr_context, keywords, ctx->flags); + return SIEVE_EXEC_OK; +} diff --git a/pigeonhole/src/lib-sieve/plugins/imap4flags/tst-hasflag.c b/pigeonhole/src/lib-sieve/plugins/imap4flags/tst-hasflag.c new file mode 100644 index 0000000..23f2acc --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/imap4flags/tst-hasflag.c @@ -0,0 +1,248 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" + +#include "sieve-commands.h" +#include "sieve-stringlist.h" +#include "sieve-code.h" +#include "sieve-comparators.h" +#include "sieve-match-types.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" +#include "sieve-match.h" + +#include "ext-imap4flags-common.h" + +/* + * Hasflag test + * + * Syntax: + * hasflag [MATCH-TYPE] [COMPARATOR] [<variable-list: string-list>] + * <list-of-flags: string-list> + */ + +static bool tst_hasflag_registered + (struct sieve_validator *valdtr, const struct sieve_extension *ext, + struct sieve_command_registration *cmd_reg); +static bool tst_hasflag_validate + (struct sieve_validator *valdtr, struct sieve_command *tst); +static bool tst_hasflag_generate + (const struct sieve_codegen_env *cgenv, struct sieve_command *cmd); + +const struct sieve_command_def tst_hasflag = { + .identifier = "hasflag", + .type = SCT_TEST, + .positional_args = -1, /* We check positional arguments ourselves */ + .subtests = 0, + .block_allowed = FALSE, + .block_required = FALSE, + .registered = tst_hasflag_registered, + .validate = tst_hasflag_validate, + .generate = tst_hasflag_generate +}; + +/* + * Hasflag operation + */ + +static bool tst_hasflag_operation_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); +static int tst_hasflag_operation_execute + (const struct sieve_runtime_env *renv, sieve_size_t *address); + +const struct sieve_operation_def hasflag_operation = { + .mnemonic = "HASFLAG", + .ext_def = &imap4flags_extension, + .code = EXT_IMAP4FLAGS_OPERATION_HASFLAG, + .dump = tst_hasflag_operation_dump, + .execute = tst_hasflag_operation_execute +}; + +/* + * Optional arguments + */ + +enum tst_hasflag_optional { + OPT_VARIABLES = SIEVE_MATCH_OPT_LAST, +}; + +/* + * Tag registration + */ + +static bool tst_hasflag_registered +(struct sieve_validator *valdtr, const struct sieve_extension *ext ATTR_UNUSED, + struct sieve_command_registration *cmd_reg) +{ + /* The order of these is not significant */ + sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR); + sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE); + + return TRUE; +} + +/* + * Validation + */ + +static bool tst_hasflag_validate +(struct sieve_validator *valdtr, struct sieve_command *tst) +{ + struct sieve_ast_argument *vars = tst->first_positional; + struct sieve_ast_argument *keys = sieve_ast_argument_next(vars); + const struct sieve_match_type mcht_default = + SIEVE_MATCH_TYPE_DEFAULT(is_match_type); + const struct sieve_comparator cmp_default = + SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); + + if ( !ext_imap4flags_command_validate(valdtr, tst) ) + return FALSE; + + if ( keys == NULL ) { + keys = vars; + vars = NULL; + } else { + vars->argument->id_code = OPT_VARIABLES; + } + + /* Validate the key argument to a specified match type */ + return sieve_match_type_validate + (valdtr, tst, keys, &mcht_default, &cmp_default); +} + +/* + * Code generation + */ + +static bool tst_hasflag_generate +(const struct sieve_codegen_env *cgenv, struct sieve_command *cmd) +{ + sieve_operation_emit(cgenv->sblock, cmd->ext, &hasflag_operation); + + /* Generate arguments */ + if ( !sieve_generate_arguments(cgenv, cmd, NULL) ) + return FALSE; + + return TRUE; +} + +/* + * Code dump + */ + +static bool tst_hasflag_operation_dump +(const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + int opt_code = 0; + + sieve_code_dumpf(denv, "HASFLAG"); + sieve_code_descend(denv); + + /* Optional operands */ + + for (;;) { + bool opok = TRUE; + int opt; + + if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code)) + < 0 ) + return FALSE; + + if ( opt == 0 ) break; + + switch ( opt_code ) { + case OPT_VARIABLES: + opok = sieve_opr_stringlist_dump(denv, address, "variables"); + break; + default: + return FALSE; + } + + if ( !opok ) return FALSE; + } + + return + sieve_opr_stringlist_dump(denv, address, "list of flags"); +} + +/* + * Interpretation + */ + +static int tst_hasflag_operation_execute +(const struct sieve_runtime_env *renv, sieve_size_t *address) +{ + const struct sieve_operation *op = renv->oprtn; + int opt_code = 0; + struct sieve_comparator cmp = + SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator); + struct sieve_match_type mcht = + SIEVE_MATCH_TYPE_DEFAULT(is_match_type); + struct sieve_stringlist *flag_list, *variables_list, *value_list, *key_list; + int match, ret; + + /* + * Read operands + */ + + /* Optional operands */ + + variables_list = NULL; + for (;;) { + int opt; + + if ( (opt=sieve_match_opr_optional_read + (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 ) + return ret; + + if ( opt == 0 ) break; + + switch ( opt_code ) { + case OPT_VARIABLES: + ret = sieve_opr_stringlist_read + (renv, address, "variables-list", &variables_list); + break; + default: + sieve_runtime_trace_error(renv, "invalid optional operand"); + ret = SIEVE_EXEC_BIN_CORRUPT; + } + + if ( ret <= 0 ) return ret; + } + + /* Fixed operands */ + + if ( (ret=sieve_opr_stringlist_read(renv, address, "flag-list", &flag_list)) + <= 0 ) + return ret; + + /* + * Perform operation + */ + + sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS, "hasflag test"); + + value_list = sieve_ext_imap4flags_get_flags + (renv, op->ext, variables_list); + + if ( sieve_match_type_is(&mcht, is_match_type) || + sieve_match_type_is(&mcht, contains_match_type) ) { + key_list = sieve_ext_imap4flags_get_flags + (renv, op->ext, flag_list); + } else { + key_list = flag_list; + } + + /* Perform match */ + if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 ) + return ret; + + /* Set test result for subsequent conditional jump */ + sieve_interpreter_set_test_result(renv->interp, match > 0); + return SIEVE_EXEC_OK; +} + + |