diff --git a/sieve/tests/encoded-character.sieve b/sieve/tests/encoded-character.sieve index 6b629b3a2eaceca48c052dbbd6c85e14e79d3932..110e6ba25be0d86f773c58a55f26221f822fc6c5 100644 --- a/sieve/tests/encoded-character.sieve +++ b/sieve/tests/encoded-character.sieve @@ -1 +1,5 @@ require "encoded-character"; +require "reject"; + +reject "You are an ${hex: 40 41 42 43 55}."; + diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c index 17d35e68c8da50339888d6063a2943ecff68c0cf..d0557d4a42e7446982f27c0acbe77f41dc42ea1d 100644 --- a/src/lib-sieve/cmd-redirect.c +++ b/src/lib-sieve/cmd-redirect.c @@ -98,7 +98,7 @@ static bool cmd_redirect_validate (validator, cmd, arg, "address", 1, SAAT_STRING) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, cmd, arg, FALSE); return TRUE; } diff --git a/src/lib-sieve/ext-encoded-character.c b/src/lib-sieve/ext-encoded-character.c index 2c6d3451fefd29eaa37c3765914abb661be69158..82ec15f0933caf1f8eb132b3ecc77bb683685daa 100644 --- a/src/lib-sieve/ext-encoded-character.c +++ b/src/lib-sieve/ext-encoded-character.c @@ -47,18 +47,195 @@ bool arg_encoded_string_validate const struct sieve_argument encoded_string_argument = { "@encoded-string", NULL, arg_encoded_string_validate, NULL, NULL }; -bool arg_encoded_string_validate - (struct sieve_validator *validator, struct sieve_ast_argument **arg, - struct sieve_command_context *context) +static bool _skip_whitespace + (const char **in, const char *inend) { + while ( *in < inend ) { + if ( **in == '\r' ) { + (*in)++; + if ( **in != '\n' ) + return FALSE; + continue; + } + + if ( **in != ' ' && **in != '\n' ) /* Loose LF is non-standard */ + break; + + (*in)++; + } + return TRUE; } +static bool _parse_hexint +(const char **in, const char *inend, int max_digits, unsigned int *result) +{ + int digit = 0; + *result = 0; + + while ( *in < inend && digit < max_digits ) { + + if ( (**in) >= '0' && (**in) <= '9' ) + *result = ((*result) << 4) + (**in) - ((unsigned int) '0'); + else if ( (**in) >= 'a' && (**in) <= 'f' ) + *result = ((*result) << 4) + (**in) - ((unsigned int) 'a') + 0x0a; + else if ( (**in) >= 'A' && (**in) <= 'F' ) + *result = ((*result) << 4) + (**in) - ((unsigned int) 'A') + 0x0a; + else + return ( digit > 0 ); + + (*in)++; + digit++; + } + + if ( digit == max_digits ) { + /* Hex digit _MUST_ end here */ + if ( (**in >= '0' && **in <= '9') || (**in >= 'a' && **in <= 'f') || + (**in >= 'A' && **in <= 'F') ) + return FALSE; + + return TRUE; + } + + return ( digit > 0 ); +} + +static bool _decode_hex +(const char **in, const char *inend, string_t *result) +{ + int values = 0; + + for (;;) { + unsigned int hexpair; + + if ( !_skip_whitespace(in, inend) ) return FALSE; + + if ( !_parse_hexint(in, inend, 2, &hexpair) ) break; + + str_append_c(result, (unsigned char) hexpair); + values++; + } + + return ( values > 0 ); +} + +static bool _decode_unicode +(const char **in, const char *inend, string_t *result) +{ + int values = 0; + + for (;;) { + unsigned int unicode_hex; + + if ( !_skip_whitespace(in, inend) ) return FALSE; + + if ( !_parse_hexint(in, inend, 6, &unicode_hex) ) break; + + /* FIXME: unicode is unimplemented */ + str_append(result, ">>unicode unimplemented<<"); + values++; + } + + return ( values > 0 ); +} + +bool arg_encoded_string_validate +(struct sieve_validator *validator ATTR_UNUSED, struct sieve_ast_argument **arg, + struct sieve_command_context *cmd) +{ + enum { ST_NONE, ST_OPEN, ST_TYPE, 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 ( p < strend ) { + switch ( state ) { + case ST_NONE: + if ( *p == '$' ) { + substart = p; + state = ST_OPEN; + } + p++; + break; + case ST_OPEN: + if ( *p == '{' ) { + state = ST_TYPE; + p++; + } else + state = ST_NONE; + break; + case ST_TYPE: + mark = p; + while ( p < strend && *p != ':' && *p != '$' && *p != '}' ) p++; + + if ( *p == '$' || *p == '}' ) { + state = ST_NONE; + break; + } + + state = ST_CLOSE; + + str_truncate(tmpstr, 0); + if ( strncasecmp(mark, "hex", p - mark) == 0 ) { + p++; + if ( !_decode_hex(&p, strend, tmpstr) ) + state = ST_NONE; + } else if ( strncasecmp(mark, "unicode", p - mark) == 0 ) { + p++; + if ( !_decode_unicode(&p, strend, tmpstr) ) + state = ST_NONE; + } else { + p++; + state = ST_NONE; + } + 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); + + printf("RESULT: %s\n", str_c(newstr)); + + sieve_ast_argument_str_set(*arg, newstr); + } + + return sieve_validator_argument_activate_super + (validator, cmd, *arg, TRUE); +} + /* Load extension into validator */ static bool ext_encoded_character_validator_load (struct sieve_validator *validator ATTR_UNUSED) { -// sieve_validator_argument_override(validator, + sieve_validator_argument_override(validator, SAT_CONST_STRING, + &encoded_string_argument); return TRUE; } diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c index 5efa31dd8ee315859838538d4895e602747f64f3..6a4013bd75313a8aa47f69be677acad8c91d50d1 100644 --- a/src/lib-sieve/ext-envelope.c +++ b/src/lib-sieve/ext-envelope.c @@ -116,7 +116,7 @@ static bool tst_envelope_validate(struct sieve_validator *validator, struct siev (validator, tst, arg, "envelope part", 1, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); arg = sieve_ast_argument_next(arg); @@ -124,7 +124,7 @@ static bool tst_envelope_validate(struct sieve_validator *validator, struct siev (validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); /* Validate the key argument to a specified match type */ sieve_match_type_validate(validator, tst, arg); diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c index 770a828fab04daaa7cf0bac3adb02e17c5cc8fd3..f4ababf13eed39ab92d54385df567e1d78b0a035 100644 --- a/src/lib-sieve/ext-fileinto.c +++ b/src/lib-sieve/ext-fileinto.c @@ -94,7 +94,7 @@ static bool cmd_fileinto_validate(struct sieve_validator *validator, struct siev (validator, cmd, arg, "folder", 1, SAAT_STRING) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, cmd, arg, FALSE); return TRUE; } diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c index 099fc58ae9cdddd885bba007e409295d909233da..e9fc70b26a9a8a641d16bac7309829b09c715d07 100644 --- a/src/lib-sieve/ext-reject.c +++ b/src/lib-sieve/ext-reject.c @@ -132,7 +132,7 @@ static bool cmd_reject_validate(struct sieve_validator *validator, struct sieve_ (validator, cmd, arg, "reason", 1, SAAT_STRING) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, cmd, arg, FALSE); return TRUE; } diff --git a/src/lib-sieve/plugins/body/tst-body.c b/src/lib-sieve/plugins/body/tst-body.c index fc64e9f4cf87ddd54e7752dc9f4318fa2d4e7c6e..f0c0e0a3da7a0cd00f1c6668af467af6d71de0a1 100644 --- a/src/lib-sieve/plugins/body/tst-body.c +++ b/src/lib-sieve/plugins/body/tst-body.c @@ -141,7 +141,7 @@ static bool tag_body_transform_validate (validator, cmd, tag, *arg, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, *arg, FALSE); + sieve_validator_argument_activate(validator, cmd, *arg, FALSE); /* Assign tag parameters */ tag->parameters = *arg; @@ -193,7 +193,7 @@ static bool tst_body_validate (validator, tst, arg, "key list", 1, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); /* Validate the key argument to a specified match type */ sieve_match_type_validate(validator, tst, arg); diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c index 411f37335eea0e18f4b72714c114f07b0f737273..a4a7473ba0a924224402125c20d0bb726c757f0d 100644 --- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c +++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c @@ -36,7 +36,7 @@ bool ext_imapflags_command_validate arg2 = sieve_ast_argument_next(arg); if ( arg2 != NULL ) { - sieve_validator_argument_activate(validator, arg, TRUE); + sieve_validator_argument_activate(validator, cmd, arg, TRUE); /* First, check syntax sanity */ @@ -73,7 +73,7 @@ bool ext_imapflags_command_validate } else arg2 = arg; - sieve_validator_argument_activate(validator, arg2, FALSE); + sieve_validator_argument_activate(validator, cmd, arg2, FALSE); return TRUE; } diff --git a/src/lib-sieve/plugins/imapflags/tst-hasflag.c b/src/lib-sieve/plugins/imapflags/tst-hasflag.c index d62276ebb061c06ab9984b47abbd59d43c3f7c24..8c81ed7029a41d48a35d2944c0c4276004cf3afd 100644 --- a/src/lib-sieve/plugins/imapflags/tst-hasflag.c +++ b/src/lib-sieve/plugins/imapflags/tst-hasflag.c @@ -107,7 +107,7 @@ static bool tst_hasflag_validate arg2 = sieve_ast_argument_next(arg); if ( arg2 != NULL ) { - sieve_validator_argument_activate(validator, arg, TRUE); + sieve_validator_argument_activate(validator, tst, arg, TRUE); /* First, check syntax sanity */ @@ -134,7 +134,7 @@ static bool tst_hasflag_validate } else arg2 = arg; - sieve_validator_argument_activate(validator, arg2, FALSE); + sieve_validator_argument_activate(validator, tst, arg2, FALSE); /* Validate the key argument to a specified match type */ diff --git a/src/lib-sieve/plugins/vacation/ext-vacation.c b/src/lib-sieve/plugins/vacation/ext-vacation.c index f0e269e8248b9958a12d579d242d531347449071..6ba0d53941812b2ed8a82fe2f84ec598b548d172 100644 --- a/src/lib-sieve/plugins/vacation/ext-vacation.c +++ b/src/lib-sieve/plugins/vacation/ext-vacation.c @@ -288,7 +288,7 @@ static bool cmd_vacation_validate(struct sieve_validator *validator, (validator, cmd, arg, "reason", 1, SAAT_STRING) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, cmd, arg, FALSE); return TRUE; } diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h index d958aeb48f456a002ff6987996d02fc715fb2601..101c9d6f9b9f15ebdb074a66a14f1c5f0171bfe5 100644 --- a/src/lib-sieve/sieve-ast.h +++ b/src/lib-sieve/sieve-ast.h @@ -252,6 +252,9 @@ void sieve_ast_unparse(struct sieve_ast *ast); #define sieve_ast_argument_tag(argument) ((argument)->_value.tag) #define sieve_ast_argument_number(argument) ((argument)->_value.number) +#define sieve_ast_argument_str_set(argument, newstr) \ + (argument)->_value.str = newstr + /* 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) diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c index 42252a1abbe817093c8e7ef7f3ea21594508bd96..a2c96c84405b4bf12d99ad4aca51ec95c505233e 100644 --- a/src/lib-sieve/sieve-validator.c +++ b/src/lib-sieve/sieve-validator.c @@ -19,11 +19,13 @@ struct sieve_default_argument { struct sieve_default_argument *overrides; }; -/* Context/Semantics checker implementation */ +/* + * Context/Semantics checker implementation + */ struct sieve_validator { pool_t pool; - + struct sieve_ast *ast; struct sieve_script *script; @@ -36,6 +38,7 @@ struct sieve_validator { ARRAY_DEFINE(ext_contexts, void *); struct sieve_default_argument default_arguments[SAT_COUNT]; + struct sieve_default_argument *current_defarg; }; /* Predeclared statics */ @@ -277,7 +280,7 @@ static void _sieve_validator_register_tag const struct sieve_argument *tag, const char *identifier, int id_code) { struct sieve_tag_registration *reg; - + reg = p_new(validator->pool, struct sieve_tag_registration, 1); reg->tag = tag; reg->id_code = id_code; @@ -412,55 +415,99 @@ inline const void *sieve_validator_extension_get_context /* 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) +void sieve_validator_argument_override +(struct sieve_validator *validator, enum sieve_argument_type type, + const struct sieve_argument *argument) { - 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; - } + struct sieve_default_argument *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].argument = argument; +} + +static bool sieve_validator_argument_default_activate +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_default_argument *defarg, struct sieve_ast_argument *arg) +{ + bool result = TRUE; + struct sieve_default_argument *prev_defarg; + + prev_defarg = validator->current_defarg; + validator->current_defarg = defarg; + + arg->argument = defarg->argument; + if (defarg->argument != NULL && defarg->argument->validate != NULL ) + result = defarg->argument->validate(validator, &arg, cmd); + + validator->current_defarg = prev_defarg; + return TRUE; } -void sieve_validator_argument_activate - (struct sieve_validator *validator ATTR_UNUSED, - struct sieve_ast_argument *arg, bool constant) +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 ) + return FALSE; + + return sieve_validator_argument_default_activate + (validator, cmd, validator->current_defarg->overrides, arg); +} + +bool sieve_validator_argument_activate +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg, bool constant) +{ + struct sieve_default_argument *defarg; + switch ( sieve_ast_argument_type(arg) ) { case SAAT_NUMBER: - arg->argument = validator->default_arguments[SAT_NUMBER].argument; + defarg = &validator->default_arguments[SAT_NUMBER]; break; case SAAT_STRING: if ( validator->default_arguments[SAT_VAR_STRING].argument == NULL || constant ) - arg->argument = validator-> - default_arguments[SAT_CONST_STRING].argument; + defarg = &validator->default_arguments[SAT_CONST_STRING]; else - arg->argument = validator-> - default_arguments[SAT_VAR_STRING].argument; + defarg = &validator->default_arguments[SAT_VAR_STRING]; break; case SAAT_STRING_LIST: if ( validator->default_arguments[SAT_VAR_STRING_LIST].argument == NULL || constant ) - arg->argument = validator-> - default_arguments[SAT_CONST_STRING_LIST].argument; + defarg = &validator->default_arguments[SAT_CONST_STRING_LIST]; else - arg->argument = validator-> - default_arguments[SAT_VAR_STRING_LIST].argument; + defarg = &validator->default_arguments[SAT_VAR_STRING_LIST]; break; default: - break; + return FALSE; + } + + return sieve_validator_argument_default_activate(validator, cmd, defarg, arg); +} + +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; } bool sieve_validate_tag_parameter @@ -479,7 +526,7 @@ bool sieve_validate_tag_parameter sieve_ast_argument_type_name(req_type), sieve_ast_argument_name(param)); return FALSE; } - sieve_validator_argument_activate(validator, param, FALSE); + sieve_validator_argument_activate(validator, cmd, param, FALSE); param->arg_id_code = tag->arg_id_code; return TRUE; diff --git a/src/lib-sieve/sieve-validator.h b/src/lib-sieve/sieve-validator.h index e565175b69463f03cd81772633706123a4602147..fcf96d13ebaf34b482204a77862e357deb661265 100644 --- a/src/lib-sieve/sieve-validator.h +++ b/src/lib-sieve/sieve-validator.h @@ -63,13 +63,21 @@ 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, - bool constant); +bool sieve_validator_argument_activate +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg, bool constant); + bool sieve_validate_tag_parameter (struct sieve_validator *validator, struct sieve_command_context *cmd, struct sieve_ast_argument *tag, struct sieve_ast_argument *param, enum sieve_ast_argument_type req_type); + +void sieve_validator_argument_override +(struct sieve_validator *validator, enum sieve_argument_type type, + const struct sieve_argument *argument); +bool sieve_validator_argument_activate_super +(struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *arg, bool constant); /* Extensions */ int sieve_validator_extension_load diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c index d3c68214e3c661e6d62e77d7b9a58758d6e64203..fd4cb1b735ecd1c92720d720f899182a5865ac60 100644 --- a/src/lib-sieve/tst-address.c +++ b/src/lib-sieve/tst-address.c @@ -79,7 +79,7 @@ static bool tst_address_validate (validator, tst, arg, "header list", 1, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); arg = sieve_ast_argument_next(arg); @@ -87,7 +87,7 @@ static bool tst_address_validate (validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); /* Validate the key argument to a specified match type */ sieve_match_type_validate(validator, tst, arg); diff --git a/src/lib-sieve/tst-exists.c b/src/lib-sieve/tst-exists.c index 2a8058481545a24d55eb394ed44572ba263261c1..d1d403706824c4c6063be2f58d53429ffa3227fd 100644 --- a/src/lib-sieve/tst-exists.c +++ b/src/lib-sieve/tst-exists.c @@ -58,7 +58,7 @@ static bool tst_exists_validate (validator, tst, arg, "header names", 1, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); tst->data = arg; diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c index 087f4cb7ae551141e7539091ad9d31756ac0118d..b29d3b442799778d73d4fe19346327a146a821e8 100644 --- a/src/lib-sieve/tst-header.c +++ b/src/lib-sieve/tst-header.c @@ -83,7 +83,7 @@ static bool tst_header_validate (validator, tst, arg, "header names", 1, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); arg = sieve_ast_argument_next(arg); @@ -91,10 +91,10 @@ static bool tst_header_validate (validator, tst, arg, "key list", 2, SAAT_STRING_LIST) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); /* Validate the key argument to a specified match type */ - sieve_match_type_validate(validator, tst, arg); + sieve_match_type_validate(validator, tst, arg); return TRUE; } diff --git a/src/lib-sieve/tst-size.c b/src/lib-sieve/tst-size.c index 5643f3ff7b0b1fbd6e2124e7e258e434eee05ccc..92e4082046bc2d0cabb3d084ad051398fddbf8fd 100644 --- a/src/lib-sieve/tst-size.c +++ b/src/lib-sieve/tst-size.c @@ -155,7 +155,7 @@ static bool tst_size_validate (validator, tst, arg, "limit", 1, SAAT_NUMBER) ) { return FALSE; } - sieve_validator_argument_activate(validator, arg, FALSE); + sieve_validator_argument_activate(validator, tst, arg, FALSE); return TRUE; }