From dd105ea5c7bd001472d4bded73b68963e42a0559 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sun, 6 Apr 2008 21:57:32 +0200
Subject: [PATCH] Include: merged import and export commands into a single
 implementation and implemented global variable storage.

---
 src/lib-sieve/plugins/include/Makefile.am     |  3 +-
 src/lib-sieve/plugins/include/cmd-export.c    | 94 -------------------
 src/lib-sieve/plugins/include/cmd-import.c    | 36 +++++--
 .../plugins/include/ext-include-common.c      |  5 +
 .../plugins/include/ext-include-variables.c   | 77 +++++++--------
 .../plugins/include/ext-include-variables.h   |  9 +-
 .../plugins/include/include-variables.sieve   |  6 ++
 .../plugins/include/include-variables1.sieve  |  5 +
 .../plugins/include/include-variables2.sieve  |  5 +
 .../plugins/include/include-variables3.sieve  | 11 +++
 src/lib-sieve/plugins/variables/cmd-set.c     |  3 +-
 .../plugins/variables/ext-variables-common.c  | 81 +++++++++++++---
 .../plugins/variables/ext-variables-common.h  |  2 +-
 .../variables/ext-variables-operands.c        | 64 ++++++++++---
 .../plugins/variables/ext-variables.c         |  4 -
 .../plugins/variables/sieve-ext-variables.h   | 23 ++++-
 16 files changed, 246 insertions(+), 182 deletions(-)
 delete mode 100644 src/lib-sieve/plugins/include/cmd-export.c
 create mode 100644 src/lib-sieve/plugins/include/include-variables3.sieve

diff --git a/src/lib-sieve/plugins/include/Makefile.am b/src/lib-sieve/plugins/include/Makefile.am
index 4a3e840ab..44236db11 100644
--- a/src/lib-sieve/plugins/include/Makefile.am
+++ b/src/lib-sieve/plugins/include/Makefile.am
@@ -11,8 +11,7 @@ AM_CPPFLAGS = \
 cmds = \
 	cmd-include.c \
 	cmd-return.c \
-	cmd-import.c \
-	cmd-export.c
+	cmd-import.c
 
 libsieve_ext_include_la_SOURCES = \
 	$(cmds) \
diff --git a/src/lib-sieve/plugins/include/cmd-export.c b/src/lib-sieve/plugins/include/cmd-export.c
deleted file mode 100644
index 6865f8c1d..000000000
--- a/src/lib-sieve/plugins/include/cmd-export.c
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "lib.h"
-
-#include "sieve-code.h"
-#include "sieve-commands.h"
-#include "sieve-commands-private.h"
-#include "sieve-validator.h" 
-#include "sieve-generator.h"
-#include "sieve-interpreter.h"
-#include "sieve-ext-variables.h"
-
-#include "ext-include-common.h"
-#include "ext-include-variables.h"
-
-/* Forward declarations */
-
-static bool cmd_export_validate
-  (struct sieve_validator *validator, struct sieve_command_context *cmd);
-		
-/* Export command 
- * 
- * Syntax
- *   export
- */	
-const struct sieve_command cmd_export = { 
-	"export", 
-	SCT_COMMAND, 
-	1, 0, FALSE, FALSE,
-	NULL, NULL, 
-	cmd_export_validate, 
-	NULL, NULL
-};
-
-/*
- * Validation
- */
-
-static bool cmd_export_validate
-  (struct sieve_validator *validator, struct sieve_command_context *cmd) 
-{
-	struct sieve_ast_argument *arg = cmd->first_positional;
-	struct sieve_command_context *prev_context = 
-		sieve_command_prev_context(cmd);
-		
-	/* Check valid command placement */
-	if ( !sieve_command_is_toplevel(cmd) ||
-		( !sieve_command_is_first(cmd) && prev_context != NULL &&
-			prev_context->command != &cmd_require && 
-			prev_context->command != &cmd_import &&
-			prev_context->command != &cmd_export) ) 
-	{	
-		sieve_command_validate_error(validator, cmd, 
-			"export commands can only be placed at top level "
-			"at the beginning of the file after any require or import commands");
-		return FALSE;
-	}
-	
-	if ( !sieve_ext_variables_is_active(validator) ) {
-		sieve_command_validate_error(validator, cmd, 
-			"export command requires that variables extension is active");
-		return FALSE;
-	}
-	
-	/* Register exported variable */
-	if ( sieve_ast_argument_type(arg) == SAAT_STRING ) {
-		/* Single string */
-		const char *variable = sieve_ast_argument_strc(arg);
-		
-		if ( !ext_include_variable_export(validator, cmd, variable) )			
-			return FALSE;
-
-	} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
-		/* String list */
-		struct sieve_ast_argument *stritem = sieve_ast_strlist_first(arg);
-		
-		while ( stritem != NULL ) {
-			const char *variable = sieve_ast_argument_strc(stritem);
-			
-			if ( !ext_include_variable_export(validator, cmd, variable) )
-				return FALSE;
-	
-			stritem = sieve_ast_strlist_next(stritem);
-		}
-	} else {
-		/* Something else */
-		sieve_command_validate_error(validator, cmd, 
-			"the export command accepts a single string or string list argument, "
-			"but %s was found", 
-			sieve_ast_argument_name(arg));
-		return FALSE;
-	}
-	
-	(void)sieve_ast_arguments_detach(arg, 1);
-	return TRUE;
-}
diff --git a/src/lib-sieve/plugins/include/cmd-import.c b/src/lib-sieve/plugins/include/cmd-import.c
index 0e7c5823d..9c2afe089 100644
--- a/src/lib-sieve/plugins/include/cmd-import.c
+++ b/src/lib-sieve/plugins/include/cmd-import.c
@@ -30,6 +30,20 @@ const struct sieve_command cmd_import = {
 	NULL, NULL
 };
 
