summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2018-10-24 00:15:01 +0300
committerSergey Poznyakoff <gray@gnu.org>2018-10-24 00:26:15 +0300
commit35c9ae8024466f176ddc77306c08b5edc21bc0a2 (patch)
tree694d9061bfba7aaea01997c8bb4efa801c49a05c
parent00b8be32a86c183c049ebfd40e67450878792bd0 (diff)
downloadmailutils-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--NEWS9
-rw-r--r--doc/texinfo/programs.texi21
-rw-r--r--include/mailutils/sieve.h2
-rw-r--r--libmu_sieve/runtime.c3
-rw-r--r--libmu_sieve/sieve-gram.y7
-rw-r--r--libmu_sieve/sieve-priv.h12
-rw-r--r--libmu_sieve/variables.c151
-rw-r--r--sieve/sieve.c87
-rw-r--r--sieve/tests/variables.at16
9 files changed, 270 insertions, 38 deletions
diff --git a/NEWS b/NEWS
index 04c9f0ff1..5f8dc26a1 100644
--- a/NEWS
+++ b/NEWS
@@ -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])
+

Return to:

Send suggestions and report system problems to the System administrator.