lib-sieve: vacation extension: finally added support for using the original recipient in vacation address check.
1.1 --- a/doc/vacation.txt Tue Aug 02 16:36:06 2011 +0200
1.2 +++ b/doc/vacation.txt Tue Aug 02 17:50:15 2011 +0200
1.3 @@ -31,9 +31,9 @@
1.4 day.
1.5
1.6 The vacation and vacation-seconds extensions have their own specific
1.7 -settings. The settings that specify a period (currently all of them)
1.8 -are specified in s(econds), unless followed by a d(ay), h(our) or m(inute)
1.9 -specifier character.
1.10 +settings. The settings that specify a period are specified in
1.11 +s(econds), unless followed by a d(ay), h(our) or m(inute) specifier
1.12 +character.
1.13
1.14 The following settings can be configured the vacation extension (default
1.15 values are indicated):
1.16 @@ -56,6 +56,27 @@
1.17 tag is specified. The configured value must lie between the
1.18 sieve_vacation_min_period and sieve_vacation_max_period.
1.19
1.20 +sieve_vacation_use_original_recipient = no
1.21 + This specifies whether the original envelope recipient should be used in
1.22 + the check for implicit delivery. The vacation command checks headers of
1.23 + the incoming message, such as To: and Cc: for the address of the
1.24 + recipient, to verify that the message is explicitly addressed at the
1.25 + recipient. If the recipient address is not found, the vacation action
1.26 + will not trigger a response to prevent sending a reply when it is not
1.27 + appropriate. Normally only the final recipient address is used in this
1.28 + check. This setting allows including the original recipient specified in
1.29 + the SMTP session if available. This is useful to handle mail accounts
1.30 + with aliases. Use this option with caution: if you are using aliases that
1.31 + point to more than a single account, senders can get multiple vacation
1.32 + responses for a single message.
1.33 +
1.34 +sieve_vacation_dont_check_recipient = no
1.35 + This disables the checks for implicit delivery entirely. This means that
1.36 + the vacation command does not verify that the message is explicitly
1.37 + addressed at the recipient. Use this option with caution. Specifying
1.38 + 'yes' will violate the Sieve standards and can cause vacation replies to
1.39 + be sent for messages not directly addressed at the recipient.
1.40 +
1.41 Invalid values for the settings above will make the Sieve interpreter log
1.42 a warning and revert to the default values.
1.43
2.1 --- a/src/lib-sieve/plugins/vacation/cmd-vacation.c Tue Aug 02 16:36:06 2011 +0200
2.2 +++ b/src/lib-sieve/plugins/vacation/cmd-vacation.c Tue Aug 02 17:50:15 2011 +0200
2.3 @@ -1017,11 +1017,11 @@
2.4 const struct sieve_script_env *senv = aenv->scriptenv;
2.5 struct act_vacation_context *ctx =
2.6 (struct act_vacation_context *) action->context;
2.7 - const char *const *hdsp;
2.8 unsigned char dupl_hash[MD5_RESULTLEN];
2.9 - const char *const *headers;
2.10 const char *sender = sieve_message_get_sender(aenv->msgctx);
2.11 const char *recipient = sieve_message_get_final_recipient(aenv->msgctx);
2.12 + const char *const *hdsp;
2.13 + const char *const *headers;
2.14 const char *reply_from = NULL;
2.15
2.16 /* Is the recipient unset?
2.17 @@ -1037,14 +1037,14 @@
2.18 if ( sender == NULL ) {
2.19 sieve_result_global_log(aenv, "discarded vacation reply to <>");
2.20 return TRUE;
2.21 - }
2.22 -
2.23 - /* Are we perhaps trying to respond to ourselves ?
2.24 + }
2.25 +
2.26 + /* Are we perhaps trying to respond to ourselves ?
2.27 */
2.28 if ( sieve_address_compare(sender, recipient, TRUE) == 0 ) {
2.29 sieve_result_global_log(aenv,
2.30 "discarded vacation reply to own address <%s>",
2.31 - str_sanitize(sender, 128));
2.32 + str_sanitize(sender, 128));
2.33 return TRUE;
2.34 }
2.35
2.36 @@ -1052,24 +1052,24 @@
2.37 */
2.38 if ( ctx->addresses != NULL ) {
2.39 const char * const *alt_address = ctx->addresses;
2.40 -
2.41 +
2.42 while ( *alt_address != NULL ) {
2.43 if ( sieve_address_compare(sender, *alt_address, TRUE) == 0 ) {
2.44 sieve_result_global_log(aenv,
2.45 "discarded vacation reply to own address <%s> "
2.46 "(as specified using :addresses argument)",
2.47 - str_sanitize(sender, 128));
2.48 + str_sanitize(sender, 128));
2.49 return TRUE;
2.50 }
2.51 alt_address++;
2.52 - }
2.53 + }
2.54 }
2.55 -
2.56 +
2.57 /* Did whe respond to this user before? */
2.58 if ( sieve_action_duplicate_check_available(senv) ) {
2.59 act_vacation_hash(ctx, sender, dupl_hash);
2.60 -
2.61 - if ( sieve_action_duplicate_check(senv, dupl_hash, sizeof(dupl_hash)) )
2.62 +
2.63 + if ( sieve_action_duplicate_check(senv, dupl_hash, sizeof(dupl_hash)) )
2.64 {
2.65 sieve_result_global_log(aenv,
2.66 "discarded duplicate vacation response to <%s>",
2.67 @@ -1077,7 +1077,7 @@
2.68 return TRUE;
2.69 }
2.70 }
2.71 -
2.72 +
2.73 /* Are we trying to respond to a mailing list ? */
2.74 hdsp = _list_headers;
2.75 while ( *hdsp != NULL ) {
2.76 @@ -1101,7 +1101,7 @@
2.77 if ( strcasecmp(*hdsp, "no") != 0 ) {
2.78 sieve_result_global_log(aenv,
2.79 "discarding vacation response to auto-submitted message from <%s>",
2.80 - str_sanitize(sender, 128));
2.81 + str_sanitize(sender, 128));
2.82 return TRUE;
2.83 }
2.84 hdsp++;
2.85 @@ -1124,59 +1124,73 @@
2.86 hdsp++;
2.87 }
2.88 }
2.89 -
2.90 +
2.91 /* Do not reply to system addresses */
2.92 if ( _is_system_address(sender) ) {
2.93 - sieve_result_global_log(aenv,
2.94 - "not sending vacation response to system address <%s>",
2.95 - str_sanitize(sender, 128));
2.96 - return TRUE;
2.97 - }
2.98 -
2.99 + sieve_result_global_log(aenv,
2.100 + "not sending vacation response to system address <%s>",
2.101 + str_sanitize(sender, 128));
2.102 + return TRUE;
2.103 + }
2.104 +
2.105 /* Is the original message directly addressed to the user or the addresses
2.106 - * specified using the :addresses tag?
2.107 + * specified using the :addresses tag?
2.108 */
2.109 - hdsp = _my_address_headers;
2.110 - while ( *hdsp != NULL ) {
2.111 - if ( mail_get_headers
2.112 - (msgdata->mail, *hdsp, &headers) >= 0 && headers[0] != NULL ) {
2.113 -
2.114 - if ( _contains_my_address(headers, recipient) ) {
2.115 - reply_from = recipient;
2.116 - break;
2.117 + if ( !config->dont_check_recipient ) {
2.118 + const char *orig_recipient = NULL;
2.119 +
2.120 + if ( config->use_original_recipient )
2.121 + orig_recipient = sieve_message_get_orig_recipient(aenv->msgctx);
2.122 +
2.123 + hdsp = _my_address_headers;
2.124 + while ( *hdsp != NULL ) {
2.125 + if ( mail_get_headers
2.126 + (msgdata->mail, *hdsp, &headers) >= 0 && headers[0] != NULL ) {
2.127 +
2.128 + if ( _contains_my_address(headers, recipient) ) {
2.129 + reply_from = recipient;
2.130 + break;
2.131 + }
2.132 +
2.133 + if ( orig_recipient != NULL && _contains_my_address(headers, orig_recipient) ) {
2.134 + reply_from = orig_recipient;
2.135 + break;
2.136 + }
2.137 +
2.138 + if ( ctx->addresses != NULL ) {
2.139 + bool found = FALSE;
2.140 + const char * const *my_address = ctx->addresses;
2.141 +
2.142 + while ( !found && *my_address != NULL ) {
2.143 + if ( (found=_contains_my_address(headers, *my_address)) )
2.144 + reply_from = *my_address;
2.145 + my_address++;
2.146 + }
2.147 +
2.148 + if ( found ) break;
2.149 + }
2.150 }
2.151 -
2.152 - if ( ctx->addresses != NULL ) {
2.153 - bool found = FALSE;
2.154 - const char * const *my_address = ctx->addresses;
2.155 -
2.156 - while ( !found && *my_address != NULL ) {
2.157 - found = _contains_my_address(headers, *my_address);
2.158 - reply_from = *my_address;
2.159 - my_address++;
2.160 - }
2.161 -
2.162 - if ( found ) break;
2.163 - }
2.164 + hdsp++;
2.165 }
2.166 - hdsp++;
2.167 - }
2.168
2.169 - if ( *hdsp == NULL ) {
2.170 - /* No, bail out */
2.171 - sieve_result_global_log(aenv,
2.172 - "discarding vacation response for message implicitly delivered to <%s>",
2.173 - recipient );
2.174 - return TRUE;
2.175 - }
2.176 -
2.177 +
2.178 + /* My address not found in the headers; we got an implicit delivery */
2.179 + if ( *hdsp == NULL ) {
2.180 + /* No, bail out */
2.181 + sieve_result_global_log(aenv,
2.182 + "discarding vacation response for message implicitly delivered to <%s>",
2.183 + recipient );
2.184 + return TRUE;
2.185 + }
2.186 + }
2.187 +
2.188 /* Send the message */
2.189 -
2.190 +
2.191 if ( act_vacation_send(aenv, ctx, sender, reply_from) ) {
2.192 sieve_number_t seconds;
2.193
2.194 sieve_result_global_log(aenv, "sent vacation response to <%s>",
2.195 - str_sanitize(sender, 128));
2.196 + str_sanitize(sender, 128));
2.197
2.198 /* Check period limits once more */
2.199 seconds = ctx->seconds;
3.1 --- a/src/lib-sieve/plugins/vacation/ext-vacation-common.c Tue Aug 02 16:36:06 2011 +0200
3.2 +++ b/src/lib-sieve/plugins/vacation/ext-vacation-common.c Tue Aug 02 17:50:15 2011 +0200
3.3 @@ -16,6 +16,7 @@
3.4 struct sieve_instance *svinst = ext->svinst;
3.5 struct ext_vacation_config *config;
3.6 sieve_number_t min_period, max_period, default_period;
3.7 + bool use_original_recipient, dont_check_recipient;
3.8
3.9 if ( *context != NULL ) {
3.10 ext_vacation_unload(ext);
3.11 @@ -48,11 +49,23 @@
3.12 "sieve_vacation_min_period < sieve_vacation_default_period < "
3.13 "sieve_vacation_max_period");
3.14 }
3.15 -
3.16 +
3.17 + if ( !sieve_setting_get_bool_value
3.18 + (svinst, "sieve_vacation_use_original_recipient", &use_original_recipient) ) {
3.19 + use_original_recipient = FALSE;
3.20 + }
3.21 +
3.22 + if ( !sieve_setting_get_bool_value
3.23 + (svinst, "sieve_vacation_dont_check_recipient", &dont_check_recipient) ) {
3.24 + dont_check_recipient = FALSE;
3.25 + }
3.26 +
3.27 config = i_new(struct ext_vacation_config, 1);
3.28 config->min_period = min_period;
3.29 config->max_period = max_period;
3.30 config->default_period = default_period;
3.31 + config->use_original_recipient = use_original_recipient;
3.32 + config->dont_check_recipient = dont_check_recipient;
3.33
3.34 *context = (void *) config;
3.35
4.1 --- a/src/lib-sieve/plugins/vacation/ext-vacation-common.h Tue Aug 02 16:36:06 2011 +0200
4.2 +++ b/src/lib-sieve/plugins/vacation/ext-vacation-common.h Tue Aug 02 17:50:15 2011 +0200
4.3 @@ -18,6 +18,8 @@
4.4 unsigned int min_period;
4.5 unsigned int max_period;
4.6 unsigned int default_period;
4.7 + bool use_original_recipient;
4.8 + bool dont_check_recipient;
4.9 };
4.10
4.11 /*
5.1 --- a/src/testsuite/testsuite-message.c Tue Aug 02 16:36:06 2011 +0200
5.2 +++ b/src/testsuite/testsuite-message.c Tue Aug 02 17:50:15 2011 +0200
5.3 @@ -33,6 +33,7 @@
5.4
5.5 static string_t *envelope_from;
5.6 static string_t *envelope_to;
5.7 +static string_t *envelope_orig_to;
5.8 static string_t *envelope_auth;
5.9
5.10 pool_t message_pool;
5.11 @@ -82,6 +83,7 @@
5.12 testsuite_message_set_data(testsuite_mail);
5.13
5.14 envelope_to = str_new(message_pool, 256);
5.15 + envelope_orig_to = str_new(message_pool, 256);
5.16 envelope_from = str_new(message_pool, 256);
5.17 envelope_auth = str_new(message_pool, 256);
5.18 }
5.19 @@ -111,7 +113,7 @@
5.20
5.21 sieve_message_context_flush(renv->msgctx);
5.22 }
5.23 -
5.24 +
5.25 void testsuite_message_deinit(void)
5.26 {
5.27 pool_unref(&message_pool);
5.28 @@ -144,6 +146,19 @@
5.29 sieve_message_context_flush(renv->msgctx);
5.30 }
5.31
5.32 +void testsuite_envelope_set_orig_recipient
5.33 +(const struct sieve_runtime_env *renv, const char *value)
5.34 +{
5.35 + str_truncate(envelope_orig_to, 0);
5.36 +
5.37 + if ( value != NULL )
5.38 + str_append(envelope_orig_to, value);
5.39 +
5.40 + testsuite_msgdata.orig_envelope_to = str_c(envelope_orig_to);
5.41 +
5.42 + sieve_message_context_flush(renv->msgctx);
5.43 +}
5.44 +
5.45 void testsuite_envelope_set_auth_user
5.46 (const struct sieve_runtime_env *renv, const char *value)
5.47 {
6.1 --- a/src/testsuite/testsuite-message.h Tue Aug 02 16:36:06 2011 +0200
6.2 +++ b/src/testsuite/testsuite-message.h Tue Aug 02 17:50:15 2011 +0200
6.3 @@ -26,6 +26,8 @@
6.4 (const struct sieve_runtime_env *renv, const char *value);
6.5 void testsuite_envelope_set_recipient
6.6 (const struct sieve_runtime_env *renv, const char *value);
6.7 +void testsuite_envelope_set_orig_recipient
6.8 + (const struct sieve_runtime_env *renv, const char *value);
6.9 void testsuite_envelope_set_auth_user
6.10 (const struct sieve_runtime_env *renv, const char *value);
6.11
7.1 --- a/src/testsuite/testsuite-objects.c Tue Aug 02 16:36:06 2011 +0200
7.2 +++ b/src/testsuite/testsuite-objects.c Tue Aug 02 17:50:15 2011 +0200
7.3 @@ -305,6 +305,7 @@
7.4 enum testsuite_object_envelope_field {
7.5 TESTSUITE_OBJECT_ENVELOPE_FROM,
7.6 TESTSUITE_OBJECT_ENVELOPE_TO,
7.7 + TESTSUITE_OBJECT_ENVELOPE_ORIG_TO,
7.8 TESTSUITE_OBJECT_ENVELOPE_AUTH_USER
7.9 };
7.10
7.11 @@ -324,6 +325,8 @@
7.12 return TESTSUITE_OBJECT_ENVELOPE_FROM;
7.13 if ( strcasecmp(identifier, "to") == 0 )
7.14 return TESTSUITE_OBJECT_ENVELOPE_TO;
7.15 + if ( strcasecmp(identifier, "orig_to") == 0 )
7.16 + return TESTSUITE_OBJECT_ENVELOPE_ORIG_TO;
7.17 if ( strcasecmp(identifier, "auth") == 0 )
7.18 return TESTSUITE_OBJECT_ENVELOPE_AUTH_USER;
7.19
7.20 @@ -337,6 +340,8 @@
7.21 return "from";
7.22 case TESTSUITE_OBJECT_ENVELOPE_TO:
7.23 return "to";
7.24 + case TESTSUITE_OBJECT_ENVELOPE_ORIG_TO:
7.25 + return "orig_to";
7.26 case TESTSUITE_OBJECT_ENVELOPE_AUTH_USER:
7.27 return "auth";
7.28 }
7.29 @@ -354,6 +359,9 @@
7.30 case TESTSUITE_OBJECT_ENVELOPE_TO:
7.31 testsuite_envelope_set_recipient(renv, str_c(value));
7.32 return TRUE;
7.33 + case TESTSUITE_OBJECT_ENVELOPE_ORIG_TO:
7.34 + testsuite_envelope_set_orig_recipient(renv, str_c(value));
7.35 + return TRUE;
7.36 case TESTSUITE_OBJECT_ENVELOPE_AUTH_USER:
7.37 testsuite_envelope_set_auth_user(renv, str_c(value));
7.38 return TRUE;
8.1 --- a/tests/extensions/vacation/reply.svtest Tue Aug 02 16:36:06 2011 +0200
8.2 +++ b/tests/extensions/vacation/reply.svtest Tue Aug 02 17:50:15 2011 +0200
8.3 @@ -207,6 +207,37 @@
8.4 }
8.5
8.6 /*
8.7 + * No reply to original recipient
8.8 + */
8.9 +
8.10 +test_result_reset;
8.11 +
8.12 +test_set "message" text:
8.13 +From: timo@example.com
8.14 +To: all@example.com
8.15 +Subject: Frop!
8.16 +
8.17 +Frop!
8.18 +.
8.19 +;
8.20 +
8.21 +test_set "envelope.from" "timo@example.com";
8.22 +test_set "envelope.to" "stephan@example.com";
8.23 +test_set "envelope.orig_to" "all@example.com";
8.24 +
8.25 +test "No reply for original recipient" {
8.26 + vacation "I am gone";
8.27 +
8.28 + if not test_result_execute {
8.29 + test_fail "failed to execute vacation";
8.30 + }
8.31 +
8.32 + if test_message :smtp 0 {
8.33 + test_fail "vacation not supposed to send message";
8.34 + }
8.35 +}
8.36 +
8.37 +/*
8.38 * Reply for normal mail
8.39 */
8.40
8.41 @@ -268,6 +299,73 @@
8.42 }
8.43 }
8.44
8.45 +/*
8.46 + * Reply for original recipient
8.47 + */
8.48
8.49 +test_result_reset;
8.50
8.51 +test_set "message" text:
8.52 +From: timo@example.com
8.53 +To: all@example.com
8.54 +Subject: Frop!
8.55
8.56 +Frop!
8.57 +.
8.58 +;
8.59 +
8.60 +test_set "envelope.from" "timo@example.com";
8.61 +test_set "envelope.to" "stephan@example.com";
8.62 +test_set "envelope.orig_to" "all@example.com";
8.63 +
8.64 +test_config_set "sieve_vacation_use_original_recipient" "yes";
8.65 +test_config_reload :extension "vacation";
8.66 +
8.67 +test "Reply for original recipient" {
8.68 + vacation "I am gone";
8.69 +
8.70 + if not test_result_execute {
8.71 + test_fail "failed to execute vacation";
8.72 + }
8.73 +
8.74 + if not test_message :smtp 0 {
8.75 + test_fail "vacation did not reply";
8.76 + }
8.77 +}
8.78 +
8.79 +/*
8.80 + * Reply for any recipient
8.81 + */
8.82 +
8.83 +test_result_reset;
8.84 +
8.85 +test_set "message" text:
8.86 +From: timo@example.com
8.87 +To: all@example.com
8.88 +Subject: Frop!
8.89 +
8.90 +Frop!
8.91 +.
8.92 +;
8.93 +
8.94 +test_set "envelope.from" "timo@example.com";
8.95 +test_set "envelope.to" "stephan@example.com";
8.96 +
8.97 +test_config_set "sieve_vacation_dont_check_recipient" "yes";
8.98 +test_config_reload :extension "vacation";
8.99 +
8.100 +test "Reply for any recipient" {
8.101 + vacation "I am gone";
8.102 +
8.103 + if not test_result_execute {
8.104 + test_fail "failed to execute vacation";
8.105 + }
8.106 +
8.107 + if not test_message :smtp 0 {
8.108 + test_fail "vacation did not reply";
8.109 + }
8.110 +}
8.111 +
8.112 +
8.113 +
8.114 +