From 44fe503fc6f2c30a342e4c50a780ef2db474b4e7 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Thu, 29 Nov 2007 18:02:05 +0100
Subject: [PATCH] Properly implemented handling of the implicit keep flag and
 fully implemented the copy extension.

---
 README                                |  4 +--
 src/lib-sieve/cmd-discard.c           | 43 +++++++++++++++++++++++++--
 src/lib-sieve/cmd-keep.c              |  8 ++---
 src/lib-sieve/cmd-redirect.c          | 15 ++++++----
 src/lib-sieve/ext-fileinto.c          |  3 +-
 src/lib-sieve/plugins/copy/ext-copy.c | 36 ++++++++++++----------
 src/lib-sieve/sieve-actions.c         | 19 +++++++-----
 src/lib-sieve/sieve-actions.h         | 10 +++++--
 src/lib-sieve/sieve-result.c          | 42 ++++++++++++++++++--------
 9 files changed, 124 insertions(+), 56 deletions(-)

diff --git a/README b/README
index 64d543fd2..9b99d7159 100644
--- a/README
+++ b/README
@@ -77,8 +77,8 @@ Extensions and their implementation status:
     relational: full 
     regex: full, but suboptimal
     vacation: validation, generation and interpretation; no execution
-    imapflags: flag management works, but flags are not stored (no :flags)
-    copy: copy tag is activated for redirect and fileinto, nothing else
+    imapflags: flag management works, but flags are not stored 
+    copy: full
     include: planned (* first leave out variables support)  
 	variables: planned (* also amend previously implemented extensions)
     body: planned                        
diff --git a/src/lib-sieve/cmd-discard.c b/src/lib-sieve/cmd-discard.c
index e03bd1f03..d165b8228 100644
--- a/src/lib-sieve/cmd-discard.c
+++ b/src/lib-sieve/cmd-discard.c
@@ -43,6 +43,24 @@ const struct sieve_opcode cmd_discard_opcode = {
 	opc_discard_execute 
 };
 
+/* discard action */
+
+static void act_discard_print
+	(const struct sieve_action *action, 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);
+		
+const struct sieve_action act_discard = {
+	"discard",
+	NULL,	NULL,
+	act_discard_print,
+	NULL, NULL,
+	act_discard_commit,
+	NULL
+};
+
+
 /*
  * Generation
  */
@@ -67,9 +85,30 @@ static bool opc_discard_execute
 {	
 	printf(">> DISCARD\n");
 	
-	sieve_result_cancel_implicit_keep(renv->result);
-	
+	(void) sieve_result_add_action(renv, &act_discard, NULL, NULL);
+
 	return TRUE;
 }
 
+/*
+ * Action
+ */
+ 
+static void act_discard_print
+(const struct sieve_action *action ATTR_UNUSED, void *context ATTR_UNUSED, 
+	bool *keep)	
+{
+	printf("* discard\n");
+	
+	*keep = FALSE;
+}
+
+static bool act_discard_commit
+(const struct sieve_action *action ATTR_UNUSED, 
+	const struct sieve_action_exec_env *aenv ATTR_UNUSED, 
+	void *tr_context ATTR_UNUSED, bool *keep)
+{
+	*keep = FALSE;
+  return TRUE;
+}
 
diff --git a/src/lib-sieve/cmd-keep.c b/src/lib-sieve/cmd-keep.c
index 7c5930908..87b369562 100644
--- a/src/lib-sieve/cmd-keep.c
+++ b/src/lib-sieve/cmd-keep.c
@@ -66,7 +66,6 @@ static bool opc_keep_execute
 	sieve_size_t *address ATTR_UNUSED)
 {	
 	struct sieve_side_effects_list *slist = NULL;
-	bool added = FALSE;
 	
 	printf(">> KEEP\n");
 	
@@ -74,13 +73,10 @@ static bool opc_keep_execute
 		return FALSE;
 	
 	if ( renv->mailenv != NULL && renv->mailenv->inbox != NULL )
-		added = sieve_act_store_add_to_result(renv,	slist, renv->mailenv->inbox);
+		(void) sieve_act_store_add_to_result(renv,	slist, renv->mailenv->inbox);
 	else
-		added = sieve_act_store_add_to_result(renv,	slist, "INBOX");
+		(void) sieve_act_store_add_to_result(renv,	slist, "INBOX");
 	
-	if ( added ) 
-		sieve_result_cancel_implicit_keep(renv->result);
-		
 	return TRUE;
 }
 
diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index 9325e8305..2ceb9d520 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -55,10 +55,10 @@ static bool 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);	
+	(const struct sieve_action *action, 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);
+	const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep);
 		
 struct act_redirect_context {
 	const char *to_address;
@@ -154,8 +154,7 @@ static bool cmd_redirect_opcode_execute
 	act = p_new(pool, struct act_redirect_context, 1);
 	act->to_address = p_strdup(pool, str_c(redirect));
 	
-	if ( sieve_result_add_action(renv, &act_redirect, slist, (void *) act) )
-		sieve_result_cancel_implicit_keep(renv->result);
+	(void) sieve_result_add_action(renv, &act_redirect, slist, (void *) act);
 	
 	t_pop();
 	return TRUE;
@@ -180,16 +179,18 @@ static bool act_redirect_check_duplicate
 }
 
 static void act_redirect_print
-(const struct sieve_action *action ATTR_UNUSED, void *context)	
+(const struct sieve_action *action ATTR_UNUSED, void *context, bool *keep)	
 {
 	struct act_redirect_context *ctx = (struct act_redirect_context *) context;
 	
 	printf("* redirect message to: %s\n", ctx->to_address);
+	
+	*keep = FALSE;
 }
 
 static bool act_redirect_commit
 (const struct sieve_action *action ATTR_UNUSED, 
-	const struct sieve_action_exec_env *aenv, void *tr_context)
+	const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep)
 {
 	const struct sieve_message_data *msgdata = aenv->msgdata;
 	struct act_redirect_context *ctx = (struct act_redirect_context *) tr_context;
@@ -200,6 +201,8 @@ static bool act_redirect_commit
 		i_info("msgid=%s: forwarded to <%s>",
 			msgdata->id == NULL ? "" : str_sanitize(msgdata->id, 80),
 			str_sanitize(ctx->to_address, 80));
+
+		*keep = FALSE;
   	return TRUE;
   }
   
diff --git a/src/lib-sieve/ext-fileinto.c b/src/lib-sieve/ext-fileinto.c
index 1789151a8..052fd577a 100644
--- a/src/lib-sieve/ext-fileinto.c
+++ b/src/lib-sieve/ext-fileinto.c
@@ -162,8 +162,7 @@ static bool ext_fileinto_opcode_execute
 
 	printf(">> FILEINTO \"%s\"\n", str_c(folder));
 
-	if ( sieve_act_store_add_to_result(renv, slist, str_c(folder)) )
-		sieve_result_cancel_implicit_keep(renv->result);
+	(void) sieve_act_store_add_to_result(renv, slist, str_c(folder));
 
 	t_pop();
 	return TRUE;
diff --git a/src/lib-sieve/plugins/copy/ext-copy.c b/src/lib-sieve/plugins/copy/ext-copy.c
index 11c21d738..d1b23be25 100644
--- a/src/lib-sieve/plugins/copy/ext-copy.c
+++ b/src/lib-sieve/plugins/copy/ext-copy.c
@@ -3,8 +3,8 @@
  *
  * Authors: Stephan Bosch
  * Specification: RFC 3894
- * Implementation: 
- * Status: under development
+ * Implementation: full
+ * Status: experimental, largely untested
  * 
  */
 
@@ -52,6 +52,9 @@ static bool ext_copy_load(int ext_id)
 
 const struct sieve_side_effect_extension ext_copy_side_effect;
 
+void seff_copy_print
+	(const struct sieve_side_effect *seffect,	const struct sieve_action *action, 
+		void *se_context, bool *keep);
 bool seff_copy_pre_execute
 	(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
 		const struct sieve_action_exec_env *aenv, void **se_context, 
@@ -59,7 +62,7 @@ bool seff_copy_pre_execute
 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);
+			void *tr_context, bool *keep);
 
 const struct sieve_side_effect copy_side_effect = {
 	"copy",
@@ -67,8 +70,8 @@ const struct sieve_side_effect copy_side_effect = {
 	
 	&ext_copy_side_effect,
 	0,
-	seff_copy_pre_execute, 
-	NULL, 
+	seff_copy_print,
+	NULL, NULL,
 	seff_copy_post_commit, 
 	NULL
 };
@@ -122,21 +125,24 @@ static const struct sieve_argument copy_tag = {
 
 /* Side effect execution */
 
-bool seff_copy_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)
+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)
 {
-	printf("        + implicit keep preserved\n");
-	return TRUE;
+	printf("        + preserve implicit keep\n");
+
+	*keep = TRUE;
 }
 
 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)
