diff --git a/Makefile.am b/Makefile.am index 3090495a4140644fb34560f211f603806e849faa..523036a24965b0b6857ece49eb7221ba0679585c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,6 +34,7 @@ test_cases = \ tests/extensions/variables/match.svtest \ tests/extensions/variables/modifiers.svtest \ tests/extensions/variables/quoting.svtest \ + tests/extensions/variables/string.svtest \ tests/extensions/include/variables.svtest \ tests/extensions/imapflags/basic.svtest \ tests/extensions/imapflags/rfc.svtest \ diff --git a/TODO b/TODO index 535bc73f0a5c5a224beef0c2a8fb887bb7b06347..20c6231d4426bc5ead0421d8ba64822b3ab307ca 100644 --- a/TODO +++ b/TODO @@ -2,7 +2,6 @@ Next (in order of descending priority/precedence): * Full standards compliance review for the engine and all fully implemented sieve extensions. Issues discovered so far: - :matches : match values must only be changed when the test matches. - - string test must not :count empty strings - If an address is not syntactically valid, then it will not be matched by tests specifying ":localpart" or ":domain". - Allow for the existance of dynamic comparators diff --git a/src/lib-sieve/mcht-contains.c b/src/lib-sieve/mcht-contains.c index e10b599670442f735a18ea565a2449866ef50dea..dc4174d0d8593eb3fb382c9bcb7d501d4f88d9d9 100644 --- a/src/lib-sieve/mcht-contains.c +++ b/src/lib-sieve/mcht-contains.c @@ -49,6 +49,9 @@ static int mcht_contains_match const char *vp = val; const char *kp = key; + if ( val == NULL || val_size == 0 ) + return ( key_size == 0 ); + if ( mctx->comparator->char_match == NULL ) return FALSE; diff --git a/src/lib-sieve/mcht-is.c b/src/lib-sieve/mcht-is.c index 0b131615bdfcf9293af1e7763800c5073223fe05..dd64df65998d766827b75c65c27a30b55d410c6d 100644 --- a/src/lib-sieve/mcht-is.c +++ b/src/lib-sieve/mcht-is.c @@ -16,7 +16,7 @@ */ static int mcht_is_match - (struct sieve_match_context *mctx, const char *val1, size_t val1_size, + (struct sieve_match_context *mctx, const char *val, size_t val_size, const char *key, size_t key_size, int key_index); /* @@ -37,12 +37,15 @@ const struct sieve_match_type is_match_type = { static int mcht_is_match (struct sieve_match_context *mctx ATTR_UNUSED, - const char *val1, size_t val1_size, + const char *val, size_t val_size, const char *key, size_t key_size, int key_index ATTR_UNUSED) { + if ( (val == NULL || val_size == 0) ) + return ( key_size == 0 ); + if ( mctx->comparator->compare != NULL ) return (mctx->comparator->compare(mctx->comparator, - val1, val1_size, key, key_size) == 0); + val, val_size, key, key_size) == 0); return FALSE; } diff --git a/src/lib-sieve/mcht-matches.c b/src/lib-sieve/mcht-matches.c index 4d6a441fba407684969e6cc2b53beb86effa4c55..00b57a2c5816315847597bc06d90eee748cb3bf0 100644 --- a/src/lib-sieve/mcht-matches.c +++ b/src/lib-sieve/mcht-matches.c @@ -86,24 +86,30 @@ static int mcht_matches_match { const struct sieve_comparator *cmp = mctx->comparator; struct sieve_match_values *mvalues; - - string_t *mvalue = t_str_new(32); /* Match value (*) */ - string_t *mchars = t_str_new(32); /* Match characters (.?..?.??) */ - string_t *section = t_str_new(32); /* Section (after beginning or *) */ - string_t *subsection = t_str_new(32); /* Sub-section (after ?) */ - - const char *vend = (const char *) val + val_size; - const char *kend = (const char *) key + key_size; - const char *vp = val; /* Value pointer */ - const char *kp = key; /* Key pointer */ - const char *wp = key; /* Wildcard (key) pointer */ - const char *pvp = val; /* Previous value Pointer */ - + string_t *mvalue, *mchars, *section, *subsection; + const char *vend, *kend, *vp, *kp, *wp, *pvp; bool backtrack = FALSE; /* TRUE: match of '?'-connected sections failed */ char wcard = '\0'; /* Current wildcard */ char next_wcard = '\0'; /* Next widlcard */ unsigned int key_offset = 0; unsigned int j = 0; + + if ( val == NULL ) { + val = ""; + val_size = 0; + } + + mvalue = t_str_new(32); /* Match value (*) */ + mchars = t_str_new(32); /* Match characters (.?..?.??) */ + section = t_str_new(32); /* Section (after beginning or *) */ + subsection = t_str_new(32); /* Sub-section (after ?) */ + + vend = (const char *) val + val_size; + kend = (const char *) key + key_size; + vp = val; /* Value pointer */ + kp = key; /* Key pointer */ + wp = key; /* Wildcard (key) pointer */ + pvp = val; /* Previous value Pointer */ /* Reset match values list */ mvalues = sieve_match_values_start(mctx->interp); diff --git a/src/lib-sieve/plugins/regex/mcht-regex.c b/src/lib-sieve/plugins/regex/mcht-regex.c index 439637b328309366831d7fa861c4e14266ccb0f9..dc4c3ec118823d14c50a3cc7f88595f1d9946a83 100644 --- a/src/lib-sieve/plugins/regex/mcht-regex.c +++ b/src/lib-sieve/plugins/regex/mcht-regex.c @@ -231,6 +231,11 @@ static int mcht_regex_match struct mcht_regex_context *ctx = (struct mcht_regex_context *) mctx->data; regex_t *regexp; + if ( val == NULL ) { + val = ""; + val_size = 0; + } + if ( key_index < 0 ) return FALSE; if ( key_index == 0 ) ctx->value_index++; diff --git a/src/lib-sieve/plugins/relational/mcht-count.c b/src/lib-sieve/plugins/relational/mcht-count.c index 874f22b011295f64d48d8f45195f14d2cf34a494..fe7bcc7753ee048817493fc945f5ccee385edd72 100644 --- a/src/lib-sieve/plugins/relational/mcht-count.c +++ b/src/lib-sieve/plugins/relational/mcht-count.c @@ -74,6 +74,9 @@ static int mcht_count_match const char *key ATTR_UNUSED, size_t key_size ATTR_UNUSED, int key_index) { + if ( val == NULL ) + return FALSE; + /* Count values */ if ( key_index == -1 ) { mctx->data = (void *) (((int) mctx->data) + 1); diff --git a/src/lib-sieve/plugins/relational/mcht-value.c b/src/lib-sieve/plugins/relational/mcht-value.c index 0ccc268644188d71e1f3d75c65af0c39a5978b9c..d9c12123369b005febbe21b4dc1c098a529c7292 100644 --- a/src/lib-sieve/plugins/relational/mcht-value.c +++ b/src/lib-sieve/plugins/relational/mcht-value.c @@ -55,7 +55,14 @@ int mcht_value_match { const struct sieve_match_type *mtch = mctx->match_type; unsigned int rel_match = REL_MATCH(mtch->object.code); - int cmp_result = mctx->comparator-> + int cmp_result; + + if ( val == NULL ) { + val = ""; + val_size = 0; + } + + cmp_result = mctx->comparator-> compare(mctx->comparator, val, val_size, key, key_size); switch ( rel_match ) { diff --git a/src/lib-sieve/plugins/variables/tst-string.c b/src/lib-sieve/plugins/variables/tst-string.c index add6d94038df4519fd1547f4d60d4c3ad8e21597..a80eabd3c7d3f070cc9096ff8ea8cceb9bb39b0e 100644 --- a/src/lib-sieve/plugins/variables/tst-string.c +++ b/src/lib-sieve/plugins/variables/tst-string.c @@ -214,9 +214,10 @@ static int tst_string_operation_execute while ( result && !matched && (result=sieve_coded_stringlist_next_item(source, &src_item)) && src_item != NULL ) { + const char *src = str_len(src_item) > 0 ? str_c(src_item) : NULL; if ( (mret=sieve_match_value - (mctx, str_c(src_item), str_len(src_item))) < 0 ) { + (mctx, src, str_len(src_item))) < 0 ) { result = FALSE; break; } diff --git a/src/lib-sieve/sieve-match-types.h b/src/lib-sieve/sieve-match-types.h index 293b6eec75cecebeeb33d256d7aaae8513008562..309d8bd25e60361a38f070d4655daec69a739905 100644 --- a/src/lib-sieve/sieve-match-types.h +++ b/src/lib-sieve/sieve-match-types.h @@ -44,7 +44,18 @@ 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); + /* + * Matching + */ + 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. + */ int (*match) (struct sieve_match_context *mctx, const char *val, size_t val_size, const char *key, size_t key_size, int key_index); diff --git a/src/lib-sieve/sieve-match.c b/src/lib-sieve/sieve-match.c index 816da07d5aeab7790207e819babb127ef0f051df..37615566e075a2a9cdffcdb34d2b2082e88fe3d3 100644 --- a/src/lib-sieve/sieve-match.c +++ b/src/lib-sieve/sieve-match.c @@ -97,7 +97,7 @@ int sieve_match_value return -1; } else { - return mtch->match(mctx, value, strlen(value), NULL, 0, -1); + return mtch->match(mctx, value, val_size, NULL, 0, -1); } return FALSE; diff --git a/tests/extensions/variables/string.svtest b/tests/extensions/variables/string.svtest index 0763aae28a1149e6a9a6fd116b4ab140c9cf24d1..a2d4aa6ec12bce52ab835f7241f1c77faa364ee9 100644 --- a/tests/extensions/variables/string.svtest +++ b/tests/extensions/variables/string.svtest @@ -16,3 +16,13 @@ test "String - :count \"\"" { test_fail "string test failed :count match"; } } + +test "RFC example" { + set "state" "${state} pending"; + + if not string :matches " ${state} " "* pending *" { + # the above test always succeeds + + test_fail "test should have matched: \" ${state} \""; + } +}