From d622ff1aed6863e7d17767954f85de59cd0ee526 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sun, 28 Dec 2008 13:37:18 +0100
Subject: [PATCH] Exported variable string argument into the Sieve engine
 itself as 'catenated string' (for similar use in other extensions like the
 testsuite).

---
 .../variables/ext-variables-arguments.c       | 92 +++++--------------
 src/lib-sieve/sieve-ast.c                     | 29 ++++--
 src/lib-sieve/sieve-ast.h                     |  8 +-
 src/lib-sieve/sieve-commands.c                | 65 +++++++++++++
 src/lib-sieve/sieve-commands.h                | 14 +++
 5 files changed, 130 insertions(+), 78 deletions(-)

diff --git a/src/lib-sieve/plugins/variables/ext-variables-arguments.c b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
index d6aced2d2..53c6ccd71 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-arguments.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-arguments.c
@@ -247,45 +247,26 @@ static bool arg_match_value_generate
 static bool arg_variable_string_validate
 	(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
 		struct sieve_command_context *context);
-static bool arg_variable_string_generate
-(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
-	struct sieve_command_context *context);
 
 const struct sieve_argument variable_string_argument = { 
 	"@variable-string", 
 	NULL, NULL,
 	arg_variable_string_validate, 
 	NULL, 
-	arg_variable_string_generate,
-};
-
-struct _variable_string_data {
-	struct sieve_ast_arg_list *str_parts;
+	sieve_arg_catenated_string_generate,
 };
 
