diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c | 950 |
1 files changed, 950 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c new file mode 100644 index 0000000..be9f677 --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-common.c @@ -0,0 +1,950 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "hash.h" +#include "str.h" +#include "array.h" + +#include "sieve-common.h" +#include "sieve-settings.h" + +#include "sieve-ast.h" +#include "sieve-binary.h" +#include "sieve-code.h" +#include "sieve-objects.h" +#include "sieve-match-types.h" + +#include "sieve-commands.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-dump.h" +#include "sieve-interpreter.h" + +#include "ext-variables-common.h" +#include "ext-variables-limits.h" +#include "ext-variables-name.h" +#include "ext-variables-modifiers.h" + +/* + * Limits + */ + +unsigned int +sieve_variables_get_max_scope_size(const struct sieve_extension *var_ext) +{ + const struct ext_variables_config *config = + ext_variables_get_config(var_ext); + + return config->max_scope_size; +} + +size_t +sieve_variables_get_max_variable_size(const struct sieve_extension *var_ext) +{ + const struct ext_variables_config *config = + ext_variables_get_config(var_ext); + + return config->max_variable_size; +} + +/* + * Extension configuration + */ + +bool +ext_variables_load(const struct sieve_extension *ext, void **context) +{ + struct sieve_instance *svinst = ext->svinst; + struct ext_variables_config *config; + unsigned long long int uint_setting; + size_t size_setting; + + if (*context != NULL) + ext_variables_unload(ext); + + config = i_new(struct ext_variables_config, 1); + + /* Get limits */ + config->max_scope_size = EXT_VARIABLES_DEFAULT_MAX_SCOPE_SIZE; + config->max_variable_size = EXT_VARIABLES_DEFAULT_MAX_VARIABLE_SIZE; + + if (sieve_setting_get_uint_value( + svinst, "sieve_variables_max_scope_size", &uint_setting)) { + if (uint_setting < EXT_VARIABLES_REQUIRED_MAX_SCOPE_SIZE) { + e_warning(svinst->event, "variables: " + "setting sieve_variables_max_scope_size " + "is lower than required by standards " + "(>= %llu items)", + (unsigned long long)EXT_VARIABLES_REQUIRED_MAX_SCOPE_SIZE); + } else { + config->max_scope_size = (unsigned int)uint_setting; + } + } + + if (sieve_setting_get_size_value( + svinst, "sieve_variables_max_variable_size", &size_setting)) { + if (size_setting < EXT_VARIABLES_REQUIRED_MAX_VARIABLE_SIZE) { + e_warning(svinst->event, "variables: " + "setting sieve_variables_max_variable_size " + "is lower than required by standards " + "(>= %zu bytes)", + (size_t)EXT_VARIABLES_REQUIRED_MAX_VARIABLE_SIZE); + } else { + config->max_variable_size = size_setting; + } + } + + *context = (void *)config; + return TRUE; +} + +void ext_variables_unload(const struct sieve_extension *ext) +{ + struct ext_variables_config *config = + (struct ext_variables_config *)ext->context; + + i_free(config); +} + +const struct ext_variables_config * +ext_variables_get_config(const struct sieve_extension *var_ext) +{ + const struct ext_variables_config *config = + (const struct ext_variables_config *)var_ext->context; + + i_assert(var_ext->def == &variables_extension); + return config; +} + +/* + * Variable scope + */ + +struct sieve_variable_scope { + pool_t pool; + int refcount; + + struct sieve_instance *svinst; + const struct sieve_extension *var_ext; + const struct sieve_extension *ext; + + struct sieve_variable *error_var; + + HASH_TABLE(const char *, struct sieve_variable *) variables; + ARRAY(struct sieve_variable *) variable_index; +}; + +struct sieve_variable_scope_binary { + struct sieve_variable_scope *scope; + + unsigned int size; + struct sieve_binary_block *sblock; + sieve_size_t address; +}; + +struct sieve_variable_scope_iter { + struct sieve_variable_scope *scope; + struct hash_iterate_context *hctx; +}; + +struct sieve_variable_scope * +sieve_variable_scope_create(struct sieve_instance *svinst, + const struct sieve_extension *var_ext, + const struct sieve_extension *ext) +{ + struct sieve_variable_scope *scope; + pool_t pool; + + i_assert(var_ext->def == &variables_extension); + + pool = pool_alloconly_create("sieve_variable_scope", 4096); + scope = p_new(pool, struct sieve_variable_scope, 1); + scope->pool = pool; + scope->refcount = 1; + + scope->svinst = svinst; + scope->var_ext = var_ext; + scope->ext = ext; + + hash_table_create(&scope->variables, pool, 0, strcase_hash, strcasecmp); + p_array_init(&scope->variable_index, pool, 128); + + return scope; +} + +void sieve_variable_scope_ref(struct sieve_variable_scope *scope) +{ + scope->refcount++; +} + +void sieve_variable_scope_unref(struct sieve_variable_scope **_scope) +{ + struct sieve_variable_scope *scope = *_scope; + + i_assert(scope->refcount > 0); + + if (--scope->refcount != 0) + return; + + hash_table_destroy(&scope->variables); + + *_scope = NULL; + pool_unref(&scope->pool); +} + +pool_t sieve_variable_scope_pool(struct sieve_variable_scope *scope) +{ + return scope->pool; +} + +struct sieve_variable * +sieve_variable_scope_declare(struct sieve_variable_scope *scope, + const char *identifier) +{ + unsigned int max_scope_size; + struct sieve_variable *var; + + var = hash_table_lookup(scope->variables, identifier); + if (var != NULL) + return var; + + max_scope_size = sieve_variables_get_max_scope_size(scope->var_ext); + if (array_count(&scope->variable_index) >= max_scope_size) { + if (scope->error_var == NULL) { + var = p_new(scope->pool, struct sieve_variable, 1); + var->identifier = "@ERROR@"; + var->index = 0; + + scope->error_var = var; + return NULL; + } + + return scope->error_var; + } + + var = p_new(scope->pool, struct sieve_variable, 1); + var->ext = scope->ext; + var->identifier = p_strdup(scope->pool, identifier); + var->index = array_count(&scope->variable_index); + + hash_table_insert(scope->variables, var->identifier, var); + array_append(&scope->variable_index, &var, 1); + return var; +} + +struct sieve_variable * +sieve_variable_scope_get_variable(struct sieve_variable_scope *scope, + const char *identifier) +{ + return hash_table_lookup(scope->variables, identifier); +} + +struct sieve_variable * +sieve_variable_scope_import(struct sieve_variable_scope *scope, + struct sieve_variable *var) +{ + struct sieve_variable *old_var, *new_var; + + old_var = sieve_variable_scope_get_variable(scope, var->identifier); + if (old_var != NULL) { + i_assert(memcmp(old_var, var, sizeof(*var)) == 0); + return old_var; + } + + new_var = p_new(scope->pool, struct sieve_variable, 1); + memcpy(new_var, var, sizeof(*new_var)); + + hash_table_insert(scope->variables, new_var->identifier, new_var); + + /* Not entered into the index because it is an external variable + (This can be done unlimited; only limited by the size of the external + scope) + */ + return new_var; +} + +struct sieve_variable_scope_iter * +sieve_variable_scope_iterate_init(struct sieve_variable_scope *scope) +{ + struct sieve_variable_scope_iter *iter; + + iter = t_new(struct sieve_variable_scope_iter, 1); + iter->scope = scope; + iter->hctx = hash_table_iterate_init(scope->variables); + + return iter; +} + +bool sieve_variable_scope_iterate(struct sieve_variable_scope_iter *iter, + struct sieve_variable **var_r) +{ + const char *key; + + return hash_table_iterate(iter->hctx, iter->scope->variables, + &key, var_r); +} + +void sieve_variable_scope_iterate_deinit( + struct sieve_variable_scope_iter **iter) +{ + hash_table_iterate_deinit(&(*iter)->hctx); + *iter = NULL; +} + +unsigned int +sieve_variable_scope_declarations(struct sieve_variable_scope *scope) +{ + return hash_table_count(scope->variables); +} + +unsigned int sieve_variable_scope_size(struct sieve_variable_scope *scope) +{ + return array_count(&scope->variable_index); +} + +struct sieve_variable * const * +sieve_variable_scope_get_variables(struct sieve_variable_scope *scope, + unsigned int *size_r) +{ + return array_get(&scope->variable_index, size_r); +} + +struct sieve_variable * +sieve_variable_scope_get_indexed(struct sieve_variable_scope *scope, + unsigned int index) +{ + struct sieve_variable * const *var; + + if (index >= array_count(&scope->variable_index)) + return NULL; + + var = array_idx(&scope->variable_index, index); + return *var; +} + +/* Scope binary */ + +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) +{ + struct sieve_variable_scope *local_scope; + unsigned int i, scope_size; + sieve_size_t pc; + sieve_offset_t end_offset; + + /* Read scope size */ + sieve_code_mark(denv); + if (!sieve_binary_read_unsigned(denv->sblock, address, &scope_size)) + return NULL; + + /* Read offset */ + pc = *address; + if (!sieve_binary_read_offset(denv->sblock, address, &end_offset)) + return NULL; + + /* Create scope */ + local_scope = sieve_variable_scope_create(svinst, var_ext, ext); + + /* Read and dump scope itself */ + + sieve_code_dumpf(denv, "VARIABLES SCOPE [%u] (end: %08x)", + scope_size, (unsigned int)(pc + end_offset)); + + for (i = 0; i < scope_size; i++) { + string_t *identifier; + + sieve_code_mark(denv); + if (!sieve_binary_read_string(denv->sblock, address, + &identifier)) + return NULL; + + sieve_code_dumpf(denv, "%3d: '%s'", i, str_c(identifier)); + + (void)sieve_variable_scope_declare(local_scope, + str_c(identifier)); + } + + return local_scope; +} + +struct sieve_variable_scope_binary * +sieve_variable_scope_binary_create(struct sieve_variable_scope *scope) +{ + struct sieve_variable_scope_binary *scpbin; + + scpbin = p_new(scope->pool, struct sieve_variable_scope_binary, 1); + scpbin->scope = scope; + + return scpbin; +} + +void sieve_variable_scope_binary_ref(struct sieve_variable_scope_binary *scpbin) +{ + sieve_variable_scope_ref(scpbin->scope); +} + +void sieve_variable_scope_binary_unref( + struct sieve_variable_scope_binary **scpbin) +{ + sieve_variable_scope_unref(&(*scpbin)->scope); + *scpbin = NULL; +} + +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) +{ + struct sieve_variable_scope *scope; + struct sieve_variable_scope_binary *scpbin; + unsigned int scope_size, max_scope_size; + const char *ext_name = (ext == NULL ? "variables" : + sieve_extension_name(ext)); + sieve_size_t pc; + sieve_offset_t end_offset; + + /* Read scope size */ + if (!sieve_binary_read_unsigned(sblock, address, &scope_size)) { + e_error(svinst->event, "%s: " + "variable scope: failed to read size", ext_name); + return NULL; + } + + /* Check size limit */ + max_scope_size = sieve_variables_get_max_scope_size(var_ext); + if (scope_size > max_scope_size) { + e_error(svinst->event, "%s: " + "variable scope: size exceeds the limit (%u > %u)", + ext_name, scope_size, max_scope_size); + return NULL; + } + + /* Read offset */ + pc = *address; + if (!sieve_binary_read_offset(sblock, address, &end_offset)) { + e_error(svinst->event, "%s: " + "variable scope: failed to read end offset", ext_name); + return NULL; + } + + /* Create scope */ + scope = sieve_variable_scope_create(svinst, var_ext, ext); + + scpbin = sieve_variable_scope_binary_create(scope); + scpbin->size = scope_size; + scpbin->sblock = sblock; + scpbin->address = *address; + + *address = pc + end_offset; + + return scpbin; +} + +struct sieve_variable_scope * +sieve_variable_scope_binary_get(struct sieve_variable_scope_binary *scpbin) +{ + const struct sieve_extension *ext = scpbin->scope->ext; + struct sieve_instance *svinst = scpbin->scope->svinst; + const char *ext_name = (ext == NULL ? "variables" : + sieve_extension_name(ext)); + unsigned int i; + + if (scpbin->sblock != NULL) { + sieve_size_t *address = &scpbin->address; + + /* Read scope itself */ + for (i = 0; i < scpbin->size; i++) { + struct sieve_variable *var; + string_t *identifier; + + if (!sieve_binary_read_string(scpbin->sblock, address, + &identifier)) { + e_error(svinst->event, "%s: variable scope: " + "failed to read variable name", + ext_name); + return NULL; + } + + var = sieve_variable_scope_declare(scpbin->scope, + str_c(identifier)); + + i_assert(var != NULL); + i_assert(var->index == i); + } + + scpbin->sblock = NULL; + } + + return scpbin->scope; +} + +unsigned int +sieve_variable_scope_binary_get_size( + struct sieve_variable_scope_binary *scpbin) +{ + if (scpbin->sblock != NULL) + return scpbin->size; + + return array_count(&scpbin->scope->variable_index); +} + +/* + * Variable storage + */ + +struct sieve_variable_storage { + pool_t pool; + const struct sieve_extension *var_ext; + struct sieve_variable_scope *scope; + struct sieve_variable_scope_binary *scope_bin; + unsigned int max_size; + ARRAY(string_t *) var_values; +}; + +struct sieve_variable_storage * +sieve_variable_storage_create(const struct sieve_extension *var_ext, + pool_t pool, + struct sieve_variable_scope_binary *scpbin) +{ + struct sieve_variable_storage *storage; + + storage = p_new(pool, struct sieve_variable_storage, 1); + storage->pool = pool; + storage->var_ext = var_ext; + storage->scope_bin = scpbin; + storage->scope = NULL; + + storage->max_size = sieve_variable_scope_binary_get_size(scpbin); + + p_array_init(&storage->var_values, pool, 4); + + return storage; +} + +static inline bool +sieve_variable_valid(struct sieve_variable_storage *storage, + unsigned int index) +{ + if (storage->scope_bin == NULL) + return TRUE; + + return (index < storage->max_size); +} + +bool sieve_variable_get_identifier(struct sieve_variable_storage *storage, + unsigned int index, const char **identifier) +{ + struct sieve_variable * const *var; + + *identifier = NULL; + + if (storage->scope_bin == NULL) + return TRUE; + + if (storage->scope == NULL) { + storage->scope = + sieve_variable_scope_binary_get(storage->scope_bin); + if (storage->scope == NULL) + return FALSE; + } + + /* FIXME: direct invasion of the scope object is a bit ugly */ + if (index >= array_count(&storage->scope->variable_index)) + return FALSE; + + var = array_idx(&storage->scope->variable_index, index); + if (*var != NULL) + *identifier = (*var)->identifier; + return TRUE; +} + +const char * +sieve_variable_get_varid(struct sieve_variable_storage *storage, + unsigned int index) +{ + if (storage->scope_bin == NULL) + return t_strdup_printf("%ld", (long)index); + + if (storage->scope == NULL) { + storage->scope = + sieve_variable_scope_binary_get(storage->scope_bin); + if (storage->scope == NULL) + return NULL; + } + + return sieve_ext_variables_get_varid(storage->scope->ext, index); +} + +bool sieve_variable_get(struct sieve_variable_storage *storage, + unsigned int index, string_t **value) +{ + *value = NULL; + + if (index < array_count(&storage->var_values)) { + string_t * const *varent; + + varent = array_idx(&storage->var_values, index); + + *value = *varent; + } else if (!sieve_variable_valid(storage, index)) { + return FALSE; + } + + return TRUE; +} + +bool sieve_variable_get_modifiable(struct sieve_variable_storage *storage, + unsigned int index, string_t **value) +{ + string_t *dummy; + + if (value == NULL) + value = &dummy; + + if (!sieve_variable_get(storage, index, value)) + return FALSE; + + if (*value == NULL) { + *value = str_new(storage->pool, 256); + array_idx_set(&storage->var_values, index, value); + } + return TRUE; +} + +bool sieve_variable_assign(struct sieve_variable_storage *storage, + unsigned int index, const string_t *value) +{ + const struct ext_variables_config *config = + ext_variables_get_config(storage->var_ext); + string_t *varval; + + if (!sieve_variable_get_modifiable(storage, index, &varval)) + return FALSE; + + str_truncate(varval, 0); + str_append_str(varval, value); + + /* Just a precaution, caller should prevent this in the first place */ + if (str_len(varval) > config->max_variable_size) + str_truncate_utf8(varval, config->max_variable_size); + + return TRUE; +} + +bool sieve_variable_assign_cstr(struct sieve_variable_storage *storage, + unsigned int index, const char *value) +{ + const struct ext_variables_config *config = + ext_variables_get_config(storage->var_ext); + string_t *varval; + + if (!sieve_variable_get_modifiable(storage, index, &varval)) + return FALSE; + + str_truncate(varval, 0); + str_append(varval, value); + + /* Just a precaution, caller should prevent this in the first place */ + if (str_len(varval) > config->max_variable_size) + str_truncate_utf8(varval, config->max_variable_size); + + return TRUE; +} + +/* + * AST Context + */ + +static void +ext_variables_ast_free(const struct sieve_extension *ext ATTR_UNUSED, + struct sieve_ast *ast ATTR_UNUSED, void *context) +{ + struct sieve_variable_scope *local_scope = + (struct sieve_variable_scope *)context; + + /* Unreference main variable scope */ + sieve_variable_scope_unref(&local_scope); +} + +static const struct sieve_ast_extension variables_ast_extension = { + &variables_extension, + ext_variables_ast_free +}; + +static struct sieve_variable_scope * +ext_variables_create_local_scope(const struct sieve_extension *this_ext, + struct sieve_ast *ast) +{ + struct sieve_variable_scope *scope; + + scope = sieve_variable_scope_create(this_ext->svinst, this_ext, NULL); + + sieve_ast_extension_register(ast, this_ext, &variables_ast_extension, + (void *)scope); + return scope; +} + +static struct sieve_variable_scope * +ext_variables_ast_get_local_scope(const struct sieve_extension *this_ext, + struct sieve_ast *ast) +{ + struct sieve_variable_scope *local_scope = + (struct sieve_variable_scope *) + sieve_ast_extension_get_context(ast, this_ext); + + return local_scope; +} + +/* + * Validator context + */ + +static struct ext_variables_validator_context * +ext_variables_validator_context_create(const struct sieve_extension *this_ext, + struct sieve_validator *valdtr) +{ + pool_t pool = sieve_validator_pool(valdtr); + struct ext_variables_validator_context *ctx; + struct sieve_ast *ast = sieve_validator_ast(valdtr); + + ctx = p_new(pool, struct ext_variables_validator_context, 1); + ctx->modifiers = sieve_validator_object_registry_create(valdtr); + ctx->namespaces = sieve_validator_object_registry_create(valdtr); + ctx->local_scope = ext_variables_create_local_scope(this_ext, ast); + + sieve_validator_extension_set_context(valdtr, this_ext, (void *)ctx); + return ctx; +} + +struct ext_variables_validator_context * +ext_variables_validator_context_get(const struct sieve_extension *this_ext, + struct sieve_validator *valdtr) +{ + struct ext_variables_validator_context *ctx; + + i_assert(sieve_extension_is(this_ext, variables_extension)); + ctx = (struct ext_variables_validator_context *) + sieve_validator_extension_get_context(valdtr, this_ext); + + if (ctx == NULL) + ctx = ext_variables_validator_context_create(this_ext, valdtr); + return ctx; +} + +void ext_variables_validator_initialize(const struct sieve_extension *this_ext, + struct sieve_validator *valdtr) +{ + struct ext_variables_validator_context *ctx; + + /* Create our context */ + ctx = ext_variables_validator_context_get(this_ext, valdtr); + + ext_variables_register_core_modifiers(this_ext, ctx); + + ctx->active = TRUE; +} + +struct sieve_variable *ext_variables_validator_get_variable( + const struct sieve_extension *this_ext, + struct sieve_validator *validator, const char *variable) +{ + struct ext_variables_validator_context *ctx = + ext_variables_validator_context_get(this_ext, validator); + + return sieve_variable_scope_get_variable(ctx->local_scope, variable); +} + +struct sieve_variable * +ext_variables_validator_declare_variable(const struct sieve_extension *this_ext, + struct sieve_validator *validator, + const char *variable) +{ + struct ext_variables_validator_context *ctx = + ext_variables_validator_context_get(this_ext, validator); + + return sieve_variable_scope_declare(ctx->local_scope, variable); +} + +struct sieve_variable_scope * +sieve_ext_variables_get_local_scope(const struct sieve_extension *var_ext, + struct sieve_validator *validator) +{ + struct ext_variables_validator_context *ctx = + ext_variables_validator_context_get(var_ext, validator); + + return ctx->local_scope; +} + +bool sieve_ext_variables_is_active(const struct sieve_extension *var_ext, + struct sieve_validator *valdtr) +{ + struct ext_variables_validator_context *ctx = + ext_variables_validator_context_get(var_ext, valdtr); + + return (ctx != NULL && ctx->active); +} + +/* + * Code generation + */ + +bool ext_variables_generator_load(const struct sieve_extension *ext, + const struct sieve_codegen_env *cgenv) +{ + struct sieve_variable_scope *local_scope = + ext_variables_ast_get_local_scope(ext, cgenv->ast); + unsigned int count = sieve_variable_scope_size(local_scope); + sieve_size_t jump; + + sieve_binary_emit_unsigned(cgenv->sblock, count); + + jump = sieve_binary_emit_offset(cgenv->sblock, 0); + + if (count > 0) { + unsigned int size, i; + struct sieve_variable *const *vars = + sieve_variable_scope_get_variables(local_scope, &size); + + for (i = 0; i < size; i++) { + sieve_binary_emit_cstring(cgenv->sblock, + vars[i]->identifier); + } + } + + sieve_binary_resolve_offset(cgenv->sblock, jump); + return TRUE; +} + +/* + * Interpreter context + */ + +struct ext_variables_interpreter_context { + pool_t pool; + + struct sieve_variable_scope *local_scope; + struct sieve_variable_scope_binary *local_scope_bin; + + struct sieve_variable_storage *local_storage; + ARRAY(struct sieve_variable_storage *) ext_storages; +}; + +static void +ext_variables_interpreter_free(const struct sieve_extension *ext ATTR_UNUSED, + struct sieve_interpreter *interp ATTR_UNUSED, + void *context) +{ + struct ext_variables_interpreter_context *ctx = + (struct ext_variables_interpreter_context *)context; + + sieve_variable_scope_binary_unref(&ctx->local_scope_bin); +} + +static struct sieve_interpreter_extension +variables_interpreter_extension = { + .ext_def = &variables_extension, + .free = ext_variables_interpreter_free +}; + +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) +{ + pool_t pool = sieve_interpreter_pool(interp); + struct ext_variables_interpreter_context *ctx; + + ctx = p_new(pool, struct ext_variables_interpreter_context, 1); + ctx->pool = pool; + ctx->local_scope = NULL; + ctx->local_scope_bin = scpbin; + ctx->local_storage = + sieve_variable_storage_create(this_ext, pool, scpbin); + p_array_init(&ctx->ext_storages, pool, + sieve_extensions_get_count(this_ext->svinst)); + + sieve_interpreter_extension_register(interp, this_ext, + &variables_interpreter_extension, + (void *)ctx); + return ctx; +} + +bool ext_variables_interpreter_load(const struct sieve_extension *ext, + const struct sieve_runtime_env *renv, + sieve_size_t *address) +{ + const struct sieve_execute_env *eenv = renv->exec_env; + struct sieve_variable_scope_binary *scpbin; + + scpbin = sieve_variable_scope_binary_read(eenv->svinst, ext, NULL, + renv->sblock, address); + if (scpbin == NULL) + return FALSE; + + /* Create our context */ + (void)ext_variables_interpreter_context_create(ext, renv->interp, + scpbin); + + /* Enable support for match values */ + (void)sieve_match_values_set_enabled(renv, TRUE); + + return TRUE; +} + +static inline struct ext_variables_interpreter_context * +ext_variables_interpreter_context_get(const struct sieve_extension *this_ext, + struct sieve_interpreter *interp) +{ + struct ext_variables_interpreter_context *ctx; + + i_assert(sieve_extension_is(this_ext, variables_extension)); + ctx = (struct ext_variables_interpreter_context *) + sieve_interpreter_extension_get_context(interp, this_ext); + return ctx; +} + +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) +{ + struct ext_variables_interpreter_context *ctx = + ext_variables_interpreter_context_get(var_ext, renv->interp); + struct sieve_variable_storage * const *storage; + + if (ext == NULL) + return ctx->local_storage; + + if (ext->id >= (int)array_count(&ctx->ext_storages)) + storage = NULL; + else + storage = array_idx(&ctx->ext_storages, ext->id); + + if (storage == NULL) + return NULL; + return *storage; +} + +void 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) +{ + struct ext_variables_interpreter_context *ctx = + ext_variables_interpreter_context_get(var_ext, renv->interp); + + if (ctx == NULL || ext == NULL || storage == NULL) + return; + if (ext->id < 0) + return; + + array_idx_set(&ctx->ext_storages, (unsigned int) ext->id, &storage); +} |