diff --git a/INSTALL b/INSTALL index 8be860b67db10bbe96ffbad9ae86b25710784607..bfb3336f8ea8995f7fbdb39a6f54d813ecde9215 100644 --- a/INSTALL +++ b/INSTALL @@ -217,6 +217,14 @@ plugin section of the config file (default values are shown if applicable): release. LDAP support may also be compiled as a plugin called `sieve_storage_ldap'. + sieve_user_email = + The primary e-mail address for the user. This is used as a default when no + other appropriate address is available for sending messages. If this setting + is not configured, either the postmaster or null "<>" address is used as a + sender, depending on the action involved. This setting is important when + there is no message envelope to extract addresses from, such as when the + script is executed in IMAP. + sieve_user_log = The path to the file where the user log file is written. If not configured, a default location is used. If the main user's personal Sieve (as configured @@ -241,6 +249,10 @@ plugin section of the config file (default values are shown if applicable): "sender" - The sender address is used (default). "recipient" - The final recipient address is used. "orig_recipient" - The original recipient is used. + "user_email" - The user's primary address is used. This is + configured with the "sieve_user_email" setting. If + that setting is unconfigured, "user_mail" is equal to + "sender" (the default). "postmaster" - The postmaster_address configured for the LDA. "<user@domain>" - Redirected messages are always sent from user@domain. The angle brackets are mandatory. The null "<>" address diff --git a/doc/example-config/conf.d/90-sieve.conf b/doc/example-config/conf.d/90-sieve.conf index f516ba42d61a4656d3214628063a319d90022ce4..edc952dbb2f9b52e59b95df2952e3fbc3bbe0f63 100644 --- a/doc/example-config/conf.d/90-sieve.conf +++ b/doc/example-config/conf.d/90-sieve.conf @@ -136,6 +136,14 @@ plugin { # (Currently only relevant for ManageSieve) #sieve_quota_max_storage = 0 + # The primary e-mail address for the user. This is used as a default when no + # other appropriate address is available for sending messages. If this setting + # is not configured, either the postmaster or null "<>" address is used as a + # sender, depending on the action involved. This setting is important when + # there is no message envelope to extract addresses from, such as when the + # script is executed in IMAP. + #sieve_user_email = + # The path to the file where the user log is written. If not configured, a # default location is used. If the main user's personal Sieve (as configured # with sieve=) is a file, the logfile is set to <filename>.log by default. If @@ -148,6 +156,10 @@ plugin { # "sender" - The sender address is used (default). # "recipient" - The final recipient address is used. # "orig_recipient" - The original recipient is used. + # "user_email" - The user's primary address is used. This is + # configured with the "sieve_user_email" setting. If + # that setting is unconfigured, "user_mail" is equal to + # "recipient". # "postmaster" - The postmaster_address configured for the LDA. # "<user@domain>" - Redirected messages are always sent from user@domain. # The angle brackets are mandatory. The null "<>" address diff --git a/src/lib-sieve/cmd-redirect.c b/src/lib-sieve/cmd-redirect.c index a2b006fa09cf0d067eed7e26aaa5261230ad3105..af3464949a43bd9d8f490aab1cbcdee44747d086 100644 --- a/src/lib-sieve/cmd-redirect.c +++ b/src/lib-sieve/cmd-redirect.c @@ -312,13 +312,12 @@ static int act_redirect_send { static const char *hide_headers[] = { "Return-Path", "X-Sieve", "X-Sieve-Redirected-From" }; - + struct sieve_instance *svinst = aenv->svinst; struct sieve_message_context *msgctx = aenv->msgctx; const struct sieve_script_env *senv = aenv->scriptenv; const char *sender; const char *recipient = sieve_message_get_final_recipient(msgctx); - struct sieve_address_source env_from = - aenv->svinst->redirect_from; + struct sieve_address_source env_from = svinst->redirect_from; struct istream *input; struct ostream *output; const char *error; @@ -354,14 +353,20 @@ static int act_redirect_send /* Envelope available */ sender = sieve_message_get_sender(msgctx); if ( sender != NULL && - sieve_address_source_get_address(&env_from, + sieve_address_source_get_address(&env_from, svinst, senv, msgctx, aenv->flags, &sender) < 0 ) sender = NULL; } else { /* No envelope available */ - if ( sieve_address_source_get_address(&env_from, - senv, msgctx, aenv->flags, &sender) <= 0 ) + if ( (ret=sieve_address_source_get_address(&env_from, svinst, + senv, msgctx, aenv->flags, &sender)) < 0 ) { sender = NULL; + } else if ( ret == 0 ) { + if ( svinst->user_email == NULL ) + sender = NULL; + else + sieve_address_to_string(svinst->user_email); + } } /* Open SMTP transport */ diff --git a/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c b/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c index f14cd88b3023469de301c1ec85639180ef7b220d..4967b58ac420030dacb010ebf728138d90e392e1 100644 --- a/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c +++ b/src/lib-sieve/plugins/enotify/mailto/ntfy-mailto.c @@ -431,6 +431,7 @@ static int ntfy_mailto_send (const struct sieve_enotify_exec_env *nenv, const struct sieve_enotify_action *nact, const char *recipient) { + struct sieve_instance *svinst = nenv->svinst; const struct sieve_message_data *msgdata = nenv->msgdata; const struct sieve_script_env *senv = nenv->scriptenv; struct ntfy_mailto_context *mtctx = @@ -467,13 +468,6 @@ static int ntfy_mailto_send return 0; } - /* Determine message from address */ - if ( nact->from == NULL ) { - from = t_strdup_printf("Postmaster <%s>", senv->postmaster_address); - } else { - from = nact->from; - } - /* Determine which sender to use From RFC 5436, Section 2.3: @@ -493,12 +487,23 @@ static int ntfy_mailto_send env_from.type = SIEVE_ADDRESS_SOURCE_EXPLICIT; } } - if ( (ret=sieve_address_source_get_address(&env_from, + if ( (ret=sieve_address_source_get_address(&env_from, svinst, senv, nenv->msgctx, nenv->flags, &from_smtp)) < 0 ) { from_smtp = NULL; } else if ( ret == 0 ) { - from_smtp = ( mtctx->from_normalized != NULL ? - mtctx->from_normalized : senv->postmaster_address ); + if ( mtctx->from_normalized != NULL ) + from_smtp = mtctx->from_normalized; + else if ( svinst->user_email != NULL ) + from_smtp = sieve_address_to_string(svinst->user_email); + else + from_smtp = senv->postmaster_address; + } + + /* Determine message from address */ + if ( nact->from == NULL ) { + from = t_strdup_printf("<%s>", from_smtp); + } else { + from = nact->from; } /* Determine subject */ @@ -551,7 +556,7 @@ static int ntfy_mailto_send } msg = t_str_new(512); - outmsgid = sieve_message_get_new_id(nenv->svinst); + outmsgid = sieve_message_get_new_id(svinst); rfc2822_header_write(msg, "X-Sieve", SIEVE_IMPLEMENTATION); rfc2822_header_write(msg, "Message-ID", outmsgid); diff --git a/src/lib-sieve/sieve-address-source.c b/src/lib-sieve/sieve-address-source.c index c51d1c6dc9d01f474d4c0f5735ba6123f55e008d..e0124ec2447503db30c368e4a029a104f5aced79 100644 --- a/src/lib-sieve/sieve-address-source.c +++ b/src/lib-sieve/sieve-address-source.c @@ -33,6 +33,8 @@ bool sieve_address_source_parse asrc->type = SIEVE_ADDRESS_SOURCE_RECIPIENT; } else if ( strcmp(value, "orig_recipient") == 0 ) { asrc->type = SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT; + } else if ( strcmp(value, "user_email") == 0 ) { + asrc->type = SIEVE_ADDRESS_SOURCE_USER_EMAIL; } else if ( strcmp(value, "postmaster") == 0 ) { asrc->type = SIEVE_ADDRESS_SOURCE_POSTMASTER; } else if ( value[0] == '<' && value[val_len-1] == '>') { @@ -70,6 +72,7 @@ bool sieve_address_source_parse_from_setting int sieve_address_source_get_address (struct sieve_address_source *asrc, + struct sieve_instance *svinst, const struct sieve_script_env *senv, struct sieve_message_context *msgctx, enum sieve_execute_flags flags, @@ -77,8 +80,12 @@ int sieve_address_source_get_address { enum sieve_address_source_type type = asrc->type; + if ( type == SIEVE_ADDRESS_SOURCE_USER_EMAIL && + svinst->user_email == NULL ) + type = SIEVE_ADDRESS_SOURCE_RECIPIENT; + if ( (flags & SIEVE_EXECUTE_FLAG_NO_ENVELOPE) != 0 ) { - switch ( asrc->type ) { + switch ( type ) { case SIEVE_ADDRESS_SOURCE_SENDER: case SIEVE_ADDRESS_SOURCE_RECIPIENT: case SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT: @@ -100,12 +107,15 @@ int sieve_address_source_get_address case SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT: *addr_r = sieve_message_get_orig_recipient(msgctx); return 1; - case SIEVE_ADDRESS_SOURCE_EXPLICIT: - *addr_r = sieve_address_to_string(asrc->address); + case SIEVE_ADDRESS_SOURCE_USER_EMAIL: + *addr_r = sieve_address_to_string(svinst->user_email); return 1; case SIEVE_ADDRESS_SOURCE_POSTMASTER: *addr_r = senv->postmaster_address; return 1; + case SIEVE_ADDRESS_SOURCE_EXPLICIT: + *addr_r = sieve_address_to_string(asrc->address); + return 1; case SIEVE_ADDRESS_SOURCE_DEFAULT: break; } diff --git a/src/lib-sieve/sieve-address-source.h b/src/lib-sieve/sieve-address-source.h index 7dad09bdafa952e34b37785477c1d9bb7595f1ce..d6bea2bada2e6de84988c74dbcefcbf5d8862964 100644 --- a/src/lib-sieve/sieve-address-source.h +++ b/src/lib-sieve/sieve-address-source.h @@ -11,6 +11,7 @@ enum sieve_address_source_type { SIEVE_ADDRESS_SOURCE_SENDER, SIEVE_ADDRESS_SOURCE_RECIPIENT, SIEVE_ADDRESS_SOURCE_ORIG_RECIPIENT, + SIEVE_ADDRESS_SOURCE_USER_EMAIL, SIEVE_ADDRESS_SOURCE_POSTMASTER, SIEVE_ADDRESS_SOURCE_EXPLICIT }; @@ -28,10 +29,11 @@ bool sieve_address_source_parse_from_setting const char *setting, struct sieve_address_source *asrc); int sieve_address_source_get_address -(struct sieve_address_source *asrc, - const struct sieve_script_env *senv, - struct sieve_message_context *msgctx, - enum sieve_execute_flags flags, - const char **addr_r); + (struct sieve_address_source *asrc, + struct sieve_instance *svinst, + const struct sieve_script_env *senv, + struct sieve_message_context *msgctx, + enum sieve_execute_flags flags, + const char **addr_r); #endif diff --git a/src/lib-sieve/sieve-common.h b/src/lib-sieve/sieve-common.h index 2c505549b1ba451f2b672b0ab706caea281892b7..705f9d95f58c47f6df391a30eccdec8bc64c469d 100644 --- a/src/lib-sieve/sieve-common.h +++ b/src/lib-sieve/sieve-common.h @@ -201,6 +201,7 @@ struct sieve_instance { size_t max_script_size; unsigned int max_actions; unsigned int max_redirects; + const struct sieve_address *user_email; struct sieve_address_source redirect_from; }; diff --git a/src/lib-sieve/sieve-settings.c b/src/lib-sieve/sieve-settings.c index 92fcb3d2f83eff93ccdeb5691c617a748748d3f4..8a967329380f7bed77899b5d2b1cb7f1f750c617 100644 --- a/src/lib-sieve/sieve-settings.c +++ b/src/lib-sieve/sieve-settings.c @@ -8,7 +8,8 @@ #include "sieve-common.h" #include "sieve-limits.h" #include "sieve-error.h" -#include "sieve-actions.h" +#include "sieve-address.h" +#include "sieve-address-source.h" #include "sieve-settings.h" #include <ctype.h> @@ -204,6 +205,7 @@ bool sieve_setting_get_duration_value void sieve_settings_load (struct sieve_instance *svinst) { + const char *str_setting; unsigned long long int uint_setting; size_t size_setting; @@ -228,6 +230,18 @@ void sieve_settings_load (void)sieve_address_source_parse_from_setting(svinst, svinst->pool, "sieve_redirect_envelope_from", &svinst->redirect_from); + + str_setting = sieve_setting_get(svinst, "sieve_user_email"); + if ( str_setting != NULL && *str_setting != '\0' ) { + svinst->user_email = + sieve_address_parse_envelope_path + (svinst->pool, str_setting); + if ( svinst->user_email == NULL ) { + sieve_sys_warning(svinst, + "Invalid address value for setting " + "`sieve_user_email': `%s'", str_setting); + } + } } diff --git a/tests/execute/smtp.svtest b/tests/execute/smtp.svtest index 08cbdcd29df21fe8229869351ec25cb4fb5d2574..e3d762582bb8b173b94e32dfb8d2bf642901ef1d 100644 --- a/tests/execute/smtp.svtest +++ b/tests/execute/smtp.svtest @@ -188,3 +188,53 @@ test "Redirect from <> with [<explicit>]" { test_fail "envelope sender incorrect"; } } + +test_result_reset; +test_set "envelope.from" "sirius@example.org"; +test_set "envelope.to" "timo@example.net"; +test_set "envelope.orig_to" "tss@example.net"; + +test_config_set "sieve_redirect_envelope_from" "user_email"; +test_config_reload; + +test "Redirect from [user email - fallback default]" { + redirect "cras@example.net"; + + if not test_result_execute { + test_fail "failed to execute redirect"; + } + + test_message :smtp 0; + + if not envelope :is "from" "timo@example.net" { + test_fail "envelope sender incorrect"; + } +} + +test_result_reset; +test_set "envelope.from" "sirius@example.org"; +test_set "envelope.to" "timo@example.net"; +test_set "envelope.orig_to" "tss@example.net"; + +test_config_set "sieve_redirect_envelope_from" "user_email"; +test_config_set "sieve_user_email" "t.sirainen@example.net"; +test_config_reload; + +test "Redirect from [user email]" { + redirect "cras@example.net"; + + if not test_result_execute { + test_fail "failed to execute redirect"; + } + + test_message :smtp 0; + + if envelope :is "from" "sirius@example.org" { + test_fail "envelope sender incorrect (not changed)"; + } + + if not envelope :is "from" "t.sirainen@example.net" { + test_fail "envelope sender incorrect"; + } +} + diff --git a/tests/extensions/enotify/mailto.svtest b/tests/extensions/enotify/mailto.svtest index afee1531c07c1647e0968db1d2361bfc9360a8e4..82f47be845eb56a878ccef45c14fc1d9c845e9c6 100644 --- a/tests/extensions/enotify/mailto.svtest +++ b/tests/extensions/enotify/mailto.svtest @@ -423,3 +423,63 @@ test "Envelope config - recipient" { test_fail "envelope recipient set incorrectly"; } } + +/* + * Envelope config - user_email + */ + +test_set "message" text: +From: stephan@example.org +To: nico@frop.example.org +Subject: Frop! + +Klutsefluts. +. +; + +test_set "envelope.from" "sirius@example.org"; +test_set "envelope.to" "bertus@frop.example.org"; + +test_config_set "sieve_notify_mailto_envelope_from" + "user_email"; +test_config_set "sieve_user_email" "b.wortel@example.org"; +test_config_reload; +test_config_reload :extension "enotify"; +test_result_reset; + +test "Envelope config - user_email" { + notify :from "nico@frop.example.org" + "mailto:stephan@example.org?cc=timo@example.com"; + + if not test_result_execute { + test_fail "failed to execute notify"; + } + + test_message :smtp 0; + + if not header :is "from" "nico@frop.example.org" { + test_fail "from set incorrectly"; + } + + if not envelope :is "from" "b.wortel@example.org" { + test_fail "envelope sender set incorrectly"; + } + + if not envelope :is "to" "stephan@example.org" { + test_fail "envelope recipient set incorrectly"; + } + + test_message :smtp 1; + + if not header :is "from" "nico@frop.example.org" { + test_fail "from set incorrectly"; + } + + if not envelope :is "from" "b.wortel@example.org" { + test_fail "envelope sender set incorrectly"; + } + + if not envelope :is "to" "timo@example.com" { + test_fail "envelope recipient set incorrectly"; + } +}