Coverage Report

Created: 2026-05-30 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file
2
 */
3
4
#include "lib.h"
5
#include "hash.h"
6
#include "str.h"
7
#include "array.h"
8
#include "settings.h"
9
10
#include "sieve-common.h"
11
12
#include "sieve-ast.h"
13
#include "sieve-binary.h"
14
#include "sieve-code.h"
15
#include "sieve-objects.h"
16
#include "sieve-match-types.h"
17
18
#include "sieve-commands.h"
19
#include "sieve-validator.h"
20
#include "sieve-generator.h"
21
#include "sieve-dump.h"
22
#include "sieve-interpreter.h"
23
24
#include "ext-variables-common.h"
25
#include "ext-variables-name.h"
26
#include "ext-variables-modifiers.h"
27
28
/*
29
 * Limits
30
 */
31
32
unsigned int
33
sieve_variables_get_max_scope_count(const struct sieve_extension *var_ext)
34
0
{
35
0
  const struct ext_variables_context *extctx =
36
0
    ext_variables_get_context(var_ext);
37
38
0
  return extctx->set->max_scope_count;
39
0
}
40
41
size_t sieve_variables_get_max_value_size(
42
  const struct sieve_extension *var_ext)
43
0
{
44
0
  const struct ext_variables_context *extctx =
45
0
    ext_variables_get_context(var_ext);
46
47
0
  return extctx->set->max_value_size;
48
0
}
49
50
/*
51
 * Extension configuration
52
 */
53
54
int ext_variables_load(const struct sieve_extension *ext, void **context_r)
55
0
{
56
0
  struct sieve_instance *svinst = ext->svinst;
57
0
  const struct ext_variables_settings *set;
58
0
  struct ext_variables_context *extctx;
59
0
  const char *error;
60
61
0
  if (settings_get(svinst->event, &ext_variables_setting_parser_info, 0,
62
0
       &set, &error) < 0) {
63
0
    e_error(svinst->event, "%s", error);
64
0
    return -1;
65
0
  }
66
67
0
  extctx = i_new(struct ext_variables_context, 1);
68
0
  extctx->set = set;
69
70
0
  *context_r = extctx;
71
0
  return 0;
72
0
}
73
74
void ext_variables_unload(const struct sieve_extension *ext)
75
0
{
76
0
  struct ext_variables_context *extctx = ext->context;
77
78
0
  if (extctx == NULL)
79
0
    return;
80
0
  settings_free(extctx->set);
81
0
  i_free(extctx);
82
0
}
83
84
const struct ext_variables_context *
85
ext_variables_get_context(const struct sieve_extension *var_ext)
86
0
{
87
0
  const struct ext_variables_context *extctx = var_ext->context;
88
89
0
  i_assert(var_ext->def == &variables_extension);
90
0
  return extctx;
91
0
}
92
93
/*
94
 * Variable scope
95
 */
96
97
struct sieve_variable_scope {
98
  pool_t pool;
99
  int refcount;
100
101
  struct sieve_instance *svinst;
102
  const struct sieve_extension *var_ext;
103
  const struct sieve_extension *ext;
104
105
  struct sieve_variable *error_var;
106
107
  HASH_TABLE(const char *, struct sieve_variable *) variables;
108
  ARRAY(struct sieve_variable *) variable_index;
109
};
110
111
struct sieve_variable_scope_binary {
112
  struct sieve_variable_scope *scope;
113
114
  unsigned int count;
115
  struct sieve_binary_block *sblock;
116
  sieve_size_t address;
117
};
118
119
struct sieve_variable_scope_iter {
120
  struct sieve_variable_scope *scope;
121
  struct hash_iterate_context *hctx;
122
};
123
124
struct sieve_variable_scope *
125
sieve_variable_scope_create(struct sieve_instance *svinst,
126
          const struct sieve_extension *var_ext,
127
          const struct sieve_extension *ext)
