Coverage Report

Created: 2026-09-03 07:00

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