From 3b694edd46a5b74e8c8e0e5853691257615a559f Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Mon, 14 Jul 2008 12:19:21 +0200
Subject: [PATCH] Added support for implicit side effects and adjusted
 imapflags extension accordingly.

---
 src/lib-sieve/Makefile.am                     |   2 +
 src/lib-sieve/cmd-discard.c                   |   6 +-
 src/lib-sieve/cmd-redirect.c                  |  10 +-
 src/lib-sieve/ext-reject.c                    |   6 +-
 src/lib-sieve/plugins/body/ext-body-common.c  |   1 +
 src/lib-sieve/plugins/copy/ext-copy.c         |  17 +--
 .../plugins/imapflags/ext-imapflags-common.c  |  64 +++++----
 .../plugins/imapflags/ext-imapflags-common.h  |   8 ++
 .../plugins/imapflags/ext-imapflags.c         |  29 +++--
 src/lib-sieve/plugins/imapflags/tag-flags.c   | 102 ++++-----------
 .../plugins/include/ext-include-common.c      |  11 +-
 .../plugins/include/ext-include-common.h      |   2 +-
 src/lib-sieve/plugins/include/ext-include.c   |   9 +-
 src/lib-sieve/plugins/include/include.sieve   |   1 +
 src/lib-sieve/plugins/vacation/cmd-vacation.c |   7 +-
 .../plugins/variables/ext-variables.c         |  11 +-
 src/lib-sieve/sieve-actions.c                 |  15 +--
 src/lib-sieve/sieve-actions.h                 |   5 +-
 src/lib-sieve/sieve-common.h                  |   3 +
 src/lib-sieve/sieve-extensions.c              |   2 +-
 src/lib-sieve/sieve-extensions.h              |   2 +-
 src/lib-sieve/sieve-interpreter.c             | 110 ++++------------
 src/lib-sieve/sieve-interpreter.h             |  11 --
 src/lib-sieve/sieve-message.c                 |  75 +++++++++++
 src/lib-sieve/sieve-message.h                 |  19 +++
 src/lib-sieve/sieve-result.c                  | 122 +++++++++++++++++-
 src/lib-sieve/sieve-result.h                  |   9 ++
 27 files changed, 389 insertions(+), 270 deletions(-)
 create mode 100644 src/lib-sieve/sieve-message.c
 create mode 100644 src/lib-sieve/sieve-message.h

diff --git a/src/lib-sieve/Makefile.am b/src/lib-sieve/Makefile.am
index a15a5cdc1..8323ccee3 100644
--- a/src/lib-sieve/Makefile.am
+++ b/src/lib-sieve/Makefile.am
@@ -52,6 +52,7 @@ libsieve_la_DEPENDENCIES = $(plugins)
 libsieve_la_LIBADD = $(plugins)
 
 libsieve_la_SOURCES = \
+	sieve-message.c \
 	sieve-lexer.c \
 	sieve-script.c \
 	sieve-ast.c \
@@ -79,6 +80,7 @@ libsieve_la_SOURCES = \
 	sieve.c 
 
 noinst_HEADERS = \
+	sieve-message.h \
 	sieve-lexer.h \
 	sieve-script.h \
 	sieve-script-private.h \