128
0
{
129
0
  struct sieve_variable_scope *scope;
130
0
  pool_t pool;
131
132
0
  i_assert(var_ext->def == &variables_extension);
133
134
0
  pool = pool_alloconly_create("sieve_variable_scope", 4096);
135
0
  scope = p_new(pool, struct sieve_variable_scope, 1);
136
0
  scope->pool = pool;
137
0
  scope->refcount = 1;
138
139
0
  scope->svinst = svinst;
140
0
  scope->var_ext = var_ext;
141
0
  scope->ext = ext;
142
143
0
  hash_table_create(&scope->variables, pool, 0, strcase_hash, strcasecmp);
144
0
  p_array_init(&scope->variable_index, pool, 128);
145
146
0
  return scope;
147
0
}
148
149
void sieve_variable_scope_ref(struct sieve_variable_scope *scope)
150
0
{
151
0
  scope->refcount++;
152
0
}
153
154
void sieve_variable_scope_unref(struct sieve_variable_scope **_scope)
155
0
{
156
0
  struct sieve_variable_scope *scope = *_scope;
157
158
0
  i_assert(scope->refcount > 0);
159
160
0
  if (--scope->refcount != 0)
161
0
    return;
162
163
0
  hash_table_destroy(&scope->variables);
164
165
0
  *_scope = NULL;
166
0
  pool_unref(&scope->pool);
167
0
}
168
169
pool_t sieve_variable_scope_pool(struct sieve_variable_scope *scope)
170
0
{
171
0
  return scope->pool;
172
0
}
173
174
struct sieve_variable *
175
sieve_variable_scope_declare(struct sieve_variable_scope *scope,
176
           const char *identifier)
177
0
{
178
0
  unsigned int max_scope_count;
179
0
  struct sieve_variable *var;
180
181
0
  var = hash_table_lookup(scope->variables, identifier);
182
0
  if (var != NULL)
183
0
    return var;
184
185
0
  max_scope_count = sieve_variables_get_max_scope_count(scope->var_ext);
186
0
  if (array_count(&scope->variable_index) >= max_scope_count) {
187
0
    if (scope->error_var == NULL) {
188
0
      var = p_new(scope->pool, struct sieve_variable, 1);
189
0
      var->identifier = "@ERROR@";
190
0
      var->index = 0;
191
192
0
      scope->error_var = var;
193
0
      return NULL;
194
0
    }
195
196
0
    return scope->error_var;
197
0
  }
198
199
0
  var = p_new(scope->pool, struct sieve_variable, 1);
200
0
  var->ext = scope->ext;
201
0
  var->identifier = p_strdup(scope->pool, identifier);
202
0
  var->index = array_count(&scope->variable_index);
203
204
0
  hash_table_insert(scope->variables, var->identifier, var);
205
0
  array_append(&scope->variable_index, &var, 1);
206
0
  return var;
207
0
}
208
209
struct sieve_variable *
210
sieve_variable_scope_get_variable(struct sieve_variable_scope *scope,
211
          const char *identifier)
212
0
{
213
0
  return hash_table_lookup(scope->variables, identifier);
214
0
}
215
216
struct sieve_variable *
217
sieve_variable_scope_import(struct sieve_variable_scope *scope,
218
          struct sieve_variable *var)
219
0
{
220
0
  struct sieve_variable *old_var, *new_var;
221
222
0
  old_var = sieve_variable_scope_get_variable(scope, var->identifier);
223
0
  if (old_var != NULL) {
224
0
    i_assert(memcmp(old_var, var, sizeof(*var)) == 0);
225
0
    return old_var;
226
0
  }
227
228
0
  new_var = p_new(scope->pool, struct sieve_variable, 1);
229
0
  memcpy(new_var, var, sizeof(*new_var));
230
231
0
  hash_table_insert(scope->variables, new_var->identifier, new_var);
232
233
  /* Not entered into the index because it is an external variable
234
     (This can be done unlimited; only limited by the size of the external
235
     scope)
236
   */
237
0
  return new_var;
238
0
}
239
240
struct sieve_variable_scope_iter *
241
sieve_variable_scope_iterate_init(struct sieve_variable_scope *scope)
242
0
{
243
0
  struct sieve_variable_scope_iter *iter;
244
245
0
  iter = t_new(struct sieve_variable_scope_iter, 1);
246
0
  iter->scope = scope;
247
0
  iter->hctx = hash_table_iterate_init(scope->variables);
248
249
0
  return iter;
250
0
}
251
252
bool sieve_variable_scope_iterate(struct sieve_variable_scope_iter *iter,
253
          struct sieve_variable **var_r)
