From 05545fa1445b855bdd5a5017765330fb85b39504 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Tue, 20 Nov 2007 14:26:33 +0100
Subject: [PATCH] Implemented detection of duplicate optional arguments.

---
 sieve/errors/address-part-errors.sieve | 10 +++++++
 sieve/errors/interesting.sieve         |  8 ++++--
 sieve/errors/match-type-errors.sieve   | 10 +++++++
 src/lib-sieve/sieve-address-parts.c    |  2 +-
 src/lib-sieve/sieve-ast.h              |  1 +
 src/lib-sieve/sieve-match-types.c      |  2 +-
 src/lib-sieve/sieve-validator.c        | 37 +++++++++++++++++++++++---
 7 files changed, 62 insertions(+), 8 deletions(-)
 create mode 100644 sieve/errors/address-part-errors.sieve
 create mode 100644 sieve/errors/match-type-errors.sieve

diff --git a/sieve/errors/address-part-errors.sieve b/sieve/errors/address-part-errors.sieve
new file mode 100644
index 000000000..9a49af08a
--- /dev/null
+++ b/sieve/errors/address-part-errors.sieve
@@ -0,0 +1,10 @@
+if address :all :comparator "i;octet" :domain "from" "STEPHAN" {
+	discard;
+
+	if address :localpart :domain :comparator "i;octet" "from" "drunksnipers.com" {
+		keep;
+	}
+	stop;
+}
+
+keep;
diff --git a/sieve/errors/interesting.sieve b/sieve/errors/interesting.sieve
index 6db130c8f..84ee424bf 100644
--- a/sieve/errors/interesting.sieve
+++ b/sieve/errors/interesting.sieve
@@ -3,9 +3,9 @@ require ["copy", "relational"];
 require "envelope";
 require "regex";
 
