From 35cdc868e1029a88560968214c644555854f0593 Mon Sep 17 00:00:00 2001
From: Stephan Bosch <stephan@rename-it.nl>
Date: Wed, 1 Dec 2010 00:46:31 +0100
Subject: [PATCH] LDA Sieve plugin: started using Dovecot reject API.

---
 TODO                                     |   4 +-
 src/lib-sieve/ext-reject.c               | 115 +------------------
 src/lib-sieve/sieve-actions.c            | 139 +++++++++++++++++++++++
 src/lib-sieve/sieve-actions.h            |   8 ++
 src/lib-sieve/sieve-types.h              |   4 +
 src/plugins/lda-sieve/lda-sieve-plugin.c |  14 ++-
 6 files changed, 167 insertions(+), 117 deletions(-)

diff --git a/TODO b/TODO
index a35196485..1ff1ab578 100644
--- a/TODO
+++ b/TODO
@@ -2,11 +2,11 @@ Current activities:
 
 * Build a sieve tool to filter an entire existing mailbox through a Sieve 
   script.
+* Finish the ereject extension
+	- Make reject/ereject use the LDA reject interface when available
 
 Next (in order of descending priority/precedence):
 
-* Finish the ereject extension
-	- Make reject/ereject use the LDA reject interface when available
 * Improve error handling. 
 	- Implement dropping errors in the user's mailbox as a mail message.
 * Add normalize() method to comparators to normalize the string before matching
diff --git a/src/lib-sieve/ext-reject.c b/src/lib-sieve/ext-reject.c
index d2b23ac30..c45725d7c 100644
--- a/src/lib-sieve/ext-reject.c
+++ b/src/lib-sieve/ext-reject.c
@@ -383,119 +383,6 @@ static void act_reject_print
 	*keep = FALSE;
 }
 
-/* FIXME: use LDA reject interface when available */
-
-static bool act_reject_send	
-(const struct sieve_action_exec_env *aenv, struct act_reject_context *ctx,
-	const char *sender, const char *recipient)
-{
-	const struct sieve_script_env *senv = aenv->scriptenv;
-	const struct sieve_message_data *msgdata = aenv->msgdata;
-	struct istream *input;
-	void *smtp_handle;
-	struct message_size hdr_size;
-	FILE *f;
-	const char *new_msgid, *boundary;
-	const unsigned char *data;
-	const char *header;
-	size_t size;
-	int ret;
-
-	/* Just to be sure */
-	if ( !sieve_smtp_available(senv) ) {
-		sieve_result_global_warning
-			(aenv, "reject action has no means to send mail");
-		return TRUE;
-	}
-
-	smtp_handle = sieve_smtp_open(senv, sender, NULL, &f);
-
-	new_msgid = sieve_message_get_new_id(senv);
-	boundary = t_strdup_printf("%s/%s", my_pid, senv->hostname);
-
-	rfc2822_header_field_write(f, "X-Sieve", SIEVE_IMPLEMENTATION);
-	rfc2822_header_field_write(f, "Message-ID", new_msgid);
-	rfc2822_header_field_write(f, "Date", message_date_create(ioloop_time));
-	rfc2822_header_field_printf(f, "From", "Mail Delivery Subsystem <%s>",
-		senv->postmaster_address);
-	rfc2822_header_field_printf(f, "To", "<%s>", sender);
-	rfc2822_header_field_write(f, "Subject", "Automatically rejected mail");
-	rfc2822_header_field_write(f, "Auto-Submitted", "auto-replied (rejected)");
-	rfc2822_header_field_write(f, "Precedence", "bulk");
-	
-	rfc2822_header_field_write(f, "MIME-Version", "1.0");
-	rfc2822_header_field_printf(f, "Content-Type", 
-		"multipart/report; report-type=disposition-notification;\n"
-		"boundary=\"%s\"", boundary);
-	
-	fprintf(f, "\r\nThis is a MIME-encapsulated message\r\n\r\n");
-
-	/* Human readable status report */
-	fprintf(f, "--%s\r\n", boundary);
-	fprintf(f, "Content-Type: text/plain; charset=utf-8\r\n");
-	fprintf(f, "Content-Disposition: inline\r\n");
-	fprintf(f, "Content-Transfer-Encoding: 8bit\r\n\r\n");
-
-	/* FIXME: var_expand_table expansion not possible */
-	fprintf(f, "Your message to <%s> was automatically rejected:\r\n"	
-		"%s\r\n", recipient, ctx->reason);
-
-	/* MDN status report */
-	fprintf(f, "--%s\r\n"
-		"Content-Type: message/disposition-notification\r\n\r\n", boundary);
-	fprintf(f, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n",
-		senv->hostname);
-	if (mail_get_first_header(msgdata->mail, "Original-Recipient", &header) > 0)
-		fprintf(f, "Original-Recipient: rfc822; %s\r\n", header);
-	fprintf(f, "Final-Recipient: rfc822; %s\r\n", recipient);
-
-	if ( msgdata->id != NULL )
-		fprintf(f, "Original-Message-ID: %s\r\n", msgdata->id);
-	fprintf(f, "Disposition: "
-		"automatic-action/MDN-sent-automatically; deleted\r\n");
-	fprintf(f, "\r\n");
-
-	/* original message's headers */
-	fprintf(f, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary);
-
-	if (mail_get_stream(msgdata->mail, &hdr_size, NULL, &input) == 0) {
-		/* Note: If you add more headers, they need to be sorted.
-		 * We'll drop Content-Type because we're not including the message
-		 * body, and having a multipart Content-Type may confuse some
-		 * MIME parsers when they don't see the message boundaries. 
-		 */
-		static const char *const exclude_headers[] = {
-			"Content-Type"
-		};
-
-		input = i_stream_create_header_filter(input,
-			HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR | HEADER_FILTER_HIDE_BODY, 
-			exclude_headers, N_ELEMENTS(exclude_headers), 
-			null_header_filter_callback, NULL);
-
-		while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
-			if (fwrite(data, size, 1, f) == 0)
-				break;
-			i_stream_skip(input, size);
-		}
-		i_stream_unref(&input);
-			
-		i_assert(ret != 0);
-	}
-
-	fprintf(f, "\r\n\r\n--%s--\r\n", boundary);
-
-	if ( !sieve_smtp_close(senv, smtp_handle) ) {
-		sieve_result_global_error(aenv,
-			"failed to send rejection message to <%s> "
-			"(refer to server log for more information)",
-			str_sanitize(sender, 80));
-		return FALSE;
-	}
-	
-	return TRUE;
-}
-
 static bool act_reject_commit
 (const struct sieve_action *action, const struct sieve_action_exec_env *aenv, 
 	void *tr_context ATTR_UNUSED, bool *keep)
