diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2018-10-24 00:15:01 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2018-10-24 00:26:15 +0300 |
commit | 35c9ae8024466f176ddc77306c08b5edc21bc0a2 (patch) | |
tree | 694d9061bfba7aaea01997c8bb4efa801c49a05c | |
parent | 00b8be32a86c183c049ebfd40e67450878792bd0 (diff) | |
download | mailutils-35c9ae8024466f176ddc77306c08b5edc21bc0a2.tar.gz mailutils-35c9ae8024466f176ddc77306c08b5edc21bc0a2.tar.bz2 |
sieve: set variables from command line
The new command line option --variable initializes the RFC 5229 variable.
* NEWS: Update.
* doc/texinfo/programs.texi: Fix description of sieve command
line options.
* include/mailutils/sieve.h (mu_sieve_variable_initialize): New proto.
* libmu_sieve/runtime.c (sieve_run): Call mu_i_sv_init_variables to
clear and initialize the table of variables.
* libmu_sieve/sieve-gram.y (mu_sieve_machine_dup): Copy variables.
(mu_sieve_machine_destroy): Destroy table of variables and initializer
list.
* libmu_sieve/sieve-priv.h (mu_sieve_machine) <init_var>: New member.
(mu_sieve_variable_initializer): New type.
(mu_i_sv_init_variables): New proto.
* libmu_sieve/variables.c (mu_sieve_variable_initialize): New function.
(mu_i_sv_copy_variables): Copy initializers as well.
(mu_i_sv_init_variables): New function.
* sieve/sieve.c: New command line option --variable.
* sieve/tests/variables.at: Test the --variable option.
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | doc/texinfo/programs.texi | 21 | ||||
-rw-r--r-- | include/mailutils/sieve.h | 2 | ||||
-rw-r--r-- | libmu_sieve/runtime.c | 3 | ||||
-rw-r--r-- | libmu_sieve/sieve-gram.y | 7 | ||||
-rw-r--r-- | libmu_sieve/sieve-priv.h | 12 | ||||
-rw-r--r-- | libmu_sieve/variables.c | 151 | ||||
-rw-r--r-- | sieve/sieve.c | 87 | ||||
-rw-r--r-- | sieve/tests/variables.at | 16 |
9 files changed, 270 insertions, 38 deletions
@@ -1,4 +1,4 @@ -GNU mailutils NEWS -- history of user-visible changes. 2018-08-26 +GNU mailutils NEWS -- history of user-visible changes. 2018-10-24 Copyright (C) 2002-2018 Free Software Foundation, Inc. See the end of file for copying conditions. @@ -46,6 +46,13 @@ Optional charset defaults to "utf-8". * Introduced support for Python 3.x +* Define sieve variables from the command line + +The sieve utility now allows you to supply initial values for +RFC 5229 variables using the --variable command line option, e.g. + + sieve --variable mailbox=outgoing + * Support for Berkeley DB versions 5 and 6 * headline variable in the mail utility diff --git a/doc/texinfo/programs.texi b/doc/texinfo/programs.texi index 15e10078f..816e2f919 100644 --- a/doc/texinfo/programs.texi +++ b/doc/texinfo/programs.texi @@ -6089,7 +6089,7 @@ stand-alone @dfn{sieve interpreter}, which is described in detail below. @node sieve interpreter @subsection A Sieve Interpreter -Sieve interpreter @command{sieve} allows to apply Sieve scripts to an +The sieve interpreter @command{sieve} allows you to apply Sieve scripts to arbitrary number of mailboxes. GNU @command{sieve} implements a superset of the Sieve language as described in RFC 3028. @xref{Sieve Language}, for a description of the Sieve language. @xref{GNU Extensions}, for a @@ -6112,6 +6112,11 @@ The @command{sieve} invocation syntax is: sieve [@var{options}] @var{script} @end example +Normally, @var{script} is the name of the disk file with the Sieve +script. If @var{script} is a single dash, the script is read from the +standard input. If the @option{-E} (@option{--expression}) option is +given, @var{script} is taken to be the sieve script text. + @noindent where @var{script} denotes the filename of the sieve program to parse, and @var{options} is one or more of the following: @@ -6147,6 +6152,9 @@ more of the following letters: @itemx --dump Compile the script, dump disassembled code on standard output and exit. +@item --environment=@var{name}=@var{value} +Set sieve environment variable @var{name} to the @var{value}. + @item -e @var{address} @itemx --email @var{address} Override the user email address. This is useful for @code{reject} and @@ -6155,6 +6163,10 @@ from the user name and the full name of the machine where @command{sieve} is executed. See also @ref{Sieve Configuration, email}. +@item -E, +@itemx --expression +Treat the @var{script} argument as Sieve program text. + @item -I @var{dir} @itemx --includedir=@var{dir} Append directory @var{dir} to the list of directories searched for @@ -6179,6 +6191,9 @@ library files. See also @ref{Sieve Configuration, library-path}. Add @var{dir} to the beginning of the list of directories searched for library files. +@item --line-info=@var{bool} +Print source location along with action logs (default). + @item -M @var{url} @itemx --mailer=@var{url} Define the URL of the default mailer. @@ -6196,6 +6211,10 @@ Do not prefix diagnostic messages with the program name. Ticket file for mailbox authentication. See also @ref{Sieve Configuration, ticket}. +@item --variable=@var{name}=@var{value} +Set Sieve variable @var{name}. This option automatically inserts +@samp{require "variables"} at the top of the script. + @item -v @itemx --verbose Log all actions executed. See also @ref{Sieve Configuration, verbose}. diff --git a/include/mailutils/sieve.h b/include/mailutils/sieve.h index d5c84c5dc..4a5671b4e 100644 --- a/include/mailutils/sieve.h +++ b/include/mailutils/sieve.h @@ -208,6 +208,8 @@ int mu_sieve_require_relational (mu_sieve_machine_t mach, const char *name); int mu_sieve_require_variables (mu_sieve_machine_t mach); int mu_sieve_has_variables (mu_sieve_machine_t mach); +int mu_sieve_variable_initialize (mu_sieve_machine_t mach, + char const *name, char const *value); int mu_sieve_require_environment (mu_sieve_machine_t mach); diff --git a/libmu_sieve/runtime.c b/libmu_sieve/runtime.c index 0d58e366a..f7deedb82 100644 --- a/libmu_sieve/runtime.c +++ b/libmu_sieve/runtime.c @@ -233,8 +233,7 @@ sieve_run (mu_sieve_machine_t mach) { mach->action_count = 0; - if (mu_sieve_has_variables (mach)) - mu_assoc_clear (mach->vartab); + mu_i_sv_init_variables (mach); for (mach->pc = 1; mach->prog[mach->pc].handler; ) (*mach->prog[mach->pc++].instr) (mach); diff --git a/libmu_sieve/sieve-gram.y b/libmu_sieve/sieve-gram.y index 898d4fd64..c1ff7df94 100644 --- a/libmu_sieve/sieve-gram.y +++ b/libmu_sieve/sieve-gram.y @@ -1232,7 +1232,9 @@ mu_sieve_machine_dup (mu_sieve_machine_t const in, mu_sieve_machine_t *out) mu_locus_range_copy (&mach->dbg_locus, &in->dbg_locus); copy_stream_state (mach, in); - + + mu_i_sv_copy_variables (mach, in); + mach->data = in->data; mach->logger = in->logger; mach->daemon_email = in->daemon_email; @@ -1412,6 +1414,9 @@ mu_sieve_machine_destroy (mu_sieve_machine_t *pmach) mu_sieve_free (mach, mach->idspace); mu_opool_destroy (&mach->string_pool); mu_list_destroy (&mach->memory_pool); + mu_assoc_destroy (&mach->vartab); + mu_list_destroy (&mach->init_var); + free (mach); *pmach = NULL; } diff --git a/libmu_sieve/sieve-priv.h b/libmu_sieve/sieve-priv.h index 77a6521d5..ed6ea5e3f 100644 --- a/libmu_sieve/sieve-priv.h +++ b/libmu_sieve/sieve-priv.h @@ -95,7 +95,8 @@ struct mu_sieve_machine regmatch_t *match_buf; /* Offsets of parenthesized groups */ size_t match_count; /* Actual number of elements used in match_buf */ size_t match_max; /* Total number of elements available in match_buf */ - + mu_list_t init_var; /* List of variable initializers */ + /* Call environment */ const char *identifier; /* Name of action or test being executed */ size_t argstart; /* Index of the first argument in valspace */ @@ -175,6 +176,12 @@ struct mu_sieve_node_list struct mu_sieve_node *head, *tail; }; +struct mu_sieve_variable_initializer +{ + char *name; + char *value; +}; + int mu_sieve_yyerror (const char *s); int mu_sieve_yylex (void); @@ -249,4 +256,7 @@ void mu_i_sv_copy_variables (mu_sieve_machine_t child, mu_sieve_machine_t parent); int mu_i_sv_expand_variables (char const *input, size_t len, char **exp, void *data); +void mu_i_sv_init_variables (mu_sieve_machine_t mach); + + diff --git a/libmu_sieve/variables.c b/libmu_sieve/variables.c index 37a9daf47..60a0abbf7 100644 --- a/libmu_sieve/variables.c +++ b/libmu_sieve/variables.c @@ -160,26 +160,11 @@ findprec (char const *name) abort (); } -static int -sieve_action_set (mu_sieve_machine_t mach) +static void +variable_set (mu_sieve_machine_t mach, char const *name, char *value) { - size_t i; - char *name; - char *value; struct sieve_variable *var, **vptr; int rc; - - mu_sieve_get_arg (mach, 0, SVT_STRING, &name); - mu_sieve_get_arg (mach, 1, SVT_STRING, &value); - - value = mu_sieve_strdup (mach, value); - for (i = 0; i < mach->tagcount; i++) - { - mu_sieve_value_t *p = mu_sieve_get_tag_n (mach, i); - char *str = findprec (p->tag)->modify (mach, value); - mu_sieve_free (mach, value); - value = str; - } rc = mu_assoc_install_ref (mach->vartab, name, &vptr); switch (rc) @@ -188,7 +173,7 @@ sieve_action_set (mu_sieve_machine_t mach) var = malloc (sizeof (*var)); if (!var) { - mu_sieve_error (mach, "%s", mu_strerror (errno)); + mu_sieve_error (mach, "variable_set: %s", mu_strerror (rc)); mu_sieve_abort (mach); } *vptr = var; @@ -200,12 +185,87 @@ sieve_action_set (mu_sieve_machine_t mach) break; default: - mu_sieve_error (mach, "mu_assoc_ref_install: %s", mu_strerror (rc)); + mu_sieve_error (mach, "variable_set: %s", mu_strerror (rc)); mu_sieve_abort (mach); } var->value = value; +} + +static int +sieve_action_set (mu_sieve_machine_t mach) +{ + size_t i; + char *name; + char *value; + + mu_sieve_get_arg (mach, 0, SVT_STRING, &name); + mu_sieve_get_arg (mach, 1, SVT_STRING, &value); + + value = mu_sieve_strdup (mach, value); + for (i = 0; i < mach->tagcount; i++) + { + mu_sieve_value_t *p = mu_sieve_get_tag_n (mach, i); + char *str = findprec (p->tag)->modify (mach, value); + mu_sieve_free (mach, value); + value = str; + } + + variable_set (mach, name, value); return 0; -} +} + +static int +varini_append (mu_sieve_machine_t mach, + struct mu_sieve_variable_initializer *vini) +{ + if (!mu_sieve_has_variables (mach)) + return EINVAL; + if (!mach->init_var) + { + mu_list_create (&mach->init_var); + mu_list_set_destroy_item (mach->init_var, mu_list_free_item); + } + return mu_list_append (mach->init_var, vini); +} + +static struct mu_sieve_variable_initializer * +varini_alloc (const char *name, const char *value) +{ + struct mu_sieve_variable_initializer *vini; + size_t namelen; + + namelen = strlen (name); + vini = malloc (sizeof (*vini) + namelen + strlen (value) + 2); + if (vini) + { + char *p = (char*) (vini + 1); + vini->name = p; + vini->value = p + namelen + 1; + strcpy (vini->name, name); + strcpy (vini->value, value); + } + return vini; +} + +int +mu_sieve_variable_initialize (mu_sieve_machine_t mach, char const *name, + char const *value) +{ + struct mu_sieve_variable_initializer *vini; + int rc; + + if (!name || !value) + return EINVAL; + if (!mu_sieve_has_variables (mach)) + return EINVAL; + vini = varini_alloc (name, value); + if (!vini) + return ENOMEM; + rc = varini_append (mach, vini); + if (rc) + free (vini); + return rc; +} static int set_tag_checker (mu_sieve_machine_t mach) @@ -414,15 +474,32 @@ mu_sieve_has_variables (mu_sieve_machine_t mach) return mach->vartab != NULL; } +static int +copy_init_var (void *item, void *data) +{ + struct mu_sieve_variable_initializer *vini = item, *vini_new; + mu_sieve_machine_t mach = data; + vini_new = varini_alloc (vini->name, vini->value); + if (!vini_new) + return ENOMEM; + return varini_append (mach, vini_new); +} + void mu_i_sv_copy_variables (mu_sieve_machine_t child, mu_sieve_machine_t parent) { mu_iterator_t itr; - + int rc; + mu_sieve_require_variables (child); - mu_assoc_get_iterator (parent->vartab, &itr); - + rc = mu_assoc_get_iterator (parent->vartab, &itr); + if (rc) + { + mu_sieve_error (child, "mu_assoc_get_iterator: %s", mu_strerror (rc)); + mu_sieve_abort (child); + } + for (mu_iterator_first (itr); !mu_iterator_is_done (itr); mu_iterator_next (itr)) { @@ -438,7 +515,33 @@ mu_i_sv_copy_variables (mu_sieve_machine_t child, mu_sieve_machine_t parent) mu_assoc_install (child->vartab, name, newval); } - mu_iterator_destroy (&itr); + mu_iterator_destroy (&itr); + + rc = mu_list_foreach (parent->init_var, copy_init_var, child); + if (rc) + { + mu_sieve_error (child, "copy_init_var: %s", mu_strerror (rc)); + mu_sieve_abort (child); + } +} + +static int +sieve_setvar (void *item, void *data) +{ + struct mu_sieve_variable_initializer *vini = item; + mu_sieve_machine_t mach = data; + variable_set (mach, vini->name, mu_sieve_strdup (mach, vini->value)); + return 0; +} + +void +mu_i_sv_init_variables (mu_sieve_machine_t mach) +{ + if (mu_sieve_has_variables (mach)) + { + mu_assoc_clear (mach->vartab); + mu_list_foreach (mach->init_var, sieve_setvar, mach); + } } diff --git a/sieve/sieve.c b/sieve/sieve.c index 59ad851d5..ade90e7c9 100644 --- a/sieve/sieve.c +++ b/sieve/sieve.c @@ -62,6 +62,7 @@ static int sieve_print_locus = 1; /* Should the log messages include the static int no_program_name; static mu_list_t env_list; +static mu_list_t var_list; static int sieve_setenv (void *item, void *data) @@ -75,6 +76,14 @@ sieve_setenv (void *item, void *data) return 0; } +static int +sieve_setvar (void *item, void *data) +{ + char *str = item; + mu_sieve_machine_t mach = data; + mu_sieve_variable_initialize (mach, str, str + strlen (str) + 1); + return 0; +} static void modify_debug_flags (mu_debug_level_t set, mu_debug_level_t clr) @@ -141,26 +150,39 @@ cli_email (struct mu_parseopt *po, struct mu_option *opt, char const *arg) } static void -cli_env (struct mu_parseopt *po, struct mu_option *opt, char const *arg) +assign (struct mu_parseopt *po, struct mu_option *opt, char const *arg, + mu_list_t *plist, char const *what) { char *p = strchr (arg, '='); if (p == NULL) - mu_parseopt_error (po, _("malformed environment setting: %s"), arg); + mu_parseopt_error (po, _("malformed %s: %s"), what, arg); else { char *str; str = mu_strdup (arg); str[p - arg] = 0; - if (!env_list) + if (!*plist) { - mu_list_create (&env_list); - mu_list_set_destroy_item (env_list, mu_list_free_item); + mu_list_create (plist); + mu_list_set_destroy_item (*plist, mu_list_free_item); } - mu_list_append (env_list, str); + mu_list_append (*plist, str); } } +static void +cli_env (struct mu_parseopt *po, struct mu_option *opt, char const *arg) +{ + assign (po, opt, arg, &env_list, _("environment setting")); +} + +static void +cli_var (struct mu_parseopt *po, struct mu_option *opt, char const *arg) +{ + assign (po, opt, arg, &var_list, _("variable assignment")); +} + static struct mu_option sieve_options[] = { { "dry-run", 'n', NULL, MU_OPTION_DEFAULT, N_("do not execute any actions, just print what would be done"), @@ -202,6 +224,9 @@ static struct mu_option sieve_options[] = { { "environment", 0, N_("NAME=VALUE"), MU_OPTION_DEFAULT, N_("set sieve environment value"), mu_c_string, NULL, cli_env }, + { "variable", 0, N_("NAME=VALUE"), MU_OPTION_DEFAULT, + N_("set sieve variable"), + mu_c_string, NULL, cli_var }, MU_OPTION_END }, *options[] = { sieve_options, NULL }; @@ -469,7 +494,46 @@ main (int argc, char *argv[]) } else if (argc == 1) { - script = mu_tilde_expansion (argv[0], MU_HIERARCHY_DELIMITER, NULL); + if (expression_option) + script = mu_strdup (argv[0]); + else if (strcmp (argv[0], "-") == 0) + { + mu_stream_t mstr; + mu_off_t size; + int rc; + + rc = mu_memory_stream_create (&mstr, MU_STREAM_RDWR); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_memory_stream_create", + NULL, rc); + exit (EX_SOFTWARE); + } + rc = mu_stream_copy (mstr, mu_strin, 0, &size); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_copy", NULL, rc); + exit (EX_SOFTWARE); + } + rc = mu_stream_seek (mstr, 0, MU_SEEK_SET, NULL); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_seek", NULL, rc); + exit (EX_SOFTWARE); + } + script = mu_alloc (size + 1); + rc = mu_stream_read (mstr, script, size, NULL); + if (rc) + { + mu_diag_funcall (MU_DIAG_ERROR, "mu_stream_read", NULL, rc); + exit (EX_SOFTWARE); + } + script[size] = 0; + mu_stream_destroy (&mstr); + expression_option = 1; + } + else + script = mu_tilde_expansion (argv[0], MU_HIERARCHY_DELIMITER, NULL); } else { @@ -490,7 +554,14 @@ main (int argc, char *argv[]) mu_list_foreach (env_list, sieve_setenv, mach); mu_list_destroy (&env_list); - + + if (var_list) + { + mu_sieve_require_variables (mach); + mu_list_foreach (var_list, sieve_setvar, mach); + mu_list_destroy (&var_list); + } + if (verbose) mu_sieve_set_logger (mach, _sieve_action_log); diff --git a/sieve/tests/variables.at b/sieve/tests/variables.at index 5cb82d61a..099c37917 100644 --- a/sieve/tests/variables.at +++ b/sieve/tests/variables.at @@ -51,6 +51,9 @@ FILEINTO on msg uid 3: delivering into INBOX ]) MUT_TESTCASE([set modifiers],[variables action set], + + + [require [["variables", "fileinto"]]; set "name" :upperfirst :lower "VALUE"; fileinto "INBOX.${name}"; @@ -97,3 +100,16 @@ if address "To" :matches "*@*.*.*" DISCARD on msg uid 2: marking as deleted IMPLICIT KEEP on msg uid 3 ]) + +m4_pushdef([MUT_SIEVE_OPTIONS],[--variable=mailbox=output]) +MUT_TESTCASE([the --variable option],[variables], +[require "fileinto"; +fileinto "${mailbox}"; +], +[],[0],[], +[FILEINTO on msg uid 1: delivering into output +FILEINTO on msg uid 2: delivering into output +FILEINTO on msg uid 3: delivering into output +]) +m4_popdef([MUT_SIEVE_OPTIONS]) + |