-/* $Cambridge: exim/src/src/routers/redirect.c,v 1.15 2006/02/07 11:19:02 ph10 Exp $ */
-
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
/* See the file NOTICE for conditions of use and distribution. */
(void *)offsetof(redirect_router_options_block, file) },
{ "file_transport", opt_stringptr,
(void *)offsetof(redirect_router_options_block, file_transport_name) },
+ { "filter_prepend_home",opt_bit | (RDON_PREPEND_HOME << 16),
+ (void *)offsetof(redirect_router_options_block, bit_options) },
{ "forbid_blackhole", opt_bit | (RDON_BLACKHOLE << 16),
(void *)offsetof(redirect_router_options_block, bit_options) },
{ "forbid_exim_filter", opt_bit | (RDON_EXIM_FILTER << 16),
(void *)offsetof(redirect_router_options_block, forbid_pipe) },
{ "forbid_sieve_filter",opt_bit | (RDON_SIEVE_FILTER << 16),
(void *)offsetof(redirect_router_options_block, bit_options) },
+ { "forbid_smtp_code", opt_bool,
+ (void *)offsetof(redirect_router_options_block, forbid_smtp_code) },
{ "hide_child_in_errmsg", opt_bool,
(void *)offsetof(redirect_router_options_block, hide_child_in_errmsg) },
{ "ignore_eacces", opt_bit | (RDON_EACCES << 16),
(void *)offsetof(redirect_router_options_block, reply_transport_name) },
{ "rewrite", opt_bit | (RDON_REWRITE << 16),
(void *)offsetof(redirect_router_options_block, bit_options) },
+ { "sieve_enotify_mailto_owner", opt_stringptr,
+ (void *)offsetof(redirect_router_options_block, sieve_enotify_mailto_owner) },
{ "sieve_subaddress", opt_stringptr,
(void *)offsetof(redirect_router_options_block, sieve_subaddress) },
{ "sieve_useraddress", opt_stringptr,
NULL, /* sieve_subaddress */
NULL, /* sieve_useraddress */
NULL, /* sieve_vacation_directory */
+ NULL, /* sieve_enotify_mailto_owner */
NULL, /* syntax_errors_text */
NULL, /* syntax_errors_to */
NULL, /* qualify_domain */
NULL, /* srs_dbselect */
#endif
022, /* modemask */
- RDO_REWRITE, /* bit_options */
+ RDO_REWRITE | RDO_PREPEND_HOME, /* bit_options */
FALSE, /* check_ancestor */
TRUE_UNSET, /* check_owner */
TRUE_UNSET, /* check_group */
FALSE, /* forbid_file */
FALSE, /* forbid_filter_reply */
FALSE, /* forbid_pipe */
+ FALSE, /* forbid_smtp_code */
FALSE, /* hide_child_in_errmsg */
FALSE, /* one_time */
FALSE, /* qualify_preserve_domain */
int verify, address_item_propagated *addr_prop)
{
int frc = rf_get_errors_address(addr, rblock, verify,
- &(addr_prop->errors_address));
+ &addr_prop->errors_address);
if (frc != OK) return frc;
-addr->p.errors_address = addr_prop->errors_address;
-return rf_get_munge_headers(addr, rblock, &(addr_prop->extra_headers),
- &(addr_prop->remove_headers));
+addr->prop.errors_address = addr_prop->errors_address;
+return rf_get_munge_headers(addr, rblock, &addr_prop->extra_headers,
+ &addr_prop->remove_headers);
}
redirect_router_options_block *ob =
(redirect_router_options_block *)(rblock->options_block);
-while (generated != NULL)
+while (generated)
{
address_item *parent;
address_item *next = generated;
- uschar *errors_address = next->p.errors_address;
+ uschar *errors_address = next->prop.errors_address;
generated = next->next;
next->parent = addr;
orflag(next, addr, af_ignore_error);
next->start_router = rblock->redirect_router;
+ if (addr->child_count == SHRT_MAX)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
+ "child addresses for <%s>", rblock->name, SHRT_MAX, addr->address);
addr->child_count++;
next->next = *addr_new;
if (ob->one_time && !queue_2stage)
{
- for (parent = addr; parent->parent != NULL; parent = parent->parent);
+ for (parent = addr; parent->parent; parent = parent->parent) ;
next->onetime_parent = parent->address;
}
unless the ancestor was routed by a case-sensitive router. */
if (ob->check_ancestor)
- {
- for (parent = addr; parent != NULL; parent = parent->parent)
- {
- if (((parent->router != NULL && parent->router->caseful_local_part)?
- Ustrcmp(next->address, parent->address)
- :
- strcmpic(next->address, parent->address)
+ for (parent = addr; parent; parent = parent->parent)
+ if ((parent->router && parent->router->caseful_local_part
+ ? Ustrcmp(next->address, parent->address)
+ : strcmpic(next->address, parent->address)
) == 0)
{
DEBUG(D_route) debug_printf("generated parent replaced by child\n");
next->address = string_copy(addr->address);
break;
}
- }
- }
/* A user filter may, under some circumstances, set up an errors address.
If so, we must take care to re-instate it when we copy in the propagated
data so that it overrides any errors_to setting on the router. */
- next->p = *addr_prop;
- if (errors_address != NULL) next->p.errors_address = errors_address;
+ next->prop = *addr_prop;
+ if (errors_address != NULL) next->prop.errors_address = errors_address;
/* For pipes, files, and autoreplies, record this router as handling them,
because they don't go through the routing process again. Then set up uid,
}
}
+#ifdef SUPPORT_I18N
+ next->prop.utf8_msg = string_is_utf8(next->address)
+ || (sender_address && string_is_utf8(sender_address));
+#endif
+
DEBUG(D_route)
{
debug_printf("%s router generated %s\n %serrors_to=%s transport=%s\n",
rblock->name,
next->address,
testflag(next, af_pfr)? "pipe, file, or autoreply\n " : "",
- next->p.errors_address,
+ next->prop.errors_address,
(next->transport == NULL)? US"NULL" : next->transport->name);
if (testflag(next, af_uid_set))
else
debug_printf("gid=unset ");
+#ifdef SUPPORT_I18N
+ if (next->prop.utf8_msg) debug_printf("utf8 ");
+#endif
+
debug_printf("home=%s\n", next->home_dir);
}
}
redirect_router_options_block *ob =
(redirect_router_options_block *)(rblock->options_block);
address_item *generated = NULL;
-uschar *save_qualify_domain_recipient = qualify_domain_recipient;
+const uschar *save_qualify_domain_recipient = qualify_domain_recipient;
uschar *discarded = US"discarded";
address_item_propagated addr_prop;
error_block *eblock = NULL;
#ifdef EXPERIMENTAL_SRS
addr_prop.srs_sender = NULL;
#endif
+#ifdef SUPPORT_I18N
+addr_prop.utf8_msg = FALSE; /*XXX should we not copy this from the parent? */
+addr_prop.utf8_downcvt = FALSE;
+addr_prop.utf8_downcvt_maybe = FALSE;
+#endif
+
/* When verifying and testing addresses, the "logwrite" command in filters
must be bypassed. */
// eximsrs_db_set(FALSE, NULL);
*/
- if(ob->srs_alias != NULL ? (usedomain = expand_string(ob->srs_alias)) == NULL : 1)
- usedomain = deliver_domain;
+ if (!(usedomain = ob->srs_alias ? expand_string(ob->srs_alias) : NULL))
+ usedomain = string_copy(deliver_domain);
if((n_srs = eximsrs_forward(&res, sender_address, usedomain)) == OK)
{
}
frc = rda_interpret(&redirect, options, ob->include_directory,
- ob->sieve_vacation_directory, ob->sieve_useraddress, ob->sieve_subaddress,
- &ugid, &generated, &(addr->message), ob->skip_syntax_errors? &eblock : NULL,
- &filtertype, string_sprintf("%s router (recipient is %s)", rblock->name,
- addr->address));
+ ob->sieve_vacation_directory, ob->sieve_enotify_mailto_owner,
+ ob->sieve_useraddress, ob->sieve_subaddress, &ugid, &generated,
+ &(addr->message), ob->skip_syntax_errors? &eblock : NULL, &filtertype,
+ string_sprintf("%s router (recipient is %s)", rblock->name, addr->address));
qualify_domain_recipient = save_qualify_domain_recipient;
break;
/* FF_DEFER and FF_FAIL can arise only as a result of explicit commands
- (:fail: in an alias file or "fail" in a filter). If a configured message was
- supplied, allow it to be included in an SMTP response after verifying. */
+ (:defer: or :fail: in an alias file or "fail" in a filter). If a configured
+ message was supplied, allow it to be included in an SMTP response after
+ verifying. Remove any SMTP code if it is not allowed. */
case FF_DEFER:
- if (addr->message == NULL) addr->message = US"forced defer";
- else addr->user_message = addr->message;
- return DEFER;
+ yield = DEFER;
+ goto SORT_MESSAGE;
case FF_FAIL:
if ((xrc = sort_errors_and_headers(rblock, addr, verify, &addr_prop)) != OK)
return xrc;
add_generated(rblock, addr_new, addr, generated, &addr_prop, &ugid, pw);
+ yield = FAIL;
+
+ SORT_MESSAGE:
if (addr->message == NULL)
- addr->message = US"forced rejection";
+ addr->message = (yield == FAIL)? US"forced rejection" : US"forced defer";
else
{
+ int ovector[3];
+ if (ob->forbid_smtp_code &&
+ pcre_exec(regex_smtp_code, NULL, CS addr->message,
+ Ustrlen(addr->message), 0, PCRE_EOPT,
+ ovector, sizeof(ovector)/sizeof(int)) >= 0)
+ {
+ DEBUG(D_route) debug_printf("SMTP code at start of error message "
+ "is ignored because forbid_smtp_code is set\n");
+ addr->message += ovector[1];
+ }
addr->user_message = addr->message;
setflag(addr, af_pass_message);
}
- return FAIL;
+ return yield;
/* As in the case of a system filter, a freeze does not happen after a manual
thaw. In case deliveries were set up by the filter, we set the child count
data that propagates. */
copyflag(next, addr, af_propagate);
- next->p = addr_prop;
+ next->prop = addr_prop;
DEBUG(D_route) debug_printf("%s router autogenerated %s\n%s%s%s",
rblock->name,