*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for matching strings */
const check_string_block *cb = arg;
int search_type, partial, affixlen, starflags;
int expand_setup = cb->expand_setup;
-const uschar *affix;
+const uschar * affix, * opts;
uschar *s;
uschar *filename = NULL;
uschar *keyquery, *result, *semicolon;
void *handle;
-error = error; /* Keep clever compilers from complaining */
-
-if (valueptr != NULL) *valueptr = NULL; /* For non-lookup matches */
+if (valueptr) *valueptr = NULL;
/* For regular expressions, use cb->origsubject rather than cb->subject so that
it works if the pattern uses (?-i) to turn off case-independence, overriding
expand_nmax = -1;
if (expand_setup == 0)
{
- expand_nstring[0] = s;
+ expand_nstring[0] = s; /* $0 (might be) the matched subject in full */
expand_nlength[0] = Ustrlen(s);
}
else if (expand_setup > 0) expand_setup--;
if (pattern[0] == '^')
{
- const pcre *re = regex_must_compile(pattern, cb->caseless, FALSE);
- return ((expand_setup < 0)?
- pcre_exec(re, NULL, CCS s, Ustrlen(s), 0, PCRE_EOPT, NULL, 0) >= 0
- :
- regex_match_and_setup(re, s, 0, expand_setup)
- )?
- OK : FAIL;
+ const pcre * re = regex_must_compile(pattern, cb->caseless, FALSE);
+ if (expand_setup < 0
+ ? pcre_exec(re, NULL, CCS s, Ustrlen(s), 0, PCRE_EOPT, NULL, 0) < 0
+ : !regex_match_and_setup(re, s, 0, expand_setup)
+ )
+ return FAIL;
+ if (valueptr) *valueptr = pattern; /* "value" gets the RE */
+ return OK;
}
/* Tail match */
if (pattern[0] == '*')
{
- BOOL yield;
int slen = Ustrlen(s);
int patlen; /* Sun compiler doesn't like non-constant initializer */
patlen = Ustrlen(++pattern);
if (patlen > slen) return FAIL;
- yield = cb->caseless?
- (strncmpic(s + slen - patlen, pattern, patlen) == 0) :
- (Ustrncmp(s + slen - patlen, pattern, patlen) == 0);
- if (yield && expand_setup >= 0)
+ if (cb->caseless
+ ? strncmpic(s + slen - patlen, pattern, patlen) != 0
+ : Ustrncmp(s + slen - patlen, pattern, patlen) != 0)
+ return FAIL;
+ if (expand_setup >= 0)
{
- expand_nstring[++expand_setup] = s;
+ expand_nstring[++expand_setup] = s; /* write a $n, the matched subject variable-part */
expand_nlength[expand_setup] = slen - patlen;
- expand_nmax = expand_setup;
+ expand_nmax = expand_setup; /* commit also $0, the matched subject */
}
- return yield? OK : FAIL;
+ if (valueptr) *valueptr = pattern - 1; /* "value" gets the (original) pattern */
+ return OK;
}
/* Match a special item starting with @ if so enabled. On its own, "@" matches
if (Ustrcmp(pattern, "@[]") == 0)
{
int slen = Ustrlen(s);
- if (s[0] != '[' && s[slen-1] != ']') return FAIL;
+ if (s[0] != '[' && s[slen-1] != ']') return FAIL; /*XXX should this be || ? */
for (ip_address_item * ip = host_find_interfaces(); ip; ip = ip->next)
if (Ustrncmp(ip->address, s+1, slen - 2) == 0
&& ip->address[slen - 2] == 0)
+ {
+ if (expand_setup >= 0) expand_nmax = expand_setup; /* commit $0, the IP addr */
+ if (valueptr) *valueptr = pattern; /* "value" gets the pattern */
return OK;
+ }
return FAIL;
}
else goto NOT_AT_SPECIAL;
if (strncmpic(ss, US"/ignore=", 8) == 0) ignore_target_hosts = ss + 8;
- else if (*ss != 0) goto NOT_AT_SPECIAL;
+ else if (*ss) goto NOT_AT_SPECIAL;
h.next = NULL;
h.name = s;
return DEFER;
}
- if (rc == HOST_FOUND_LOCAL && !secy) return OK;
- if (prim) return FAIL;
- return removed? OK : FAIL;
+ if ((rc != HOST_FOUND_LOCAL || secy) && (prim || !removed))
+ return FAIL;
+
+ if (expand_setup >= 0) expand_nmax = expand_setup; /* commit $0, the matched subject */
+ if (valueptr) *valueptr = pattern; /* "value" gets the patterm */
+ return OK;
/*** The above line used to be the following line, but this is incorrect,
because host_find_bydns() may return HOST_NOT_FOUND if it removed some MX
if ((semicolon = Ustrchr(pattern, ';')) == NULL)
{
- BOOL yield = cb->caseless?
- (strcmpic(s, pattern) == 0) : (Ustrcmp(s, pattern) == 0);
- if (yield && expand_setup >= 0) expand_nmax = expand_setup;
- return yield? OK : FAIL;
+ if (cb->caseless ? strcmpic(s, pattern) != 0 : Ustrcmp(s, pattern) != 0)
+ return FAIL;
+ if (expand_setup >= 0) expand_nmax = expand_setup; /* Original code! $0 gets the matched subject */
+ if (valueptr) *valueptr = pattern; /* "value" gets the pattern */
+ return OK;
}
/* Otherwise we have a lookup item. The lookup type, including partial, etc. is
*semicolon = 0;
search_type = search_findtype_partial(pattern, &partial, &affix, &affixlen,
- &starflags);
+ &starflags, &opts);
*semicolon = ';';
if (search_type < 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
search_error_message);
/* Set the parameters for the three different kinds of lookup. */
-keyquery = semicolon + 1;
-while (isspace(*keyquery)) keyquery++;
-
-if (mac_islookup(search_type, lookup_absfilequery))
- {
- filename = keyquery;
- while (*keyquery != 0 && !isspace(*keyquery)) keyquery++;
- filename = string_copyn(filename, keyquery - filename);
- while (isspace(*keyquery)) keyquery++;
- }
-
-else if (!mac_islookup(search_type, lookup_querystyle))
- {
- filename = keyquery;
- keyquery = s;
- }
+keyquery = search_args(search_type, s, semicolon+1, &filename, opts);
/* Now do the actual lookup; throw away the data returned unless it was asked
for; partial matching is all handled inside search_find(). Note that there is
if (!(handle = search_open(filename, search_type, 0, NULL, NULL)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s", search_error_message);
result = search_find(handle, filename, keyquery, partial, affix, affixlen,
- starflags, &expand_setup);
+ starflags, &expand_setup, opts);
-if (!result) return f.search_find_defer? DEFER : FAIL;
+if (!result) return f.search_find_defer ? DEFER : FAIL;
if (valueptr) *valueptr = result;
expand_nmax = expand_setup;
{
check_string_block cb;
cb.origsubject = s;
-cb.subject = caseless? string_copylc(s) : string_copy(s);
+cb.subject = caseless ? string_copylc(s) : string_copy(s);
cb.expand_setup = expand_setup;
cb.use_partial = use_partial;
cb.caseless = caseless;
case MCL_STRING:
case MCL_DOMAIN:
case MCL_LOCALPART:
- return ((check_string_block *)arg)->subject;
+ return ((check_string_block *)arg)->subject;
case MCL_HOST:
- return ((check_host_block *)arg)->host_address;
+ return ((check_host_block *)arg)->host_address;
case MCL_ADDRESS:
- return ((check_address_block *)arg)->address;
+ return ((check_address_block *)arg)->address;
}
return US""; /* In practice, should never happen */
}
const uschar *list;
uschar *sss;
uschar *ot = NULL;
-uschar buffer[1024];
/* Save time by not scanning for the option name when we don't need it. */
/* For an unnamed list, use the expanded version in comments */
-HDEBUG(D_any) if (ot == NULL) ot = string_sprintf("%s in \"%s\"?", name, list);
+HDEBUG(D_any) if (!ot) ot = string_sprintf("%s in \"%s\"?", name, list);
/* Now scan the list and process each item in turn, until one of them matches,
or we hit an error. */
-while ((sss = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
+while ((sss = string_nextinlist(&list, &sep, NULL, 0)))
{
uschar * ss = sss;
nb->cache_data = p;
if (*valueptr)
DEBUG(D_lists) debug_printf("data from lookup saved for "
- "cache for %s: %s\n", ss, *valueptr);
+ "cache for %s: key '%s' value '%s'\n", ss, p->key, *valueptr);
}
}
}
else
{
DEBUG(D_lists) debug_printf("cached %s match for %s\n",
- ((bits & (-bits)) == bits)? "yes" : "no", ss);
+ (bits & (-bits)) == bits ? "yes" : "no", ss);
cached = US" - cached";
if (valueptr)
if (listname[0] == 0)
listname = string_sprintf("\"%s\"", *listptr);
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
- string_open_failed(errno, "%s when checking %s", sss, listname));
+ string_open_failed("%s when checking %s", sss, listname));
}
/* Trailing comments are introduced by #, but in an address list or local
unsigned int *local_cache_bits = cache_bits;
check_string_block cb;
cb.origsubject = s;
-cb.subject = caseless? string_copylc(s) : string_copy(s);
-cb.expand_setup = (sep > UCHAR_MAX)? 0 : -1;
+cb.subject = caseless ? string_copylc(s) : string_copy(s);
+cb.at_is_special = FALSE;
+switch (type & ~MCL_NOEXPAND)
+ {
+ case MCL_DOMAIN: cb.at_is_special = TRUE; /*FALLTHROUGH*/
+ case MCL_LOCALPART: cb.expand_setup = 0; break;
+ default: cb.expand_setup = sep > UCHAR_MAX ? 0 : -1; break;
+ }
cb.use_partial = TRUE;
cb.caseless = caseless;
-cb.at_is_special = (type == MCL_DOMAIN || type == MCL_DOMAIN + MCL_NOEXPAND);
-if (valueptr != NULL) *valueptr = NULL;
+if (valueptr) *valueptr = NULL;
return match_check_list(listptr, sep, anchorptr, &local_cache_bits,
check_string, &cb, type, s, valueptr);
}
const uschar *s;
uschar *pdomain, *sdomain;
-error = error; /* Keep clever compilers from complaining */
-
DEBUG(D_lists) debug_printf("address match test: subject=%s pattern=%s\n",
subject, pattern);
{
int cllen = pllen - 1;
if (sllen < cllen) return FAIL;
- if (cb->caseless)
- {
- if (strncmpic(subject+sllen-cllen, pattern + 1, cllen) != 0)
- return FAIL;
- }
- else
- {
- if (Ustrncmp(subject+sllen-cllen, pattern + 1, cllen) != 0)
+ if (cb->caseless
+ ? strncmpic(subject+sllen-cllen, pattern + 1, cllen) != 0
+ : Ustrncmp(subject+sllen-cllen, pattern + 1, cllen) != 0)
return FAIL;
- }
if (cb->expand_setup > 0)
{
expand_nstring[cb->expand_setup] = subject;
else
{
if (sllen != pllen) return FAIL;
- if (cb->caseless)
- {
- if (strncmpic(subject, pattern, sllen) != 0) return FAIL;
- }
- else
- {
- if (Ustrncmp(subject, pattern, sllen) != 0) return FAIL;
- }
+ if (cb->caseless
+ ? strncmpic(subject, pattern, sllen) != 0
+ : Ustrncmp(subject, pattern, sllen) != 0) return FAIL;
}
}
original code read as follows:
return match_check_string(sdomain + 1,
- (pdomain == NULL)? pattern : pdomain + 1,
+ pdomain ? pdomain + 1 : pattern,
cb->expand_setup + expand_inc, TRUE, cb->caseless, TRUE, NULL);
This supported only literal domains and *.x.y patterns. In order to allow for
was changed to use the list scanning function. */
csb.origsubject = sdomain + 1;
-csb.subject = (cb->caseless)? string_copylc(sdomain+1) : string_copy(sdomain+1);
+csb.subject = cb->caseless ? string_copylc(sdomain+1) : string_copy(sdomain+1);
csb.expand_setup = cb->expand_setup + expand_inc;
csb.use_partial = TRUE;
csb.caseless = cb->caseless;
csb.at_is_special = TRUE;
-listptr = (pdomain == NULL)? pattern : pdomain + 1;
-if (valueptr != NULL) *valueptr = NULL;
+listptr = pdomain ? pdomain + 1 : pattern;
+if (valueptr) *valueptr = NULL;
return match_check_list(
&listptr, /* list of one item */