+/* Export command 
+ * 
+ * Syntax
+ *   export
+ */	
+const struct sieve_command cmd_export = { 
+	"export", 
+	SCT_COMMAND, 
+	1, 0, FALSE, FALSE,
+	NULL, NULL, 
+	cmd_import_validate, 
+	NULL, NULL
+};
+
 /*
  * Validation
  */
@@ -45,17 +59,21 @@ static bool cmd_import_validate
 	if ( !sieve_command_is_toplevel(cmd) ||
 		( !sieve_command_is_first(cmd) && prev_context != NULL &&
 			prev_context->command != &cmd_require && 
-			prev_context->command != &cmd_import) ) 
+			prev_context->command != &cmd_import &&
+			(cmd->command != &cmd_export || prev_context->command != &cmd_export) ) ) 
 	{	
 		sieve_command_validate_error(validator, cmd, 
-			"import commands can only be placed at top level "
-			"at the beginning of the file after any require commands");
+			"%s commands can only be placed at top level "
+			"at the beginning of the file after any require %scommands",
+			cmd->command->identifier, cmd->command == &cmd_export ? "or import " : "");
 		return FALSE;
 	}
+
 	
 	if ( !sieve_ext_variables_is_active(validator) ) {
 		sieve_command_validate_error(validator, cmd, 
-			"import command requires that variables extension is active");
+			"%s command requires that variables extension is active",
+			cmd->command->identifier);
 		return FALSE;
 	}
 		
@@ -64,7 +82,8 @@ static bool cmd_import_validate
 		/* Single string */
 		const char *variable = sieve_ast_argument_strc(arg);
 		
