From 99cf7d6448a2a9dc3e01a8f954e02f6c5412de2b Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 7 Aug 2009 23:21:07 +0200
Subject: [PATCH] Sieve-filter: added support for setting flags on message in
 the source folder.

---
 src/lib-sieve/plugins/imap4flags/tag-flags.c |  38 +-----
 src/lib-sieve/sieve-actions.c                | 122 ++++++++++++++++---
 src/lib-sieve/sieve-actions.h                |   7 +-
 3 files changed, 113 insertions(+), 54 deletions(-)

diff --git a/src/lib-sieve/plugins/imap4flags/tag-flags.c b/src/lib-sieve/plugins/imap4flags/tag-flags.c
index 7c621d8f2..5755f05f6 100644
--- a/src/lib-sieve/plugins/imap4flags/tag-flags.c
+++ b/src/lib-sieve/plugins/imap4flags/tag-flags.c
@@ -395,47 +395,17 @@ static bool seff_flags_pre_execute
 	void **se_context, void *tr_context)
 {	
 	struct seff_flags_context *ctx = (struct seff_flags_context *) *se_context;
-	struct act_store_transaction *trans = 
-		(struct act_store_transaction *) tr_context;
+	const char *const *keywords;
 		
 	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 ) {
-		unsigned int i;
-
-		if ( !array_is_created(&trans->keywords) ) {
-			pool_t pool = sieve_result_pool(aenv->result); 
-			p_array_init(&trans->keywords, pool, 2);
-		}
 		
-		for ( i = 0; i < array_count(&ctx->keywords); i++ ) {		
-			const char *const *keyword = array_idx(&ctx->keywords, i);
-			const char *kw_error;
-
-			if ( trans->box != NULL ) {
-				if ( mailbox_keyword_is_valid(trans->box, *keyword, &kw_error) )
-					array_append(&trans->keywords, keyword, 1);
-				else {
-					char *error = "";
-					if ( kw_error != NULL && *kw_error != '\0' ) {
-						error = t_strdup_noconst(kw_error);
-						error[0] = i_tolower(error[0]);
-					}
-				
-					sieve_result_warning(aenv, 
-						"specified IMAP keyword '%s' is invalid (ignored): %s", 
-						str_sanitize(*keyword, 64), error);
-				}
-			}
-		}
-	}
+	(void)array_append_space(&ctx->keywords);
+	keywords = array_idx(&ctx->keywords, 0);
 
-	/* Assign mail flags for subsequent mailbox_copy() */
-	trans->flags |= ctx->flags;
+	sieve_act_store_add_flags(aenv, tr_context, keywords, ctx->flags);
 	
 	return TRUE;
 }
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index fdedc7e5b..9e9c845f8 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -15,6 +15,8 @@
 #include "sieve-result.h"
 #include "sieve-actions.h"
 
+#include <ctype.h>
+
 /*
  * Action execution environment
  */
@@ -119,6 +121,53 @@ int sieve_act_store_add_to_result
 		source_line, (void *) act, 0);
 }
 
+void sieve_act_store_add_flags
+(const struct sieve_action_exec_env *aenv, void *tr_context,
+	const char *const *keywords, enum mail_flags flags)
+{
+	struct act_store_transaction *trans = 
+		(struct act_store_transaction *) tr_context;
+
+	/* Assign mail keywords for subsequent mailbox_copy() */
+	if ( *keywords != NULL ) {
+		const char *const *kw;
+
+		if ( !array_is_created(&trans->keywords) ) {
+			pool_t pool = sieve_result_pool(aenv->result); 
+			p_array_init(&trans->keywords, pool, 2);
+		}
+		
+		kw = keywords;
+		while ( *kw != NULL ) {
+
+			const char *kw_error;
+
+			if ( trans->box != NULL ) {
+				if ( mailbox_keyword_is_valid(trans->box, *kw, &kw_error) )
+					array_append(&trans->keywords, kw, 1);
+				else {
+					char *error = "";
+					if ( kw_error != NULL && *kw_error != '\0' ) {
+						error = t_strdup_noconst(kw_error);
+						error[0] = i_tolower(error[0]);
+					}
+				
+					sieve_result_warning(aenv, 
+						"specified IMAP keyword '%s' is invalid (ignored): %s", 
+						str_sanitize(*kw, 64), error);
+				}
+			}
+
+			kw++;
+		}
+	}
+
+	/* Assign mail flags for subsequent mailbox_copy() */
+	trans->flags |= flags;
+
+	trans->flags_altered = TRUE;
+}
+
 /* Equality */
 
 static bool act_store_equals
@@ -322,21 +371,64 @@ static bool act_store_start
 	return ( disabled || redundant || (box != NULL) );
 }
 
