From 19f3572d81eda0fb52c081b91057fe2c61358d0e Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Tue, 20 Nov 2007 22:18:07 +0100 Subject: [PATCH] Implemented regex match execution. --- src/lib-sieve/plugins/regex/ext-regex.c | 53 ++++++++- src/lib-sieve/plugins/regex/regex.sieve | 2 +- .../plugins/relational/ext-relational.c | 8 +- src/lib-sieve/sieve-address-parts.c | 9 +- src/lib-sieve/sieve-address-parts.h | 7 +- src/lib-sieve/sieve-common.h | 1 + src/lib-sieve/sieve-match-types.c | 109 ++++++++++++++---- src/lib-sieve/sieve-match-types.h | 21 +++- src/lib-sieve/tst-address.c | 8 +- src/lib-sieve/tst-header.c | 10 +- 10 files changed, 183 insertions(+), 45 deletions(-) diff --git a/src/lib-sieve/plugins/regex/ext-regex.c b/src/lib-sieve/plugins/regex/ext-regex.c index ab50e599b..e92cbabe3 100644 --- a/src/lib-sieve/plugins/regex/ext-regex.c +++ b/src/lib-sieve/plugins/regex/ext-regex.c @@ -36,6 +36,16 @@ static bool ext_regex_validator_load(struct sieve_validator *validator); static bool ext_regex_interpreter_load (struct sieve_interpreter *interpreter); +void *mtch_regex_match_init + (const struct sieve_match_type *mtch, const struct sieve_comparator *cmp, + const char *key, size_t key_size); +static bool mtch_regex_match + (const struct sieve_match_type *mtch ATTR_UNUSED, + const struct sieve_comparator *cmp, const char *val, size_t val_size, + const char *key, size_t key_size, void *key_context); +void mtch_regex_match_deinit + (const struct sieve_match_type *mtch, void *key_context); + /* Extension definitions */ static int ext_my_id; @@ -75,7 +85,9 @@ const struct sieve_match_type regex_match_type = { 0, NULL, mtch_regex_validate_context, - NULL + mtch_regex_match_init, + mtch_regex_match, + mtch_regex_match_deinit, }; const struct sieve_match_type_extension regex_match_extension = { @@ -183,6 +195,45 @@ bool mtch_regex_validate_context return TRUE; } +void *mtch_regex_match_init +(const struct sieve_match_type *mtch ATTR_UNUSED, + const struct sieve_comparator *cmp, const char *key, + size_t key_size ATTR_UNUSED) +{ + int ret; + int cflags; + regex_t *regexp = p_new(pool_datastack_create(), regex_t, 1); + + if ( cmp == &i_octet_comparator ) + cflags = REG_EXTENDED | REG_NOSUB; + else if ( cmp == &i_ascii_casemap_comparator ) + cflags = REG_EXTENDED | REG_NOSUB | REG_ICASE; + else + return NULL; + + if ( (ret=regcomp(regexp, key, cflags)) != 0 ) { + /* FIXME: Do something useful, i.e. report error somewhere */ + return NULL; + } + + return regexp; +} + +static bool mtch_regex_match +(const struct sieve_match_type *mtch ATTR_UNUSED, + const struct sieve_comparator *cmp ATTR_UNUSED, const char *val, + size_t val_size ATTR_UNUSED, const char *key ATTR_UNUSED, + size_t key_size ATTR_UNUSED, void *key_context) +{ + return ( regexec((regex_t *) key_context, val, 0, NULL, 0) == 0 ); +} + +void mtch_regex_match_deinit + (const struct sieve_match_type *mtch ATTR_UNUSED, void *key_context) +{ + regfree((regex_t *) key_context); +} + /* Load extension into validator */ static bool ext_regex_validator_load(struct sieve_validator *validator) diff --git a/src/lib-sieve/plugins/regex/regex.sieve b/src/lib-sieve/plugins/regex/regex.sieve index 437a77b90..7531742f9 100644 --- a/src/lib-sieve/plugins/regex/regex.sieve +++ b/src/lib-sieve/plugins/regex/regex.sieve @@ -1,6 +1,6 @@ require "regex"; -if address :regex :comparator "i;ascii-casemap" "from" "sirius(\\+.*)?@drunksnipers\\.com" { +if address :regex :comparator "i;ascii-casemap" "from" "stephan(\\+.*)?@drunksnipers\\.com" { keep; stop; } diff --git a/src/lib-sieve/plugins/relational/ext-relational.c b/src/lib-sieve/plugins/relational/ext-relational.c index a116ce41e..d42e9332c 100644 --- a/src/lib-sieve/plugins/relational/ext-relational.c +++ b/src/lib-sieve/plugins/relational/ext-relational.c @@ -190,7 +190,7 @@ const struct sieve_match_type value_match_type = { &relational_match_extension, RELATIONAL_VALUE, ext_relational_parameter_validate, - NULL, NULL + NULL, NULL, NULL, NULL }; const struct sieve_match_type count_match_type = { @@ -199,7 +199,7 @@ const struct sieve_match_type count_match_type = { &relational_match_extension, RELATIONAL_COUNT, ext_relational_parameter_validate, - NULL, NULL + NULL, NULL, NULL, NULL }; /* Per-parameter match type objects, used for generation/interpretation @@ -213,7 +213,7 @@ const struct sieve_match_type count_match_type = { SIEVE_MATCH_TYPE_CUSTOM, \ &relational_match_extension, \ REL_MATCH_INDEX(RELATIONAL_VALUE, rel_match), \ - NULL, NULL, NULL \ + NULL, NULL, NULL, NULL, NULL \ } #define COUNT_MATCH_TYPE(name, rel_match, func) { \ @@ -221,7 +221,7 @@ const struct sieve_match_type count_match_type = { SIEVE_MATCH_TYPE_CUSTOM, \ &relational_match_extension, \ REL_MATCH_INDEX(RELATIONAL_COUNT, rel_match), \ - NULL, NULL, NULL \ + NULL, NULL, NULL, NULL, NULL \ } static const struct sieve_match_type rel_match_types[] = { diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c index 26d14a58e..7a5acd1e3 100644 --- a/src/lib-sieve/sieve-address-parts.c +++ b/src/lib-sieve/sieve-address-parts.c @@ -370,10 +370,9 @@ static bool tag_address_part_generate * Address Matching */ -bool sieve_address_match_stringlist - (const struct sieve_address_part *addrp, const struct sieve_match_type *mtch, - const struct sieve_comparator *cmp, struct sieve_coded_stringlist *key_list, - const char *data) +bool sieve_address_match +(const struct sieve_address_part *addrp, struct sieve_match_context *mctx, + const char *data) { bool matched = FALSE; const struct message_address *addr; @@ -393,7 +392,7 @@ bool sieve_address_match_stringlist part = addrp->extract_from(addr); - if ( part != NULL && sieve_match_stringlist(mtch, cmp, key_list, part) ) + if ( part != NULL && sieve_match_value(mctx, part) ) matched = TRUE; } diff --git a/src/lib-sieve/sieve-address-parts.h b/src/lib-sieve/sieve-address-parts.h index aaad6413f..5fe765bfd 100644 --- a/src/lib-sieve/sieve-address-parts.h +++ b/src/lib-sieve/sieve-address-parts.h @@ -67,9 +67,8 @@ bool sieve_opr_address_part_dump (struct sieve_interpreter *interpreter, struct sieve_binary *sbin, sieve_size_t *address); -bool sieve_address_match_stringlist - (const struct sieve_address_part *addrp, const struct sieve_match_type *mtch, - const struct sieve_comparator *cmp, struct sieve_coded_stringlist *key_list, - const char *data); +bool sieve_address_match +(const struct sieve_address_part *addrp, struct sieve_match_context *mctx, + const char *data); #endif /* __SIEVE_ADDRESS_PARTS_H */ diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index cb4994c62..eecbf3eec 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -63,6 +63,7 @@ struct sieve_comparator; /* sieve-match-types.h */ struct sieve_match_type; +struct sieve_match_context; /* sieve-address-parts.h */ struct sieve_address_part; diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c index e69aea0e9..af2739ebe 100644 --- a/src/lib-sieve/sieve-match-types.c +++ b/src/lib-sieve/sieve-match-types.c @@ -416,43 +416,107 @@ static bool tag_match_type_generate return TRUE; } -/* Stringlist Utility */ +/* Match Utility */ -bool sieve_match_stringlist - (const struct sieve_match_type *mtch, const struct sieve_comparator *cmp, - struct sieve_coded_stringlist *key_list, const char *value) +struct sieve_match_context { + const struct sieve_match_type *match_type; + const struct sieve_comparator *comparator; + struct sieve_coded_stringlist *key_list; + + ARRAY_DEFINE(key_contexts, void *); + + int value_index; +}; + +struct sieve_match_context *sieve_match_begin +(const struct sieve_match_type *mtch, const struct sieve_comparator *cmp, + struct sieve_coded_stringlist *key_list) { + struct sieve_match_context *mctx = + p_new(pool_datastack_create(), struct sieve_match_context, 1); + int listlen = sieve_coded_stringlist_get_length(key_list); + + mctx->match_type = mtch; + mctx->comparator = cmp; + mctx->key_list = key_list; + mctx->value_index = 0; + + p_array_init(&mctx->key_contexts, pool_datastack_create(), listlen); + array_idx_clear(&mctx->key_contexts, listlen-1); + + return mctx; +} + +bool sieve_match_value + (struct sieve_match_context *mctx, const char *value) +{ + const struct sieve_match_type *mtch = mctx->match_type; + unsigned int key_index; string_t *key_item; - sieve_coded_stringlist_reset(key_list); + sieve_coded_stringlist_reset(mctx->key_list); /* Reject unimplemented match-type */ if ( mtch->match == NULL ) return FALSE; /* Match to all key values */ + key_index = 0; key_item = NULL; - while ( sieve_coded_stringlist_next_item(key_list, &key_item) && + while ( sieve_coded_stringlist_next_item(mctx->key_list, &key_item) && key_item != NULL ) { - if ( mtch->match(mtch, cmp, value, strlen(value), - str_c(key_item), str_len(key_item)) ) + void * const *kctx; + + if ( mctx->value_index == 0 && mtch->match_init != NULL ) { + void *key_ctx = mtch->match_init( + mctx->match_type, mctx->comparator, + str_c(key_item), str_len(key_item)); + + kctx = &key_ctx; + array_idx_set(&mctx->key_contexts, key_index, kctx); + } else + kctx = array_idx(&mctx->key_contexts, key_index); + + if ( mtch->match + (mctx->match_type, mctx->comparator, value, strlen(value), + str_c(key_item), str_len(key_item), *kctx) ) return TRUE; + + key_index++; } - + + mctx->value_index++; + + return FALSE; +} + +bool sieve_match_end(struct sieve_match_context *mctx) +{ + unsigned int i; + const struct sieve_match_type *mtch = mctx->match_type; + + if ( mtch->match_deinit != NULL ) { + for ( i = 0; i < array_count(&mctx->key_contexts); i++ ) { + void * const *kctx = array_idx(&mctx->key_contexts, i); + + mtch->match_deinit(mtch, *kctx); + } + } + return FALSE; } /* * Matching */ - + static bool mtch_is_match (const struct sieve_match_type *mtch ATTR_UNUSED, - const struct sieve_comparator *cmp, - const char *val1, size_t val1_size, const char *val2, size_t val2_size) + const struct sieve_comparator *cmp, const char *val1, size_t val1_size, + const char *key, size_t key_size, void *key_context ATTR_UNUSED) { if ( cmp->compare != NULL ) - return (cmp->compare(cmp, val1, val1_size, val2, val2_size) == 0); + return (cmp->compare(cmp, val1, val1_size, key, key_size) == 0); return FALSE; } @@ -462,8 +526,8 @@ static bool mtch_is_match */ static bool mtch_contains_match (const struct sieve_match_type *mtch ATTR_UNUSED, - const struct sieve_comparator *cmp, - const char *val, size_t val_size, const char *key, size_t key_size) + const struct sieve_comparator *cmp, const char *val, size_t val_size, + const char *key, size_t key_size, void *key_context ATTR_UNUSED) { const char *vend = (const char *) val + val_size; const char *kend = (const char *) key + key_size; @@ -484,8 +548,8 @@ static bool mtch_contains_match static bool mtch_matches_match (const struct sieve_match_type *mtch ATTR_UNUSED, - const struct sieve_comparator *cmp ATTR_UNUSED, - const char *val, size_t val_size, const char *key, size_t key_size) + const struct sieve_comparator *cmp, const char *val, size_t val_size, + const char *key, size_t key_size, void *key_context ATTR_UNUSED) { return FALSE; } @@ -507,8 +571,9 @@ const struct sieve_match_type is_match_type = { SIEVE_MATCH_TYPE_IS, NULL, 0, - NULL, NULL, + NULL, NULL, NULL, mtch_is_match, + NULL }; const struct sieve_match_type contains_match_type = { @@ -516,8 +581,9 @@ const struct sieve_match_type contains_match_type = { SIEVE_MATCH_TYPE_CONTAINS, NULL, 0, - NULL, NULL, + NULL, NULL, NULL, mtch_contains_match, + NULL }; const struct sieve_match_type matches_match_type = { @@ -525,8 +591,9 @@ const struct sieve_match_type matches_match_type = { SIEVE_MATCH_TYPE_MATCHES, NULL, 0, - NULL, NULL, - mtch_matches_match + NULL, NULL, NULL, + mtch_matches_match, + 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 61716e071..63550d937 100644 --- a/src/lib-sieve/sieve-match-types.h +++ b/src/lib-sieve/sieve-match-types.h @@ -10,6 +10,7 @@ enum sieve_match_type_code { SIEVE_MATCH_TYPE_CUSTOM }; +struct sieve_match_type; struct sieve_match_type_extension; struct sieve_match_type_context; @@ -28,9 +29,14 @@ struct sieve_match_type { (struct sieve_validator *validator, struct sieve_ast_argument *arg, struct sieve_match_type_context *ctx, struct sieve_ast_argument *key_arg); + void *(*match_init) + (const struct sieve_match_type *mtch, const struct sieve_comparator *cmp, + const char *key, size_t key_size); bool (*match) (const struct sieve_match_type *mtch, const struct sieve_comparator *cmp, - const char *val1, size_t val1_size, const char *val2, size_t val2_size); + const char *val, size_t val_size, const char *key, size_t key_size, + void *key_context); + void (*match_deinit)(const struct sieve_match_type *mtch, void *key_context); }; struct sieve_match_type_extension { @@ -92,10 +98,15 @@ bool sieve_opr_match_type_dump (struct sieve_interpreter *interpreter, struct sieve_binary *sbin, sieve_size_t *address); -/* Stringlist Utility */ +/* Match Utility */ + +struct sieve_match_context; -bool sieve_match_stringlist - (const struct sieve_match_type *mtch, const struct sieve_comparator *cmp, - struct sieve_coded_stringlist *key_list, const char *value); +struct sieve_match_context *sieve_match_begin +(const struct sieve_match_type *mtch, const struct sieve_comparator *cmp, + struct sieve_coded_stringlist *key_list); +bool sieve_match_value + (struct sieve_match_context *mctx, const char *value); +bool sieve_match_end(struct sieve_match_context *mctx); #endif /* __SIEVE_MATCH_TYPES_H */ diff --git a/src/lib-sieve/tst-address.c b/src/lib-sieve/tst-address.c index 41b2947d0..409988015 100644 --- a/src/lib-sieve/tst-address.c +++ b/src/lib-sieve/tst-address.c @@ -157,6 +157,7 @@ static bool tst_address_opcode_execute const struct sieve_match_type *mtch = &is_match_type; const struct sieve_address_part *addrp = &all_address_part; unsigned int opt_code; + struct sieve_match_context *mctx; struct sieve_coded_stringlist *hdr_list; struct sieve_coded_stringlist *key_list; string_t *hdr_item; @@ -199,6 +200,9 @@ static bool tst_address_opcode_execute t_pop(); return FALSE; } + + /* Initialize match context */ + mctx = sieve_match_begin(mtch, cmp, key_list); /* Iterate through all requested headers to match */ hdr_item = NULL; @@ -210,12 +214,14 @@ static bool tst_address_opcode_execute int i; for ( i = 0; !matched && headers[i] != NULL; i++ ) { - if ( sieve_address_match_stringlist(addrp, mtch, cmp, key_list, headers[i]) ) + if ( sieve_address_match(addrp, mctx, headers[i]) ) matched = TRUE; } } } + sieve_match_end(mctx); + t_pop(); sieve_interpreter_set_test_result(interp, matched); diff --git a/src/lib-sieve/tst-header.c b/src/lib-sieve/tst-header.c index ec1ac4c17..43767a2a7 100644 --- a/src/lib-sieve/tst-header.c +++ b/src/lib-sieve/tst-header.c @@ -141,10 +141,10 @@ static bool tst_header_opcode_execute (struct sieve_interpreter *interp, struct sieve_binary *sbin, sieve_size_t *address) { struct mail *mail = sieve_interpreter_get_mail(interp); - unsigned int opt_code; const struct sieve_comparator *cmp = &i_octet_comparator; const struct sieve_match_type *mtch = &is_match_type; + struct sieve_match_context *mctx; struct sieve_coded_stringlist *hdr_list; struct sieve_coded_stringlist *key_list; string_t *hdr_item; @@ -181,7 +181,9 @@ static bool tst_header_opcode_execute t_pop(); return FALSE; } - + + mctx = sieve_match_begin(mtch, cmp, key_list); + /* Iterate through all requested headers to match */ hdr_item = NULL; matched = FALSE; @@ -192,11 +194,13 @@ static bool tst_header_opcode_execute int i; for ( i = 0; !matched && headers[i] != NULL; i++ ) { - if ( sieve_match_stringlist(mtch, cmp, key_list, headers[i]) ) + if ( sieve_match_value(mctx, headers[i]) ) matched = TRUE; } } } + + sieve_match_end(mctx); t_pop(); -- GitLab