254
0
{
255
0
  const char *key;
256
257
0
  return hash_table_iterate(iter->hctx, iter->scope->variables,
258
0
          &key, var_r);
259
0
}
260
261
void sieve_variable_scope_iterate_deinit(
262
  struct sieve_variable_scope_iter **iter)
263
0
{
264
0
  hash_table_iterate_deinit(&(*iter)->hctx);
265
0
  *iter = NULL;
266
0
}
267
268
unsigned int
269
sieve_variable_scope_declarations(struct sieve_variable_scope *scope)
270
0
{
271
0
  return hash_table_count(scope->variables);
272
0
}
273
274
unsigned int sieve_variable_scope_size(struct sieve_variable_scope *scope)
275
0
{
276
0
  return array_count(&scope->variable_index);
277
0
}
278
279
struct sieve_variable *const *
280
sieve_variable_scope_get_variables(struct sieve_variable_scope *scope,
281
           unsigned int *size_r)
282
0
{
283
0
  return array_get(&scope->variable_index, size_r);
284
0
}
285
286
struct sieve_variable *
287
sieve_variable_scope_get_indexed(struct sieve_variable_scope *scope,
288
         unsigned int index)
289
0
{
290
0
  struct sieve_variable *const *var;
291
292
0
  if (index >= array_count(&scope->variable_index))
293
0
    return NULL;
294
295
0
  var = array_idx(&scope->variable_index, index);
296
0
  return *var;
297
0
}
298
299
/* Scope binary */
300
301
struct sieve_variable_scope *
302
sieve_variable_scope_binary_dump(struct sieve_instance *svinst,
303
         const struct sieve_extension *var_ext,
304
         const struct sieve_extension *ext,
305
         const struct sieve_dumptime_env *denv,
306
         sieve_size_t *address)
307
0
{
308
0
  struct sieve_variable_scope *local_scope;
309
0
  unsigned int i, scope_size;
310
0
  sieve_size_t pc;
311
0
  sieve_offset_t end_offset;
312
313
  /* Read scope size */
314
0
  sieve_code_mark(denv);
315
0
  if (!sieve_binary_read_unsigned(denv->sblock, address, &scope_size))
316
0
    return NULL;
317
318
  /* Read offset */
319
0
  pc = *address;
320
0
  if (!sieve_binary_read_offset(denv->sblock, address, &end_offset))
321
0
    return NULL;
322
323
  /* Create scope */
324
0
  local_scope = sieve_variable_scope_create(svinst, var_ext, ext);
325
326
  /* Read and dump scope itself */
327
328
0
  sieve_code_dumpf(denv, "VARIABLES SCOPE [%u] (end: %08x)",
329
0
       scope_size, (unsigned int)(pc + end_offset));
330
331
0
  for (i = 0; i < scope_size; i++) {
332
0
    string_t *identifier;
333
334
0
    sieve_code_mark(denv);
335
0
    if (!sieve_binary_read_string(denv->sblock, address,
336
0
                &identifier))
337
0
      return NULL;
338
339
0
    sieve_code_dumpf(denv, "%3d: '%s'", i, str_c(identifier));
340
341
0
    (void)sieve_variable_scope_declare(local_scope,
342
0
               str_c(identifier));
343
0
  }
344
345
0
  return local_scope;
346
0
}
347
348
struct sieve_variable_scope_binary *
349
sieve_variable_scope_binary_create(struct sieve_variable_scope *scope)
350
0
{
351
0
  struct sieve_variable_scope_binary *scpbin;
352
353
0
  scpbin = p_new(scope->pool, struct sieve_variable_scope_binary, 1);
354
0
  scpbin->scope = scope;
355
356
0
  return scpbin;
357
0
}
358
359
void sieve_variable_scope_binary_ref(struct sieve_variable_scope_binary *scpbin)
360
0
{
361
0
  sieve_variable_scope_ref(scpbin->scope);
362
0
}
363
364
void sieve_variable_scope_binary_unref(
365
  struct sieve_variable_scope_binary **scpbin)
