diff options
Diffstat (limited to 'pigeonhole/src/testsuite/testsuite-substitutions.c')
-rw-r--r-- | pigeonhole/src/testsuite/testsuite-substitutions.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/pigeonhole/src/testsuite/testsuite-substitutions.c b/pigeonhole/src/testsuite/testsuite-substitutions.c new file mode 100644 index 0000000..b165587 --- /dev/null +++ b/pigeonhole/src/testsuite/testsuite-substitutions.c @@ -0,0 +1,253 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" + +#include "sieve.h" +#include "sieve-code.h" +#include "sieve-commands.h" +#include "sieve-binary.h" +#include "sieve-generator.h" +#include "sieve-interpreter.h" +#include "sieve-dump.h" + +#include "testsuite-common.h" +#include "testsuite-substitutions.h" + +/* + * Forward declarations + */ + +void testsuite_opr_substitution_emit + (struct sieve_binary_block *sblock, const struct testsuite_substitution *tsub, + const char *param); + +/* + * Testsuite substitutions + */ + +/* FIXME: make this extendible */ + +enum { + TESTSUITE_SUBSTITUTION_FILE, +}; + +static const struct testsuite_substitution_def testsuite_file_substitution; + +static const struct testsuite_substitution_def *substitutions[] = { + &testsuite_file_substitution, +}; + +static const unsigned int substitutions_count = N_ELEMENTS(substitutions); + +static inline const struct testsuite_substitution_def * +testsuite_substitution_get +(unsigned int code) +{ + if ( code >= substitutions_count ) + return NULL; + + return substitutions[code]; +} + +static const struct testsuite_substitution *testsuite_substitution_create +(struct sieve_ast *ast, const char *identifier) +{ + unsigned int i; + + for ( i = 0; i < substitutions_count; i++ ) { + if ( strcasecmp(substitutions[i]->obj_def.identifier, identifier) == 0 ) { + const struct testsuite_substitution_def *tsub_def = substitutions[i]; + struct testsuite_substitution *tsub; + + tsub = p_new(sieve_ast_pool(ast), struct testsuite_substitution, 1); + tsub->object.def = &tsub_def->obj_def; + tsub->object.ext = testsuite_ext; + tsub->def = tsub_def; + + return tsub; + } + } + + return NULL; +} + +/* + * Substitution argument + */ + +static bool arg_testsuite_substitution_generate + (const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, + struct sieve_command *context); + +struct _testsuite_substitution_context { + const struct testsuite_substitution *tsub; + const char *param; +}; + +const struct sieve_argument_def testsuite_substitution_argument = { + .identifier = "@testsuite-substitution", + .generate = arg_testsuite_substitution_generate +}; + +struct sieve_ast_argument *testsuite_substitution_argument_create +(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_ast *ast, + unsigned int source_line, const char *substitution, const char *param) +{ + const struct testsuite_substitution *tsub; + struct _testsuite_substitution_context *tsctx; + struct sieve_ast_argument *arg; + pool_t pool; + + tsub = testsuite_substitution_create(ast, substitution); + if ( tsub == NULL ) + return NULL; + + arg = sieve_ast_argument_create(ast, source_line); + arg->type = SAAT_STRING; + + pool = sieve_ast_pool(ast); + tsctx = p_new(pool, struct _testsuite_substitution_context, 1); + tsctx->tsub = tsub; + tsctx->param = p_strdup(pool, param); + + arg->argument = sieve_argument_create + (ast, &testsuite_substitution_argument, testsuite_ext, 0); + arg->argument->data = (void *) tsctx; + + return arg; +} + +static bool arg_testsuite_substitution_generate +(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, + struct sieve_command *context ATTR_UNUSED) +{ + struct _testsuite_substitution_context *tsctx = + (struct _testsuite_substitution_context *) arg->argument->data; + + testsuite_opr_substitution_emit(cgenv->sblock, tsctx->tsub, tsctx->param); + + return TRUE; +} + +/* + * Substitution operand + */ + +static bool opr_substitution_dump + (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd, + sieve_size_t *address); +static int opr_substitution_read_value + (const struct sieve_runtime_env *renv, const struct sieve_operand *oprnd, + sieve_size_t *address, string_t **str); + +const struct sieve_opr_string_interface testsuite_substitution_interface = { + opr_substitution_dump, + opr_substitution_read_value +}; + +const struct sieve_operand_def testsuite_substitution_operand = { + .name = "test-substitution", + .ext_def = &testsuite_extension, + .code = TESTSUITE_OPERAND_SUBSTITUTION, + .class = &string_class, + .interface = &testsuite_substitution_interface +}; + +void testsuite_opr_substitution_emit +(struct sieve_binary_block *sblock, const struct testsuite_substitution *tsub, + const char *param) +{ + /* Default variable storage */ + (void) sieve_operand_emit + (sblock, testsuite_ext, &testsuite_substitution_operand); + (void) sieve_binary_emit_unsigned(sblock, tsub->object.def->code); + (void) sieve_binary_emit_cstring(sblock, param); +} + +static bool opr_substitution_dump +(const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd, + sieve_size_t *address) +{ + unsigned int code = 0; + const struct testsuite_substitution_def *tsub; + string_t *param; + + if ( !sieve_binary_read_unsigned(denv->sblock, address, &code) ) + return FALSE; + + tsub = testsuite_substitution_get(code); + if ( tsub == NULL ) + return FALSE; + + if ( !sieve_binary_read_string(denv->sblock, address, ¶m) ) + return FALSE; + + if ( oprnd->field_name != NULL ) + sieve_code_dumpf(denv, "%s: TEST_SUBS %%{%s:%s}", + oprnd->field_name, tsub->obj_def.identifier, str_c(param)); + else + sieve_code_dumpf(denv, "TEST_SUBS %%{%s:%s}", + tsub->obj_def.identifier, str_c(param)); + return TRUE; +} + +static int opr_substitution_read_value +(const struct sieve_runtime_env *renv, + const struct sieve_operand *oprnd ATTR_UNUSED, sieve_size_t *address, + string_t **str_r) +{ + const struct testsuite_substitution_def *tsub; + unsigned int code = 0; + string_t *param; + + if ( !sieve_binary_read_unsigned(renv->sblock, address, &code) ) + return SIEVE_EXEC_BIN_CORRUPT; + + tsub = testsuite_substitution_get(code); + if ( tsub == NULL ) + return SIEVE_EXEC_FAILURE; + + /* Parameter str can be NULL if we are requested to only skip and not + * actually read the argument. + */ + if ( str_r == NULL ) { + if ( !sieve_binary_read_string(renv->sblock, address, NULL) ) + return SIEVE_EXEC_BIN_CORRUPT; + + return SIEVE_EXEC_OK; + } + + if ( !sieve_binary_read_string(renv->sblock, address, ¶m) ) + return SIEVE_EXEC_BIN_CORRUPT; + + if ( !tsub->get_value(str_c(param), str_r) ) + return SIEVE_EXEC_FAILURE; + + return SIEVE_EXEC_OK; +} + +/* + * Testsuite substitution definitions + */ + +static bool testsuite_file_substitution_get_value + (const char *param, string_t **result); + +static const struct testsuite_substitution_def +testsuite_file_substitution = { + SIEVE_OBJECT("file", + &testsuite_substitution_operand, + TESTSUITE_SUBSTITUTION_FILE), + .get_value = testsuite_file_substitution_get_value +}; + +static bool testsuite_file_substitution_get_value +(const char *param, string_t **result) +{ + *result = t_str_new(256); + + str_printfa(*result, "[FILE: %s]", param); + return TRUE; +} + |