From c527430b02a3e3712dd1883ed48a15d967b2d7bf Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Tue, 20 Dec 2011 20:05:21 +0100
Subject: [PATCH] lib-sieve: adjusted code fetch api for handling omitted
 operands better. Removes quite a bit of duplicated source code.

---
 src/lib-sieve/cmd-redirect.c                  |  4 +-
 src/lib-sieve/ext-fileinto.c                  |  4 +-
 src/lib-sieve/plugins/date/tst-date.c         | 26 +-------
 .../plugins/editheader/cmd-deleteheader.c     | 26 ++------
 src/lib-sieve/plugins/imap4flags/tag-flags.c  | 57 +++++++-----------
 src/lib-sieve/sieve-code.c                    | 59 +++++++++++++++++--
 src/lib-sieve/sieve-code.h                    | 10 +++-
 7 files changed, 96 insertions(+), 90 deletions(-)

diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index 6ce20a20d..6b1e1f35e 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -209,8 +209,8 @@ static int cmd_redirect_operation_execute
 		return ret;
 
 	/* Read the address */
-	if ( (ret=sieve_opr_string_read_ex(renv, address, "address", &redirect, 
-		&literal_address)) <= 0 )
+	if ( (ret=sieve_opr_string_read_ex
+		(renv, address, "address", FALSE, &redirect, &literal_address)) <= 0 )
 		return ret;
 
 	/*
diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c
index 93c466d34..ec98dee5d 100644
--- a/src/lib-sieve/ext-fileinto.c
+++ b/src/lib-sieve/ext-fileinto.c
@@ -183,8 +183,8 @@ static int ext_fileinto_operation_execute
 		return ret;
 
 	/* Folder operand */