+static struct mail_keywords *act_store_keywords_create
+(const struct sieve_action_exec_env *aenv, ARRAY_TYPE(const_string) *keywords, 
+	struct mailbox *box)
+{
+	struct mail_keywords *box_keywords = NULL;
+	
+	if ( array_is_created(keywords) && array_count(keywords) > 0 ) 
+	{
+		const char *const *kwds;
+		
+		(void)array_append_space(keywords);
+		kwds = array_idx(keywords, 0);
+				
+		/* FIXME: Do we need to clear duplicates? */
+		if ( mailbox_keywords_create(box, kwds, &box_keywords) < 0) {
+			sieve_result_error(aenv, "invalid keywords set for stored message");
+			return NULL;
+		}
+	}
+
+	return box_keywords;	
+}
+
 static bool act_store_execute
 (const struct sieve_action *action ATTR_UNUSED, 
 	const struct sieve_action_exec_env *aenv, void *tr_context)
 {   
 	struct act_store_transaction *trans = 
 		(struct act_store_transaction *) tr_context;
-	struct mail_keywords *keywords = NULL;
+	const struct sieve_message_data *msgdata = aenv->msgdata;
 	struct mail_save_context *save_ctx;
+	struct mail_keywords *keywords = NULL;
 	bool result = TRUE;
 	
 	/* Verify transaction */
 	if ( trans == NULL ) return FALSE;
 
 	/* Check whether we need to do anything */
-	if ( trans->disabled || trans->redundant ) return TRUE;
+	if ( trans->disabled ) return TRUE;
+
+	/* If the message originates from the target mailbox, only update the flags 
+	 * and keywords 
+	 */
+	if ( trans->redundant ) {
+		if ( trans->flags_altered ) {
+			keywords = act_store_keywords_create
+				(aenv, &trans->keywords, msgdata->mail->box);
+
+			if ( keywords != NULL ) {
+				mail_update_keywords(msgdata->mail, MODIFY_REPLACE, keywords);
+				mailbox_keywords_free(trans->box, &keywords);
+			}
+
+			mail_update_flags(msgdata->mail, MODIFY_REPLACE, trans->flags);
+		}
+
+		return TRUE;
+	}
 
 	/* Exit early if namespace or mailbox are not available */
 	if ( trans->namespace == NULL )
@@ -360,26 +452,18 @@ static bool act_store_execute
 
 	/* Create mail object for stored message */
 	trans->dest_mail = mail_alloc(trans->mail_trans, 0, NULL);
-
-	/* Collect keywords added by side-effects */
-	if ( array_is_created(&trans->keywords) && array_count(&trans->keywords) > 0 ) 
-	{
-		const char *const *kwds;
-		
-		(void)array_append_space(&trans->keywords);
-		kwds = array_idx(&trans->keywords, 0);
-				
-		/* FIXME: Do we need to clear duplicates? */
-		if ( mailbox_keywords_create(trans->box, kwds, &keywords) < 0) {
-			sieve_result_error(aenv, "invalid keywords set for stored message");
-			keywords = NULL;
-		}
-	}
-	
+ 
 	/* Store the message */
 	save_ctx = mailbox_save_alloc(trans->mail_trans);
-	mailbox_save_set_flags(save_ctx, trans->flags, keywords);
 	mailbox_save_set_dest_mail(save_ctx, trans->dest_mail);
+
+	/* Apply keywords and flags that side-effects may have added */
+	if ( trans->flags_altered ) {
+		keywords = act_store_keywords_create(aenv, &trans->keywords, trans->box);
+		
+		mailbox_save_set_flags(save_ctx, trans->flags, keywords);
+	}
+
 	if ( mailbox_copy(&save_ctx, aenv->msgdata->mail) < 0 ) {
 		act_store_get_storage_error(aenv, trans);
  		result = FALSE;
diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h
index 81b32fc13..c9128a8cb 100644
--- a/src/lib-sieve/sieve-actions.h
+++ b/src/lib-sieve/sieve-actions.h
@@ -199,8 +199,9 @@ struct act_store_transaction {
 	const char *error;
 	
 	enum mail_flags flags;
-	ARRAY_DEFINE(keywords, const char *);
+	ARRAY_TYPE(const_string) keywords;
 
+	unsigned int flags_altered:1;
 	unsigned int disabled:1;
 	unsigned int redundant:1;
 };
@@ -210,6 +211,10 @@ int sieve_act_store_add_to_result
 		struct sieve_side_effects_list *seffects, const char *folder,
 		unsigned int source_line);
 
+void sieve_act_store_add_flags
+	(const struct sieve_action_exec_env *aenv, void *tr_context,
+		const char *const *keywords, enum mail_flags flags);
+
 /*		
  * Action utility functions
  */
-- 
GitLab