diff --git a/src/lib-sieve/cmd-discard.c b/src/lib-sieve/cmd-discard.c
index feff4843a..42af9c156 100644
--- a/src/lib-sieve/cmd-discard.c
+++ b/src/lib-sieve/cmd-discard.c
@@ -46,7 +46,8 @@ const struct sieve_operation cmd_discard_operation = {
 /* discard action */
 
 static void act_discard_print
-	(const struct sieve_action *action, void *context, bool *keep);	
+	(const struct sieve_action *action, struct sieve_result *result,
+		void *context, bool *keep);	
 static bool act_discard_commit
 (const struct sieve_action *action, 
 	const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep);
@@ -94,7 +95,8 @@ static bool cmd_discard_operation_execute
  */
  
 static void act_discard_print
-(const struct sieve_action *action ATTR_UNUSED, void *context ATTR_UNUSED, 
+(const struct sieve_action *action ATTR_UNUSED, 
+	struct sieve_result *result ATTR_UNUSED, void *context ATTR_UNUSED, 
 	bool *keep)	
 {
 	printf("* discard\n");
diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index ce228c0d7..342bb87a4 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -67,10 +67,11 @@ static int act_redirect_check_duplicate
 	(const struct sieve_runtime_env *renv,
 		const struct sieve_action *action1, void *context1, void *context2);
 static void act_redirect_print
-	(const struct sieve_action *action, void *context, bool *keep);	
+	(const struct sieve_action *action, struct sieve_result *result,
+		void *context, bool *keep);	
 static bool act_redirect_commit
-(const struct sieve_action *action ATTR_UNUSED, 
-	const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep);
+	(const struct sieve_action *action ATTR_UNUSED, 
+		const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep);
 		
 struct act_redirect_context {
 	const char *to_address;
@@ -208,7 +209,8 @@ static int act_redirect_check_duplicate
 }
 
 static void act_redirect_print
-(const struct sieve_action *action ATTR_UNUSED, void *context, bool *keep)	
+(const struct sieve_action *action ATTR_UNUSED, 
+	struct sieve_result *result ATTR_UNUSED, void *context, bool *keep)	
 {
 	struct act_redirect_context *ctx = (struct act_redirect_context *) context;
 	
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index 69497e52e..f64c992fe 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -99,7 +99,8 @@ int act_reject_check_conflict
 	(const struct sieve_runtime_env *renv, const struct sieve_action *action,
     	const struct sieve_action *other_action, void *context);
 static void act_reject_print
-	(const struct sieve_action *action, void *context, bool *keep);	
+	(const struct sieve_action *action, struct sieve_result *result,
+		void *context, bool *keep);	
 static bool act_reject_commit
 	(const struct sieve_action *action ATTR_UNUSED, 
 		const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep);
@@ -254,7 +255,8 @@ int act_reject_check_conflict
 }
  
 static void act_reject_print
-(const struct sieve_action *action ATTR_UNUSED, void *context, bool *keep)	
+(const struct sieve_action *action ATTR_UNUSED, 
+	struct sieve_result *result ATTR_UNUSED, void *context, bool *keep)	
 {
 	struct act_reject_context *ctx = (struct act_reject_context *) context;
 	
diff --git a/src/lib-sieve/plugins/body/ext-body-common.c b/src/lib-sieve/plugins/body/ext-body-common.c
index 38505a3ff..ff1690834 100644
--- a/src/lib-sieve/plugins/body/ext-body-common.c
+++ b/src/lib-sieve/plugins/body/ext-body-common.c
@@ -10,6 +10,7 @@
 #include "message-decoder.h"
 
 #include "sieve-common.h"
+#include "sieve-message.h"
 #include "sieve-interpreter.h"
 
 #include "ext-body-common.h"
diff --git a/src/lib-sieve/plugins/copy/ext-copy.c b/src/lib-sieve/plugins/copy/ext-copy.c
index 1122462dd..ce4faa81b 100644
--- a/src/lib-sieve/plugins/copy/ext-copy.c
+++ b/src/lib-sieve/plugins/copy/ext-copy.c
@@ -55,12 +55,12 @@ static bool ext_copy_load(int ext_id)
 const struct sieve_side_effect_extension ext_copy_side_effect;
 
 static void seff_copy_print
-	(const struct sieve_side_effect *seffect,	const struct sieve_action *action, 
-		void *se_context, bool *keep);
+	(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
+		struct sieve_result *result, void *se_context, bool *keep);
 static bool seff_copy_post_commit
-		(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
-			const struct sieve_action_exec_env *aenv, void *se_context,
-			void *tr_context, bool *keep);
+	(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
+		const struct sieve_action_exec_env *aenv, void *se_context,
+		void *tr_context, bool *keep);
 
 const struct sieve_side_effect copy_side_effect = {
 	"copy",
@@ -125,9 +125,10 @@ static const struct sieve_argument copy_tag = {
 /* Side effect execution */
 
 static void seff_copy_print
-	(const struct sieve_side_effect *seffect ATTR_UNUSED, 
-		const struct sieve_action *action ATTR_UNUSED, 
-		void *se_context ATTR_UNUSED, bool *keep)
+(const struct sieve_side_effect *seffect ATTR_UNUSED, 
+	const struct sieve_action *action ATTR_UNUSED, 
+	struct sieve_result *result ATTR_UNUSED,
+	void *se_context ATTR_UNUSED, bool *keep)
 {
 	printf("        + preserve implicit keep\n");
 
diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
index a64f5c43f..b448d5cea 100644
--- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
@@ -6,6 +6,7 @@
 #include "sieve-validator.h" 
 #include "sieve-generator.h"
 #include "sieve-interpreter.h"
+#include "sieve-result.h"
 #include "sieve-dump.h"
 
 #include "sieve-ext-variables.h"
@@ -167,47 +168,51 @@ void ext_imapflags_attach_flags_tag
 	/* Tag specified by user */
 	sieve_validator_register_external_tag
 		(valdtr, &tag_flags, command, -1);
-		
-	/* Implicit tag if none is specified */
-	sieve_validator_register_persistent_tag
-		(valdtr, &tag_flags_implicit, command);
 }
 
 /* Context access */
 
-struct ext_imapflags_message_context {
+struct ext_imapflags_result_context {
     string_t *internal_flags;
 };
 
-static inline struct ext_imapflags_message_context *
-	_get_message_context(struct sieve_message_context *msgctx)
+static inline struct ext_imapflags_result_context *
+	_get_result_context(struct sieve_result *result)
 {
-	struct ext_imapflags_message_context *mctx =
-		(struct ext_imapflags_message_context *) 
-		sieve_message_context_extension_get(msgctx, ext_imapflags_my_id);
+	struct ext_imapflags_result_context *rctx =
+		(struct ext_imapflags_result_context *) 
+		sieve_result_extension_get_context(result, ext_imapflags_my_id);
 
-	if ( mctx == NULL ) {
-		pool_t pool = sieve_message_context_pool(msgctx);
+	if ( rctx == NULL ) {
+		pool_t pool = sieve_result_pool(result);
 
-		mctx =p_new(pool, struct ext_imapflags_message_context, 1);
-		mctx->internal_flags = str_new(pool, 32);
+		rctx =p_new(pool, struct ext_imapflags_result_context, 1);
+		rctx->internal_flags = str_new(pool, 32);
 
-		sieve_message_context_extension_set	
-			(msgctx, ext_imapflags_my_id, mctx);
+		sieve_result_extension_set_context
+			(result, ext_imapflags_my_id, rctx);
 	}
 
-	return mctx;
+	return rctx;
 }
 
 static string_t *_get_flags_string
-	(struct sieve_message_context *msgctx)
+	(struct sieve_result *result)
 {
-	struct ext_imapflags_message_context *ctx = 
-		_get_message_context(msgctx);
+	struct ext_imapflags_result_context *ctx = 
+		_get_result_context(result);
 		
 	return ctx->internal_flags;
 }
 
+/* Initialization */
+
+void ext_imapflags_runtime_init(const struct sieve_runtime_env *renv)
+{	
+	sieve_result_add_implicit_side_effect
+		(renv->result, &act_store, &flags_side_effect, NULL);
+}
+
 /* Flag operations */
 
 static bool flag_is_valid(const char *flag)
@@ -369,7 +374,7 @@ void ext_imapflags_set_flags
 	if ( storage != NULL ) 
 		sieve_variable_get_modifiable(storage, var_index, &cur_flags);
 	else
-		cur_flags = _get_flags_string(renv->msgctx);
+		cur_flags = _get_flags_string(renv->result);
 
 	flags_list_set_flags(cur_flags, flags);		
 }
@@ -383,7 +388,7 @@ void ext_imapflags_add_flags
 	if ( storage != NULL ) 
 		sieve_variable_get_modifiable(storage, var_index, &cur_flags);
 	else
-		cur_flags = _get_flags_string(renv->msgctx);
+		cur_flags = _get_flags_string(renv->result);
 	
 	flags_list_add_flags(cur_flags, flags);		
 }
@@ -397,7 +402,7 @@ void ext_imapflags_remove_flags
 	if ( storage != NULL ) 
 		sieve_variable_get_modifiable(storage, var_index, &cur_flags);
 	else
-		cur_flags = _get_flags_string(renv->msgctx);
+		cur_flags = _get_flags_string(renv->result);
 	
 	flags_list_remove_flags(cur_flags, flags);		
 }
@@ -411,7 +416,7 @@ const char *ext_imapflags_get_flags_string
 	if ( storage != NULL ) 
 		sieve_variable_get_modifiable(storage, var_index, &cur_flags);
 	else
-		cur_flags = _get_flags_string(renv->msgctx);
+		cur_flags = _get_flags_string(renv->result);
 
 	return str_c(cur_flags);
 }
@@ -425,11 +430,20 @@ void ext_imapflags_get_flags_init
 	if ( storage != NULL ) 
 		sieve_variable_get_modifiable(storage, var_index, &cur_flags);
 	else
-		cur_flags = _get_flags_string(renv->msgctx);
+		cur_flags = _get_flags_string(renv->result);
 	
 	ext_imapflags_iter_init(iter, cur_flags);		
 }
 
+void ext_imapflags_get_implicit_flags_init
+(struct ext_imapflags_iter *iter, struct sieve_result *result)
+{
+	string_t *cur_flags = _get_flags_string(result);
+	
+	ext_imapflags_iter_init(iter, cur_flags);		
+}
+
+
 	
 	
 
diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
index 2394382c5..ca35782b6 100644
--- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
@@ -7,7 +7,9 @@
 #include "sieve-ext-variables.h"
 
 extern int ext_imapflags_my_id;
+
 extern const struct sieve_extension imapflags_extension;
+extern const struct sieve_side_effect flags_side_effect;
 
 enum ext_imapflags_opcode {
 	EXT_IMAPFLAGS_OPERATION_SETFLAG,
@@ -33,6 +35,10 @@ bool ext_imapflags_command_operands_read
 void ext_imapflags_attach_flags_tag
 	(struct sieve_validator *valdtr, const char *command);
 
+/* Initialization */
+
+void ext_imapflags_runtime_init(const struct sieve_runtime_env *renv);
+
 /* Flag registration */
 
 struct ext_imapflags_iter {
@@ -64,6 +70,8 @@ void ext_imapflags_remove_flags
 void ext_imapflags_get_flags_init
 	(struct ext_imapflags_iter *iter, const struct sieve_runtime_env *renv,
 		struct sieve_variable_storage *storage, unsigned int var_index);
+void ext_imapflags_get_implicit_flags_init
+	(struct ext_imapflags_iter *iter, struct sieve_result *result);
 
 
 #endif /* __EXT_IMAPFLAGS_COMMON_H */
diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags.c b/src/lib-sieve/plugins/imapflags/ext-imapflags.c
index e790c48d4..8dcfcd4e8 100644
--- a/src/lib-sieve/plugins/imapflags/ext-imapflags.c
+++ b/src/lib-sieve/plugins/imapflags/ext-imapflags.c
@@ -28,9 +28,9 @@
 /* Forward declarations */
 
 static bool ext_imapflags_load(int ext_id);
-static bool ext_imapflags_validator_load(struct sieve_validator *validator);
-static bool ext_imapflags_interpreter_load
-	(struct sieve_interpreter *interpreter);
+static bool ext_imapflags_validator_load(struct sieve_validator *valdtr);
+static bool ext_imapflags_runtime_load
+	(const struct sieve_runtime_env *renv);
 static bool ext_imapflags_binary_load(struct sieve_binary *sbin);
 
 /* Commands */
@@ -60,7 +60,7 @@ const struct sieve_extension imapflags_extension = {
 	ext_imapflags_load,
 	ext_imapflags_validator_load, 
 	NULL, 
-	ext_imapflags_interpreter_load, 
+	ext_imapflags_runtime_load, 
 	ext_imapflags_binary_load,
 	NULL,
 	SIEVE_EXT_DEFINE_OPERATIONS(imapflags_operations), 
@@ -79,16 +79,16 @@ extern const struct sieve_side_effect_extension imapflags_seffect_extension;
 /* Load extension into validator */
 
 static bool ext_imapflags_validator_load
-	(struct sieve_validator *validator)
+	(struct sieve_validator *valdtr)
 {
 	/* Register commands */
-	sieve_validator_register_command(validator, &cmd_setflag);
-	sieve_validator_register_command(validator, &cmd_addflag);
-	sieve_validator_register_command(validator, &cmd_removeflag);
-	sieve_validator_register_command(validator, &tst_hasflag);
+	sieve_validator_register_command(valdtr, &cmd_setflag);
+	sieve_validator_register_command(valdtr, &cmd_addflag);
+	sieve_validator_register_command(valdtr, &cmd_removeflag);
+	sieve_validator_register_command(valdtr, &tst_hasflag);
 	
-	ext_imapflags_attach_flags_tag(validator, "keep");
-	ext_imapflags_attach_flags_tag(validator, "fileinto");
+	ext_imapflags_attach_flags_tag(valdtr, "keep");
+	ext_imapflags_attach_flags_tag(valdtr, "fileinto");
 
 	return TRUE;
 }
@@ -109,10 +109,11 @@ static bool ext_imapflags_binary_load(struct sieve_binary *sbin)
  * Interpreter context
  */
 
-static bool ext_imapflags_interpreter_load
-	(struct sieve_interpreter *interpreter ATTR_UNUSED)
+static bool ext_imapflags_runtime_load
+	(const struct sieve_runtime_env *renv)
 {
-	/* Will contain something when variables extension is implemented */
+	ext_imapflags_runtime_init(renv);
+	
 	return TRUE;
 }
 
diff --git a/src/lib-sieve/plugins/imapflags/tag-flags.c b/src/lib-sieve/plugins/imapflags/tag-flags.c
index 56097fb41..254e15826 100644
--- a/src/lib-sieve/plugins/imapflags/tag-flags.c
+++ b/src/lib-sieve/plugins/imapflags/tag-flags.c
@@ -13,8 +13,6 @@
 
 #include "ext-imapflags-common.h"
 
-static bool tag_flags_validate_persistent
-	(struct sieve_validator *validator, struct sieve_command_context *cmd);
 static bool tag_flags_validate
 	(struct sieve_validator *validator,	struct sieve_ast_argument **arg, 
 		struct sieve_command_context *cmd);
@@ -32,14 +30,6 @@ const struct sieve_argument tag_flags = {
 	tag_flags_generate 
 };
 
-const struct sieve_argument tag_flags_implicit = { 
-	"@flags-implicit", 
-	NULL, 
-	tag_flags_validate_persistent,
-	NULL,	NULL, 
-	tag_flags_generate 
-};
-
 /* Side effect */
 
 extern const struct sieve_side_effect_extension imapflags_seffect_extension;
@@ -51,29 +41,20 @@ static bool seff_flags_read_context
 	(const struct sieve_side_effect *seffect, 
 		const struct sieve_runtime_env *renv, sieve_size_t *address,
 		void **se_context);
-static bool seff_flags_read_implicit_context
-	(const struct sieve_side_effect *seffect, 
-		const struct sieve_runtime_env *renv, sieve_size_t *address,
-		void **se_context);
 static void seff_flags_print
-	(const struct sieve_side_effect *seffect,	const struct sieve_action *action, 
-		void *se_context, bool *keep);
+	(const struct sieve_side_effect *seffect,	const struct sieve_action *action,
+		struct sieve_result *result, void *se_context, bool *keep);
 static bool seff_flags_pre_execute
 	(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
 		const struct sieve_action_exec_env *aenv, 
 		void **se_context, void *tr_context);
 
-enum ext_imapflags_side_effect_type {
-	EXT_IMAPFLAGS_SEFFECT_FLAGS,
-	EXT_IMAPFLAGS_SEFFECT_FLAGS_IMPLICIT,
-};
-
 const struct sieve_side_effect flags_side_effect = {
 	"flags",
 	&act_store,
 	
 	&imapflags_seffect_extension,
-	EXT_IMAPFLAGS_SEFFECT_FLAGS,
+	0,
 	seff_flags_dump_context,
 	seff_flags_read_context,
 	seff_flags_print,
@@ -81,41 +62,14 @@ const struct sieve_side_effect flags_side_effect = {
 	NULL, NULL, NULL
 };
 
-const struct sieve_side_effect flags_implicit_side_effect = {
-	"flags-implicit",
-	&act_store,
-	
-	&imapflags_seffect_extension,
-	EXT_IMAPFLAGS_SEFFECT_FLAGS_IMPLICIT,
-	NULL,
-	seff_flags_read_implicit_context,
-	seff_flags_print,
-	seff_flags_pre_execute, 
-	NULL, NULL, NULL
-};
-
-const struct sieve_side_effect *imapflags_side_effects[] = {
-	&flags_side_effect, &flags_implicit_side_effect
-};
-
 const struct sieve_side_effect_extension imapflags_seffect_extension = {
 	&imapflags_extension,
 
-	SIEVE_EXT_DEFINE_SIDE_EFFECTS(imapflags_side_effects)
+	SIEVE_EXT_DEFINE_SIDE_EFFECT(flags_side_effect)
 };
 
 /* Tag validation */
 
-static bool tag_flags_validate_persistent
-(struct sieve_validator *validator ATTR_UNUSED, struct sieve_command_context *cmd)
-{	
-	if ( sieve_command_find_argument(cmd, &tag_flags) == NULL ) {
-		sieve_command_add_dynamic_tag(cmd, &tag_flags_implicit, -1);
-	}
-	
-	return TRUE;
-}
-
 static bool tag_flags_validate
 (struct sieve_validator *validator,	struct sieve_ast_argument **arg, 
 	struct sieve_command_context *cmd)
@@ -154,19 +108,13 @@ static bool tag_flags_generate
       return FALSE;
   }
 
-	if ( arg->argument == &tag_flags ) {
-		sieve_opr_side_effect_emit(sbin, &flags_side_effect, ext_imapflags_my_id);
-		  
-		param = arg->parameters;
-	
-		/* Call the generation function for the argument */ 
-		if ( param->argument != NULL && param->argument->generate != NULL && 
-			!param->argument->generate(generator, param, cmd) ) 
-			return FALSE;
-	} else if ( arg->argument == &tag_flags_implicit ) {
-		sieve_opr_side_effect_emit
-			(sbin, &flags_implicit_side_effect, ext_imapflags_my_id);
-	} else
+	sieve_opr_side_effect_emit(sbin, &flags_side_effect, ext_imapflags_my_id);
+	  
+	param = arg->parameters;
+
+	/* Call the generation function for the argument */ 
+	if ( param->argument != NULL && param->argument->generate != NULL && 
+		!param->argument->generate(generator, param, cmd) ) 
 		return FALSE;
 	
   return TRUE;
@@ -244,13 +192,10 @@ static bool seff_flags_read_context
 	return result;
 }
 
-static bool seff_flags_read_implicit_context
-(const struct sieve_side_effect *seffect ATTR_UNUSED, 
-	const struct sieve_runtime_env *renv, sieve_size_t *address ATTR_UNUSED,
-	void **se_context)
+static struct seff_flags_context *seff_flags_get_implicit_context
+(struct sieve_result *result)
 {
-	bool result = TRUE;
-	pool_t pool = sieve_result_pool(renv->result);
+	pool_t pool = sieve_result_pool(result);
 	struct seff_flags_context *ctx;
 	const char *flag;
 	struct ext_imapflags_iter flit;
@@ -261,7 +206,7 @@ static bool seff_flags_read_implicit_context
 	t_push();
 		
 	/* Unpack */
-	ext_imapflags_get_flags_init(&flit, renv, NULL, 0);
+	ext_imapflags_get_implicit_flags_init(&flit, result);
 	while ( (flag=ext_imapflags_iter_get_flag(&flit)) != NULL ) {		
 		if (flag != NULL && *flag != '\\') {
 			/* keyword */
@@ -280,23 +225,24 @@ static bool seff_flags_read_implicit_context
 				ctx->flags |= MAIL_DRAFT;
 		}
 	}
-	
-	*se_context = (void *) ctx;
 
 	t_pop();
 	
-	return result;
+	return ctx;
 }
 
-
 static void seff_flags_print
 (const struct sieve_side_effect *seffect ATTR_UNUSED, 
 	const struct sieve_action *action ATTR_UNUSED, 
+	struct sieve_result *result,
 	void *se_context ATTR_UNUSED, bool *keep)
 {
 	struct seff_flags_context *ctx = (struct seff_flags_context *) se_context;
 	unsigned int i;
 	
+	if ( ctx == NULL )
+		ctx = seff_flags_get_implicit_context(result);
+	
 	printf("        + add flags:");
 
 	if ( (ctx->flags & MAIL_FLAGGED) > 0 )
@@ -333,6 +279,11 @@ static bool seff_flags_pre_execute
 	struct seff_flags_context *ctx = (struct seff_flags_context *) *se_context;
 	struct act_store_transaction *trans = 
 		(struct act_store_transaction *) tr_context;
+		
+	if ( ctx == NULL ) {
+		ctx = seff_flags_get_implicit_context(aenv->result);
+		*se_context = (void *) ctx;
+	}
 
 	/* Assign mail keywords for subsequent mailbox_copy() */
 	if ( array_count(&ctx->keywords) > 0 ) {
@@ -342,10 +293,7 @@ static bool seff_flags_pre_execute
 		}
 		
 		array_append_array(&trans->keywords, &ctx->keywords);
-		
-		printf("keywords: %d\n", array_count(&ctx->keywords));
 	}
-	printf("flags: %d\n", trans->flags);
 
 	/* Assign mail flags for subsequent mailbox_copy() */
 	trans->flags |= ctx->flags;
diff --git a/src/lib-sieve/plugins/include/ext-include-common.c b/src/lib-sieve/plugins/include/ext-include-common.c
index 57fdc1ab9..6b1c4ccd3 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.c
+++ b/src/lib-sieve/plugins/include/ext-include-common.c
@@ -167,19 +167,18 @@ static inline struct ext_include_interpreter_context *
 	return ctx;
 }
 
-void ext_include_register_interpreter_context
-(struct sieve_interpreter *interp)
+void ext_include_runtime_context_init
+(const struct sieve_runtime_env *renv)
 {
 	struct ext_include_interpreter_context *ctx = 
-		ext_include_get_interpreter_context(interp);
-	struct sieve_script *script = sieve_interpreter_script(interp);
+		ext_include_get_interpreter_context(renv->interp);
 	
 	if ( ctx == NULL ) {
 		ctx = ext_include_create_interpreter_context
-			(interp, NULL, script, SBIN_SYSBLOCK_MAIN_PROGRAM);
+			(renv->interp, NULL, renv->script, SBIN_SYSBLOCK_MAIN_PROGRAM);
 		
 		sieve_interpreter_extension_set_context
-			(interp, ext_include_my_id, (void *) ctx);		
+			(renv->interp, ext_include_my_id, (void *) ctx);		
 	}
 }
 
diff --git a/src/lib-sieve/plugins/include/ext-include-common.h b/src/lib-sieve/plugins/include/ext-include-common.h
index ffd05a9e5..35a2b8094 100644
--- a/src/lib-sieve/plugins/include/ext-include-common.h
+++ b/src/lib-sieve/plugins/include/ext-include-common.h
@@ -55,7 +55,7 @@ bool ext_include_generate_include
 
 /* Interpreter */
 
-void ext_include_register_interpreter_context(struct sieve_interpreter *interp);
+void ext_include_runtime_context_init(const struct sieve_runtime_env *renv);
 
 bool ext_include_execute_include
 	(const struct sieve_runtime_env *renv, unsigned int block_id);
diff --git a/src/lib-sieve/plugins/include/ext-include.c b/src/lib-sieve/plugins/include/ext-include.c
index bae9985e0..d9eb0cfb3 100644
--- a/src/lib-sieve/plugins/include/ext-include.c
+++ b/src/lib-sieve/plugins/include/ext-include.c
@@ -33,7 +33,7 @@ static bool ext_include_load(int ext_id);
 static bool ext_include_validator_load(struct sieve_validator *validator);
 static bool ext_include_generator_load(struct sieve_generator *gentr);
 static bool ext_include_binary_load(struct sieve_binary *sbin);
-static bool ext_include_interpreter_load(struct sieve_interpreter *interp);
+static bool ext_include_runtime_load(const struct sieve_runtime_env *renv);
 
 /* Operations */
 
@@ -54,7 +54,7 @@ const struct sieve_extension include_extension = {
 	ext_include_load,
 	ext_include_validator_load, 
 	ext_include_generator_load,
-	ext_include_interpreter_load, 
+	ext_include_runtime_load, 
 	ext_include_binary_load, 
 	ext_include_binary_dump,
 	SIEVE_EXT_DEFINE_OPERATIONS(ext_include_operations),
@@ -92,9 +92,10 @@ static bool ext_include_generator_load(struct sieve_generator *gentr)
 
 /* Load extension into interpreter */
 
-static bool ext_include_interpreter_load(struct sieve_interpreter *interp)
+static bool ext_include_runtime_load
+(const struct sieve_runtime_env *renv)
 {
-	ext_include_register_interpreter_context(interp);
+	ext_include_runtime_context_init(renv);
 	
 	return TRUE;
 }
diff --git a/src/lib-sieve/plugins/include/include.sieve b/src/lib-sieve/plugins/include/include.sieve
index 1b90fc329..81c3bb5ff 100644
--- a/src/lib-sieve/plugins/include/include.sieve
+++ b/src/lib-sieve/plugins/include/include.sieve
@@ -1,4 +1,5 @@
 require "include";
+require "variables";
 
 include "included1";
 include :global "included2";
diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
index 96fe5468e..ac7b0c30f 100644
--- a/src/lib-sieve/plugins/vacation/cmd-vacation.c
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -56,7 +56,8 @@ int act_vacation_check_conflict
 	(const struct sieve_runtime_env *renv, const struct sieve_action *action,
 		const struct sieve_action *other_action, void *context);
 static void act_vacation_print
-	(const struct sieve_action *action, void *context, bool *keep);	
+	(const struct sieve_action *action, struct sieve_result *result,
+		void *context, bool *keep);	
 static bool act_vacation_commit
 	(const struct sieve_action *action,	const struct sieve_action_exec_env *aenv, 
 		void *tr_context, bool *keep);
@@ -468,8 +469,8 @@ int act_vacation_check_conflict
 }
  
 static void act_vacation_print
-(const struct sieve_action *action ATTR_UNUSED, void *context, 
-	bool *keep ATTR_UNUSED)	
+(const struct sieve_action *action ATTR_UNUSED, struct sieve_result *result ATTR_UNUSED,
+	void *context, bool *keep ATTR_UNUSED)	
 {
 	struct act_vacation_context *ctx = (struct act_vacation_context *) context;
 	
diff --git a/src/lib-sieve/plugins/variables/ext-variables.c b/src/lib-sieve/plugins/variables/ext-variables.c
index 7d1885da2..4edfa9b6d 100644
--- a/src/lib-sieve/plugins/variables/ext-variables.c
+++ b/src/lib-sieve/plugins/variables/ext-variables.c
@@ -21,6 +21,7 @@
 #include "sieve-extensions.h"
 #include "sieve-commands.h"
 #include "sieve-binary.h"
+#include "sieve-interpreter.h"
 
 #include "sieve-validator.h"
 
@@ -35,7 +36,7 @@
 static bool ext_variables_load(int ext_id);
 static bool ext_variables_validator_load(struct sieve_validator *validator);
 static bool ext_variables_binary_load(struct sieve_binary *sbin);
-static bool ext_variables_interpreter_load(struct sieve_interpreter *interp);
+static bool ext_variables_runtime_load(const struct sieve_runtime_env *renv);
 
 /* Commands */
 
@@ -69,7 +70,7 @@ struct sieve_extension variables_extension = {
 	ext_variables_load,
 	ext_variables_validator_load, 
 	NULL, 
-	ext_variables_interpreter_load, 
+	ext_variables_runtime_load, 
 	ext_variables_binary_load,
 	NULL,
 	SIEVE_EXT_DEFINE_OPERATIONS(ext_variables_operations), 
@@ -110,10 +111,10 @@ static bool ext_variables_binary_load
 
 /* Load extension into interpreter */
 
-static bool ext_variables_interpreter_load
-	(struct sieve_interpreter *interp)
+static bool ext_variables_runtime_load
+	(const struct sieve_runtime_env *renv)
 {
-	ext_variables_interpreter_initialize(interp);
+	ext_variables_interpreter_initialize(renv->interp);
 
 	return TRUE;
 }
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index 8e9e628f6..844f9760d 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -180,11 +180,11 @@ bool sieve_opr_side_effect_dump
 /* Store action */
 
 static int act_store_check_duplicate
-	(const struct sieve_runtime_env *renv ATTR_UNUSED,
-		const struct sieve_action *action1 ATTR_UNUSED, 
+	(const struct sieve_runtime_env *renv, const struct sieve_action *action1, 
 		void *context1, void *context2);
 static void act_store_print
-	(const struct sieve_action *action ATTR_UNUSED, void *context, bool *keep);
+	(const struct sieve_action *action, struct sieve_result *result,
+		void *context, bool *keep);
 
 static bool act_store_start
 	(const struct sieve_action *action,
@@ -243,7 +243,8 @@ static int act_store_check_duplicate
 }
 
 static void act_store_print
-(const struct sieve_action *action ATTR_UNUSED, void *context, bool *keep)	
+(const struct sieve_action *action ATTR_UNUSED, 
+	struct sieve_result *result ATTR_UNUSED, void *context, bool *keep)	
 {
 	struct act_store_context *ctx = (struct act_store_context *) context;
 	
@@ -322,9 +323,7 @@ static bool act_store_execute
 	if ( array_is_created(&trans->keywords) && array_count(&trans->keywords) > 0 ) 
 	{
 		const char *const *kwds;
-	
-		printf("KEYWORDS: %d\n", array_count(&trans->keywords));
-	
+		
 		(void)array_append_space(&trans->keywords);
 		kwds = array_idx(&trans->keywords, 0);
 				
@@ -336,8 +335,6 @@ static bool act_store_execute
 		}
 	}
 	
-	printf("FLAGS: %d\n", trans->flags);
-
 	if (mailbox_copy(trans->mail_trans, aenv->msgdata->mail, trans->flags, 
 		keywords, trans->dest_mail) < 0) {
 		act_store_get_storage_error(aenv, trans);
diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h
index d29bc1be6..b17ffe838 100644
--- a/src/lib-sieve/sieve-actions.h
+++ b/src/lib-sieve/sieve-actions.h
@@ -34,7 +34,8 @@ struct sieve_action {
 			void *context);
 
 	void (*print)
-		(const struct sieve_action *action, void *context, bool *keep);	
+		(const struct sieve_action *action, struct sieve_result *result, 
+			void *context, bool *keep);	
 		
 	bool (*start)
 		(const struct sieve_action *action, 
@@ -72,7 +73,7 @@ struct sieve_side_effect {
 			
 	void (*print)
 		(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
-			void *se_context, bool *keep);
+			struct sieve_result *result, void *se_context, bool *keep);
 
 	bool (*pre_execute)
 		(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h
index 79d41b3b7..7ce1f2360 100644
--- a/src/lib-sieve/sieve-common.h
+++ b/src/lib-sieve/sieve-common.h
@@ -93,6 +93,9 @@ struct sieve_side_effect;
 /* sieve-script.h */
 struct sieve_script;
 
+/* sieve-message.h */
+struct sieve_message_context;
+
 /* sieve.c */
 struct sieve_ast *sieve_parse
 	(struct sieve_script *script, struct sieve_error_handler *ehandler);
diff --git a/src/lib-sieve/sieve-extensions.c b/src/lib-sieve/sieve-extensions.c
index 627fd7d90..c349db5dc 100644
--- a/src/lib-sieve/sieve-extensions.c
+++ b/src/lib-sieve/sieve-extensions.c
@@ -202,7 +202,7 @@ static bool _list_extension(const struct sieve_extension *ext)
 	if ( *ext->name == '@' ) return FALSE;
 
 	if ( ext->validator_load == NULL && ext->generator_load == NULL &&
-		ext->binary_load == NULL && ext->interpreter_load == NULL &&
+		ext->binary_load == NULL && ext->runtime_load == NULL &&
 		ext->load == NULL && 
 		ext->operations.count == 0 && ext->operands.count == 0 ) {
 		return FALSE;
diff --git a/src/lib-sieve/sieve-extensions.h b/src/lib-sieve/sieve-extensions.h
index f8b65eb24..0f5bff415 100644
--- a/src/lib-sieve/sieve-extensions.h
+++ b/src/lib-sieve/sieve-extensions.h
@@ -21,7 +21,7 @@ struct sieve_extension {
 	bool (*validator_load)(struct sieve_validator *validator);	
 	bool (*generator_load)(struct sieve_generator *generator);
 	
-	bool (*interpreter_load)(struct sieve_interpreter *interpreter);
+	bool (*runtime_load)(const struct sieve_runtime_env *renv);
 	
 	bool (*binary_load)(struct sieve_binary *binary);
 	bool (*binary_dump)(struct sieve_dumptime_env *denv);
diff --git a/src/lib-sieve/sieve-interpreter.c b/src/lib-sieve/sieve-interpreter.c
index 3b4accb5d..067a5b56c 100644
--- a/src/lib-sieve/sieve-interpreter.c
+++ b/src/lib-sieve/sieve-interpreter.c
@@ -9,6 +9,7 @@
 
 #include "sieve-error.h"
 #include "sieve-extensions.h"
+#include "sieve-message.h"
 #include "sieve-commands-private.h"
 #include "sieve-code.h"
 #include "sieve-actions.h"
@@ -19,75 +20,6 @@
 
 #include "sieve-interpreter.h"
 
-/* 
- * Message context 
- *   (might get moved to separate file) 
- */
-
-struct sieve_message_context {
-	pool_t pool;
-	int refcount;
-	
-	/* Context data for extensions */
-	ARRAY_DEFINE(ext_contexts, void *); 
-};
-
-static struct sieve_message_context *sieve_message_context_create(void)
-{
-	pool_t pool;
-	struct sieve_message_context *msgctx;
-	
-	pool = pool_alloconly_create("sieve_message_context", 1024);
-	msgctx = p_new(pool, struct sieve_message_context, 1);
-	msgctx->pool = pool;
-	msgctx->refcount = 1;
-	
-	p_array_init(&msgctx->ext_contexts, pool, 4);
-	
-	return msgctx;
-}
-
-static void sieve_message_context_ref(struct sieve_message_context *msgctx)
-{
-	msgctx->refcount++;
-}
-
-static void sieve_message_context_unref(struct sieve_message_context **msgctx)
-{
-	i_assert((*msgctx)->refcount > 0);
-
-	if (--(*msgctx)->refcount != 0)
-		return;
-	
-	pool_unref(&((*msgctx)->pool));
-	
-	*msgctx = NULL;
-}
-
-void sieve_message_context_extension_set
-	(struct sieve_message_context *msgctx, int ext_id, void *context)
-{
-	array_idx_set(&msgctx->ext_contexts, (unsigned int) ext_id, &context);	
-}
-
-const void *sieve_message_context_extension_get
-	(struct sieve_message_context *msgctx, int ext_id) 
-{
-	void * const *ctx;
-
-	if  ( ext_id < 0 || ext_id >= (int) array_count(&msgctx->ext_contexts) )
-		return NULL;
-	
-	ctx = array_idx(&msgctx->ext_contexts, (unsigned int) ext_id);		
-
-	return *ctx;
-}
-
-pool_t sieve_message_context_pool(struct sieve_message_context *msgctx)
-{
-	return msgctx->pool;
-}
-
 /* 
  * Interpreter 
  */
@@ -116,8 +48,6 @@ struct sieve_interpreter {
 struct sieve_interpreter *sieve_interpreter_create
 (struct sieve_binary *sbin, struct sieve_error_handler *ehandler) 
 {
-	unsigned int i;
-	int idx;
 	pool_t pool;
 	struct sieve_interpreter *interp;
 	
@@ -136,23 +66,6 @@ struct sieve_interpreter *sieve_interpreter_create
 	interp->pc = 0;
 
 	p_array_init(&interp->ext_contexts, pool, 4);
-
-	/* Pre-load core language features implemented as 'extensions' */
-	for ( i = 0; i < sieve_preloaded_extensions_count; i++ ) {
-		const struct sieve_extension *ext = sieve_preloaded_extensions[i];
-		
-		if ( ext->interpreter_load != NULL )
-			(void)ext->interpreter_load(interp);		
-	}
-
-	/* Load other extensions listed in the binary */
-	for ( idx = 0; idx < sieve_binary_extensions_count(sbin); idx++ ) {
-		const struct sieve_extension *ext = 
-			sieve_binary_extension_get_by_index(sbin, idx, NULL);
-		
-		if ( ext->interpreter_load != NULL )
-			ext->interpreter_load(interp);
-	}
 	
 	return interp;
 }
@@ -416,6 +329,10 @@ int sieve_interpreter_start
 	const struct sieve_script_env *senv, struct sieve_message_context *msgctx, 
 	struct sieve_result *result, bool *interrupted) 
 {
+	struct sieve_binary *sbin = interp->runenv.sbin;
+	unsigned int i;
+	int idx;
+	
 	interp->runenv.msgdata = msgdata;
 	interp->runenv.result = result;		
 	interp->runenv.scriptenv = senv;
@@ -427,6 +344,23 @@ int sieve_interpreter_start
 		sieve_message_context_ref(msgctx);
 	}
 	
+	/* Pre-load core language features implemented as 'extensions' */
+	for ( i = 0; i < sieve_preloaded_extensions_count; i++ ) {
+		const struct sieve_extension *ext = sieve_preloaded_extensions[i];
+		
+		if ( ext->runtime_load != NULL )
+			(void)ext->runtime_load(&interp->runenv);		
+	}
+
+	/* Load other extensions listed in the binary */
+	for ( idx = 0; idx < sieve_binary_extensions_count(sbin); idx++ ) {
+		const struct sieve_extension *ext = 
+			sieve_binary_extension_get_by_index(sbin, idx, NULL);
+		
+		if ( ext->runtime_load != NULL )
+			ext->runtime_load(&interp->runenv);
+	}
+
 	return sieve_interpreter_continue(interp, interrupted); 
 }
 
diff --git a/src/lib-sieve/sieve-interpreter.h b/src/lib-sieve/sieve-interpreter.h
index 15f53e8c5..cc431804e 100644
--- a/src/lib-sieve/sieve-interpreter.h
+++ b/src/lib-sieve/sieve-interpreter.h
@@ -11,17 +11,6 @@
 /* FIXME: make execution dumps use some interpreter function */
 #include <stdio.h>
 
-/* Message context */
-
-struct sieve_message_context;
-
-void sieve_message_context_extension_set
-	(struct sieve_message_context *msgctx, int ext_id, void *context);
-const void *sieve_message_context_extension_get
-	(struct sieve_message_context *msgctx, int ext_id);
-pool_t sieve_message_context_pool
-	(struct sieve_message_context *msgctx);
-
 /* Interpreter */
 
 struct sieve_interpreter;
diff --git a/src/lib-sieve/sieve-message.c b/src/lib-sieve/sieve-message.c
new file mode 100644
index 000000000..57bc9aa63
--- /dev/null
+++ b/src/lib-sieve/sieve-message.c
@@ -0,0 +1,75 @@
+#include "lib.h"
+#include "mempool.h"
+#include "array.h"
+
+#include "sieve-common.h"
+#include "sieve-message.h"
+
+/* 
+ * Message context 
+ */
+
+struct sieve_message_context {
+	pool_t pool;
+	int refcount;
+	
+	/* Context data for extensions */
+	ARRAY_DEFINE(ext_contexts, void *); 
+};
+
+struct sieve_message_context *sieve_message_context_create(void)
+{
+	pool_t pool;
+	struct sieve_message_context *msgctx;
+	
+	pool = pool_alloconly_create("sieve_message_context", 1024);
+	msgctx = p_new(pool, struct sieve_message_context, 1);
+	msgctx->pool = pool;
+	msgctx->refcount = 1;
+	
+	p_array_init(&msgctx->ext_contexts, pool, 4);
+	
+	return msgctx;
+}
+
+void sieve_message_context_ref(struct sieve_message_context *msgctx)
+{
+	msgctx->refcount++;
+}
+
+void sieve_message_context_unref(struct sieve_message_context **msgctx)
+{
+	i_assert((*msgctx)->refcount > 0);
+
+	if (--(*msgctx)->refcount != 0)
+		return;
+	
+	pool_unref(&((*msgctx)->pool));
+	
+	*msgctx = NULL;
+}
+
+void sieve_message_context_extension_set
+	(struct sieve_message_context *msgctx, int ext_id, void *context)
+{
+	array_idx_set(&msgctx->ext_contexts, (unsigned int) ext_id, &context);	
+}
+
+const void *sieve_message_context_extension_get
+	(struct sieve_message_context *msgctx, int ext_id) 
+{
+	void * const *ctx;
+
+	if  ( ext_id < 0 || ext_id >= (int) array_count(&msgctx->ext_contexts) )
+		return NULL;
+	
+	ctx = array_idx(&msgctx->ext_contexts, (unsigned int) ext_id);		
+
+	return *ctx;
+}
+
+pool_t sieve_message_context_pool(struct sieve_message_context *msgctx)
+{
+	return msgctx->pool;
+}
+
diff --git a/src/lib-sieve/sieve-message.h b/src/lib-sieve/sieve-message.h
new file mode 100644
index 000000000..33fd667d7
--- /dev/null
+++ b/src/lib-sieve/sieve-message.h
@@ -0,0 +1,19 @@
+#ifndef __SIEVE_MESSAGE_H
+#define __SIEVE_MESSAGE_H
+
+/* Message context */
+
+struct sieve_message_context;
+
+struct sieve_message_context *sieve_message_context_create(void);
+void sieve_message_context_ref(struct sieve_message_context *msgctx);
+void sieve_message_context_unref(struct sieve_message_context **msgctx);
+
+void sieve_message_context_extension_set
+	(struct sieve_message_context *msgctx, int ext_id, void *context);
+const void *sieve_message_context_extension_get
+	(struct sieve_message_context *msgctx, int ext_id);
+pool_t sieve_message_context_pool
+	(struct sieve_message_context *msgctx);
+	
+#endif
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index cd2ab1916..bfdd71668 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1,5 +1,6 @@
 #include "lib.h"
 #include "mempool.h"
+#include "hash.h"
 #include "strfuncs.h"
 #include "str-sanitize.h"
 
@@ -11,6 +12,10 @@
 
 #include <stdio.h>
 
+/*
+ *
+ */
+
 struct sieve_result_action {
 	struct sieve_result *result;
 	const struct sieve_action *action;
@@ -36,15 +41,25 @@ struct sieve_result_side_effect {
 	struct sieve_result_side_effect *prev, *next; 
 };
 
+struct sieve_result_implicit_side_effects {
+	const struct sieve_action *action;
+	struct sieve_side_effects_list *seffects;
+};
+
 struct sieve_result {
 	pool_t pool;
 	int refcount;
+	
+	/* Context data for extensions */
+	ARRAY_DEFINE(ext_contexts, void *); 
 
 	struct sieve_error_handler *ehandler;
 		
 	struct sieve_action_exec_env action_env;
 	struct sieve_result_action *first_action;
 	struct sieve_result_action *last_action;
+	
+	struct hash_table *implicit_seffects;
 };
 
 struct sieve_result *sieve_result_create
@@ -58,6 +73,8 @@ struct sieve_result *sieve_result_create
 	result->refcount = 1;
 	result->pool = pool;
 	
+	p_array_init(&result->ext_contexts, pool, 4);
+	
 	result->ehandler = ehandler;
 	sieve_error_handler_ref(ehandler);
 
@@ -66,6 +83,7 @@ struct sieve_result *sieve_result_create
 	result->first_action = NULL;
 	result->last_action = NULL;
 
+	result->implicit_seffects = NULL;
 	return result;
 }
 
@@ -78,14 +96,14 @@ void sieve_result_unref(struct sieve_result **result)
 {
 	i_assert((*result)->refcount > 0);
 
-    if (--(*result)->refcount != 0)
-        return;
+	if (--(*result)->refcount != 0)
+		return;
 
 	sieve_error_handler_unref(&(*result)->ehandler);
 
-    pool_unref(&(*result)->pool);
+	pool_unref(&(*result)->pool);
 
-    *result = NULL;
+ 	*result = NULL;
 }
 
 pool_t sieve_result_pool(struct sieve_result *result)
@@ -93,6 +111,25 @@ pool_t sieve_result_pool(struct sieve_result *result)
 	return result->pool;
 }
 
+void sieve_result_extension_set_context
+	(struct sieve_result *result, int ext_id, void *context)
+{
+	array_idx_set(&result->ext_contexts, (unsigned int) ext_id, &context);	
+}
+
+const void *sieve_result_extension_get_context
+	(struct sieve_result *result, int ext_id) 
+{
+	void * const *ctx;
+
+	if  ( ext_id < 0 || ext_id >= (int) array_count(&result->ext_contexts) )
+		return NULL;
+	
+	ctx = array_idx(&result->ext_contexts, (unsigned int) ext_id);		
+
+	return *ctx;
+}
+
 /* Logging of result */
 
 static const char *_get_location(const struct sieve_action_exec_env *aenv)
@@ -123,6 +160,33 @@ void sieve_result_log
 
 /* Result composition */
 
+void sieve_result_add_implicit_side_effect
+(struct sieve_result *result, const struct sieve_action *to_action, 
+	const struct sieve_side_effect *seffect, void *context)
+{
+	struct sieve_result_implicit_side_effects *implseff = NULL;
+	
+	if ( result->implicit_seffects == NULL ) {
+		result->implicit_seffects = hash_create
+			(result->pool, result->pool, 0, NULL, NULL);
+	} else {
+		implseff = (struct sieve_result_implicit_side_effects *) 
+			hash_lookup(result->implicit_seffects, to_action);
+	}
+
+	if ( implseff == NULL ) {
+		implseff = p_new
+			(result->pool, struct sieve_result_implicit_side_effects, 1);
+		implseff->action = to_action;
+		implseff->seffects = sieve_side_effects_list_create(result);
+		
+		hash_insert(result->implicit_seffects, (void *) to_action, 
+			(void *) implseff);
+	}	
+	
+	sieve_side_effects_list_add(implseff->seffects, seffect, context);
+}
+
 int sieve_result_add_action
 (const struct sieve_runtime_env *renv,
 	const struct sieve_action *action, struct sieve_side_effects_list *seffects,
@@ -180,6 +244,50 @@ int sieve_result_add_action
 		raction->next = NULL;
 	}	
 	
+	/* Apply any implicit side effects */
+	if ( result->implicit_seffects != NULL ) {
+		struct sieve_result_implicit_side_effects *implseff;
+		
+		/* Check for implicit side effects to this particular action */
+		implseff = (struct sieve_result_implicit_side_effects *) 
+				hash_lookup(result->implicit_seffects, action);
+		
+		if ( implseff != NULL ) {
+			struct sieve_result_side_effect *iseff;
+			
+			/* Iterate through all implicit side effects and add those that are 
+			 * missing.
+			 */
+			iseff = implseff->seffects->first_effect;
+			while ( iseff != NULL ) {
+				struct sieve_result_side_effect *seff;
+				bool exists = FALSE;
+				
+				/* Scan for presence */
+				if ( seffects != NULL ) {
+					seff = seffects->first_effect;
+					while ( seff != NULL ) {
+						if ( seff->seffect == iseff->seffect ) {
+							exists = TRUE;
+							break;
+						}
+					
+						seff = seff->next;
+					}
+				} else {
+					raction->seffects = seffects = sieve_side_effects_list_create(result);
+				}
+				
+				/* If not present, add it */
+				if ( !exists ) {
+					sieve_side_effects_list_add(seffects, iseff->seffect, iseff->context);
+				}
+				
+				iseff = iseff->next;
+			}
+		}
+	}
+	
 	return 0;
 }	
 
@@ -197,7 +305,7 @@ bool sieve_result_print(struct sieve_result *result)
 
 	
 		if ( act->print != NULL ) {
-			act->print(act, rac->context, &keep);
+			act->print(act, result, rac->context, &keep);
 		} else {
 			printf("* %s\n", act->name); 
 		}
@@ -208,7 +316,7 @@ bool sieve_result_print(struct sieve_result *result)
 			sef = rsef->seffect;
 			if ( sef->print != NULL ) 
 				sef->print
-					(sef, act, rsef->context, &keep);
+					(sef, act, result, rsef->context, &keep);
 			rsef = rsef->next;
 		}
 
@@ -418,7 +526,7 @@ void sieve_side_effects_list_add
 {
 	struct sieve_result_side_effect *reffect;
 	
-	/* Create new action object */
+	/* Create new side effect object */
 	reffect = p_new(list->result->pool, struct sieve_result_side_effect, 1);
 	reffect->seffect = seffect;
 	reffect->context = context;
diff --git a/src/lib-sieve/sieve-result.h b/src/lib-sieve/sieve-result.h
index 8db7ca630..f5917cc8a 100644
--- a/src/lib-sieve/sieve-result.h
+++ b/src/lib-sieve/sieve-result.h
@@ -13,6 +13,11 @@ void sieve_result_ref(struct sieve_result *result);
 void sieve_result_unref(struct sieve_result **result); 
 pool_t sieve_result_pool(struct sieve_result *result);
 
+void sieve_result_extension_set_context
+	(struct sieve_result *result, int ext_id, void *context);
+const void *sieve_result_extension_get_context
+	(struct sieve_result *result, int ext_id); 
+
 /* Error handling */
 
 void sieve_result_log
@@ -22,6 +27,10 @@ void sieve_result_error
 	(const struct sieve_action_exec_env *aenv, const char *fmt, ...)
 		ATTR_FORMAT(2, 3);
 
+void sieve_result_add_implicit_side_effect
+(struct sieve_result *result, const struct sieve_action *to_action, 
+	const struct sieve_side_effect *seffect, void *context);
+	
 int sieve_result_add_action
 (const struct sieve_runtime_env *renv,
 	const struct sieve_action *action, struct sieve_side_effects_list *seffects,
-- 
GitLab