diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c index 255d29bbf12b00ea8eb9e3dd748411a9ee0d3c52..24d67095a407da9c2fb3f45b0803ae172834833d 100644 --- a/src/lib-sieve/sieve-ast.c +++ b/src/lib-sieve/sieve-ast.c @@ -313,6 +313,18 @@ void sieve_ast_unref(struct sieve_ast **ast) { } } +const char *sieve_ast_type_name(enum sieve_ast_type ast_type) { + switch ( ast_type ) { + + case SAT_NONE: return "none"; + case SAT_ROOT: return "ast root node"; + case SAT_COMMAND: return "command"; + case SAT_TEST: return "test"; + + default: return "??AST NODE??"; + } +} + /* Debug */ /* Unparsing, currently implemented using plain printf()s */ diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h index 81ce0c254cbb3e34491d229b243b0d7e9e84f9ee..5b196c541a065c0c42dd66ec42908e763f69e852 100644 --- a/src/lib-sieve/sieve-ast.h +++ b/src/lib-sieve/sieve-ast.h @@ -190,6 +190,8 @@ struct sieve_ast *sieve_ast_create( void ); void sieve_ast_ref(struct sieve_ast *ast); void sieve_ast_unref(struct sieve_ast **ast); +const char *sieve_ast_type_name(enum sieve_ast_type ast_type); + /* Debug */ void sieve_ast_unparse(struct sieve_ast *ast); diff --git a/src/lib-sieve/sieve-commands.c b/src/lib-sieve/sieve-commands.c index adc20b413a9b18c5f2f1f11d0647d4ce8ec1d70c..a1345ea3d66c51ee0cd28107683ac30ed464ba4e 100644 --- a/src/lib-sieve/sieve-commands.c +++ b/src/lib-sieve/sieve-commands.c @@ -219,6 +219,7 @@ struct sieve_command_context *sieve_command_context_create const char *sieve_command_type_name(const struct sieve_command *command) { switch ( command->type ) { + case SCT_NONE: return "command of unspecified type (bug)"; case SCT_TEST: return "test"; case SCT_COMMAND: return "command"; default: diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h index a20b58a4210c52844e618c9e344752d4e27e5fff..47df57a991e54c38475968b50f097ea23aaea6c2 100644 --- a/src/lib-sieve/sieve-commands.h +++ b/src/lib-sieve/sieve-commands.h @@ -28,6 +28,7 @@ extern const struct sieve_argument string_list_argument; /* Command */ enum sieve_command_type { + SCT_NONE, SCT_COMMAND, SCT_TEST }; diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index 95402b79e8d302a1cc3b8081cde9de6c6e758ebb..afd08f38e78703493763b6b3b70622fcb8fd85b1 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -121,11 +121,7 @@ static bool _cmd_unknown_validate } static const struct sieve_command unknown_command = { - "", SCT_COMMAND, 0, 0, FALSE, FALSE , - NULL, NULL, _cmd_unknown_validate, NULL, NULL -}; -static const struct sieve_command unknown_test = { - "", SCT_TEST, 0, 0, FALSE, FALSE, + "", SCT_NONE, 0, 0, FALSE, FALSE , NULL, NULL, _cmd_unknown_validate, NULL, NULL }; @@ -174,12 +170,6 @@ static void sieve_validator_register_unknown_command _sieve_validator_register_command(validator, &unknown_command, command); } -static void sieve_validator_register_unknown_test - (struct sieve_validator *validator, const char *test) -{ - _sieve_validator_register_command(validator, &unknown_test, test); -} - static struct sieve_command_registration *sieve_validator_find_command_registration (struct sieve_validator *validator, const char *command) { @@ -547,106 +537,37 @@ static bool sieve_validate_command_block /* AST Validation */ -static bool sieve_validate_test_list(struct sieve_validator *validator, struct sieve_ast_node *test_list); -static bool sieve_validate_test(struct sieve_validator *validator, struct sieve_ast_node *tst_node); -static bool sieve_validate_block(struct sieve_validator *validator, struct sieve_ast_node *block); -static bool sieve_validate_command(struct sieve_validator *validator, struct sieve_ast_node *cmd_node); - -static bool sieve_validate_test(struct sieve_validator *validator, struct sieve_ast_node *tst_node) -{ - bool result = TRUE; - const struct sieve_command *test; - - i_assert( sieve_ast_node_type(tst_node) == SAT_TEST ); - - test = sieve_validator_find_command(validator, tst_node->identifier); - - if ( test != NULL ) { - /* Identifier = "" when the command was previously marked as unknown */ - if ( *(test->identifier) != '\0' ) { - if ( test->type != SCT_TEST ) { - sieve_validator_error( - validator, tst_node, - "attempted to use command '%s' as test", tst_node->identifier); - result = FALSE; - } else { - struct sieve_command_context *ctx = - sieve_command_context_create(tst_node, test); - tst_node->context = ctx; - - /* If pre-validation fails, don't bother to validate further - * as context might be missing and doing so is not very useful for - * further error reporting anyway - */ - if ( test->pre_validate == NULL || - test->pre_validate(validator, ctx) ) { - - /* Check syntax */ - if ( - !sieve_validate_command_arguments - (validator,ctx, test->positional_arguments) || - !sieve_validate_command_subtests - (validator, ctx, test->subtests) ) - { - result = FALSE; - } else { - /* Call command validation function if specified */ - if ( test->validate != NULL ) - result = test->validate(validator, ctx) && result; - } - } else - result = FALSE; - } - } else - result = FALSE; - - } else { - sieve_validator_error(validator, tst_node, - "unknown test '%s' (only reported once at first occurence)", - tst_node->identifier); - sieve_validator_register_unknown_test(validator, tst_node->identifier); - - result = FALSE; - } - - result = sieve_validate_test_list(validator, tst_node) && result; - - return result; -} - static bool sieve_validate_test_list - (struct sieve_validator *validator, struct sieve_ast_node *test_list) -{ - bool result = TRUE; - struct sieve_ast_node *test; - - test = sieve_ast_test_first(test_list); - while ( test != NULL ) { - result = sieve_validate_test(validator, test) && result; - test = sieve_ast_test_next(test); - } + (struct sieve_validator *validator, struct sieve_ast_node *test_list); +static bool sieve_validate_block + (struct sieve_validator *validator, struct sieve_ast_node *block); +static bool sieve_validate_command + (struct sieve_validator *validator, struct sieve_ast_node *cmd_node); - return result; -} - static bool sieve_validate_command (struct sieve_validator *validator, struct sieve_ast_node *cmd_node) { + enum sieve_ast_type ast_type = sieve_ast_node_type(cmd_node); bool result = TRUE; const struct sieve_command *command; - i_assert( sieve_ast_node_type(cmd_node) == SAT_COMMAND ); + i_assert( ast_type == SAT_TEST || ast_type == SAT_COMMAND ); command = sieve_validator_find_command(validator, cmd_node->identifier); if ( command != NULL ) { /* Identifier = "" when the command was previously marked as unknown */ if ( *(command->identifier) != '\0' ) { - if ( command->type != SCT_COMMAND ) { + if ( (command->type == SCT_COMMAND && ast_type == SAT_TEST) || + (command->type == SCT_TEST && ast_type == SAT_COMMAND) ) + { sieve_validator_error( - validator, cmd_node, - "attempted to use test '%s' as command", cmd_node->identifier); - result = FALSE; + validator, cmd_node, "attempted to use %s '%s' as %s", + sieve_command_type_name(command), cmd_node->identifier, + sieve_ast_type_name(ast_type)); + + return FALSE; + } else { struct sieve_command_context *ctx = sieve_command_context_create(cmd_node, command); @@ -665,8 +586,9 @@ static bool sieve_validate_command (validator, ctx, command->positional_arguments) || !sieve_validate_command_subtests (validator, ctx, command->subtests) || - !sieve_validate_command_block - (validator, ctx, command->block_allowed, command->block_required) ) + (ast_type == SAT_COMMAND && !sieve_validate_command_block + (validator, ctx, command->block_allowed, + command->block_required)) ) { result = FALSE; } else { @@ -683,15 +605,33 @@ static bool sieve_validate_command } else { sieve_validator_error( validator, cmd_node, - "unknown command '%s' (only reported once at first occurence)", - cmd_node->identifier); + "unknown %s '%s' (only reported once at first occurence)", + sieve_ast_type_name(ast_type), cmd_node->identifier); + sieve_validator_register_unknown_command(validator, cmd_node->identifier); result = FALSE; } result = sieve_validate_test_list(validator, cmd_node) && result; - result = sieve_validate_block(validator, cmd_node) && result; + + if ( ast_type == SAT_COMMAND ) + result = sieve_validate_block(validator, cmd_node) && result; + + return result; +} + +static bool sieve_validate_test_list + (struct sieve_validator *validator, struct sieve_ast_node *test_list) +{ + bool result = TRUE; + struct sieve_ast_node *test; + + test = sieve_ast_test_first(test_list); + while ( test != NULL ) { + result = sieve_validate_command(validator, test) && result; + test = sieve_ast_test_next(test); + } return result; }