1 /* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2  */
3 
4 #include "lib.h"
5 #include "str.h"
6 #include "mempool.h"
7 #include "array.h"
8 
9 #include "sieve-common.h"
10 #include "sieve-script.h"
11 #include "sieve-extensions.h"
12 
13 #include "sieve-ast.h"
14 
15 #include <stdio.h>
16 
17 /*
18  * Forward declarations
19  */
20 
21 static struct sieve_ast_node *
22 sieve_ast_node_create(struct sieve_ast *ast, struct sieve_ast_node *parent,
23 		      enum sieve_ast_type type, unsigned int source_line);
24 
25 /*
26  * Types
27  */
28 
29 /* Extensions to the AST */
30 
31 struct sieve_ast_extension_reg {
32 	const struct sieve_extension *ext;
33 	const struct sieve_ast_extension *ast_ext;
34 	void *context;
35 
36 	bool required:1;
37 };
38 
39 /*
40  * AST object
41  */
42 
43 struct sieve_ast {
44 	pool_t pool;
45 	int refcount;
46 
47 	struct sieve_instance *svinst;
48 
49 	struct sieve_script *script;
50 
51 	struct sieve_ast_node *root;
52 
53 	ARRAY(const struct sieve_extension *) linked_extensions;
54 	ARRAY(struct sieve_ast_extension_reg) extensions;
55 };
56 
sieve_ast_create(struct sieve_script * script)57 struct sieve_ast *sieve_ast_create(struct sieve_script *script)
58 {
59 	pool_t pool;
60 	struct sieve_ast *ast;
61 	unsigned int ext_count;
62 
63 	pool = pool_alloconly_create("sieve_ast", 32768);
64 	ast = p_new(pool, struct sieve_ast, 1);
65 	ast->pool = pool;
66 	ast->refcount = 1;
67 
68 	ast->script = script;
69 	sieve_script_ref(script);
70 	ast->svinst = sieve_script_svinst(script);
71 
72 	ast->root = sieve_ast_node_create(ast, NULL, SAT_ROOT, 0);
73 	ast->root->identifier = "ROOT";
74 
75 	ext_count = sieve_extensions_get_count(ast->svinst);
76 	p_array_init(&ast->linked_extensions, pool, ext_count);
77 	p_array_init(&ast->extensions, pool, ext_count);
78 
79 	return ast;
80 }
81 
sieve_ast_ref(struct sieve_ast * ast)82 void sieve_ast_ref(struct sieve_ast *ast)
83 {
84 	ast->refcount++;
85 }
86 
sieve_ast_unref(struct sieve_ast ** ast)87 void sieve_ast_unref(struct sieve_ast **ast)
88 {
89 	unsigned int i, ext_count;
90 	const struct sieve_ast_extension_reg *extrs;
91 
92 	i_assert((*ast)->refcount > 0);
93 
94 	if (--(*ast)->refcount != 0)
95 		return;
96 
97 	/* Release script reference */
98 	sieve_script_unref(&(*ast)->script);
99 
100 	/* Signal registered extensions that the AST is being destroyed */
101 	extrs = array_get(&(*ast)->extensions, &ext_count);
102 	for (i = 0; i < ext_count; i++) {
103 		if (extrs[i].ast_ext != NULL &&	extrs[i].ast_ext->free != NULL)
104 			extrs[i].ast_ext->free(extrs[i].ext, *ast,
105 					       extrs[i].context);
106 	}
107 
108 	/* Destroy AST */
109 	pool_unref(&(*ast)->pool);
110 
111 	*ast = NULL;
112 }
113 
sieve_ast_root(struct sieve_ast * ast)114 struct sieve_ast_node *sieve_ast_root(struct sieve_ast *ast)
115 {
116 	return ast->root;
117 }
118 
sieve_ast_pool(struct sieve_ast * ast)119 pool_t sieve_ast_pool(struct sieve_ast *ast)
120 {
121 	return ast->pool;
122 }
123 
sieve_ast_script(struct sieve_ast * ast)124 struct sieve_script *sieve_ast_script(struct sieve_ast *ast)
125 {
126 	return ast->script;
127 }
128 
129 /*
130  * Extension support
131  */
132 
sieve_ast_extension_link(struct sieve_ast * ast,const struct sieve_extension * ext,bool required)133 void sieve_ast_extension_link(struct sieve_ast *ast,
134 			      const struct sieve_extension *ext, bool required)
135 {
136 	unsigned int i, ext_count;
137 	const struct sieve_extension *const *extensions;
138 	struct sieve_ast_extension_reg *reg;
139 
140 	if (ext->id < 0)
141 		return;
142 
143 	/* Initialize registration */
144 	reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id);
145 	i_assert(reg->ext == NULL || reg->ext == ext);
146 	reg->ext = ext;
147 	reg->required = reg->required || required;
148 
149 	/* Prevent duplicates */
150 	extensions = array_get(&ast->linked_extensions, &ext_count);
151 	for (i = 0; i < ext_count; i++) {
152 		if (extensions[i] == ext)
153 			return;
154 	}
155 
156 	/* Add extension */
157 	array_append(&ast->linked_extensions, &ext, 1);
158 }
159 
160 const struct sieve_extension * const *
sieve_ast_extensions_get(struct sieve_ast * ast,unsigned int * count_r)161 sieve_ast_extensions_get(struct sieve_ast *ast, unsigned int *count_r)
162 {
163 	return array_get(&ast->linked_extensions, count_r);
164 }
165 
sieve_ast_extension_register(struct sieve_ast * ast,const struct sieve_extension * ext,const struct sieve_ast_extension * ast_ext,void * context)166 void sieve_ast_extension_register(struct sieve_ast *ast,
167 				  const struct sieve_extension *ext,
168 				  const struct sieve_ast_extension *ast_ext,
169 				  void *context)
170 {
171 	struct sieve_ast_extension_reg *reg;
172 
173 	if (ext->id < 0)
174 		return;
175 
176 	/* Initialize registration */
177 	reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id);
178 	i_assert(reg->ext == NULL || reg->ext == ext);
179 	reg->ext = ext;
180 	reg->ast_ext = ast_ext;
181 	reg->context = context;
182 }
183 
sieve_ast_extension_set_context(struct sieve_ast * ast,const struct sieve_extension * ext,void * context)184 void sieve_ast_extension_set_context(struct sieve_ast *ast,
185 				     const struct sieve_extension *ext,
186 				     void *context)
187 {
188 	struct sieve_ast_extension_reg *reg;
189 
190 	if (ext->id < 0)
191 		return;
192 
193 	reg = array_idx_get_space(&ast->extensions, (unsigned int)ext->id);
194 	reg->context = context;
195 }
196 
sieve_ast_extension_get_context(struct sieve_ast * ast,const struct sieve_extension * ext)197 void *sieve_ast_extension_get_context(struct sieve_ast *ast,
198 				      const struct sieve_extension *ext)
199 {
200 	const struct sieve_ast_extension_reg *reg;
201 
202 	if  (ext->id < 0 || ext->id >= (int)array_count(&ast->extensions))
203 		return NULL;
204 
205 	reg = array_idx(&ast->extensions, (unsigned int)ext->id);
206 
207 	return reg->context;
208 }
209 
sieve_ast_extension_is_required(struct sieve_ast * ast,const struct sieve_extension * ext)210 bool sieve_ast_extension_is_required
211 (struct sieve_ast *ast, const struct sieve_extension *ext)
212 {
213 	const struct sieve_ast_extension_reg *reg;
214 
215 	i_assert(ext->id >= 0 &&
216 		 ext->id < (int)array_count(&ast->extensions));
217 
218 	reg = array_idx(&ast->extensions, (unsigned int)ext->id);
219 	return reg->required;
220 }
221 
222 /*
223  * AST list implementations
224  */
225 
226 /* Very simplistic linked list implementation
227    FIXME: Merge with core
228  */
229 #define __LIST_CREATE(pool, type) { \
230 		type *list = p_new(pool, type, 1); \
231 		list->head = NULL; \
232 		list->tail = NULL; \
233 		list->len = 0; \
234 		return list; \
235 	}
236 
237 #define __LIST_ADD(list, node) { \
238 		if (list->len + 1 < list->len) \
239 			return FALSE; \
240 		\
241 		node->next = NULL; \
242 		if (list->head == NULL) { \
243 			node->prev = NULL; \
244 			list->head = node; \
245 			list->tail = node; \
246 		} else { \
247 			list->tail->next = node; \
248 			node->prev = list->tail; \
249 			list->tail = node; \
250 		} \
251 		list->len++; \
252 		node->list = list; \
253 		return TRUE; \
254 	}
255 
256 #define __LIST_INSERT(list, before, node) { \
257 		if (list->len + 1 < list->len) \
258 			return FALSE; \
259 		\
260 		node->next = before; \
261 		if (list->head == before) { \
262 			node->prev = NULL; \
263 			list->head = node; \
264 		} else { \
265 			before->prev->next = node; \
266 		} \
267 		node->prev = before->prev; \
268 		before->prev = node; \
269 		list->len++; \
270 		node->list = list; \
271 		\
272 		return TRUE; \
273 	}
274 
275 #define __LIST_JOIN(list, node_type, items) { \
276 		node_type *node; \
277 		\
278 		if (list->len + items->len < list->len) \
279 			return FALSE; \
280 		\
281 		if (items->len == 0) \
282 			return TRUE; \
283 		\
284 		if (list->head == NULL) { \
285 			list->head = items->head; \
286 			list->tail = items->tail; \
287 		} else { \
288 			list->tail->next = items->head; \
289 			items->head->prev = list->tail; \
290 			list->tail = items->tail; \
291 		} \
292 		list->len += items->len; \
293 		\
294 		node = items->head; \
295 		while (node != NULL) { \
296 			node->list = list; \
297 			node = node->next; \
298 		} \
299 		return TRUE; \
300 	}
301 
302 #define __LIST_DETACH(first, node_type, count) { \
303 		node_type *last, *result; \
304 		unsigned int left; \
305 		\
306 		i_assert(first->list != NULL); \
307 		\
308 		left = count - 1; \
309 		last = first; \
310 		while (left > 0 && last->next != NULL) { \
311 			left--; \
312 			last = last->next; \
313 		} \
314 		\
315 		if (first->list->head == first) \
316 			first->list->head = last->next; \
317 		if (first->list->tail == last) \
318 			first->list->tail = first->prev; \
319 		\
320 		if (first->prev != NULL) \
321 			first->prev->next = last->next;	\
322 		if (last->next != NULL) \
323 			last->next->prev = first->prev; \
324 		\
325 		first->list->len -= count - left; \
326 		\
327 		result = last->next; \
328 		first->prev = NULL; \
329 		last->next = NULL; \
330 		\
331 		return result; \
332 	}
333 
334 /* List of AST nodes */
335 
336 static struct sieve_ast_list *
sieve_ast_list_create(pool_t pool)337 sieve_ast_list_create(pool_t pool)
338 	__LIST_CREATE(pool, struct sieve_ast_list)
339 
340 static bool
341 sieve_ast_list_add(struct sieve_ast_list *list, struct sieve_ast_node *node)
342 	__LIST_ADD(list, node)
343 
344 static struct sieve_ast_node *
345 sieve_ast_list_detach(struct sieve_ast_node *first, unsigned int count)
346 	__LIST_DETACH(first, struct sieve_ast_node, count)
347 
348 /* List of argument AST nodes */
349 
350 struct sieve_ast_arg_list *sieve_ast_arg_list_create(pool_t pool)
351 	__LIST_CREATE(pool, struct sieve_ast_arg_list)
352 
353 bool sieve_ast_arg_list_add(struct sieve_ast_arg_list *list,
354 			    struct sieve_ast_argument *argument)
355 	__LIST_ADD(list, argument)
356 
357 bool sieve_ast_arg_list_insert(struct sieve_ast_arg_list *list,
358 			       struct sieve_ast_argument *before,
359 			       struct sieve_ast_argument *argument)
360 	__LIST_INSERT(list, before, argument)
361 
362 static bool
363 sieve_ast_arg_list_join(struct sieve_ast_arg_list *list,
364 			struct sieve_ast_arg_list *items)
365 	__LIST_JOIN(list, struct sieve_ast_argument, items)
366 
367 static struct sieve_ast_argument *
368 sieve_ast_arg_list_detach(struct sieve_ast_argument *first,
369 			  const unsigned int count)
370 	__LIST_DETACH(first, struct sieve_ast_argument, count)
371 
372 void sieve_ast_arg_list_substitute(struct sieve_ast_arg_list *list,
373 				   struct sieve_ast_argument *argument,
374 				   struct sieve_ast_argument *replacement)
375 {
376 	if (list->head == argument)
377 		list->head = replacement;
378 	if (list->tail == argument)
379 		list->tail = replacement;
380 
381 	if (argument->prev != NULL)
382 		argument->prev->next = replacement;
383 	if (argument->next != NULL)
384 		argument->next->prev = replacement;
385 
386 	replacement->prev = argument->prev;
387 	replacement->next = argument->next;
388 	replacement->list = argument->list;
389 
390 	argument->next = NULL;
391 	argument->prev = NULL;
392 }
393 
394 /*
395  * AST node
396  */
397 
398 static struct sieve_ast_node *
sieve_ast_node_create(struct sieve_ast * ast,struct sieve_ast_node * parent,enum sieve_ast_type type,unsigned int source_line)399 sieve_ast_node_create(struct sieve_ast *ast, struct sieve_ast_node *parent,
400 		      enum sieve_ast_type type, unsigned int source_line)
401 {
402 	struct sieve_ast_node *node =
403 		p_new(ast->pool, struct sieve_ast_node, 1);
404 
405 	node->ast = ast;
406 	node->parent = parent;
407 	node->type = type;
408 
409 	node->prev = NULL;
410 	node->next = NULL;
411 
412 	node->arguments = NULL;
413 	node->tests = NULL;
414 	node->commands = NULL;
415 
416 	node->test_list = FALSE;
417 	node->block = FALSE;
418 
419 	node->source_line = source_line;
420 
421 	return node;
422 }
423 
424 static bool
sieve_ast_node_add_command(struct sieve_ast_node * node,struct sieve_ast_node * command)425 sieve_ast_node_add_command(struct sieve_ast_node *node,
426 			   struct sieve_ast_node *command)
427 {
428 	i_assert(command->type == SAT_COMMAND &&
429 		 (node->type == SAT_ROOT || node->type == SAT_COMMAND));
430 
431 	if (node->commands == NULL)
432 		node->commands = sieve_ast_list_create(node->ast->pool);
433 
434 	return sieve_ast_list_add(node->commands, command);
435 }
436 
437 static bool
sieve_ast_node_add_test(struct sieve_ast_node * node,struct sieve_ast_node * test)438 sieve_ast_node_add_test(struct sieve_ast_node *node,
439 			struct sieve_ast_node *test)
440 {
441 	i_assert(test->type == SAT_TEST &&
442 		 (node->type == SAT_TEST || node->type == SAT_COMMAND));
443 
444 	if (node->tests == NULL)
445 		node->tests = sieve_ast_list_create(node->ast->pool);
446 
447 	return sieve_ast_list_add(node->tests, test);
448 }
449 
450 static bool
sieve_ast_node_add_argument(struct sieve_ast_node * node,struct sieve_ast_argument * argument)451 sieve_ast_node_add_argument(struct sieve_ast_node *node,
452 			    struct sieve_ast_argument *argument)
453 {
454 	i_assert(node->type == SAT_TEST || node->type == SAT_COMMAND);
455 
456 	if (node->arguments == NULL)
457 		node->arguments = sieve_ast_arg_list_create(node->ast->pool);
458 
459 	return sieve_ast_arg_list_add(node->arguments, argument);
460 }
461 
sieve_ast_node_detach(struct sieve_ast_node * first)462 struct sieve_ast_node *sieve_ast_node_detach(struct sieve_ast_node *first)
463 {
464 	return sieve_ast_list_detach(first, 1);
465 }
466 
sieve_ast_type_name(enum sieve_ast_type ast_type)467 const char *sieve_ast_type_name(enum sieve_ast_type ast_type)
468 {
469 	switch (ast_type) {
470 	case SAT_NONE:
471 		return "none";
472 	case SAT_ROOT:
473 		return "ast root node";
474 	case SAT_COMMAND:
475 		return "command";
476 	case SAT_TEST:
477 		return "test";
478 	default:
479 		return "??AST NODE??";
480 	}
481 }
482 
483 /*
484  * Argument AST node
485  */
486 
487 struct sieve_ast_argument *
sieve_ast_argument_create(struct sieve_ast * ast,unsigned int source_line)488 sieve_ast_argument_create(struct sieve_ast *ast, unsigned int source_line)
489 {
490 	struct sieve_ast_argument *arg =
491 		p_new(ast->pool, struct sieve_ast_argument, 1);
492 
493 	arg->ast = ast;
494 
495 	arg->prev = NULL;
496 	arg->next = NULL;
497 
498 	arg->source_line = source_line;
499 
500 	arg->argument = NULL;
501 
502 	return arg;
503 }
504 
505 static void
sieve_ast_argument_substitute(struct sieve_ast_argument * argument,struct sieve_ast_argument * replacement)506 sieve_ast_argument_substitute(struct sieve_ast_argument *argument,
507 			      struct sieve_ast_argument *replacement)
508 {
509 	sieve_ast_arg_list_substitute(argument->list, argument, replacement);
510 }
511 
512 struct sieve_ast_argument *
sieve_ast_argument_string_create_raw(struct sieve_ast * ast,string_t * str,unsigned int source_line)513 sieve_ast_argument_string_create_raw(struct sieve_ast *ast, string_t *str,
514 				     unsigned int source_line)
515 {
516 	struct sieve_ast_argument *argument =
517 		sieve_ast_argument_create(ast, source_line);
518 
519 	argument->type = SAAT_STRING;
520 	argument->_value.str = str;
521 
522 	return argument;
523 }
524 
525 struct sieve_ast_argument *
sieve_ast_argument_string_create(struct sieve_ast_node * node,const string_t * str,unsigned int source_line)526 sieve_ast_argument_string_create(struct sieve_ast_node *node,
527 				 const string_t *str, unsigned int source_line)
528 {
529 	struct sieve_ast_argument *argument;
530 	string_t *newstr;
531 
532 	/* Allocate new internal string buffer */
533 	newstr = str_new(node->ast->pool, str_len(str));
534 
535 	/* Clone string */
536 	str_append_str(newstr, str);
537 
538 	/* Create string argument */
539 	argument = sieve_ast_argument_string_create_raw(
540 		node->ast, newstr, source_line);
541 
542 	/* Add argument to command/test node */
543 	sieve_ast_node_add_argument(node, argument);
544 
545 	return argument;
546 }
547 
548 struct sieve_ast_argument *
sieve_ast_argument_cstring_create(struct sieve_ast_node * node,const char * str,unsigned int source_line)549 sieve_ast_argument_cstring_create(struct sieve_ast_node *node, const char *str,
550 				  unsigned int source_line)
551 {
552 	struct sieve_ast_argument *argument;
553 	string_t *newstr;
554 
555 	/* Allocate new internal string buffer */
556 	newstr = str_new(node->ast->pool, strlen(str));
557 
558 	/* Clone string */
559 	str_append(newstr, str);
560 
561 	/* Create string argument */
562 	argument = sieve_ast_argument_string_create_raw(
563 		node->ast, newstr, source_line);
564 
565 	/* Add argument to command/test node */
566 	sieve_ast_node_add_argument(node, argument);
567 
568 	return argument;
569 }
570 
sieve_ast_argument_string_set(struct sieve_ast_argument * argument,string_t * newstr)571 void sieve_ast_argument_string_set(struct sieve_ast_argument *argument,
572 				   string_t *newstr)
573 {
574 	i_assert(argument->type == SAAT_STRING);
575 	argument->_value.str = newstr;
576 }
577 
sieve_ast_argument_string_setc(struct sieve_ast_argument * argument,const char * newstr)578 void sieve_ast_argument_string_setc(struct sieve_ast_argument *argument,
579 				    const char *newstr)
580 {
581 	i_assert(argument->type == SAAT_STRING);
582 
583 	str_truncate(argument->_value.str, 0);
584 	str_append(argument->_value.str, newstr);
585 }
586 
sieve_ast_argument_number_substitute(struct sieve_ast_argument * argument,sieve_number_t number)587 void sieve_ast_argument_number_substitute(struct sieve_ast_argument *argument,
588 					  sieve_number_t number)
589 {
590 	argument->type = SAAT_NUMBER;
591 	argument->_value.number = number;
592 }
593 
594 struct sieve_ast_argument *
sieve_ast_argument_stringlist_create(struct sieve_ast_node * node,unsigned int source_line)595 sieve_ast_argument_stringlist_create(struct sieve_ast_node *node,
596 				     unsigned int source_line)
597 {
598 	struct sieve_ast_argument *argument =
599 		sieve_ast_argument_create(node->ast, source_line);
600 
601 	argument->type = SAAT_STRING_LIST;
602 	argument->_value.strlist = NULL;
603 
604 	sieve_ast_node_add_argument(node, argument);
605 
606 	return argument;
607 }
608 
609 struct sieve_ast_argument *
sieve_ast_argument_stringlist_substitute(struct sieve_ast_node * node,struct sieve_ast_argument * arg)610 sieve_ast_argument_stringlist_substitute(struct sieve_ast_node *node,
611 					 struct sieve_ast_argument *arg)
612 {
613 	struct sieve_ast_argument *argument =
614 		sieve_ast_argument_create(node->ast, arg->source_line);
615 
616 	argument->type = SAAT_STRING_LIST;
617 	argument->_value.strlist = NULL;
618 
619 	sieve_ast_argument_substitute(arg, argument);
620 
621 	return argument;
622 }
623 
624 static inline bool
_sieve_ast_stringlist_add_item(struct sieve_ast_argument * list,struct sieve_ast_argument * item)625 _sieve_ast_stringlist_add_item(struct sieve_ast_argument *list,
626 			       struct sieve_ast_argument *item)
627 {
628 	i_assert(list->type == SAAT_STRING_LIST);
629 
630 	if (list->_value.strlist == NULL) {
631 		list->_value.strlist =
632 			sieve_ast_arg_list_create(list->ast->pool);
633 	}
634 
635 	return sieve_ast_arg_list_add(list->_value.strlist, item);
636 }
637 
638 static bool
sieve_ast_stringlist_add_stringlist(struct sieve_ast_argument * list,struct sieve_ast_argument * items)639 sieve_ast_stringlist_add_stringlist(struct sieve_ast_argument *list,
640 				    struct sieve_ast_argument *items)
641 {
642 	i_assert(list->type == SAAT_STRING_LIST);
643 	i_assert(items->type == SAAT_STRING_LIST);
644 
645 	if (list->_value.strlist == NULL) {
646 		list->_value.strlist =
647 			sieve_ast_arg_list_create(list->ast->pool);
648 	}
649 
650 	return sieve_ast_arg_list_join(list->_value.strlist,
651 				       items->_value.strlist);
652 }
653 
654 static bool
_sieve_ast_stringlist_add_str(struct sieve_ast_argument * list,string_t * str,unsigned int source_line)655 _sieve_ast_stringlist_add_str(struct sieve_ast_argument *list, string_t *str,
656 			      unsigned int source_line)
657 {
658 	struct sieve_ast_argument *stritem;
659 
660 	stritem = sieve_ast_argument_create(list->ast, source_line);
661 	stritem->type = SAAT_STRING;
662 	stritem->_value.str = str;
663 
664 	return _sieve_ast_stringlist_add_item(list, stritem);
665 }
666 
sieve_ast_stringlist_add(struct sieve_ast_argument * list,const string_t * str,unsigned int source_line)667 bool sieve_ast_stringlist_add(struct sieve_ast_argument *list,
668 			      const string_t *str, unsigned int source_line)
669 {
670 	string_t *copied_str = str_new(list->ast->pool, str_len(str));
671 	str_append_str(copied_str, str);
672 
673 	return _sieve_ast_stringlist_add_str(list, copied_str, source_line);
674 }
675 
sieve_ast_stringlist_add_strc(struct sieve_ast_argument * list,const char * str,unsigned int source_line)676 bool sieve_ast_stringlist_add_strc(struct sieve_ast_argument *list,
677 				   const char *str, unsigned int source_line)
678 {
679 	string_t *copied_str = str_new(list->ast->pool, strlen(str));
680 	str_append(copied_str, str);
681 
682 	return _sieve_ast_stringlist_add_str(list, copied_str, source_line);
683 }
684 
685 struct sieve_ast_argument *
sieve_ast_argument_tag_create(struct sieve_ast_node * node,const char * tag,unsigned int source_line)686 sieve_ast_argument_tag_create(struct sieve_ast_node *node, const char *tag,
687 			      unsigned int source_line)
688 {
689 	struct sieve_ast_argument *argument =
690 		sieve_ast_argument_create(node->ast, source_line);
691 
692 	argument->type = SAAT_TAG;
693 	argument->_value.tag = p_strdup(node->ast->pool, tag);
694 
695 	if (!sieve_ast_node_add_argument(node, argument))
696 		return NULL;
697 	return argument;
698 }
699 
700 struct sieve_ast_argument *
sieve_ast_argument_tag_insert(struct sieve_ast_argument * before,const char * tag,unsigned int source_line)701 sieve_ast_argument_tag_insert(struct sieve_ast_argument *before,
702 			      const char *tag, unsigned int source_line)
703 {
704 	struct sieve_ast_argument *argument =
705 		sieve_ast_argument_create(before->ast, source_line);
706 
707 	argument->type = SAAT_TAG;
708 	argument->_value.tag = p_strdup(before->ast->pool, tag);
709 
710 	if (!sieve_ast_arg_list_insert(before->list, before, argument))
711 		return NULL;
712 	return argument;
713 }
714 
715 struct sieve_ast_argument *
sieve_ast_argument_number_create(struct sieve_ast_node * node,sieve_number_t number,unsigned int source_line)716 sieve_ast_argument_number_create(struct sieve_ast_node *node,
717 				 sieve_number_t number,
718 				 unsigned int source_line)
719 {
720 	struct sieve_ast_argument *argument =
721 		sieve_ast_argument_create(node->ast, source_line);
722 
723 	argument->type = SAAT_NUMBER;
724 	argument->_value.number = number;
725 
726 	if (!sieve_ast_node_add_argument(node, argument))
727 		return NULL;
728 	return argument;
729 }
730 
sieve_ast_argument_number_set(struct sieve_ast_argument * argument,sieve_number_t newnum)731 void sieve_ast_argument_number_set(struct sieve_ast_argument *argument,
732 				   sieve_number_t newnum)
733 {
734 	i_assert(argument->type == SAAT_NUMBER);
735 	argument->_value.number = newnum;
736 }
737 
738 struct sieve_ast_argument *
sieve_ast_arguments_detach(struct sieve_ast_argument * first,unsigned int count)739 sieve_ast_arguments_detach(struct sieve_ast_argument *first,
740 			   unsigned int count)
741 {
742 	return sieve_ast_arg_list_detach(first, count);
743 }
744 
sieve_ast_argument_attach(struct sieve_ast_node * node,struct sieve_ast_argument * argument)745 bool sieve_ast_argument_attach(struct sieve_ast_node *node,
746 			       struct sieve_ast_argument *argument)
747 {
748 	return sieve_ast_node_add_argument(node, argument);
749 }
750 
sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type)751 const char *sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type)
752 {
753 	switch (arg_type) {
754 	case SAAT_NONE:
755 		return "none";
756 	case SAAT_STRING_LIST:
757 		return "a string list";
758 	case SAAT_STRING:
759 		return "a string";
760 	case SAAT_NUMBER:
761 		return "a number";
762 	case SAAT_TAG:
763 		return "a tag";
764 	default:
765 		return "??ARGUMENT??";
766 	}
767 }
768 
769 /* Test AST node */
770 
771 struct sieve_ast_node *
sieve_ast_test_create(struct sieve_ast_node * parent,const char * identifier,unsigned int source_line)772 sieve_ast_test_create(struct sieve_ast_node *parent, const char *identifier,
773 		      unsigned int source_line)
774 {
775 	struct sieve_ast_node *test = sieve_ast_node_create(
776 		parent->ast, parent, SAT_TEST, source_line);
777 
778 	test->identifier = p_strdup(parent->ast->pool, identifier);
779 
780 	if (!sieve_ast_node_add_test(parent, test))
781 		return NULL;
782 	return test;
783 }
784 
785 /* Command AST node */
786 
787 struct sieve_ast_node *
sieve_ast_command_create(struct sieve_ast_node * parent,const char * identifier,unsigned int source_line)788 sieve_ast_command_create(struct sieve_ast_node *parent, const char *identifier,
789 			 unsigned int source_line)
790 {
791 	struct sieve_ast_node *command = sieve_ast_node_create(
792 		parent->ast, parent, SAT_COMMAND, source_line);
793 
794 	command->identifier = p_strdup(parent->ast->pool, identifier);
795 
796 	if (!sieve_ast_node_add_command(parent, command))
797 		return NULL;
798 	return command;
799 }
800 
801 /*
802  * Utility
803  */
804 
sieve_ast_stringlist_map(struct sieve_ast_argument ** listitem,void * context,int (* map_function)(void * context,struct sieve_ast_argument * arg))805 int sieve_ast_stringlist_map(
806 	struct sieve_ast_argument **listitem, void *context,
807 	int (*map_function)(void *context, struct sieve_ast_argument *arg))
808 {
809 	if (sieve_ast_argument_type(*listitem) == SAAT_STRING) {
810 		/* Single string */
811 		return map_function(context, *listitem);
812 	} else if (sieve_ast_argument_type(*listitem) == SAAT_STRING_LIST) {
813 		int ret = 0;
814 
815 		/* String list */
816 		*listitem = sieve_ast_strlist_first(*listitem);
817 
818 		while (*listitem != NULL) {
819 			if ((ret = map_function(context, *listitem)) <= 0)
820 				return ret;
821 
822 			*listitem = sieve_ast_strlist_next(*listitem);
823 		}
824 
825 		return ret;
826 	}
827 
828 	i_unreached();
829 	return -1;
830 }
831 
832 struct sieve_ast_argument *
sieve_ast_stringlist_join(struct sieve_ast_argument * list,struct sieve_ast_argument * items)833 sieve_ast_stringlist_join(struct sieve_ast_argument *list,
834 			  struct sieve_ast_argument *items)
835 {
836 	enum sieve_ast_argument_type list_type, items_type;
837 	struct sieve_ast_argument *newlist;
838 
839 	list_type = sieve_ast_argument_type(list);
840 	items_type = sieve_ast_argument_type(items);
841 
842 	switch (list_type) {
843 	case SAAT_STRING:
844 		switch (items_type) {
845 		case SAAT_STRING:
846 			newlist = sieve_ast_argument_create(
847 				list->ast, list->source_line);
848 			newlist->type = SAAT_STRING_LIST;
849 			newlist->_value.strlist = NULL;
850 
851 			sieve_ast_argument_substitute(list, newlist);
852 			sieve_ast_arguments_detach(items, 1);
853 
854 			if (!_sieve_ast_stringlist_add_item(newlist, list) ||
855 			    !_sieve_ast_stringlist_add_item(newlist, items))
856 				return NULL;
857 			return newlist;
858 		case SAAT_STRING_LIST:
859 			/* Adding stringlist to string; make them swith places
860 			   and add one to the other.
861 			 */
862 			sieve_ast_arguments_detach(items, 1);
863 			sieve_ast_argument_substitute(list, items);
864 			if (!_sieve_ast_stringlist_add_item(items, list))
865 				return NULL;
866 			return list;
867 		default:
868 			i_unreached();
869 		}
870 		break;
871 	case SAAT_STRING_LIST:
872 		switch (items_type) {
873 		case SAAT_STRING:
874 			/* Adding string to stringlist; straightforward add */
875 			sieve_ast_arguments_detach(items, 1);
876 			if (!_sieve_ast_stringlist_add_item(list, items))
877 				return NULL;
878 			return list;
879 		case SAAT_STRING_LIST:
880 			/* Adding stringlist to stringlist; perform actual join
881 			 */
882 			sieve_ast_arguments_detach(items, 1);
883 			if (!sieve_ast_stringlist_add_stringlist(list, items))
884 				return NULL;
885 			return list;
886 		default:
887 			i_unreached();
888 		}
889 		break;
890 	default:
891 		i_unreached();
892 	}
893 	return NULL;
894 }
895 
896 /* Debug */
897 
898 /* Unparsing, currently implemented using plain printf()s */
899 
sieve_ast_unparse_string(const string_t * strval)900 static void sieve_ast_unparse_string(const string_t *strval)
901 {
902 	char *str = t_strdup_noconst(str_c((string_t *)strval));
903 
904 	if (strchr(str, '\n') != NULL && str[strlen(str)-1] == '\n') {
905 		/* Print it as a multi-line string and do required dotstuffing
906 		 */
907 		char *spos = str;
908 		char *epos = strchr(str, '\n');
909 		printf("text:\n");
910 
911 		while (epos != NULL) {
912 			*epos = '\0';
913 			if (*spos == '.')
914 				printf(".");
915 
916 			printf("%s\n", spos);
917 
918 			spos = epos+1;
919 			epos = strchr(spos, '\n');
920 		}
921 		if (*spos == '.')
922 			printf(".");
923 
924 		printf("%s\n.\n", spos);
925 	} else {
926 		/* Print it as a quoted string and escape " */
927 		char *spos = str;
928 		char *epos = strchr(str, '"');
929 		printf("\"");
930 
931 		while (epos != NULL) {
932 			*epos = '\0';
933 			printf("%s\\\"", spos);
934 
935 			spos = epos+1;
936 			epos = strchr(spos, '"');
937 		}
938 
939 		printf("%s\"", spos);
940 	}
941 }
942 
943 static void
944 sieve_ast_unparse_argument(struct sieve_ast_argument *argument, int level);
945 
946 static void
sieve_ast_unparse_stringlist(struct sieve_ast_argument * strlist,int level)947 sieve_ast_unparse_stringlist(struct sieve_ast_argument *strlist, int level)
948 {
949 	struct sieve_ast_argument *stritem;
950 
951 	if (sieve_ast_strlist_count(strlist) > 1) {
952 		int i;
953 
954 		printf("[\n");
955 
956 		/* Create indent */
957 		for (i = 0; i < level+2; i++)
958 			printf("  ");
959 
960 		stritem = sieve_ast_strlist_first(strlist);
961 		if (stritem != NULL) {
962 			sieve_ast_unparse_string(
963 				sieve_ast_strlist_str(stritem));
964 
965 			stritem = sieve_ast_strlist_next(stritem);
966 			while (stritem != NULL) {
967 				printf(",\n");
968 				for (i = 0; i < level+2; i++)
969 					printf("  ");
970 				sieve_ast_unparse_string(
971 					sieve_ast_strlist_str(stritem));
972 				stritem = sieve_ast_strlist_next(stritem);
973 			}
974 		}
975 
976 		printf(" ]");
977 	} else {
978 		stritem = sieve_ast_strlist_first(strlist);
979 		if (stritem != NULL) {
980 			sieve_ast_unparse_string(
981 				sieve_ast_strlist_str(stritem));
982 		}
983 	}
984 }
985 
986 static void
sieve_ast_unparse_argument(struct sieve_ast_argument * argument,int level)987 sieve_ast_unparse_argument(struct sieve_ast_argument *argument, int level)
988 {
989 	switch (argument->type) {
990 	case SAAT_STRING:
991 		sieve_ast_unparse_string(sieve_ast_argument_str(argument));
992 		break;
993 	case SAAT_STRING_LIST:
994 		sieve_ast_unparse_stringlist(argument, level+1);
995 		break;
996 	case SAAT_NUMBER:
997 		printf("%"SIEVE_PRI_NUMBER,
998 		       sieve_ast_argument_number(argument));
999 		break;
1000 	case SAAT_TAG:
1001 		printf(":%s", sieve_ast_argument_tag(argument));
1002 		break;
1003 	default:
1004 		printf("??ARGUMENT??");
1005 		break;
1006 	}
1007 }
1008 
1009 static void sieve_ast_unparse_test(struct sieve_ast_node *node, int level);
1010 
sieve_ast_unparse_tests(struct sieve_ast_node * node,int level)1011 static void sieve_ast_unparse_tests(struct sieve_ast_node *node, int level)
1012 {
1013 	struct sieve_ast_node *test;
1014 
1015 	if (sieve_ast_test_count(node) > 1) {
1016 		int i;
1017 
1018 		printf(" (\n");
1019 
1020 		/* Create indent */
1021 		for (i = 0; i < level+2; i++)
1022 			printf("  ");
1023 
1024 		test = sieve_ast_test_first(node);
1025 		sieve_ast_unparse_test(test, level+1);
1026 
1027 		test = sieve_ast_test_next(test);
1028 		while (test != NULL) {
1029 			printf(", \n");
1030 			for (i = 0; i < level+2; i++)
1031 				printf("  ");
1032 			sieve_ast_unparse_test(test, level+1);
1033 			test = sieve_ast_test_next(test);
1034 		}
1035 
1036 		printf(" )");
1037 	} else {
1038 		test = sieve_ast_test_first(node);
1039 		if (test != NULL)
1040 			sieve_ast_unparse_test(test, level);
1041 	}
1042 }
1043 
sieve_ast_unparse_test(struct sieve_ast_node * node,int level)1044 static void sieve_ast_unparse_test(struct sieve_ast_node *node, int level)
1045 {
1046 	struct sieve_ast_argument *argument;
1047 
1048 	printf(" %s", node->identifier);
1049 
1050 	argument = sieve_ast_argument_first(node);
1051 	while (argument != NULL) {
1052 		printf(" ");
1053 		sieve_ast_unparse_argument(argument, level);
1054 		argument = sieve_ast_argument_next(argument);
1055 	}
1056 
1057 	sieve_ast_unparse_tests(node, level);
1058 }
1059 
sieve_ast_unparse_command(struct sieve_ast_node * node,int level)1060 static void sieve_ast_unparse_command(struct sieve_ast_node *node, int level)
1061 {
1062 	struct sieve_ast_node *command;
1063 	struct sieve_ast_argument *argument;
1064 
1065 	int i;
1066 
1067 	/* Create indent */
1068 	for (i = 0; i < level; i++)
1069 		printf("  ");
1070 
1071 	printf("%s", node->identifier);
1072 
1073 	argument = sieve_ast_argument_first(node);
1074 	while (argument != NULL) {
1075 		printf(" ");
1076 		sieve_ast_unparse_argument(argument, level);
1077 		argument = sieve_ast_argument_next(argument);
1078 	}
1079 
1080 	sieve_ast_unparse_tests(node, level);
1081 
1082 	command = sieve_ast_command_first(node);
1083 	if (command != NULL) {
1084 		printf(" {\n");
1085 
1086 		while (command != NULL) {
1087 			sieve_ast_unparse_command(command, level+1);
1088 			command = sieve_ast_command_next(command);
1089 		}
1090 
1091 		for (i = 0; i < level; i++)
1092 			printf("  ");
1093 		printf("}\n");
1094 	} else
1095 		printf(";\n");
1096 }
1097 
sieve_ast_unparse(struct sieve_ast * ast)1098 void sieve_ast_unparse(struct sieve_ast *ast)
1099 {
1100 	struct sieve_ast_node *command;
1101 
1102 	printf("Unparsing Abstract Syntax Tree:\n");
1103 
1104 	T_BEGIN {
1105 		command = sieve_ast_command_first(sieve_ast_root(ast));
1106 		while (command != NULL) {
1107 			sieve_ast_unparse_command(command, 0);
1108 			command = sieve_ast_command_next(command);
1109 		}
1110 	} T_END;
1111 }
1112