From ea0e6b494daa8a52ebf05aff6cf63a2143fe4ab4 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Tue, 29 Jul 2008 11:30:15 +0200
Subject: [PATCH] Variables: resolved issues in the scope implementation.

---
 TODO                                          |  2 -
 .../plugins/include/ext-include-common.c      |  9 +++
 .../plugins/variables/ext-variables-common.c  | 60 ++++++++++++++++++-
 .../plugins/variables/sieve-ext-variables.h   |  5 ++
 4 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/TODO b/TODO
index 07a50b0ea..a42d94485 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,4 @@
 Next (in order of descending priority/precedence):
-* Resolve problems in variables extension: scope uses hash the wrong way.
-
 * Full standards compliance review for the engine and all fully implemented 
   sieve extensions. Issues discovered so far:
 	- :matches : match values must only be changed when the test 
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
index a987d9ae4..bb02e59c4 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.c
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -94,10 +94,16 @@ static void ext_include_ast_free
 	struct sieve_script **scripts;
 	unsigned int count, i;
 
+	/* Unreference included scripts */
 	scripts = array_get_modifiable(&actx->included_scripts, &count);
     for ( i = 0; i < count; i++ ) {
 		sieve_script_unref(&scripts[i]);
     }	
+
+	/* Unreference variable scopes */
+	sieve_variable_scope_unref(&actx->import_vars);
+	if ( actx->global_vars != NULL )
+		sieve_variable_scope_unref(&actx->global_vars);
 }
 
 static const struct sieve_ast_extension include_ast_extension = {
@@ -120,6 +126,9 @@ struct ext_include_ast_context *ext_include_create_ast_context
             (struct ext_include_ast_context *)
             sieve_ast_extension_get_context(parent, &include_extension);
         actx->global_vars = ( parent_ctx == NULL ? NULL : parent_ctx->global_vars );
+
+		if ( actx->global_vars != NULL )
+	        sieve_variable_scope_ref(actx->global_vars);
     }
 
 	sieve_ast_extension_register(ast, &include_ast_extension, (void *) actx);
diff --git a/src/lib-sieve/plugins/variables/ext-variables-common.c b/src/lib-sieve/plugins/variables/ext-variables-common.c
index 028b8e08f..1459f07e4 100644
--- a/src/lib-sieve/plugins/variables/ext-variables-common.c
+++ b/src/lib-sieve/plugins/variables/ext-variables-common.c
@@ -42,6 +42,8 @@ const unsigned int default_set_modifiers_count =
 
 struct sieve_variable_scope {
 	pool_t pool;
+	int refcount;
+
 	const struct sieve_extension *ext;
 
 	unsigned int next_index;
@@ -55,13 +57,31 @@ struct sieve_variable_scope *sieve_variable_scope_create
 	
 	scope = p_new(pool, struct sieve_variable_scope, 1);
 	scope->pool = pool;
+	scope->refcount = 1;
+
 	scope->ext = ext;
 	scope->variables = hash_create
-		(pool, pool, 0, strcase_hash, (hash_cmp_callback_t *)strcasecmp);
+		(default_pool, pool, 0, strcase_hash, (hash_cmp_callback_t *)strcasecmp);
 		
 	return scope;
 }
 
+void sieve_variable_scope_ref(struct sieve_variable_scope *scope)
+{
+    scope->refcount++;
+}
+
+void sieve_variable_scope_unref(struct sieve_variable_scope **scope)
+{
+    i_assert((*scope)->refcount > 0);
+
+    if (--(*scope)->refcount != 0)
+        return;
+
+	hash_destroy(&(*scope)->variables);
+    *scope = NULL;
+}
+
 struct sieve_variable *sieve_variable_scope_declare
 (struct sieve_variable_scope *scope, const char *identifier)
 {
@@ -159,7 +179,41 @@ void sieve_variable_assign
 	str_append_str(varval, value);
 }
 
-/* Validator context */
+/*
+ * AST Context
+ */
+
+static void ext_variables_ast_free
+(struct sieve_ast *ast ATTR_UNUSED, void *context)
+{
+	struct sieve_variable_scope *main_scope =
+		(struct sieve_variable_scope *) context;
+
+    /* Unreference main variable scope */
+    sieve_variable_scope_unref(&main_scope);
+}
+
+static const struct sieve_ast_extension variables_ast_extension = {
+    &variables_extension,
+    ext_variables_ast_free
+};
+
+static struct sieve_variable_scope *ext_variables_create_main_scope
+(struct sieve_ast *ast)
+{
+    struct sieve_variable_scope *scope;
+    pool_t pool = sieve_ast_pool(ast);
+
+	scope = sieve_variable_scope_create(pool, NULL);
+
+    sieve_ast_extension_register(ast, &variables_ast_extension, (void *) scope);
+
+    return scope;
+}
+
+/*
+ * Validator context 
+ */
 
 static struct ext_variables_validator_context *
 ext_variables_validator_context_create(struct sieve_validator *valdtr)
@@ -170,7 +224,7 @@ ext_variables_validator_context_create(struct sieve_validator *valdtr)
 	
 	ctx = p_new(pool, struct ext_variables_validator_context, 1);
 	ctx->modifiers = sieve_validator_object_registry_create(valdtr);
-	ctx->main_scope = sieve_variable_scope_create(sieve_ast_pool(ast), NULL);
+	ctx->main_scope = ext_variables_create_main_scope(ast);
 
 	sieve_validator_extension_set_context
 		(valdtr, &variables_extension, (void *) ctx);
diff --git a/src/lib-sieve/plugins/variables/sieve-ext-variables.h b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
index e554f410e..65068725b 100644
--- a/src/lib-sieve/plugins/variables/sieve-ext-variables.h
+++ b/src/lib-sieve/plugins/variables/sieve-ext-variables.h
@@ -23,6 +23,11 @@ struct sieve_variable_scope;
 
 struct sieve_variable_scope *sieve_variable_scope_create
 	(pool_t pool, const struct sieve_extension *ext);
+void sieve_variable_scope_ref
+	(struct sieve_variable_scope *scope);
+void sieve_variable_scope_unref
+	(struct sieve_variable_scope **scope);
+
 struct sieve_variable *sieve_variable_scope_declare
 	(struct sieve_variable_scope *scope, const char *identifier);
 struct sieve_variable *sieve_variable_scope_import
-- 
GitLab