1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2 */
3
4 #include "lib.h"
5 #include "str.h"
6 #include "str-sanitize.h"
7
8 #include "rfc2822.h"
9
10 #include "sieve-common.h"
11 #include "sieve-ast.h"
12 #include "sieve-validator.h"
13 #include "sieve-generator.h"
14 #include "sieve-binary.h"
15 #include "sieve-commands.h"
16 #include "sieve-code.h"
17 #include "sieve-interpreter.h"
18
19 /*
20 * Literal arguments
21 */
22
23 /* Forward declarations */
24
25 static bool arg_number_generate
26 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
27 struct sieve_command *context);
28 static bool arg_string_generate
29 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
30 struct sieve_command *context);
31 static bool arg_string_list_validate
32 (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
33 struct sieve_command *context);
34 static bool arg_string_list_generate
35 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
36 struct sieve_command *context);
37
38 /* Argument objects */
39
40 const struct sieve_argument_def number_argument = {
41 .identifier = "@number",
42 .generate = arg_number_generate
43 };
44
45 const struct sieve_argument_def string_argument = {
46 .identifier = "@string",
47 .generate = arg_string_generate
48 };
49
50 const struct sieve_argument_def string_list_argument = {
51 .identifier = "@string-list",
52 .validate = arg_string_list_validate,
53 .generate = arg_string_list_generate
54 };
55
56 /* Argument implementations */
57
arg_number_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * cmd ATTR_UNUSED)58 static bool arg_number_generate
59 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
60 struct sieve_command *cmd ATTR_UNUSED)
61 {
62 sieve_opr_number_emit(cgenv->sblock, sieve_ast_argument_number(arg));
63
64 return TRUE;
65 }
66
arg_string_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * cmd ATTR_UNUSED)67 static bool arg_string_generate
68 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
69 struct sieve_command *cmd ATTR_UNUSED)
70 {
71 sieve_opr_string_emit(cgenv->sblock, sieve_ast_argument_str(arg));
72
73 return TRUE;
74 }
75
arg_string_list_validate(struct sieve_validator * valdtr,struct sieve_ast_argument ** arg,struct sieve_command * cmd)76 static bool arg_string_list_validate
77 (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
78 struct sieve_command *cmd)
79 {
80 struct sieve_ast_argument *stritem;
81
82 stritem = sieve_ast_strlist_first(*arg);
83 while ( stritem != NULL ) {
84 if ( !sieve_validator_argument_activate(valdtr, cmd, stritem, FALSE) )
85 return FALSE;
86
87 stritem = sieve_ast_strlist_next(stritem);
88 }
89
90 return TRUE;
91 }
92
emit_string_list_operand(const struct sieve_codegen_env * cgenv,const struct sieve_ast_argument * strlist,struct sieve_command * cmd)93 static bool emit_string_list_operand
94 (const struct sieve_codegen_env *cgenv, const struct sieve_ast_argument *strlist,
95 struct sieve_command *cmd)
96 {
97 void *list_context;
98 struct sieve_ast_argument *stritem;
99
100 sieve_opr_stringlist_emit_start
101 (cgenv->sblock, sieve_ast_strlist_count(strlist), &list_context);
102
103 stritem = sieve_ast_strlist_first(strlist);
104 while ( stritem != NULL ) {
105 if ( !sieve_generate_argument(cgenv, stritem, cmd) )
106 return FALSE;
107
108 stritem = sieve_ast_strlist_next(stritem);
109 }
110
111 sieve_opr_stringlist_emit_end(cgenv->sblock, list_context);
112
113 return TRUE;
114 }
115
arg_string_list_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * cmd)116 static bool arg_string_list_generate
117 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
118 struct sieve_command *cmd)
119 {
120 if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
121 return ( sieve_generate_argument(cgenv, arg, cmd) );
122
123 } else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
124 bool result = TRUE;
125
126 if ( sieve_ast_strlist_count(arg) == 1 )
127 return ( sieve_generate_argument
128 (cgenv, sieve_ast_strlist_first(arg), cmd) );
129 else {
130 T_BEGIN {
131 result=emit_string_list_operand(cgenv, arg, cmd);
132 } T_END;
133 }
134
135 return result;
136 }
137
138 return FALSE;
139 }
140
141 /*
142 * Abstract arguments
143 *
144 * (Generated by processing and not by parsing the grammar)
145 */
146
147 /* Catenated string */
148
149 struct sieve_arg_catenated_string {
150 struct sieve_ast_arg_list *str_parts;
151 };
152
sieve_arg_catenated_string_create(struct sieve_ast_argument * orig_arg)153 struct sieve_arg_catenated_string *sieve_arg_catenated_string_create
154 (struct sieve_ast_argument *orig_arg)
155 {
156 pool_t pool = sieve_ast_pool(orig_arg->ast);
157 struct sieve_ast_arg_list *arglist;
158 struct sieve_arg_catenated_string *catstr;
159
160 arglist = sieve_ast_arg_list_create(pool);
161
162 catstr = p_new(pool, struct sieve_arg_catenated_string, 1);
163 catstr->str_parts = arglist;
164 (orig_arg)->argument->data = (void *) catstr;
165
166 return catstr;
167 }
168
sieve_arg_catenated_string_add_element(struct sieve_arg_catenated_string * catstr,struct sieve_ast_argument * element)169 void sieve_arg_catenated_string_add_element
170 (struct sieve_arg_catenated_string *catstr,
171 struct sieve_ast_argument *element)
172 {
173 sieve_ast_arg_list_add(catstr->str_parts, element);
174 }
175
176 #define _cat_string_first(catstr) __AST_LIST_FIRST((catstr)->str_parts)
177 #define _cat_string_count(catstr) __AST_LIST_COUNT((catstr)->str_parts)
178 #define _cat_string_next(item) __AST_LIST_NEXT(item)
179
sieve_arg_catenated_string_generate(const struct sieve_codegen_env * cgenv,struct sieve_ast_argument * arg,struct sieve_command * cmd)180 bool sieve_arg_catenated_string_generate
181 (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg,
182 struct sieve_command *cmd)
183 {
184 struct sieve_arg_catenated_string *catstr =
185 (struct sieve_arg_catenated_string *) arg->argument->data;
186 struct sieve_ast_argument *strpart;
187
188 if ( _cat_string_count(catstr) == 1 )
189 sieve_generate_argument(cgenv, _cat_string_first(catstr), cmd);
190 else {
191 sieve_opr_catenated_string_emit(cgenv->sblock, _cat_string_count(catstr));
192
193 strpart = _cat_string_first(catstr);
194 while ( strpart != NULL ) {
195 if ( !sieve_generate_argument(cgenv, strpart, cmd) )
196 return FALSE;
197
198 strpart = _cat_string_next(strpart);
199 }
200 }
201
202 return TRUE;
203 }
204
205 /*
206 * Argument creation
207 */
208
sieve_argument_create(struct sieve_ast * ast,const struct sieve_argument_def * def,const struct sieve_extension * ext,int id_code)209 struct sieve_argument *sieve_argument_create
210 (struct sieve_ast *ast, const struct sieve_argument_def *def,
211 const struct sieve_extension *ext, int id_code)
212 {
213 struct sieve_argument *arg;
214 pool_t pool;
215
216 pool = sieve_ast_pool(ast);
217 arg = p_new(pool, struct sieve_argument, 1);
218 arg->def = def;
219 arg->ext = ext;
220 arg->id_code = id_code;
221
222 return arg;
223 }
224
225 /*
226 * Core tests and commands
227 */
228
229 const struct sieve_command_def *sieve_core_tests[] = {
230 &tst_false, &tst_true,
231 &tst_not, &tst_anyof, &tst_allof,
232 &tst_address, &tst_header, &tst_exists, &tst_size
233 };
234
235 const unsigned int sieve_core_tests_count = N_ELEMENTS(sieve_core_tests);
236
237 const struct sieve_command_def *sieve_core_commands[] = {
238 &cmd_require,
239 &cmd_stop, &cmd_if, &cmd_elsif, &cmd_else,
240 &cmd_keep, &cmd_discard, &cmd_redirect
241 };
242
243 const unsigned int sieve_core_commands_count = N_ELEMENTS(sieve_core_commands);
244
245 /*
246 * Command context
247 */
248
sieve_command_prev(struct sieve_command * cmd)249 struct sieve_command *sieve_command_prev
250 (struct sieve_command *cmd)
251 {
252 struct sieve_ast_node *node = sieve_ast_node_prev(cmd->ast_node);
253
254 if ( node != NULL ) {
255 return node->command;
256 }
257
258 return NULL;
259 }
260
sieve_command_parent(struct sieve_command * cmd)261 struct sieve_command *sieve_command_parent
262 (struct sieve_command *cmd)
263 {
264 struct sieve_ast_node *node = sieve_ast_node_parent(cmd->ast_node);
265
266 return ( node != NULL ? node->command : NULL );
267 }
268
sieve_command_create(struct sieve_ast_node * cmd_node,const struct sieve_extension * ext,const struct sieve_command_def * cmd_def,struct sieve_command_registration * cmd_reg)269 struct sieve_command *sieve_command_create
270 (struct sieve_ast_node *cmd_node, const struct sieve_extension *ext,
271 const struct sieve_command_def *cmd_def,
272 struct sieve_command_registration *cmd_reg)
273 {
274 struct sieve_command *cmd;
275
276 cmd = p_new(sieve_ast_node_pool(cmd_node), struct sieve_command, 1);
277
278 cmd->ast_node = cmd_node;
279 cmd->def = cmd_def;
280 cmd->ext = ext;
281 cmd->reg = cmd_reg;
282
283 cmd->block_exit_command = NULL;
284
285 return cmd;
286 }
287
sieve_command_def_type_name(const struct sieve_command_def * cmd_def)288 const char *sieve_command_def_type_name
289 (const struct sieve_command_def *cmd_def)
290 {
291 switch ( cmd_def->type ) {
292 case SCT_NONE: return "command of unspecified type (bug)";
293 case SCT_TEST: return "test";
294 case SCT_COMMAND: return "command";
295 case SCT_HYBRID: return "command or test";
296 default:
297 break;
298 }
299 return "??COMMAND-TYPE??";
300 }
301
sieve_command_type_name(const struct sieve_command * cmd)302 const char *sieve_command_type_name
303 (const struct sieve_command *cmd)
304 {
305 switch ( cmd->def->type ) {
306 case SCT_NONE: return "command of unspecified type (bug)";
307 case SCT_TEST: return "test";
308 case SCT_COMMAND: return "command";
309 case SCT_HYBRID:
310 if ( cmd->ast_node->type == SAT_TEST )
311 return "test";
312 return "command";
313 default:
314 break;
315 }
316 return "??COMMAND-TYPE??";
317 }
318
sieve_command_add_dynamic_tag(struct sieve_command * cmd,const struct sieve_extension * ext,const struct sieve_argument_def * tag,int id_code)319 struct sieve_ast_argument *sieve_command_add_dynamic_tag
320 (struct sieve_command *cmd, const struct sieve_extension *ext,
321 const struct sieve_argument_def *tag, int id_code)
322 {
323 struct sieve_ast_argument *arg;
324
325 if ( cmd->first_positional != NULL )
326 arg = sieve_ast_argument_tag_insert
327 (cmd->first_positional, tag->identifier, cmd->ast_node->source_line);
328 else
329 arg = sieve_ast_argument_tag_create
330 (cmd->ast_node, tag->identifier, cmd->ast_node->source_line);
331
332 arg->argument = sieve_argument_create(cmd->ast_node->ast, tag, ext, id_code);
333
334 return arg;
335 }
336
sieve_command_find_argument(struct sieve_command * cmd,const struct sieve_argument_def * arg_def)337 struct sieve_ast_argument *sieve_command_find_argument
338 (struct sieve_command *cmd, const struct sieve_argument_def *arg_def)
339 {
340 struct sieve_ast_argument *arg = sieve_ast_argument_first(cmd->ast_node);
341
342 /* Visit tagged and optional arguments */
343 while ( arg != NULL ) {
344 if ( arg->argument != NULL && arg->argument->def == arg_def )
345 return arg;
346
347 arg = sieve_ast_argument_next(arg);
348 }
349
350 return arg;
351 }
352
353 /* Use this function with caution. The command commits to exiting the block.
354 * When it for some reason does not, the interpretation will break later on,
355 * because exiting jumps are not generated when they would otherwise be
356 * necessary.
357 */
sieve_command_exit_block_unconditionally(struct sieve_command * cmd)358 void sieve_command_exit_block_unconditionally
359 (struct sieve_command *cmd)
360 {
361 struct sieve_command *parent = sieve_command_parent(cmd);
362
363 /* Only the first unconditional exit is of importance */
364 if ( parent != NULL && parent->block_exit_command == NULL )
365 parent->block_exit_command = cmd;
366 }
367
sieve_command_block_exits_unconditionally(struct sieve_command * cmd)368 bool sieve_command_block_exits_unconditionally
369 (struct sieve_command *cmd)
370 {
371 return ( cmd->block_exit_command != NULL );
372 }
373
374 /*
375 * Command utility functions
376 */
377
378 /* NOTE: this may be moved */
379
_verify_header_name_item(void * context,struct sieve_ast_argument * header)380 static int _verify_header_name_item
381 (void *context, struct sieve_ast_argument *header)
382 {
383 struct sieve_validator *valdtr = (struct sieve_validator *) context;
384 string_t *name = sieve_ast_argument_str(header);
385
386 if ( sieve_argument_is_string_literal(header) &&
387 !rfc2822_header_field_name_verify(str_c(name), str_len(name)) ) {
388 sieve_argument_validate_warning
389 (valdtr, header, "specified header field name '%s' is invalid",
390 str_sanitize(str_c(name), 80));
391
392 return 0;
393 }
394
395 return 1;
396 }
397
sieve_command_verify_headers_argument(struct sieve_validator * valdtr,struct sieve_ast_argument * headers)398 bool sieve_command_verify_headers_argument
399 (struct sieve_validator *valdtr, struct sieve_ast_argument *headers)
400 {
401 return ( sieve_ast_stringlist_map
402 (&headers, (void *) valdtr, _verify_header_name_item) >= 0 );
403 }
404