-		if ( !ext_include_variable_import(validator, cmd, variable) )
+		if ( !ext_include_variable_import_global
+			(validator, cmd, variable, cmd->command == &cmd_export) )
 			return FALSE;
 
 	} else if ( sieve_ast_argument_type(arg) == SAAT_STRING_LIST ) {
@@ -74,7 +93,8 @@ static bool cmd_import_validate
 		while ( stritem != NULL ) {
 			const char *variable = sieve_ast_argument_strc(stritem);
 			
-			if ( !ext_include_variable_import(validator, cmd, variable) )
+			if ( !ext_include_variable_import_global
+				(validator, cmd, variable, cmd->command == &cmd_export) )
 				return FALSE;
 	
 			stritem = sieve_ast_strlist_next(stritem);
@@ -82,8 +102,8 @@ static bool cmd_import_validate
 	} else {
 		/* Something else */
 		sieve_command_validate_error(validator, cmd, 
-			"the import command accepts a single string or string list argument, "
-			"but %s was found", 
+			"the %s command accepts a single string or string list argument, "
+			"but %s was found", cmd->command->identifier,
 			sieve_ast_argument_name(arg));
 		return FALSE;
 	}
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
index d54c8dff4..57fdc1ab9 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.c
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -306,6 +306,7 @@ bool ext_include_execute_include
 		struct sieve_error_handler *ehandler = 
 			sieve_interpreter_get_error_handler(renv->interp);
 		struct sieve_interpreter *subinterp;
+		struct sieve_variable_storage *varstrg;
 		unsigned int this_block_id;
 		bool interrupted = FALSE;	
 
@@ -316,6 +317,10 @@ bool ext_include_execute_include
 		subinterp = sieve_interpreter_create(renv->sbin, ehandler);			
 		curctx = ext_include_initialize_interpreter_context
 			(subinterp, ctx, NULL, block_id);
+			
+		/* Create variable storage for global variables */
+		varstrg = sieve_ext_variables_get_storage(renv->interp, ext_include_my_id);
+		sieve_ext_variables_set_storage(subinterp, varstrg, ext_include_my_id);
 	
 		/* Activate and start the top-level included script */
 		if ( sieve_binary_block_set_active(renv->sbin, block_id, &this_block_id) ) 			
diff --git a/src/lib-sieve/plugins/include/ext-include-variables.c b/src/lib-sieve/plugins/include/ext-include-variables.c
index e01275950..59f66279a 100644
--- a/src/lib-sieve/plugins/include/ext-include-variables.c
+++ b/src/lib-sieve/plugins/include/ext-include-variables.c
@@ -31,7 +31,7 @@ struct ext_include_ast_context *ext_include_create_ast_context
 
 	pool_t pool = sieve_ast_pool(ast);
 	ctx = p_new(pool, struct ext_include_ast_context, 1);
-	ctx->import_vars = sieve_variable_scope_create(pool);
+	ctx->import_vars = sieve_variable_scope_create(pool, ext_include_my_id);
 	
 	if ( parent != NULL ) {
 		struct ext_include_ast_context *parent_ctx = 
@@ -62,50 +62,51 @@ static inline struct ext_include_ast_context *
  * Variable import-export
  */
  
-bool ext_include_variable_import
+bool ext_include_variable_import_global
 (struct sieve_validator *valdtr, struct sieve_command_context *cmd, 
-	const char *variable)
-{
-	struct ext_include_ast_context *ctx = 
-		ext_include_get_ast_context(cmd->ast_node->ast);
-	
-	if ( ctx->global_vars == NULL || 
-		sieve_variable_scope_get_variable(ctx->global_vars, variable, FALSE)
-		== NULL ) 
-	{
-		sieve_command_validate_error(valdtr, cmd, 
-			"importing unknown global variable '%s'", variable);
-		return FALSE;
-	}
-	
-	printf("VAR IMPORT: %s\n", variable);
-	(void)sieve_variable_scope_declare(ctx->import_vars, variable);
-	
-	return TRUE;
-}
-
-bool ext_include_variable_export
-(struct sieve_validator *valdtr, struct sieve_command_context *cmd, 
-	const char *variable)
+	const char *variable, bool export)
 {
 	struct sieve_ast *ast = cmd->ast_node->ast;
 	struct ext_include_ast_context *ctx = ext_include_get_ast_context(ast);
+	struct sieve_variable_scope *main_scope;
+	struct sieve_variable *var;
+
+	if ( export ) {	
+		if ( sieve_variable_scope_get_variable(ctx->import_vars, variable, FALSE) 
+			!= NULL ) {
+			sieve_command_validate_error(valdtr, cmd, 
+				"cannot export imported variable '%s'", variable);
+			return FALSE;
+		}
 	
-	if ( sieve_variable_scope_get_variable(ctx->import_vars, variable, FALSE) 
-		!= NULL ) {
-		sieve_command_validate_error(valdtr, cmd, 
-					"cannot export imported variable '%s'", variable);
-		return FALSE;
-	}
-	
-	if ( ctx->global_vars == NULL ) {
-		pool_t pool = sieve_ast_pool(ast);
-		ctx->global_vars = sieve_variable_scope_create(pool);
-	}
+		if ( ctx->global_vars == NULL ) {
+			pool_t pool = sieve_ast_pool(ast);
+			ctx->global_vars = sieve_variable_scope_create(pool, ext_include_my_id);
+		}
+		
+		printf("VAR EXPORT: %s\n", variable);
+		var = sieve_variable_scope_get_variable(ctx->global_vars, variable, TRUE);
 		
-	printf("VAR EXPORT: %s\n", variable);
+	} else {
+		var = NULL;
 		
-	(void)sieve_variable_scope_declare(ctx->global_vars, variable);
+		if ( ctx->global_vars != NULL ) {
+			var = sieve_variable_scope_get_variable
+				(ctx->global_vars, variable, FALSE);
+		}
+	
+		if ( var == NULL ) {
+			sieve_command_validate_error(valdtr, cmd, 
+				"importing unknown global variable '%s'", variable);
+			return FALSE;
+		}
+		
+		printf("VAR IMPORT: %s\n", variable);
+		(void)sieve_variable_scope_declare(ctx->import_vars, variable);
+	}
+
+	main_scope = sieve_ext_variables_get_main_scope(valdtr);
+	(void)sieve_variable_scope_import(main_scope, var);
 	return TRUE;	
 }
 
diff --git a/src/lib-sieve/plugins/include/ext-include-variables.h b/src/lib-sieve/plugins/include/ext-include-variables.h
index 0fefff051..e5aea5d86 100644
--- a/src/lib-sieve/plugins/include/ext-include-variables.h
+++ b/src/lib-sieve/plugins/include/ext-include-variables.h
@@ -2,6 +2,8 @@
 #define __EXT_INCLUDE_VARIABLES_H
 
 #include "sieve-common.h"
+#include "sieve-ext-variables.h"
+
 #include "ext-include-common.h"
 
 /* 
@@ -15,12 +17,9 @@ struct ext_include_ast_context *ext_include_create_ast_context
  * Variable import-export
  */
  
-bool ext_include_variable_import
-	(struct sieve_validator *valdtr, struct sieve_command_context *cmd, 
-		const char *variable);
-bool ext_include_variable_export
+bool ext_include_variable_import_global
 	(struct sieve_validator *valdtr, struct sieve_command_context *cmd, 
-		const char *variable);
+		const char *variable, bool export);
 		
 #endif /* __EXT_INCLUDE_VARIABLES_H */
 
