X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/54a2a2a9983913a91ccef3aac107a159434a4714..b50e778f1011c618e6f7fd73ac544a5903a29e1a:/src/src/search.c?ds=sidebyside diff --git a/src/src/search.c b/src/src/search.c index dc90f53d5..d929322ba 100644 --- a/src/src/search.c +++ b/src/src/search.c @@ -115,6 +115,7 @@ Arguments: otherwise it's a literal string afflen the length of the affix starflags where to put the SEARCH_STAR and SEARCH_STARAT flags + opts where to put the options Returns: +ve => valid lookup name; value is offset in lookup_list -ve => invalid name; message in search_error_message. @@ -122,11 +123,12 @@ Returns: +ve => valid lookup name; value is offset in lookup_list int search_findtype_partial(const uschar *name, int *ptypeptr, const uschar **ptypeaff, - int *afflen, int *starflags) + int *afflen, int *starflags, const uschar ** opts) { int len, stype; int pv = -1; const uschar *ss = name; +const uschar * t; *starflags = 0; *ptypeaff = NULL; @@ -167,19 +169,26 @@ if (Ustrncmp(name, "partial", 7) == 0) } } -/* Now we are left with a lookup name, possibly followed by * or *@. */ +/* Now we are left with a lookup name, possibly followed by * or *@, +and then by options starting with a "," */ len = Ustrlen(ss); -if (len >= 2 && Ustrncmp(ss + len - 2, "*@", 2) == 0) +if ((t = Ustrchr(ss, '*'))) { - *starflags |= SEARCH_STARAT; - len -= 2; + len = t - ss; + *starflags |= (t[1] == '@' ? SEARCH_STARAT : SEARCH_STAR); } -else if (len >= 1 && ss[len-1] == '*') +else + t = ss; + +if ((t = Ustrchr(t, ','))) { - *starflags |= SEARCH_STAR; - len--; + int l = t - ss; + if (l < len) len = l; + *opts = string_copy(t+1); } +else + * opts = NULL; /* Check for the individual search type. Only those that are actually in the binary are valid. For query-style types, "partial" and default types are @@ -325,8 +334,8 @@ Returns: an identifying handle for the open database; */ void * -search_open(uschar *filename, int search_type, int modemask, uid_t *owners, - gid_t *owngroups) +search_open(const uschar * filename, int search_type, int modemask, + uid_t * owners, gid_t * owngroups) { void *handle; tree_node *t; @@ -454,6 +463,7 @@ Arguments: NULL for query-style searches keystring the keystring for single-key+file lookups, or the querystring for query-style lookups + opts type-specific options Returns: a pointer to a dynamic string containing the answer, or NULL if the query failed or was deferred; in the @@ -462,7 +472,8 @@ Returns: a pointer to a dynamic string containing the answer, */ static uschar * -internal_search_find(void *handle, uschar *filename, uschar *keystring) +internal_search_find(void * handle, const uschar * filename, uschar * keystring, + const uschar * opts) { tree_node * t = (tree_node *)handle; search_cache * c = (search_cache *)(t->data.ptr); @@ -478,8 +489,9 @@ search_error_message = US""; f.search_find_defer = FALSE; DEBUG(D_lookup) debug_printf_indent("internal_search_find: file=\"%s\"\n " - "type=%s key=\"%s\"\n", filename, - lookup_list[search_type]->name, keystring); + "type=%s key=\"%s\" opts=%s%s%s\n", filename, + lookup_list[search_type]->name, keystring, + opts ? "\"" : "", opts, opts ? "\"" : ""); /* Insurance. If the keystring is empty, just fail. */ @@ -494,6 +506,7 @@ file. No need to check c->item_cache for NULL, tree_search will do so. */ if ( (t = tree_search(c->item_cache, keystring)) && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL)) + && (!opts && !e->opts || opts && e->opts && Ustrcmp(opts, e->opts) == 0) ) { /* Data was in the cache already; set the pointer from the tree node */ data = e->data.ptr; @@ -508,7 +521,8 @@ else DEBUG(D_lookup) { - if (t) debug_printf_indent("cached data found but past valid time; "); + if (t) + debug_printf_indent("cached data found but either wrong opts or dated; "); debug_printf_indent("%s lookup required for %s%s%s\n", filename ? US"file" : US"database", keystring, @@ -520,7 +534,7 @@ else distinguish if necessary. */ if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength, - &data, &search_error_message, &do_cache) == DEFER) + &data, &search_error_message, &do_cache, opts) == DEFER) f.search_find_defer = TRUE; /* A record that has been found is now in data, which is either NULL @@ -531,23 +545,23 @@ else else if (do_cache) { - int len = keylength + 1; - - if (t) /* Previous, out-of-date cache entry. Update with the */ - { /* new result and forget the old one */ - e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache; - e->data.ptr = data; - } - else + if (!t) /* No existing entry. Create new one. */ { + int len = keylength + 1; e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len, is_tainted(keystring)); e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache; + e->opts = opts; e->data.ptr = data; t = (tree_node *)(e+1); memcpy(t->name, keystring, len); t->data.ptr = e; tree_insertnode(&c->item_cache, t); } + /* Else previous, out-of-date cache entry. Update with the */ + /* new result and forget the old one */ + e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache; + e->opts = opts; + e->data.ptr = data; } /* If caching was disabled, empty the cache tree. We just set the cache @@ -598,6 +612,7 @@ Arguments: starflags SEARCH_STAR and SEARCH_STARAT flags expand_setup pointer to offset for setting up expansion strings; don't do any if < 0 + opts type-specific options Returns: a pointer to a dynamic string containing the answer, or NULL if the query failed or was deferred; in the @@ -605,8 +620,9 @@ Returns: a pointer to a dynamic string containing the answer, */ uschar * -search_find(void *handle, uschar *filename, uschar *keystring, int partial, - const uschar *affix, int affixlen, int starflags, int *expand_setup) +search_find(void * handle, const uschar * filename, uschar * keystring, + int partial, const uschar * affix, int affixlen, int starflags, + int * expand_setup, const uschar * opts) { tree_node *t = (tree_node *)handle; BOOL set_null_wild = FALSE; @@ -616,9 +632,11 @@ DEBUG(D_lookup) { if (partial < 0) affixlen = 99; /* So that "NULL" prints */ debug_printf_indent("search_find: file=\"%s\"\n key=\"%s\" " - "partial=%d affix=%.*s starflags=%x\n", - (filename == NULL)? US"NULL" : filename, - keystring, partial, affixlen, affix, starflags); + "partial=%d affix=%.*s starflags=%x opts=%s%s%s\n", + filename ? filename : US"NULL", + keystring, partial, affixlen, affix, starflags, + opts ? "\"" : "", opts, opts ? "\"" : ""); + } /* Arrange to put this database at the top of the LRU chain if it is a type @@ -668,7 +686,7 @@ DEBUG(D_lookup) /* First of all, try to match the key string verbatim. If matched a complete entry but could have been partial, flag to set up variables. */ -yield = internal_search_find(handle, filename, keystring); +yield = internal_search_find(handle, filename, keystring, opts); if (f.search_find_defer) return NULL; if (yield) { if (partial >= 0) set_null_wild = TRUE; } @@ -693,7 +711,7 @@ else if (partial >= 0) Ustrncpy(keystring2, affix, affixlen); Ustrcpy(keystring2 + affixlen, keystring); DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring2); - yield = internal_search_find(handle, filename, keystring2); + yield = internal_search_find(handle, filename, keystring2, opts); if (f.search_find_defer) return NULL; } @@ -731,7 +749,7 @@ else if (partial >= 0) } DEBUG(D_lookup) debug_printf_indent("trying partial match %s\n", keystring3); - yield = internal_search_find(handle, filename, keystring3); + yield = internal_search_find(handle, filename, keystring3, opts); if (f.search_find_defer) return NULL; if (yield) { @@ -772,7 +790,7 @@ if (!yield && starflags & SEARCH_STARAT) *atat = '*'; DEBUG(D_lookup) debug_printf_indent("trying default match %s\n", atat); - yield = internal_search_find(handle, filename, atat); + yield = internal_search_find(handle, filename, atat, opts); *atat = savechar; if (f.search_find_defer) return NULL; @@ -795,7 +813,7 @@ and the second is empty. */ if (!yield && starflags & (SEARCH_STAR|SEARCH_STARAT)) { DEBUG(D_lookup) debug_printf_indent("trying to match *\n"); - yield = internal_search_find(handle, filename, US"*"); + yield = internal_search_find(handle, filename, US"*", opts); if (yield && expand_setup && *expand_setup >= 0) { *expand_setup += 1;