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