366
0
{
367
0
  sieve_variable_scope_unref(&(*scpbin)->scope);
368
0
  *scpbin = NULL;
369
0
}
370
371
struct sieve_variable_scope_binary *
372
sieve_variable_scope_binary_read(struct sieve_instance *svinst,
373
         const struct sieve_extension *var_ext,
374
         const struct sieve_extension *ext,
375
         struct sieve_binary_block *sblock,
376
         sieve_size_t *address)
377
0
{
378
0
  struct sieve_variable_scope *scope;
379
0
  struct sieve_variable_scope_binary *scpbin;
380
0
  unsigned int scope_count, max_scope_count;
381
0
  const char *ext_name = (ext == NULL ? "variables" :
382
0
        sieve_extension_name(ext));
383
0
  sieve_size_t pc;
384
0
  sieve_offset_t end_offset;
385
386
  /* Read scope size */
387
0
  if (!sieve_binary_read_unsigned(sblock, address, &scope_count)) {
388
0
    e_error(svinst->event, "%s: "
389
0
      "variable scope: failed to read count", ext_name);
390
0
    return NULL;
391
0
  }
392
393
  /* Check size limit */
394
0
  max_scope_count = sieve_variables_get_max_scope_count(var_ext);
395
0
  if (scope_count > max_scope_count) {
396
0
    e_error(svinst->event, "%s: "
397
0
      "variable scope: count exceeds the limit (%u > %u)",
398
0
      ext_name, scope_count, max_scope_count);
399
0
    return NULL;
400
0
  }
401
402
  /* Read offset */
403
0
  pc = *address;
404
0
  if (!sieve_binary_read_offset(sblock, address, &end_offset)) {
405
0
    e_error(svinst->event, "%s: "
406
0
      "variable scope: failed to read end offset", ext_name);
407
0
    return NULL;
408
0
  }
409
410
  /* Create scope */
411
0
  scope = sieve_variable_scope_create(svinst, var_ext, ext);
412
413
0
  scpbin = sieve_variable_scope_binary_create(scope);
414
0
  scpbin->count = scope_count;
415
0
  scpbin->sblock = sblock;
416
0
  scpbin->address = *address;
417
418
0
  *address = pc + end_offset;
419
420
0
  return scpbin;
421
0
}
422
423
struct sieve_variable_scope *
424
sieve_variable_scope_binary_get(struct sieve_variable_scope_binary *scpbin)
425
0
{
426
0
  const struct sieve_extension *ext = scpbin->scope->ext;
427
0
  struct sieve_instance *svinst = scpbin->scope->svinst;
428
0
  const char *ext_name = (ext == NULL ? "variables" :
429
0
        sieve_extension_name(ext));
430
0
  unsigned int i;
431
432
0
  if (scpbin->sblock != NULL) {
433
0
    sieve_size_t *address = &scpbin->address;
434
435
    /* Read scope itself */
436
0
    for (i = 0; i < scpbin->count; i++) {
437
0
      struct sieve_variable *var;
438
0
      string_t *identifier;
439
440
0
      if (!sieve_binary_read_string(scpbin->sblock, address,
441
0
                  &identifier)) {
442
0
        e_error(svinst->event, "%s: variable scope: "
443
0
          "failed to read variable name",
444
0
          ext_name);
445
0
        return NULL;
446
0
      }
447
448
0
      var = sieve_variable_scope_declare(scpbin->scope,
449
0
                 str_c(identifier));
450
451
0
      i_assert(var != NULL);
452
0
      i_assert(var->index == i);
453
0
    }
454
455
0
    scpbin->sblock = NULL;
456
0
  }
457
458
0
  return scpbin->scope;
459
0
}
460
461
unsigned int
462
sieve_variable_scope_binary_get_count(
463
  struct sieve_variable_scope_binary *scpbin)
464
0
{
465
0
  if (scpbin->sblock != NULL)
466
0
    return scpbin->count;
467
468
0
  return array_count(&scpbin->scope->variable_index);
469
0
}
470
471
/*
472
 * Variable storage
473
 */
