From 8cfba719cec89d81b21358b57faeaabb06dd945f Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Tue, 20 Nov 2007 10:57:46 +0100
Subject: [PATCH] Removed code duplication in validator: merged command and
 test validation in one function.

---
 src/lib-sieve/sieve-ast.c       |  12 +++
 src/lib-sieve/sieve-ast.h       |   2 +
 src/lib-sieve/sieve-commands.c  |   1 +
 src/lib-sieve/sieve-commands.h  |   1 +
 src/lib-sieve/sieve-validator.c | 142 +++++++++-----------------------
 5 files changed, 57 insertions(+), 101 deletions(-)

diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c
index 255d29bbf..24d67095a 100644
--- a/src/lib-sieve/sieve-ast.c
+++ b/src/lib-sieve/sieve-ast.c
@@ -313,6 +313,18 @@ void sieve_ast_unref(struct sieve_ast **ast) {
 	}
 }
 
+const char *sieve_ast_type_name(enum sieve_ast_type ast_type) {
+	switch ( ast_type ) {
+	
+	case SAT_NONE: return "none";
+	case SAT_ROOT: return "ast root node";
+	case SAT_COMMAND: return "command";
+	case SAT_TEST: return "test";
+	
+	default: return "??AST NODE??";
+	}
+}
+
 /* Debug */
 
 /* Unparsing, currently implemented using plain printf()s */
diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h
index 81ce0c254..5b196c541 100644
--- a/src/lib-sieve/sieve-ast.h
+++ b/src/lib-sieve/sieve-ast.h
@@ -190,6 +190,8 @@ struct sieve_ast *sieve_ast_create( void );
 void sieve_ast_ref(struct sieve_ast *ast);
 void sieve_ast_unref(struct sieve_ast **ast);
 
+const char *sieve_ast_type_name(enum sieve_ast_type ast_type);
+
 /* Debug */
 void sieve_ast_unparse(struct sieve_ast *ast);
 
diff --git a/src/lib-sieve/sieve-commands.c b/src/lib-sieve/sieve-commands.c
index adc20b413..a1345ea3d 100644
--- a/src/lib-sieve/sieve-commands.c
+++ b/src/lib-sieve/sieve-commands.c
@@ -219,6 +219,7 @@ struct sieve_command_context *sieve_command_context_create
 
 const char *sieve_command_type_name(const struct sieve_command *command) {
 	switch ( command->type ) {
+	case SCT_NONE: return "command of unspecified type (bug)";
 	case SCT_TEST: return "test";
 	case SCT_COMMAND: return "command";
 	default:
diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h
index a20b58a42..47df57a99 100644
--- a/src/lib-sieve/sieve-commands.h
+++ b/src/lib-sieve/sieve-commands.h
@@ -28,6 +28,7 @@ extern const struct sieve_argument string_list_argument;
 /* Command */
 
 enum sieve_command_type {
+	SCT_NONE,
 	SCT_COMMAND,
 	SCT_TEST
 };
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index 95402b79e..afd08f38e 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -121,11 +121,7 @@ static bool _cmd_unknown_validate
 }
 
 static const struct sieve_command unknown_command = { 
-	"", SCT_COMMAND, 0, 0, FALSE, FALSE , 
-	NULL, NULL, _cmd_unknown_validate, NULL, NULL 
-};
-static const struct sieve_command unknown_test = { 
-	"", SCT_TEST, 0, 0, FALSE, FALSE,
+	"", SCT_NONE, 0, 0, FALSE, FALSE , 
 	NULL, NULL, _cmd_unknown_validate, NULL, NULL 
 };
 
@@ -174,12 +170,6 @@ static void sieve_validator_register_unknown_command
 	_sieve_validator_register_command(validator, &unknown_command, command);		
 }
 
