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