From 6a6b34095e5f858b11030f59660476c312da9ddf Mon Sep 17 00:00:00 2001 From: Stephan Bosch <stephan@rename-it.nl> Date: Thu, 22 Nov 2007 00:41:00 +0100 Subject: [PATCH] Made first buggy implementation of :matches match type. --- sieve/tests/matches.sieve | 54 +++++++++ .../ext-cmp-i-ascii-numeric.c | 1 + src/lib-sieve/sieve-comparators.c | 68 ++++++++--- src/lib-sieve/sieve-comparators.h | 6 +- src/lib-sieve/sieve-match-types.c | 111 +++++++++++++++++- 5 files changed, 216 insertions(+), 24 deletions(-) create mode 100644 sieve/tests/matches.sieve diff --git a/sieve/tests/matches.sieve b/sieve/tests/matches.sieve new file mode 100644 index 000000000..913d33b34 --- /dev/null +++ b/sieve/tests/matches.sieve @@ -0,0 +1,54 @@ +require "fileinto"; + +fileinto "SHOULD MATCH"; +if address :matches "from" "*@d*ksn*ers.com" { + fileinto "A"; +} +if address :matches "from" "stephan+sieve@drunksnipers.*" { + fileinto "B"; +} +if address :matches "from" "*+sieve@drunksnipers.com" { + fileinto "C"; +} +if address :matches "from" "stephan+sieve?drunksnipers.com" { + fileinto "D"; +} +if address :matches "from" "?tephan+sieve@drunksnipers.com" { + fileinto "E"; +} +if address :matches "from" "stephan+sieve@drunksnipers.co?" { + fileinto "F"; +} +if address :matches "from" "?t?phan?sieve?drunksnip?rs.co?" { + fileinto "G"; +} +if address :matches "x-bullshit" "33333\\?\\?\\??" { + fileinto "H"; +} + +fileinto "SHOULD NOT MATCH"; +if address :matches "from" "*@d*kn*ers.com" { + fileinto "A"; +} +if address :matches "from" "stepan+sieve@drunksnipers.*" { + fileinto "B"; +} +if address :matches "from" "*+sieve@drunksnipers.om" { + fileinto "C"; +} +if address :matches "from" "stephan+sieve?drunksipers.com" { + fileinto "D"; +} +if address :matches "from" "?tephan+sievedrunksnipers.com" { + fileinto "E"; +} +if address :matches "from" "sephan+sieve@drunksnipers.co?" { + fileinto "F"; +} +if address :matches "from" "?t?phan?sieve?dunksnip?rs.co?" { + fileinto "G"; +} +if address :matches "x-bullshit" "33333\\?\\??" { + fileinto "H"; +} + diff --git a/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c b/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c index 229307ddd..f51dccbf7 100644 --- a/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c +++ b/src/lib-sieve/plugins/comparator-i-ascii-numeric/ext-cmp-i-ascii-numeric.c @@ -64,6 +64,7 @@ const struct sieve_comparator i_ascii_numeric_comparator = { &i_ascii_numeric_comparator_ext, 0, cmp_i_ascii_numeric_compare, + NULL, NULL }; diff --git a/src/lib-sieve/sieve-comparators.c b/src/lib-sieve/sieve-comparators.c index e9798840d..e861b1680 100644 --- a/src/lib-sieve/sieve-comparators.c +++ b/src/lib-sieve/sieve-comparators.c @@ -33,7 +33,10 @@ static int cmp_i_octet_compare const char *val1, size_t val1_size, const char *val2, size_t val2_size); static bool cmp_i_octet_char_match (const struct sieve_comparator *cmp, const char **val1, const char *val1_end, - const char **val2, const char *val2_end); + const char **val2, const char *val2_end); +static bool cmp_i_octet_char_skip + (const struct sieve_comparator *cmp, const char **val, const char *val_end); + static int cmp_i_ascii_casemap_compare (const struct sieve_comparator *cmp, const char *val1, size_t val1_size, const char *val2, size_t val2_size); @@ -412,7 +415,8 @@ const struct sieve_comparator i_octet_comparator = { NULL, 0, cmp_i_octet_compare, - cmp_i_octet_char_match + cmp_i_octet_char_match, + cmp_i_octet_char_skip }; const struct sieve_comparator i_ascii_casemap_comparator = { @@ -423,7 +427,8 @@ const struct sieve_comparator i_ascii_casemap_comparator = { NULL, 0, cmp_i_ascii_casemap_compare, - cmp_i_ascii_casemap_char_match + cmp_i_ascii_casemap_char_match, + cmp_i_octet_char_skip }; const struct sieve_comparator *sieve_core_comparators[] = { @@ -460,13 +465,34 @@ static int cmp_i_octet_compare( static bool cmp_i_octet_char_match (const struct sieve_comparator *cmp ATTR_UNUSED, - const char **val1, const char *val1_end ATTR_UNUSED, - const char **val2, const char *val2_end ATTR_UNUSED) + const char **val, const char *val_end, + const char **key, const char *key_end) { - if ( **val1 == **val2 ) { - (*val1)++; - (*val2)++; - + const char *val_begin = *val; + const char *key_begin = *key; + + while ( **val == **key && *val < val_end && *key < key_end ) { + (*val)++; + (*key)++; + } + + if ( *key < key_end ) { + /* Reset */ + *val = val_begin; + *key = key_begin; + + return FALSE; + } + + return TRUE; +} + +static bool cmp_i_octet_char_skip + (const struct sieve_comparator *cmp ATTR_UNUSED, + const char **val, const char *val_end) +{ + if ( *val < val_end ) { + (*val)++; return TRUE; } @@ -500,17 +526,27 @@ static int cmp_i_ascii_casemap_compare( static bool cmp_i_ascii_casemap_char_match (const struct sieve_comparator *cmp ATTR_UNUSED, - const char **val1, const char *val1_end ATTR_UNUSED, - const char **val2, const char *val2_end ATTR_UNUSED) + const char **val, const char *val_end, + const char **key, const char *key_end) { - if ( tolower(**val1) == tolower(**val2) ) { - (*val1)++; - (*val2)++; + const char *val_begin = *val; + const char *key_begin = *key; + + while ( tolower(**val) == tolower(**key) && + *val < val_end && *key < key_end ) { + (*val)++; + (*key)++; + } + + if ( *key < key_end ) { + /* Reset */ + *val = val_begin; + *key = key_begin; - return TRUE; + return FALSE; } - return FALSE; + return TRUE; } diff --git a/src/lib-sieve/sieve-comparators.h b/src/lib-sieve/sieve-comparators.h index 39207e2c0..10b7c8290 100644 --- a/src/lib-sieve/sieve-comparators.h +++ b/src/lib-sieve/sieve-comparators.h @@ -32,8 +32,10 @@ struct sieve_comparator { /* Prefix and substring match */ bool (*char_match)(const struct sieve_comparator *cmp, - const char **val1, const char *val1_end, - const char **val2, const char *val2_end); + const char **val, const char *val_end, + const char **key, const char *key_end); + bool (*char_skip)(const struct sieve_comparator *cmp, + const char **val, const char *val_end); }; struct sieve_comparator_extension { diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c index 1605ee226..fe586c4ba 100644 --- a/src/lib-sieve/sieve-match-types.c +++ b/src/lib-sieve/sieve-match-types.c @@ -536,6 +536,7 @@ static bool mtch_contains_match (struct sieve_match_context *mctx, const char *val, size_t val_size, const char *key, size_t key_size, int key_index ATTR_UNUSED) { + const struct sieve_comparator *cmp = mctx->comparator; const char *vend = (const char *) val + val_size; const char *kend = (const char *) key + key_size; const char *vp = val; @@ -545,20 +546,118 @@ static bool mtch_contains_match return FALSE; while ( (vp < vend) && (kp < kend) ) { - if ( !mctx->comparator->char_match(mctx->comparator, &vp, vend, &kp, kend) ) { - vp = vp - (kp - key) + 1; - kp = key; - } + if ( !cmp->char_match(cmp, &vp, vend, &kp, kend) ) + vp++; } - return (kp == kend); + return (kp == kend); +} + +static bool _matches_section + (const struct sieve_comparator *cmp, + const char **val, const char *vend, + const char **key, const char *kend) +{ + const char *val_begin = *val; + const char *key_begin = *key; + const char *wp = *key; + + while ( *key < kend ) { + char wildcard; + + /* Find next ? wildcard, \ escape or end of key pattern */ + while ( wp < kend && *wp != '?' && *wp != '\\' ) { + wp++; + } + + wildcard = *wp; + + /* Match text */ + if ( wp > *key && !cmp->char_match(cmp, val, vend, key, wp) ) + break; + + if ( *key == kend ) return TRUE; + + wp++; + *key = wp; + + if ( wildcard == '\\' ) + wp++; + else if ( !cmp->char_skip(cmp, val, vend) ) + break; + } + + if ( *key < kend ) { + /* Reset */ + *val = val_begin; + *key = key_begin; + return FALSE; + } + + return TRUE; } static bool mtch_matches_match (struct sieve_match_context *mctx, const char *val, size_t val_size, const char *key, size_t key_size, int key_index ATTR_UNUSED) { - return FALSE; + const struct sieve_comparator *cmp = mctx->comparator; + const char *vend = (const char *) val + val_size; + const char *kend = (const char *) key + key_size; + const char *vp = val; + const char *kp = key; + const char *wp = key; + + /* Match the pattern as a two-level structure: + * <pattern> = <section>*<section>*<section>.... + * <section> = [text]?[text]?[text].... + */ + + while (kp < kend) { + char wildcard; + + /* Find next * wildcard or end of key pattern */ + + while ( wp < kend && *wp != '*' ) { + if ( *wp == '\\' ) { + /* Defer handling of escaping for ? to the _matches_section function */ + if ( wp < kend - 1 && *(wp+1) == '?' ) + wp++; + else + break; + } + + wp++; + } + + wildcard = *wp; + + /* Find this section */ + if ( wp > kp ) { + while ( (vp < vend) && (kp < wp) ) { + + if ( !_matches_section(cmp, &vp, vend, &kp, wp) ) { + /* First section must match without offset */ + if ( kp == key ) return FALSE; + + vp++; + } + } + } + + /* Check whether we matched up to the * wildcard or the end */ + if ( wp > kp ) return FALSE; + + if ( kp == kend ) return TRUE; + + wp++; + kp = wp; + + if ( wildcard == '\\' ) + wp++; + } + + return (kp == kend); } /* -- GitLab