-if header :is "To" "Stephan \"Nico\" Bosch <nico@vestingbar>" {
+if header :is "To" "Stephan \"Nico\" Bosch <nico@voorbeeld.nl>" {
 	fileinto "INBOX.stephan";	
-} elsif header :matches "To" "*@vestingbar.nl" {
+} elsif header :matches "To" "*@voorbeeld.nl" {
 	fileinto "INBOX.vestingbar";
 }
 
@@ -16,3 +16,7 @@ if envelope :isnot :comperator "i;ascii-casemap" :localpart "From" "nico" {
 if :disabled true {
 	break;
 }
+
+if header :comparator "i;octet" :is :comparator "i;ascii-casemap" {
+	frop;
+}
diff --git a/sieve/errors/match-type-errors.sieve b/sieve/errors/match-type-errors.sieve
new file mode 100644
index 000000000..05723d71f
--- /dev/null
+++ b/sieve/errors/match-type-errors.sieve
@@ -0,0 +1,10 @@
+if address :contains :is :comparator "i;ascii-casemap" :localpart "from" "STEPHAN" {
+	discard;
+
+	if address :contains :domain :comparator "i;octet" :matches "from" "drunksnipers.com" {
+		keep;
+	}
+	stop;
+}
+
+keep;
diff --git a/src/lib-sieve/sieve-address-parts.c b/src/lib-sieve/sieve-address-parts.c
index 77e5e39da..26d14a58e 100644
--- a/src/lib-sieve/sieve-address-parts.c
+++ b/src/lib-sieve/sieve-address-parts.c
@@ -410,7 +410,7 @@ bool sieve_address_match_stringlist
  */
 
 const struct sieve_argument address_part_tag = { 
-	NULL,
+	"ADDRESS-PART",
 	tag_address_part_is_instance_of, 
 	tag_address_part_validate,
 	NULL, 
diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h
index 5b196c541..ecaa436af 100644
--- a/src/lib-sieve/sieve-ast.h
+++ b/src/lib-sieve/sieve-ast.h
@@ -232,6 +232,7 @@ void sieve_ast_unparse(struct sieve_ast *ast);
 
 /* AST argument macros */
 #define sieve_ast_argument_first(node) __LIST_FIRST(node, arguments)
+#define sieve_ast_argument_prev(argument) __LIST_PREV(argument)
 #define sieve_ast_argument_next(argument) __LIST_NEXT(argument)
 #define sieve_ast_argument_count(node) __LIST_COUNT(node, arguments)
 #define sieve_ast_argument_type(argument) ((argument) == NULL ? SAAT_NONE : (argument)->type)
diff --git a/src/lib-sieve/sieve-match-types.c b/src/lib-sieve/sieve-match-types.c
index bb3ec242d..5ac03d8cd 100644
--- a/src/lib-sieve/sieve-match-types.c
+++ b/src/lib-sieve/sieve-match-types.c
@@ -475,7 +475,7 @@ static bool mtch_matches_match
  */
 
 const struct sieve_argument match_type_tag = { 
-	NULL,
+	"MATCH-TYPE",
 	tag_match_type_is_instance_of, 
 	tag_match_type_validate, 
 	tag_match_type_validate_context,
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index 715903ff4..d3aac8522 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -402,6 +402,8 @@ static bool sieve_validate_command_arguments
 	/* Parse tagged and optional arguments */
 	while ( sieve_ast_argument_type(arg) == SAAT_TAG ) {
 		unsigned int id_code;
+		struct sieve_ast_argument *tag_arg = arg;
+		struct sieve_ast_argument *parg; 
 		const struct sieve_argument *tag = 
 			sieve_validator_find_tag
 				(validator, cmd_reg, sieve_ast_argument_tag(arg), &id_code);
@@ -421,18 +423,43 @@ static bool sieve_validate_command_arguments
 		if ( tag->identifier != NULL && *(tag->identifier) == '\0' ) 
 			return FALSE;
 		
-		/* Assign the tagged argument type to the ast for later reference (in generator) */
+		/* Assign the tagged argument type to the ast for later reference 
+		 * (in generator) 
+		 */
 		arg->argument = tag;
 		arg->arg_id_code = id_code;
 		
 		/* Call the validation function for the tag (if present)
-		 *   Fail if the validation fails.
+		 *   Fail if the validation fails:
+		 *     Let's not whine multiple times about a single command having multiple 
+		 *     bad arguments...
 		 */ 
 		if ( tag->validate != NULL ) { 
 			if ( !tag->validate(validator, &arg, cmd) ) 
 				return FALSE;
 		} else
 			arg = sieve_ast_argument_next(arg);  
+			
+		/* Scan backwards for any duplicates */
+		parg = sieve_ast_argument_prev(tag_arg);
+		while ( parg != NULL ) {
+			if ( parg->argument == tag ) {
+				const char *tag_id = sieve_ast_argument_tag(tag_arg);
+				const char *tag_desc =
+					strcmp(tag->identifier, tag_id) != 0 ?
+					t_strdup_printf("%s argument (:%s)", tag->identifier, tag_id) : 
+					t_strdup_printf(":%s argument", tag->identifier); 
+					 
+				sieve_command_validate_error(validator, cmd, 
+					"encountered duplicate %s for the %s %s",
+					tag_desc, cmd->command->identifier, 
+					sieve_command_type_name(cmd->command));
+					
+				return FALSE;	
+			}
+			
+			parg = sieve_ast_argument_prev(parg);
+		}
 	} 
 	
 	/* Remaining arguments should be positional (tags are not allowed here) */
@@ -441,8 +468,10 @@ static bool sieve_validate_command_arguments
 	while ( arg != NULL ) {
 		if ( sieve_ast_argument_type(arg) == SAAT_TAG ) {
 			sieve_command_validate_error(validator, cmd, 
-				"encountered an unexpected tagged argument ':%s' while validating positional arguments for the %s %s",
-				sieve_ast_argument_tag(arg), cmd->command->identifier, sieve_command_type_name(cmd->command));
+				"encountered an unexpected tagged argument ':%s' "
+				"while validating positional arguments for the %s %s",
+				sieve_ast_argument_tag(arg), cmd->command->identifier, 
+				sieve_command_type_name(cmd->command));
 			return FALSE;
 		}
 		
-- 
GitLab