diff options
Diffstat (limited to 'pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c')
-rw-r--r-- | pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c new file mode 100644 index 0000000..359f3bf --- /dev/null +++ b/pigeonhole/src/lib-sieve/plugins/variables/ext-variables-operands.c @@ -0,0 +1,279 @@ +/* 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-extensions.h" +#include "sieve-ast.h" +#include "sieve-binary.h" +#include "sieve-code.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-dump.h" +#include "ext-variables-operands.h" + +/* + * Variable operand + */ + +static bool opr_variable_dump + (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd, + sieve_size_t *address); +static int opr_variable_read_value + (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd, + sieve_size_t *address, string_t **str_r); + +const struct sieve_opr_string_interface variable_interface = { + opr_variable_dump, + opr_variable_read_value +}; + +const struct sieve_operand_def variable_operand = { + .name = "variable", + .ext_def = &variables_extension, + .code = EXT_VARIABLES_OPERAND_VARIABLE, + .class = &string_class, + .interface = &variable_interface +}; + +void sieve_variables_opr_variable_emit +(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext, + struct sieve_variable *var) +{ + i_assert( sieve_extension_is(var_ext, variables_extension) ); + + if ( var->ext == NULL ) { + /* Default variable storage */ + (void) sieve_operand_emit(sblock, var_ext, &variable_operand); + (void) sieve_binary_emit_byte(sblock, 0); /* Default */ + (void) sieve_binary_emit_unsigned(sblock, var->index); + return; + } + + (void) sieve_operand_emit(sblock, var_ext, &variable_operand); + (void) sieve_binary_emit_extension(sblock, var->ext, 1); /* Extension */ + (void) sieve_binary_emit_unsigned(sblock, var->index); +} + +static bool opr_variable_dump +(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd, + sieve_size_t *address) +{ + const struct sieve_extension *this_ext = oprnd->ext; + unsigned int index = 0; + const struct sieve_extension *ext; + unsigned int code = 1; /* Initially set to offset value */ + const char *identifier; + + if ( !sieve_binary_read_extension(denv->sblock, address, &code, &ext) ) + return FALSE; + + if ( !sieve_binary_read_unsigned(denv->sblock, address, &index) ) + return FALSE; + + identifier = ext_variables_dump_get_identifier(this_ext, denv, ext, index); + identifier = identifier == NULL ? "??" : identifier; + + if ( oprnd->field_name != NULL ) + sieve_code_dumpf(denv, "%s: VAR[%s] ${%s}", + oprnd->field_name, sieve_ext_variables_get_varid(ext, index), identifier); + else + sieve_code_dumpf(denv, "VAR[%s] ${%s}", + sieve_ext_variables_get_varid(ext, index), identifier); + + return TRUE; +} + +static int opr_variable_read_value +(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd, + sieve_size_t *address, string_t **str_r) +{ + const struct sieve_extension *this_ext = oprnd->ext; + const struct sieve_extension *ext; + unsigned int code = 1; /* Initially set to offset value */ + struct sieve_variable_storage *storage; + unsigned int index = 0; + + if ( !sieve_binary_read_extension(renv->sblock, address, &code, &ext) ) { + sieve_runtime_trace_operand_error(renv, oprnd, + "variable operand corrupt: invalid extension byte"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + storage = sieve_ext_variables_runtime_get_storage + (this_ext, renv, ext); + if ( storage == NULL ) { + sieve_runtime_trace_operand_error(renv, oprnd, + "variable operand corrupt: extension has no storage"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + if ( sieve_binary_read_unsigned(renv->sblock, address, &index) ) { + /* Parameter str can be NULL if we are requested to only skip and not + * actually read the argument. + */ + if ( str_r != NULL ) { + if ( !sieve_variable_get(storage, index, str_r) ) + return SIEVE_EXEC_FAILURE; + + if ( *str_r == NULL ) *str_r = t_str_new(0); + } + + return SIEVE_EXEC_OK; + } + + sieve_runtime_trace_operand_error(renv, oprnd, + "variable operand corrupt: invalid variable index"); + return SIEVE_EXEC_BIN_CORRUPT; +} + +int sieve_variable_operand_read_data +(const struct sieve_runtime_env *renv, struct sieve_operand *oprnd, + sieve_size_t *address, const char *field_name, + struct sieve_variable_storage **storage_r, unsigned int *var_index_r) +{ + const struct sieve_extension *ext; + unsigned int code = 1; /* Initially set to offset value */ + unsigned int idx = 0; + + oprnd->field_name = field_name; + + if ( !sieve_operand_is_variable(oprnd) ) { + sieve_runtime_trace_operand_error(renv, oprnd, + "expected variable operand but found %s", sieve_operand_name(oprnd)); + return SIEVE_EXEC_BIN_CORRUPT; + } + + if ( !sieve_binary_read_extension(renv->sblock, address, &code, &ext) ) { + sieve_runtime_trace_operand_error(renv, oprnd, + "variable operand corrupt: invalid extension byte"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + *storage_r = sieve_ext_variables_runtime_get_storage + (oprnd->ext, renv, ext); + if ( *storage_r == NULL ) { + sieve_runtime_trace_operand_error(renv, oprnd, + "variable operand corrupt: extension has no storage"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + if ( !sieve_binary_read_unsigned(renv->sblock, address, &idx) ) { + sieve_runtime_trace_operand_error(renv, oprnd, + "variable operand corrupt: invalid variable index"); + return SIEVE_EXEC_BIN_CORRUPT; + } + + *var_index_r = idx; + return SIEVE_EXEC_OK; +} + +int sieve_variable_operand_read +(const struct sieve_runtime_env *renv, sieve_size_t *address, + const char *field_name, struct sieve_variable_storage **storage_r, + unsigned int *var_index_r) +{ + struct sieve_operand operand; + int ret; + + if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand)) + <= 0) + return ret; + + return sieve_variable_operand_read_data + (renv, &operand, address, field_name, storage_r, var_index_r); +} + +/* + * Match value operand + */ + +static bool opr_match_value_dump + (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd, + sieve_size_t *address); +static int opr_match_value_read + (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd, + sieve_size_t *address, string_t **str_r); + +const struct sieve_opr_string_interface match_value_interface = { + opr_match_value_dump, + opr_match_value_read +}; + +const struct sieve_operand_def match_value_operand = { + .name = "match-value", + .ext_def = &variables_extension, + .code = EXT_VARIABLES_OPERAND_MATCH_VALUE, + .class = &string_class, + .interface = &match_value_interface +}; + +void sieve_variables_opr_match_value_emit +(struct sieve_binary_block *sblock, const struct sieve_extension *var_ext, + unsigned int index) +{ + i_assert( sieve_extension_is(var_ext, variables_extension) ); + (void) sieve_operand_emit(sblock, var_ext, &match_value_operand); + (void) sieve_binary_emit_unsigned(sblock, index); +} + +static bool opr_match_value_dump +(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd, + sieve_size_t *address) +{ + unsigned int index = 0; + + if (sieve_binary_read_unsigned(denv->sblock, address, &index) ) { + if ( oprnd->field_name != NULL ) + sieve_code_dumpf + (denv, "%s: MATCHVAL %lu", oprnd->field_name, (unsigned long) index); + else + sieve_code_dumpf(denv, "MATCHVAL %lu", (unsigned long) index); + + return TRUE; + } + + return FALSE; +} + +static int opr_match_value_read +(const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd, + sieve_size_t *address, string_t **str_r) +{ + const struct sieve_extension *this_ext = oprnd->ext; + const struct ext_variables_config *config = + ext_variables_get_config(this_ext); + unsigned int index = 0; + + if ( sieve_binary_read_unsigned(renv->sblock, address, &index) ) { + /* Parameter str can be NULL if we are requested to only skip and not + * actually read the argument. + */ + if ( str_r != NULL ) { + sieve_match_values_get(renv, index, str_r); + + if ( *str_r == NULL ) + *str_r = t_str_new(0); + else if ( str_len(*str_r) > config->max_variable_size ) + str_truncate_utf8(*str_r, config->max_variable_size); + } + + return SIEVE_EXEC_OK; + } + + sieve_runtime_trace_operand_error(renv, oprnd, + "match value operand corrupt: invalid index data"); + return SIEVE_EXEC_BIN_CORRUPT; +} |