From 59568b9dee7cef3afc47f42d6bc2a0164fc9359e Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 17 Sep 2010 22:05:33 +0200
Subject: [PATCH] Regex: added support for variable regex keys.

---
 TODO                                        |  1 -
 src/lib-sieve/plugins/regex/mcht-regex.c    | 29 ++++++++++++---------
 tests/compile/errors.svtest                 |  2 +-
 tests/compile/errors/unsupported.sieve      |  9 -------
 tests/extensions/regex/basic.svtest         | 13 +++++++++
 tests/extensions/regex/errors.svtest        | 15 +++++++++++
 tests/extensions/regex/errors/runtime.sieve |  9 +++++++
 7 files changed, 55 insertions(+), 23 deletions(-)
 create mode 100644 tests/extensions/regex/errors/runtime.sieve

diff --git a/TODO b/TODO
index 57d0d5a5d..1305d77f2 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 9d1061564..ed06114de 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(&regexp, sieve_ast_argument_strc(key), cflags)) != 0 ) {
+	if ( (ret=regcomp(&regexp, regex_str, cflags)) != 0 ) {
 		sieve_argument_validate_error(valdtr, key,
-			"invalid regular expression for regex match: %s", 
-			_regexp_error(&regexp, ret));
+			"invalid regular expression '%s' for regex match: %s", 
+			str_sanitize(regex_str, 128), _regexp_error(&regexp, ret));
 
 		regfree(&regexp);	
 		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 8dc58aeee..a1d3673c5 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 a9481d256..e367ad193 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 940fec8ec..a78abfac2 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 79c4115e3..2e0ebe0d6 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 000000000..2d0bf6628
--- /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";
+}
-- 
GitLab