-	if ( (ret=sieve_opr_string_read_ex(renv, address, "folder", &folder, 
-		&folder_literal)) <= 0 )
+	if ( (ret=sieve_opr_string_read_ex
+		(renv, address, "folder", FALSE, &folder, &folder_literal)) <= 0 )
 		return ret;
 
 	/*
diff --git a/src/lib-sieve/plugins/date/tst-date.c b/src/lib-sieve/plugins/date/tst-date.c
index eeb13070d..9dab18772 100644
--- a/src/lib-sieve/plugins/date/tst-date.c
+++ b/src/lib-sieve/plugins/date/tst-date.c
@@ -331,7 +331,6 @@ static bool tst_date_operation_dump
 {
 	int opt_code = 0;
 	const struct sieve_operation *op = denv->oprtn;
-	struct sieve_operand operand;
 
 	sieve_code_dumpf(denv, "%s", sieve_operation_mnemonic(op));
 	sieve_code_descend(denv);
@@ -347,18 +346,8 @@ static bool tst_date_operation_dump
 
 		switch ( opt_code ) {
 		case OPT_DATE_ZONE:
-			if ( !sieve_operand_read(denv->sblock, address, "zone", &operand) ) {
-				sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
+			if ( !sieve_opr_string_dump_ex(denv, address, "zone", "ORIGINAL") )
 				return FALSE;
-			}				
-
-			if ( sieve_operand_is_omitted(&operand) ) {
-				sieve_code_dumpf(denv, "zone: ORIGINAL");
-			} else {
-				if ( !sieve_opr_string_dump_data
-					(denv, &operand, address, "zone") )
-					return FALSE;
-			}
 			break;
     default:
 			return FALSE;
@@ -388,7 +377,6 @@ static int tst_date_operation_execute
 		SIEVE_MATCH_TYPE_DEFAULT(is_match_type);
 	struct sieve_comparator cmp = 
 		SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
-	struct sieve_operand oprnd;
 	string_t *date_part = NULL, *zone = NULL;
 	struct sieve_stringlist *hdr_list = NULL, *hdr_value_list;
 	struct sieve_stringlist *value_list, *key_list;
@@ -408,18 +396,10 @@ static int tst_date_operation_execute
 	
 		switch ( opt_code ) {
 		case OPT_DATE_ZONE:
-			if ( (ret=sieve_operand_runtime_read(renv, address, "zone", &oprnd))
-				<= 0 )
+			if ( (ret=sieve_opr_string_read_ex
+				(renv, address, "zone", TRUE, &zone, &zone_literal)) <= 0 )
 				return ret;
 
-			if ( !sieve_operand_is_omitted(&oprnd) ) {
-				if ( (ret=sieve_opr_string_read_data
-					(renv, &oprnd, address, "zone", &zone)) <= 0 )
-					return ret;
-
-				zone_literal = sieve_operand_is_string_literal(&oprnd);
-			}
-
 			zone_specified = TRUE;
 			break;
 		default:
diff --git a/src/lib-sieve/plugins/editheader/cmd-deleteheader.c b/src/lib-sieve/plugins/editheader/cmd-deleteheader.c
index 7030350f6..433d36ed2 100644
--- a/src/lib-sieve/plugins/editheader/cmd-deleteheader.c
+++ b/src/lib-sieve/plugins/editheader/cmd-deleteheader.c
@@ -316,7 +316,6 @@ static bool cmd_deleteheader_generate
 static bool cmd_deleteheader_operation_dump
 (const struct sieve_dumptime_env *denv, sieve_size_t *address)
 {
-	struct sieve_operand oprnd;
 	int opt_code = 0;
 
 	sieve_code_dumpf(denv, "DELETEHEADER");
@@ -347,19 +346,7 @@ static bool cmd_deleteheader_operation_dump
 	if ( !sieve_opr_string_dump(denv, address, "field name") )
 		return FALSE;
 
-	sieve_code_mark(denv);
-
-	if ( !sieve_operand_read
-		(denv->sblock, address, "value patterns", &oprnd) ) {
-		sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
-		return FALSE;
-	}				
-
-	if ( sieve_operand_is_omitted(&oprnd) )
-		return TRUE;
-
-	return sieve_opr_stringlist_dump_data
-		(denv, &oprnd, address, "value patterns");
+	return sieve_opr_stringlist_dump_ex(denv, address, "value patterns", "");
 }
 
 /* 
@@ -371,7 +358,6 @@ static int cmd_deleteheader_operation_execute
 {
 	const struct sieve_extension *this_ext = renv->oprtn->ext;
 	int opt_code = 0;
-	struct sieve_operand oprnd;
 	struct sieve_comparator cmp = 
 		SIEVE_COMPARATOR_DEFAULT(i_ascii_casemap_comparator);
 	struct sieve_match_type mcht = 
@@ -423,13 +409,9 @@ static int cmd_deleteheader_operation_execute
 		<= 0 )
 		return ret;
 
-	/* Read value-patterns */	
-	if ( (ret=sieve_operand_runtime_read
-		(renv, address, "value-patterns", &oprnd)) <= 0 )
-		return ret;
-
-	if ( !sieve_operand_is_omitted(&oprnd) && (ret=sieve_opr_stringlist_read_data
-		(renv, &oprnd, address, "value-patterns", &vpattern_list)) <= 0 )
+	/* Read value-patterns */
+	if ( (ret=sieve_opr_stringlist_read_ex
+		(renv, address, "value-patterns", TRUE, &vpattern_list)) <= 0 )
 		return ret;
 	
 	/*
diff --git a/src/lib-sieve/plugins/imap4flags/tag-flags.c b/src/lib-sieve/plugins/imap4flags/tag-flags.c
index 7d53d9aa2..e0f960e03 100644
--- a/src/lib-sieve/plugins/imap4flags/tag-flags.c
+++ b/src/lib-sieve/plugins/imap4flags/tag-flags.c
@@ -197,19 +197,7 @@ static bool seff_flags_dump_context
 (const struct sieve_side_effect *seffect ATTR_UNUSED, 
 	const struct sieve_dumptime_env *denv, sieve_size_t *address)
 {
-  struct sieve_operand oprnd;
-
-  if ( !sieve_operand_read(denv->sblock, address, "flags", &oprnd) ) {
-		sieve_code_dumpf(denv, "ERROR: INVALID OPERAND");
-		return FALSE;
-	}
-
-	if ( sieve_operand_is_omitted(&oprnd) ) {
-		sieve_code_dumpf(denv, "flags: INTERNAL");
-		return TRUE;
-	}
-
-	return sieve_opr_stringlist_dump_data(denv, &oprnd, address, "flags");
+	return sieve_opr_stringlist_dump_ex(denv, address, "flags", "INTERNAL");
 }
 
 static struct seff_flags_context *seff_flags_get_implicit_context
@@ -252,43 +240,30 @@ static struct seff_flags_context *seff_flags_get_implicit_context
 	return ctx;
 }
 
-static int seff_flags_read_context
+static int seff_flags_do_read_context
 (const struct sieve_side_effect *seffect, 
 	const struct sieve_runtime_env *renv, sieve_size_t *address,
 	void **se_context)
 {
-	struct sieve_operand oprnd;
 	pool_t pool = sieve_result_pool(renv->result);
 	struct seff_flags_context *ctx;
 	string_t *flags_item;
-	struct sieve_stringlist *flag_list;
-	int ret;
-	
-	t_push();
+	struct sieve_stringlist *flag_list = NULL;
+	int ret;	
 
-	/* Check whether explicit flag list operand is present */
-	if ( (ret=sieve_operand_runtime_read(renv, address, "flags", &oprnd)) <= 0 ) {
- 		t_pop();
+	if ( (ret=sieve_opr_stringlist_read_ex
+		(renv, address, "flags", TRUE, &flag_list)) <= 0 )
 		return ret;
-	}
 	