diff --git a/src/lib-sieve/plugins/include/include-variables.sieve b/src/lib-sieve/plugins/include/include-variables.sieve
index 996c81aa6..fe655633f 100644
--- a/src/lib-sieve/plugins/include/include-variables.sieve
+++ b/src/lib-sieve/plugins/include/include-variables.sieve
@@ -1,8 +1,11 @@
 require "include";
 require "variables";
+require "fileinto";
 
 export ["value1", "value2"];
 export ["value3", "value4"];
+export ["result1", "result2"];
+export "result";
 
 set "value1" "Works";
 set "value2" "fine.";
@@ -11,3 +14,6 @@ set "value4" "it does.";
 
 include "include-variables1";
 include "include-variables2";
+include "include-variables3";
+
+fileinto "${result}";
diff --git a/src/lib-sieve/plugins/include/include-variables1.sieve b/src/lib-sieve/plugins/include/include-variables1.sieve
index ec4cd8885..91dab0b04 100644
--- a/src/lib-sieve/plugins/include/include-variables1.sieve
+++ b/src/lib-sieve/plugins/include/include-variables1.sieve
@@ -3,5 +3,10 @@ require "variables";
 require "fileinto";
 
 import ["value1", "value2"];
+export ["result1"];
 
 fileinto "${value1} ${value2}";
