From 176c337e2a0b73b70da5dbbc1036aa1aec336443 Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Mon, 29 Apr 2019 14:57:56 +0300
Subject: [PATCH] lib-sieve: Add sieve_exec_status.significant_action_executed

---
 src/lib-sieve/cmd-discard.c                   |  1 +
 src/lib-sieve/cmd-redirect.c                  |  1 +
 src/lib-sieve/ext-reject.c                    |  1 +
 .../plugins/duplicate/ext-duplicate-common.c  |  1 +
 src/lib-sieve/plugins/enotify/cmd-notify.c    |  2 +
 src/lib-sieve/plugins/notify/cmd-notify.c     |  5 ++-
 src/lib-sieve/plugins/vacation/cmd-vacation.c |  2 +
 .../plugins/vnd.dovecot/report/cmd-report.c   |  1 +
 src/lib-sieve/sieve-actions.c                 | 43 +++++++++++++++++--
 src/lib-sieve/sieve-types.h                   |  1 +
 10 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/src/lib-sieve/cmd-discard.c b/src/lib-sieve/cmd-discard.c
index 92c710951..a5ed06677 100644
--- a/src/lib-sieve/cmd-discard.c
+++ b/src/lib-sieve/cmd-discard.c
@@ -154,6 +154,7 @@ static int act_discard_commit
 	const struct sieve_action_exec_env *aenv,
 	void *tr_context ATTR_UNUSED, bool *keep)
 {
+	aenv->exec_status->significant_action_executed = TRUE;
 	sieve_result_global_log(aenv,
 		"marked message to be discarded if not explicitly delivered "
 		"(discard action)");
diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c
index 0647ce11d..af405b412 100644
--- a/src/lib-sieve/cmd-redirect.c
+++ b/src/lib-sieve/cmd-redirect.c
@@ -576,6 +576,7 @@ act_redirect_commit(const struct sieve_action *action,
 		sieve_action_duplicate_mark(senv, dupeid, strlen(dupeid),
 			ioloop_time + svinst->redirect_duplicate_period);
 
+		aenv->exec_status->significant_action_executed = TRUE;
 		sieve_result_global_log(
 			aenv, "redirect action: forwarded to <%s>",
 			smtp_address_encode(ctx->to_address));
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index 9519f4118..def2b8604 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -519,6 +519,7 @@ static int act_reject_commit
 		(aenv, recipient, rj_ctx->reason)) <= 0 )
 		return ret;
 
+	aenv->exec_status->significant_action_executed = TRUE;
 	sieve_result_global_log(aenv,
 		"rejected message from <%s> (%s)",
 		smtp_address_encode(sender),
diff --git a/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c b/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
index 62e0bbd29..73afea044 100644
--- a/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
+++ b/src/lib-sieve/plugins/duplicate/ext-duplicate-common.c
@@ -118,6 +118,7 @@ static void act_duplicate_mark_finish
 		/* Message was handled successfully, so track duplicate for this
 		 * message.
 		 */
+		aenv->exec_status->significant_action_executed = TRUE;
 		sieve_action_duplicate_mark
 			(senv, data->hash, sizeof(data->hash), ioloop_time + data->period);
 	}
diff --git a/src/lib-sieve/plugins/enotify/cmd-notify.c b/src/lib-sieve/plugins/enotify/cmd-notify.c
index e69cbc240..52ef15e20 100644
--- a/src/lib-sieve/plugins/enotify/cmd-notify.c
+++ b/src/lib-sieve/plugins/enotify/cmd-notify.c
@@ -578,6 +578,8 @@ static int act_notify_commit
 			(aenv->ehandler, NULL, "notify action");
 
 		ret = method->def->action_execute(&nenv, act);
+		if (ret >= 0)
+			aenv->exec_status->significant_action_executed = TRUE;
 
 		sieve_error_handler_unref(&nenv.ehandler);
 	}
diff --git a/src/lib-sieve/plugins/notify/cmd-notify.c b/src/lib-sieve/plugins/notify/cmd-notify.c
index 3019eb999..9ee5322ca 100644
--- a/src/lib-sieve/plugins/notify/cmd-notify.c
+++ b/src/lib-sieve/plugins/notify/cmd-notify.c
@@ -838,7 +838,10 @@ static int act_notify_commit
 		result = act_notify_send(aenv, act);
 	} T_END;
 
-	return ( result ? SIEVE_EXEC_OK : SIEVE_EXEC_FAILURE );
+	if (!result)
+		return SIEVE_EXEC_FAILURE;
+	aenv->exec_status->significant_action_executed = TRUE;
+	return SIEVE_EXEC_OK;
 }
 
 
diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c
index 2f6806f27..d7af93e2e 100644
--- a/src/lib-sieve/plugins/vacation/cmd-vacation.c
+++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c
@@ -1134,6 +1134,7 @@ static int act_vacation_send
 		return SIEVE_EXEC_FAILURE;
 	}
 
+	aenv->exec_status->significant_action_executed = TRUE;
 	return SIEVE_EXEC_OK;
 }
 
@@ -1459,6 +1460,7 @@ static int act_vacation_commit
 	if ( ret == SIEVE_EXEC_OK ) {
 		sieve_number_t seconds;
 
+		aenv->exec_status->significant_action_executed = TRUE;
 		sieve_result_global_log(aenv, "sent vacation response to <%s>",
 			smtp_address_encode(sender));
 
diff --git a/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c b/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
index 4ec2514f4..15caf1ff3 100644
--- a/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
+++ b/src/lib-sieve/plugins/vnd.dovecot/report/cmd-report.c
@@ -650,6 +650,7 @@ static int act_report_send
 				str_sanitize(error, 512));
 		}
 	} else {
+		aenv->exec_status->significant_action_executed = TRUE;
 		sieve_result_global_log(aenv,
 			"sent `%s' report to <%s>",
 			str_sanitize(act->feedback_type, 32),
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index b71b48371..c32b7fd41 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -482,6 +482,32 @@ static struct mail_keywords *act_store_keywords_create
 	return box_keywords;
 }
 
+static bool
+have_equal_keywords(struct mail *mail, struct mail_keywords *new_kw)
+{
+	const ARRAY_TYPE(keyword_indexes) *old_kw_arr =
+		mail_get_keyword_indexes(mail);
+	const unsigned int *old_kw;
+	unsigned int i, j;
+
+	if (array_count(old_kw_arr) != new_kw->count)
+		return FALSE;
+	if (new_kw->count == 0)
+		return TRUE;
+
+	old_kw = array_front(old_kw_arr);
+	for (i = 0; i < new_kw->count; i++) {
+		/* new_kw->count equals old_kw's count and it's easier to use */
+		for (j = 0; j < new_kw->count; j++) {
+			if (old_kw[j] == new_kw->idx[i])
+				break;
+		}
+		if (j == new_kw->count)
+			return FALSE;
+	}
+	return TRUE;
+}
+
 static int act_store_execute
 (const struct sieve_action *action,
 	const struct sieve_action_exec_env *aenv, void *tr_context)
@@ -538,11 +564,17 @@ static int act_store_execute
 				(aenv, &trans->keywords, mail->box, TRUE);
 
 			if ( keywords != NULL ) {
-				mail_update_keywords(mail, MODIFY_REPLACE, keywords);
+				if (!have_equal_keywords(mail, keywords)) {
+					aenv->exec_status->significant_action_executed = TRUE;
+					mail_update_keywords(mail, MODIFY_REPLACE, keywords);
+				}
 				mailbox_keywords_unref(&keywords);
 			}
 
-			mail_update_flags(mail, MODIFY_REPLACE, trans->flags);
+			if ((mail_get_flags(mail) & MAIL_FLAGS_NONRECENT) != trans->flags) {
+				aenv->exec_status->significant_action_executed = TRUE;
+				mail_update_flags(mail, MODIFY_REPLACE, trans->flags);
+			}
 		}
 
 		return SIEVE_EXEC_OK;
@@ -581,7 +613,10 @@ static int act_store_execute
 	if ( trans->flags_altered ) {
 		keywords = act_store_keywords_create(aenv, &trans->keywords, trans->box, FALSE);
 
-		mailbox_save_set_flags(save_ctx, trans->flags, keywords);
+		if (trans->flags != 0 || keywords != NULL) {
+			aenv->exec_status->significant_action_executed = TRUE;
+			mailbox_save_set_flags(save_ctx, trans->flags, keywords);
+		}
 	} else {
 		mailbox_save_copy_flags(save_ctx, mail);
 	}
@@ -590,6 +625,8 @@ static int act_store_execute
 		sieve_act_store_get_storage_error(aenv, trans);
 		status = ( trans->error_code == MAIL_ERROR_TEMP ?
 			SIEVE_EXEC_TEMP_FAILURE : SIEVE_EXEC_FAILURE );
+	} else {
+		aenv->exec_status->significant_action_executed = TRUE;
 	}
 
 	/* Deallocate keywords */
diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h
index 6b93dd203..dce10d542 100644
--- a/src/lib-sieve/sieve-types.h
+++ b/src/lib-sieve/sieve-types.h
@@ -260,6 +260,7 @@ struct sieve_exec_status {
 	bool tried_default_save:1;
 	bool keep_original:1;
 	bool store_failed:1;
+	bool significant_action_executed:1;
 };
 
 /*
-- 
GitLab