Commit 57e0b979 57e0b97994f04b8d3f36ef3c45a99941b4f011bc by Sergey Poznyakoff

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
1 parent 44f87939
gint @ fd86bf7d
Subproject commit 42f4712085b40173eaea58e14b1a579291a6fe3a
Subproject commit fd86bf7d44b0c970771830692ae7491447ebe8b1
......
......@@ -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);
......
......@@ -31,6 +31,7 @@ libmu_sieve_la_SOURCES = \
conf.c\
comparator.c\
encoded.c\
environment.c\
load.c\
mem.c\
prog.c\
......
/* 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;
}
......@@ -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);
......
......@@ -108,6 +108,8 @@ 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 */
......
......@@ -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
......
......@@ -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 }
};
......
......@@ -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,6 +484,8 @@ 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);
......