From 6cf3d1d3fcfeb59527a12803d72728a7ec57fcf3 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Tue, 27 Nov 2007 01:12:29 +0100
Subject: [PATCH] Turned action execution into a transaction.

---
 src/lib-sieve/cmd-keep.c      |  1 +
 src/lib-sieve/cmd-redirect.c  | 19 ++++----
 src/lib-sieve/sieve-actions.c | 82 +++++++++++++++++++++++++----------
 src/lib-sieve/sieve-actions.h | 15 ++++++-
 src/lib-sieve/sieve-result.c  | 61 +++++++++++++++++++++++---
 5 files changed, 138 insertions(+), 40 deletions(-)

diff --git a/src/lib-sieve/cmd-keep.c b/src/lib-sieve/cmd-keep.c
index 13f871757..7a59bc212 100644
--- a/src/lib-sieve/cmd-keep.c
+++ b/src/lib-sieve/cmd-keep.c
@@ -2,6 +2,7 @@
 
 #include "sieve-commands.h"
 #include "sieve-commands-private.h"
+#include "sieve-actions.h"
 #include "sieve-validator.h" 
 #include "sieve-generator.h"
 #include "sieve-interpreter.h"
diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index 1dbee6daf..e6c802fae 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -56,9 +56,9 @@ static bool act_redirect_check_duplicate
 		const struct sieve_action *action1, void *context1, void *context2);
 static void act_redirect_print
 	(const struct sieve_action *action, void *context);	
-static int act_redirect_execute
-	(const struct sieve_action *action,	const struct sieve_action_exec_env *aenv, 
-		void *context);
+static bool act_redirect_commit
+(const struct sieve_action *action ATTR_UNUSED, 
+	const struct sieve_action_exec_env *aenv, void *tr_context);
 		
 struct act_redirect_context {
 	const char *to_address;
@@ -69,7 +69,9 @@ const struct sieve_action act_redirect = {
 	act_redirect_check_duplicate, 
 	NULL,
 	act_redirect_print,
-	act_redirect_execute
+	NULL, NULL,
+	act_redirect_commit,
+	NULL
 };
 
 /* Validation */
@@ -178,12 +180,12 @@ static void act_redirect_print
 	printf("* redirect message to: %s\n", ctx->to_address);
 }
 
-static int act_redirect_execute
+static bool act_redirect_commit
 (const struct sieve_action *action ATTR_UNUSED, 
-	const struct sieve_action_exec_env *aenv, void *context)
+	const struct sieve_action_exec_env *aenv, void *tr_context)
 {
 	const struct sieve_message_data *msgdata = aenv->msgdata;
-	struct act_redirect_context *ctx = (struct act_redirect_context *) context;
+	struct act_redirect_context *ctx = (struct act_redirect_context *) tr_context;
 	int res;
 	
 	if ((res = aenv->mailenv->
@@ -191,9 +193,10 @@ static int act_redirect_execute
 		i_info("msgid=%s: forwarded to <%s>",
 			msgdata->id == NULL ? "" : str_sanitize(msgdata->id, 80),
 			str_sanitize(ctx->to_address, 80));
+  	return TRUE;
   }
   
-	return res;
+	return FALSE;
 }
 
 
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index fc11fd911..a62ce74b6 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -14,18 +14,47 @@ static bool act_store_check_duplicate
 		void *context1, void *context2);
 static void act_store_print
 	(const struct sieve_action *action ATTR_UNUSED, void *context);
-static int act_store_execute
-	(const struct sieve_action *action,	const struct sieve_action_exec_env *aenv, 
-		void *context);
+
+static bool act_store_start
+	(const struct sieve_action *action,
+		const struct sieve_action_exec_env *aenv, void *context, void **tr_context);
+static bool act_store_execute
+	(const struct sieve_action *action ATTR_UNUSED, 
+		const struct sieve_action_exec_env *aenv, void *tr_context);
+static bool act_store_commit
+	(const struct sieve_action *action ATTR_UNUSED, 
+		const struct sieve_action_exec_env *aenv, void *tr_context);
+static void act_store_rollback
+	(const struct sieve_action *action ATTR_UNUSED, 
+		const struct sieve_action_exec_env *aenv, void *tr_context);
 		
 const struct sieve_action act_store = {
 	"store",
 	act_store_check_duplicate, 
 	NULL, 
 	act_store_print,
-	act_store_execute
+	act_store_start,
+	act_store_execute,
+	act_store_commit,
+	act_store_rollback,
 };
 
+bool sieve_act_store_add_to_result
+(const struct sieve_runtime_env *renv, const char *folder)
+{
+	pool_t pool;
+	struct act_store_context *act;
+	
+	/* Add redirect action to the result */
+	pool = sieve_result_pool(renv->result);
+	act = p_new(pool, struct act_store_context, 1);
+	act->folder = p_strdup(pool, folder);
+
+	return sieve_result_add_action(renv, &act_store, (void *) act);
+}
+
+/* Store action implementation */
+
 static bool act_store_check_duplicate
 (const struct sieve_runtime_env *renv ATTR_UNUSED,
 	const struct sieve_action *action1 ATTR_UNUSED, 
@@ -48,28 +77,35 @@ static void act_store_print
 	printf("* store message in folder: %s\n", ctx->folder);
 }
 
