-/* $Cambridge: exim/src/src/routers/manualroute.c,v 1.2 2005/01/04 10:00:44 ph10 Exp $ */
-
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
/* See the file NOTICE for conditions of use and distribution. */
/* Options specific to the manualroute router. */
optionlist manualroute_router_options[] = {
+ { "host_all_ignored", opt_stringptr,
+ (void *)(offsetof(manualroute_router_options_block, host_all_ignored)) },
{ "host_find_failed", opt_stringptr,
(void *)(offsetof(manualroute_router_options_block, host_find_failed)) },
{ "hosts_randomize", opt_bool,
/* Default private options block for the manualroute router. */
manualroute_router_options_block manualroute_router_option_defaults = {
- hff_freeze, /* host_find_failed code */
+ -1, /* host_all_ignored code (unset) */
+ -1, /* host_find_failed code (unset) */
FALSE, /* hosts_randomize */
+ US"defer", /* host_all_ignored */
US"freeze", /* host_find_failed */
NULL, /* route_data */
NULL /* route_list */
};
+/* Names and values for host_find_failed and host_all_ignored. */
+
+static uschar *hff_names[] = {
+ US"ignore", /* MUST be first - not valid for host_all_ignored */
+ US"decline",
+ US"defer",
+ US"fail",
+ US"freeze",
+ US"pass" };
+
+static int hff_codes[] = { hff_ignore, hff_decline, hff_defer, hff_fail,
+ hff_freeze, hff_pass };
+
+static int hff_count= sizeof(hff_codes)/sizeof(int);
{
manualroute_router_options_block *ob =
(manualroute_router_options_block *)(rblock->options_block);
+int i;
/* Host_find_failed must be a recognized word */
-if (Ustrcmp(ob->host_find_failed, "freeze") == 0)
- ob->hff_code = hff_freeze;
-else if (Ustrcmp(ob->host_find_failed, "decline") == 0)
- ob->hff_code = hff_decline;
-else if (Ustrcmp(ob->host_find_failed, "defer") == 0)
- ob->hff_code = hff_defer;
-else if (Ustrcmp(ob->host_find_failed, "pass") == 0)
- ob->hff_code = hff_pass;
-else if (Ustrcmp(ob->host_find_failed, "fail") == 0)
- ob->hff_code = hff_fail;
-else
+for (i = 0; i < hff_count; i++)
+ {
+ if (Ustrcmp(ob->host_find_failed, hff_names[i]) == 0)
+ {
+ ob->hff_code = hff_codes[i];
+ break;
+ }
+ }
+if (ob->hff_code < 0)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
"unrecognized setting for host_find_failed option", rblock->name);
+for (i = 1; i < hff_count; i++) /* NB starts at 1 to skip "ignore" */
+ {
+ if (Ustrcmp(ob->host_all_ignored, hff_names[i]) == 0)
+ {
+ ob->hai_code = hff_codes[i];
+ break;
+ }
+ }
+if (ob->hai_code < 0)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n "
+ "unrecognized setting for host_all_ignored option", rblock->name);
+
/* One of route_list or route_data must be specified */
if ((ob->route_list == NULL && ob->route_data == NULL) ||
*/
static BOOL
-parse_route_item(uschar *s, uschar **domain, uschar **hostlist,
- uschar **options)
+parse_route_item(const uschar *s, const uschar **domain, const uschar **hostlist,
+ const uschar **options)
{
while (*s != 0 && isspace(*s)) s++;
router_instance *rblock, /* data for this instantiation */
address_item *addr, /* address we are working on */
struct passwd *pw, /* passwd entry after check_local_user */
- BOOL verify, /* TRUE when verifying */
+ int verify, /* v_none/v_recipient/v_sender/v_expn */
address_item **addr_local, /* add it to this if it's local */
address_item **addr_remote, /* add it to this if it's remote */
address_item **addr_new, /* put new addresses on here */
{
int rc, lookup_type;
uschar *route_item = NULL;
-uschar *options = NULL;
-uschar *hostlist = NULL;
-uschar *domain, *newhostlist, *listptr;
+const uschar *options = NULL;
+const uschar *hostlist = NULL;
+const uschar *domain;
+uschar *newhostlist;
+const uschar *listptr;
manualroute_router_options_block *ob =
(manualroute_router_options_block *)(rblock->options_block);
transport_instance *transport = NULL;
/* Check the current domain; if it matches, break the loop */
if ((rc = match_isinlist(addr->domain, &domain, UCHAR_MAX+1,
- &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, &lookup_value)) == OK)
+ &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, CUSS &lookup_value)) == OK)
break;
/* If there was a problem doing the check, defer */
while (*options != 0)
{
- int term;
- uschar *s = options;
+ unsigned n;
+ const uschar *s = options;
while (*options != 0 && !isspace(*options)) options++;
- term = *options;
- *options = 0;
+ n = options-s;
- if (Ustrcmp(s, "randomize") == 0) randomize = TRUE;
- else if (Ustrcmp(s, "no_randomize") == 0) randomize = FALSE;
- else if (Ustrcmp(s, "byname") == 0) lookup_type = lk_byname;
- else if (Ustrcmp(s, "bydns") == 0) lookup_type = lk_bydns;
+ if (Ustrncmp(s, "randomize", n) == 0) randomize = TRUE;
+ else if (Ustrncmp(s, "no_randomize", n) == 0) randomize = FALSE;
+ else if (Ustrncmp(s, "byname", n) == 0) lookup_type = lk_byname;
+ else if (Ustrncmp(s, "bydns", n) == 0) lookup_type = lk_bydns;
else
{
transport_instance *t;
for (t = transports; t != NULL; t = t->next)
- {
if (Ustrcmp(t->name, s) == 0)
{
transport = t;
individual_transport_set = TRUE;
break;
}
- }
+
if (t == NULL)
{
s = string_sprintf("unknown routing option or transport name \"%s\"", s);
}
}
- if (term != 0)
+ if (*options)
{
options++;
while (*options != 0 && isspace(*options)) options++;
/* Set up the errors address, if any. */
-rc = rf_get_errors_address(addr, rblock, verify, &(addr->p.errors_address));
+rc = rf_get_errors_address(addr, rblock, verify, &addr->prop.errors_address);
if (rc != OK) return rc;
/* Set up the additional and removeable headers for this address. */
-rc = rf_get_munge_headers(addr, rblock, &(addr->p.extra_headers),
- &(addr->p.remove_headers));
+rc = rf_get_munge_headers(addr, rblock, &addr->prop.extra_headers,
+ &addr->prop.remove_headers);
if (rc != OK) return rc;
/* If an individual transport is not set, get the transport for this router, if
if (hostlist[0] == 0)
{
- if (verify) goto ROUTED;
+ if (verify != v_none) goto ROUTED;
addr->message = string_sprintf("error in %s router: no host(s) specified "
- "for domain %s", rblock->name, domain);
+ "for domain %s", rblock->name, addr->domain);
log_write(0, LOG_MAIN, "%s", addr->message);
return DEFER;
}
ob->hff_code, addr_new);
if (rc != OK) return rc;
+/* If host_find_failed is set to "ignore", it is possible for all the hosts to
+be ignored, in which case we will end up with an empty host list. What happens
+is controlled by host_all_ignored. */
+
+if (addr->host_list == NULL)
+ {
+ int i;
+ DEBUG(D_route) debug_printf("host_find_failed ignored every host\n");
+ if (ob->hai_code == hff_decline) return DECLINE;
+ if (ob->hai_code == hff_pass) return PASS;
+
+ for (i = 0; i < hff_count; i++)
+ if (ob->hai_code == hff_codes[i]) break;
+
+ addr->message = string_sprintf("lookup failed for all hosts in %s router: "
+ "host_find_failed=ignore host_all_ignored=%s", rblock->name, hff_names[i]);
+
+ if (ob->hai_code == hff_defer) return DEFER;
+ if (ob->hai_code == hff_fail) return FAIL;
+
+ addr->special_action = SPECIAL_FREEZE;
+ return DEFER;
+ }
+
/* Finally, since we have done all the routing here, there must be a transport
defined for these hosts. It will be a remote one, as a local transport is
dealt with above. However, we don't need one if verifying only. */
-if (transport == NULL && !verify)
+if (transport == NULL && verify == v_none)
{
log_write(0, LOG_MAIN, "Error in %s router: no transport defined",
rblock->name);