summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2016-12-11 18:10:47 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2016-12-11 18:10:47 +0200
commit57e0b97994f04b8d3f36ef3c45a99941b4f011bc (patch)
tree58a1de1ec129d4ebf98b95fa59715c30cc7289b8
parent44f87939efa0a33e8d1f26b9d9fa3e15c32d808a (diff)
downloadmailutils-57e0b97994f04b8d3f36ef3c45a99941b4f011bc.tar.gz
mailutils-57e0b97994f04b8d3f36ef3c45a99941b4f011bc.tar.bz2
Support for environment extension (RFC 5183).
* include/mailutils/sieve.h (mu_sieve_require_environment): New proto. * libmu_sieve/Makefile.am: Add environment.c * libmu_sieve/environment.c: New file. * libmu_sieve/require.c: Handle "environment" keyword. * libmu_sieve/sieve-priv.h (mu_sieve_machine) <exenv>: New member. * libmu_sieve/sieve.l: Bugfixes * libmu_sieve/variables.c: Add missing static qualifiers * sieve/sieve.c: New option --environment
m---------gint0
-rw-r--r--include/mailutils/sieve.h7
-rw-r--r--libmu_sieve/Makefile.am1
-rw-r--r--libmu_sieve/environment.c226
-rw-r--r--libmu_sieve/require.c2
-rw-r--r--libmu_sieve/sieve-priv.h4
-rw-r--r--libmu_sieve/sieve.l30
-rw-r--r--libmu_sieve/variables.c4
-rw-r--r--sieve/sieve.c43
9 files changed, 300 insertions, 17 deletions
diff --git a/gint b/gint
-Subproject 42f4712085b40173eaea58e14b1a579291a6fe3
+Subproject fd86bf7d44b0c970771830692ae7491447ebe8b
diff --git a/include/mailutils/sieve.h b/include/mailutils/sieve.h
index bbaccb56d..4e07497f1 100644
--- a/include/mailutils/sieve.h
+++ b/include/mailutils/sieve.h
@@ -205,6 +205,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_require_environment (mu_sieve_machine_t mach);
+
void *mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name);
void mu_sieve_unload_ext (void *handle);
@@ -292,6 +294,11 @@ void mu_sieve_set_daemon_email (mu_sieve_machine_t mach, const char *email);
int mu_sieve_get_message_sender (mu_message_t msg, char **ptext);
+int mu_sieve_get_environ (mu_sieve_machine_t mach, char const *name,
+ char **retval);
+int mu_sieve_set_environ (mu_sieve_machine_t mach, char const *name,
+ char const *value);
+
/* Stream state saving & restoring */
void mu_sieve_stream_save (mu_sieve_machine_t mach);
void mu_sieve_stream_restore (mu_sieve_machine_t mach);
diff --git a/libmu_sieve/Makefile.am b/libmu_sieve/Makefile.am
index a0ce50b65..fd96ac505 100644
--- a/libmu_sieve/Makefile.am
+++ b/libmu_sieve/Makefile.am
@@ -31,6 +31,7 @@ libmu_sieve_la_SOURCES = \
conf.c\
comparator.c\
encoded.c\
+ environment.c\
load.c\
mem.c\
prog.c\
diff --git a/libmu_sieve/environment.c b/libmu_sieve/environment.c
new file mode 100644
index 000000000..9de486271
--- /dev/null
+++ b/libmu_sieve/environment.c
@@ -0,0 +1,226 @@
+/* The Sieve "environment" extension for GNU Mailutils
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ GNU Mailutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Mailutils is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with GNU Mailutils. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sieve-priv.h>
+
+int
+retrieve_env (void *item, void *data, size_t idx, char **pval)
+{
+ mu_sieve_machine_t mach;
+
+ if (idx)
+ return MU_ERR_NOENT;
+ mach = data;
+ return mu_sieve_get_environ (mach, item, pval);
+}
+
+static int
+sieve_test_environment (mu_sieve_machine_t mach)
+{
+ mu_sieve_value_t *name, *key_list;
+
+ name = mu_sieve_get_arg_untyped (mach, 0);
+ key_list = mu_sieve_get_arg_untyped (mach, 1);
+
+ return mu_sieve_vlist_compare (mach, name, key_list, retrieve_env, NULL,
+ mach);
+}
+
+static mu_sieve_data_type environ_args[] = {
+ SVT_STRING,
+ SVT_STRING_LIST,
+ SVT_VOID
+};
+
+static mu_sieve_tag_group_t environ_tag_groups[] = {
+ { mu_sieve_match_part_tags, mu_sieve_match_part_checker },
+ { NULL }
+};
+
+int
+mu_sieve_require_environment (mu_sieve_machine_t mach)
+{
+ mu_sieve_register_test (mach, "environment", sieve_test_environment,
+ environ_args, environ_tag_groups, 1);
+ return 0;
+}
+
+static char *
+std_name_get (mu_sieve_machine_t mach)
+{
+ return strdup (PACKAGE_NAME);
+}
+
+static char *
+std_version_get (mu_sieve_machine_t mach)
+{
+ return strdup (PACKAGE_VERSION);
+}
+
+/* "host" => The fully-qualified domain name of the host where
+ the Sieve script is executing.
+*/
+static char *
+std_host_get (mu_sieve_machine_t mach)
+{
+ char *host;
+ int rc;
+
+ rc = mu_get_host_name (&host);
+ if (rc == 0)
+ return host;
+ return NULL;
+}
+
+
+/* "domain" => The primary DNS domain associated with the Sieve
+ execution context, usually but not always a proper
+ suffix of the host name.
+*/
+static char *
+std_domain_get (mu_sieve_machine_t mach)
+{
+ char *host;
+ int rc;
+
+ rc = mu_get_host_name (&host);
+ if (rc == 0)
+ {
+ char *p = strchr (host, '.');
+ if (p)
+ {
+ p = strdup (p + 1);
+ free (host);
+ return p;
+ }
+ return host;
+ }
+ return NULL;
+}
+
+/* FIXME: do we need set? If so, mu_set_host_name is also needed */
+
+struct stdenviron
+{
+ char *name;
+ char *(*get) (mu_sieve_machine_t);
+ int (*set) (mu_sieve_machine_t, char const *, char const *value);
+};
+
+static struct stdenviron stdenv[] =
+{
+ { "domain", std_domain_get, NULL },
+ { "host", std_host_get, NULL },
+ { "name", std_name_get, NULL },
+ { "version", std_version_get, NULL },
+ { NULL }
+};
+
+static struct stdenviron const *
+stdenv_find (char const *name)
+{
+ struct stdenviron const *p;
+
+ for (p = stdenv; p->name; p++)
+ if (strcmp (p->name, name) == 0)
+ return p;
+ return NULL;
+}
+
+static char *
+stdenv_get (mu_sieve_machine_t mach, char const *name)
+{
+ struct stdenviron const *p = stdenv_find (name);
+ if (!p)
+ return NULL;
+ return p->get (mach);
+}
+
+static int
+stdenv_set (mu_sieve_machine_t mach, char const *name, char const *value)
+{
+ struct stdenviron const *p = stdenv_find (name);
+ if (!p)
+ return MU_ERR_NOENT;
+ if (!p->set)
+ return EACCES;
+ return p->set (mach, name, value);
+}
+
+int
+mu_sieve_get_environ (mu_sieve_machine_t mach, char const *name, char **retval)
+{
+ char *p;
+
+ p = stdenv_get (mach, name);
+ if (p)
+ {
+ *retval = p;
+ return 0;
+ }
+
+ if (!mach->exenv)
+ return MU_ERR_NOENT;
+
+ p = mu_assoc_ref (mach->exenv, name);
+ if (p)
+ {
+ *retval = strdup (*(char**)p);
+ if (!*retval)
+ return errno;
+ }
+ else
+ return MU_ERR_NOENT;
+ return 0;
+}
+
+int
+mu_sieve_set_environ (mu_sieve_machine_t mach, char const *name,
+ char const *value)
+{
+ int rc;
+
+ rc = stdenv_set (mach, name, value);
+ if (rc == MU_ERR_NOENT)
+ {
+ char **pptr;
+
+ if (!mach->exenv)
+ {
+ int rc = mu_assoc_create (&mach->exenv, sizeof (char *), 0);
+ if (rc)
+ return rc;
+ }
+ rc = mu_assoc_ref_install (mach->exenv, name, (void **) &pptr);
+ if (rc == 0 || rc == MU_ERR_EXISTS)
+ {
+ char *copy = strdup (value);
+ if (!copy)
+ rc = errno;
+ else
+ {
+ *pptr = copy;
+ rc = 0;
+ }
+ }
+ }
+ return rc;
+}
+
diff --git a/libmu_sieve/require.c b/libmu_sieve/require.c
index f0ff27c77..c8f5b62b9 100644
--- a/libmu_sieve/require.c
+++ b/libmu_sieve/require.c
@@ -43,6 +43,8 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list)
rc = mu_sieve_require_relational (mach, name);
else if (strcmp (name, "encoded-character") == 0) /* RFC 5228, 2.4.2.4 */
rc = mu_sieve_require_encoded_character (mach, name);
+ else if (strcmp (name, "environment") == 0) /* RFC 5183 */
+ rc = mu_sieve_require_environment (mach);
else if (strncmp (name, "comparator-", 11) == 0)
rc = mu_sieve_registry_require (mach, name + 11,
mu_sieve_record_comparator);
diff --git a/libmu_sieve/sieve-priv.h b/libmu_sieve/sieve-priv.h
index f5fb38a45..b288f213a 100644
--- a/libmu_sieve/sieve-priv.h
+++ b/libmu_sieve/sieve-priv.h
@@ -107,7 +107,9 @@ struct mu_sieve_machine
int dry_run; /* Dry-run mode */
jmp_buf errbuf; /* Target location for non-local exits */
-
+
+ mu_assoc_t exenv; /* Execution environment (RFC 5183) */
+
mu_mailbox_t mailbox; /* Mailbox to operate upon */
size_t msgno; /* Current message number */
mu_message_t msg; /* Current message */
diff --git a/libmu_sieve/sieve.l b/libmu_sieve/sieve.l
index b18cd4ae6..ffc7a4ab8 100644
--- a/libmu_sieve/sieve.l
+++ b/libmu_sieve/sieve.l
@@ -41,10 +41,11 @@ static int strip_tabs;
static int number (void);
static int string (void);
static void line_begin (void);
-static void line_add (char *text, size_t len);
+static void line_add (char const *text, size_t len);
+static void line_addz (char const *text);
static void line_finish (void);
static void multiline_begin (void);
-static void multiline_add (char *);
+static void multiline_add (void);
static void multiline_finish (void);
static char *multiline_strip_tabs (char *text);
static void ident (const char *text);
@@ -286,8 +287,8 @@ true return TRUE;
\"[^\\"\n]*\" { return string (); }
\"[^\\"\n]*\\. { BEGIN(STR);
line_begin ();
- line_add (str_unescape (yytext + 1, yyleng - 1), 0); }
-<STR>[^\\"\n]*\\. { line_add (str_unescape (yytext, yyleng), 0); }
+ line_addz (str_unescape (yytext + 1, yyleng - 1)); }
+<STR>[^\\"\n]*\\. { line_addz (str_unescape (yytext, yyleng)); }
<STR>[^\\"\n]*\" { BEGIN(INITIAL);
if (yyleng > 1)
line_add (yytext, yyleng - 1);
@@ -303,7 +304,7 @@ text:-?\\?{IDENT}[ \t]*#.*\n { BEGIN(ML);
text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML);
multiline_begin (); }
<ML>#[ \t]*include.*\n { if (multiline_delimiter[0] == '\\')
- multiline_add (NULL);
+ multiline_add ();
else
sieve_include (); }
<ML>.*\n { char *p = multiline_strip_tabs (yytext);
@@ -318,7 +319,7 @@ text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML);
multiline_finish ();
return MULTILINE;
}
- multiline_add (NULL); }
+ multiline_add (); }
{WS} ;
/* Other tokens */
\n ;
@@ -527,19 +528,22 @@ multiline_strip_tabs (char *text)
}
static void
-line_add (char *text, size_t len)
+line_add (char const *text, size_t len)
{
- if (len == 0)
- len = strlen (text);
mu_opool_append (mu_sieve_machine->string_pool, text, len);
}
static void
-multiline_add (char *s)
+line_addz (char const *text)
{
- if (!s)
- s = multiline_strip_tabs (yytext);
- mu_opool_appendz (mu_sieve_machine->string_pool, s);
+ mu_opool_appendz (mu_sieve_machine->string_pool, text);
+}
+
+static void
+multiline_add (void)
+{
+ mu_opool_appendz (mu_sieve_machine->string_pool,
+ multiline_strip_tabs (yytext));
}
static void
diff --git a/libmu_sieve/variables.c b/libmu_sieve/variables.c
index 347457782..c73b7e8d0 100644
--- a/libmu_sieve/variables.c
+++ b/libmu_sieve/variables.c
@@ -284,13 +284,13 @@ sieve_test_string (mu_sieve_machine_t mach)
retrieve_string, fold_string, mach);
}
-mu_sieve_data_type string_args[] = {
+static mu_sieve_data_type string_args[] = {
SVT_STRING_LIST,
SVT_STRING_LIST,
SVT_VOID
};
-mu_sieve_tag_group_t string_tag_groups[] = {
+static mu_sieve_tag_group_t string_tag_groups[] = {
{ mu_sieve_match_part_tags, mu_sieve_match_part_checker },
{ NULL }
};
diff --git a/sieve/sieve.c b/sieve/sieve.c
index 483130709..edf3b754f 100644
--- a/sieve/sieve.c
+++ b/sieve/sieve.c
@@ -61,6 +61,21 @@ static int sieve_print_locus = 1; /* Should the log messages include the
locus */
static int no_program_name;
+static mu_list_t env_list;
+
+static int
+sieve_setenv (void *item, void *data)
+{
+ char *str = item;
+ mu_sieve_machine_t mach = data;
+ int rc = mu_sieve_set_environ (mach, str, str + strlen (str) + 1);
+ if (rc)
+ mu_error (_("can't set environment item %s: %s"),
+ str, mu_strerror (rc));
+ return 0;
+}
+
+
static void
modify_debug_flags (mu_debug_level_t set, mu_debug_level_t clr)
{
@@ -125,6 +140,27 @@ cli_email (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
mu_parseopt_error (po, _("invalid email: %s"), mu_strerror (rc));
}
+static void
+cli_env (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
+{
+ char *p = strchr (arg, '=');
+ if (p == NULL)
+ mu_parseopt_error (po, _("malformed environment setting: %s"), arg);
+ else
+ {
+ char *str;
+
+ str = mu_strdup (arg);
+ str[p - arg] = 0;
+ if (!env_list)
+ {
+ mu_list_create (&env_list);
+ mu_list_set_destroy_item (env_list, mu_list_free_item);
+ }
+ mu_list_append (env_list, str);
+ }
+}
+
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"),
@@ -163,6 +199,9 @@ static struct mu_option sieve_options[] = {
{ "no-program-name", 0, NULL, MU_OPTION_DEFAULT,
N_("do not prefix diagnostic messages with the program name"),
mu_c_int, &no_program_name },
+ { "environment", 0, N_("NAME=VALUE"), MU_OPTION_DEFAULT,
+ N_("set sieve environment value"),
+ mu_c_string, NULL, cli_env },
MU_OPTION_END
}, *options[] = { sieve_options, NULL };
@@ -445,7 +484,9 @@ main (int argc, char *argv[])
mu_error (_("cannot initialize sieve machine: %s"), mu_strerror (rc));
return EX_SOFTWARE;
}
-
+ mu_list_foreach (env_list, sieve_setenv, mach);
+ mu_list_destroy (&env_list);
+
if (verbose)
mu_sieve_set_logger (mach, _sieve_action_log);

Return to:

Send suggestions and report system problems to the System administrator.