474
475
struct sieve_variable_storage {
476
  pool_t pool;
477
  const struct sieve_extension *var_ext;
478
  struct sieve_variable_scope *scope;
479
  struct sieve_variable_scope_binary *scope_bin;
480
  unsigned int max_count;
481
  ARRAY(string_t *) var_values;
482
};
483
484
struct sieve_variable_storage *
485
sieve_variable_storage_create(const struct sieve_extension *var_ext,
486
            pool_t pool,
487
            struct sieve_variable_scope_binary *scpbin)
488
0
{
489
0
  struct sieve_variable_storage *storage;
490
491
0
  storage = p_new(pool, struct sieve_variable_storage, 1);
492
0
  storage->pool = pool;
493
0
  storage->var_ext = var_ext;
494
0
  storage->scope_bin = scpbin;
495
0
  storage->scope = NULL;
496
497
0
  storage->max_count = sieve_variable_scope_binary_get_count(scpbin);
498
499
0
  p_array_init(&storage->var_values, pool, 4);
500
501
0
  return storage;
502
0
}
503
504
static inline bool
505
sieve_variable_valid(struct sieve_variable_storage *storage,
506
         unsigned int index)
507
0
{
508
0
  if (storage->scope_bin == NULL)
509
0
    return TRUE;
510
511
0
  return (index < storage->max_count);
512
0
}
513
514
bool sieve_variable_get_identifier(struct sieve_variable_storage *storage,
515
           unsigned int index, const char **identifier)
516
0
{
517
0
  struct sieve_variable *const *var;
518
519
0
  *identifier = NULL;
520
521
0
  if (storage->scope_bin == NULL)
522
0
    return TRUE;
523
524
0
  if (storage->scope == NULL) {
525
0
    storage->scope =
526
0
      sieve_variable_scope_binary_get(storage->scope_bin);
527
0
    if (storage->scope == NULL)
528
0
      return FALSE;
529
0
  }
530
531
  /* FIXME: direct invasion of the scope object is a bit ugly */
532
0
  if (index >= array_count(&storage->scope->variable_index))
533
0
    return FALSE;
534
535
0
  var = array_idx(&storage->scope->variable_index, index);
536
0
  if (*var != NULL)
537
0
    *identifier = (*var)->identifier;
538
0
  return TRUE;
539
0
}
540
541
const char *
542
sieve_variable_get_varid(struct sieve_variable_storage *storage,
543
       unsigned int index)
544
0
{
545
0
  if (storage->scope_bin == NULL)
546
0
    return t_strdup_printf("%ld", (long)index);
547
548
0
  if (storage->scope == NULL) {
549
0
    storage->scope =
550
0
      sieve_variable_scope_binary_get(storage->scope_bin);
551
0
    if (storage->scope == NULL)
552
0
      return NULL;
553
0
  }
554
555
0
  return sieve_ext_variables_get_varid(storage->scope->ext, index);
556
0
}
557
558
bool sieve_variable_get(struct sieve_variable_storage *storage,
559
      unsigned int index, string_t **value)
560
0
{
561
0
  *value = NULL;
562
563
0
  if (index < array_count(&storage->var_values)) {
564
0
    string_t *const *varent;
565
566
0
    varent = array_idx(&storage->var_values, index);
567
568
0
    *value = *varent;
569
0
  } else if (!sieve_variable_valid(storage, index)) {
570
0
    return FALSE;
571
0
  }
572
573
0
  return TRUE;
574
0
}
575
576
bool sieve_variable_get_modifiable(struct sieve_variable_storage *storage,
577
           unsigned int index, string_t **value)
578
0
{
579
0
  string_t *dummy;
580
581
0
  if (value == NULL)
582
0
    value = &dummy;
583
584
0
  if (!sieve_variable_get(storage, index, value))
585
0
    return FALSE;
586
587
0
  if (*value == NULL) {
588
0
    *value = str_new(storage->pool, 256);
589
0
    array_idx_set(&storage->var_values, index, value);
590
0
  }
591
0
  return TRUE;
592
0
}
593
594
bool sieve_variable_assign(struct sieve_variable_storage *storage,
595
         unsigned int index, const string_t *value)
