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