Skip to content
Snippets Groups Projects
Commit 35cdc868 authored by Stephan Bosch's avatar Stephan Bosch
Browse files

LDA Sieve plugin: started using Dovecot reject API.

parent 2f20241f
No related branches found
No related tags found
No related merge requests found
...@@ -2,11 +2,11 @@ Current activities: ...@@ -2,11 +2,11 @@ Current activities:
* Build a sieve tool to filter an entire existing mailbox through a Sieve * Build a sieve tool to filter an entire existing mailbox through a Sieve
script. script.
* Finish the ereject extension
- Make reject/ereject use the LDA reject interface when available
Next (in order of descending priority/precedence): Next (in order of descending priority/precedence):
* Finish the ereject extension
- Make reject/ereject use the LDA reject interface when available
* Improve error handling. * Improve error handling.
- Implement dropping errors in the user's mailbox as a mail message. - Implement dropping errors in the user's mailbox as a mail message.
* Add normalize() method to comparators to normalize the string before matching * Add normalize() method to comparators to normalize the string before matching
......
...@@ -383,119 +383,6 @@ static void act_reject_print ...@@ -383,119 +383,6 @@ static void act_reject_print
*keep = FALSE; *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 static bool act_reject_commit
(const struct sieve_action *action, const struct sieve_action_exec_env *aenv, (const struct sieve_action *action, const struct sieve_action_exec_env *aenv,
void *tr_context ATTR_UNUSED, bool *keep) void *tr_context ATTR_UNUSED, bool *keep)
...@@ -526,7 +413,7 @@ static bool act_reject_commit ...@@ -526,7 +413,7 @@ static bool act_reject_commit
return TRUE; 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, sieve_result_global_log(aenv,
"rejected message from <%s> (%s)", str_sanitize(sender, 80), "rejected message from <%s> (%s)", str_sanitize(sender, 80),
( rj_ctx->ereject ? "ereject" : "reject" )); ( rj_ctx->ereject ? "ereject" : "reject" ));
......
...@@ -4,10 +4,18 @@ ...@@ -4,10 +4,18 @@
#include "lib.h" #include "lib.h"
#include "str.h" #include "str.h"
#include "strfuncs.h" #include "strfuncs.h"
#include "ioloop.h"
#include "hostpid.h"
#include "str-sanitize.h" #include "str-sanitize.h"
#include "unichar.h" #include "unichar.h"
#include "istream.h"
#include "istream-header-filter.h"
#include "mail-deliver.h" #include "mail-deliver.h"
#include "mail-storage.h" #include "mail-storage.h"
#include "message-date.h"
#include "message-size.h"
#include "rfc2822.h"
#include "sieve-code.h" #include "sieve-code.h"
#include "sieve-extensions.h" #include "sieve-extensions.h"
...@@ -16,6 +24,8 @@ ...@@ -16,6 +24,8 @@
#include "sieve-dump.h" #include "sieve-dump.h"
#include "sieve-result.h" #include "sieve-result.h"
#include "sieve-actions.h" #include "sieve-actions.h"
#include "sieve-message.h"
#include "sieve-smtp.h"
#include <ctype.h> #include <ctype.h>
...@@ -679,6 +689,8 @@ static void act_store_rollback ...@@ -679,6 +689,8 @@ static void act_store_rollback
* Action utility functions * Action utility functions
*/ */
/* Checking for duplicates */
bool sieve_action_duplicate_check_available bool sieve_action_duplicate_check_available
(const struct sieve_script_env *senv) (const struct sieve_script_env *senv)
{ {
...@@ -705,5 +717,132 @@ void sieve_action_duplicate_mark ...@@ -705,5 +717,132 @@ void sieve_action_duplicate_mark
senv->duplicate_mark senv->duplicate_mark
(senv->script_context, id, id_size, senv->username, time); (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);
}
...@@ -247,6 +247,8 @@ void sieve_act_store_get_storage_error ...@@ -247,6 +247,8 @@ void sieve_act_store_get_storage_error
* Action utility functions * Action utility functions
*/ */
/* Checking for duplicates */
bool sieve_action_duplicate_check_available bool sieve_action_duplicate_check_available
(const struct sieve_script_env *senv); (const struct sieve_script_env *senv);
int sieve_action_duplicate_check int sieve_action_duplicate_check
...@@ -255,4 +257,10 @@ void sieve_action_duplicate_mark ...@@ -255,4 +257,10 @@ void sieve_action_duplicate_mark
(const struct sieve_script_env *senv, const void *id, size_t id_size, (const struct sieve_script_env *senv, const void *id, size_t id_size,
time_t time); 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 */ #endif /* __SIEVE_ACTIONS_H */
...@@ -136,6 +136,10 @@ struct sieve_script_env { ...@@ -136,6 +136,10 @@ struct sieve_script_env {
void (*duplicate_mark) void (*duplicate_mark)
(void *script_ctx, const void *id, size_t id_size, const char *user, (void *script_ctx, const void *id, size_t id_size, const char *user,
time_t time); time_t time);
/* Interface for rejecting mail */
int (*reject_mail)(void *script_ctx, const char *recipient,
const char *reason);
/* Execution status record */ /* Execution status record */
struct sieve_exec_status *exec_status; struct sieve_exec_status *exec_status;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "mail-user.h" #include "mail-user.h"
#include "duplicate.h" #include "duplicate.h"
#include "smtp-client.h" #include "smtp-client.h"
#include "mail-send.h"
#include "lda-settings.h" #include "lda-settings.h"
#include "sieve.h" #include "sieve.h"
...@@ -77,7 +78,8 @@ static void *lda_sieve_smtp_open ...@@ -77,7 +78,8 @@ static void *lda_sieve_smtp_open
(void *script_ctx, const char *destination, (void *script_ctx, const char *destination,
const char *return_path, FILE **file_r) 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); return (void *) smtp_client_open(dctx->set, destination, return_path, file_r);
} }
...@@ -90,6 +92,15 @@ static bool lda_sieve_smtp_close ...@@ -90,6 +92,15 @@ static bool lda_sieve_smtp_close
return ( smtp_client_close(smtp_client) == 0 ); 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 * Duplicate checking
*/ */
...@@ -611,6 +622,7 @@ static int lda_sieve_run ...@@ -611,6 +622,7 @@ static int lda_sieve_run
scriptenv.smtp_close = lda_sieve_smtp_close; scriptenv.smtp_close = lda_sieve_smtp_close;
scriptenv.duplicate_mark = lda_sieve_duplicate_mark; scriptenv.duplicate_mark = lda_sieve_duplicate_mark;
scriptenv.duplicate_check = lda_sieve_duplicate_check; scriptenv.duplicate_check = lda_sieve_duplicate_check;
scriptenv.reject_mail = lda_sieve_reject_mail;
scriptenv.script_context = (void *) mdctx; scriptenv.script_context = (void *) mdctx;
scriptenv.exec_status = &estatus; scriptenv.exec_status = &estatus;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment

Consent

On this website, we use the web analytics service Matomo to analyze and review the use of our website. Through the collected statistics, we can improve our offerings and make them more appealing for you. Here, you can decide whether to allow us to process your data and set corresponding cookies for these purposes, in addition to technically necessary cookies. Further information on data protection—especially regarding "cookies" and "Matomo"—can be found in our privacy policy. You can withdraw your consent at any time.