596
0
{
597
0
  const struct ext_variables_context *extctx =
598
0
    ext_variables_get_context(storage->var_ext);
599
0
  string_t *varval;
600
601
0
  if (!sieve_variable_get_modifiable(storage, index, &varval))
602
0
    return FALSE;
603
604
0
  str_truncate(varval, 0);
605
0
  str_append_str(varval, value);
606
607
  /* Just a precaution, caller should prevent this in the first place */
608
0
  if (str_len(varval) > extctx->set->max_value_size)
609
0
    str_truncate_utf8(varval, extctx->set->max_value_size);
610
611
0
  return TRUE;
612
0
}
613
614
bool sieve_variable_assign_cstr(struct sieve_variable_storage *storage,
615
        unsigned int index, const char *value)
616
0
{
617
0
  const struct ext_variables_context *extctx =
618
0
    ext_variables_get_context(storage->var_ext);
619
0
  string_t *varval;
620
621
0
  if (!sieve_variable_get_modifiable(storage, index, &varval))
622
0
    return FALSE;
623
624
0
  str_truncate(varval, 0);
625
0
  str_append(varval, value);
626
627
  /* Just a precaution, caller should prevent this in the first place */
628
0
  if (str_len(varval) > extctx->set->max_value_size)
629
0
    str_truncate_utf8(varval, extctx->set->max_value_size);
630
631
0
  return TRUE;
632
0
}
633
634
/*
635
 * AST Context
636
 */
637
638
static void
639
ext_variables_ast_free(const struct sieve_extension *ext ATTR_UNUSED,
640
           struct sieve_ast *ast ATTR_UNUSED, void *context)
641
0
{
642
0
  struct sieve_variable_scope *local_scope =
643
0
    (struct sieve_variable_scope *)context;
644
645
  /* Unreference main variable scope */
646
0
  sieve_variable_scope_unref(&local_scope);
647
0
}
648
649
static const struct sieve_ast_extension variables_ast_extension = {
650
  &variables_extension,
651
  ext_variables_ast_free,
652
};
653
654
static struct sieve_variable_scope *
655
ext_variables_create_local_scope(const struct sieve_extension *this_ext,
656
         struct sieve_ast *ast)
657
0
{
658
0
  struct sieve_variable_scope *scope;
659
660
0
  scope = sieve_variable_scope_create(this_ext->svinst, this_ext, NULL);
661
662
0
  sieve_ast_extension_register(ast, this_ext, &variables_ast_extension,
663
0
             scope);
664
0
  return scope;
665
0
}
666
667
static struct sieve_variable_scope *
668
ext_variables_ast_get_local_scope(const struct sieve_extension *this_ext,
669
          struct sieve_ast *ast)
670
0
{
671
0
  struct sieve_variable_scope *local_scope =
672
0
    (struct sieve_variable_scope *)
673
0
      sieve_ast_extension_get_context(ast, this_ext);
674
675
0
  return local_scope;
676
0
}
677
678
/*
679
 * Validator context
680
 */
681
682
static struct ext_variables_validator_context *
683
ext_variables_validator_context_create(const struct sieve_extension *this_ext,
684
               struct sieve_validator *valdtr)
685
0
{
686
0
  pool_t pool = sieve_validator_pool(valdtr);
687
0
  struct ext_variables_validator_context *ctx;
688
0
  struct sieve_ast *ast = sieve_validator_ast(valdtr);
689
690
0
  ctx = p_new(pool, struct ext_variables_validator_context, 1);
691
0
  ctx->modifiers = sieve_validator_object_registry_create(valdtr);
692
0
  ctx->namespaces = sieve_validator_object_registry_create(valdtr);
693
0
  ctx->local_scope = ext_variables_create_local_scope(this_ext, ast);
694
695
0
  sieve_validator_extension_set_context(valdtr, this_ext, ctx);
696
0
  return ctx;
697
0
}
698
699
struct ext_variables_validator_context *
700
ext_variables_validator_context_get(const struct sieve_extension *this_ext,
701
            struct sieve_validator *valdtr)
702
0
{
703
0
  struct ext_variables_validator_context *ctx;
704
705
0
  i_assert(sieve_extension_is(this_ext, variables_extension));
706
0
  ctx = (struct ext_variables_validator_context *)
707
0
    sieve_validator_extension_get_context(valdtr, this_ext);
708
709
0
  if (ctx == NULL)
710
0
    ctx = ext_variables_validator_context_create(this_ext, valdtr);
711
0
  return ctx;
712
0
}
713
714
void ext_variables_validator_initialize(const struct sieve_extension *this_ext,
715
          struct sieve_validator *valdtr)
