From 47ce4d8c34b231cfe18a02b2cdba4d4b9bd304c7 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 10 Apr 2009 19:16:07 +0200
Subject: [PATCH] Include: added skeleton :once modifier.

---
 src/lib-sieve/plugins/include/cmd-include.c   | 54 ++++++++++++++++---
 .../plugins/include/ext-include-common.c      | 16 ++++--
 .../plugins/include/ext-include-common.h      |  2 +-
 src/lib-sieve/sieve-binary-dumper.c           |  2 +-
 .../extensions/include/included/once-1.sieve  |  9 ++++
 .../extensions/include/included/once-2.sieve  | 12 +++++
 tests/extensions/include/once.svtest          | 20 +++++++
 7 files changed, 102 insertions(+), 13 deletions(-)
 create mode 100644 tests/extensions/include/included/once-1.sieve
 create mode 100644 tests/extensions/include/included/once-2.sieve
 create mode 100644 tests/extensions/include/once.svtest

diff --git a/src/lib-sieve/plugins/include/cmd-include.c b/src/lib-sieve/plugins/include/cmd-include.c
index 730acf0b7..5dbb27ceb 100644
--- a/src/lib-sieve/plugins/include/cmd-include.c
+++ b/src/lib-sieve/plugins/include/cmd-include.c
@@ -76,6 +76,9 @@ const struct sieve_operation include_operation = {
 struct cmd_include_context_data {
 	enum ext_include_script_location location;
 	bool location_assigned;
+	
+	bool include_once;
+	
 	struct sieve_script *script;
 };   
 
@@ -101,6 +104,17 @@ static const struct sieve_argument include_global_tag = {
 	NULL, NULL 
 };
 
+static bool cmd_include_validate_once_tag
+	(struct sieve_validator *validator, struct sieve_ast_argument **arg, 
+		struct sieve_command_context *cmd);
+
+static const struct sieve_argument include_once_tag = { 
+	"once", 
+	NULL, NULL,
+	cmd_include_validate_once_tag, 
+	NULL, NULL 
+};
+
 /* 
  * Tag validation 
  */
@@ -134,6 +148,21 @@ static bool cmd_include_validate_location_tag
 	return TRUE;
 }
 
+static bool cmd_include_validate_once_tag
+(struct sieve_validator *validator ATTR_UNUSED, struct sieve_ast_argument **arg, 
+	struct sieve_command_context *cmd)
+{    
+	struct cmd_include_context_data *ctx_data = 
+		(struct cmd_include_context_data *) cmd->data;
+
+	ctx_data->include_once = TRUE;
+	
+	/* Delete this tag (for now) */
+	*arg = sieve_ast_arguments_detach(*arg, 1);
+
+	return TRUE;
+}
+
 /* 
  * Command registration 
  */
@@ -145,6 +174,8 @@ static bool cmd_include_registered
 		(validator, cmd_reg, &include_personal_tag, 0); 	
 	sieve_validator_register_tag
 		(validator, cmd_reg, &include_global_tag, 0); 	
+	sieve_validator_register_tag
+		(validator, cmd_reg, &include_once_tag, 0); 	
 
 	return TRUE;
 }
@@ -240,6 +271,7 @@ static bool cmd_include_generate
 	struct cmd_include_context_data *ctx_data = 
 		(struct cmd_include_context_data *) cmd->data;
 	const struct ext_include_script_info *included;
