From 53ea26031474c64386ef6db43cc802edd684591a Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Sat, 5 Jan 2008 23:11:59 +0100 Subject: [PATCH] First successful variable substitutions. --- src/lib-sieve/plugins/variables/cmd-set.c | 19 +- .../plugins/variables/ext-variables-common.c | 332 +++++++++++++++++- .../plugins/variables/ext-variables-common.h | 17 +- .../plugins/variables/ext-variables.c | 108 +----- .../plugins/variables/variables.sieve | 3 + src/lib-sieve/sieve-ast.c | 15 +- src/lib-sieve/sieve-ast.h | 97 +++-- src/lib-sieve/sieve-validator.c | 52 ++- 8 files changed, 467 insertions(+), 176 deletions(-) diff --git a/src/lib-sieve/plugins/variables/cmd-set.c b/src/lib-sieve/plugins/variables/cmd-set.c index d5e0a4719..2d911f85a 100644 --- a/src/lib-sieve/plugins/variables/cmd-set.c +++ b/src/lib-sieve/plugins/variables/cmd-set.c @@ -75,8 +75,6 @@ static bool tag_modifier_validate (struct sieve_validator *validator, struct sieve_ast_argument **arg, struct sieve_command_context *cmd) { - struct sieve_ast_argument *tag = *arg; - /* Skip parameter */ *arg = sieve_ast_argument_next(*arg); @@ -165,7 +163,7 @@ static bool cmd_set_validate(struct sieve_validator *validator, (validator, cmd, arg, "value", 2, SAAT_STRING) ) { return FALSE; } - sieve_validator_argument_activate(validator, cmd, arg, TRUE); + sieve_validator_argument_activate(validator, cmd, arg, FALSE); return TRUE; } @@ -211,11 +209,20 @@ static bool cmd_set_operation_execute (const struct sieve_operation *op ATTR_UNUSED, const struct sieve_runtime_env *renv, sieve_size_t *address) { - struct sieve_variable_storage *storage = - ext_variables_interpreter_get_storage(renv->interp); - + struct sieve_variable_storage *storage; + unsigned int var_index; + string_t *value; + printf(">> SET\n"); + if ( !ext_variables_opr_variable_read(renv, address, &storage, &var_index) ) + return FALSE; + + if ( !sieve_opr_string_read(renv, address, &value) ) + return FALSE; + + sieve_variable_assign(storage, var_index, value); + return TRUE; } diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.c b/src/lib-sieve/plugins/variables/ext-variables-common.c index 59826b6b9..9fc481226 100644 --- a/src/lib-sieve/plugins/variables/ext-variables-common.c +++ b/src/lib-sieve/plugins/variables/ext-variables-common.c @@ -14,6 +14,8 @@ #include "ext-variables-common.h" +#include <ctype.h> + /* Forward declarations */ extern const struct ext_variables_set_modifier lower_modifier; @@ -223,7 +225,11 @@ struct sieve_variable_storage *ext_variables_interpreter_get_storage return ctx->local_storage; } -/* Variable arguments */ +/* + * Arguments + */ + +/* Variable argument */ static bool arg_variable_generate (struct sieve_generator *generator, struct sieve_ast_argument *arg, @@ -232,6 +238,28 @@ static bool arg_variable_generate const struct sieve_argument variable_argument = { "@variable", NULL, NULL, NULL, arg_variable_generate }; +static struct sieve_ast_argument *ext_variables_variable_argument_create +(struct sieve_validator *validator, struct sieve_ast *ast, + unsigned int source_line, const char *variable) +{ + struct ext_variables_validator_context *ctx; + struct sieve_variable *var; + struct sieve_ast_argument *arg; + + ctx = ext_variables_validator_context_get(validator); + var = sieve_variable_scope_get_variable(ctx->main_scope, variable); + + if ( var == NULL ) + return NULL; + + arg = sieve_ast_argument_create(ast, source_line); + arg->type = SAAT_STRING; + arg->argument = &variable_argument; + arg->context = (void *) var; + + return arg; +} + void ext_variables_variable_argument_activate (struct sieve_validator *validator, struct sieve_ast_argument *arg) { @@ -257,21 +285,219 @@ static bool arg_variable_generate return TRUE; } -/* Variable operands */ +/* Variable string argument */ + +static bool arg_variable_string_validate + (struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command_context *context); +static bool arg_variable_string_generate +(struct sieve_generator *generator, struct sieve_ast_argument *arg, + struct sieve_command_context *context); + +const struct sieve_argument variable_string_argument = { + "@variable-string", + NULL, + arg_variable_string_validate, + NULL, + arg_variable_string_generate, +}; + +struct _variable_string_data { + struct sieve_ast_arg_list *str_parts; +}; + +inline static struct sieve_ast_argument *_add_string_element +(struct sieve_ast_arg_list *list, struct sieve_ast_argument *arg) +{ + struct sieve_ast_argument *strarg = + sieve_ast_argument_create(arg->ast, arg->source_line); + sieve_ast_arg_list_add(list, strarg); + strarg->type = SAAT_STRING; + + return strarg; +} + +static bool arg_variable_string_validate +(struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd) +{ + enum { ST_NONE, ST_OPEN, ST_VARIABLE, ST_CLOSE } state = ST_NONE; + pool_t pool = sieve_ast_pool((*arg)->ast); + struct sieve_ast_arg_list *arglist = NULL; + string_t *str = sieve_ast_argument_str(*arg); + string_t *ident; + const char *p, *mark, *strstart, *substart = NULL; + const char *strval = (const char *) str_data(str); + const char *strend = strval + str_len(str); + struct _variable_string_data *strdata; + bool result = TRUE; + + //t_push(); + + ident = t_str_new(32); + + p = strval; + strstart = p; + while ( result && p < strend ) { + switch ( state ) { + case ST_NONE: + if ( *p == '$' ) { + substart = p; + state = ST_OPEN; + } + p++; + break; + case ST_OPEN: + if ( *p == '{' ) { + state = ST_VARIABLE; + p++; + } else + state = ST_NONE; + break; + case ST_VARIABLE: + mark = p; + + if ( p < strend ) { + if (*p == '_' || isalpha(*p) ) { + str_append_c(ident, *p); + p++; + + while ( p < strend && (*p == '_' || isalnum(*p)) ) { + str_append_c(ident, *p); + p++; + } + state = ST_CLOSE; + } else if ( isdigit(*p) ) { + unsigned int num_variable = *p - '0'; + p++; + + while ( p < strend && isdigit(*p) ) { + num_variable = num_variable*10 + (*p - '0'); + p++; + } + state = ST_CLOSE; + } else + state = ST_NONE; + } + + break; + case ST_CLOSE: + if ( *p == '}' ) { + struct sieve_ast_argument *strarg; + + /* We now know that the substitution is valid */ + + if ( arglist == NULL ) { + arglist = sieve_ast_arg_list_create(pool); + } + + if ( substart > strstart ) { + strarg = _add_string_element(arglist, *arg); + strarg->_value.str = str_new(pool, substart - strstart); + str_append_n(strarg->_value.str, strstart, substart - strstart); + + if ( !sieve_validator_argument_activate_super + (validator, cmd, strarg, FALSE) ) + return FALSE; + + printf("STR: %s\n", t_strdup_until(strstart, substart)); + } + + /* Find the variable */ + strarg = ext_variables_variable_argument_create + (validator, (*arg)->ast, (*arg)->source_line, str_c(ident)); + if ( strarg != NULL ) + sieve_ast_arg_list_add(arglist, strarg); + + printf("VAR: %s\n", str_c(ident)); + str_truncate(ident, 0); + + strstart = p + 1; + substart = strstart; + } + state = ST_NONE; + p++; + } + } + + //t_pop(); + + if ( arglist == NULL ) { + printf("STR: %s\n", strval); + return sieve_validator_argument_activate_super + (validator, cmd, *arg, TRUE); + } + + if ( substart > strstart ) { + struct sieve_ast_argument *strarg = _add_string_element(arglist, *arg); + strarg->_value.str = str_new(pool, substart - strstart); + str_append_n(strarg->_value.str, strstart, substart - strstart); + + if ( !sieve_validator_argument_activate_super + (validator, cmd, strarg, FALSE) ) + return FALSE; + + printf("STR: %s\n", t_strdup_until(strstart, substart)); + } + + strdata = p_new(pool, struct _variable_string_data, 1); + strdata->str_parts = arglist; + + (*arg)->context = (void *) strdata; + + return TRUE; +} + +#define _string_data_first(data) __AST_LIST_FIRST((data)->str_parts) +#define _string_data_count(data) __AST_LIST_COUNT((data)->str_parts) +#define _string_data_next(item) __AST_LIST_NEXT(item) + +static bool arg_variable_string_generate +(struct sieve_generator *generator, struct sieve_ast_argument *arg, + struct sieve_command_context *cmd) +{ + struct sieve_binary *sbin = sieve_generator_get_binary(generator); + struct _variable_string_data *strdata = + (struct _variable_string_data *) arg->context; + struct sieve_ast_argument *strpart; + + if ( _string_data_count(strdata) == 1 ) + sieve_generate_argument(generator, _string_data_first(strdata), cmd); + else { + ext_variables_opr_variable_string_emit(sbin, _string_data_count(strdata)); + + strpart = _string_data_first(strdata); + while ( strpart != NULL ) { + if ( !sieve_generate_argument(generator, strpart, cmd) ) + return FALSE; + + strpart = _string_data_next(strpart); + } + } + + return TRUE; +} + +/* + * Operands + */ + +/* Variable operand */ -static bool opr_variable_read +static bool opr_variable_read_value (const struct sieve_runtime_env *renv, sieve_size_t *address, string_t **str); static bool opr_variable_dump (const struct sieve_dumptime_env *denv, sieve_size_t *address); const struct sieve_opr_string_interface variable_interface = { opr_variable_dump, - opr_variable_read + opr_variable_read_value }; const struct sieve_operand variable_operand = { "variable", - &variables_extension, 0, + &variables_extension, + EXT_VARIABLES_OPERAND_VARIABLE, &string_class, &variable_interface }; @@ -297,14 +523,17 @@ static bool opr_variable_dump return FALSE; } -static bool opr_variable_read +static bool opr_variable_read_value (const struct sieve_runtime_env *renv, sieve_size_t *address, string_t **str) { + struct sieve_variable_storage *storage; sieve_size_t index = 0; + storage = ext_variables_interpreter_get_storage(renv->interp); + if ( storage == NULL ) return FALSE; + if (sieve_binary_read_integer(renv->sbin, address, &index) ) { - *str = t_str_new(10); - str_append(*str, "VARIABLE"); + sieve_variable_get(storage, index, str); return TRUE; } @@ -312,20 +541,97 @@ static bool opr_variable_read return FALSE; } -bool ext_variables_opr_variable_assign - (struct sieve_binary *sbin, sieve_size_t *address, string_t *str) +bool ext_variables_opr_variable_read + (const struct sieve_runtime_env *renv, sieve_size_t *address, + struct sieve_variable_storage **storage, unsigned int *var_index) { - sieve_size_t index = 0; + const struct sieve_operand *operand = sieve_operand_read(renv->sbin, address); + sieve_size_t idx = 0; - if (sieve_binary_read_integer(sbin, address, &index) ) { - /* FIXME: Assign */ + if ( operand != &variable_operand ) + return FALSE; + + *storage = ext_variables_interpreter_get_storage(renv->interp); + if ( *storage == NULL ) return FALSE; + if (sieve_binary_read_integer(renv->sbin, address, &idx) ) { + *var_index = idx; return TRUE; } return FALSE; } +/* Variable string operand */ + +static bool opr_variable_string_read + (const struct sieve_runtime_env *renv, sieve_size_t *address, string_t **str); +static bool opr_variable_string_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address); + +const struct sieve_opr_string_interface variable_string_interface = { + opr_variable_string_dump, + opr_variable_string_read +}; + +const struct sieve_operand variable_string_operand = { + "variable-string", + &variables_extension, + EXT_VARIABLES_OPERAND_VARIABLE_STRING, + &string_class, + &variable_string_interface +}; + +void ext_variables_opr_variable_string_emit + (struct sieve_binary *sbin, unsigned int elements) +{ + (void) sieve_operand_emit_code + (sbin, &variable_string_operand, ext_variables_my_id); + (void) sieve_binary_emit_integer(sbin, elements); +} + +static bool opr_variable_string_dump + (const struct sieve_dumptime_env *denv, sieve_size_t *address) +{ + sieve_size_t elements = 0; + unsigned int i; + + if (!sieve_binary_read_integer(denv->sbin, address, &elements) ) + return FALSE; + + sieve_code_dumpf(denv, "VARSTR [%ld]:", (long) elements); + + sieve_code_descend(denv); + for ( i = 0; i < (unsigned int) elements; i++ ) { + sieve_opr_string_dump(denv, address); + } + sieve_code_ascend(denv); + + return TRUE; +} + +static bool opr_variable_string_read + (const struct sieve_runtime_env *renv, sieve_size_t *address, string_t **str) +{ + sieve_size_t elements = 0; + unsigned int i; + + if ( !sieve_binary_read_integer(renv->sbin, address, &elements) ) + return FALSE; + + *str = t_str_new(128); + for ( i = 0; i < (unsigned int) elements; i++ ) { + string_t *strelm; + + if ( !sieve_opr_string_read(renv, address, &strelm) ) + return FALSE; + + str_append_str(*str, strelm); + } + + return TRUE; +} + /* Set modifier registration */ const struct ext_variables_set_modifier *ext_variables_set_modifier_find diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.h b/src/lib-sieve/plugins/variables/ext-variables-common.h index 5dcadf54b..7e9db1f19 100644 --- a/src/lib-sieve/plugins/variables/ext-variables-common.h +++ b/src/lib-sieve/plugins/variables/ext-variables-common.h @@ -14,6 +14,11 @@ enum ext_variables_opcode { EXT_VARIABLES_OPERATION_STRING }; +enum ext_variables_operand { + EXT_VARIABLES_OPERAND_VARIABLE, + EXT_VARIABLES_OPERAND_VARIABLE_STRING +}; + /* Extension */ void ext_variables_validator_initialize(struct sieve_validator *validator); @@ -40,12 +45,20 @@ struct ext_variables_set_modifier { const struct ext_variables_set_modifier *ext_variables_set_modifier_find (struct sieve_validator *validator, const char *identifier); +/* Arguments */ + +extern const struct sieve_argument variable_string_argument; + /* Variables */ void ext_variables_opr_variable_emit (struct sieve_binary *sbin, struct sieve_variable *var); -bool ext_variables_opr_variable_assign - (struct sieve_binary *sbin, sieve_size_t *address, string_t *str); +bool ext_variables_opr_variable_read + (const struct sieve_runtime_env *renv, sieve_size_t *address, + struct sieve_variable_storage **storage, unsigned int *var_index); + +void ext_variables_opr_variable_string_emit + (struct sieve_binary *sbin, unsigned int elements); void ext_variables_variable_argument_activate (struct sieve_validator *validator, struct sieve_ast_argument *arg); diff --git a/src/lib-sieve/plugins/variables/ext-variables.c b/src/lib-sieve/plugins/variables/ext-variables.c index 4f2f41f1a..0b3828892 100644 --- a/src/lib-sieve/plugins/variables/ext-variables.c +++ b/src/lib-sieve/plugins/variables/ext-variables.c @@ -43,6 +43,12 @@ const struct sieve_operation *ext_variables_operations[] = { /* Operands */ extern const struct sieve_operand variable_operand; +extern const struct sieve_operand variable_string_operand; + +const struct sieve_operation *ext_variables_operands[] = { + &variable_operand, &variable_string_operand +}; + /* Extension definitions */ @@ -55,7 +61,7 @@ struct sieve_extension variables_extension = { NULL, NULL, ext_variables_interpreter_load, SIEVE_EXT_DEFINE_OPERATIONS(ext_variables_operations), - SIEVE_EXT_DEFINE_OPERAND(variable_operand) + SIEVE_EXT_DEFINE_OPERANDS(ext_variables_operands) }; static bool ext_variables_load(int ext_id) @@ -64,109 +70,13 @@ static bool ext_variables_load(int ext_id) return TRUE; } -/* New argument */ - -static bool arg_variable_string_validate - (struct sieve_validator *validator, struct sieve_ast_argument **arg, - struct sieve_command_context *context); - -const struct sieve_argument variable_string_argument = - { "@variable-string", NULL, arg_variable_string_validate, NULL, NULL }; - -static bool arg_variable_string_validate -(struct sieve_validator *validator, struct sieve_ast_argument **arg, - struct sieve_command_context *cmd) -{ - bool result = TRUE; - enum { ST_NONE, ST_OPEN, ST_VARIABLE, ST_CLOSE } - state = ST_NONE; - string_t *str = sieve_ast_argument_str(*arg); - string_t *tmpstr, *newstr = NULL; - const char *p, *mark, *strstart, *substart = NULL; - const char *strval = (const char *) str_data(str); - const char *strend = strval + str_len(str); - - T_FRAME( - tmpstr = t_str_new(32); - - p = strval; - strstart = p; - while ( result && p < strend ) { - switch ( state ) { - case ST_NONE: - if ( *p == '$' ) { - substart = p; - state = ST_OPEN; - } - p++; - break; - case ST_OPEN: - if ( *p == '{' ) { - state = ST_VARIABLE; - p++; - } else - state = ST_NONE; - break; - case ST_VARIABLE: - mark = p; - - if ( p < strend ) { - if (*p == '_' || isalpha(*p) ) { - p++; - - while ( p < strend && (*p == '_' || isalnum(*p)) ) { - p++; - } - } else if ( isdigit(*p) ) { - unsigned int num_variable = *p - '0'; - p++; - - while ( p < strend && isdigit(*p) ) { - num_variable = num_variable*10 + (*p - '0'); - p++; - } - } - } - - break; - case ST_CLOSE: - if ( *p == '}' ) { - /* We now know that the substitution is valid */ - - if ( newstr == NULL ) { - newstr = str_new(sieve_ast_pool((*arg)->ast), str_len(str)*2); - } - - str_append_n(newstr, strstart, substart-strstart); - str_append_str(newstr, tmpstr); - - strstart = p + 1; - substart = strstart; - } - state = ST_NONE; - p++; - } - } - ); - - if ( newstr != NULL ) { - if ( strstart != strend ) - str_append_n(newstr, strstart, strend-strstart); - - sieve_ast_argument_str_set(*arg, newstr); - } - - return sieve_validator_argument_activate_super - (validator, cmd, *arg, TRUE); -} - /* Load extension into validator */ static bool ext_variables_validator_load (struct sieve_validator *validator) { - /*sieve_validator_argument_override(validator, SAT_VAR_STRING, - &variable_string_argument);*/ + sieve_validator_argument_override(validator, SAT_VAR_STRING, + &variable_string_argument); sieve_validator_register_command(validator, &cmd_set); sieve_validator_register_command(validator, &tst_string); diff --git a/src/lib-sieve/plugins/variables/variables.sieve b/src/lib-sieve/plugins/variables/variables.sieve index 498c48ae7..207dbc0ec 100644 --- a/src/lib-sieve/plugins/variables/variables.sieve +++ b/src/lib-sieve/plugins/variables/variables.sieve @@ -1,4 +1,7 @@ require "variables"; +require "fileinto"; set :upper "foo" "foosome"; set :lower "bar" "bareable"; + +fileinto "${foo}.${bar}"; diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c index 500a0717f..c3bef9fb7 100644 --- a/src/lib-sieve/sieve-ast.c +++ b/src/lib-sieve/sieve-ast.c @@ -135,16 +135,16 @@ static void sieve_ast_list_add( struct sieve_ast_list *list, struct sieve_ast_no __LIST_ADD(list, node) /* List of argument AST nodes */ -static struct sieve_ast_arg_list *sieve_ast_arg_list_create( pool_t pool ) +struct sieve_ast_arg_list *sieve_ast_arg_list_create( pool_t pool ) __LIST_CREATE(pool, struct sieve_ast_arg_list) -static void sieve_ast_arg_list_add +void sieve_ast_arg_list_add ( struct sieve_ast_arg_list *list, struct sieve_ast_argument *argument ) __LIST_ADD(list, argument) -inline static void sieve_ast_arg_list_substitute -(struct sieve_ast_arg_list *list, - struct sieve_ast_argument *argument, struct sieve_ast_argument *replacement) +void sieve_ast_arg_list_substitute +(struct sieve_ast_arg_list *list, struct sieve_ast_argument *argument, + struct sieve_ast_argument *replacement) { if ( list->head == argument ) list->head = replacement; @@ -269,10 +269,11 @@ static void sieve_ast_argument_substitute } /* Argument AST node */ -static struct sieve_ast_argument *sieve_ast_argument_create +struct sieve_ast_argument *sieve_ast_argument_create (struct sieve_ast *ast, unsigned int source_line) { - struct sieve_ast_argument *arg = p_new(ast->pool, struct sieve_ast_argument, 1); + struct sieve_ast_argument *arg = + p_new(ast->pool, struct sieve_ast_argument, 1); arg->ast = ast; diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h index 1cbfcbefd..76262be54 100644 --- a/src/lib-sieve/sieve-ast.h +++ b/src/lib-sieve/sieve-ast.h @@ -34,13 +34,13 @@ | [number | tag | *string] . - Tests and commands are defined using the same structure: sieve_ast_node. However, arguments and - string-lists are described using sieve_ast_argument. + Tests and commands are defined using the same structure: sieve_ast_node. + However, arguments and string-lists are described using sieve_ast_argument. */ -/* IMPORTANT NOTICE: Do not decorate the AST with objects other than those allocated on - * the ast's pool or static const objects. Otherwise it is possible that pointers in the tree - * become dangling which is highly undesirable. +/* IMPORTANT NOTICE: Do not decorate the AST with objects other than those + * allocated on the ast's pool or static const objects. Otherwise it is possible + * that pointers in the tree become dangling which is highly undesirable. */ struct sieve_ast_list; @@ -166,6 +166,17 @@ void sieve_ast_error struct sieve_ast_node *node, const char *fmt, va_list args); /* sieve_ast_argument */ + +struct sieve_ast_argument *sieve_ast_argument_create + (struct sieve_ast *ast, unsigned int source_line); + +struct sieve_ast_arg_list *sieve_ast_arg_list_create(pool_t pool); +void sieve_ast_arg_list_add + (struct sieve_ast_arg_list *list, struct sieve_ast_argument *argument); +void sieve_ast_arg_list_substitute +(struct sieve_ast_arg_list *list, struct sieve_ast_argument *argument, + struct sieve_ast_argument *replacement); + struct sieve_ast_argument *sieve_ast_argument_string_create (struct sieve_ast_node *node, const string_t *str, unsigned int source_line); struct sieve_ast_argument *sieve_ast_argument_tag_create @@ -186,17 +197,21 @@ const char *sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type); sieve_ast_argument_type_name((argument)->type) void sieve_ast_stringlist_add - (struct sieve_ast_argument *list, const string_t *str, unsigned int source_line); + (struct sieve_ast_argument *list, const string_t *str, + unsigned int source_line); void sieve_ast_stringlist_add_strc - (struct sieve_ast_argument *list, const char *str, unsigned int source_line); + (struct sieve_ast_argument *list, const char *str, + unsigned int source_line); /* sieve_ast_test */ struct sieve_ast_node *sieve_ast_test_create - (struct sieve_ast_node *parent, const char *identifier, unsigned int source_line); + (struct sieve_ast_node *parent, const char *identifier, + unsigned int source_line); /* sieve_ast_command */ struct sieve_ast_node *sieve_ast_command_create - (struct sieve_ast_node *parent, const char *identifier, unsigned int source_line); + (struct sieve_ast_node *parent, const char *identifier, + unsigned int source_line); /* Debug */ void sieve_ast_unparse(struct sieve_ast *ast); @@ -204,45 +219,54 @@ void sieve_ast_unparse(struct sieve_ast *ast); /* AST access macros */ /* Generic list access macros */ -#define __LIST_FIRST(node, list) ((node)->list == NULL ? NULL : (node)->list->head) -#define __LIST_LAST(node, list) ((node)->list == NULL ? NULL : (node)->list->tail) -#define __LIST_NEXT(item) ((item)->next) -#define __LIST_PREV(item) ((item)->prev) -#define __LIST_COUNT(node, list) ((node)->list == NULL || (node)->list->head == NULL ? 0 : (node)->list->len) +#define __AST_LIST_FIRST(list) \ + ((list) == NULL ? NULL : (list)->head) +#define __AST_LIST_LAST(list) \ + ((list) == NULL ? NULL : (list)->tail) +#define __AST_LIST_COUNT(list) \ + ((list) == NULL || (list)->head == NULL ? 0 : (list)->len) +#define __AST_LIST_NEXT(item) ((item)->next) +#define __AST_LIST_PREV(item) ((item)->prev) + +#define __AST_NODE_LIST_FIRST(node, list) __AST_LIST_FIRST((node)->list) +#define __AST_NODE_LIST_LAST(node, list) __AST_LIST_LAST((node)->list) +#define __AST_NODE_LIST_COUNT(node, list) __AST_LIST_COUNT((node)->list) /* AST macros */ /* AST node macros */ #define sieve_ast_node_pool(node) (sieve_ast_pool((node)->ast)) #define sieve_ast_node_parent(node) ((node)->parent) -#define sieve_ast_node_prev(node) __LIST_PREV(node) -#define sieve_ast_node_next(node) __LIST_NEXT(node) +#define sieve_ast_node_prev(node) __AST_LIST_PREV(node) +#define sieve_ast_node_next(node) __AST_LIST_NEXT(node) #define sieve_ast_node_type(node) ((node) == NULL ? SAT_NONE : (node)->type) #define sieve_ast_node_line(node) ((node) == NULL ? 0 : (node)->source_line) /* AST command node macros */ -#define sieve_ast_command_first(node) __LIST_FIRST(node, commands) -#define sieve_ast_command_prev(command) __LIST_PREV(command) -#define sieve_ast_command_next(command) __LIST_NEXT(command) -#define sieve_ast_command_count(node) __LIST_COUNT(node, commands) +#define sieve_ast_command_first(node) __AST_NODE_LIST_FIRST(node, commands) +#define sieve_ast_command_count(node) __AST_NODE_LIST_COUNT(node, commands) +#define sieve_ast_command_prev(command) __AST_LIST_PREV(command) +#define sieve_ast_command_next(command) __AST_LIST_NEXT(command) /* Compare the identifier of the previous command */ #define sieve_ast_prev_cmd_is(cmd, id) \ ( (cmd)->prev == NULL ? FALSE : strncasecmp((cmd)->prev->identifier, id, sizeof(id)-1) == 0 ) /* AST test macros */ -#define sieve_ast_test_first(node) __LIST_FIRST(node, tests) -#define sieve_ast_test_next(test) __LIST_NEXT(test) -#define sieve_ast_test_count(node) __LIST_COUNT(node, tests) +#define sieve_ast_test_count(node) __AST_NODE_LIST_COUNT(node, tests) +#define sieve_ast_test_first(node) __AST_NODE_LIST_FIRST(node, tests) +#define sieve_ast_test_next(test) __AST_LIST_NEXT(test) /* AST argument macros */ -#define sieve_ast_argument_first(node) __LIST_FIRST(node, arguments) -#define sieve_ast_argument_last(node) __LIST_LAST(node, arguments) -#define sieve_ast_argument_prev(argument) __LIST_PREV(argument) -#define sieve_ast_argument_next(argument) __LIST_NEXT(argument) -#define sieve_ast_argument_count(node) __LIST_COUNT(node, arguments) -#define sieve_ast_argument_type(argument) ((argument) == NULL ? SAAT_NONE : (argument)->type) -#define sieve_ast_argument_line(argument) ((argument) == NULL ? 0 : (argument)->source_line) +#define sieve_ast_argument_first(node) __AST_NODE_LIST_FIRST(node, arguments) +#define sieve_ast_argument_last(node) __AST_NODE_LIST_LAST(node, arguments) +#define sieve_ast_argument_count(node) __AST_NODE_LIST_COUNT(node, arguments) +#define sieve_ast_argument_prev(argument) __AST_LIST_PREV(argument) +#define sieve_ast_argument_next(argument) __AST_LIST_NEXT(argument) +#define sieve_ast_argument_type(argument) \ + ((argument) == NULL ? SAAT_NONE : (argument)->type) +#define sieve_ast_argument_line(argument) \ + ((argument) == NULL ? 0 : (argument)->source_line) #define sieve_ast_argument_str(argument) ((argument)->_value.str) #define sieve_ast_argument_strc(argument) (str_c((argument)->_value.str)) @@ -254,12 +278,15 @@ void sieve_ast_unparse(struct sieve_ast *ast); /* AST string list macros */ // @UNSAFE: should check whether we are actually accessing a string list -#define sieve_ast_strlist_first(list) __LIST_FIRST(list, _value.strlist) -#define sieve_ast_strlist_last(list) __LIST_LAST(list, _value.strlist) -#define sieve_ast_strlist_next(str) __LIST_NEXT(str) -#define sieve_ast_strlist_prev(str) __LIST_PREV(str) +#define sieve_ast_strlist_first(list) \ + __AST_NODE_LIST_FIRST(list, _value.strlist) +#define sieve_ast_strlist_last(list) \ + __AST_NODE_LIST_LAST(list, _value.strlist) +#define sieve_ast_strlist_count(list) \ + __AST_NODE_LIST_COUNT(list, _value.strlist) +#define sieve_ast_strlist_next(str) __AST_LIST_NEXT(str) +#define sieve_ast_strlist_prev(str) __AST_LIST_PREV(str) #define sieve_ast_strlist_str(str) sieve_ast_argument_str(str) #define sieve_ast_strlist_strc(str) sieve_ast_argument_strc(str) -#define sieve_ast_strlist_count(list) __LIST_COUNT(list, _value.strlist) #endif /* __SIEVE_AST_H */ diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index c6bbff2ee..16f0aa79d 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -37,8 +37,10 @@ struct sieve_validator { ARRAY_DEFINE(ext_contexts, void *); + /* This is currently a wee bit ugly and needs more thought */ struct sieve_default_argument default_arguments[SAT_COUNT]; struct sieve_default_argument *current_defarg; + enum sieve_argument_type current_defarg_type; }; /* Predeclared statics */ @@ -427,12 +429,15 @@ void sieve_validator_argument_override (struct sieve_validator *validator, enum sieve_argument_type type, const struct sieve_argument *argument) { - struct sieve_default_argument *arg = - p_new(validator->pool, struct sieve_default_argument, 1); + struct sieve_default_argument *arg; - *arg = validator->default_arguments[type]; + if ( validator->default_arguments[type].argument != NULL ) { + arg = p_new(validator->pool, struct sieve_default_argument, 1); + *arg = validator->default_arguments[type]; + + validator->default_arguments[type].overrides = arg; + } - validator->default_arguments[type].overrides = arg; validator->default_arguments[type].argument = argument; } @@ -459,12 +464,29 @@ bool sieve_validator_argument_activate_super (struct sieve_validator *validator, struct sieve_command_context *cmd, struct sieve_ast_argument *arg, bool constant ATTR_UNUSED) { - if ( validator->current_defarg == NULL && - validator->current_defarg->overrides == NULL ) + struct sieve_default_argument *defarg; + + if ( validator->current_defarg == NULL ) return FALSE; + if ( validator->current_defarg->overrides == NULL ) { + switch ( validator->current_defarg_type ) { + case SAT_NUMBER: + case SAT_CONST_STRING: + case SAT_STRING_LIST: + return FALSE; + case SAT_VAR_STRING: + validator->current_defarg_type = SAT_CONST_STRING; + defarg = &validator->default_arguments[validator->current_defarg_type]; + break; + default: + return FALSE; + } + } else + defarg = validator->current_defarg->overrides; + return sieve_validator_argument_default_activate - (validator, cmd, validator->current_defarg->overrides, arg); + (validator, cmd, defarg, arg); } bool sieve_validator_argument_activate @@ -474,23 +496,25 @@ bool sieve_validator_argument_activate struct sieve_default_argument *defarg; switch ( sieve_ast_argument_type(arg) ) { - case SAAT_NUMBER: - defarg = &validator->default_arguments[SAT_NUMBER]; + case SAAT_NUMBER: + validator->current_defarg_type = SAT_NUMBER; break; case SAAT_STRING: - if ( validator->default_arguments[SAT_VAR_STRING].argument == NULL || - constant ) - defarg = &validator->default_arguments[SAT_CONST_STRING]; + if ( constant || + validator->default_arguments[SAT_VAR_STRING].argument == NULL ) + validator->current_defarg_type = SAT_CONST_STRING; else - defarg = &validator->default_arguments[SAT_VAR_STRING]; + validator->current_defarg_type = SAT_VAR_STRING; break; case SAAT_STRING_LIST: - defarg = &validator->default_arguments[SAT_STRING_LIST]; + validator->current_defarg_type = SAT_STRING_LIST; break; default: return FALSE; } + defarg = &validator->default_arguments[validator->current_defarg_type]; + return sieve_validator_argument_default_activate(validator, cmd, defarg, arg); } -- GitLab