+
+set "result1" "${value1} ${value2}";
+
+fileinto "RESULT: ${result1}";
diff --git a/src/lib-sieve/plugins/include/include-variables2.sieve b/src/lib-sieve/plugins/include/include-variables2.sieve
index 1736dbd78..681c39749 100644
--- a/src/lib-sieve/plugins/include/include-variables2.sieve
+++ b/src/lib-sieve/plugins/include/include-variables2.sieve
@@ -4,5 +4,10 @@ require "fileinto";
 
 import "value3";
 import "value4";
+export "result2";
 
 fileinto "${value3} ${value4}";
+
+set "result2" "${value3} ${value4}";
+
+fileinto "RESULT: ${result2}";
diff --git a/src/lib-sieve/plugins/include/include-variables3.sieve b/src/lib-sieve/plugins/include/include-variables3.sieve
new file mode 100644
index 000000000..c7625bc59
--- /dev/null
+++ b/src/lib-sieve/plugins/include/include-variables3.sieve
@@ -0,0 +1,11 @@
+require "include";
+require "variables";
+require "fileinto";
+
+import "result1";
+import "result2";
+export "result";
+
+set "result" "${result1} ${result2}";
+
+fileinto "RESULT: ${result}";
diff --git a/src/lib-sieve/plugins/variables/cmd-set.c b/src/lib-sieve/plugins/variables/cmd-set.c
index 69d49d7e4..e4180228b 100644
--- a/src/lib-sieve/plugins/variables/cmd-set.c
+++ b/src/lib-sieve/plugins/variables/cmd-set.c
@@ -353,7 +353,8 @@ static bool cmd_set_operation_execute
 	printf(">> SET\n");
 	
 	/* Read the variable identifier */
-	if ( !ext_variables_opr_variable_read(renv, address, &storage, &var_index) )
+	if ( !ext_variables_opr_variable_read
+		(renv, address, &storage, &var_index) )
 		return FALSE;	
 		
 	/* Read the raw string value */
diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.c b/src/lib-sieve/plugins/variables/ext-variables-common.c
index 95c9beb53..96abf265c 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-common.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-common.c
@@ -61,18 +61,20 @@ void sieve_variables_extension_set
 
 struct sieve_variable_scope {
 	pool_t pool;
-  const char *identifier;
+  int ext_id;
 
 	unsigned int next_index;
 	struct hash_table *variables;
 };
 
-struct sieve_variable_scope *sieve_variable_scope_create(pool_t pool) 
+struct sieve_variable_scope *sieve_variable_scope_create
+	(pool_t pool, int ext_id) 
 {
 	struct sieve_variable_scope *scope;
 	
 	scope = p_new(pool, struct sieve_variable_scope, 1);
 	scope->pool = pool;
+	scope->ext_id = ext_id;
 	scope->variables = hash_create
 		(pool, pool, 0, strcase_hash, (hash_cmp_callback_t *)strcasecmp);
 		
@@ -82,13 +84,14 @@ struct sieve_variable_scope *sieve_variable_scope_create(pool_t pool)
 struct sieve_variable *sieve_variable_scope_declare
 (struct sieve_variable_scope *scope, const char *identifier)
 {
-	struct sieve_variable *var = p_new(scope->pool, struct sieve_variable, 1);
-	var->identifier = identifier;
-	var->index = scope->next_index++;
+	struct sieve_variable *new_var = p_new(scope->pool, struct sieve_variable, 1);
+	new_var->identifier = identifier;
+	new_var->index = scope->next_index++;
+	new_var->ext_id = scope->ext_id;
 		
-	hash_insert(scope->variables, (void *) identifier, (void *) var);
+	hash_insert(scope->variables, (void *) identifier, (void *) new_var);
 	
-	return var;
+	return new_var;
 }
 
 struct sieve_variable *sieve_variable_scope_get_variable
@@ -103,6 +106,17 @@ struct sieve_variable *sieve_variable_scope_get_variable
 	return var;
 }
 