+(const struct sieve_side_effect *seffect ATTR_UNUSED, 
+	const struct sieve_action *action, 
+	const struct sieve_action_exec_env *aenv ATTR_UNUSED, 
+		void *se_context ATTR_UNUSED,	void *tr_context ATTR_UNUSED, bool *keep)
 {	
-	printf("        + implicit keep restored\n");
+	i_info("implicit keep preserved after %s action.", action->name);
+	*keep = TRUE;
 	return TRUE;
 }
 
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index 1d41439d6..48e9b4c55 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -126,7 +126,7 @@ static bool act_store_check_duplicate
 		const struct sieve_action *action1 ATTR_UNUSED, 
 		void *context1, void *context2);
 static void act_store_print
-	(const struct sieve_action *action ATTR_UNUSED, void *context);
+	(const struct sieve_action *action ATTR_UNUSED, void *context, bool *keep);
 
 static bool act_store_start
 	(const struct sieve_action *action,
@@ -136,7 +136,7 @@ static bool act_store_execute
 		const struct sieve_action_exec_env *aenv, void *tr_context);
 static bool act_store_commit
 	(const struct sieve_action *action, 
-		const struct sieve_action_exec_env *aenv, void *tr_context);
+		const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep);
 static void act_store_rollback
 	(const struct sieve_action *action, 
 		const struct sieve_action_exec_env *aenv, void *tr_context, bool success);
@@ -184,11 +184,13 @@ static bool act_store_check_duplicate
 }
 
 static void act_store_print
-(const struct sieve_action *action ATTR_UNUSED, void *context)	
+(const struct sieve_action *action ATTR_UNUSED, void *context, bool *keep)	
 {
 	struct act_store_context *ctx = (struct act_store_context *) context;
 	
 	printf("* store message in folder: %s\n", ctx->folder);
+	
+	*keep = FALSE;
 }
 
 /* Store transaction */
@@ -274,7 +276,7 @@ static void act_store_log_status
 		mailbox_name = str_sanitize(mailbox_get_name(trans->box), 80);
 
 	if (!rolled_back && status) {
-		i_info("msgid=%s: saved mail to %s", msgid, mailbox_name);
+		i_info("msgid=%s: stored mail into mailbox '%s'", msgid, mailbox_name);
 	} else {
 		const char *errstr;
 		enum mail_error error;
@@ -285,15 +287,16 @@ static void act_store_log_status
 			errstr = mail_storage_get_last_error(trans->namespace->storage, &error);
 
 		if ( status )
-			i_info("msgid=%s: save to %s aborted.", msgid, mailbox_name);
+			i_info("msgid=%s: store into mailbox '%s' aborted.", msgid, mailbox_name);
 		else
-			i_info("msgid=%s: save failed to %s: %s", msgid, mailbox_name, errstr);
+			i_info("msgid=%s: failed to store into mailbox '%s': %s", 
+				msgid, mailbox_name, errstr);
 	}
 }
 
 static bool act_store_commit
 (const struct sieve_action *action ATTR_UNUSED, 
-	const struct sieve_action_exec_env *aenv, void *tr_context)
+	const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep)
 {  
 	struct act_store_transaction *trans = 
 		(struct act_store_transaction *) tr_context;
@@ -301,6 +304,8 @@ static bool act_store_commit
 	
 	act_store_log_status(trans, aenv->msgdata, FALSE, status);
 	
+	*keep = !status;
+	
 	if ( trans->box != NULL )
 		mailbox_close(&trans->box);
 	
diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h
index 75058cf4c..57d804042 100644
--- a/src/lib-sieve/sieve-actions.h
+++ b/src/lib-sieve/sieve-actions.h
@@ -26,7 +26,7 @@ struct sieve_action {
 			void *context1);
 
 	void (*print)
-		(const struct sieve_action *action, void *context);	
+		(const struct sieve_action *action, void *context, bool *keep);	
 		
 	bool (*start)
 		(const struct sieve_action *action, 
@@ -37,7 +37,7 @@ struct sieve_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);
+			const struct sieve_action_exec_env *aenv, void *tr_context, bool *keep);
 	void (*rollback)
 		(const struct sieve_action *action, 
 			const struct sieve_action_exec_env *aenv, void *tr_context, bool success);