@@ -526,7 +413,7 @@ static bool act_reject_commit
 		return TRUE;
 	}
 		
-	if ( act_reject_send(aenv, rj_ctx, sender, recipient) ) {
+	if ( sieve_action_reject_mail(aenv, sender, recipient, rj_ctx->reason) ) {
 		sieve_result_global_log(aenv, 
 			"rejected message from <%s> (%s)", str_sanitize(sender, 80),
 			( rj_ctx->ereject ? "ereject" : "reject" ));
diff --git a/src/lib-sieve/sieve-actions.c b/src/lib-sieve/sieve-actions.c
index 49597afaa..43153a772 100644
--- a/src/lib-sieve/sieve-actions.c
+++ b/src/lib-sieve/sieve-actions.c
@@ -4,10 +4,18 @@
 #include "lib.h"
 #include "str.h"
 #include "strfuncs.h"
+#include "ioloop.h"
+#include "hostpid.h"
 #include "str-sanitize.h"
 #include "unichar.h"
+#include "istream.h"
+#include "istream-header-filter.h"
 #include "mail-deliver.h"
 #include "mail-storage.h"
+#include "message-date.h"
+#include "message-size.h"
+
+#include "rfc2822.h"
 
 #include "sieve-code.h"
 #include "sieve-extensions.h"
@@ -16,6 +24,8 @@
 #include "sieve-dump.h"
 #include "sieve-result.h"
 #include "sieve-actions.h"
+#include "sieve-message.h"
+#include "sieve-smtp.h"
 
 #include <ctype.h>
 
@@ -679,6 +689,8 @@ static void act_store_rollback
  * Action utility functions
  */
 
+/* Checking for duplicates */
+
 bool sieve_action_duplicate_check_available
 (const struct sieve_script_env *senv)
 {
@@ -705,5 +717,132 @@ void sieve_action_duplicate_mark
 	senv->duplicate_mark
 		(senv->script_context, id, id_size, senv->username, time);
 }
+
+/* Rejecting the mail */
+
+static bool sieve_action_do_reject_mail
+(const struct sieve_action_exec_env *aenv, const char *sender, 
+	const char *recipient, const char *reason)
+{
+	const struct sieve_script_env *senv = aenv->scriptenv;
+	const struct sieve_message_data *msgdata = aenv->msgdata;
+	struct istream *input;
+	void *smtp_handle;
+	struct message_size hdr_size;
+	FILE *f;
+	const char *new_msgid, *boundary;
+	const unsigned char *data;
+	const char *header;
+	size_t size;
+	int ret;
+
+	/* Just to be sure */
+	if ( !sieve_smtp_available(senv) ) {
+		sieve_result_global_warning
+			(aenv, "reject action has no means to send mail");
+		return TRUE;
+	}
+
+	smtp_handle = sieve_smtp_open(senv, sender, NULL, &f);
+
+	new_msgid = sieve_message_get_new_id(senv);
+	boundary = t_strdup_printf("%s/%s", my_pid, senv->hostname);
+
+	rfc2822_header_field_write(f, "X-Sieve", SIEVE_IMPLEMENTATION);
+	rfc2822_header_field_write(f, "Message-ID", new_msgid);
+	rfc2822_header_field_write(f, "Date", message_date_create(ioloop_time));
+	rfc2822_header_field_printf(f, "From", "Mail Delivery Subsystem <%s>",
+		senv->postmaster_address);
+	rfc2822_header_field_printf(f, "To", "<%s>", sender);
+	rfc2822_header_field_write(f, "Subject", "Automatically rejected mail");
+	rfc2822_header_field_write(f, "Auto-Submitted", "auto-replied (rejected)");
+	rfc2822_header_field_write(f, "Precedence", "bulk");
+	
+	rfc2822_header_field_write(f, "MIME-Version", "1.0");
+	rfc2822_header_field_printf(f, "Content-Type", 
+		"multipart/report; report-type=disposition-notification;\n"
+		"boundary=\"%s\"", boundary);
+	
+	fprintf(f, "\r\nThis is a MIME-encapsulated message\r\n\r\n");
+
+	/* Human readable status report */
+	fprintf(f, "--%s\r\n", boundary);
+	fprintf(f, "Content-Type: text/plain; charset=utf-8\r\n");
+	fprintf(f, "Content-Disposition: inline\r\n");
+	fprintf(f, "Content-Transfer-Encoding: 8bit\r\n\r\n");
+
+	fprintf(f, "Your message to <%s> was automatically rejected:\r\n"	
+		"%s\r\n", recipient, reason);
+
+	/* MDN status report */
+	fprintf(f, "--%s\r\n"
+		"Content-Type: message/disposition-notification\r\n\r\n", boundary);
+	fprintf(f, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n",
+		senv->hostname);
+	if (mail_get_first_header(msgdata->mail, "Original-Recipient", &header) > 0)
+		fprintf(f, "Original-Recipient: rfc822; %s\r\n", header);
+	fprintf(f, "Final-Recipient: rfc822; %s\r\n", recipient);
+
+	if ( msgdata->id != NULL )
+		fprintf(f, "Original-Message-ID: %s\r\n", msgdata->id);
+	fprintf(f, "Disposition: "
+		"automatic-action/MDN-sent-automatically; deleted\r\n");
+	fprintf(f, "\r\n");
+
+	/* original message's headers */
+	fprintf(f, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary);
+
+	if (mail_get_stream(msgdata->mail, &hdr_size, NULL, &input) == 0) {
+		/* Note: If you add more headers, they need to be sorted.
+		 * We'll drop Content-Type because we're not including the message
+		 * body, and having a multipart Content-Type may confuse some
+		 * MIME parsers when they don't see the message boundaries. 
+		 */
+		static const char *const exclude_headers[] = {
+			"Content-Type"
+		};
+
+		input = i_stream_create_header_filter(input,
+			HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR | HEADER_FILTER_HIDE_BODY, 
+			exclude_headers, N_ELEMENTS(exclude_headers), 
+			null_header_filter_callback, NULL);
+
+		while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
+			if (fwrite(data, size, 1, f) == 0)
+				break;
+			i_stream_skip(input, size);
+		}
+		i_stream_unref(&input);
+			
+		i_assert(ret != 0);
+	}
+
+	fprintf(f, "\r\n\r\n--%s--\r\n", boundary);
+
+	if ( !sieve_smtp_close(senv, smtp_handle) ) {
+		sieve_result_global_error(aenv,
+			"failed to send rejection message to <%s> "
+			"(refer to server log for more information)",
+			str_sanitize(sender, 80));
+		return FALSE;
+	}
+	
+	return TRUE;
+}
+
+bool sieve_action_reject_mail
+(const struct sieve_action_exec_env *aenv,
+	const char *sender, const char *recipient, const char *reason)
+{
+	const struct sieve_script_env *senv = aenv->scriptenv;
+
+	if ( senv->reject_mail != NULL ) {
+		return ( senv->reject_mail(senv->script_context, recipient, reason) >= 0 );
+	}
+		
+	return sieve_action_do_reject_mail(aenv, sender, recipient, reason);
+}
+
+
 	
 
diff --git a/src/lib-sieve/sieve-actions.h b/src/lib-sieve/sieve-actions.h
index 51b75da11..eb354236c 100644
--- a/src/lib-sieve/sieve-actions.h
+++ b/src/lib-sieve/sieve-actions.h
@@ -247,6 +247,8 @@ void sieve_act_store_get_storage_error
  * Action utility functions
  */
 
+/* Checking for duplicates */
+
 bool sieve_action_duplicate_check_available
 	(const struct sieve_script_env *senv);
 int sieve_action_duplicate_check
@@ -255,4 +257,10 @@ void sieve_action_duplicate_mark
 	(const struct sieve_script_env *senv, const void *id, size_t id_size,
 		time_t time);
 
+/* Rejecting mail */
+
+bool sieve_action_reject_mail
+(const struct sieve_action_exec_env *aenv,
+	const char *sender, const char *recipient, const char *reason);
+
 #endif /* __SIEVE_ACTIONS_H */
diff --git a/src/lib-sieve/sieve-types.h b/src/lib-sieve/sieve-types.h
index c75f87524..3cec61ead 100644
--- a/src/lib-sieve/sieve-types.h
+++ b/src/lib-sieve/sieve-types.h
@@ -136,6 +136,10 @@ struct sieve_script_env {
 	void (*duplicate_mark)
 		(void *script_ctx, const void *id, size_t id_size, const char *user, 
 			time_t time);
+
+	/* Interface for rejecting mail */
+	int (*reject_mail)(void *script_ctx, const char *recipient,
+			const char *reason);
 	
 	/* Execution status record */	
 	struct sieve_exec_status *exec_status;
diff --git a/src/plugins/lda-sieve/lda-sieve-plugin.c b/src/plugins/lda-sieve/lda-sieve-plugin.c
index a31ebc421..a817da9e0 100644
--- a/src/plugins/lda-sieve/lda-sieve-plugin.c
+++ b/src/plugins/lda-sieve/lda-sieve-plugin.c
@@ -10,6 +10,7 @@
 #include "mail-user.h"
 #include "duplicate.h"
 #include "smtp-client.h"
+#include "mail-send.h"
 #include "lda-settings.h"
 
 #include "sieve.h"
@@ -77,7 +78,8 @@ static void *lda_sieve_smtp_open
 (void *script_ctx, const char *destination,
 	const char *return_path, FILE **file_r)
 {
-	struct mail_deliver_context *dctx = (struct mail_deliver_context *) script_ctx;
+	struct mail_deliver_context *dctx =
+		(struct mail_deliver_context *) script_ctx;
 
 	return (void *) smtp_client_open(dctx->set, destination, return_path, file_r);
 }
@@ -90,6 +92,15 @@ static bool lda_sieve_smtp_close
 	return ( smtp_client_close(smtp_client) == 0 );
 }
 
+static int lda_sieve_reject_mail(void *script_ctx, const char *recipient,
+	const char *reason)
+{
+	struct mail_deliver_context *dctx =
+		(struct mail_deliver_context *) script_ctx;
+	
+	return mail_send_rejection(dctx, recipient, reason);
+}
+
 /*
  * Duplicate checking
  */
@@ -611,6 +622,7 @@ static int lda_sieve_run
 	scriptenv.smtp_close = lda_sieve_smtp_close;
 	scriptenv.duplicate_mark = lda_sieve_duplicate_mark;
 	scriptenv.duplicate_check = lda_sieve_duplicate_check;
+	scriptenv.reject_mail = lda_sieve_reject_mail;
 	scriptenv.script_context = (void *) mdctx;
 	scriptenv.exec_status = &estatus;
 
-- 
GitLab