diff --git a/TODO b/TODO index 57d0d5a5d518153953b0300481b53ad3d5f159df..1305d77f21bffd58d948c61298099929fddce9ed 100644 --- a/TODO +++ b/TODO @@ -7,7 +7,6 @@ Next (in order of descending priority/precedence): * Add normalize() method to comparators to normalize the string before matching (for efficiency). * Further develop regex extension and update it to the latest draft: - - Allow for :regex matching with variable key - Implement the :quoteregex set modifier - Investigate the use of the TRE regexp library to gain UTF-8 capability * Finish body extension: diff --git a/src/lib-sieve/plugins/regex/mcht-regex.c b/src/lib-sieve/plugins/regex/mcht-regex.c index 9d1061564939c569d5e18da0bb59516216978fa7..ed06114deae7bccad0cef467687b5f7fe630d509 100644 --- a/src/lib-sieve/plugins/regex/mcht-regex.c +++ b/src/lib-sieve/plugins/regex/mcht-regex.c @@ -17,6 +17,7 @@ #include "sieve-stringlist.h" #include "sieve-commands.h" #include "sieve-validator.h" +#include "sieve-interpreter.h" #include "sieve-comparators.h" #include "sieve-match-types.h" #include "sieve-match.h" @@ -94,11 +95,12 @@ static int mcht_regex_validate_regexp { int ret; regex_t regexp; + const char *regex_str = sieve_ast_argument_strc(key); - if ( (ret=regcomp(®exp, sieve_ast_argument_strc(key), cflags)) != 0 ) { + if ( (ret=regcomp(®exp, regex_str, cflags)) != 0 ) { sieve_argument_validate_error(valdtr, key, - "invalid regular expression for regex match: %s", - _regexp_error(®exp, ret)); + "invalid regular expression '%s' for regex match: %s", + str_sanitize(regex_str, 128), _regexp_error(®exp, ret)); regfree(®exp); return FALSE; @@ -122,15 +124,12 @@ static int mcht_regex_validate_key_argument /* FIXME: We can currently only handle string literal argument, so * variables are not allowed. */ - if ( !sieve_argument_is_string_literal(key) ) { - sieve_argument_validate_error(keyctx->valdtr, key, - "this Sieve implementation currently only accepts a literal string " - "for a regular expression"); - return FALSE; + if ( sieve_argument_is_string_literal(key) ) { + return mcht_regex_validate_regexp + (keyctx->valdtr, keyctx->mtctx, key, keyctx->cflags); } - return mcht_regex_validate_regexp - (keyctx->valdtr, keyctx->mtctx, key, keyctx->cflags); + return TRUE; } static bool mcht_regex_validate_context @@ -301,12 +300,18 @@ static int mcht_regex_match_keys rkey->status = -1; /* Not supported */ if ( rkey->status >= 0 ) { + const char *regex_str = str_c(key_item); + int rxret; + /* Indicate whether match values need to be produced */ if ( ctx->nmatch == 0 ) cflags |= REG_NOSUB; /* Compile regular expression */ - if ( regcomp(&rkey->regexp, str_c(key_item), cflags) != 0 ) { - /* FIXME: Do something useful, i.e. report error somewhere */ + if ( (rxret=regcomp(&rkey->regexp, regex_str, cflags)) != 0 ) { + sieve_runtime_error(renv, NULL, + "invalid regular expression '%s' for regex match: %s", + str_sanitize(regex_str, 128), + _regexp_error(&rkey->regexp, rxret)); rkey->status = -1; } else { rkey->status = 1; diff --git a/tests/compile/errors.svtest b/tests/compile/errors.svtest index 8dc58aeeeb99409f710fe02200b1f2d4f953b138..a1d3673c5d19b28a568100a9462fd4d6223961ad 100644 --- a/tests/compile/errors.svtest +++ b/tests/compile/errors.svtest @@ -361,7 +361,7 @@ test "Unsupported language features (FIXME: count only)" { test_fail "compile should have failed."; } - if not test_error :count "eq" :comparator "i;ascii-numeric" "4" { + if not test_error :count "eq" :comparator "i;ascii-numeric" "3" { test_fail "wrong number of errors reported"; } } diff --git a/tests/compile/errors/unsupported.sieve b/tests/compile/errors/unsupported.sieve index a9481d256c6c52fd5ee54675468410dc4af1fe04..e367ad193d47f4272532b02c94fb2cd448d5a101 100644 --- a/tests/compile/errors/unsupported.sieve +++ b/tests/compile/errors/unsupported.sieve @@ -26,14 +26,5 @@ set "script" "blacklist"; include "${blacklist}"; -/* Variable regexp */ - -set "match" "(.*)rename-it(.*)"; - -if address :regex "from" "${match}" { - stop; -} - - diff --git a/tests/extensions/regex/basic.svtest b/tests/extensions/regex/basic.svtest index 940fec8ec4a63220a368055b4f98e7d774a39e33..a78abfac2cedb948d2f0a474c4a1bc5af96ab41a 100644 --- a/tests/extensions/regex/basic.svtest +++ b/tests/extensions/regex/basic.svtest @@ -1,6 +1,7 @@ require "vnd.dovecot.testsuite"; require "regex"; +require "variables"; test_set "message" text: From: stephan+sieve@friep.example.com @@ -35,4 +36,16 @@ test "More values" { if not address :regex "to" [".*\\.uk", ".*\\.nl", ".*\\.tk", ".*fi\\..*"] { test_fail "failed to match last"; } +} + +test "Variable regex" { + set "regex" "stephan[+](sieve)@friep.example.com"; + + if not header :regex "from" "${regex}" { + test_fail "failed to match variable regex"; + } + + if not string "${1}" "sieve" { + test_fail "failed to extract proper match value from variable regex"; + } } diff --git a/tests/extensions/regex/errors.svtest b/tests/extensions/regex/errors.svtest index 79c4115e3f544a9f2d81b297b643fef5b299ef41..2e0ebe0d6d340d7887c7d41af2fc2486eb607940 100644 --- a/tests/extensions/regex/errors.svtest +++ b/tests/extensions/regex/errors.svtest @@ -12,3 +12,18 @@ test "Compile errors" { test_fail "wrong number of errors reported"; } } + +test "Runtime errors" { + if not test_script_compile "errors/runtime.sieve" { + test_fail "failed to compile"; + } + + if not test_script_run { + test_fail "script should have run fine"; + } + + if not test_error :count "eq" :comparator "i;ascii-numeric" "1" { + test_fail "wrong number of errors reported"; + } +} + diff --git a/tests/extensions/regex/errors/runtime.sieve b/tests/extensions/regex/errors/runtime.sieve new file mode 100644 index 0000000000000000000000000000000000000000..2d0bf6628f0de4881ecabf96843bece24fb44c49 --- /dev/null +++ b/tests/extensions/regex/errors/runtime.sieve @@ -0,0 +1,9 @@ +require "regex"; +require "variables"; +require "fileinto"; + +set "regex" "["; + +if header :regex "to" "${regex}" { + fileinto "frop"; +}