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
1 Subproject commit 42f4712085b40173eaea58e14b1a579291a6fe3a 1 Subproject commit fd86bf7d44b0c970771830692ae7491447ebe8b1
......
...@@ -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);
......
...@@ -31,6 +31,7 @@ libmu_sieve_la_SOURCES = \ ...@@ -31,6 +31,7 @@ libmu_sieve_la_SOURCES = \
31 conf.c\ 31 conf.c\
32 comparator.c\ 32 comparator.c\
33 encoded.c\ 33 encoded.c\
34 environment.c\
34 load.c\ 35 load.c\
35 mem.c\ 36 mem.c\
36 prog.c\ 37 prog.c\
......
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);
......
...@@ -107,7 +107,9 @@ struct mu_sieve_machine ...@@ -107,7 +107,9 @@ struct mu_sieve_machine
107 107
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,7 +484,9 @@ main (int argc, char *argv[]) ...@@ -445,7 +484,9 @@ 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 }
448 487 mu_list_foreach (env_list, sieve_setenv, mach);
488 mu_list_destroy (&env_list);
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);
451 492
......