From 353c11c7ad621c051007b9173092deb9e5eba5fe Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 1 Aug 2008 17:54:40 +0200
Subject: [PATCH] Fixed bug in the order of default argument processing.
 Variable strings were evaluated befor constant strings, which is wrong.

---
 src/lib-sieve/ext-encoded-character.c         |  3 +-
 .../variables/ext-variables-arguments.c       |  2 +-
 src/lib-sieve/sieve-validator.c               | 46 +++++++++++--------
 tests/extensions/variables/quoting.svtest     | 36 +++++++++++++++
 4 files changed, 64 insertions(+), 23 deletions(-)
 create mode 100644 tests/extensions/variables/quoting.svtest

diff --git a/src/lib-sieve/ext-encoded-character.c b/src/lib-sieve/ext-encoded-character.c
index 1097b3eee..85532885e 100644
--- a/src/lib-sieve/ext-encoded-character.c
+++ b/src/lib-sieve/ext-encoded-character.c
@@ -94,9 +94,8 @@ static bool _parse_hexint
 	
 		if ( (**in) >= '0' && (**in) <= '9' ) 
 			*result = ((*result) << 4) + (**in) - ((unsigned int) '0');
-		/* REPORTME: Lower-case version is not allowed by RFC 
 		else if ( (**in) >= 'a' && (**in) <= 'f' )
-			*result = ((*result) << 4) + (**in) - ((unsigned int) 'a') + 0x0a;*/
+			*result = ((*result) << 4) + (**in) - ((unsigned int) 'a') + 0x0a;
 		else if ( (**in) >= 'A' && (**in) <= 'F' )
 			*result = ((*result) << 4) + (**in) - ((unsigned int) 'A') + 0x0a;
 		else
diff --git a/src/lib-sieve/plugins/variables/ext-variables-arguments.c b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
index 07788ac0d..146fd8f2d 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-arguments.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
@@ -210,7 +210,7 @@ static bool arg_variable_string_validate
 	const char *strend = strval + str_len(str);
 	struct _variable_string_data *strdata;
 	bool result = TRUE;
-	
+
 	ARRAY_TYPE(ext_variable_name) substitution;	
 	int nelements = 0;
 	
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index f6f38ff8a..c91d6113e 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -39,8 +39,11 @@ struct sieve_validator {
 	
 	/* This is currently a wee bit ugly and needs more thought */
 	struct sieve_default_argument default_arguments[SAT_COUNT];
+
+	/* Default argument processing state (FIXME: ugly) */
 	struct sieve_default_argument *current_defarg;
 	enum sieve_argument_type current_defarg_type;
+	bool current_defarg_constant;
 };
 
 /* Predeclared statics */
@@ -106,6 +109,8 @@ struct sieve_validator *sieve_validator_create
 	/* Setup default arguments */
 	validator->default_arguments[SAT_NUMBER].
 		argument = &number_argument;
+	validator->default_arguments[SAT_VAR_STRING].
+		argument = &string_argument;
 	validator->default_arguments[SAT_CONST_STRING].
 		argument = &string_argument;
 	validator->default_arguments[SAT_STRING_LIST].
@@ -497,27 +502,26 @@ bool sieve_validator_argument_activate_super
 	struct sieve_ast_argument *arg, bool constant ATTR_UNUSED)
 {
 	struct sieve_default_argument *defarg;
-	
-	if ( validator->current_defarg == NULL )
+
+	if ( validator->current_defarg == NULL ||	
+		validator->current_defarg->overrides == NULL )
 		return FALSE;
 	
-	if ( validator->current_defarg->overrides == NULL ) {
-		enum sieve_argument_type prev_type = validator->current_defarg_type;
-		
-		switch ( validator->current_defarg_type ) {
-		case SAT_NUMBER:
+	if ( validator->current_defarg->overrides->argument == &string_argument ) {
+		switch ( validator->current_defarg_type) {
 		case SAT_CONST_STRING:
-		case SAT_STRING_LIST:
-			return FALSE;
+			if ( !validator->current_defarg_constant ) {
+				validator->current_defarg_type = SAT_VAR_STRING;
+				defarg = &validator->default_arguments[SAT_VAR_STRING];
+			} else
+				defarg = validator->current_defarg->overrides;
+			break;
 		case SAT_VAR_STRING:
-			validator->current_defarg_type = SAT_CONST_STRING;
-			defarg = &validator->default_arguments[validator->current_defarg_type];
+			defarg = validator->current_defarg->overrides;
 			break;
-		default: 
+		default:
 			return FALSE;
 		}
-		
-		validator->current_defarg_type = prev_type;
 	} else
 		defarg = validator->current_defarg->overrides;
 	
@@ -536,11 +540,7 @@ bool sieve_validator_argument_activate
 		validator->current_defarg_type = SAT_NUMBER;
 		break;
 	case SAAT_STRING:
-		if ( constant || 
-			validator->default_arguments[SAT_VAR_STRING].argument == NULL )
-			validator->current_defarg_type = SAT_CONST_STRING;
-		else
-			validator->current_defarg_type = SAT_VAR_STRING;
+		validator->current_defarg_type = SAT_CONST_STRING;
 		break;
 	case SAAT_STRING_LIST:
 		validator->current_defarg_type = SAT_STRING_LIST;
@@ -548,8 +548,14 @@ bool sieve_validator_argument_activate
 	default:
 		return FALSE;
 	}
-	
+
+	validator->current_defarg_constant = constant;
 	defarg = &validator->default_arguments[validator->current_defarg_type];
+
+	if ( !constant && defarg->argument == &string_argument ) {
+		validator->current_defarg_type = SAT_VAR_STRING;
+		defarg = &validator->default_arguments[SAT_VAR_STRING];
+	}
 	
 	return sieve_validator_argument_default_activate(validator, cmd, defarg, arg);
 }
diff --git a/tests/extensions/variables/quoting.svtest b/tests/extensions/variables/quoting.svtest
new file mode 100644
index 000000000..e9a23b0a0
--- /dev/null
+++ b/tests/extensions/variables/quoting.svtest
@@ -0,0 +1,36 @@
+require "vnd.dovecot.testsuite";
+
+require "variables";
+require "encoded-character";
+
+test "Encodings - RFC examples" {
+	set "s" "$";
+	set "foo" "bar";
+
+	# "${fo\o}"  => ${foo}  => the expansion of variable foo.
+	if not string :is "${fo\o}" "bar" {
+		test_fail "failed 'the expansion of variable foo (${s}{fo\\o})'";
+	}
+
+	# "${fo\\o}" => ${fo\o} => illegal identifier => left verbatim.      
+	if not string :is "${fo\\o}" "${s}{fo\\o}" {
+		test_fail "failed 'illegal identifier => left verbatim'";
+	}
+
+	# "\${foo}"  => ${foo}  => the expansion of variable foo.
+	if not string "\${foo}" "bar" {
+		test_fail "failed 'the expansion of variable foo (\\${s}{foo})'";
+	}
+
+	# "\\${foo}" => \${foo} => a backslash character followed by the
+	#                          expansion of variable foo.
+	if not string "\\${foo}" "\\bar" {
+		test_fail "failed 'a backslash character followed by expansion of variable foo";
+	}
+
+	set "name" "Ethelbert";
+	if not string "dear${hex:20 24 7b 4e}ame}" "dear Ethelbert" {
+		test_fail "failed 'dear Ethelbert' example";
+    }
+}
+
-- 
GitLab