From f153305df6cd239702aa3a5e1cc255f62ce9eff7 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Mon, 28 Jul 2008 00:22:23 +0200
Subject: [PATCH] Encoded-character: fixed a few bugs to properly match the
 examples provided in the RFC.

---
 src/lib-sieve/ext-encoded-character.c         |  21 ++-
 src/testsuite/Makefile.am                     |   1 +
 .../tests/extensions/encoded-character.svtest | 138 ++++++++++++++++++
 3 files changed, 153 insertions(+), 7 deletions(-)
 create mode 100644 src/testsuite/tests/extensions/encoded-character.svtest

diff --git a/src/lib-sieve/ext-encoded-character.c b/src/lib-sieve/ext-encoded-character.c
index c58c189a2..334640611 100644
--- a/src/lib-sieve/ext-encoded-character.c
+++ b/src/lib-sieve/ext-encoded-character.c
@@ -25,7 +25,8 @@
  */
 
 static bool ext_encoded_character_load(int ext_id);
-static bool ext_encoded_character_validator_load(struct sieve_validator *validator);
+static bool ext_encoded_character_validator_load
+	(struct sieve_validator *validator);
 
 static int ext_my_id;
 	
@@ -60,6 +61,8 @@ const struct sieve_argument encoded_string_argument = {
 	NULL, NULL 
 };
 
+/* Parsing */
+
 static bool _skip_whitespace
 	(const char **in, const char *inend)
 {
@@ -87,11 +90,11 @@ static bool _parse_hexint
 	int digit = 0;
 	*result = 0;
 		
-	while ( *in < inend && digit < max_digits ) {
+	while ( *in < inend && (max_digits == 0 || digit < max_digits) ) {
 	
 		if ( (**in) >= '0' && (**in) <= '9' ) 
 			*result = ((*result) << 4) + (**in) - ((unsigned int) '0');
-		/* Lower-case version is not allowed by RFC 
+		/* REPORTME: Lower-case version is not allowed by RFC 
 		else if ( (**in) >= 'a' && (**in) <= 'f' )
 			*result = ((*result) << 4) + (**in) - ((unsigned int) 'a') + 0x0a;*/
 		else if ( (**in) >= 'A' && (**in) <= 'F' )
@@ -143,9 +146,9 @@ static int _decode_unicode
 	for (;;) {
 		unsigned int unicode_hex;
 		
-		if ( !_skip_whitespace(in, inend) ) return FALSE;
+		if ( !_skip_whitespace(in, inend) ) return 0;
 		
-		if ( !_parse_hexint(in, inend, 6, &unicode_hex) ) break;
+		if ( !_parse_hexint(in, inend, 0, &unicode_hex) ) break;
 
 		if ( (unicode_hex <= 0xD7FF) || 
 			(unicode_hex >= 0xE000 && unicode_hex <= 0x10FFFF)	) 
@@ -248,9 +251,10 @@ bool arg_encoded_string_validate
 					
 					strstart = p + 1;
 					substart = strstart;
-				}
+					
+					p++;	
+				} 
 				state = ST_NONE;
-				p++;	
 			}
 		}
 	} T_END;
@@ -262,6 +266,7 @@ bool arg_encoded_string_validate
 		sieve_ast_argument_string_set(*arg, newstr);
 	}
 	
+	/* Pass the processed string to a (possible) next layer of processing */
 	return sieve_validator_argument_activate_super
 		(validator, cmd, *arg, TRUE);
 }
@@ -273,7 +278,9 @@ bool arg_encoded_string_validate
 static bool ext_encoded_character_validator_load
 (struct sieve_validator *validator ATTR_UNUSED)
 {
+	/* Override the constant string argument with our own */
 	sieve_validator_argument_override(validator, SAT_CONST_STRING, 
 		&encoded_string_argument); 
+	
 	return TRUE;
 }
diff --git a/src/testsuite/Makefile.am b/src/testsuite/Makefile.am
index 7aeb84955..d814713a7 100644
--- a/src/testsuite/Makefile.am
+++ b/src/testsuite/Makefile.am
@@ -75,6 +75,7 @@ test_cases = \
 	tests/match-types/matches.svtest \
 	tests/match-types/relational.svtest \
 	tests/address-parts/subaddress.svtest \