+	unsigned int flags = ctx_data->include_once;
 
 	/* Compile (if necessary) and include the script into the binary.
 	 * This yields the id of the binary block containing the compiled byte code.  
@@ -250,6 +282,7 @@ static bool cmd_include_generate
  		
  	(void)sieve_operation_emit_code(cgenv->sbin, &include_operation);
 	(void)sieve_binary_emit_unsigned(cgenv->sbin, included->id); 
+	(void)sieve_binary_emit_byte(cgenv->sbin, flags); 
  	 		
 	return TRUE;
 }
@@ -264,7 +297,7 @@ static bool opc_include_dump
 {
 	const struct ext_include_script_info *included;
 	struct ext_include_binary_context *binctx;
-	unsigned int include_id;
+	unsigned int include_id, flags;
 
 	sieve_code_dumpf(denv, "INCLUDE:");
 	
@@ -272,15 +305,19 @@ static bool opc_include_dump
 	if ( !sieve_binary_read_unsigned(denv->sbin, address, &include_id) )
 		return FALSE;
 
+	if ( !sieve_binary_read_byte(denv->sbin, address, &flags) )
+		return FALSE;
+
 	binctx = ext_include_binary_get_context(denv->sbin);
 	included = ext_include_binary_script_get_included(binctx, include_id);
 	if ( included == NULL )
 		return FALSE;
 		
 	sieve_code_descend(denv);
-	sieve_code_dumpf(denv, "script: %s [ID: %d, BLOCK: %d]", 
-		sieve_script_filename(included->script), include_id, included->block_id);
-	 
+	sieve_code_dumpf(denv, "script: %s %s[ID: %d, BLOCK: %d]", 
+		sieve_script_filename(included->script), (flags & 0x01 ? "(once) " : ""),
+		include_id, included->block_id);
+
 	return TRUE;
 }
 
@@ -292,14 +329,19 @@ static int opc_include_execute
 (const struct sieve_operation *op ATTR_UNUSED,
 	const struct sieve_runtime_env *renv, sieve_size_t *address)
 {
-	unsigned int include_id;
+	unsigned int include_id, flags;
 		
 	if ( !sieve_binary_read_unsigned(renv->sbin, address, &include_id) ) {
 		sieve_runtime_trace_error(renv, "invalid include-id operand");
 		return SIEVE_EXEC_BIN_CORRUPT;
 	}
+
+	if ( !sieve_binary_read_unsigned(renv->sbin, address, &flags) ) {
+		sieve_runtime_trace_error(renv, "invalid flags operand");
+		return SIEVE_EXEC_BIN_CORRUPT;
+	}
 	
-	return ext_include_execute_include(renv, include_id);
+	return ext_include_execute_include(renv, include_id, flags & 0x01);
 }
 
 
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
index 8486a4146..f6786253d 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.c
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -453,7 +453,7 @@ bool ext_include_generate_include
  */
 
 bool ext_include_execute_include
