Add variables for wildcard portion of local-part affix. Bug 281
authorJeremy Harris <jgh146exb@wizmail.org>
Sat, 29 Feb 2020 16:30:35 +0000 (16:30 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Sat, 29 Feb 2020 17:43:26 +0000 (17:43 +0000)
17 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/src/deliver.c
src/src/expand.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/receive.c
src/src/route.c
src/src/structs.h
src/src/transport.c
test/confs/0015
test/confs/0016
test/mail/0015.CALLER
test/mail/0015.userx
test/mail/0016.userx
test/scripts/0000-Basic/0016

index bba71b76d14d04f55bbf6adea73386208c3c46de..f9bdbd8ec93cb9f8074b8dc7661d1a78a433beae 100644 (file)
@@ -1399,16 +1399,21 @@ If the &%domains%& option is set, the domain of the address must be in the set
 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$&"
@@ -12447,12 +12452,19 @@ the retrieved data.
 .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
@@ -12506,12 +12518,26 @@ When an address is being routed or delivered, and a
 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$&"
@@ -18785,6 +18811,12 @@ command for LMTP, SMTP, and BSMTP deliveries has the prefix removed by default.
 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
index 3cef43c320955c4a77fc2347eebcb8f7c6ad0512..fb6e444d33cbf5f6ce72659f5f15240ac5696f11 100644 (file)
@@ -39,7 +39,9 @@ Version 4.94
  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.
 
 
 
index 467813800ff5f3b3e16f5778cf9280fada4a6075..5c5167b3a94f42b5e9139afd2a30be14284a1ec8 100644 (file)
@@ -220,7 +220,9 @@ if (!addr->next)
 
   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;
@@ -260,7 +262,9 @@ if (!addr->next)
       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;
       }
     }
 
index 661959306bbb6d6f0d06c626b0226486a2883dea..660fe98cfc7ffe4f971a642ebd989ed47a34abff 100644 (file)
@@ -589,7 +589,9 @@ static var_entry var_table[] = {
   { "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 },
index be929a7108b47ad586a43cb71fbf8a86cb25b725..df4b33606982b574322c3f5c9127ad3160ba2ddf 100644 (file)
@@ -421,8 +421,8 @@ extern uschar *rfc2047_decode2(uschar *, BOOL, uschar *, int, int *, int *,
                  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 *,
index a5711c73b205e9f00069a3137590046912ec4c62..4ce15acaaac7c98f37d08c02785adf13f770a146 100644 (file)
@@ -541,7 +541,9 @@ address_item address_defaults = {
   .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,
@@ -822,7 +824,9 @@ uschar *deliver_localpart_data = 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;
index b570078c3af3d0e22c7922c5a11182a85446680c..1fea9c9b00e3345f27c16bfcc0a7ed87df309ec5 100644 (file)
@@ -490,7 +490,9 @@ extern uschar *deliver_localpart_data; /* From local part lookup */
 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 */
index f30ffd92d68fc613823671e07b54987794fb095c..96a48fe655eb7e3132c1b9787bf907d7fd92d1d8 100644 (file)
@@ -2907,9 +2907,8 @@ if (  from_header
     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;
index a1426d58f9dc7a701e2520bedf78b9a4cf47f615..8b43613ce9a477fbc0a40a6a701da151258695f3 100644 (file)
@@ -335,19 +335,20 @@ wildcard.
 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] == '*')
@@ -355,10 +356,19 @@ while ((prefix = string_nextinlist(&listptr, &sep, prebuf, sizeof(prebuf))))
     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;
@@ -377,31 +387,40 @@ is a wildcard.
 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;
@@ -1620,9 +1639,9 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
   /* 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);
@@ -1633,10 +1652,12 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
 
   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);
       }
@@ -1652,11 +1673,13 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
 
   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);
       }
index aa394ac7347c092983c89831f271a0dbf643a15a..7d700fb72ad0333849c18a4bc020ea5851a38f85 100644 (file)
@@ -553,7 +553,9 @@ typedef struct address_item {
   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 */
index d9eba1621fa7c6344f6bb0cf37ef6cbc89b8e4f6..90789fd606e8d33d5df876897438841618376aee 100644 (file)
@@ -591,14 +591,14 @@ if (include_affixes)
   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),
index 8c62e2e08d255c4b96a35bb23c7e0d3182b9793a..b1472da06cc78136a9c9d0cad077d5390264c21c 100644 (file)
@@ -83,7 +83,8 @@ local_delivery:
   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
@@ -94,7 +95,8 @@ local_delivery_b:
   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
index dcc005f0b3f81c7dba6d091fc5a20dbc1e71bfca..9e190d8ebd0b74388f65535d0e4bf64e1c8990e1 100644 (file)
@@ -39,8 +39,11 @@ local_delivery:
   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
index aa2e0d9ca4a5bd3717ea9bfda6c6c25f6ec3a96a..e01024b97db6500ccc10ff97ccfcb43e51ef88d9 100644 (file)
@@ -17,6 +17,7 @@ Message-Id: <E10HmaZ-0005vi-00@the.local.host.name>
 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
@@ -73,6 +74,7 @@ Message-Id: <E10HmbC-0005vi-00@the.local.host.name>
 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
index 29b1e9a9507a153ff1141ad1e756ada8f9615b06..870f580151c10508ffa19b9ce003a24e19c53cc1 100644 (file)
@@ -11,6 +11,7 @@ From: CALLER_NAME <CALLER@test.ex>
 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.
 
@@ -30,6 +31,7 @@ From: CALLER_NAME <CALLER@test.ex>
 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. 
 
@@ -46,6 +48,7 @@ From: CALLER_NAME <CALLER@test.ex>
 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.
 
@@ -65,6 +68,7 @@ From: CALLER_NAME <CALLER@test.ex>
 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. 
 
@@ -83,6 +87,7 @@ From: CALLER_NAME <CALLER@test.ex>
 Date: Tue, 2 Mar 1999 09:44:33 +0000
 X-local_part: userx
 X-local_part_prefix: b+
+X-local_part_prefix_v: 
 
 Text.
 .
@@ -100,6 +105,7 @@ From: CALLER_NAME <CALLER@test.ex>
 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>
@@ -116,5 +122,6 @@ From: CALLER_NAME <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
 
 .
index 8e33c3631b0d10193240245cf353c761a4132e68..5889f68ed44f99ec60231dd01b8c5a2008b4425b 100644 (file)
@@ -9,6 +9,9 @@ Received: from CALLER by the.local.host.name with local (Exim x.yz)
 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.
 
@@ -26,6 +29,9 @@ Auto-Submitted: auto-replied
 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. 
 
index d2b07d281f077342e6eee22999fc77da873b3d88..a3cf1168cae970dfc8ada9701272342e97c03734 100644 (file)
@@ -1,3 +1,4 @@
 # local part suffix
 exim -odi userx+page
 Some message text.
+****