+	tests/extensions/encoded-character.svtest \
 	tests/extensions/envelope.svtest \
 	tests/extensions/variables/basic.svtest \
 	tests/extensions/include/variables.svtest \
diff --git a/src/testsuite/tests/extensions/encoded-character.svtest b/src/testsuite/tests/extensions/encoded-character.svtest
new file mode 100644
index 000000000..e241495ba
--- /dev/null
+++ b/src/testsuite/tests/extensions/encoded-character.svtest
@@ -0,0 +1,138 @@
+require "vnd.dovecot.testsuite";
+
+require "encoded-character";
+require "variables";
+
+test "HEX equality one" {
+	if not string "${hex:42}" "B" {
+		test_fail "failed to match the string 'B'";
+	}
+
+	if string "${hex:42}" "b" {
+		test_fail "matched nonsense";
+	}
+
+	if string "${hex:42}" "" {
+		test_fail "substitution failed";
+	}
+}
+
+test "HEX equality one middle" {
+	if not string " ${hex:42} " " B " {
+		test_fail "failed to match the string ' B '";
+	}
+
+	if string " ${hex:42} " " b " {
+		test_fail "matched nonsense";
+	}
+
+	if string " ${hex:42} " "  " {
+		test_fail "substitution failed";
+	}
+}
+
+test "HEX equality one begin" {
+	if not string "${hex:42} " "B " {
+		test_fail "failed to match the string 'B '";
+	}
+
+	if string "${hex:42} " " b" {
+		test_fail "matched nonsense";
+	}
+
+	if string "${hex:42} " " " {
+		test_fail "substitution failed";
+	}
+}
+
+test "HEX equality one end" {
+	if not string " ${hex:42}" " B" {
+		test_fail "failed to match the string ' B'";
+	}
+
+	if string " ${hex:42}" " b " {
+		test_fail "matched nonsense";
+	}
+
+	if string " ${hex:42}" " " {
+		test_fail "substitution failed";
+	}
+}
+
+test "HEX equality two triple" {
+	if not string "${hex:42 61 64}${hex: 61 73 73}" "Badass" {
+		test_fail "failed to match the string 'Badass'";
+	}
+
+	if string "${hex:42 61 64}${hex: 61 73 73}" "Sadass" {
+		test_fail "matched nonsense";
+	}
+
+	if string "${hex:42 61 64}${hex: 61 73 73}" "" {
+		test_fail "substitution failed";
+	}
+}
+
+test "HEX equality braindead" {
+	if not string "${hex:42 72 61 69 6E 64 65 61 64}" "Braindead" {
+		test_fail "failed to match the string 'Braindead'";
+	}
+
+	if string "${hex:42 72 61 69 6E 64 65 61 64}" "Brian Nut" {
+		test_fail "matched nonsense";
+	}
+}
+
+/*
+ * RFC Examples
+ */
+
+test "RFC Examples" {
+	if not string "$${hex:40}" "$@" {
+		test_fail "failed RFC example 1";
+	}
+
+	if not string "${hex: 40 }" "@" {
+		test_fail "failed RFC example 2";
+	}
+
+	if not string "${HEX: 40}" "@" {
+		test_fail "failed RFC example 3";
+	}
+	
+	if not string "${hex:40" "${hex:40" {
+		test_fail "failed RFC example 4";
+	}
+
+	if not string "${hex:400}" "${hex:400}" {
+		test_fail "failed RFC example 5";
+	}
+
+	if not string "${hex:4${hex:30}}" "${hex: 24}{hex:40}" {
+		test_fail "failed RFC example 6";
+	}
+
+	if not string "${unicode:40}" "@" {
+		test_fail "failed RFC example 7";
+	}
+     
+	if not string "${ unicode:40}" "${ unicode:40}" {
+		test_fail "failed RFC example 8";
+	}
+
+	if not string "${UNICODE:40}" "@" {
+		test_fail "failed RFC example 9";
+	}
+
+	if not string "${UnICoDE:0000040}" "@" {
+		test_fail "failed RFC example 10";
+	}
+
+	if not string "${Unicode:40}" "@" {
+		test_fail "failed RFC example 11";
+	}
+
+	if not string "${Unicode:Cool}" "${Unicode:Cool}" {
+		test_fail "failed RFC example 12";
+	}
+}
-- 
GitLab