716
0
{
717
0
  struct ext_variables_validator_context *ctx;
718
719
  /* Create our context */
720
0
  ctx = ext_variables_validator_context_get(this_ext, valdtr);
721
722
0
  ext_variables_register_core_modifiers(this_ext, ctx);
723
724
0
  ctx->active = TRUE;
725
0
}
726
727
struct sieve_variable *ext_variables_validator_get_variable(
728
  const struct sieve_extension *this_ext,
729
  struct sieve_validator *validator, const char *variable)
730
0
{
731
0
  struct ext_variables_validator_context *ctx =
732
0
    ext_variables_validator_context_get(this_ext, validator);
733
734
0
  return sieve_variable_scope_get_variable(ctx->local_scope, variable);
735
0
}
736
737
struct sieve_variable *
738
ext_variables_validator_declare_variable(const struct sieve_extension *this_ext,
739
           struct sieve_validator *validator,
740
           const char *variable)
741
0
{
742
0
  struct ext_variables_validator_context *ctx =
743
0
    ext_variables_validator_context_get(this_ext, validator);
744
745
0
  return sieve_variable_scope_declare(ctx->local_scope, variable);
746
0
}
747
748
struct sieve_variable_scope *
749
sieve_ext_variables_get_local_scope(const struct sieve_extension *var_ext,
750
            struct sieve_validator *validator)
751
0
{
752
0
  struct ext_variables_validator_context *ctx =
753
0
    ext_variables_validator_context_get(var_ext, validator);
754
755
0
  return ctx->local_scope;
756
0
}
757
758
bool sieve_ext_variables_is_active(const struct sieve_extension *var_ext,
759
           struct sieve_validator *valdtr)
760
0
{
761
0
  struct ext_variables_validator_context *ctx =
762
0
    ext_variables_validator_context_get(var_ext, valdtr);
763
764
0
  return (ctx != NULL && ctx->active);
765
0
}
766
767
/*
768
 * Code generation
769
 */
770
771
bool ext_variables_generator_load(const struct sieve_extension *ext,
772
          const struct sieve_codegen_env *cgenv)
773
0
{
774
0
  struct sieve_variable_scope *local_scope =
775
0
    ext_variables_ast_get_local_scope(ext, cgenv->ast);
776
0
  unsigned int count = sieve_variable_scope_size(local_scope);
777
0
  sieve_size_t jump;
778
779
0
  sieve_binary_emit_unsigned(cgenv->sblock, count);
780
781
0
  jump = sieve_binary_emit_offset(cgenv->sblock, 0);
782
783
0
  if (count > 0) {
784
0
    unsigned int size, i;
785
0
    struct sieve_variable *const *vars =
786
0
      sieve_variable_scope_get_variables(local_scope, &size);
787
788
0
    for (i = 0; i < size; i++) {
789
0
      sieve_binary_emit_cstring(cgenv->sblock,
790
0
              vars[i]->identifier);
791
0
    }
792
0
  }
793
794
0
  sieve_binary_resolve_offset(cgenv->sblock, jump);
795
0
  return TRUE;
796
0
}
797
798
/*
799
 * Interpreter context
800
 */
801
802
struct ext_variables_interpreter_context {
803
  pool_t pool;
804
805
  struct sieve_variable_scope *local_scope;
806
  struct sieve_variable_scope_binary *local_scope_bin;
807
808
  struct sieve_variable_storage *local_storage;
809
  ARRAY(struct sieve_variable_storage *) ext_storages;
810
};
811
812
static void
813
ext_variables_interpreter_free(const struct sieve_extension *ext ATTR_UNUSED,
814
             struct sieve_interpreter *interp ATTR_UNUSED,
815
             void *context)
