From 600afb87b6ad12889ba74bda25b46b475d88a1fa Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Sat, 16 Oct 2010 21:19:51 +0200
Subject: [PATCH] Sieve-filter: implemented basic filtering with source mailbox
 actions.

---
 doc/man/sieve-filter.1.in      |  58 +++++++++--------
 src/sieve-tools/sieve-filter.c | 115 +++++++++++++++++++++------------
 2 files changed, 102 insertions(+), 71 deletions(-)

diff --git a/doc/man/sieve-filter.1.in b/doc/man/sieve-filter.1.in
index 05191ef53..38f5e805b 100644
--- a/doc/man/sieve-filter.1.in
+++ b/doc/man/sieve-filter.1.in
@@ -14,6 +14,7 @@ implements.
 .RI [ options ]
 .I script\-file
 .I source\-mailbox
+.RI [ source\-action ]
 .SH DESCRIPTION
 .PP
 The \fBsieve\-filter\fP command is part of the Pigeonhole Project
@@ -88,34 +89,6 @@ Sieve actions such as redirect, reject, vacation and notify, but using this
 option outgoing messages can be fed to the \fBstdin\fP of an external shell
 command. This option has no effect in simulation mode. Unless you really know
 what you are doing, \fBDO NOT USE THIS TO FEED MAIL TO SENDMAIL!\fP.
-.TP 
-.BI \-R\  source\-action
-Specifies what needs to be done with messages in the source mailbox once
-processed by the Sieve script. By default, the sieve\-filter command does not
-remove the messages from the source mailbox. In particular this means that the
-keep and fileinto actions will cause the messages to be copied. To alter this
-behavior, the \fIsource\-action\fP parameter of the \fB\-R\fP option accepts
-one of the following values:
-.RS 7
-.TP 
-\fBkeep\fP (default)
-Keep processed messages in source folder. If \fB\-W\fR is specified and the
-source mailbox is the destination of a keep or fileinto action, flags may be
-changed by the Sieve script, but messages are never duplicated there. 
-.TP 
-\fBflag\fP
-Flag processed messages as \\DELETED.
-.TP 
-\fBmove\fP [\fIfolder\fP]
-Move processed messages to the indicated \fIfolder\fP.
-.TP 
-\fBexpunge\fP
-Expunge processed messages, meaning that these are removed irreversibly when the
-tool finishes filtering.
-.PP
-Note that the chosen \fIsource\-action\fP only has an effect on the source
-mailbox when the \fB\-W\fP option is specified as well.
-.RE
 .TP
 .BI \-s\  script\-file
 Specify additional scripts to be executed before the main script. Multiple
@@ -157,6 +130,35 @@ into a new binary.
 .TP
 .I source\-mailbox
 The name of the source mailbox.
+.TP 
+.I source\-action
+Specifies what needs to be done with messages in the source mailbox once
+processed by the Sieve script. By default, the sieve\-filter command does not
+remove the messages from the source mailbox. In particular this means that the
+keep and fileinto actions will cause the messages to be copied. To alter this
+behavior, the \fIsource\-action\fP parameter of the \fB\-R\fP option accepts
+one of the following values:
+.RS 7
+.TP 
+.BR keep\  (default)
+Keep processed messages in source folder. If \fB\-W\fR is specified and the
+source mailbox is the destination of a keep or fileinto action, flags may be
+changed by the Sieve script, but messages are never duplicated there. 
+.TP 
+.BI move\  folder
+Move processed messages to the indicated \fIfolder\fP.
+.TP 
+.B delete
+Flag processed messages as \\DELETED.
+.TP 
+.B expunge
+Expunge processed messages, meaning that these are removed irreversibly when the
+tool finishes filtering.
+.PP
+Note that the chosen \fIsource\-action\fP only has an effect on the source
+mailbox when the \fB\-W\fP option is specified as well.
+.RE
+
 .\"------------------------------------------------------------------------
 
 .SH EXAMPLES
diff --git a/src/sieve-tools/sieve-filter.c b/src/sieve-tools/sieve-filter.c
index 3a67e6659..4d359f06c 100644
--- a/src/sieve-tools/sieve-filter.c
+++ b/src/sieve-tools/sieve-filter.c
@@ -35,33 +35,33 @@
 static void print_help(void)
 {
 	printf(
-"Usage: sieve-filter [-m <mailbox>] [-x <extensions>] [-s <script-file>] [-c]\n"
-"                    <script-file> <src-mail-store> [<dest-mail-store>]\n"
-"Usage: sieve-filter [-c <config-file>] [-C] [-D] [-e]\n"
-"                  [-m <default-mailbox>] [-P <plugin>]\n"
-"                  [-r <recipient-address>] [-s <script-file>]\n"
-"                  [-t <trace-file>] [-T <trace-option>] [-x <extensions>]\n"
-"                  <script-file> <mail-file>\n"
+"Usage: sieve-filter [-c <config-file>] [-C] [-D] [-e] [-m <default-mailbox>]\n"
+"                    [-P <plugin>] [-q <output-mailbox>] [-Q <mail-command>]\n"
+"                    [-s <script-file>] [-u <user>] [-W] [-x <extensions>]\n"
+"                    <script-file> <source-mailbox> <source-action>\n"
 	);
 }
 