-inline static struct sieve_ast_argument *_add_string_element
-(struct sieve_ast_arg_list *list, struct sieve_ast_argument *arg)
-{
-	struct sieve_ast_argument *strarg = 
-		sieve_ast_argument_create(arg->ast, arg->source_line);
-	sieve_ast_arg_list_add(list, strarg);
-	strarg->type = SAAT_STRING;
-
-	return strarg;
-}
-
 static bool arg_variable_string_validate
 (struct sieve_validator *validator, struct sieve_ast_argument **arg, 
 		struct sieve_command_context *cmd)
 {
 	enum { ST_NONE, ST_OPEN, ST_VARIABLE, ST_CLOSE } state = ST_NONE;
 	pool_t pool = sieve_ast_pool((*arg)->ast);
-	struct sieve_ast_arg_list *arglist = NULL;
+	struct sieve_arg_catenated_string *catstr = NULL;
 	string_t *str = sieve_ast_argument_str(*arg);
 	const char *p, *strstart, *substart = NULL;
 	const char *strval = (const char *) str_data(str);
 	const char *strend = strval + str_len(str);
-	struct _variable_string_data *strdata;
 	bool result = TRUE;
 
 	ARRAY_TYPE(ext_variable_name) substitution;	
@@ -336,8 +317,8 @@ static bool arg_variable_string_validate
 				
 					/* We now know that the substitution is valid */	
 					
-					if ( arglist == NULL ) {
-						arglist = sieve_ast_arg_list_create(pool);
+					if ( catstr == NULL ) {
+						catstr = sieve_arg_catenated_string_create(*arg);
 					}
 				
 					/* Add the substring that is before the substitution to the 
@@ -347,9 +328,12 @@ static bool arg_variable_string_validate
 					 * coalesce this substring with the one after the substitution.
 					 */
 					if ( substart > strstart ) {
-						strarg = _add_string_element(arglist, *arg);
-						strarg->_value.str = str_new(pool, substart - strstart);
-						str_append_n(strarg->_value.str, strstart, substart - strstart); 
+						string_t *newstr = str_new(pool, substart - strstart);
+						str_append_n(newstr, strstart, substart - strstart); 
+						
+						strarg = sieve_ast_argument_string_create_raw
+							((*arg)->ast, newstr, (*arg)->source_line);
+						sieve_arg_catenated_string_add_element(catstr, strarg);
 					
 						/* Give other substitution extensions a chance to do their work */
 						if ( !sieve_validator_argument_activate_super
@@ -371,7 +355,7 @@ static bool arg_variable_string_validate
 							strarg = ext_variables_variable_argument_create
 								(validator, (*arg)->ast, (*arg)->source_line, str_c(cur_ident));
 							if ( strarg != NULL )
-								sieve_ast_arg_list_add(arglist, strarg);
+								sieve_arg_catenated_string_add_element(catstr, strarg);
 							else {
 								_ext_variables_scope_size_error
 									(validator, *arg, str_c(cur_element->identifier));
@@ -391,7 +375,7 @@ static bool arg_variable_string_validate
 								(validator, (*arg)->ast, (*arg)->source_line, 
 								cur_element->num_variable);
 							if ( strarg != NULL )
-								sieve_ast_arg_list_add(arglist, strarg);
+								sieve_arg_catenated_string_add_element(catstr, strarg);
 						}
 					} else {
 						const struct ext_variable_name *cur_element = 
@@ -425,62 +409,30 @@ static bool arg_variable_string_validate
 	if ( !result ) return FALSE;
 	
 	/* Check whether any substitutions were found */
-	if ( arglist == NULL ) {
+	if ( catstr == NULL ) {
 		/* No substitutions in this string, pass it on to any other substution
 		 * extension.
 		 */
-		return sieve_validator_argument_activate_super
-			(validator, cmd, *arg, TRUE);
+		return sieve_validator_argument_activate_super(validator, cmd, *arg, TRUE);
 	}
 	
 	/* Add the final substring that comes after the last substitution to the 
 	 * variable-string AST.
 	 */
 	if ( strend > strstart ) {
-		struct sieve_ast_argument *strarg = _add_string_element(arglist, *arg);
-		strarg->_value.str = str_new(pool, strend - strstart);
-		str_append_n(strarg->_value.str, strstart, strend - strstart); 
-	
+		struct sieve_ast_argument *strarg;
+		string_t *newstr = str_new(pool, strend - strstart);
+		str_append_n(newstr, strstart, strend - strstart); 
+
+		strarg = sieve_ast_argument_string_create_raw
+			((*arg)->ast, newstr, (*arg)->source_line);
+		sieve_arg_catenated_string_add_element(catstr, strarg);
+			
 		/* Give other substitution extensions a chance to do their work */	
 		if ( !sieve_validator_argument_activate_super
 			(validator, cmd, strarg, FALSE) )
 			return FALSE;
 	}	
 	
-	/* Assign the constructed variable-string AST-branch to the actual AST */
-	strdata = p_new(pool, struct _variable_string_data, 1);
-	strdata->str_parts = arglist;
-	(*arg)->context = (void *) strdata;
-
-	return TRUE;
-}
-
-#define _string_data_first(data) __AST_LIST_FIRST((data)->str_parts)
-#define _string_data_count(data) __AST_LIST_COUNT((data)->str_parts)
-#define _string_data_next(item) __AST_LIST_NEXT(item)
-
-static bool arg_variable_string_generate
-(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
-	struct sieve_command_context *cmd) 
-{
-	struct sieve_binary *sbin = cgenv->sbin;
-	struct _variable_string_data *strdata = 
-		(struct _variable_string_data *) arg->context;
-	struct sieve_ast_argument *strpart;
-	
-	if ( _string_data_count(strdata) == 1 )
-		sieve_generate_argument(cgenv, _string_data_first(strdata), cmd);
-	else {
-		sieve_opr_catenated_string_emit(sbin, _string_data_count(strdata));
-
-		strpart = _string_data_first(strdata);
-		while ( strpart != NULL ) {
-			if ( !sieve_generate_argument(cgenv, strpart, cmd) )
-				return FALSE;
-			
-			strpart = _string_data_next(strpart);
-		}
-	}
-	
 	return TRUE;
 }
diff --git a/src/lib-sieve/sieve-ast.c b/src/lib-sieve/sieve-ast.c
index 1f5f4c350..4bb4ca054 100644
--- a/src/lib-sieve/sieve-ast.c
+++ b/src/lib-sieve/sieve-ast.c
@@ -459,18 +459,35 @@ static void sieve_ast_argument_substitute
 	sieve_ast_arg_list_substitute(argument->list, argument, replacement);
 }
 
-struct sieve_ast_argument *sieve_ast_argument_string_create
-(struct sieve_ast_node *node, const string_t *str, unsigned int source_line) 
-{	
+struct sieve_ast_argument *sieve_ast_argument_string_create_raw
+(struct sieve_ast *ast, string_t *str, unsigned int source_line) 
+{
 	struct sieve_ast_argument *argument = sieve_ast_argument_create
-		(node->ast, source_line);
+		(ast, source_line);
 		
 	argument->type = SAAT_STRING;
+	argument->_value.str = str;
+
+	return argument;
+}
+
+struct sieve_ast_argument *sieve_ast_argument_string_create
+(struct sieve_ast_node *node, const string_t *str, unsigned int source_line) 
+{	
+	struct sieve_ast_argument *argument;
+	string_t *newstr;
+	
+	/* Allocate new internal string buffer */
+	newstr = str_new(node->ast->pool, str_len(str));
 	
 	/* Clone string */
-	argument->_value.str = str_new(node->ast->pool, str_len(str));
-	str_append_str(argument->_value.str, str);
+	str_append_str(newstr, str);
+	 
+	/* Create string argument */
+	argument = sieve_ast_argument_string_create_raw
+		(node->ast, newstr, source_line);
 
+	/* Add argument to command/test node */
 	sieve_ast_node_add_argument(node, argument);
 
 	return argument;
diff --git a/src/lib-sieve/sieve-ast.h b/src/lib-sieve/sieve-ast.h
index f2fc4e3e2..68c7175bf 100644
--- a/src/lib-sieve/sieve-ast.h
+++ b/src/lib-sieve/sieve-ast.h
@@ -230,13 +230,17 @@ bool sieve_ast_arg_list_insert
 	(struct sieve_ast_arg_list *list, struct sieve_ast_argument *before,
 		struct sieve_ast_argument *argument);
 void sieve_ast_arg_list_substitute
-(struct sieve_ast_arg_list *list, struct sieve_ast_argument *argument, 
-	struct sieve_ast_argument *replacement);
+	(struct sieve_ast_arg_list *list, struct sieve_ast_argument *argument, 
+		struct sieve_ast_argument *replacement);
 
+struct sieve_ast_argument *sieve_ast_argument_string_create_raw
+	(struct sieve_ast *ast, string_t *str, unsigned int source_line);
 struct sieve_ast_argument *sieve_ast_argument_string_create
 	(struct sieve_ast_node *node, const string_t *str, unsigned int source_line);
+	
 struct sieve_ast_argument *sieve_ast_argument_tag_create
 	(struct sieve_ast_node *node, const char *tag, unsigned int source_line);
+
 struct sieve_ast_argument *sieve_ast_argument_number_create
 	(struct sieve_ast_node *node, unsigned int number, unsigned int source_line);
 
diff --git a/src/lib-sieve/sieve-commands.c b/src/lib-sieve/sieve-commands.c
index 4dbd914be..58f712582 100644
--- a/src/lib-sieve/sieve-commands.c
+++ b/src/lib-sieve/sieve-commands.c
@@ -142,6 +142,71 @@ static bool arg_string_list_generate
 	return FALSE;
 }
 
+/*
+ * Abstract arguments 
+ *
+ *   (Generated by processing and not by parsing the grammar)
+ */
+ 
+/* Catenated string */
+
+struct sieve_arg_catenated_string {
+	struct sieve_ast_arg_list *str_parts;
+};
+ 
+struct sieve_arg_catenated_string *sieve_arg_catenated_string_create
+(struct sieve_ast_argument *orig_arg)
+{
+	pool_t pool = sieve_ast_pool(orig_arg->ast);
+	struct sieve_ast_arg_list *arglist;
+	struct sieve_arg_catenated_string *catstr;
+
+	arglist = sieve_ast_arg_list_create(pool);
+					
+	catstr = p_new(pool, struct sieve_arg_catenated_string, 1);
+	catstr->str_parts = arglist;
+	(orig_arg)->context = (void *) catstr;
+	
+	return catstr;
+}
+
+void sieve_arg_catenated_string_add_element
+(struct sieve_arg_catenated_string *catstr, 
+	struct sieve_ast_argument *element)
+{
+	sieve_ast_arg_list_add(catstr->str_parts, element);
+}
+
+#define _cat_string_first(catstr) __AST_LIST_FIRST((catstr)->str_parts)
+#define _cat_string_count(catstr) __AST_LIST_COUNT((catstr)->str_parts)
+#define _cat_string_next(item) __AST_LIST_NEXT(item)
+
+bool sieve_arg_catenated_string_generate
+(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
+	struct sieve_command_context *cmd) 
+{
+	struct sieve_binary *sbin = cgenv->sbin;
+	struct sieve_arg_catenated_string *catstr = 
+		(struct sieve_arg_catenated_string *) arg->context;
+	struct sieve_ast_argument *strpart;
+	
+	if ( _cat_string_count(catstr) == 1 )
+		sieve_generate_argument(cgenv, _cat_string_first(catstr), cmd);
+	else {
+		sieve_opr_catenated_string_emit(sbin, _cat_string_count(catstr));
+
+		strpart = _cat_string_first(catstr);
+		while ( strpart != NULL ) {
+			if ( !sieve_generate_argument(cgenv, strpart, cmd) )
+				return FALSE;
+			
+			strpart = _cat_string_next(strpart);
+		}
+	}
+	
+	return TRUE;
+}
+
 /* 
  * Core tests and commands 
  */
diff --git a/src/lib-sieve/sieve-commands.h b/src/lib-sieve/sieve-commands.h
index bcfd6c89c..710afed83 100644
--- a/src/lib-sieve/sieve-commands.h
+++ b/src/lib-sieve/sieve-commands.h
@@ -52,6 +52,20 @@ extern const struct sieve_argument number_argument;
 extern const struct sieve_argument string_argument;
 extern const struct sieve_argument string_list_argument;
 
+/* Catenated string argument */
+
+bool sieve_arg_catenated_string_generate
+	(const struct sieve_codegen_env *cgenv, struct sieve_ast_argument *arg, 
+		struct sieve_command_context *context);
+
+struct sieve_arg_catenated_string;		
+
+struct sieve_arg_catenated_string *sieve_arg_catenated_string_create
+	(struct sieve_ast_argument *orig_arg);
+void sieve_arg_catenated_string_add_element
+	(struct sieve_arg_catenated_string *strdata, 
+		struct sieve_ast_argument *element);
+
 /* 
  * Command object
  */
-- 
GitLab