-	if ( sieve_operand_is_omitted(&oprnd) ) {
+	if ( flag_list == NULL ) {
 		/* Flag list is omitted, use current value of internal 
 		 * variable to construct side effect context.
 		 */
 		*se_context = seff_flags_get_implicit_context
 			(SIEVE_OBJECT_EXTENSION(seffect), renv->result);
-		t_pop();
 		return SIEVE_EXEC_OK;
 	}
-	
-	/* Read flag-list */
-	if ( (ret=sieve_opr_stringlist_read_data
-		(renv, &oprnd, address, NULL, &flag_list)) <= 0 ) {
-		t_pop();
-		return ret;
-	}
-	
+		
 	ctx = p_new(pool, struct seff_flags_context, 1);
 	p_array_init(&ctx->keywords, pool, 2);
 
@@ -325,12 +300,24 @@ static int seff_flags_read_context
 	}
 	
 	*se_context = (void *) ctx;
-
-	t_pop();
 	
 	return SIEVE_EXEC_OK;
 }
 
+static int seff_flags_read_context
+(const struct sieve_side_effect *seffect, 
+	const struct sieve_runtime_env *renv, sieve_size_t *address,
+	void **se_context)
+{
+	int ret;
+
+	T_BEGIN {
+		ret = seff_flags_do_read_context(seffect, renv, address, se_context);
+	} T_END;
+
+	return ret;
+}
+
 /* Result verification */
 
 static int seff_flags_merge
diff --git a/src/lib-sieve/sieve-code.c b/src/lib-sieve/sieve-code.c
index 5269702df..1b8232dba 100644
--- a/src/lib-sieve/sieve-code.c
+++ b/src/lib-sieve/sieve-code.c
@@ -536,7 +536,7 @@ bool sieve_opr_string_dump
 
 bool sieve_opr_string_dump_ex
 (const struct sieve_dumptime_env *denv, sieve_size_t *address, 
-	const char *field_name, bool *literal_r)
+	const char *field_name, const char *omitted_value)
 {
 	struct sieve_operand operand;
 	
@@ -546,7 +546,11 @@ bool sieve_opr_string_dump_ex
 		return FALSE;
 	}
 
-	*literal_r = sieve_operand_is_string_literal(&operand);
+	if ( omitted_value != NULL && sieve_operand_is_omitted(&operand) ) {
+		if ( *omitted_value != '\0' )
+			sieve_code_dumpf(denv, "%s: %s", field_name, omitted_value);
+		return TRUE;
+	}
 
 	return sieve_opr_string_dump_data(denv, &operand, address, field_name);
 } 
@@ -592,7 +596,7 @@ int sieve_opr_string_read
 
 int sieve_opr_string_read_ex
 (const struct sieve_runtime_env *renv, sieve_size_t *address,
-	const char *field_name, string_t **str_r, bool *literal_r)
+	const char *field_name, bool optional, string_t **str_r, bool *literal_r)
 {
 	struct sieve_operand operand;
 	int ret;
@@ -601,7 +605,13 @@ int sieve_opr_string_read_ex
 		<= 0 )
 		return ret;
 
-	*literal_r = sieve_operand_is_string_literal(&operand);
+	if ( optional && sieve_operand_is_omitted(&operand) ) {
+		*str_r = NULL;
+		return TRUE;
+	}
+
+	if ( literal_r != NULL )
+		*literal_r = sieve_operand_is_string_literal(&operand);
 
 	return sieve_opr_string_read_data(renv, &operand, address, field_name, str_r);
 }
