diff --git a/src/lib-sieve/plugins/regex/ext-regex.c b/src/lib-sieve/plugins/regex/ext-regex.c index 6a379acfae2d257f86c968ea890cdb56a7dcd7a9..e34746bd5235c6bebd6edd67934b90c4cfc79c0f 100644 --- a/src/lib-sieve/plugins/regex/ext-regex.c +++ b/src/lib-sieve/plugins/regex/ext-regex.c @@ -57,7 +57,8 @@ const struct sieve_match_type regex_match_type = { "regex", SIEVE_MATCH_TYPE_CUSTOM, ®ex_match_extension, - 0 + 0, + NULL }; const struct sieve_match_type_extension regex_match_extension = { diff --git a/src/lib-sieve/plugins/relational/ext-relational.c b/src/lib-sieve/plugins/relational/ext-relational.c index 4687f15af19dfbbe6499dda88c48cc4f4bd542b1..5b46af083f8b2a1c552e8ddcae5f4412f9524d91 100644 --- a/src/lib-sieve/plugins/relational/ext-relational.c +++ b/src/lib-sieve/plugins/relational/ext-relational.c @@ -3,7 +3,7 @@ * * Author: Stephan Bosch * Specification: RFC 3431 - * Implementation: + * Implementation: validation only * Status: under development * */ @@ -18,6 +18,7 @@ #include "sieve-common.h" +#include "sieve-ast.h" #include "sieve-code.h" #include "sieve-extensions.h" #include "sieve-commands.h" @@ -33,6 +34,18 @@ static bool ext_relational_validator_load(struct sieve_validator *validator); static bool ext_relational_interpreter_load (struct sieve_interpreter *interpreter); +/* Types */ + +enum relational_match { + REL_MATCH_GREATER, + REL_MATCH_GREATER_EQUAL, + REL_MATCH_LESS, + REL_MATCH_LESS_EQUAL, + REL_MATCH_EQUAL, + REL_MATCH_NOT_EQUAL, + REL_MATCH_INVALID +}; + /* Extension definitions */ static int ext_my_id; @@ -54,6 +67,97 @@ static bool ext_relational_load(int ext_id) return TRUE; } +/* Validation */ + +static bool ext_relational_parameter_validate + (struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_match_type_context *ctx) +{ + enum relational_match rel_match = REL_MATCH_INVALID; + const char *rel_match_id; + + /* Check syntax: + * relational-match = DQUOTE ( "gt" / "ge" / "lt" + * / "le" / "eq" / "ne" ) DQUOTE + * + * So, actually this must be a constant string and it is implemented as such + */ + + /* Did we get a string in the first place ? */ + if ( (*arg)->type != SAAT_STRING ) { + sieve_command_validate_error(validator, ctx->command_ctx, + "the :%s match-type requires a constant string argument containing " + "one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", " + "but %s was found", + ctx->match_type->identifier, sieve_ast_argument_name(*arg)); + return FALSE; + } + + /* Check the relational match id */ + + rel_match_id = sieve_ast_argument_strc(*arg); + switch ( rel_match_id[0] ) { + /* "gt" or "ge" */ + case 'g': + switch ( rel_match_id[1] ) { + case 't': + rel_match = REL_MATCH_GREATER; + break; + case 'e': + rel_match = REL_MATCH_GREATER_EQUAL; + break; + default: + rel_match = REL_MATCH_INVALID; + } + break; + /* "lt" or "le" */ + case 'l': + switch ( rel_match_id[1] ) { + case 't': + rel_match = REL_MATCH_LESS; + break; + case 'e': + rel_match = REL_MATCH_LESS_EQUAL; + break; + default: + rel_match = REL_MATCH_INVALID; + } + break; + /* "eq" */ + case 'e': + if ( rel_match_id[1] == 'q' ) + rel_match = REL_MATCH_EQUAL; + else + rel_match = REL_MATCH_INVALID; + + break; + /* "ne" */ + case 'n': + if ( rel_match_id[1] == 'e' ) + rel_match = REL_MATCH_NOT_EQUAL; + else + rel_match = REL_MATCH_INVALID; + break; + /* invalid */ + default: + rel_match = REL_MATCH_INVALID; + } + + if ( rel_match >= REL_MATCH_INVALID ) { + sieve_command_validate_error(validator, ctx->command_ctx, + "the :%s match-type requires a constant string argument containing " + "one of \"gt\", \"ge\", \"lt\", \"le\", \"eq\" or \"ne\", " + "but \"%s\" was found", + ctx->match_type->identifier, rel_match_id); + return FALSE; + } + + /* Delete argument */ + *arg = sieve_ast_arguments_delete(*arg, 1); + + return TRUE; +} + /* Actual extension implementation */ @@ -70,14 +174,16 @@ const struct sieve_match_type value_match_type = { "value", SIEVE_MATCH_TYPE_CUSTOM, &relational_match_extension, - RELATIONAL_VALUE + RELATIONAL_VALUE, + ext_relational_parameter_validate }; const struct sieve_match_type count_match_type = { "count", SIEVE_MATCH_TYPE_CUSTOM, &relational_match_extension, - RELATIONAL_COUNT + RELATIONAL_COUNT, + ext_relational_parameter_validate }; static const struct sieve_match_type *ext_relational_get_match diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c index 48e16c3ca421a90f86c2339b36acc29b86d44bfa..2ef62a893b78c3e0caab1b564f29ecbf91b2a681 100644 --- a/src/lib-sieve/sieve-match-types.c +++ b/src/lib-sieve/sieve-match-types.c @@ -22,9 +22,9 @@ */ static void opr_match_type_emit - (struct sieve_binary *sbin, struct sieve_match_type *addrp); + (struct sieve_binary *sbin, const struct sieve_match_type *mtch); static void opr_match_type_emit_ext - (struct sieve_binary *sbin, struct sieve_match_type *addrp, int ext_id); + (struct sieve_binary *sbin, const struct sieve_match_type *mtch, int ext_id); /* * Address-part 'extension' @@ -78,25 +78,25 @@ static inline struct mtch_validator_context * static void _sieve_match_type_register (pool_t pool, struct mtch_validator_context *ctx, - const struct sieve_match_type *addrp, int ext_id) + const struct sieve_match_type *mtch, int ext_id) { struct mtch_validator_registration *reg; reg = p_new(pool, struct mtch_validator_registration, 1); - reg->match_type = addrp; + reg->match_type = mtch; reg->ext_id = ext_id; - hash_insert(ctx->registrations, (void *) addrp->identifier, (void *) reg); + hash_insert(ctx->registrations, (void *) mtch->identifier, (void *) reg); } void sieve_match_type_register (struct sieve_validator *validator, - const struct sieve_match_type *addrp, int ext_id) + const struct sieve_match_type *mtch, int ext_id) { pool_t pool = sieve_validator_pool(validator); struct mtch_validator_context *ctx = get_validator_context(validator); - _sieve_match_type_register(pool, ctx, addrp, ext_id); + _sieve_match_type_register(pool, ctx, mtch, ext_id); } const struct sieve_match_type *sieve_match_type_find @@ -129,9 +129,9 @@ bool mtch_validator_load(struct sieve_validator *validator) /* Register core match-types */ for ( i = 0; i < sieve_core_match_types_count; i++ ) { - const struct sieve_match_type *addrp = sieve_core_match_types[i]; + const struct sieve_match_type *mtch = sieve_core_match_types[i]; - _sieve_match_type_register(pool, ctx, addrp, -1); + _sieve_match_type_register(pool, ctx, mtch, -1); } sieve_validator_extension_set_context(validator, ext_my_id, ctx); @@ -231,20 +231,21 @@ static bool tag_match_type_validate struct sieve_command_context *cmd) { int ext_id; - const struct sieve_match_type *addrp; + struct sieve_match_type_context *mtctx; + const struct sieve_match_type *mtch; /* Syntax: - * ":localpart" / ":domain" / ":all" (subject to extension) + * ":is" / ":contains" / ":matches" (subject to extension) */ /* Get match_type from registry */ - addrp = sieve_match_type_find + mtch = sieve_match_type_find (validator, sieve_ast_argument_tag(*arg), &ext_id); - /* In theory, addrp can never be NULL, because we must have found it earlier + /* In theory, mtch can never be NULL, because we must have found it earlier * to get here. */ - if ( addrp == NULL ) { + if ( mtch == NULL ) { sieve_command_validate_error(validator, cmd, "unknown match-type modifier '%s' " "(this error should not occur and is probably a bug)", @@ -253,35 +254,43 @@ static bool tag_match_type_validate return FALSE; } - /* Store match-type in context */ - (*arg)->context = (void *) addrp; + /* Create context */ + mtctx = p_new(sieve_command_pool(cmd), struct sieve_match_type_context, 1); + mtctx->match_type = mtch; + mtctx->command_ctx = cmd; + + (*arg)->context = (void *) mtctx; (*arg)->ext_id = ext_id; /* Skip tag */ *arg = sieve_ast_argument_next(*arg); - + + if ( mtch->validate != NULL ) { + return mtch->validate(validator, arg, mtctx); + } + return TRUE; } /* Code generation */ static void opr_match_type_emit - (struct sieve_binary *sbin, struct sieve_match_type *addrp) + (struct sieve_binary *sbin, const struct sieve_match_type *mtch) { (void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_MATCH_TYPE); - (void) sieve_binary_emit_byte(sbin, addrp->code); + (void) sieve_binary_emit_byte(sbin, mtch->code); } static void opr_match_type_emit_ext - (struct sieve_binary *sbin, struct sieve_match_type *addrp, int ext_id) + (struct sieve_binary *sbin, const struct sieve_match_type *mtch, int ext_id) { unsigned char mtch_code = SIEVE_MATCH_TYPE_CUSTOM + sieve_binary_extension_get_index(sbin, ext_id); (void) sieve_operand_emit_code(sbin, SIEVE_OPERAND_MATCH_TYPE); (void) sieve_binary_emit_byte(sbin, mtch_code); - if ( addrp->extension->match_type == NULL ) - (void) sieve_binary_emit_byte(sbin, addrp->ext_code); + if ( mtch->extension->match_type == NULL ) + (void) sieve_binary_emit_byte(sbin, mtch->ext_code); } const struct sieve_match_type *sieve_opr_match_type_read @@ -332,13 +341,13 @@ bool sieve_opr_match_type_dump struct sieve_binary *sbin, sieve_size_t *address) { sieve_size_t pc = *address; - const struct sieve_match_type *addrp = + const struct sieve_match_type *mtch = sieve_opr_match_type_read(interpreter, sbin, address); - if ( addrp == NULL ) + if ( mtch == NULL ) return FALSE; - printf("%08x: MATCH-TYPE: %s\n", pc, addrp->identifier); + printf("%08x: MATCH-TYPE: %s\n", pc, mtch->identifier); return TRUE; } @@ -348,16 +357,16 @@ static bool tag_match_type_generate struct sieve_command_context *cmd ATTR_UNUSED) { struct sieve_binary *sbin = sieve_generator_get_binary(generator); - struct sieve_match_type *addrp = - (struct sieve_match_type *) (*arg)->context; + struct sieve_match_type_context *mtctx = + (struct sieve_match_type_context *) (*arg)->context; - if ( addrp->extension == NULL ) { - if ( addrp->code < SIEVE_MATCH_TYPE_CUSTOM ) - opr_match_type_emit(sbin, addrp); + if ( mtctx->match_type->extension == NULL ) { + if ( mtctx->match_type->code < SIEVE_MATCH_TYPE_CUSTOM ) + opr_match_type_emit(sbin, mtctx->match_type); else return FALSE; } else { - opr_match_type_emit_ext(sbin, addrp, (*arg)->ext_id); + opr_match_type_emit_ext(sbin, mtctx->match_type, (*arg)->ext_id); } *arg = sieve_ast_argument_next(*arg); @@ -386,6 +395,7 @@ const struct sieve_match_type is_match_type = { SIEVE_MATCH_TYPE_IS, NULL, 0, + NULL }; const struct sieve_match_type contains_match_type = { @@ -393,6 +403,7 @@ const struct sieve_match_type contains_match_type = { SIEVE_MATCH_TYPE_CONTAINS, NULL, 0, + NULL }; const struct sieve_match_type matches_match_type = { @@ -400,6 +411,7 @@ const struct sieve_match_type matches_match_type = { SIEVE_MATCH_TYPE_MATCHES, NULL, 0, + NULL }; const struct sieve_match_type *sieve_core_match_types[] = { diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h index 7af63242d94df1a0e49a0078144ea94a3a972253..08814f1bd7028f5da1f230898060bec75b4716c4 100644 --- a/src/lib-sieve/sieve-match-types.h +++ b/src/lib-sieve/sieve-match-types.h @@ -11,6 +11,7 @@ enum sieve_match_type_code { }; struct sieve_match_type_extension; +struct sieve_match_type_context; struct sieve_match_type { const char *identifier; @@ -19,6 +20,10 @@ struct sieve_match_type { const struct sieve_match_type_extension *extension; unsigned int ext_code; + + bool (*validate) + (struct sieve_validator *validator, struct sieve_ast_argument **arg, + struct sieve_match_type_context *ctx); }; struct sieve_match_type_extension { @@ -32,6 +37,12 @@ struct sieve_match_type_extension { (unsigned int code); }; +struct sieve_match_type_context { + struct sieve_command_context *command_ctx; + const struct sieve_match_type *match_type; + void *ctx_data; +}; + void sieve_match_types_link_tags (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg,