diff --git a/src/lib-sieve/plugins/vacation/cmd-vacation.c b/src/lib-sieve/plugins/vacation/cmd-vacation.c index 19ace8a8ec31deb03e6006b3185699af67ff275a..f81a3e5c90149e99850ca0f54a22a0f9db72b75d 100644 --- a/src/lib-sieve/plugins/vacation/cmd-vacation.c +++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c @@ -813,6 +813,16 @@ static const char * const _my_address_headers[] = { NULL }; +/* Headers that should be searched for the full sender address + */ + +static const char * const _sender_headers[] = { + "from", + "sender", + "resent-from", + NULL +}; + static inline bool _is_system_address(const char *address) { if ( strncasecmp(address, "MAILER-DAEMON", 13) == 0 ) @@ -887,16 +897,77 @@ static bool _contains_8bit(const char *text) return FALSE; } +static int _get_full_reply_recipient +(const struct sieve_action_exec_env *aenv, + const char *smtp_to, const char **reply_to_r) +{ + const struct sieve_message_data *msgdata = aenv->msgdata; + const char *const *hdsp; + int ret; + + hdsp = _sender_headers; + while ( *hdsp != NULL ) { + const char *header; + + if ( (ret=mail_get_first_header(msgdata->mail, + *hdsp, &header)) < 0 ) { + return sieve_result_mail_error(aenv, msgdata->mail, + "vacation action: " + "failed to read header field `%s'", *hdsp); + } + if ( ret > 0 && header != NULL ) { + const struct message_address *addr; + + addr = message_address_parse + (pool_datastack_create(), (const unsigned char *) header, + strlen(header), 256, FALSE); + + while ( addr != NULL ) { + if ( addr->domain != NULL && !addr->invalid_syntax ) { + struct sieve_address svaddr; + const char *hdr_address; + + i_assert(addr->mailbox != NULL); + + i_zero(&svaddr); + svaddr.local_part = addr->mailbox; + svaddr.domain = addr->domain; + + hdr_address = sieve_address_to_string(&svaddr); + if ( sieve_address_compare + (hdr_address, smtp_to, TRUE) == 0 ) { + struct message_address this_addr; + + this_addr = *addr; + this_addr.next = NULL; + + string_t *str = t_str_new(256); + message_address_write(str, &this_addr); + *reply_to_r = str_c(str); + return TRUE; + } + } + + addr = addr->next; + } + } + hdsp++; + } + + *reply_to_r = t_strconcat("<", smtp_to, ">", NULL); + return SIEVE_EXEC_OK; +} + static int act_vacation_send (const struct sieve_action_exec_env *aenv, struct act_vacation_context *ctx, - const char *reply_to, const char *reply_from, const char *smtp_from) + const char *smtp_to, const char *smtp_from, const char *reply_from) { const struct sieve_message_data *msgdata = aenv->msgdata; const struct sieve_script_env *senv = aenv->scriptenv; struct sieve_smtp_context *sctx; struct ostream *output; string_t *msg; - const char *header, *outmsgid, *subject, *error; + const char *header, *outmsgid, *subject, *reply_to, *error; int ret; /* Check smpt functions just to be sure */ @@ -927,9 +998,16 @@ static int act_vacation_send subject = str_sanitize(subject, 256); + /* Obtain full To address for reply */ + + reply_to = smtp_to; + if ((ret=_get_full_reply_recipient(aenv, + smtp_to, &reply_to)) <= 0) + return ret; + /* Open smtp session */ - sctx = sieve_smtp_start_single(senv, reply_to, smtp_from, &output); + sctx = sieve_smtp_start_single(senv, smtp_to, smtp_from, &output); outmsgid = sieve_message_get_new_id(aenv->svinst); @@ -947,10 +1025,7 @@ static int act_vacation_send else rfc2822_header_printf(msg, "From", "Postmaster <%s>", senv->postmaster_address); - /* FIXME: If From header of message has same address, we should use that - * instead to properly include the phrase part. - */ - rfc2822_header_printf(msg, "To", "<%s>", reply_to); + rfc2822_header_printf(msg, "To", "%s", reply_to); if ( _contains_8bit(subject) ) rfc2822_header_utf8_printf(msg, "Subject", "%s", subject); @@ -1306,8 +1381,9 @@ static int act_vacation_commit /* Send the message */ T_BEGIN { - ret = act_vacation_send(aenv, ctx, sender, reply_from, - (config->send_from_recipient ? smtp_from : NULL)); + ret = act_vacation_send(aenv, ctx, sender, + (config->send_from_recipient ? smtp_from : NULL), + reply_from); } T_END; if ( ret == SIEVE_EXEC_OK ) { diff --git a/tests/extensions/vacation/message.svtest b/tests/extensions/vacation/message.svtest index d86560f80319f8706d4c0f18e09143ce0f2a557d..e2abbfdaab55508b156d245c87e19f12282be5e1 100644 --- a/tests/extensions/vacation/message.svtest +++ b/tests/extensions/vacation/message.svtest @@ -87,6 +87,108 @@ test "No subject" { } } +/* + * Reply to + */ + +test_set "message" text: +From: "Stephan Bosch" <stephan@example.org> +Subject: Reply to me +To: nico@frop.example.org + +Frop +. +; + +test_result_reset; +test "Reply to" { + vacation "I am not in today!"; + + if not test_result_execute { + test_fail "execution of result failed"; + } + + test_message :smtp 0; + + if not address :is "to" "stephan@example.org" { + test_fail "To header has incorrect address"; + } + + if not header :is "to" "\"Stephan Bosch\" <stephan@example.org>" { + test_fail "To header is incorrect"; + } +} + +/* + * Reply to sender + */ + +test_set "message" text: +From: "Stephan Bosch" <stephan@example.org> +Sender: "Hendrik-Jan Tuinman" <h.j.tuinman@example.org> +Subject: Reply to me +To: nico@frop.example.org + +Frop +. +; + +test_set "envelope.from" "h.j.tuinman@example.org"; + +test_result_reset; +test "Reply to sender" { + vacation "I am not in today!"; + + if not test_result_execute { + test_fail "execution of result failed"; + } + + test_message :smtp 0; + + if not address :is "to" "h.j.tuinman@example.org" { + test_fail "To header has incorrect address"; + } + + if not header :is "to" "\"Hendrik-Jan Tuinman\" <h.j.tuinman@example.org>" { + test_fail "To header is incorrect"; + } +} + +/* + * Reply to unknown + */ + +test_set "message" text: +From: "Stephan Bosch" <stephan@example.org> +Sender: "Hendrik-Jan Tuinman" <h.j.tuinman@example.org> +Subject: Reply to me +To: nico@frop.example.org + +Frop +. +; + +test_set "envelope.from" "arie.aardappel@example.org"; + +test_result_reset; +test "Reply to unknown" { + vacation "I am not in today!"; + + if not test_result_execute { + test_fail "execution of result failed"; + } + + test_message :smtp 0; + + if not address :is "to" "arie.aardappel@example.org" { + test_fail "To header has incorrect address"; + } + + if not header :is "to" "<arie.aardappel@example.org>" { + test_fail "To header is incorrect"; + } +} + /* * References */