@@ -54,6 +54,10 @@ struct sieve_side_effect {
 	const struct sieve_side_effect_extension *extension;
 	unsigned int ext_code;
 
+	void (*print)
+		(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
+			void *se_context, bool *keep);
+
 	bool (*pre_execute)
 		(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
 			const struct sieve_action_exec_env *aenv, void **se_context, 
@@ -65,7 +69,7 @@ struct sieve_side_effect {
 	bool (*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);
+			void *tr_context, bool *keep);
 	void (*rollback)
 		(const struct sieve_side_effect *seffect, const struct sieve_action *action, 
 			const struct sieve_action_exec_env *aenv, void *se_context,
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index ae5d8043e..93cd5c518 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -38,8 +38,6 @@ struct sieve_result {
 	struct sieve_action_exec_env action_env;
 	struct sieve_result_action *first_action;
 	struct sieve_result_action *last_action;
-	
-	unsigned int implicit_keep:1; 
 };
 
 struct sieve_result *sieve_result_create(void) 
@@ -54,8 +52,6 @@ struct sieve_result *sieve_result_create(void)
 		
 	result->first_action = NULL;
 	result->last_action = NULL;
-	
-	result->implicit_keep = TRUE;
 
 	return result;
 }
@@ -80,11 +76,6 @@ inline pool_t sieve_result_pool(struct sieve_result *result)
 	return result->pool;
 }
 
-void sieve_result_cancel_implicit_keep(struct sieve_result *result)
-{
-	result->implicit_keep = FALSE;
-}
-
 bool sieve_result_add_action
 (const struct sieve_runtime_env *renv,
 	const struct sieve_action *action, struct sieve_side_effects_list *seffects,
@@ -146,21 +137,38 @@ bool sieve_result_add_action
 
 bool sieve_result_print(struct sieve_result *result)
 {
+	bool implicit_keep = TRUE;
 	struct sieve_result_action *rac = result->first_action;
 	
 	printf("\nPerformed actions:\n");
 	while ( rac != NULL ) {		
+		bool keep = TRUE;
 		const struct sieve_action *act = rac->action;
+		struct sieve_result_side_effect *rsef;
+		const struct sieve_side_effect *sef;
+
 	
 		if ( act->print != NULL ) {
-			act->print(act, rac->context);	
+			act->print(act, rac->context, &keep);
 		} else {
 			printf("* %s\n", act->name); 
 		}
+	
+		/* Print side effects */
+		rsef = rac->seffects != NULL ? rac->seffects->first_effect : NULL;
+		while ( rsef != NULL ) {
+			sef = rsef->seffect;
+			if ( sef->print != NULL ) 
+				sef->print
+					(sef, act, rsef->context, &keep);
+			rsef = rsef->next;
+		}
+
+		implicit_keep = implicit_keep && keep;		
 		rac = rac->next;	
 	}
 	
-	printf("\nImplicit keep: %s\n", result->implicit_keep ? "yes" : "no");
+	printf("\nImplicit keep: %s\n", implicit_keep ? "yes" : "no");
 	
 	return TRUE;
 }
@@ -169,6 +177,7 @@ bool sieve_result_execute
 	(struct sieve_result *result, const struct sieve_message_data *msgdata,
 		const struct sieve_mail_environment *menv)
 { 
+	bool implicit_keep = TRUE;
 	bool success = TRUE, commit_ok;
 	struct sieve_result_action *rac;
 	struct sieve_result_action *last_attempted;
@@ -250,8 +259,11 @@ bool sieve_result_execute
 				rac->context : rac->tr_context;
 		
 		if ( success ) {
+			bool keep = TRUE;
+		
 			if ( act->commit != NULL ) 
-				commit_ok = act->commit(act, &result->action_env, context) && commit_ok;
+				commit_ok = act->commit(act, &result->action_env, context, &keep) && 
+					commit_ok;
 	
 			/* Execute post_commit event of side effects */
 			rsef = rac->seffects != NULL ? rac->seffects->first_effect : NULL;
@@ -259,9 +271,12 @@ bool sieve_result_execute
 				sef = rsef->seffect;
 				if ( sef->post_commit != NULL ) 
 					sef->post_commit
-						(sef, act, &result->action_env, rsef->context, context);
+						(sef, act, &result->action_env, rsef->context, context, 
+							&keep);
 				rsef = rsef->next;
 			}
+			
+			implicit_keep = implicit_keep && keep;
 		} else {
 			if ( act->rollback != NULL ) 
 				act->rollback(act, &result->action_env, context, rac->success);
@@ -277,6 +292,7 @@ bool sieve_result_execute
 				rsef = rsef->next;
 			}
 		}
+		
 		rac = rac->next;	
 	}
 	
-- 
GitLab