-	(const struct sieve_runtime_env *renv, unsigned int include_id)
+(const struct sieve_runtime_env *renv, unsigned int include_id, bool once)
 {
 	int result = TRUE;
 	struct ext_include_interpreter_context *ctx;
@@ -472,8 +472,8 @@ bool ext_include_execute_include
 	ctx = ext_include_get_interpreter_context(renv->interp);
 	block_id = included->block_id;
 
-	sieve_runtime_trace(renv, "INCLUDE command (id: %d, script: %s, block: %d)", 
-		include_id, sieve_script_name(included->script), block_id);
+	sieve_runtime_trace(renv, "INCLUDE command (script: %s, id: %d block: %d) START::", 
+		sieve_script_name(included->script), include_id, block_id);
 
 	if ( ctx->parent == NULL ) {
 		struct ext_include_interpreter_context *curctx = NULL;
@@ -514,11 +514,15 @@ bool ext_include_execute_include
 		 */
 		if ( result > 0 && interrupted && !curctx->returned ) {
 			while ( result > 0 ) {
+
 				if ( ( (interrupted && curctx->returned) || (!interrupted) ) && 
 					curctx->parent != NULL ) {
 					
 					/* Sub-interpreter ended or executed return */
 					
+					sieve_runtime_trace(renv, "INCLUDE command (block: %d) END ::", 
+						curctx->block_id);
+
 					/* Ascend interpreter stack */
 					curctx = curctx->parent;
 					sieve_interpreter_free(&subinterp);
@@ -534,6 +538,7 @@ bool ext_include_execute_include
 					/* Continue parent */
 					curctx->inc_block_id = 0;
 					curctx->returned = FALSE;
+
 					result = ( sieve_interpreter_continue(subinterp, &interrupted) == 1 );
 				} else {
 					if ( curctx->inc_block_id >= SBIN_SYSBLOCK_LAST ) {
@@ -577,8 +582,9 @@ bool ext_include_execute_include
 					}
 				}
 			}
-		}
-		
+		} else 
+			sieve_runtime_trace(renv, "INCLUDE command (block: %d) END ::", curctx->block_id);
+
 		/* Free any sub-interpreters that might still be active */
 		while ( curctx != NULL && curctx->parent != NULL ) {
 			struct ext_include_interpreter_context *nextctx	= curctx->parent;
diff --git a/src/lib-sieve/plugins/include/ext-include-common.h b/src/lib-sieve/plugins/include/ext-include-common.h
index 128fdd09c..5d2e8d84f 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.h
+++ b/src/lib-sieve/plugins/include/ext-include-common.h
@@ -101,7 +101,7 @@ bool ext_include_generate_include
 void ext_include_interpreter_context_init(struct sieve_interpreter *interp);
 
 bool ext_include_execute_include
-	(const struct sieve_runtime_env *renv, unsigned int block_id);
+	(const struct sieve_runtime_env *renv, unsigned int block_id, bool once);
 void ext_include_execute_return(const struct sieve_runtime_env *renv);
 
 struct sieve_variable_storage *ext_include_interpreter_get_global_variables
diff --git a/src/lib-sieve/sieve-binary-dumper.c b/src/lib-sieve/sieve-binary-dumper.c
index 7dd31a023..89a041a97 100644
--- a/src/lib-sieve/sieve-binary-dumper.c
+++ b/src/lib-sieve/sieve-binary-dumper.c
@@ -132,7 +132,7 @@ bool sieve_binary_dumper_run
 	
 	/* Dump main program */
 	
-	sieve_binary_dump_sectionf(denv, "Main program");
+	sieve_binary_dump_sectionf(denv, "Main program (block: %d)", SBIN_SYSBLOCK_MAIN_PROGRAM);
 
 	if ( !sieve_binary_block_set_active(sbin, SBIN_SYSBLOCK_MAIN_PROGRAM, NULL) ) {
         return FALSE;
diff --git a/tests/extensions/include/included/once-1.sieve b/tests/extensions/include/included/once-1.sieve
new file mode 100644
index 000000000..288d1412c
--- /dev/null
+++ b/tests/extensions/include/included/once-1.sieve
@@ -0,0 +1,9 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} ONE";
+
+return;
+
diff --git a/tests/extensions/include/included/once-2.sieve b/tests/extensions/include/included/once-2.sieve
new file mode 100644
index 000000000..226df6de3
--- /dev/null
+++ b/tests/extensions/include/included/once-2.sieve
@@ -0,0 +1,12 @@
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "${result} TWO";
+
+keep;
+
+include "once-1.sieve";
+
+return;
diff --git a/tests/extensions/include/once.svtest b/tests/extensions/include/once.svtest
new file mode 100644
index 000000000..1a08c8da4
--- /dev/null
+++ b/tests/extensions/include/once.svtest
@@ -0,0 +1,20 @@
+require "vnd.dovecot.testsuite";
+require "include";
+require "variables";
+
+global "result";
+
+set "result" "";
+
+test "Included Once" {
+	include "once-1";
+	include "once-2";
+
+	if string "${result}" " ONE TWO ONE" {
+		test_fail "duplicate included :once script";
+	}
+
+	if not string "${result}" " ONE TWO" {
+		test_fail "unexpected result value: ${result}";
+	}
+}
-- 
GitLab