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
Showing
9 changed files
with
299 additions
and
16 deletions
gint @ fd86bf7d
... | @@ -205,6 +205,8 @@ int mu_sieve_require_relational (mu_sieve_machine_t mach, const char *name); | ... | @@ -205,6 +205,8 @@ int mu_sieve_require_relational (mu_sieve_machine_t mach, const char *name); |
205 | int mu_sieve_require_variables (mu_sieve_machine_t mach); | 205 | int mu_sieve_require_variables (mu_sieve_machine_t mach); |
206 | int mu_sieve_has_variables (mu_sieve_machine_t mach); | 206 | int mu_sieve_has_variables (mu_sieve_machine_t mach); |
207 | 207 | ||
208 | int mu_sieve_require_environment (mu_sieve_machine_t mach); | ||
209 | |||
208 | void *mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name); | 210 | void *mu_sieve_load_ext (mu_sieve_machine_t mach, const char *name); |
209 | void mu_sieve_unload_ext (void *handle); | 211 | void mu_sieve_unload_ext (void *handle); |
210 | 212 | ||
... | @@ -292,6 +294,11 @@ void mu_sieve_set_daemon_email (mu_sieve_machine_t mach, const char *email); | ... | @@ -292,6 +294,11 @@ void mu_sieve_set_daemon_email (mu_sieve_machine_t mach, const char *email); |
292 | 294 | ||
293 | int mu_sieve_get_message_sender (mu_message_t msg, char **ptext); | 295 | int mu_sieve_get_message_sender (mu_message_t msg, char **ptext); |
294 | 296 | ||
297 | int mu_sieve_get_environ (mu_sieve_machine_t mach, char const *name, | ||
298 | char **retval); | ||
299 | int mu_sieve_set_environ (mu_sieve_machine_t mach, char const *name, | ||
300 | char const *value); | ||
301 | |||
295 | /* Stream state saving & restoring */ | 302 | /* Stream state saving & restoring */ |
296 | void mu_sieve_stream_save (mu_sieve_machine_t mach); | 303 | void mu_sieve_stream_save (mu_sieve_machine_t mach); |
297 | void mu_sieve_stream_restore (mu_sieve_machine_t mach); | 304 | void mu_sieve_stream_restore (mu_sieve_machine_t mach); | ... | ... |
libmu_sieve/environment.c
0 → 100644
1 | /* The Sieve "environment" extension for GNU Mailutils | ||
2 | Copyright (C) 2016 Free Software Foundation, Inc. | ||
3 | |||
4 | GNU Mailutils is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU Lesser General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Mailutils is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General Public | ||
15 | License along with GNU Mailutils. If not, see | ||
16 | <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | #ifdef HAVE_CONFIG_H | ||
19 | # include <config.h> | ||
20 | #endif | ||
21 | #include <sieve-priv.h> | ||
22 | |||
23 | int | ||
24 | retrieve_env (void *item, void *data, size_t idx, char **pval) | ||
25 | { | ||
26 | mu_sieve_machine_t mach; | ||
27 | |||
28 | if (idx) | ||
29 | return MU_ERR_NOENT; | ||
30 | mach = data; | ||
31 | return mu_sieve_get_environ (mach, item, pval); | ||
32 | } | ||
33 | |||
34 | static int | ||
35 | sieve_test_environment (mu_sieve_machine_t mach) | ||
36 | { | ||
37 | mu_sieve_value_t *name, *key_list; | ||
38 | |||
39 | name = mu_sieve_get_arg_untyped (mach, 0); | ||
40 | key_list = mu_sieve_get_arg_untyped (mach, 1); | ||
41 | |||
42 | return mu_sieve_vlist_compare (mach, name, key_list, retrieve_env, NULL, | ||
43 | mach); | ||
44 | } | ||
45 | |||
46 | static mu_sieve_data_type environ_args[] = { | ||
47 | SVT_STRING, | ||
48 | SVT_STRING_LIST, | ||
49 | SVT_VOID | ||
50 | }; | ||
51 | |||
52 | static mu_sieve_tag_group_t environ_tag_groups[] = { | ||
53 | { mu_sieve_match_part_tags, mu_sieve_match_part_checker }, | ||
54 | { NULL } | ||
55 | }; | ||
56 | |||
57 | int | ||
58 | mu_sieve_require_environment (mu_sieve_machine_t mach) | ||
59 | { | ||
60 | mu_sieve_register_test (mach, "environment", sieve_test_environment, | ||
61 | environ_args, environ_tag_groups, 1); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static char * | ||
66 | std_name_get (mu_sieve_machine_t mach) | ||
67 | { | ||
68 | return strdup (PACKAGE_NAME); | ||
69 | } | ||
70 | |||
71 | static char * | ||
72 | std_version_get (mu_sieve_machine_t mach) | ||
73 | { | ||
74 | return strdup (PACKAGE_VERSION); | ||
75 | } | ||
76 | |||
77 | /* "host" => The fully-qualified domain name of the host where | ||
78 | the Sieve script is executing. | ||
79 | */ | ||
80 | static char * | ||
81 | std_host_get (mu_sieve_machine_t mach) | ||
82 | { | ||
83 | char *host; | ||
84 | int rc; | ||
85 | |||
86 | rc = mu_get_host_name (&host); | ||
87 | if (rc == 0) | ||
88 | return host; | ||
89 | return NULL; | ||
90 | } | ||
91 | |||
92 | |||
93 | /* "domain" => The primary DNS domain associated with the Sieve | ||
94 | execution context, usually but not always a proper | ||
95 | suffix of the host name. | ||
96 | */ | ||
97 | static char * | ||
98 | std_domain_get (mu_sieve_machine_t mach) | ||
99 | { | ||
100 | char *host; | ||
101 | int rc; | ||
102 | |||
103 | rc = mu_get_host_name (&host); | ||
104 | if (rc == 0) | ||
105 | { | ||
106 | char *p = strchr (host, '.'); | ||
107 | if (p) | ||
108 | { | ||
109 | p = strdup (p + 1); | ||
110 | free (host); | ||
111 | return p; | ||
112 | } | ||
113 | return host; | ||
114 | } | ||
115 | return NULL; | ||
116 | } | ||
117 | |||
118 | /* FIXME: do we need set? If so, mu_set_host_name is also needed */ | ||
119 | |||
120 | struct stdenviron | ||
121 | { | ||
122 | char *name; | ||
123 | char *(*get) (mu_sieve_machine_t); | ||
124 | int (*set) (mu_sieve_machine_t, char const *, char const *value); | ||
125 | }; | ||
126 | |||
127 | static struct stdenviron stdenv[] = | ||
128 | { | ||
129 | { "domain", std_domain_get, NULL }, | ||
130 | { "host", std_host_get, NULL }, | ||
131 | { "name", std_name_get, NULL }, | ||
132 | { "version", std_version_get, NULL }, | ||
133 | { NULL } | ||
134 | }; | ||
135 | |||
136 | static struct stdenviron const * | ||
137 | stdenv_find (char const *name) | ||
138 | { | ||
139 | struct stdenviron const *p; | ||
140 | |||
141 | for (p = stdenv; p->name; p++) | ||
142 | if (strcmp (p->name, name) == 0) | ||
143 | return p; | ||
144 | return NULL; | ||
145 | } | ||
146 | |||
147 | static char * | ||
148 | stdenv_get (mu_sieve_machine_t mach, char const *name) | ||
149 | { | ||
150 | struct stdenviron const *p = stdenv_find (name); | ||
151 | if (!p) | ||
152 | return NULL; | ||
153 | return p->get (mach); | ||
154 | } | ||
155 | |||
156 | static int | ||
157 | stdenv_set (mu_sieve_machine_t mach, char const *name, char const *value) | ||
158 | { | ||
159 | struct stdenviron const *p = stdenv_find (name); | ||
160 | if (!p) | ||
161 | return MU_ERR_NOENT; | ||
162 | if (!p->set) | ||
163 | return EACCES; | ||
164 | return p->set (mach, name, value); | ||
165 | } | ||
166 | |||
167 | int | ||
168 | mu_sieve_get_environ (mu_sieve_machine_t mach, char const *name, char **retval) | ||
169 | { | ||
170 | char *p; | ||
171 | |||
172 | p = stdenv_get (mach, name); | ||
173 | if (p) | ||
174 | { | ||
175 | *retval = p; | ||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | if (!mach->exenv) | ||
180 | return MU_ERR_NOENT; | ||
181 | |||
182 | p = mu_assoc_ref (mach->exenv, name); | ||
183 | if (p) | ||
184 | { | ||
185 | *retval = strdup (*(char**)p); | ||
186 | if (!*retval) | ||
187 | return errno; | ||
188 | } | ||
189 | else | ||
190 | return MU_ERR_NOENT; | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | int | ||
195 | mu_sieve_set_environ (mu_sieve_machine_t mach, char const *name, | ||
196 | char const *value) | ||
197 | { | ||
198 | int rc; | ||
199 | |||
200 | rc = stdenv_set (mach, name, value); | ||
201 | if (rc == MU_ERR_NOENT) | ||
202 | { | ||
203 | char **pptr; | ||
204 | |||
205 | if (!mach->exenv) | ||
206 | { | ||
207 | int rc = mu_assoc_create (&mach->exenv, sizeof (char *), 0); | ||
208 | if (rc) | ||
209 | return rc; | ||
210 | } | ||
211 | rc = mu_assoc_ref_install (mach->exenv, name, (void **) &pptr); | ||
212 | if (rc == 0 || rc == MU_ERR_EXISTS) | ||
213 | { | ||
214 | char *copy = strdup (value); | ||
215 | if (!copy) | ||
216 | rc = errno; | ||
217 | else | ||
218 | { | ||
219 | *pptr = copy; | ||
220 | rc = 0; | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | return rc; | ||
225 | } | ||
226 |
... | @@ -43,6 +43,8 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list) | ... | @@ -43,6 +43,8 @@ mu_sieve_require (mu_sieve_machine_t mach, mu_sieve_slice_t list) |
43 | rc = mu_sieve_require_relational (mach, name); | 43 | rc = mu_sieve_require_relational (mach, name); |
44 | else if (strcmp (name, "encoded-character") == 0) /* RFC 5228, 2.4.2.4 */ | 44 | else if (strcmp (name, "encoded-character") == 0) /* RFC 5228, 2.4.2.4 */ |
45 | rc = mu_sieve_require_encoded_character (mach, name); | 45 | rc = mu_sieve_require_encoded_character (mach, name); |
46 | else if (strcmp (name, "environment") == 0) /* RFC 5183 */ | ||
47 | rc = mu_sieve_require_environment (mach); | ||
46 | else if (strncmp (name, "comparator-", 11) == 0) | 48 | else if (strncmp (name, "comparator-", 11) == 0) |
47 | rc = mu_sieve_registry_require (mach, name + 11, | 49 | rc = mu_sieve_registry_require (mach, name + 11, |
48 | mu_sieve_record_comparator); | 50 | mu_sieve_record_comparator); | ... | ... |
... | @@ -108,6 +108,8 @@ struct mu_sieve_machine | ... | @@ -108,6 +108,8 @@ struct mu_sieve_machine |
108 | int dry_run; /* Dry-run mode */ | 108 | int dry_run; /* Dry-run mode */ |
109 | jmp_buf errbuf; /* Target location for non-local exits */ | 109 | jmp_buf errbuf; /* Target location for non-local exits */ |
110 | 110 | ||
111 | mu_assoc_t exenv; /* Execution environment (RFC 5183) */ | ||
112 | |||
111 | mu_mailbox_t mailbox; /* Mailbox to operate upon */ | 113 | mu_mailbox_t mailbox; /* Mailbox to operate upon */ |
112 | size_t msgno; /* Current message number */ | 114 | size_t msgno; /* Current message number */ |
113 | mu_message_t msg; /* Current message */ | 115 | mu_message_t msg; /* Current message */ | ... | ... |
... | @@ -41,10 +41,11 @@ static int strip_tabs; | ... | @@ -41,10 +41,11 @@ static int strip_tabs; |
41 | static int number (void); | 41 | static int number (void); |
42 | static int string (void); | 42 | static int string (void); |
43 | static void line_begin (void); | 43 | static void line_begin (void); |
44 | static void line_add (char *text, size_t len); | 44 | static void line_add (char const *text, size_t len); |
45 | static void line_addz (char const *text); | ||
45 | static void line_finish (void); | 46 | static void line_finish (void); |
46 | static void multiline_begin (void); | 47 | static void multiline_begin (void); |
47 | static void multiline_add (char *); | 48 | static void multiline_add (void); |
48 | static void multiline_finish (void); | 49 | static void multiline_finish (void); |
49 | static char *multiline_strip_tabs (char *text); | 50 | static char *multiline_strip_tabs (char *text); |
50 | static void ident (const char *text); | 51 | static void ident (const char *text); |
... | @@ -286,8 +287,8 @@ true return TRUE; | ... | @@ -286,8 +287,8 @@ true return TRUE; |
286 | \"[^\\"\n]*\" { return string (); } | 287 | \"[^\\"\n]*\" { return string (); } |
287 | \"[^\\"\n]*\\. { BEGIN(STR); | 288 | \"[^\\"\n]*\\. { BEGIN(STR); |
288 | line_begin (); | 289 | line_begin (); |
289 | line_add (str_unescape (yytext + 1, yyleng - 1), 0); } | 290 | line_addz (str_unescape (yytext + 1, yyleng - 1)); } |
290 | <STR>[^\\"\n]*\\. { line_add (str_unescape (yytext, yyleng), 0); } | 291 | <STR>[^\\"\n]*\\. { line_addz (str_unescape (yytext, yyleng)); } |
291 | <STR>[^\\"\n]*\" { BEGIN(INITIAL); | 292 | <STR>[^\\"\n]*\" { BEGIN(INITIAL); |
292 | if (yyleng > 1) | 293 | if (yyleng > 1) |
293 | line_add (yytext, yyleng - 1); | 294 | line_add (yytext, yyleng - 1); |
... | @@ -303,7 +304,7 @@ text:-?\\?{IDENT}[ \t]*#.*\n { BEGIN(ML); | ... | @@ -303,7 +304,7 @@ text:-?\\?{IDENT}[ \t]*#.*\n { BEGIN(ML); |
303 | text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML); | 304 | text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML); |
304 | multiline_begin (); } | 305 | multiline_begin (); } |
305 | <ML>#[ \t]*include.*\n { if (multiline_delimiter[0] == '\\') | 306 | <ML>#[ \t]*include.*\n { if (multiline_delimiter[0] == '\\') |
306 | multiline_add (NULL); | 307 | multiline_add (); |
307 | else | 308 | else |
308 | sieve_include (); } | 309 | sieve_include (); } |
309 | <ML>.*\n { char *p = multiline_strip_tabs (yytext); | 310 | <ML>.*\n { char *p = multiline_strip_tabs (yytext); |
... | @@ -318,7 +319,7 @@ text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML); | ... | @@ -318,7 +319,7 @@ text:-?\\?{IDENT}[ \t]*\n { BEGIN(ML); |
318 | multiline_finish (); | 319 | multiline_finish (); |
319 | return MULTILINE; | 320 | return MULTILINE; |
320 | } | 321 | } |
321 | multiline_add (NULL); } | 322 | multiline_add (); } |
322 | {WS} ; | 323 | {WS} ; |
323 | /* Other tokens */ | 324 | /* Other tokens */ |
324 | \n ; | 325 | \n ; |
... | @@ -527,19 +528,22 @@ multiline_strip_tabs (char *text) | ... | @@ -527,19 +528,22 @@ multiline_strip_tabs (char *text) |
527 | } | 528 | } |
528 | 529 | ||
529 | static void | 530 | static void |
530 | line_add (char *text, size_t len) | 531 | line_add (char const *text, size_t len) |
531 | { | 532 | { |
532 | if (len == 0) | ||
533 | len = strlen (text); | ||
534 | mu_opool_append (mu_sieve_machine->string_pool, text, len); | 533 | mu_opool_append (mu_sieve_machine->string_pool, text, len); |
535 | } | 534 | } |
536 | 535 | ||
537 | static void | 536 | static void |
538 | multiline_add (char *s) | 537 | line_addz (char const *text) |
539 | { | 538 | { |
540 | if (!s) | 539 | mu_opool_appendz (mu_sieve_machine->string_pool, text); |
541 | s = multiline_strip_tabs (yytext); | 540 | } |
542 | mu_opool_appendz (mu_sieve_machine->string_pool, s); | 541 | |
542 | static void | ||
543 | multiline_add (void) | ||
544 | { | ||
545 | mu_opool_appendz (mu_sieve_machine->string_pool, | ||
546 | multiline_strip_tabs (yytext)); | ||
543 | } | 547 | } |
544 | 548 | ||
545 | static void | 549 | static void | ... | ... |
... | @@ -284,13 +284,13 @@ sieve_test_string (mu_sieve_machine_t mach) | ... | @@ -284,13 +284,13 @@ sieve_test_string (mu_sieve_machine_t mach) |
284 | retrieve_string, fold_string, mach); | 284 | retrieve_string, fold_string, mach); |
285 | } | 285 | } |
286 | 286 | ||
287 | mu_sieve_data_type string_args[] = { | 287 | static mu_sieve_data_type string_args[] = { |
288 | SVT_STRING_LIST, | 288 | SVT_STRING_LIST, |
289 | SVT_STRING_LIST, | 289 | SVT_STRING_LIST, |
290 | SVT_VOID | 290 | SVT_VOID |
291 | }; | 291 | }; |
292 | 292 | ||
293 | mu_sieve_tag_group_t string_tag_groups[] = { | 293 | static mu_sieve_tag_group_t string_tag_groups[] = { |
294 | { mu_sieve_match_part_tags, mu_sieve_match_part_checker }, | 294 | { mu_sieve_match_part_tags, mu_sieve_match_part_checker }, |
295 | { NULL } | 295 | { NULL } |
296 | }; | 296 | }; | ... | ... |
... | @@ -61,6 +61,21 @@ static int sieve_print_locus = 1; /* Should the log messages include the | ... | @@ -61,6 +61,21 @@ static int sieve_print_locus = 1; /* Should the log messages include the |
61 | locus */ | 61 | locus */ |
62 | static int no_program_name; | 62 | static int no_program_name; |
63 | 63 | ||
64 | static mu_list_t env_list; | ||
65 | |||
66 | static int | ||
67 | sieve_setenv (void *item, void *data) | ||
68 | { | ||
69 | char *str = item; | ||
70 | mu_sieve_machine_t mach = data; | ||
71 | int rc = mu_sieve_set_environ (mach, str, str + strlen (str) + 1); | ||
72 | if (rc) | ||
73 | mu_error (_("can't set environment item %s: %s"), | ||
74 | str, mu_strerror (rc)); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | |||
64 | static void | 79 | static void |
65 | modify_debug_flags (mu_debug_level_t set, mu_debug_level_t clr) | 80 | modify_debug_flags (mu_debug_level_t set, mu_debug_level_t clr) |
66 | { | 81 | { |
... | @@ -125,6 +140,27 @@ cli_email (struct mu_parseopt *po, struct mu_option *opt, char const *arg) | ... | @@ -125,6 +140,27 @@ cli_email (struct mu_parseopt *po, struct mu_option *opt, char const *arg) |
125 | mu_parseopt_error (po, _("invalid email: %s"), mu_strerror (rc)); | 140 | mu_parseopt_error (po, _("invalid email: %s"), mu_strerror (rc)); |
126 | } | 141 | } |
127 | 142 | ||
143 | static void | ||
144 | cli_env (struct mu_parseopt *po, struct mu_option *opt, char const *arg) | ||
145 | { | ||
146 | char *p = strchr (arg, '='); | ||
147 | if (p == NULL) | ||
148 | mu_parseopt_error (po, _("malformed environment setting: %s"), arg); | ||
149 | else | ||
150 | { | ||
151 | char *str; | ||
152 | |||
153 | str = mu_strdup (arg); | ||
154 | str[p - arg] = 0; | ||
155 | if (!env_list) | ||
156 | { | ||
157 | mu_list_create (&env_list); | ||
158 | mu_list_set_destroy_item (env_list, mu_list_free_item); | ||
159 | } | ||
160 | mu_list_append (env_list, str); | ||
161 | } | ||
162 | } | ||
163 | |||
128 | static struct mu_option sieve_options[] = { | 164 | static struct mu_option sieve_options[] = { |
129 | { "dry-run", 'n', NULL, MU_OPTION_DEFAULT, | 165 | { "dry-run", 'n', NULL, MU_OPTION_DEFAULT, |
130 | N_("do not execute any actions, just print what would be done"), | 166 | N_("do not execute any actions, just print what would be done"), |
... | @@ -163,6 +199,9 @@ static struct mu_option sieve_options[] = { | ... | @@ -163,6 +199,9 @@ static struct mu_option sieve_options[] = { |
163 | { "no-program-name", 0, NULL, MU_OPTION_DEFAULT, | 199 | { "no-program-name", 0, NULL, MU_OPTION_DEFAULT, |
164 | N_("do not prefix diagnostic messages with the program name"), | 200 | N_("do not prefix diagnostic messages with the program name"), |
165 | mu_c_int, &no_program_name }, | 201 | mu_c_int, &no_program_name }, |
202 | { "environment", 0, N_("NAME=VALUE"), MU_OPTION_DEFAULT, | ||
203 | N_("set sieve environment value"), | ||
204 | mu_c_string, NULL, cli_env }, | ||
166 | MU_OPTION_END | 205 | MU_OPTION_END |
167 | }, *options[] = { sieve_options, NULL }; | 206 | }, *options[] = { sieve_options, NULL }; |
168 | 207 | ||
... | @@ -445,6 +484,8 @@ main (int argc, char *argv[]) | ... | @@ -445,6 +484,8 @@ main (int argc, char *argv[]) |
445 | mu_error (_("cannot initialize sieve machine: %s"), mu_strerror (rc)); | 484 | mu_error (_("cannot initialize sieve machine: %s"), mu_strerror (rc)); |
446 | return EX_SOFTWARE; | 485 | return EX_SOFTWARE; |
447 | } | 486 | } |
487 | mu_list_foreach (env_list, sieve_setenv, mach); | ||
488 | mu_list_destroy (&env_list); | ||
448 | 489 | ||
449 | if (verbose) | 490 | if (verbose) |
450 | mu_sieve_set_logger (mach, _sieve_action_log); | 491 | mu_sieve_set_logger (mach, _sieve_action_log); | ... | ... |
-
Please register or sign in to post a comment