+struct sieve_variable *sieve_variable_scope_import
+(struct sieve_variable_scope *scope, struct sieve_variable *var)
+{
+	struct sieve_variable *new_var = p_new(scope->pool, struct sieve_variable, 1);
+	memcpy(new_var, var, sizeof(struct sieve_variable));
+		
+	hash_insert(scope->variables, (void *) new_var->identifier, (void *) new_var);
+	
+	return new_var;
+}
+
 /* Variable storage */
 
 struct sieve_variable_storage {
@@ -172,7 +186,7 @@ ext_variables_validator_context_create(struct sieve_validator *validator)
 	ctx = p_new(pool, struct ext_variables_validator_context, 1);
 	ctx->set_modifiers = hash_create
 		(pool, pool, 0, str_hash, (hash_cmp_callback_t *)strcmp);
-	ctx->main_scope = sieve_variable_scope_create(sieve_ast_pool(ast));
+	ctx->main_scope = sieve_variable_scope_create(sieve_ast_pool(ast), -1);
 
 	sieve_validator_extension_set_context
 		(validator, ext_variables_my_id, (void *) ctx);
@@ -211,6 +225,15 @@ struct sieve_variable *ext_variables_validator_get_variable
 	return sieve_variable_scope_get_variable(ctx->main_scope, variable, declare);
 }
 
+struct sieve_variable_scope *sieve_ext_variables_get_main_scope
+(struct sieve_validator *validator)
+{
+	struct ext_variables_validator_context *ctx = 
+		ext_variables_validator_context_get(validator);
+		
+	return ctx->main_scope;
+}
+
 bool sieve_ext_variables_is_active(struct sieve_validator *valdtr)
 {
 	return ( ext_variables_validator_context_get(valdtr) != NULL );
@@ -220,6 +243,7 @@ bool sieve_ext_variables_is_active(struct sieve_validator *valdtr)
 
 struct ext_variables_interpreter_context {
 	struct sieve_variable_storage *local_storage;
+	ARRAY_DEFINE(ext_storages, struct sieve_variable_storage *);
 };
 
 static struct ext_variables_interpreter_context *
@@ -230,6 +254,7 @@ ext_variables_interpreter_context_create(struct sieve_interpreter *interp)
 	
 	ctx = p_new(pool, struct ext_variables_interpreter_context, 1);
 	ctx->local_storage = sieve_variable_storage_create(pool);
+	p_array_init(&ctx->ext_storages, pool, sieve_extensions_get_count());
 
 	sieve_interpreter_extension_set_context
 		(interp, ext_variables_my_id, (void *) ctx);
@@ -255,13 +280,45 @@ ext_variables_interpreter_context_get(struct sieve_interpreter *interp)
 		sieve_interpreter_extension_get_context(interp, ext_variables_my_id);
 }
 
-struct sieve_variable_storage *ext_variables_interpreter_get_storage
-	(struct sieve_interpreter *interp)
+struct sieve_variable_storage *sieve_ext_variables_get_storage
+	(struct sieve_interpreter *interp, int ext_id)
 {
 	struct ext_variables_interpreter_context *ctx = 
 		ext_variables_interpreter_context_get(interp);
+	struct sieve_variable_storage * const *storage;
 		
-	return ctx->local_storage;
+	if ( ext_id < 0 )
+		return ctx->local_storage;
+
+	if ( ext_id >= (int) array_count(&ctx->ext_storages) ) {
+		storage = NULL;
+	} else {
+		storage = array_idx(&ctx->ext_storages, ext_id);
+	}
+	
+	if ( storage == NULL || *storage == NULL ) {
+		pool_t pool = sieve_interpreter_pool(interp);
+		struct sieve_variable_storage *strg = sieve_variable_storage_create(pool);
+		
+		array_idx_set(&ctx->ext_storages, (unsigned int) ext_id, &strg);
+		
+		return strg;		
+	}
+	
+	return *storage;
+}
+
+void sieve_ext_variables_set_storage
+(struct sieve_interpreter *interp, struct sieve_variable_storage *storage,
+	int ext_id)
+{
+	struct ext_variables_interpreter_context *ctx = 
+		ext_variables_interpreter_context_get(interp);
+		
+	if ( ext_id < 0 || storage == NULL )
+		return;
+		
+	array_idx_set(&ctx->ext_storages, (unsigned int) ext_id, &storage);
 }
 
 /* Set modifier registration */
