.cindex queues named
The name of the spool queue in use; empty for the default queue.
+.new
+.vitem &$r_...$&
+.vindex &$r_...$&
+.cindex router variables
+Values can be placed in these variables by the &%set%& option of a router.
+They can be given any name that starts with &$r_$&.
+The values persist for the address being handled through subsequent routers
+and the eventual transport.
+.wen
+
.vitem &$rcpt_count$&
.vindex "&$rcpt_count$&"
When a message is being received by SMTP, this variable contains the number of
This makes the configuration file less messy, and also reduces the number of
lookups (though Exim does cache lookups).
+.new
+See also the &%set%& option below.
+.wen
+
.vindex "&$sender_address_data$&"
.vindex "&$address_data$&"
The &%address_data%& facility is also useful as a means of passing information
matters.
+.new
+.option set routers string unset
+.cindex router variables
+This option may be used multiple times on a router.
+Each string given must be of the form $"name = value"$
+and the names used must start with the string &"r_"&.
+Strings are accumulated for each router which is run.
+When a router runs, the strings are evaluated in order,
+to create variables.
+The variable is set with the expansion of the value.
+The variables can be used by the router options
+(not including any preconditions)
+and by the transport.
+Later definitions of a given named variable will override former ones.
+Varible use is via the usual &$r_...$& syntax.
+
+This is similar to the &%address_data%& option, except that
+many independent variables can be used, with choice of naming.
+.wen
+
+
.option translate_ip_address routers string&!! unset
.cindex "IP address" "translating"
.cindex "packet radio"
8. Expansion operator ${sha2_N:} for N=256, 384, 512.
+ 9. Router variables, $r_... settable from router options and usable in routers
+ and transports.
+
Version 4.92
--------------
server_secret string* unset cram_md5 3.10
server_service string "smtp" cyrus_sasl,gsasl,heimdal_gssapi (cyrus-only) 4.80 (others)
server_set_id string* unset authenticators 3.10
+set string* unset routers 4.93
shadow_condition string* unset transports
shadow_transport string unset transports
size_addition integer 1024 smtp 1.91
+/************************************************/
+/* Set router-assigned variables, forgetting any previous.
+Return FALSE on failure */
+
+static BOOL
+set_router_vars(gstring * g_varlist)
+{
+const uschar * varlist;
+int sep = 0;
+
+router_var = NULL;
+if (!g_varlist) return TRUE;
+varlist = CUS string_from_gstring(g_varlist);
+
+/* Walk the varlist, creating variables */
+
+for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); )
+ {
+ const uschar * assignment = ele;
+ int esep = '=';
+ uschar * name = string_nextinlist(&assignment, &esep, NULL, 0);
+ tree_node * node, ** root = &router_var;
+
+ /* Variable name must exist and start "r_". */
+
+ if (!name || name[0] != 'r' || name[1] != '_' || !name[2])
+ return FALSE;
+ name += 2;
+
+ if (!(node = tree_search(*root, name)))
+ {
+ node = store_get(sizeof(tree_node) + Ustrlen(name));
+ Ustrcpy(node->name, name);
+ (void)tree_insertnode(root, node);
+ }
+ node->data.ptr = US assignment;
+ }
+return TRUE;
+}
+
+
/*************************************************
* Set expansion values for an address *
*************************************************/
deliver_address_data = addr->prop.address_data;
deliver_domain_data = addr->prop.domain_data;
deliver_localpart_data = addr->prop.localpart_data;
+set_router_vars(addr->prop.set); /*XXX failure cases? */
/* These may be unset for multiple addresses */
if ((Ustrncmp(name, "acl_c", 5) == 0 || Ustrncmp(name, "acl_m", 5) == 0) &&
!isalpha(name[5]))
{
- tree_node *node =
- tree_search((name[4] == 'c')? acl_var_c : acl_var_m, name + 4);
+ tree_node * node =
+ tree_search(name[4] == 'c' ? acl_var_c : acl_var_m, name + 4);
+ return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
+ }
+else if (Ustrncmp(name, "r_", 2) == 0)
+ {
+ tree_node * node = tree_search(router_var, name + 2);
return node ? node->data.ptr : strict_acl_vars ? NULL : US"";
}
.errors_address = NULL,
.extra_headers = NULL,
.remove_headers = NULL,
+ .set = NULL,
#ifdef EXPERIMENTAL_SRS
.srs_sender = NULL,
#endif
.retry_use_local_part = TRUE_UNSET,
.same_domain_copy_routing = FALSE,
.self_rewrite = FALSE,
+ .set = NULL,
.suffix_optional = FALSE,
.verify_only = FALSE,
.verify_recipient = TRUE,
};
uschar *router_name = NULL;
+tree_node *router_var = NULL;
ip_address_item *running_interfaces = NULL;
extern router_instance *routers; /* Chain of instantiated routers */
extern router_instance router_defaults;/* Default values */
extern uschar *router_name; /* Name of router last started */
+extern tree_node *router_var; /* Variables set by router */
extern ip_address_item *running_interfaces; /* Host's running interfaces */
extern uschar *running_status; /* Flag string for testing */
extern int runrc; /* rc from ${run} */
(void *)(offsetof(router_instance, self)) },
{ "senders", opt_stringptr|opt_public,
(void *)offsetof(router_instance, senders) },
+ { "set", opt_stringptr|opt_public|opt_rep_str,
+ (void *)offsetof(router_instance, set) },
#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
{ "translate_ip_address", opt_stringptr|opt_public,
(void *)offsetof(router_instance, translate_ip_address) },
new->prop.ignore_error = addr->prop.ignore_error;
new->prop.address_data = addr->prop.address_data;
+new->prop.set = addr->prop.set;
new->dsn_flags = addr->dsn_flags;
new->dsn_orcpt = addr->dsn_orcpt;
search_error_message = NULL;
+ /* Add any variable-settings that are on the router, to the list on the
+ addr. Expansion is done here and not later when the addr is used. There may
+ be multiple settings, gathered during readconf; this code gathers them during
+ router traversal. */
+
+ if (r->set)
+ {
+ const uschar * list = r->set;
+ int sep = 0;
+ for (uschar * ele; (ele = string_nextinlist(&list, &sep, NULL, 0)); )
+ {
+ uschar * ee;
+ if (!(ee = expand_string(ele)))
+ if (f.expand_string_forcedfail)
+ {
+ DEBUG(D_route) debug_printf("forced failure in expansion of \"%s\" "
+ "(router variable): decline action taken\n", ele);
+
+ /* Expand "more" if necessary; DEFER => an expansion failed */
+
+ yield = exp_bool(addr, US"router", r->name, D_route,
+ US"more", r->more, r->expand_more, &more);
+ if (yield != OK) goto ROUTE_EXIT;
+
+ if (!more)
+ {
+ DEBUG(D_route)
+ debug_printf("\"more\"=false: skipping remaining routers\n");
+ router_name = NULL;
+ r = NULL;
+ break;
+ }
+ else continue; /* With next router */
+ }
+ else
+ {
+ addr->message = string_sprintf("expansion of \"%s\" failed "
+ "in %s router: %s", ele, r->name, expand_string_message);
+ yield = DEFER;
+ goto ROUTE_EXIT;
+ }
+
+ addr->prop.set = string_append_listele(addr->prop.set, ':', ee);
+ }
+ }
+
/* Finally, expand the address_data field in the router. Forced failure
behaves as if the router declined. Any other failure is more serious. On
success, the string is attached to the address for all subsequent processing.
if (r->address_data)
{
DEBUG(D_route) debug_printf("processing address_data\n");
- deliver_address_data = expand_string(r->address_data);
- if (!deliver_address_data)
+ if (!(deliver_address_data = expand_string(r->address_data)))
{
if (f.expand_string_forcedfail)
{
bzero(&addr_prop, sizeof(addr_prop));
addr_prop.address_data = deliver_address_data;
+addr_prop.set = addr->prop.set;
rc = rf_get_errors_address(addr, rblock, verify, &addr_prop.errors_address);
if (rc != OK) return rc;
addr_prop.errors_address = NULL;
addr_prop.extra_headers = NULL;
addr_prop.remove_headers = NULL;
+addr_prop.set = addr->prop.set;
#ifdef EXPERIMENTAL_SRS
addr_prop.srs_sender = NULL;
BOOL retry_use_local_part; /* Just what it says */
BOOL same_domain_copy_routing; /* TRUE => copy routing for same domain */
BOOL self_rewrite; /* TRUE to rewrite headers if making local */
+ uschar *set; /* Variable = value to set; list */
BOOL suffix_optional; /* As it says */
BOOL verify_only; /* Skip this router if not verifying */
BOOL verify_recipient; /* Use this router when verifying a recipient*/
uschar *errors_address; /* where to send errors (NULL => sender) */
header_line *extra_headers; /* additional headers */
uschar *remove_headers; /* list of those to remove */
+ gstring *set; /* list of variables, with values */
#ifdef EXPERIMENTAL_SRS
uschar *srs_sender; /* Change return path when delivering */
vaddr->basic_errno = addr->basic_errno;
vaddr->more_errno = addr->more_errno;
vaddr->prop.address_data = addr->prop.address_data;
+ vaddr->prop.set = addr->prop.set;
copyflag(vaddr, addr, af_pass_message);
}
return yield;
of $address_data to be that of the child */
vaddr->prop.address_data = addr->prop.address_data;
+ vaddr->prop.set = addr->prop.set;
/* If stopped because more than one new address, cannot cutthrough */
--- /dev/null
+# Exim test configuration 0166
+
+.include DIR/aux-var/std_conf_prefix
+
+
+# ----- Main settings -----
+
+domainlist local_domains = test.ex
+qualify_domain = test.ex
+
+
+# ----- Routers -----
+
+begin routers
+
+alias:
+ driver = redirect
+ debug_print = DEBUG: $r_r1 $r_r2
+ data = b
+ set = r_r1 = $local_part
+
+user:
+ driver = accept
+ debug_print = DEBUG: $r_r1 $r_r2
+ set = r_r1 = $local_part
+ set = r_r2 = $local_part
+ transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+ driver = appendfile
+ envelope_to_add
+ file = DIR/test-mail/$local_part
+ user = CALLER
+ debug_print = DEBUG: $r_r1 $r_r2
+ headers_add = X-r1: $r_r1\nX-r2: $r_r2
+
+
+# End
--- /dev/null
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => b <a@test.ex> R=user T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
--- /dev/null
+From CALLER@test.ex Tue Mar 02 09:44:33 1999
+Envelope-to: a@test.ex
+Received: from CALLER by the.local.host.name with local (Exim x.yz)
+ (envelope-from <CALLER@test.ex>)
+ id 10HmaX-0005vi-00
+ for a@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@the.local.host.name>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-r1: b
+X-r2: b
+
+
--- /dev/null
+# router variables
+exim -odi a
router_home_directory = new macro2 + 1234
self = freeze
senders =
+set =
transport = T1
transport_current_directory =
transport_home_directory =
router_home_directory =
self = freeze
senders =
+set =
transport = t1
transport_current_directory =
transport_home_directory =