diff --git a/sieve/errors/address-errors.sieve b/sieve/errors/address-errors.sieve index 603320c8346f6448567dbe767fbb17f4ca3f7846..4744f1d9c01fade4c42d711626ae9f0a560d040f 100644 --- a/sieve/errors/address-errors.sieve +++ b/sieve/errors/address-errors.sieve @@ -1,3 +1,5 @@ +require "comparator-i;ascii-numeric"; + if address :isnot :comparator "i;ascii-casemap" :localpart "From" "nico" { discard; } diff --git a/sieve/errors/header-errors.sieve b/sieve/errors/header-errors.sieve index 6c66b5ac3ce1312ad726b99c881c4edb452eb3de..ac6108ba131741a96fe3432239da621b7e5975bf 100644 --- a/sieve/errors/header-errors.sieve +++ b/sieve/errors/header-errors.sieve @@ -1,3 +1,5 @@ +require "comparator-i;ascii-numeric"; + if header :isnot :comparator "i;ascii-casemap" "From" "nico" { discard; } diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c index 7143599bf3f5f7a1c2d05caac0a71578e714bcb3..a45076a2bffe17405602ffb9b90c0844aea5df9d 100644 --- a/src/lib-sieve/cmd-redirect.c +++ b/src/lib-sieve/cmd-redirect.c @@ -6,23 +6,20 @@ bool cmd_redirect_validate(struct sieve_validator *validator, struct sieve_command_context *cmd) { - struct sieve_ast_argument *argument; + struct sieve_ast_argument *arg; /* Check valid syntax * Syntax: redirect <address: string> */ - if ( !sieve_validate_command_arguments(validator, cmd, 1, &argument) || + if ( !sieve_validate_command_arguments(validator, cmd, 1, &arg) || !sieve_validate_command_subtests(validator, cmd, 0) || !sieve_validate_command_block(validator, cmd, FALSE, FALSE) ) { return FALSE; } /* Check argument */ - if ( sieve_ast_argument_type(argument) != SAAT_STRING ) { - /* Somethin else */ - sieve_command_validate_error(validator, cmd, - "the redirect command accepts a single string argument (address) but %s was found", - sieve_ast_argument_name(argument)); + if ( !sieve_validate_positional_argument + (validator, cmd, arg, "address", 1, SAAT_STRING) ) { return FALSE; } diff --git a/src/lib-sieve/cmd-require.c b/src/lib-sieve/cmd-require.c index 738f6f8260b994fdf75942e12be47250ffda50d1..ed03974bdf792fd2fb7925ebfe74f437aefe143c 100644 --- a/src/lib-sieve/cmd-require.c +++ b/src/lib-sieve/cmd-require.c @@ -21,7 +21,8 @@ bool cmd_require_validate(struct sieve_validator *validator, struct sieve_comman !sieve_ast_prev_cmd_is(cmd->ast_node, "require") ) ) { sieve_command_validate_error(validator, cmd, - "the require command can only be placed at top level at the beginning of the file"); + "the require command can only be placed at top level " + "at the beginning of the file"); return FALSE; } @@ -61,7 +62,8 @@ bool cmd_require_validate(struct sieve_validator *validator, struct sieve_comman } else { /* Something else */ sieve_command_validate_error(validator, cmd, - "the require command accepts a single string or string list argument but %s was found", + "the require command accepts a single string or string list argument, " + "but %s was found", sieve_ast_argument_name(arg)); return FALSE; } diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c index 12bcae1bae9122df779e76d815479ada1e6ff68a..d3447983a1759257fa17c8645d60dabb485e8e2e 100644 --- a/src/lib-sieve/ext-envelope.c +++ b/src/lib-sieve/ext-envelope.c @@ -88,20 +88,17 @@ static bool tst_envelope_validate(struct sieve_validator *validator, struct siev return FALSE; } - if ( sieve_ast_argument_type(arg) != SAAT_STRING && sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) { - sieve_command_validate_error(validator, tst, - "the envelope test expects a string-list as first argument (envelope part), but %s was found", - sieve_ast_argument_name(arg)); - return FALSE; + if ( !sieve_validate_positional_argument + (validator, tst, arg, "envelope part", 1, SAAT_STRING_LIST) ) { + return FALSE; } sieve_validator_argument_activate(validator, arg); arg = sieve_ast_argument_next(arg); - if ( sieve_ast_argument_type(arg) != SAAT_STRING && sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) { - sieve_command_validate_error(validator, tst, - "the envelope test expects a string-list as second argument (key list), but %s was found", - sieve_ast_argument_name(arg)); - return FALSE; + + if ( !sieve_validate_positional_argument + (validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) { + return FALSE; } sieve_validator_argument_activate(validator, arg); diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c index 42d0cbb53b2e3a71f7581c0d24e70caf5d98bfab..d811b56d0db2bbdc628171647b7ec3dec056a25c 100644 --- a/src/lib-sieve/ext-fileinto.c +++ b/src/lib-sieve/ext-fileinto.c @@ -51,7 +51,7 @@ static bool cmd_fileinto_validate(struct sieve_validator *validator, struct siev struct sieve_ast_argument *arg; /* Check valid syntax: - * reject <reason: string> + * fileinto <folder: string> */ if ( !sieve_validate_command_arguments(validator, cmd, 1, &arg) || !sieve_validate_command_subtests(validator, cmd, 0) || @@ -60,7 +60,10 @@ static bool cmd_fileinto_validate(struct sieve_validator *validator, struct siev return FALSE; } - + if ( !sieve_validate_positional_argument + (validator, cmd, arg, "folder", 1, SAAT_STRING) ) { + return FALSE; + } sieve_validator_argument_activate(validator, arg); return TRUE; @@ -85,8 +88,8 @@ static bool cmd_fileinto_generate sieve_generator_emit_opcode_ext(generator, ext_my_id); /* Generate arguments */ - if ( !sieve_generate_arguments(generator, ctx, NULL) ) - return FALSE; + if ( !sieve_generate_arguments(generator, ctx, NULL) ) + return FALSE; return TRUE; } diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c index 141123a02234980a32451975c6ffb38be4232dec..bedc71c0e03d49d5d9fe41b79fbee4c265eaf4d1 100644 --- a/src/lib-sieve/ext-reject.c +++ b/src/lib-sieve/ext-reject.c @@ -68,6 +68,10 @@ static bool cmd_reject_validate(struct sieve_validator *validator, struct sieve_ return FALSE; } + if ( !sieve_validate_positional_argument + (validator, cmd, arg, "reason", 1, SAAT_STRING) ) { + return FALSE; + } sieve_validator_argument_activate(validator, arg); return TRUE; diff --git a/src/lib-sieve/plugins/subaddress/subaddress.sieve b/src/lib-sieve/plugins/subaddress/subaddress.sieve index 1b4a0c71581833d53e6e494403ca020d36d83968..7c2ab9329f8a247f10470a8a07d0339632e5fe0f 100644 --- a/src/lib-sieve/plugins/subaddress/subaddress.sieve +++ b/src/lib-sieve/plugins/subaddress/subaddress.sieve @@ -8,7 +8,7 @@ if address :comparator "i;ascii-casemap" :user "from" "STEPHAN" { keep; stop; } - fileinto "INBOX.frop"; + stop; } keep; diff --git a/src/lib-sieve/plugins/vacation/ext-vacation.c b/src/lib-sieve/plugins/vacation/ext-vacation.c index 085a1c5d195db9927742509e24bfb8c3c1c48d1e..d80c6392a55f2b8e9e1073d2a1afe32676ca8175 100644 --- a/src/lib-sieve/plugins/vacation/ext-vacation.c +++ b/src/lib-sieve/plugins/vacation/ext-vacation.c @@ -244,7 +244,8 @@ static bool cmd_vacation_registered(struct sieve_validator *validator, struct si /* Command validation */ -static bool cmd_vacation_validate(struct sieve_validator *validator, struct sieve_command_context *cmd) +static bool cmd_vacation_validate(struct sieve_validator *validator, + struct sieve_command_context *cmd) { struct sieve_ast_argument *arg; @@ -260,6 +261,10 @@ static bool cmd_vacation_validate(struct sieve_validator *validator, struct siev return FALSE; } + if ( !sieve_validate_positional_argument + (validator, cmd, arg, "reason", 1, SAAT_STRING) ) { + return FALSE; + } sieve_validator_argument_activate(validator, arg); return TRUE; diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c index b66658ac7b3ed577dbe2254ea19f535dcae3627b..255d29bbf12b00ea8eb9e3dd748411a9ee0d3c52 100644 --- a/src/lib-sieve/sieve-ast.c +++ b/src/lib-sieve/sieve-ast.c @@ -243,8 +243,8 @@ struct sieve_ast_argument *sieve_ast_arguments_delete return sieve_ast_arg_list_delete(first, count); } -const char *sieve_ast_argument_name(struct sieve_ast_argument *argument) { - switch ( argument->type ) { +const char *sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type) { + switch ( arg_type ) { case SAAT_NONE: return "none"; case SAAT_STRING_LIST: return "a string list"; diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h index bfc60ec3e23d5f6255e4ab6303b8ef525013e83e..6c7a657271ea600e2ec362ef3a501bb5fed73039 100644 --- a/src/lib-sieve/sieve-ast.h +++ b/src/lib-sieve/sieve-ast.h @@ -163,7 +163,9 @@ struct sieve_ast_argument *sieve_ast_argument_number_create struct sieve_ast_argument *sieve_ast_arguments_delete (struct sieve_ast_argument *first, unsigned int count); -const char *sieve_ast_argument_name(struct sieve_ast_argument *argument); +const char *sieve_ast_argument_type_name(enum sieve_ast_argument_type arg_type); +#define sieve_ast_argument_name(argument) \ + 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); diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index e60ee85d3892e97d932377a45103c1a981916743..cb4994c625d25c960afe94ffbef64e41b57a7e58 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -15,6 +15,8 @@ typedef uint64_t sieve_number_t; */ /* sieve-ast.h */ +enum sieve_ast_argument_type; + struct sieve_ast; struct sieve_ast_node; struct sieve_ast_argument; diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index 2c2cd3f39c212608ae8cb0f3cf55af95bd021b13..aeb39f2a59a6ab69120aba736fe4887998565547 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -329,7 +329,48 @@ inline const void *sieve_validator_extension_get_context(struct sieve_validator return array_idx(&validator->ext_contexts, (unsigned int) ext_id); } -/* Tag Validation API */ +/* Argument Validation API */ + +bool sieve_validate_positional_argument + (struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg, const char *arg_name, unsigned int arg_pos, + enum sieve_ast_argument_type req_type) +{ + if ( sieve_ast_argument_type(arg) != req_type && + (sieve_ast_argument_type(arg) != SAAT_STRING || + req_type != SAAT_STRING_LIST) ) + { + sieve_command_validate_error(validator, cmd, + "the %s %s expects %s as argument %d (%s), but %s was found", + cmd->command->identifier, sieve_command_type_name(cmd->command), + sieve_ast_argument_type_name(req_type), + arg_pos, arg_name, sieve_ast_argument_name(arg)); + return FALSE; + } + + return TRUE; +} + +void sieve_validator_argument_activate + (struct sieve_validator *validator ATTR_UNUSED, struct sieve_ast_argument *arg) +{ + switch ( sieve_ast_argument_type(arg) ) { + case SAAT_NUMBER: + arg->argument = &number_argument; + break; + case SAAT_STRING: + arg->argument = &string_argument; + break; + case SAAT_STRING_LIST: + arg->argument = &string_list_argument; + break; + case SAAT_TAG: + i_error("!!BUG!!: sieve_validator_argument_activate: cannot activate tagged argument."); + break; + default: + break; + } +} /* Test validation API */ @@ -428,27 +469,6 @@ bool sieve_validate_command_arguments return TRUE; } - -void sieve_validator_argument_activate - (struct sieve_validator *validator ATTR_UNUSED, struct sieve_ast_argument *arg) -{ - switch ( sieve_ast_argument_type(arg) ) { - case SAAT_NUMBER: - arg->argument = &number_argument; - break; - case SAAT_STRING: - arg->argument = &string_argument; - break; - case SAAT_STRING_LIST: - arg->argument = &string_list_argument; - break; - case SAAT_TAG: - i_error("!!BUG!!: sieve_validator_argument_activate: cannot activate tagged argument."); - break; - default: - break; - } -} /* Command Validation API */ @@ -580,15 +600,16 @@ static bool sieve_validate_test(struct sieve_validator *validator, struct sieve_ 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 ) { - sieve_validate_test(validator, test); + result = result && sieve_validate_test(validator, test); test = sieve_ast_test_next(test); } - return TRUE; + return result; } static bool sieve_validate_command(struct sieve_validator *validator, struct sieve_ast_node *cmd_node) @@ -646,17 +667,18 @@ static bool sieve_validate_command(struct sieve_validator *validator, struct sie static bool sieve_validate_block(struct sieve_validator *validator, struct sieve_ast_node *block) { + bool result = TRUE; struct sieve_ast_node *command; t_push(); command = sieve_ast_command_first(block); while ( command != NULL ) { - sieve_validate_command(validator, command); + result = result && sieve_validate_command(validator, command); command = sieve_ast_command_next(command); } t_pop(); - return TRUE; + return result; } bool sieve_validator_run(struct sieve_validator *validator) { diff --git a/src/lib-sieve/sieve-validator.h b/src/lib-sieve/sieve-validator.h index f980b6dea249a93c85241964c49ae5280fec55b6..601e5200fc9ffaca19d98bd2d8eebb1626f0943f 100644 --- a/src/lib-sieve/sieve-validator.h +++ b/src/lib-sieve/sieve-validator.h @@ -37,9 +37,14 @@ void sieve_validator_link_match_type_tags unsigned int id_code); /* Argument validation */ + bool sieve_validate_command_arguments (struct sieve_validator *validator, struct sieve_command_context *tst, const unsigned int count, struct sieve_ast_argument **first_positional); +bool sieve_validate_positional_argument + (struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg, const char *arg_name, unsigned int arg_pos, + enum sieve_ast_argument_type req_type); void sieve_validator_argument_activate (struct sieve_validator *validator, struct sieve_ast_argument *arg); diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c index cb65d0c71af5767bcc8cea8c0b6ff3961f554bf6..69ef9c0387efeb2a96fa463f2988f094518b30f6 100644 --- a/src/lib-sieve/tst-address.c +++ b/src/lib-sieve/tst-address.c @@ -58,20 +58,17 @@ bool tst_address_validate(struct sieve_validator *validator, struct sieve_comman tst->data = arg; - if ( sieve_ast_argument_type(arg) != SAAT_STRING && sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) { - sieve_command_validate_error(validator, tst, - "the address test expects a string-list as first argument (header list), but %s was found", - sieve_ast_argument_name(arg)); - return FALSE; + if ( !sieve_validate_positional_argument + (validator, tst, arg, "header list", 1, SAAT_STRING_LIST) ) { + return FALSE; } sieve_validator_argument_activate(validator, arg); - + arg = sieve_ast_argument_next(arg); - if ( sieve_ast_argument_type(arg) != SAAT_STRING && sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) { - sieve_command_validate_error(validator, tst, - "the address test expects a string-list as second argument (key list), but %s was found", - sieve_ast_argument_name(arg)); - return FALSE; + + if ( !sieve_validate_positional_argument + (validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) { + return FALSE; } sieve_validator_argument_activate(validator, arg); @@ -104,26 +101,26 @@ static bool tst_address_opcode_dump printf("ADDRESS\n"); /* Handle any optional arguments */ - if ( sieve_operand_optional_present(sbin, address) ) { - while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) { - switch ( opt_code ) { - case OPT_COMPARATOR: + if ( sieve_operand_optional_present(sbin, address) ) { + while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) { + switch ( opt_code ) { + case OPT_COMPARATOR: if ( !sieve_opr_comparator_dump(interp, sbin, address) ) return FALSE; - break; - case OPT_MATCH_TYPE: + break; + case OPT_MATCH_TYPE: if ( !sieve_opr_match_type_dump(interp, sbin, address) ) - return FALSE; - break; + return FALSE; + break; case OPT_ADDRESS_PART: if ( !sieve_opr_address_part_dump(interp, sbin, address) ) return FALSE; break; - default: - return FALSE; - } - } - } + default: + return FALSE; + } + } + } return sieve_opr_stringlist_dump(sbin, address) && @@ -149,26 +146,26 @@ static bool tst_address_opcode_execute printf("?? ADDRESS\n"); /* Handle any optional arguments */ - if ( sieve_operand_optional_present(sbin, address) ) { - while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) { - switch ( opt_code ) { - case OPT_COMPARATOR: - if ( (cmp = sieve_opr_comparator_read(interp, sbin, address)) == NULL ) + if ( sieve_operand_optional_present(sbin, address) ) { + while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) { + switch ( opt_code ) { + case OPT_COMPARATOR: + if ( (cmp = sieve_opr_comparator_read(interp, sbin, address)) == NULL ) return FALSE; - break; - case OPT_MATCH_TYPE: - if ( (mtch = sieve_opr_match_type_read(interp, sbin, address)) == NULL ) + break; + case OPT_MATCH_TYPE: + if ( (mtch = sieve_opr_match_type_read(interp, sbin, address)) == NULL ) return FALSE; - break; + break; case OPT_ADDRESS_PART: if ( (addrp = sieve_opr_address_part_read(interp, sbin, address)) == NULL ) return FALSE; break; - default: - return FALSE; - } - } - } + default: + return FALSE; + } + } + } t_push(); diff --git a/src/lib-sieve/tst-exists.c b/src/lib-sieve/tst-exists.c index e515c089e10895cb99584887191ca5219548487d..d5c1d37967914a699d1c7a43f943f4b4cf8fe4fe 100644 --- a/src/lib-sieve/tst-exists.c +++ b/src/lib-sieve/tst-exists.c @@ -30,11 +30,9 @@ bool tst_exists_validate(struct sieve_validator *validator, struct sieve_command return FALSE; } - if ( sieve_ast_argument_type(arg) != SAAT_STRING && sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) { - sieve_command_validate_error(validator, tst, - "the exists test expects a string-list as only argument (header names), but %s was found", - sieve_ast_argument_name(arg)); - return FALSE; + if ( !sieve_validate_positional_argument + (validator, tst, arg, "header names", 1, SAAT_STRING_LIST) ) { + return FALSE; } sieve_validator_argument_activate(validator, arg); diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c index ff42d2484b9f44bb4e6869d0a0c4bf643d9a0e68..30567c0329097664a6d20a7364588f823f4da414 100644 --- a/src/lib-sieve/tst-header.c +++ b/src/lib-sieve/tst-header.c @@ -51,20 +51,17 @@ bool tst_header_validate(struct sieve_validator *validator, struct sieve_command !sieve_validate_command_subtests(validator, tst, 0) ) return FALSE; - if ( sieve_ast_argument_type(arg) != SAAT_STRING && sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) { - sieve_command_validate_error(validator, tst, - "the header test expects a string-list as first argument (header names), but %s was found", - sieve_ast_argument_name(arg)); - return FALSE; + if ( !sieve_validate_positional_argument + (validator, tst, arg, "header names", 1, SAAT_STRING_LIST) ) { + return FALSE; } sieve_validator_argument_activate(validator, arg); arg = sieve_ast_argument_next(arg); - if ( sieve_ast_argument_type(arg) != SAAT_STRING && sieve_ast_argument_type(arg) != SAAT_STRING_LIST ) { - sieve_command_validate_error(validator, tst, - "the header test expects a string-list as second argument (key list), but %s was found", - sieve_ast_argument_name(arg)); - return FALSE; + + if ( !sieve_validate_positional_argument + (validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) { + return FALSE; } sieve_validator_argument_activate(validator, arg); @@ -79,8 +76,8 @@ bool tst_header_generate sieve_generator_emit_opcode(generator, SIEVE_OPCODE_HEADER); /* Generate arguments */ - if ( !sieve_generate_arguments(generator, ctx, NULL) ) - return FALSE; + if ( !sieve_generate_arguments(generator, ctx, NULL) ) + return FALSE; return TRUE; } @@ -93,7 +90,7 @@ static bool tst_header_opcode_dump { unsigned int opt_code; - printf("HEADER\n"); + printf("HEADER\n"); /* Handle any optional arguments */ if ( sieve_operand_optional_present(sbin, address) ) { @@ -112,8 +109,8 @@ static bool tst_header_opcode_dump } return - sieve_opr_stringlist_dump(sbin, address) && - sieve_opr_stringlist_dump(sbin, address); + sieve_opr_stringlist_dump(sbin, address) && + sieve_opr_stringlist_dump(sbin, address); } /* Code execution */ @@ -134,20 +131,20 @@ static bool tst_header_opcode_execute printf("?? HEADER\n"); /* Handle any optional arguments */ - if ( sieve_operand_optional_present(sbin, address) ) { - while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) { - switch ( opt_code ) { - case OPT_COMPARATOR: - cmp = sieve_opr_comparator_read(interp, sbin, address); - break; - case OPT_MATCH_TYPE: - mtch = sieve_opr_match_type_read(interp, sbin, address); - break; - default: - return FALSE; - } - } - } + if ( sieve_operand_optional_present(sbin, address) ) { + while ( (opt_code=sieve_operand_optional_read(sbin, address)) ) { + switch ( opt_code ) { + case OPT_COMPARATOR: + cmp = sieve_opr_comparator_read(interp, sbin, address); + break; + case OPT_MATCH_TYPE: + mtch = sieve_opr_match_type_read(interp, sbin, address); + break; + default: + return FALSE; + } + } + } t_push(); diff --git a/src/lib-sieve/tst-size.c b/src/lib-sieve/tst-size.c index 2ddca289ca193e4e409d5c32bc687787fe47c9eb..5823e4ca19da4e97c5463e49606d4596f34f281f 100644 --- a/src/lib-sieve/tst-size.c +++ b/src/lib-sieve/tst-size.c @@ -114,11 +114,9 @@ bool tst_size_validate(struct sieve_validator *validator, struct sieve_command_c return FALSE; } - if ( sieve_ast_argument_type(arg) != SAAT_NUMBER ) { - sieve_command_validate_error(validator, tst, - "the size test expects a number as argument (limit), but %s was found", - sieve_ast_argument_name(arg)); - return FALSE; + if ( !sieve_validate_positional_argument + (validator, tst, arg, "limit", 1, SAAT_NUMBER) ) { + return FALSE; } sieve_validator_argument_activate(validator, arg);