65
65
static int cmd_redirect_operation_execute
66
66
(const struct sieve_runtime_env *renv, sieve_size_t *address);
68
const struct sieve_operation_def cmd_redirect_operation = {
68
const struct sieve_operation_def cmd_redirect_operation = {
71
71
SIEVE_OPERATION_REDIRECT,
72
cmd_redirect_operation_dump,
73
cmd_redirect_operation_execute
72
cmd_redirect_operation_dump,
73
cmd_redirect_operation_execute
80
80
static bool act_redirect_equals
81
(const struct sieve_script_env *senv, const struct sieve_action *act1,
81
(const struct sieve_script_env *senv, const struct sieve_action *act1,
82
82
const struct sieve_action *act2);
83
83
static int act_redirect_check_duplicate
84
84
(const struct sieve_runtime_env *renv,
85
const struct sieve_action *act,
85
const struct sieve_action *act,
86
86
const struct sieve_action *act_other);
87
87
static void act_redirect_print
88
88
(const struct sieve_action *action, const struct sieve_result_print_env *rpenv,
90
static bool act_redirect_commit
90
static int act_redirect_commit
91
91
(const struct sieve_action *action, const struct sieve_action_exec_env *aenv,
92
92
void *tr_context, bool *keep);
94
94
const struct sieve_action_def act_redirect = {
96
96
SIEVE_ACTFLAG_TRIES_DELIVER,
97
97
act_redirect_equals,
98
act_redirect_check_duplicate,
98
act_redirect_check_duplicate,
100
100
act_redirect_print,
275
275
static bool act_redirect_equals
276
(const struct sieve_script_env *senv ATTR_UNUSED,
276
(const struct sieve_script_env *senv ATTR_UNUSED,
277
277
const struct sieve_action *act1, const struct sieve_action *act2)
279
279
struct act_redirect_context *rd_ctx1 =
280
280
(struct act_redirect_context *) act1->context;
281
struct act_redirect_context *rd_ctx2 =
281
struct act_redirect_context *rd_ctx2 =
282
282
(struct act_redirect_context *) act2->context;
284
284
/* Address is already normalized */
285
285
return ( sieve_address_compare
286
286
(rd_ctx1->to_address, rd_ctx2->to_address, TRUE) == 0 );
289
289
static int act_redirect_check_duplicate
290
290
(const struct sieve_runtime_env *renv ATTR_UNUSED,
291
const struct sieve_action *act,
291
const struct sieve_action *act,
292
292
const struct sieve_action *act_other)
294
294
return ( act_redirect_equals(renv->scriptenv, act, act_other) ? 1 : 0 );
297
297
static void act_redirect_print
298
(const struct sieve_action *action,
299
const struct sieve_result_print_env *rpenv, bool *keep)
298
(const struct sieve_action *action,
299
const struct sieve_result_print_env *rpenv, bool *keep)
301
struct act_redirect_context *ctx =
301
struct act_redirect_context *ctx =
302
302
(struct act_redirect_context *) action->context;
304
sieve_result_action_printf(rpenv, "redirect message to: %s",
304
sieve_result_action_printf(rpenv, "redirect message to: %s",
305
305
str_sanitize(ctx->to_address, 128));
310
static bool act_redirect_send
310
static int act_redirect_send
311
311
(const struct sieve_action_exec_env *aenv, struct mail *mail,
312
312
struct act_redirect_context *ctx)
314
static const char *hide_headers[] =
314
static const char *hide_headers[] =
315
315
{ "Return-Path", "X-Sieve", "X-Sieve-Redirected-From" };
317
317
struct sieve_message_context *msgctx = aenv->msgctx;
318
318
const struct sieve_script_env *senv = aenv->scriptenv;
319
319
const char *sender = sieve_message_get_sender(msgctx);
320
320
const char *recipient = sieve_message_get_final_recipient(msgctx);
321
struct istream *input, *crlf_input;
321
struct istream *input;
322
struct ostream *output;
322
323
void *smtp_handle;
324
const unsigned char *data;
327
325
/* Just to be sure */
328
326
if ( !sieve_smtp_available(senv) ) {
329
327
sieve_result_global_warning
330
328
(aenv, "redirect action has no means to send mail.");
329
return SIEVE_EXEC_FAILURE;
334
332
if (mail_get_stream(mail, NULL, NULL, &input) < 0)
333
return SIEVE_EXEC_TEMP_FAILURE;
337
335
/* Open SMTP transport */
338
smtp_handle = sieve_smtp_open(senv, ctx->to_address, sender, &f);
336
smtp_handle = sieve_smtp_open(senv, ctx->to_address, sender, &output);
340
338
/* Remove unwanted headers */
341
339
input = i_stream_create_header_filter
342
(input, HEADER_FILTER_EXCLUDE, hide_headers,
343
N_ELEMENTS(hide_headers), null_header_filter_callback, NULL);
345
/* Make sure the message contains CRLF consistently */
346
crlf_input = i_stream_create_crlf(input);
348
/* Prepend sieve headers (should not affect signatures) */
349
rfc2822_header_field_write(f, "X-Sieve", SIEVE_IMPLEMENTATION);
350
if ( recipient != NULL )
351
rfc2822_header_field_write(f, "X-Sieve-Redirected-From", recipient);
353
/* Pipe the message to the outgoing SMTP transport */
354
while (i_stream_read_data(crlf_input, &data, &size, 0) > 0) {
355
if (fwrite(data, size, 1, f) == 0)
357
i_stream_skip(crlf_input, size);
360
// FIXME: handle stream error. Currently, we have no means to abort here.
362
i_stream_unref(&crlf_input);
363
i_stream_unref(&input);
340
(input, HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR, hide_headers,
341
N_ELEMENTS(hide_headers), *null_header_filter_callback, (void *)NULL);
344
string_t *hdr = t_str_new(256);
346
/* Prepend sieve headers (should not affect signatures) */
347
rfc2822_header_append(hdr, "X-Sieve", SIEVE_IMPLEMENTATION, FALSE, NULL);
348
if ( recipient != NULL ) {
349
rfc2822_header_append
350
(hdr, "X-Sieve-Redirected-From", recipient, FALSE, NULL);
352
o_stream_send(output, str_data(hdr), str_len(hdr));
355
o_stream_send_istream(output, input);
356
i_stream_unref(&input);
365
358
/* Close SMTP transport */
366
359
if ( !sieve_smtp_close(senv, smtp_handle) ) {
367
sieve_result_global_error(aenv,
360
sieve_result_global_error(aenv,
368
361
"failed to redirect message to <%s> "
369
362
"(refer to server log for more information)",
370
363
str_sanitize(ctx->to_address, 80));
364
return SIEVE_EXEC_FAILURE;
367
return SIEVE_EXEC_OK;
377
static bool act_redirect_commit
378
(const struct sieve_action *action,
370
static int act_redirect_commit
371
(const struct sieve_action *action,
379
372
const struct sieve_action_exec_env *aenv, void *tr_context ATTR_UNUSED,
385
378
action->mail : sieve_message_get_mail(aenv->msgctx) );
386
379
const struct sieve_message_data *msgdata = aenv->msgdata;
387
380
const struct sieve_script_env *senv = aenv->scriptenv;
381
const char *orig_recipient = sieve_message_get_orig_recipient(aenv->msgctx);
388
382
const char *dupeid;
390
385
/* Prevent mail loops if possible */
391
dupeid = msgdata->id == NULL ?
392
NULL : t_strdup_printf("%s-%s", msgdata->id, ctx->to_address);
386
dupeid = msgdata->id == NULL ? NULL : t_strdup_printf
387
("%s-%s-%s", msgdata->id, orig_recipient, ctx->to_address);
393
388
if (dupeid != NULL) {
394
389
/* Check whether we've seen this message before */
395
390
if (sieve_action_duplicate_check(senv, dupeid, strlen(dupeid))) {
396
391
sieve_result_global_log(aenv, "discarded duplicate forward to <%s>",
397
392
str_sanitize(ctx->to_address, 128));
394
return SIEVE_EXEC_OK;
402
398
/* Try to forward the message */
403
if ( act_redirect_send(aenv, mail, ctx) ) {
399
if ( (ret=act_redirect_send(aenv, mail, ctx)) == SIEVE_EXEC_OK) {
405
401
/* Mark this message id as forwarded to the specified destination */
406
402
if (dupeid != NULL) {