diff options
Diffstat (limited to 'pigeonhole/src/testsuite/testsuite-arguments.c')
-rw-r--r-- | pigeonhole/src/testsuite/testsuite-arguments.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/pigeonhole/src/testsuite/testsuite-arguments.c b/pigeonhole/src/testsuite/testsuite-arguments.c new file mode 100644 index 0000000..f1e17f4 --- /dev/null +++ b/pigeonhole/src/testsuite/testsuite-arguments.c @@ -0,0 +1,190 @@ +/* Copyright (c) 2002-2018 Pigeonhole authors, see the included COPYING file + */ + +#include "lib.h" +#include "str.h" +#include "str-sanitize.h" +#include "array.h" + +#include "sieve-common.h" +#include "sieve-ast.h" +#include "sieve-commands.h" +#include "sieve-code.h" +#include "sieve-validator.h" +#include "sieve-generator.h" +#include "sieve-dump.h" + +#include "testsuite-common.h" +#include "testsuite-substitutions.h" +#include "testsuite-arguments.h" + +#include <ctype.h> + +/* + * Testsuite string argument + */ + +static bool arg_testsuite_string_validate + (struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command *context); + +const struct sieve_argument_def testsuite_string_argument = { + .identifier = "@testsuite-string", + .validate = arg_testsuite_string_validate, + .generate = sieve_arg_catenated_string_generate, +}; + +static bool arg_testsuite_string_validate +(struct sieve_validator *valdtr, struct sieve_ast_argument **arg, + struct sieve_command *cmd) +{ + enum { ST_NONE, ST_OPEN, ST_SUBSTITUTION, ST_PARAM, ST_CLOSE } state = + ST_NONE; + pool_t pool = sieve_ast_pool((*arg)->ast); + struct sieve_arg_catenated_string *catstr = NULL; + string_t *str = sieve_ast_argument_str(*arg); + const char *p, *strstart, *substart = NULL; + const char *strval = (const char *) str_data(str); + const char *strend = strval + str_len(str); + bool result = TRUE; + string_t *subs_name = t_str_new(256); + string_t *subs_param = t_str_new(256); + + T_BEGIN { + /* Initialize substitution structure */ + + p = strval; + strstart = p; + while ( result && p < strend ) { + switch ( state ) { + + /* Nothing found yet */ + case ST_NONE: + if ( *p == '%' ) { + substart = p; + state = ST_OPEN; + str_truncate(subs_name, 0); + str_truncate(subs_param, 0); + } + p++; + break; + + /* Got '%' */ + case ST_OPEN: + if ( *p == '{' ) { + state = ST_SUBSTITUTION; + p++; + } else + state = ST_NONE; + break; + + /* Got '%{' */ + case ST_SUBSTITUTION: + state = ST_PARAM; + + while ( *p != '}' && *p != ':' ) { + if ( !i_isalnum(*p) ) { + state = ST_NONE; + break; + } + str_append_c(subs_name, *p); + p++; + } + break; + + /* Got '%{name' */ + case ST_PARAM: + if ( *p == ':' ) { + p++; + while ( *p != '}' ) { + str_append_c(subs_param, *p); + p++; + } + } + state = ST_CLOSE; + break; + + /* Finished parsing param, expecting '}' */ + case ST_CLOSE: + if ( *p == '}' ) { + struct sieve_ast_argument *strarg; + + /* We now know that the substitution is valid */ + + if ( catstr == NULL ) { + catstr = sieve_arg_catenated_string_create(*arg); + } + + /* Add the substring that is before the substitution to the + * variable-string AST. + */ + if ( substart > strstart ) { + string_t *newstr = str_new(pool, substart - strstart); + str_append_data(newstr, strstart, substart - strstart); + + strarg = sieve_ast_argument_string_create_raw + ((*arg)->ast, newstr, (*arg)->source_line); + sieve_arg_catenated_string_add_element(catstr, strarg); + + /* Give other substitution extensions a chance to do their work */ + if ( !sieve_validator_argument_activate_super + (valdtr, cmd, strarg, FALSE) ) { + result = FALSE; + break; + } + } + + strarg = testsuite_substitution_argument_create + (valdtr, (*arg)->ast, (*arg)->source_line, str_c(subs_name), + str_c(subs_param)); + + if ( strarg != NULL ) + sieve_arg_catenated_string_add_element(catstr, strarg); + else { + sieve_argument_validate_error(valdtr, *arg, + "unknown testsuite substitution type '%s'", str_c(subs_name)); + } + + strstart = p + 1; + substart = strstart; + + p++; + } + + /* Finished, reset for the next substitution */ + state = ST_NONE; + } + } + } T_END; + + /* Bail out early if substitution is invalid */ + if ( !result ) return FALSE; + + /* Check whether any substitutions were found */ + if ( catstr == NULL ) { + /* No substitutions in this string, pass it on to any other substution + * extension. + */ + return sieve_validator_argument_activate_super(valdtr, cmd, *arg, TRUE); + } + + /* Add the final substring that comes after the last substitution to the + * variable-string AST. + */ + if ( strend > strstart ) { + struct sieve_ast_argument *strarg; + string_t *newstr = str_new(pool, strend - strstart); + str_append_data(newstr, strstart, strend - strstart); + + strarg = sieve_ast_argument_string_create_raw + ((*arg)->ast, newstr, (*arg)->source_line); + sieve_arg_catenated_string_add_element(catstr, strarg); + + /* Give other substitution extensions a chance to do their work */ + if ( !sieve_validator_argument_activate_super + (valdtr, cmd, strarg, FALSE) ) + return FALSE; + } + + return TRUE; +} |