of domains that it defines.
.next
.vindex "&$local_part_prefix$&"
+.vindex "&$local_part_prefix_v$&"
.vindex "&$local_part$&"
.vindex "&$local_part_suffix$&"
+.vindex "&$local_part_suffix_v$&"
.cindex affix "router precondition"
If the &%local_parts%& option is set, the local part of the address must be in
the set of local parts that it defines. If &%local_part_prefix%& or
&%local_part_suffix%& is in use, the prefix or suffix is removed from the local
part before this check. If you want to do precondition tests on local parts
that include affixes, you can do so by using a &%condition%& option (see below)
-that uses the variables &$local_part$&, &$local_part_prefix$&, and
-&$local_part_suffix$& as necessary.
+.new
+that uses the variables &$local_part$&, &$local_part_prefix$&,
+&$local_part_prefix_v$&, &$local_part_suffix$&
+and &$local_part_suffix_v$& as necessary.
+.wen
.next
.vindex "&$local_user_uid$&"
.vindex "&$local_user_gid$&"
.wen
.vindex "&$local_part_prefix$&"
+.vindex "&$local_part_prefix_v$&"
.vindex "&$local_part_suffix$&"
+.vindex "&$local_part_suffix_v$&"
.cindex affix variables
If a local part prefix or suffix has been recognized, it is not included in the
value of &$local_part$& during routing and subsequent delivery. The values of
any prefix or suffix are in &$local_part_prefix$& and
&$local_part_suffix$&, respectively.
+.new
+If the affix specification included a wildcard then the portion of
+the affix matched by the wildcard is in
+&$local_part_prefix_v$& or &$local_part_suffix_v$& as appropriate.
+.wen
When a message is being delivered to a file, pipe, or autoreply transport as a
result of aliasing or forwarding, &$local_part$& is set to the local part of
specific prefix for the local part was recognized, it is available in this
variable, having been removed from &$local_part$&.
+.new
+.vitem &$local_part_prefix_v$&
+.vindex "&$local_part_prefix_v$&"
+When &$local_part_prefix$& is valid and the prefix match used a wildcard,
+the portion matching the wildcard is available in this variable.
+.wen
+
.vitem &$local_part_suffix$&
.vindex "&$local_part_suffix$&"
When an address is being routed or delivered, and a
specific suffix for the local part was recognized, it is available in this
variable, having been removed from &$local_part$&.
+.new
+.vitem &$local_part_suffix_v$&
+.vindex "&$local_part_suffix_v$&"
+When &$local_part_suffix$& is valid and the suffix match used a wildcard,
+the portion matching the wildcard is available in this variable.
+.wen
+
.new
.vitem &$local_part_verified$&
.vindex "&$local_part_verified$&"
This behaviour can be overridden by setting &%rcpt_include_affixes%& true on
the relevant transport.
+.new
+.vindex &$local_part_prefix_v$&
+If wildcarding (above) was used then the part of the prefix matching the
+wildcard is available in &$local_part_prefix_v$&.
+.wen
+
When an address is being verified, &%local_part_prefix%& affects only the
behaviour of the router. If the callout feature of verification is in use, this
means that the full address, including the prefix, will be used during the
9. Items specified for the router and transport headers_remove option can use
a trailing asterisk to specify globbing.
-10. New "queue_size" variable.
+10. New $queue_size variable.
+
+11. New variables $local_part_{pre,suf}fix_v.
deliver_localpart = addr->local_part;
deliver_localpart_prefix = addr->prefix;
+ deliver_localpart_prefix_v = addr->prefix_v;
deliver_localpart_suffix = addr->suffix;
+ deliver_localpart_suffix_v = addr->suffix_v;
for (addr_orig = addr; addr_orig->parent; addr_orig = addr_orig->parent) ;
deliver_domain_orig = addr_orig->domain;
else if (deliver_localpart[0] == '|') address_pipe = addr->local_part;
deliver_localpart = addr->parent->local_part;
deliver_localpart_prefix = addr->parent->prefix;
+ deliver_localpart_prefix_v = addr->parent->prefix_v;
deliver_localpart_suffix = addr->parent->suffix;
+ deliver_localpart_suffix_v = addr->parent->suffix_v;
}
}
{ "local_part", vtype_stringptr, &deliver_localpart },
{ "local_part_data", vtype_stringptr, &deliver_localpart_data },
{ "local_part_prefix", vtype_stringptr, &deliver_localpart_prefix },
+ { "local_part_prefix_v", vtype_stringptr, &deliver_localpart_prefix_v },
{ "local_part_suffix", vtype_stringptr, &deliver_localpart_suffix },
+ { "local_part_suffix_v", vtype_stringptr, &deliver_localpart_suffix_v },
{ "local_part_verified", vtype_stringptr, &deliver_localpart_verified },
#ifdef HAVE_LOCAL_SCAN
{ "local_scan_data", vtype_stringptr, &local_scan_data },
uschar **);
extern int route_address(address_item *, address_item **, address_item **,
address_item **, address_item **, int);
-extern int route_check_prefix(const uschar *, const uschar *);
-extern int route_check_suffix(const uschar *, const uschar *);
+extern int route_check_prefix(const uschar *, const uschar *, unsigned *);
+extern int route_check_suffix(const uschar *, const uschar *, unsigned *);
extern BOOL route_findgroup(uschar *, gid_t *);
extern BOOL route_finduser(const uschar *, struct passwd **, uid_t *);
extern BOOL route_find_expanded_group(uschar *, uschar *, uschar *, gid_t *,
.lc_local_part = NULL,
.local_part = NULL,
.prefix = NULL,
+ .prefix_v = NULL,
.suffix = NULL,
+ .suffix_v = NULL,
.domain = NULL,
.address_retry_key = NULL,
.domain_retry_key = NULL,
uschar *deliver_localpart_orig = NULL;
uschar *deliver_localpart_parent = NULL;
uschar *deliver_localpart_prefix = NULL;
+uschar *deliver_localpart_prefix_v = NULL;
uschar *deliver_localpart_suffix = NULL;
+uschar *deliver_localpart_suffix_v = NULL;
uschar *deliver_localpart_verified = NULL;
uschar *deliver_out_buffer = NULL;
int deliver_queue_load_max = -1;
extern uschar *deliver_localpart_orig; /* The original local part for delivery */
extern uschar *deliver_localpart_parent; /* The parent local part for delivery */
extern uschar *deliver_localpart_prefix; /* The stripped prefix, if any */
+extern uschar *deliver_localpart_prefix_v; /* The stripped-prefix variable portion, if any */
extern uschar *deliver_localpart_suffix; /* The stripped suffix, if any */
+extern uschar *deliver_localpart_suffix_v; /* The stripped-suffix variable portion, if any */
extern uschar *deliver_localpart_verified; /* de-tainted by check_local_part */
extern uschar *deliver_out_buffer; /* Buffer for copying file */
extern int deliver_queue_load_max; /* Different value for queue running */
uschar *at = domain ? from_address + domain - 1 : NULL;
if (at) *at = 0;
- from_address += route_check_prefix(from_address, local_from_prefix);
- slen = route_check_suffix(from_address, local_from_suffix);
- if (slen > 0)
+ from_address += route_check_prefix(from_address, local_from_prefix, NULL);
+ if ((slen = route_check_suffix(from_address, local_from_suffix, NULL)) > 0)
{
memmove(from_address+slen, from_address, Ustrlen(from_address)-slen);
from_address += slen;
Arguments:
local_part the local part to check
prefixes the list of prefixes
+ vp if set, pointer to place for size of wildcard portion
Returns: length of matching prefix or zero
*/
int
-route_check_prefix(const uschar *local_part, const uschar *prefixes)
+route_check_prefix(const uschar * local_part, const uschar * prefixes,
+ unsigned * vp)
{
int sep = 0;
uschar *prefix;
const uschar *listptr = prefixes;
-uschar prebuf[64];
-while ((prefix = string_nextinlist(&listptr, &sep, prebuf, sizeof(prebuf))))
+while ((prefix = string_nextinlist(&listptr, &sep, NULL, 0)))
{
int plen = Ustrlen(prefix);
if (prefix[0] == '*')
prefix++;
for (const uschar * p = local_part + Ustrlen(local_part) - (--plen);
p >= local_part; p--)
- if (strncmpic(prefix, p, plen) == 0) return plen + p - local_part;
+ if (strncmpic(prefix, p, plen) == 0)
+ {
+ unsigned vlen = p - local_part;
+ if (vp) *vp = vlen;
+ return plen + vlen;
+ }
}
else
- if (strncmpic(prefix, local_part, plen) == 0) return plen;
+ if (strncmpic(prefix, local_part, plen) == 0)
+ {
+ if (vp) *vp = 0;
+ return plen;
+ }
}
return 0;
Arguments:
local_part the local part to check
suffixes the list of suffixes
+ vp if set, pointer to place for size of wildcard portion
Returns: length of matching suffix or zero
*/
int
-route_check_suffix(const uschar *local_part, const uschar *suffixes)
+route_check_suffix(const uschar * local_part, const uschar * suffixes,
+ unsigned * vp)
{
int sep = 0;
int alen = Ustrlen(local_part);
uschar *suffix;
const uschar *listptr = suffixes;
-uschar sufbuf[64];
-while ((suffix = string_nextinlist(&listptr, &sep, sufbuf, sizeof(sufbuf))))
+while ((suffix = string_nextinlist(&listptr, &sep, NULL, 0)))
{
int slen = Ustrlen(suffix);
if (suffix[slen-1] == '*')
{
- const uschar *pend = local_part + alen - (--slen) + 1;
+ const uschar * pend = local_part + alen - (--slen) + 1;
for (const uschar * p = local_part; p < pend; p++)
- if (strncmpic(suffix, p, slen) == 0) return alen - (p - local_part);
+ if (strncmpic(suffix, p, slen) == 0)
+ {
+ int tlen = alen - (p - local_part);
+ if (vp) *vp = tlen - slen;
+ return tlen;
+ }
}
else
if (alen > slen && strncmpic(suffix, local_part + alen - slen, slen) == 0)
+ {
+ if (vp) *vp = 0;
return slen;
+ }
}
return 0;
/* Default no affixes and select whether to use a caseful or caseless local
part in this router. */
- addr->prefix = addr->suffix = NULL;
- addr->local_part = r->caseful_local_part?
- addr->cc_local_part : addr->lc_local_part;
+ addr->prefix = addr->prefix_v = addr->suffix = addr->suffix_v = NULL;
+ addr->local_part = r->caseful_local_part
+ ? addr->cc_local_part : addr->lc_local_part;
DEBUG(D_route) debug_printf("local_part=%s domain=%s\n", addr->local_part,
addr->domain);
if (r->prefix)
{
- int plen = route_check_prefix(addr->local_part, r->prefix);
+ unsigned vlen;
+ int plen = route_check_prefix(addr->local_part, r->prefix, &vlen);
if (plen > 0)
{
addr->prefix = string_copyn(addr->local_part, plen);
+ if (vlen) addr->prefix_v = string_copyn(addr->local_part, vlen);
addr->local_part += plen;
DEBUG(D_route) debug_printf("stripped prefix %s\n", addr->prefix);
}
if (r->suffix)
{
- int slen = route_check_suffix(addr->local_part, r->suffix);
+ unsigned vlen;
+ int slen = route_check_suffix(addr->local_part, r->suffix, &vlen);
if (slen > 0)
{
int lplen = Ustrlen(addr->local_part) - slen;
addr->suffix = addr->local_part + lplen;
+ addr->suffix_v = addr->suffix + Ustrlen(addr->suffix) - vlen;
addr->local_part = string_copyn(addr->local_part, lplen);
DEBUG(D_route) debug_printf("stripped suffix %s\n", addr->suffix);
}
uschar *lc_local_part; /* lowercased local part */
uschar *local_part; /* points to cc or lc version */
uschar *prefix; /* stripped prefix of local part */
+ uschar *prefix_v; /* variable part of above */
uschar *suffix; /* stripped suffix of local part */
+ uschar *suffix_v; /* variable part of above */
const uschar *domain; /* working domain (lower cased) */
uschar *address_retry_key; /* retry key including full address */
return addr->address;
}
-if (addr->suffix == NULL)
+if (!addr->suffix)
{
- if (addr->prefix == NULL) return addr->address;
+ if (!addr->prefix) return addr->address;
return addr->address + Ustrlen(addr->prefix);
}
at = Ustrrchr(addr->address, '@');
-plen = (addr->prefix == NULL)? 0 : Ustrlen(addr->prefix);
+plen = addr->prefix ? Ustrlen(addr->prefix) : 0;
slen = Ustrlen(addr->suffix);
return string_sprintf("%.*s@%s", (int)(at - addr->address - plen - slen),
file = DIR/test-mail/${bless:$local_part}
return_path_add
headers_add = X-local_part: $local_part\n\
- X-local_part_prefix: $local_part_prefix
+ X-local_part_prefix: $local_part_prefix\n\
+ X-local_part_prefix_v: $local_part_prefix_v
local_delivery_b:
driver = appendfile
return_path_add
use_bsmtp
headers_add = X-local_part: $local_part\n\
- X-local_part_prefix: $local_part_prefix
+ X-local_part_prefix: $local_part_prefix\n\
+ X-local_part_prefix_v: $local_part_prefix_v
delivery_s:
driver = smtp
user = CALLER
delivery_date_add
envelope_to_add
- file = DIR/test-mail/${bless:$local_part}
+ headers_add = X-local_part: $local_part\n\
+ X-local_part_suffix: $local_part_suffix\n\
+ X-local_part_suffix_v: $local_part_suffix_v
return_path_add
+ file = DIR/test-mail/${bless:$local_part}
address_reply:
driver = autoreply
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: CALLER
X-local_part_prefix:
+X-local_part_prefix_v:
--NNNNNNNNNN-eximdsn-MMMMMMMMMM
Content-type: text/plain; charset=us-ascii
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: CALLER
X-local_part_prefix:
+X-local_part_prefix_v:
--NNNNNNNNNN-eximdsn-MMMMMMMMMM
Content-type: text/plain; charset=us-ascii
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: userx
X-local_part_prefix: page+
+X-local_part_prefix_v: page
Some message text.
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: userx
X-local_part_prefix:
+X-local_part_prefix_v:
callpager -r 108 PAGE:Some message text.
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: userx
X-local_part_prefix: page+
+X-local_part_prefix_v: page
Some more message text.
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: userx
X-local_part_prefix:
+X-local_part_prefix_v:
callpager -r 108 PAGE:Some more message text.
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: userx
X-local_part_prefix: b+
+X-local_part_prefix_v:
Text.
.
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: userx
X-local_part_prefix:
+X-local_part_prefix_v:
.
MAIL FROM:<CALLER@test.ex>
Date: Tue, 2 Mar 1999 09:44:33 +0000
X-local_part: userx
X-local_part_prefix: x+
+X-local_part_prefix_v: x
.
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-local_part: userx
+X-local_part_suffix: +page
+X-local_part_suffix_v: page
Some message text.
Message-Id: <E10HmaY-0005vi-00@the.local.host.name>
From: CALLER_NAME <CALLER@test.ex>
Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-local_part: userx
+X-local_part_suffix:
+X-local_part_suffix_v:
callpager -r 108 PAGE:Some message text.
# local part suffix
exim -odi userx+page
Some message text.
+****