816
0
{
817
0
  struct ext_variables_interpreter_context *ctx =
818
0
    (struct ext_variables_interpreter_context *)context;
819
820
0
  sieve_variable_scope_binary_unref(&ctx->local_scope_bin);
821
0
}
822
823
static struct sieve_interpreter_extension
824
variables_interpreter_extension = {
825
  .ext_def = &variables_extension,
826
  .free = ext_variables_interpreter_free,
827
};
828
829
static struct ext_variables_interpreter_context *
830
ext_variables_interpreter_context_create(
831
  const struct sieve_extension *this_ext,
832
  struct sieve_interpreter *interp,
833
  struct sieve_variable_scope_binary *scpbin)
834
0
{
835
0
  pool_t pool = sieve_interpreter_pool(interp);
836
0
  struct ext_variables_interpreter_context *ctx;
837
838
0
  ctx = p_new(pool, struct ext_variables_interpreter_context, 1);
839
0
  ctx->pool = pool;
840
0
  ctx->local_scope = NULL;
841
0
  ctx->local_scope_bin = scpbin;
842
0
  ctx->local_storage =
843
0
    sieve_variable_storage_create(this_ext, pool, scpbin);
844
0
  p_array_init(&ctx->ext_storages, pool,
845
0
         sieve_extensions_get_count(this_ext->svinst));
846
847
0
  sieve_interpreter_extension_register(interp, this_ext,
848
0
               &variables_interpreter_extension,
849
0
               ctx);
850
0
  return ctx;
851
0
}
852
853
bool ext_variables_interpreter_load(const struct sieve_extension *ext,
854
            const struct sieve_runtime_env *renv,
855
            sieve_size_t *address)
856
0
{
857
0
  const struct sieve_execute_env *eenv = renv->exec_env;
858
0
  struct sieve_variable_scope_binary *scpbin;
859
860
0
  scpbin = sieve_variable_scope_binary_read(eenv->svinst, ext, NULL,
861
0
              renv->sblock, address);
862
0
  if (scpbin == NULL)
863
0
    return FALSE;
864
865
  /* Create our context */
866
0
  (void)ext_variables_interpreter_context_create(ext, renv->interp,
867
0
                   scpbin);
868
869
  /* Enable support for match values */
870
0
  (void)sieve_match_values_set_enabled(renv, TRUE);
871
872
0
  return TRUE;
873
0
}
874
875
static inline struct ext_variables_interpreter_context *
876
ext_variables_interpreter_context_get(const struct sieve_extension *this_ext,
877
              struct sieve_interpreter *interp)
878
0
{
879
0
  struct ext_variables_interpreter_context *ctx;
880
881
0
  i_assert(sieve_extension_is(this_ext, variables_extension));
882
0
  ctx = (struct ext_variables_interpreter_context *)
883
0
    sieve_interpreter_extension_get_context(interp, this_ext);
884
0
  return ctx;
885
0
}
886
887
struct sieve_variable_storage *
888
sieve_ext_variables_runtime_get_storage(const struct sieve_extension *var_ext,
889
          const struct sieve_runtime_env *renv,
890
          const struct sieve_extension *ext)
891
0
{
892
0
  struct ext_variables_interpreter_context *ctx =
893
0
    ext_variables_interpreter_context_get(var_ext, renv->interp);
894
0
  struct sieve_variable_storage *const *storage;
895
896
0
  if (ext == NULL)
897
0
    return ctx->local_storage;
898
899
0
  if (ext->id >= (int)array_count(&ctx->ext_storages))
900
0
    storage = NULL;
901
0
  else
902
0
    storage = array_idx(&ctx->ext_storages, ext->id);
903
904
0
  if (storage == NULL)
905
0
    return NULL;
906
0
  return *storage;
907
0
}
908
909
void sieve_ext_variables_runtime_set_storage(
910
  const struct sieve_extension *var_ext,
911
  const struct sieve_runtime_env *renv, const struct sieve_extension *ext,
912
  struct sieve_variable_storage *storage)
913
0
{
914
0
  struct ext_variables_interpreter_context *ctx =
915
0
    ext_variables_interpreter_context_get(var_ext, renv->interp);
916
917
0
  if (ctx == NULL || ext == NULL || storage == NULL)
918
0
    return;
919
0
  if (ext->id < 0)
920
0
    return;
921
922
0
  array_idx_set(&ctx->ext_storages, (unsigned int) ext->id, &storage);
923
0
}