-static int act_store_execute
+/* Store transaction */
+
+static bool act_store_start
 (const struct sieve_action *action ATTR_UNUSED, 
-	const struct sieve_action_exec_env *aenv, void *context)
-{
-	const struct sieve_message_data *msgdata = aenv->msgdata;
-	struct act_store_context *ctx = (struct act_store_context *) context;
-	int res = 0;
-  
-	return res;
+	const struct sieve_action_exec_env *aenv, void *context, void **tr_context)
+{  
+	return TRUE;
 }
 
-bool sieve_act_store_add_to_result
-(const struct sieve_runtime_env *renv, const char *folder)
-{
-	pool_t pool;
-	struct act_store_context *act;
-	
-	/* Add redirect action to the result */
-	pool = sieve_result_pool(renv->result);
-	act = p_new(pool, struct act_store_context, 1);
-	act->folder = p_strdup(pool, folder);
+static bool act_store_execute
+(const struct sieve_action *action ATTR_UNUSED, 
+	const struct sieve_action_exec_env *aenv, void *tr_context)
+{  
+	return TRUE;
+}
 
-	return sieve_result_add_action(renv, &act_store, (void *) act);
+static bool act_store_commit
+(const struct sieve_action *action ATTR_UNUSED, 
+	const struct sieve_action_exec_env *aenv, void *tr_context)
+{  
+	return TRUE;
 }
 
+static void act_store_rollback
+(const struct sieve_action *action ATTR_UNUSED, 
+	const struct sieve_action_exec_env *aenv, void *tr_context)
+{  
+}
+
+
+
+
diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h
index c76d9cc91..64b298fea 100644
--- a/src/lib-sieve/sieve-actions.h
+++ b/src/lib-sieve/sieve-actions.h
@@ -21,9 +21,20 @@ struct sieve_action {
 
 	void (*print)
 		(const struct sieve_action *action, void *context);	
-	int (*execute)
+		
+	bool (*start)
+		(const struct sieve_action *action, 
+			const struct sieve_action_exec_env *aenv, void *context, 
+			void **tr_context);		
+	bool (*execute)
+		(const struct sieve_action *action, 
+			const struct sieve_action_exec_env *aenv, void *tr_context);
+	bool (*commit)
+		(const struct sieve_action *action, 
+			const struct sieve_action_exec_env *aenv, void *tr_context);
+	void (*rollback)
 		(const struct sieve_action *action, 
-			const struct sieve_action_exec_env *aenv, void *context);	
+			const struct sieve_action_exec_env *aenv, void *tr_context);
 };
 
 /* Actions common to multiple commands */
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 07e7efc34..e2b4f71bf 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -11,7 +11,7 @@
 struct sieve_result_action {
 	const struct sieve_action *action;
 	void *context;
-
+	void *tr_context;
 	struct sieve_result_action *prev, *next; 
 };
 
@@ -104,6 +104,7 @@ bool sieve_result_add_action
 	raction = p_new(result->pool, struct sieve_result_action, 1);
 	raction->action = action;
 	raction->context = context;
+	raction->tr_context = NULL;
 	
 	/* Add */
 	if ( result->first_action == NULL ) {
@@ -146,22 +147,68 @@ bool sieve_result_execute
 	(struct sieve_result *result, const struct sieve_message_data *msgdata,
 		const struct sieve_mail_environment *menv)
 { 
-	struct sieve_result_action *rac = result->first_action;
+	bool success = TRUE, commit_ok;
+	struct sieve_result_action *rac;
 	
 	result->action_env.msgdata = msgdata;
 	result->action_env.mailenv = menv;
 	
-	printf("\n");
-	while ( rac != NULL ) {
+	/* Transaction start */
+	
+	printf("\nTransaction start:\n");
+	
+	rac = result->first_action;
+	while ( success && rac != NULL ) {
+		const struct sieve_action *act = rac->action;
+	
+		if ( act->start != NULL ) {
+			success = success && act->start(act, &result->action_env, rac->context, 
+				&rac->tr_context);
+		} 
+		rac = rac->next;	
+	}
+	
+	/* Transaction execute */
+	
+	printf("\nTransaction execute:\n");
+	
+	rac = result->first_action;
+	while ( success && rac != NULL ) {
 		const struct sieve_action *act = rac->action;
 	
 		if ( act->execute != NULL ) {
-			(void) act->execute(act, &result->action_env, rac->context);
+			void *context = rac->tr_context == NULL ? 
+				rac->context : rac->tr_context;
+				
+			success = success && act->execute(act, &result->action_env, context);
+		} 
+		rac = rac->next;	
+	}
+	
+	/* Transaction commit/rollback */
+	if ( success )
+		printf("\nTransaction commit:\n");
+	else
+		printf("\nTransaction rollback:\n");
+
+	commit_ok = success;
+	rac = result->first_action;
+	while ( rac != NULL ) {
+		const struct sieve_action *act = rac->action;
+		void *context = rac->tr_context == NULL ? 
+				rac->context : rac->tr_context;
+		
+		if ( success ) {
+			if ( act->commit != NULL ) 
+				commit_ok = act->commit(act, &result->action_env, context) && commit_ok;
 		} else {
-			i_warning("Action %s performs absolutely nothing.", act->name);	
+			if ( act->rollback != NULL ) 
+				act->rollback(act, &result->action_env, context);
 		}
 		rac = rac->next;	
 	}
 	
-	return TRUE;
+	printf("\nTransaction result: %s\n", commit_ok ? "success" : "failed");
+	
+	return commit_ok;
 }
-- 
GitLab