-static void sieve_validator_register_unknown_test
-	(struct sieve_validator *validator, const char *test) 
-{		
-	_sieve_validator_register_command(validator, &unknown_test, test);		
-}
-
 static struct sieve_command_registration *sieve_validator_find_command_registration
 		(struct sieve_validator *validator, const char *command) 
 {
@@ -547,106 +537,37 @@ static bool sieve_validate_command_block
 
 /* AST Validation */
 
-static bool sieve_validate_test_list(struct sieve_validator *validator, struct sieve_ast_node *test_list); 
-static bool sieve_validate_test(struct sieve_validator *validator, struct sieve_ast_node *tst_node); 
-static bool sieve_validate_block(struct sieve_validator *validator, struct sieve_ast_node *block);
-static bool sieve_validate_command(struct sieve_validator *validator, struct sieve_ast_node *cmd_node);
-
-static bool sieve_validate_test(struct sieve_validator *validator, struct sieve_ast_node *tst_node) 
-{
-	bool result = TRUE;
-	const struct sieve_command *test;
-	
-	i_assert( sieve_ast_node_type(tst_node) == SAT_TEST );
-	
-	test = sieve_validator_find_command(validator, tst_node->identifier);
-	
-	if ( test != NULL ) {
-		/* Identifier = "" when the command was previously marked as unknown */
-		if ( *(test->identifier) != '\0' ) {
-			if ( test->type != SCT_TEST ) {
-				sieve_validator_error(
-					validator, tst_node, 
-					"attempted to use command '%s' as test", tst_node->identifier);
-			 	result = FALSE;
-			} else {
-				struct sieve_command_context *ctx = 
-					sieve_command_context_create(tst_node, test); 
-				tst_node->context = ctx;
-
-				/* If pre-validation fails, don't bother to validate further 
-				 * as context might be missing and doing so is not very useful for 
-				 * further error reporting anyway
-				 */
-				if ( test->pre_validate == NULL || 
-					test->pre_validate(validator, ctx) ) {
-	
-					/* Check syntax */
-		 			if ( 
-		 				!sieve_validate_command_arguments
-		 					(validator,ctx, test->positional_arguments) ||
-		 				!sieve_validate_command_subtests
-		 					(validator, ctx, test->subtests) ) 
-		 			{
-		 				result = FALSE; 
-		 			} else {
-						/* Call command validation function if specified */
-						if ( test->validate != NULL )
-							result = test->validate(validator, ctx) && result;
-					}
-				} else 
-					result = FALSE;
-			}
-		} else 
-			result = FALSE;
-			
-	} else {
-		sieve_validator_error(validator, tst_node, 
-			"unknown test '%s' (only reported once at first occurence)", 
-			tst_node->identifier);
-		sieve_validator_register_unknown_test(validator, tst_node->identifier);
-		
-		result = FALSE;
-	}
-	
-	result = sieve_validate_test_list(validator, tst_node) && result;
-
-	return result;
-}
-
 static bool sieve_validate_test_list
-	(struct sieve_validator *validator, struct sieve_ast_node *test_list) 
-{
-	bool result = TRUE;
-	struct sieve_ast_node *test;
-
-	test = sieve_ast_test_first(test_list);
-	while ( test != NULL ) {	
-		result = sieve_validate_test(validator, test) && result;	
-		test = sieve_ast_test_next(test);
-	}		
+	(struct sieve_validator *validator, struct sieve_ast_node *test_list); 
+static bool sieve_validate_block
+	(struct sieve_validator *validator, struct sieve_ast_node *block);
+static bool sieve_validate_command
+	(struct sieve_validator *validator, struct sieve_ast_node *cmd_node);
 	
-	return result;
-}
-
 static bool sieve_validate_command
 	(struct sieve_validator *validator, struct sieve_ast_node *cmd_node) 
 {
+	enum sieve_ast_type ast_type = sieve_ast_node_type(cmd_node);
 	bool result = TRUE;
 	const struct sieve_command *command;
 	
-	i_assert( sieve_ast_node_type(cmd_node) == SAT_COMMAND );
+	i_assert( ast_type == SAT_TEST || ast_type == SAT_COMMAND );
 	
 	command = sieve_validator_find_command(validator, cmd_node->identifier);
 	
 	if ( command != NULL ) {
 		/* Identifier = "" when the command was previously marked as unknown */
 		if ( *(command->identifier) != '\0' ) {
-			if ( command->type != SCT_COMMAND ) {
+			if ( (command->type == SCT_COMMAND && ast_type == SAT_TEST) || 
+				(command->type == SCT_TEST && ast_type == SAT_COMMAND) ) 
+			{
 				sieve_validator_error(
-					validator, cmd_node, 
-					"attempted to use test '%s' as command", cmd_node->identifier);
-			 	result = FALSE;
+					validator, cmd_node, "attempted to use %s '%s' as %s", 
+					sieve_command_type_name(command),	cmd_node->identifier,
+					sieve_ast_type_name(ast_type));
+			
+			 	return FALSE;
+			
 			} else { 
 				struct sieve_command_context *ctx = 
 					sieve_command_context_create(cmd_node, command); 
@@ -665,8 +586,9 @@ static bool sieve_validate_command
 							(validator, ctx, command->positional_arguments) ||
 	 					!sieve_validate_command_subtests
 	 						(validator, ctx, command->subtests) || 
-	 					!sieve_validate_command_block
-	 						(validator, ctx, command->block_allowed, command->block_required) ) 
+	 					(ast_type == SAT_COMMAND && !sieve_validate_command_block
+	 						(validator, ctx, command->block_allowed, 
+	 							command->block_required)) ) 
 	 				{
 	 					result = FALSE;
 	 				} else {
@@ -683,15 +605,33 @@ static bool sieve_validate_command
 	} else {
 		sieve_validator_error(
 			validator, cmd_node, 
-			"unknown command '%s' (only reported once at first occurence)", 
-			cmd_node->identifier);
+			"unknown %s '%s' (only reported once at first occurence)", 
+			sieve_ast_type_name(ast_type), cmd_node->identifier);
+			
 		sieve_validator_register_unknown_command(validator, cmd_node->identifier);
 		
 		result = FALSE;
 	}
 	
 	result = sieve_validate_test_list(validator, cmd_node) && result;
-	result = sieve_validate_block(validator, cmd_node) && result;
+
+	if ( ast_type == SAT_COMMAND )
+		result = sieve_validate_block(validator, cmd_node) && result;
+	
+	return result;
+}
+
+static bool sieve_validate_test_list
+	(struct sieve_validator *validator, struct sieve_ast_node *test_list) 
+{
+	bool result = TRUE;
+	struct sieve_ast_node *test;
+
+	test = sieve_ast_test_first(test_list);
+	while ( test != NULL ) {	
+		result = sieve_validate_command(validator, test) && result;	
+		test = sieve_ast_test_next(test);
+	}		
 	
 	return result;
 }
-- 
GitLab