From ad66ace5dee06ce98081f4986cb42cc200d55e6f Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Sat, 16 Aug 2008 14:33:40 +0200 Subject: [PATCH] Cleaned up match type implementation. --- sieve/errors/match-type-errors.sieve | 16 --- src/lib-sieve/ext-envelope.c | 3 +- src/lib-sieve/plugins/body/tst-body.c | 3 +- src/lib-sieve/plugins/imapflags/tst-hasflag.c | 3 +- src/lib-sieve/plugins/regex/mcht-regex.c | 17 ++- src/lib-sieve/plugins/variables/tst-string.c | 3 +- src/lib-sieve/sieve-comparators.h | 9 +- src/lib-sieve/sieve-match-types.c | 119 ++++++++++-------- src/lib-sieve/sieve-match-types.h | 86 ++++++++----- src/lib-sieve/tst-address.c | 3 +- src/lib-sieve/tst-header.c | 3 +- src/testsuite/tst-test-error.c | 3 +- tests/compile/errors.svtest | 14 +++ tests/compile/errors/match-type.sieve | 7 ++ 14 files changed, 174 insertions(+), 115 deletions(-) delete mode 100644 sieve/errors/match-type-errors.sieve create mode 100644 tests/compile/errors/match-type.sieve diff --git a/sieve/errors/match-type-errors.sieve b/sieve/errors/match-type-errors.sieve deleted file mode 100644 index f2b08be9f..000000000 --- a/sieve/errors/match-type-errors.sieve +++ /dev/null @@ -1,16 +0,0 @@ -require "comparator-i;ascii-numeric"; - -if address :contains :is :comparator "i;ascii-casemap" :localpart "from" "STEPHAN" { - discard; - - if address :contains :domain :comparator "i;octet" :matches "from" "drunksnipers.com" { - keep; - } - stop; -} - -if header :contains :comparator "i;ascii-numeric" "from" "drunksnipers.com" { - keep; -} - -keep; diff --git a/src/lib-sieve/ext-envelope.c b/src/lib-sieve/ext-envelope.c index f8c8deaa3..5dba8dd29 100644 --- a/src/lib-sieve/ext-envelope.c +++ b/src/lib-sieve/ext-envelope.c @@ -280,7 +280,8 @@ static bool tst_envelope_validate return FALSE; /* Validate the key argument to a specified match type */ - return sieve_match_type_validate(validator, tst, arg); + return sieve_match_type_validate + (validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator); } /* diff --git a/src/lib-sieve/plugins/body/tst-body.c b/src/lib-sieve/plugins/body/tst-body.c index 1d58e30f1..5ea705450 100644 --- a/src/lib-sieve/plugins/body/tst-body.c +++ b/src/lib-sieve/plugins/body/tst-body.c @@ -207,7 +207,8 @@ static bool tst_body_validate return FALSE; /* Validate the key argument to a specified match type */ - return sieve_match_type_validate(validator, tst, arg); + return sieve_match_type_validate + (validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator); } /* diff --git a/src/lib-sieve/plugins/imapflags/tst-hasflag.c b/src/lib-sieve/plugins/imapflags/tst-hasflag.c index cf1115149..54afc9184 100644 --- a/src/lib-sieve/plugins/imapflags/tst-hasflag.c +++ b/src/lib-sieve/plugins/imapflags/tst-hasflag.c @@ -103,7 +103,8 @@ static bool tst_hasflag_validate } /* Validate the key argument to a specified match type */ - return sieve_match_type_validate(validator, tst, keys); + return sieve_match_type_validate + (validator, tst, keys, &is_match_type, &i_ascii_casemap_comparator); } /* diff --git a/src/lib-sieve/plugins/regex/mcht-regex.c b/src/lib-sieve/plugins/regex/mcht-regex.c index d38ba3338..a7935c2f1 100644 --- a/src/lib-sieve/plugins/regex/mcht-regex.c +++ b/src/lib-sieve/plugins/regex/mcht-regex.c @@ -127,18 +127,15 @@ bool mcht_regex_validate_context (struct sieve_validator *validator, struct sieve_ast_argument *arg ATTR_UNUSED, struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg) { + const struct sieve_comparator *cmp = ctx->comparator; int cflags = REG_EXTENDED | REG_NOSUB; struct _regex_key_context keyctx; - struct sieve_ast_argument *cmp_arg; struct sieve_ast_argument *kitem; - cmp_arg = sieve_command_find_argument(ctx->command_ctx, &comparator_tag); - if ( cmp_arg != NULL ) { - /* FIXME: new commands might use incompatible default comparator */ - - if ( sieve_comparator_tag_is(cmp_arg, &i_ascii_casemap_comparator) ) + if ( cmp != NULL ) { + if ( cmp == &i_ascii_casemap_comparator ) cflags = REG_EXTENDED | REG_NOSUB | REG_ICASE; - else if ( sieve_comparator_tag_is(cmp_arg, &i_octet_comparator) ) + else if ( cmp == &i_octet_comparator ) cflags = REG_EXTENDED | REG_NOSUB; else { sieve_command_validate_error(validator, ctx->command_ctx, @@ -150,14 +147,14 @@ bool mcht_regex_validate_context /* Validate regular expression keys */ - keyctx.valdtr = validator; + keyctx.valdtr = validator; keyctx.mctx = ctx; keyctx.cflags = cflags; kitem = key_arg; - if ( !sieve_ast_stringlist_map(&kitem, (void *) &keyctx, + if ( !sieve_ast_stringlist_map(&kitem, (void *) &keyctx, mcht_regex_validate_key_argument) ) - return FALSE; + return FALSE; return TRUE; } diff --git a/src/lib-sieve/plugins/variables/tst-string.c b/src/lib-sieve/plugins/variables/tst-string.c index a80eabd3c..04c05b73f 100644 --- a/src/lib-sieve/plugins/variables/tst-string.c +++ b/src/lib-sieve/plugins/variables/tst-string.c @@ -110,7 +110,8 @@ static bool tst_string_validate return FALSE; /* Validate the key argument to a specified match type */ - return sieve_match_type_validate(validator, tst, arg); + return sieve_match_type_validate + (validator, tst, arg, &is_match_type, &i_octet_comparator); } /* diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h index 76fa69beb..c3adb7199 100644 --- a/src/lib-sieve/sieve-comparators.h +++ b/src/lib-sieve/sieve-comparators.h @@ -5,8 +5,9 @@ #define __SIEVE_COMPARATORS_H #include "sieve-common.h" -#include "sieve-objects.h" #include "sieve-extensions.h" +#include "sieve-commands.h" +#include "sieve-objects.h" #include "sieve-code.h" /* @@ -63,6 +64,12 @@ struct sieve_comparator { extern const struct sieve_argument comparator_tag; +static inline bool sieve_argument_is_comparator + (struct sieve_ast_argument *arg) +{ + return arg->argument == &comparator_tag; +} + void sieve_comparators_link_tag (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, int id_code); diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c index 1153a4901..be1af4c64 100644 --- a/src/lib-sieve/sieve-match-types.c +++ b/src/lib-sieve/sieve-match-types.c @@ -1,3 +1,6 @@ +/* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file + */ + #include <stdio.h> #include "lib.h" @@ -362,6 +365,7 @@ static bool tag_match_type_is_instance_of mtctx = p_new(sieve_command_pool(cmd), struct sieve_match_type_context, 1); mtctx->match_type = mtch; mtctx->command_ctx = cmd; + mtctx->comparator = NULL; /* Can be filled in later */ arg->context = (void *) mtctx; @@ -406,52 +410,69 @@ static bool tag_match_type_generate return TRUE; } -bool sieve_match_type_validate_argument -(struct sieve_validator *validator, struct sieve_ast_argument *arg, - struct sieve_ast_argument *key_arg ) -{ - struct sieve_match_type_context *mtctx = - (struct sieve_match_type_context *) arg->context; - - i_assert(arg->argument == &match_type_tag); - - /* Check whether this match type requires additional validation. - * Additional validation can override the match type recorded in the context - * for later code generation. - */ - if ( mtctx != NULL && mtctx->match_type != NULL && - mtctx->match_type->validate_context != NULL ) { - return mtctx->match_type->validate_context(validator, arg, mtctx, key_arg); - } - - return TRUE; +void sieve_match_types_link_tags + (struct sieve_validator *validator, + struct sieve_command_registration *cmd_reg, int id_code) +{ + sieve_validator_register_tag + (validator, cmd_reg, &match_type_tag, id_code); } +/* + * Validation + */ + bool sieve_match_type_validate (struct sieve_validator *validator, struct sieve_command_context *cmd, - struct sieve_ast_argument *key_arg ) + struct sieve_ast_argument *key_arg, + const struct sieve_match_type *mcht_default, + const struct sieve_comparator *cmp_default) { struct sieve_ast_argument *arg = sieve_command_first_argument(cmd); + struct sieve_ast_argument *mt_arg = NULL; + struct sieve_match_type_context *mtctx; + const struct sieve_match_type *mcht = NULL; + const struct sieve_comparator *cmp = NULL; + /* Find match type and comparator among the arguments */ while ( arg != NULL && arg != cmd->first_positional ) { - if ( arg->argument == &match_type_tag ) { - if ( !sieve_match_type_validate_argument(validator, arg, key_arg) ) - return FALSE; + if ( sieve_argument_is_comparator(arg) ) { + cmp = sieve_comparator_tag_get(arg); + if ( mt_arg != NULL ) break; + } + + if ( sieve_argument_is_match_type(arg) ) { + mt_arg = arg; + if ( cmp != NULL ) break; } arg = sieve_ast_argument_next(arg); } + + /* Verify using the default comparator if none is specified explicitly */ + if ( cmp == NULL ) + cmp = cmp_default; + + /* Verify the default match type if none is specified explicitly */ + if ( mt_arg == NULL || mt_arg->context == NULL ) { + mtctx = NULL; + mcht = mcht_default; + } else { + mtctx = (struct sieve_match_type_context *) mt_arg->context; + mcht = mtctx->match_type; + mtctx->comparator = cmp; + } + /* Check whether this match type requires additional validation. + * Additional validation can override the match type recorded in the context + * for later code generation. + */ + if ( mcht != NULL && mcht->validate_context != NULL ) { + return mcht->validate_context(validator, mt_arg, mtctx, key_arg); + } + return TRUE; } -void sieve_match_types_link_tags - (struct sieve_validator *validator, - struct sieve_command_registration *cmd_reg, int id_code) -{ - sieve_validator_register_tag - (validator, cmd_reg, &match_type_tag, id_code); -} - /* * Match-type operand */ @@ -471,35 +492,27 @@ const struct sieve_operand match_type_operand = { }; /* - * Matching + * Common validation implementation */ bool sieve_match_substring_validate_context -(struct sieve_validator *validator, struct sieve_ast_argument *arg, - struct sieve_match_type_context *ctx, +(struct sieve_validator *validator, struct sieve_ast_argument *arg ATTR_UNUSED, + struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg ATTR_UNUSED) { - struct sieve_ast_argument *carg = - sieve_command_first_argument(ctx->command_ctx); - - while ( carg != NULL && carg != ctx->command_ctx->first_positional ) { - if ( carg != arg && carg->argument == &comparator_tag ) { - const struct sieve_comparator *cmp = - sieve_comparator_tag_get(carg); + const struct sieve_comparator *cmp = ctx->comparator; + + if ( cmp == NULL ) + return TRUE; - if ( (cmp->flags & SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH) == 0 ) { - sieve_command_validate_error(validator, ctx->command_ctx, - "the specified %s comparator does not support " - "sub-string matching as required by the :%s match type", - cmp->object.identifier, ctx->match_type->object.identifier ); - - return FALSE; - } - return TRUE; - } + if ( (cmp->flags & SIEVE_COMPARATOR_FLAG_SUBSTRING_MATCH) == 0 ) { + sieve_command_validate_error(validator, ctx->command_ctx, + "the specified %s comparator does not support " + "sub-string matching as required by the :%s match type", + cmp->object.identifier, ctx->match_type->object.identifier ); - carg = sieve_ast_argument_next(carg); + return FALSE; } - + return TRUE; } diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h index 87da2a3ed..775d67a6b 100644 --- a/src/lib-sieve/sieve-match-types.h +++ b/src/lib-sieve/sieve-match-types.h @@ -1,11 +1,21 @@ +/* Copyright (c) 2002-2008 Dovecot Sieve authors, see the included COPYING file + */ + #ifndef __SIEVE_MATCH_TYPES_H #define __SIEVE_MATCH_TYPES_H #include "sieve-common.h" #include "sieve-extensions.h" +#include "sieve-commands.h" #include "sieve-code.h" #include "sieve-objects.h" +/* + * Types + */ + +struct sieve_match_type_context; + /* * Core match types */ @@ -21,9 +31,10 @@ extern const struct sieve_match_type is_match_type; extern const struct sieve_match_type contains_match_type; extern const struct sieve_match_type matches_match_type; -struct sieve_match_type; -struct sieve_match_type_context; - +/* + * Match type object + */ + struct sieve_match_type { struct sieve_object object; @@ -50,11 +61,11 @@ struct sieve_match_type { void (*match_init)(struct sieve_match_context *mctx); - /* WARNING: some tests may pass a val == NULL parameter indicating that the passed - * value has no significance. For string-type matches this should map to the empty - * string "", but for match types that consider the passed values as objects rather - * than strings (e.g. :count) this means that the passed value should be skipped. - * This is currently only used by string test of the variables extension. + /* WARNING: some tests may pass a val == NULL parameter indicating that the + * passed value has no significance. For string-type matches this should map + * to the empty string "", but for match types that consider the passed values + * as objects rather than strings (e.g. :count) this means that the passed + * value should be skipped. */ int (*match) (struct sieve_match_context *mctx, const char *val, size_t val_size, @@ -66,6 +77,9 @@ struct sieve_match_type_context { struct sieve_command_context *command_ctx; const struct sieve_match_type *match_type; + /* Only filled in when match_type->validate_context() is called */ + const struct sieve_comparator *comparator; + /* Context data could be used in the future to pass data between validator and * generator in match types that use extra parameters. Currently not * necessary, not even for the relational extension. @@ -73,7 +87,18 @@ struct sieve_match_type_context { void *ctx_data; }; -/* Match values */ +/* + * Match type registration + */ + +void sieve_match_type_register + (struct sieve_validator *validator, const struct sieve_match_type *mcht); +const struct sieve_match_type *sieve_match_type_find + (struct sieve_validator *validator, const char *identifier); + +/* + * Match values + */ struct sieve_match_values; @@ -98,29 +123,34 @@ void sieve_match_values_commit void sieve_match_values_abort (struct sieve_match_values **mvalues); - void sieve_match_values_get (struct sieve_interpreter *interp, unsigned int index, string_t **value_r); -/* ... */ +/* + * Match type tagged argument + */ + +extern const struct sieve_argument match_type_tag; + +static inline bool sieve_argument_is_match_type + (struct sieve_ast_argument *arg) +{ + return ( arg->argument == &match_type_tag ); +} void sieve_match_types_link_tags (struct sieve_validator *validator, struct sieve_command_registration *cmd_reg, int id_code); -bool sieve_match_type_validate_argument -(struct sieve_validator *validator, struct sieve_ast_argument *arg, - struct sieve_ast_argument *key_arg); -bool sieve_match_type_validate -(struct sieve_validator *validator, struct sieve_command_context *cmd, - struct sieve_ast_argument *key_arg); - -void sieve_match_type_register - (struct sieve_validator *validator, - const struct sieve_match_type *addrp); -const struct sieve_match_type *sieve_match_type_find - (struct sieve_validator *validator, const char *identifier); -extern const struct sieve_argument match_type_tag; +/* + * Validation + */ + +bool sieve_match_type_validate + (struct sieve_validator *validator, struct sieve_command_context *cmd, + struct sieve_ast_argument *key_arg, + const struct sieve_match_type *mcht_default, + const struct sieve_comparator *cmp_default); /* * Match type operand @@ -159,11 +189,11 @@ static inline bool sieve_opr_match_type_dump (denv, &sieve_match_type_operand_class, address, NULL); } -/* Match Utility */ +/* Common validation implementation */ bool sieve_match_substring_validate_context -(struct sieve_validator *validator, struct sieve_ast_argument *arg, - struct sieve_match_type_context *ctx, - struct sieve_ast_argument *key_arg); + (struct sieve_validator *validator, struct sieve_ast_argument *arg, + struct sieve_match_type_context *ctx, + struct sieve_ast_argument *key_arg); #endif /* __SIEVE_MATCH_TYPES_H */ diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c index 2cf3685ef..afbe9ec75 100644 --- a/src/lib-sieve/tst-address.c +++ b/src/lib-sieve/tst-address.c @@ -168,7 +168,8 @@ static bool tst_address_validate return FALSE; /* Validate the key argument to a specified match type */ - return sieve_match_type_validate(validator, tst, arg); + return sieve_match_type_validate + (validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator); } /* diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c index 4335aab70..934d59964 100644 --- a/src/lib-sieve/tst-header.c +++ b/src/lib-sieve/tst-header.c @@ -99,7 +99,8 @@ static bool tst_header_validate return FALSE; /* Validate the key argument to a specified match type */ - return sieve_match_type_validate(validator, tst, arg); + return sieve_match_type_validate + (validator, tst, arg, &is_match_type, &i_ascii_casemap_comparator); } /* diff --git a/src/testsuite/tst-test-error.c b/src/testsuite/tst-test-error.c index 07a881180..772787f4b 100644 --- a/src/testsuite/tst-test-error.c +++ b/src/testsuite/tst-test-error.c @@ -143,7 +143,8 @@ static bool tst_test_error_validate return FALSE; /* Validate the key argument to a specified match type */ - return sieve_match_type_validate(valdtr, tst, arg); + return sieve_match_type_validate + (valdtr, tst, arg, &is_match_type, &i_octet_comparator); } /* diff --git a/tests/compile/errors.svtest b/tests/compile/errors.svtest index bcc5a44bf..af68e17e8 100644 --- a/tests/compile/errors.svtest +++ b/tests/compile/errors.svtest @@ -256,6 +256,20 @@ test "ADDRESS-PART errors (FIXME: count only)" { } } +/* + * MATCH-TYPE errors + */ + +test "MATCH-TYPE errors (FIXME: count only)" { + if test_compile "errors/match-type.sieve" { + test_fail "compile should have failed."; + } + + if not test_error :count "eq" :comparator "i;ascii-numeric" "2" { + test_fail "wrong number of errors reported"; + } +} + /* * Encoded-character errors */ diff --git a/tests/compile/errors/match-type.sieve b/tests/compile/errors/match-type.sieve new file mode 100644 index 000000000..4df456405 --- /dev/null +++ b/tests/compile/errors/match-type.sieve @@ -0,0 +1,7 @@ +require "comparator-i;ascii-numeric"; + +if header :contains :comparator "i;ascii-numeric" "from" "drunksnipers.com" { + keep; +} + +keep; -- GitLab