@@ -276,6 +333,4 @@ const struct ext_variables_set_modifier *ext_variables_set_modifier_find
 		hash_lookup(ctx->set_modifiers, identifier);
 }
 
-/* Interpreter context */
-
 
diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.h b/src/lib-sieve/plugins/variables/ext-variables-common.h
index dd8e42181..1579f0594 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-common.h
+++ b/src/lib-sieve/plugins/variables/ext-variables-common.h
@@ -71,7 +71,7 @@ struct sieve_variable *ext_variables_validator_get_variable
 (struct sieve_validator *validator, const char *variable, bool declare);
 
 struct sieve_variable_storage *ext_variables_interpreter_get_storage
-	(struct sieve_interpreter *interp);
+	(struct sieve_interpreter *interp, unsigned int ext_id);
 	
 /* Extensions */
 
diff --git a/src/lib-sieve/plugins/variables/ext-variables-operands.c b/src/lib-sieve/plugins/variables/ext-variables-operands.c
index efdf06def..31a2e6446 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-operands.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-operands.c
@@ -39,42 +39,72 @@ const struct sieve_operand variable_operand = {
 	EXT_VARIABLES_OPERAND_VARIABLE,
 	&string_class,
 	&variable_interface
-};	
+};
 
 void ext_variables_opr_variable_emit
 	(struct sieve_binary *sbin, struct sieve_variable *var) 
 {
+	if ( var->ext_id < 0 ) {
+		/* Default variable storage */
+		(void) sieve_operand_emit_code(sbin, &variable_operand, ext_variables_my_id);
+		(void) sieve_binary_emit_byte(sbin, 0);
+		(void) sieve_binary_emit_integer(sbin, var->index);
+		return;
+	} 
+	
 	(void) sieve_operand_emit_code(sbin, &variable_operand, ext_variables_my_id);
+	(void) sieve_binary_emit_byte(sbin, 1 +	var->ext_id);
 	(void) sieve_binary_emit_integer(sbin, var->index);
 }
 
 static bool opr_variable_dump
 	(const struct sieve_dumptime_env *denv, sieve_size_t *address) 
 {
+	unsigned int code;
+	int ext_id;
 	sieve_size_t index = 0;
+	const struct sieve_extension *ext = NULL;
 	
-	if (sieve_binary_read_integer(denv->sbin, address, &index) ) {
-		sieve_code_dumpf(denv, "VAR: %ld", (long) index);
-
-		return TRUE;
+	if ( !sieve_binary_read_byte(denv->sbin, address, &code) ) {
+		return FALSE;
+	} 
+	ext_id = code - 1;
+	
+	if ( ext_id >= 0 && (ext = sieve_extension_get_by_id(ext_id)) == NULL ) {
+		return FALSE;
 	}
 	
-	return FALSE;
+	if ( !sieve_binary_read_integer(denv->sbin, address, &index) ) {
+		return FALSE;
+	}
+		
+	if ( ext == NULL )
+		sieve_code_dumpf(denv, "VAR: %ld", (long) index);
+	else
+		sieve_code_dumpf(denv, "VAR: [%d:%s] %ld", ext_id, ext->name, (long) index);
+	return TRUE;
 }
 
 static bool opr_variable_read_value
   (const struct sieve_runtime_env *renv, sieve_size_t *address, string_t **str)
 { 
+	unsigned int code;
+	int ext_id;
 	struct sieve_variable_storage *storage;
 	sieve_size_t index = 0;
 	
-	storage = ext_variables_interpreter_get_storage(renv->interp);
+	if ( !sieve_binary_read_byte(renv->sbin, address, &code) ) {
+		return FALSE;
+	}
+	ext_id = code - 1;
+	
+	storage = sieve_ext_variables_get_storage(renv->interp, ext_id);
 	if ( storage == NULL ) return FALSE;
-		
+	
 	if (sieve_binary_read_integer(renv->sbin, address, &index) ) {
 		/* Parameter str can be NULL if we are requested to only skip and not 
 		 * actually read the argument.
-	 	*/
+		 */
 		if ( str != NULL ) {
 			sieve_variable_get(storage, index, str);
 		
@@ -87,20 +117,28 @@ static bool opr_variable_read_value
 }
 
 bool ext_variables_opr_variable_read
-	(const struct sieve_runtime_env *renv, sieve_size_t *address, 
-		struct sieve_variable_storage **storage, unsigned int *var_index)
+(const struct sieve_runtime_env *renv, sieve_size_t *address, 
+	struct sieve_variable_storage **storage, unsigned int *var_index)
 {
+	unsigned int code;
+	int ext_id;
 	const struct sieve_operand *operand = sieve_operand_read(renv->sbin, address);
 	sieve_size_t idx = 0;
 	
 	if ( operand != &variable_operand ) 
 		return FALSE;
 		
-	*storage = ext_variables_interpreter_get_storage(renv->interp);
-	if ( *storage == NULL ) return FALSE;
+	if ( !sieve_binary_read_byte(renv->sbin, address, &code) ) {
+		return FALSE;
+	}
+	ext_id = code - 1;
+		
+	*storage = sieve_ext_variables_get_storage(renv->interp, ext_id);
+	if ( *storage == NULL )	return FALSE;
 	
 	if (sieve_binary_read_integer(renv->sbin, address, &idx) ) {
 		*var_index = idx;
+		
 		return TRUE;
 	}
 	
diff --git a/src/lib-sieve/plugins/variables/ext-variables.c b/src/lib-sieve/plugins/variables/ext-variables.c
index e66c9bc0e..a2b273f88 100644
--- a/src/lib-sieve/plugins/variables/ext-variables.c
+++ b/src/lib-sieve/plugins/variables/ext-variables.c
@@ -55,10 +55,6 @@ const struct sieve_operation *ext_variables_operations[] = {
 
 /* Operands */
 
-extern const struct sieve_operand variable_operand;
-extern const struct sieve_operand match_value_operand;
-extern const struct sieve_operand variable_string_operand;
-
 const struct sieve_operand *ext_variables_operands[] = {
 	&variable_operand, 
 	&match_value_operand,
diff --git a/src/lib-sieve/plugins/variables/sieve-ext-variables.h b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
index d2f025d5a..f7607501e 100644
--- a/src/lib-sieve/plugins/variables/sieve-ext-variables.h
+++ b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
@@ -8,8 +8,6 @@
 #include "sieve-common.h"
 #include "sieve-extensions.h"
 
-bool sieve_ext_variables_is_active(struct sieve_validator *valdtr);
-
 /*
  * Variable scope
  */
@@ -17,13 +15,17 @@ bool sieve_ext_variables_is_active(struct sieve_validator *valdtr);
 struct sieve_variable {
 	const char *identifier;
 	unsigned int index;
+	int ext_id;
 };
 
 struct sieve_variable_scope;
 
-struct sieve_variable_scope *sieve_variable_scope_create(pool_t pool);
+struct sieve_variable_scope *sieve_variable_scope_create
+	(pool_t pool, int ext_id);
 struct sieve_variable *sieve_variable_scope_declare
 	(struct sieve_variable_scope *scope, const char *identifier);
+struct sieve_variable *sieve_variable_scope_import
+	(struct sieve_variable_scope *scope, struct sieve_variable *var);
 struct sieve_variable *sieve_variable_scope_get_variable
 	(struct sieve_variable_scope *scope, const char *identifier, bool create);
 	
@@ -58,4 +60,19 @@ void sieve_variables_extension_set
 	(struct sieve_binary *sbin, int ext_id,
 		const struct sieve_variables_extension *ext);
 
+/*
+ * Variables access
+ */
+
+bool sieve_ext_variables_is_active(struct sieve_validator *valdtr);
+
+struct sieve_variable_scope *sieve_ext_variables_get_main_scope
+	(struct sieve_validator *validator);
+	
+struct sieve_variable_storage *sieve_ext_variables_get_storage
+	(struct sieve_interpreter *interp, int ext_id);
+void sieve_ext_variables_set_storage
+	(struct sieve_interpreter *interp, struct sieve_variable_storage *storage,
+		int ext_id);	
+	
 #endif /* __SIEVE_EXT_VARIABLES_H */
-- 
GitLab