From 2b6bc9234a65ef209c6efcda023a3ecf86b27e65 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Fri, 30 Nov 2007 21:56:55 +0100
Subject: [PATCH] Further developed imapflags extension and added proper
 logging functions to the result object.

---
 .../plugins/imapflags/ext-imapflags-common.c  |   2 +-
 .../plugins/imapflags/ext-imapflags-common.h  |   3 +
 .../plugins/imapflags/imapflags.sieve         |   8 +-
 src/lib-sieve/plugins/imapflags/tag-flags.c   | 109 +++++++++++++-----
 src/lib-sieve/sieve-actions.c                 |  43 ++++---
 src/lib-sieve/sieve-actions.h                 |   1 +
 src/lib-sieve/sieve-result.c                  |  37 ++++++
 src/lib-sieve/sieve-result.h                  |   5 +
 src/lib-sieve/sieve-validator.c               |   8 +-
 9 files changed, 156 insertions(+), 60 deletions(-)

diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
index 5f88019bc..871bd5e74 100644
--- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
+++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.c
@@ -131,7 +131,7 @@ static bool flag_is_valid(const char *flag)
 	return TRUE;  
 }
 
-static void ext_imapflags_iter_init
+void ext_imapflags_iter_init
 	(struct ext_imapflags_iter *iter, string_t *flags_list) 
 {
 	iter->flags_list = flags_list;
diff --git a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
index 087e3ec20..e50b6fb0b 100644
--- a/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
+++ b/src/lib-sieve/plugins/imapflags/ext-imapflags-common.h
@@ -31,6 +31,9 @@ struct ext_imapflags_iter {
 	unsigned int offset;
 	unsigned int last;
 };
+
+void ext_imapflags_iter_init
+	(struct ext_imapflags_iter *iter, string_t *flags_list);
 	
 const char *ext_imapflags_iter_get_flag
 	(struct ext_imapflags_iter *iter);
diff --git a/src/lib-sieve/plugins/imapflags/imapflags.sieve b/src/lib-sieve/plugins/imapflags/imapflags.sieve
index a05a2f68b..44a39ec7c 100644
--- a/src/lib-sieve/plugins/imapflags/imapflags.sieve
+++ b/src/lib-sieve/plugins/imapflags/imapflags.sieve
@@ -9,7 +9,7 @@ removeflag "$DSNRequired";
 
 if header :contains "from" "boss@frobnitzm.example.edu" {
 	setflag "\\Flagged";
-	fileinto "INBOX.From Boss";
+	fileinto "From Boss";
 }
 
 if header :contains "Disposition-Notification-To" "mel@example.com" {
@@ -18,11 +18,11 @@ if header :contains "Disposition-Notification-To" "mel@example.com" {
 
 if header :contains "from" "imap@cac.washington.example.edu" {
 	removeflag "$MDNRequired \\Flagged \\Seen \\Deleted";
-	fileinto "INBOX.imap-list";
+	fileinto "imap-list";
 }
 
 if hasflag :count "ge" :comparator "i;ascii-numeric" "2" {
-	fileinto "INBOX.imap-twoflags";
+	fileinto "imap-twoflags";
 }
 
-fileinto :flags "\\Seen" "INBOX";
+fileinto :flags "\\Seen $MDNRequired \\Draft" "INBOX";
diff --git a/src/lib-sieve/plugins/imapflags/tag-flags.c b/src/lib-sieve/plugins/imapflags/tag-flags.c
index ea9257486..9aa9e961a 100644
--- a/src/lib-sieve/plugins/imapflags/tag-flags.c
+++ b/src/lib-sieve/plugins/imapflags/tag-flags.c
@@ -1,5 +1,6 @@
 #include "lib.h"
 #include "array.h"
+#include "mail-storage.h"
 
 #include "sieve-extensions.h"
 #include "sieve-commands.h"
@@ -38,14 +39,10 @@ bool seff_flags_read
 void seff_flags_print
 	(const struct sieve_side_effect *seffect,	const struct sieve_action *action, 
 		void *se_context, bool *keep);
-bool seff_flags_pre_execute
+bool seff_flags_post_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);
-bool seff_flags_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_action_exec_env *aenv, 
+		void *se_context, void *tr_context);
 
 const struct sieve_side_effect flags_side_effect = {
 	"flags",
@@ -55,9 +52,9 @@ const struct sieve_side_effect flags_side_effect = {
 	0,
 	seff_flags_read,
 	seff_flags_print,
-	NULL, NULL,
-	seff_flags_post_commit, 
-	NULL
+	NULL,
+	seff_flags_post_execute, 
+	NULL, NULL
 };
 
 const struct sieve_side_effect_extension imapflags_seffect_extension = {
@@ -120,17 +117,24 @@ static bool tag_flags_generate
 
 /* Side effect execution */
 
+struct seff_flags_context {
+	const char *const *keywords;
+	enum mail_flags flags;
+};
+
 bool seff_flags_read
 (const struct sieve_side_effect *seffect ATTR_UNUSED, 
 	const struct sieve_runtime_env *renv, sieve_size_t *address,
 	void **se_context)
 {
 	pool_t pool = sieve_result_pool(renv->result);
-	ARRAY_DEFINE(flags, const char *);
-	string_t *flag_item;
+	struct seff_flags_context *ctx;
+	ARRAY_DEFINE(keywords, const char *);
+	string_t *flags_item;
 	struct sieve_coded_stringlist *flag_list;
 	
-	p_array_init(&flags, pool, 2);
+	ctx = p_new(pool, struct seff_flags_context, 1);
+	p_array_init(&keywords, pool, 2);
 	
 	t_push();
 	
@@ -141,16 +145,37 @@ bool seff_flags_read
 	}
 	
 	/* Iterate through all requested headers to match */
-	flag_item = NULL;
-	while ( sieve_coded_stringlist_next_item(flag_list, &flag_item) && 
-		flag_item != NULL ) {
-		const char *flag = str_c(flag_item);
-		
-		array_append(&flags, &flag, 1);
+	flags_item = NULL;
+	while ( sieve_coded_stringlist_next_item(flag_list, &flags_item) && 
+		flags_item != NULL ) {
+		const char *flag;
+		struct ext_imapflags_iter flit;
+
+		ext_imapflags_iter_init(&flit, flags_item);
+	
+		while ( (flag=ext_imapflags_iter_get_flag(&flit)) != NULL ) {		
+			if (flag != NULL && *flag != '\\') {
+				/* keyword */
+				array_append(&keywords, &flag, 1);
+			} else {
+				/* system flag */
+				if (flag == NULL || strcasecmp(flag, "\\flagged") == 0)
+					ctx->flags |= MAIL_FLAGGED;
+				else if (strcasecmp(flag, "\\answered") == 0)
+					ctx->flags |= MAIL_ANSWERED;
+				else if (strcasecmp(flag, "\\deleted") == 0)
+					ctx->flags |= MAIL_DELETED;
+				else if (strcasecmp(flag, "\\seen") == 0)
+					ctx->flags |= MAIL_SEEN;
+				else if (strcasecmp(flag, "\\draft") == 0)
+					ctx->flags |= MAIL_DRAFT;
+			}
+		}
 	}
 	
-	(void)array_append_space(&flags);
-	*se_context = (void **) array_idx(&flags, 0);
+	(void)array_append_space(&keywords);
+	ctx->keywords = array_idx(&keywords, 0);
+	*se_context = (void *) ctx;
 
 	t_pop();
 	
@@ -162,14 +187,30 @@ void seff_flags_print
 	const struct sieve_action *action ATTR_UNUSED, 
 	void *se_context ATTR_UNUSED, bool *keep)
 {
-	const char *const *flags = (const char *const *) se_context;
+	struct seff_flags_context *ctx = (struct seff_flags_context *) se_context;
+	const char *const *keywords = ctx->keywords;
 	
 	printf("        + add flags:");
 
-	while ( *flags != NULL ) {
-		printf(" %s", *flags);
+	if ( (ctx->flags & MAIL_FLAGGED) > 0 )
+		printf(" \\flagged\n");
+
+	if ( (ctx->flags & MAIL_ANSWERED) > 0 )
+		printf(" \\answered");
 		
-		flags++;
+	if ( (ctx->flags & MAIL_DELETED) > 0 )
+		printf(" \\deleted");
+					
+	if ( (ctx->flags & MAIL_SEEN) > 0 )
+		printf(" \\seen");
+		
+	if ( (ctx->flags & MAIL_DRAFT) > 0 )
+		printf(" \\draft");
+
+	while ( *keywords != NULL ) {
+		printf(" %s", *keywords);
+		
+		keywords++;
 	};
 	
 	printf("\n");
@@ -177,14 +218,22 @@ void seff_flags_print
 	*keep = TRUE;
 }
 
-bool seff_flags_post_commit
+bool seff_flags_post_execute
 (const struct sieve_side_effect *seffect ATTR_UNUSED, 
-	const struct sieve_action *action, 
+	const struct sieve_action *action ATTR_UNUSED, 
 	const struct sieve_action_exec_env *aenv ATTR_UNUSED, 
-	void *se_context ATTR_UNUSED,	void *tr_context ATTR_UNUSED, bool *keep)
+	void *se_context, void *tr_context)
 {	
-	i_info("implicit keep preserved after %s action.", action->name);
-	*keep = TRUE;
+	struct seff_flags_context *ctx = (struct seff_flags_context *) se_context;
+	struct act_store_transaction *trans = 
+		(struct act_store_transaction *) tr_context;
+
+	printf("SETTING FLAGS\n");
+	/* Update message flags. */
+	mail_update_flags(trans->dest_mail, MODIFY_ADD, ctx->flags);
+	/* Update message keywords. */
+	//mail_update_keywords(trans->dest_mail, MODIFY_REPLACE, keywords);
+	
 	return TRUE;
 }
 
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index 48e9b4c55..7a2c73a25 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -8,7 +8,9 @@
 #include "sieve-binary.h"
 #include "sieve-interpreter.h"
 #include "sieve-result.h"
-#include "sieve-actions.h"\
+#include "sieve-actions.h"
+
+#include <ctype.h>
 
 /* 
  * Side-effects 'extension' 
@@ -47,6 +49,7 @@ static inline const struct sieve_side_effect_extension *
 }
 
 void sieve_side_effect_extension_set
+
 	(struct sieve_binary *sbin, int ext_id,
 		const struct sieve_side_effect_extension *ext)
 {
@@ -114,7 +117,6 @@ const struct sieve_side_effect *sieve_opr_side_effect_read
 	return NULL; 
 }
 
-
 /*
  * Actions common to multiple core commands 
  */
@@ -228,10 +230,8 @@ static bool act_store_start
 	trans->namespace = ns;
 	trans->box = box;
 	
-	if ( box == NULL ) {
-		printf("Open failed\n");
-		act_store_get_storage_error(aenv, trans);
-	}	
+	if ( box == NULL ) 
+		act_store_get_storage_error(aenv, trans);	
 	
 	*tr_context = (void *)trans;
 
@@ -250,8 +250,10 @@ static bool act_store_execute
 	trans->mail_trans = mailbox_transaction_begin
 		(trans->box, MAILBOX_TRANSACTION_FLAG_EXTERNAL);
 
-  if (mailbox_copy(trans->mail_trans, aenv->msgdata->mail, 0, NULL, NULL) < 0) {
-  	printf("Copy failed\n");
+	trans->dest_mail = mail_alloc(trans->mail_trans, 0, NULL);
+
+  if (mailbox_copy(trans->mail_trans, aenv->msgdata->mail, MAIL_DRAFT, NULL, 
+  	trans->dest_mail) < 0) {
   	act_store_get_storage_error(aenv, trans);
  		return FALSE;
  	}
@@ -261,22 +263,17 @@ static bool act_store_execute
 
 static void act_store_log_status
 (struct act_store_transaction *trans, 
-	const struct sieve_message_data *msgdata, bool rolled_back, bool status )
+	const struct sieve_action_exec_env *aenv, bool rolled_back, bool status )
 {
-	const char *msgid, *mailbox_name;
+	const char *mailbox_name;
 	
-	if (mail_get_first_header(msgdata->mail, "Message-ID", &msgid) <= 0)
-		msgid = "";
-	else
-		msgid = str_sanitize(msgid, 80);
-
 	if ( trans->box == NULL )
 		mailbox_name = str_sanitize(trans->context->folder, 80);
 	else
 		mailbox_name = str_sanitize(mailbox_get_name(trans->box), 80);
 
 	if (!rolled_back && status) {
-		i_info("msgid=%s: stored mail into mailbox '%s'", msgid, mailbox_name);
+		sieve_result_log(aenv, "stored mail into mailbox '%s'", mailbox_name);
 	} else {
 		const char *errstr;
 		enum mail_error error;
@@ -285,12 +282,12 @@ static void act_store_log_status
 			errstr = trans->error;
 		else
 			errstr = mail_storage_get_last_error(trans->namespace->storage, &error);
-
+			
 		if ( status )
-			i_info("msgid=%s: store into mailbox '%s' aborted.", msgid, mailbox_name);
+			sieve_result_log(aenv, "store into mailbox '%s' aborted.", mailbox_name);
 		else
-			i_info("msgid=%s: failed to store into mailbox '%s': %s", 
-				msgid, mailbox_name, errstr);
+			sieve_result_error(aenv, "failed to store into mailbox '%s': %s", 
+				mailbox_name, errstr);
 	}
 }
 
@@ -302,7 +299,7 @@ static bool act_store_commit
 		(struct act_store_transaction *) tr_context;
 	bool status = mailbox_transaction_commit(&trans->mail_trans) == 0;
 	
-	act_store_log_status(trans, aenv->msgdata, FALSE, status);
+	act_store_log_status(trans, aenv, FALSE, status);
 	
 	*keep = !status;
 	
@@ -319,11 +316,11 @@ static void act_store_rollback
 	struct act_store_transaction *trans = 
 		(struct act_store_transaction *) tr_context;
 
+  act_store_log_status(trans, aenv, TRUE, success);
+
 	if ( trans->mail_trans != NULL )
 	  mailbox_transaction_rollback(&trans->mail_trans);
   
-  act_store_log_status(trans, aenv->msgdata, TRUE, success);
-
 	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 a36821be9..c3f97bd10 100644
--- a/src/lib-sieve/sieve-actions.h
+++ b/src/lib-sieve/sieve-actions.h
@@ -120,6 +120,7 @@ struct act_store_transaction {
 	struct mail_namespace *namespace;
 	struct mailbox *box;
 	struct mailbox_transaction_context *mail_trans;
+	struct mail *dest_mail;
 	const char *error;
 };
 
diff --git a/src/lib-sieve/sieve-result.c b/src/lib-sieve/sieve-result.c
index 93cd5c518..e0afc5fb2 100644
--- a/src/lib-sieve/sieve-result.c
+++ b/src/lib-sieve/sieve-result.c
@@ -1,5 +1,7 @@
 #include "lib.h"
 #include "mempool.h"
+#include "strfuncs.h"
+#include "str-sanitize.h"
 
 #include "sieve-common.h"
 #include "sieve-interpreter.h"
@@ -7,6 +9,7 @@
 #include "sieve-result.h"
 
 #include <stdio.h>
+
 struct sieve_result_action {
 	struct sieve_result *result;
 	const struct sieve_action *action;
@@ -76,6 +79,40 @@ inline pool_t sieve_result_pool(struct sieve_result *result)
 	return result->pool;
 }
 
+/* Logging of result */
+
+void sieve_result_log
+	(const struct sieve_action_exec_env *aenv, const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	
+	/* Kludgy, needs explict support from liblib.a (something like i_vinfo) */
+	
+	i_info("msgid=%s: %s", aenv->msgdata->id == NULL ? 
+		"unspecified" : str_sanitize(aenv->msgdata->id, 80), 
+		t_strdup_vprintf(fmt, args)); 
+	
+	va_end(args);
+}
+
+void sieve_result_error
+	(const struct sieve_action_exec_env *aenv, const char *fmt, ...)
+{
+	va_list args;
+	va_start(args, fmt);
+	
+	/* Kludgy, needs explict support from liblib.a (something like i_vinfo) */
+	
+	i_error("msgid=%s: %s", aenv->msgdata->id == NULL ? 
+		"unspecified" : str_sanitize(aenv->msgdata->id, 80), 
+		t_strdup_vprintf(fmt, args)); 
+	
+	va_end(args);
+}
+
+/* Result composition */
+
 bool sieve_result_add_action
 (const struct sieve_runtime_env *renv,
 	const struct sieve_action *action, struct sieve_side_effects_list *seffects,
diff --git a/src/lib-sieve/sieve-result.h b/src/lib-sieve/sieve-result.h
index 8927048e1..f982a1ed9 100644
--- a/src/lib-sieve/sieve-result.h
+++ b/src/lib-sieve/sieve-result.h
@@ -12,6 +12,11 @@ void sieve_result_ref(struct sieve_result *result);
 void sieve_result_unref(struct sieve_result **result); 
 inline pool_t sieve_result_pool(struct sieve_result *result);
 
+void sieve_result_log
+	(const struct sieve_action_exec_env *aenv, const char *fmt, ...);
+void sieve_result_error
+	(const struct sieve_action_exec_env *aenv, const char *fmt, ...);
+	
 bool sieve_result_add_action
 (const struct sieve_runtime_env *renv,
 	const struct sieve_action *action, struct sieve_side_effects_list *seffects,
diff --git a/src/lib-sieve/sieve-validator.c b/src/lib-sieve/sieve-validator.c
index 747e35718..d43d9e5d0 100644
--- a/src/lib-sieve/sieve-validator.c
+++ b/src/lib-sieve/sieve-validator.c
@@ -32,7 +32,9 @@ static void sieve_validator_register_core_tests(struct sieve_validator *validato
 
 /* Error management */
 
-void sieve_validator_warning(struct sieve_validator *validator, struct sieve_ast_node *node, const char *fmt, ...) 
+void sieve_validator_warning
+(struct sieve_validator *validator, struct sieve_ast_node *node, 
+	const char *fmt, ...) 
 { 
 	va_list args;
 	va_start(args, fmt);
@@ -42,7 +44,9 @@ void sieve_validator_warning(struct sieve_validator *validator, struct sieve_ast
 	va_end(args);
 }
  
-void sieve_validator_error(struct sieve_validator *validator, struct sieve_ast_node *node, const char *fmt, ...) 
+void sieve_validator_error
+(struct sieve_validator *validator, struct sieve_ast_node *node, 
+	const char *fmt, ...) 
 {
 	va_list args;
 	va_start(args, fmt);
-- 
GitLab