-enum source_action_type {
-	SOURCE_ACTION_KEEP,            /* Always keep messages in source folder */ 
-	SOURCE_ACTION_DELETE,          /* Flag discarded messages as \DELETED */
-	SOURCE_ACTION_TRASH_FOLDER,    /* Move discarded messages to Trash folder */      
-	SOURCE_ACTION_EXPUNGE          /* Expunge discarded messages */
+enum sieve_filter_source_action {
+	SIEVE_FILTER_SACT_KEEP,          /* Always keep messages in source folder */ 
+	SIEVE_FILTER_SACT_MOVE,          /* Move discarded messages to Trash folder */      
+	SIEVE_FILTER_SACT_DELETE,        /* Flag discarded messages as \DELETED */
+	SIEVE_FILTER_SACT_EXPUNGE        /* Expunge discarded messages */
 };
 
-struct source_action {
-	enum source_action_type type;
-	const char *trash_folder;
+struct sieve_filter_context {
+	enum sieve_filter_source_action source_action;
+	const char *move_mailbox;
+
+	struct sieve_script_env *senv;
+	struct sieve_binary *main_sbin;
+	struct sieve_error_handler *ehandler;
 };
 
 static int filter_message
-(struct mail *mail, struct sieve_binary *main_sbin, 
-	struct sieve_script_env *senv, struct sieve_error_handler *ehandler,
-	struct source_action source_action)
+(struct sieve_filter_context *sfctx, struct mail *mail)
 {
+	struct sieve_error_handler *ehandler = sfctx->ehandler; 
 	struct sieve_exec_status estatus;
 	struct sieve_binary *sbin;
 	struct sieve_message_data msgdata;
@@ -72,7 +72,7 @@ static int filter_message
 
 	/* Initialize execution status */
 	memset(&estatus, 0, sizeof(estatus));
-	senv->exec_status = &estatus;
+	sfctx->senv->exec_status = &estatus;
 
 	/* Collect necessary message data */
 	memset(&msgdata, 0, sizeof(msgdata));
@@ -80,37 +80,35 @@ static int filter_message
 	msgdata.return_path = sender;
 	msgdata.orig_envelope_to = recipient;
 	msgdata.final_envelope_to = recipient;
-	msgdata.auth_user = senv->username;
+	msgdata.auth_user = sfctx->senv->username;
 	(void)mail_get_first_header(mail, "Message-ID", &msgdata.id);
 
 	/* Single script */
-	sbin = main_sbin;
-	main_sbin = NULL;
+	sbin = sfctx->main_sbin;
 
 	/* Execute script */
-	ret = sieve_execute(sbin, &msgdata, senv, ehandler, NULL);
+	ret = sieve_execute(sbin, &msgdata, sfctx->senv, ehandler, NULL);
 
 	/* Handle message in source folder */
 	if ( ret > 0 && !estatus.keep_original ) {
-		switch ( source_action.type ) {
+		switch ( sfctx->source_action ) {
 		/* Leave it there */
-		case SOURCE_ACTION_KEEP:
+		case SIEVE_FILTER_SACT_KEEP:
 			sieve_info(ehandler, NULL, "message left in source mailbox");
 			break;
+		/* Move message to Trash folder */
+		case SIEVE_FILTER_SACT_MOVE:			
+			sieve_info(ehandler, NULL, 
+				"message in source mailbox moved to mailbox '%s'", sfctx->move_mailbox);
+			break;
 		/* Flag message as \DELETED */
-		case SOURCE_ACTION_DELETE:					
+		case SIEVE_FILTER_SACT_DELETE:					
 			sieve_info(ehandler, NULL, "message flagged as deleted in source mailbox");
 			mail_update_flags(mail, MODIFY_ADD, MAIL_DELETED);
 			break;
-		/* Move message to Trash folder */
-		case SOURCE_ACTION_TRASH_FOLDER:			
-			sieve_info(ehandler, NULL, 
-				"message in source folder moved to folder '%s'", 
-				source_action.trash_folder);
-			break;
 		/* Expunge the message immediately */
-		case SOURCE_ACTION_EXPUNGE:
-			sieve_info(ehandler, NULL, "message removed from source folder");
+		case SIEVE_FILTER_SACT_EXPUNGE:
+			sieve_info(ehandler, NULL, "message expunged from source mailbox");
 			mail_expunge(mail);
 			break;
 		/* Unknown */
@@ -118,6 +116,8 @@ static int filter_message
 			i_unreached();
 			break;
 		}
+	} else {
+		sieve_info(ehandler, NULL, "message left in source mailbox");
 	}
 
 	return ret;
@@ -139,10 +139,9 @@ static void mail_search_build_add_flags
 }
 
 static int filter_mailbox
-(struct mailbox *src_box, struct sieve_binary *main_sbin, 
-	struct sieve_script_env *senv, struct sieve_error_handler *ehandler,
-	struct source_action source_action)
+(struct sieve_filter_context *sfctx, struct mailbox *src_box)
 {
+	struct sieve_error_handler *ehandler = sfctx->ehandler;
 	struct mail_search_args *search_args;
 	struct mailbox_transaction_context *t;
 	struct mail_search_context *search_ctx;
@@ -189,7 +188,7 @@ static int filter_mailbox
 		sieve_info(ehandler, NULL,
 			"filtering: [%s; %"PRIuUOFF_T" bytes] %s", date, size, subject);
 	
-		ret = filter_message(mail, main_sbin, senv, ehandler, source_action);
+		ret = filter_message(sfctx, mail);
 	}
 	mail_free(&mail);
 	
@@ -235,8 +234,9 @@ int main(int argc, char **argv)
 {
 	struct sieve_instance *svinst;
 	ARRAY_TYPE (const_string) scriptfiles;
-	const char *scriptfile,	*src_mailbox, *dst_mailbox;
-	struct source_action source_action = { SOURCE_ACTION_KEEP, "Trash" };
+	const char *scriptfile,	*src_mailbox, *dst_mailbox, *move_mailbox;
+	struct sieve_filter_context sfctx;
+	enum sieve_filter_source_action source_action = SIEVE_FILTER_SACT_KEEP;
 	struct mail_user *mail_user;
 	struct sieve_binary *main_sbin;
 	struct sieve_script_env scriptenv;
@@ -249,13 +249,15 @@ int main(int argc, char **argv)
 	enum mail_error error;
 	int c;
 
-	sieve_tool = sieve_tool_init("sieve-filter", &argc, &argv, "m:s:x:P:CD", FALSE);
+	sieve_tool = sieve_tool_init("sieve-filter", &argc, &argv, 
+		"R:m:s:x:P:CD", FALSE);
 
 	t_array_init(&scriptfiles, 16);
 
 	/* Parse arguments */
 	scriptfile =  NULL;
 	src_mailbox = dst_mailbox = "INBOX";
+	move_mailbox = "Trash";
 	force_compile = FALSE;
 	while ((c = sieve_tool_getopt(sieve_tool)) > 0) {
 		switch (c) {
@@ -305,6 +307,26 @@ int main(int argc, char **argv)
 		print_help();
 		i_fatal_status(EX_USAGE, "Missing <source-mailbox> argument");
 	}
+		
+	if ( optind < argc ) {
+		const char *srcact = argv[optind++];
+
+		if ( strcmp(srcact, "keep") == 0 ) {
+			source_action = SIEVE_FILTER_SACT_KEEP;
+		} else if ( strcmp(srcact, "move") == 0 ) {
+			source_action = SIEVE_FILTER_SACT_MOVE;
+			if ( optind < argc ) {
+				move_mailbox = t_strdup(argv[optind++]);
+			}
+		} else if ( strcmp(srcact, "flag") == 0 ) {
+			source_action = SIEVE_FILTER_SACT_DELETE;
+		} else if ( strcmp(srcact, "expunge") == 0 ) {
+			source_action = SIEVE_FILTER_SACT_EXPUNGE;
+		} else {
+			print_help();
+			i_fatal_status(EX_USAGE, "Invalid <source-action> argument");
+		}
+	} 
 
 	if ( optind != argc ) {
 		print_help();
@@ -359,9 +381,16 @@ int main(int argc, char **argv)
 	scriptenv.smtp_open = NULL;
 	scriptenv.smtp_close = NULL;
 
+	/* Compose filter context */
+	memset(&sfctx, 0, sizeof(sfctx));
+	sfctx.senv = &scriptenv;
+	sfctx.source_action = source_action;
+	sfctx.move_mailbox = move_mailbox;
+	sfctx.main_sbin = main_sbin;
+	sfctx.ehandler = ehandler;
+
 	/* Apply Sieve filter to all messages found */
-	(void) filter_mailbox
-		(src_box, main_sbin, &scriptenv, ehandler, source_action);
+	(void) filter_mailbox(&sfctx, src_box);
 	
 	/* Close the mailbox */
 	if ( src_box != NULL )
-- 
GitLab