@@ -732,6 +742,27 @@ bool sieve_opr_stringlist_dump
 	return sieve_opr_stringlist_dump_data(denv, &operand, address, field_name);
 }
 
+bool sieve_opr_stringlist_dump_ex
+(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+	const char *field_name, const char *omitted_value) 
+{
+	struct sieve_operand operand;
+
+	sieve_code_mark(denv);
+
+	if ( !sieve_operand_read(denv->sblock, address, field_name, &operand) ) {
+		return FALSE;
+	}
+
+	if ( omitted_value != NULL && sieve_operand_is_omitted(&operand) ) {
+		if ( *omitted_value != '\0' )
+			sieve_code_dumpf(denv, "%s: %s", field_name, omitted_value);
+		return TRUE;
+	}
+
+	return sieve_opr_stringlist_dump_data(denv, &operand, address, field_name);
+}
+
 int sieve_opr_stringlist_read_data
 (const struct sieve_runtime_env *renv, struct sieve_operand *oprnd,
 	sieve_size_t *address, const char *field_name, 
@@ -799,6 +830,26 @@ int sieve_opr_stringlist_read
 		(renv, &operand, address, field_name, strlist_r);
 }
 
+int sieve_opr_stringlist_read_ex
+(const struct sieve_runtime_env *renv, sieve_size_t *address, 
+	const char *field_name, bool optional, struct sieve_stringlist **strlist_r)
+{
+	struct sieve_operand operand;
+	int ret;
+
+	if ( (ret=sieve_operand_runtime_read(renv, address, field_name, &operand))
+		<= 0 )
+		return ret;
+
+	if ( optional && sieve_operand_is_omitted(&operand) ) {
+		*strlist_r = NULL;
+		return TRUE;
+	}
+	
+	return sieve_opr_stringlist_read_data
+		(renv, &operand, address, field_name, strlist_r);
+}
+
 static bool opr_stringlist_dump
 (const struct sieve_dumptime_env *denv, const struct sieve_operand *oprnd,
 	sieve_size_t *address) 
diff --git a/src/lib-sieve/sieve-code.h b/src/lib-sieve/sieve-code.h
index 04cdbfbbc..ac4e9a585 100644
--- a/src/lib-sieve/sieve-code.h
+++ b/src/lib-sieve/sieve-code.h
@@ -213,7 +213,7 @@ bool sieve_opr_string_dump
 		const char *field_name); 
 bool sieve_opr_string_dump_ex
 	(const struct sieve_dumptime_env *denv, sieve_size_t *address, 
-		const char *field_name, bool *literal_r); 
+		const char *field_name, const char *omitted_value); 
 int sieve_opr_string_read_data
 	(const struct sieve_runtime_env *renv, struct sieve_operand *operand,
 		sieve_size_t *address, const char *field_name, string_t **str_r);
@@ -222,7 +222,7 @@ int sieve_opr_string_read
 		const char *field_name, string_t **str_r);
 int sieve_opr_string_read_ex
 	(const struct sieve_runtime_env *renv, sieve_size_t *address, 
-		const char *field_name, string_t **str_r, bool *literal_r);
+		const char *field_name, bool optional, string_t **str_r, bool *literal_r);
 
 static inline bool sieve_operand_is_string
 (const struct sieve_operand *operand)
@@ -252,6 +252,9 @@ bool sieve_opr_stringlist_dump_data
 bool sieve_opr_stringlist_dump
 	(const struct sieve_dumptime_env *denv, sieve_size_t *address,
 		const char *field_name);
+bool sieve_opr_stringlist_dump_ex
+	(const struct sieve_dumptime_env *denv, sieve_size_t *address,
+		const char *field_name, const char *omitted_value);
 int sieve_opr_stringlist_read_data
 	(const struct sieve_runtime_env *renv, struct sieve_operand *operand, 
 		sieve_size_t *address, const char *field_name, 
@@ -259,6 +262,9 @@ int sieve_opr_stringlist_read_data
 int sieve_opr_stringlist_read
 	(const struct sieve_runtime_env *renv, sieve_size_t *address,
 		const char *field_name, struct sieve_stringlist **strlist_r);
+int sieve_opr_stringlist_read_ex
+	(const struct sieve_runtime_env *renv, sieve_size_t *address,
+		const char *field_name, bool optional, struct sieve_stringlist **strlist_r);
 
 static inline bool sieve_operand_is_stringlist
 (const struct sieve_operand *operand)
-- 
GitLab