diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-12-11 18:10:47 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2016-12-11 18:10:47 +0200 |
commit | 57e0b97994f04b8d3f36ef3c45a99941b4f011bc (patch) | |
tree | 58a1de1ec129d4ebf98b95fa59715c30cc7289b8 | |
parent | 44f87939efa0a33e8d1f26b9d9fa3e15c32d808a (diff) | |
download | mailutils-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--------- | gint | 0 | ||||
-rw-r--r-- | include/mailutils/sieve.h | 7 | ||||
-rw-r--r-- | libmu_sieve/Makefile.am | 1 | ||||
-rw-r--r-- | libmu_sieve/environment.c | 226 | ||||
-rw-r--r-- | libmu_sieve/require.c | 2 | ||||
-rw-r--r-- | libmu_sieve/sieve-priv.h | 4 | ||||
-rw-r--r-- | libmu_sieve/sieve.l | 30 | ||||
-rw-r--r-- | libmu_sieve/variables.c | 4 | ||||
-rw-r--r-- | sieve/sieve.c | 43 |
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); |