7 /* multi-dictionary search
11 /* MAPS *maps_create(title, map_names, flags)
13 /* const char *map_names;
16 /* const char *maps_find(maps, key, flags)
21 /* MAPS *maps_free(maps)
24 /* This module implements multi-dictionary searches. it goes
25 /* through the high-level dictionary interface and does file
26 /* locking. Dictionaries are opened read-only, and in-memory
27 /* dictionary instances are shared.
29 /* maps_create() takes list of type:name pairs and opens the
30 /* named dictionaries.
31 /* The result is a handle that must be specified along with all
32 /* other maps_xxx() operations.
33 /* See dict_open(3) for a description of flags.
34 /* This includes the flags that specify preferences for search
35 /* string case folding.
37 /* maps_find() searches the specified list of dictionaries
38 /* in the specified order for the named key. The result is in
39 /* memory that is overwritten upon each call.
40 /* The flags argument is either 0 or specifies a filter:
41 /* for example, DICT_FLAG_FIXED | DICT_FLAG_PATTERN selects
42 /* dictionaries that have fixed keys or pattern keys.
44 /* maps_free() releases storage claimed by maps_create()
45 /* and conveniently returns a null pointer.
49 /* String used for diagnostics. Typically one specifies the
50 /* type of information stored in the lookup tables.
52 /* Null-terminated string with type:name dictionary specifications,
53 /* separated by whitespace or commas.
55 /* With maps_create(), flags that are passed to dict_open().
56 /* With maps_find(), flags that control searching behavior
57 /* as documented above.
59 /* A result from maps_create().
61 /* Null-terminated string with a lookup key. Table lookup is case
64 /* Panic: inappropriate use; fatal errors: out of memory, unable
65 /* to open database. Warnings: null string lookup result.
67 /* maps_find() returns a null pointer when the requested
68 /* information was not found. The global \fIdict_errno\fR
69 /* variable indicates if the last lookup failed due to a problem.
71 /* The dictionary name space is flat, so dictionary names allocated
72 /* by maps_create() may collide with dictionary names allocated by
75 /* This functionality could be implemented by allowing the user to
76 /* specify dictionary search paths to dict_lookup() or dict_eval().
77 /* However, that would either require that the dict(3) module adopts
78 /* someone else's list notation syntax, or that the dict(3) module
79 /* imposes syntax restrictions onto other software, neither of which
84 /* The Secure Mailer license must be distributed with this software.
87 /* IBM T.J. Watson Research
89 /* Yorktown Heights, NY 10598, USA
97 /* Utility library. */
100 #include <mymalloc.h>
103 #include <stringops.h>
104 #include <split_at.h>
106 /* Global library. */
108 #include "mail_conf.h"
111 /* maps_create - initialize */
113 MAPS
*maps_create(const char *title
, const char *map_names
, int dict_flags
)
115 const char *myname
= "maps_create";
118 static char sep
[] = " \t,\r\n";
121 VSTRING
*map_type_name_flags
;
127 maps
= (MAPS
*) mymalloc(sizeof(*maps
));
128 maps
->title
= mystrdup(title
);
129 maps
->argv
= argv_alloc(2);
132 * For each specified type:name pair, either register a new dictionary,
133 * or increment the reference count of an existing one.
136 bufp
= temp
= mystrdup(map_names
);
137 map_type_name_flags
= vstring_alloc(10);
139 #define OPEN_FLAGS O_RDONLY
141 while ((map_type_name
= mystrtok(&bufp
, sep
)) != 0) {
142 vstring_sprintf(map_type_name_flags
, "%s(%o,%s)",
143 map_type_name
, OPEN_FLAGS
,
144 dict_flags_str(dict_flags
));
145 if ((dict
= dict_handle(vstring_str(map_type_name_flags
))) == 0)
146 dict
= dict_open(map_type_name
, OPEN_FLAGS
, dict_flags
);
147 if ((dict
->flags
& dict_flags
) != dict_flags
)
148 msg_panic("%s: map %s has flags 0%o, want flags 0%o",
149 myname
, map_type_name
, dict
->flags
, dict_flags
);
150 dict_register(vstring_str(map_type_name_flags
), dict
);
151 argv_add(maps
->argv
, vstring_str(map_type_name_flags
), ARGV_END
);
154 vstring_free(map_type_name_flags
);
159 /* maps_find - search a list of dictionaries */
161 const char *maps_find(MAPS
*maps
, const char *name
, int flags
)
163 const char *myname
= "maps_find";
165 const char *expansion
;
169 * Temp. workaround, for buggy callers that pass zero-length keys when
170 * given partial addresses.
175 for (map_name
= maps
->argv
->argv
; *map_name
; map_name
++) {
176 if ((dict
= dict_handle(*map_name
)) == 0)
177 msg_panic("%s: dictionary not found: %s", myname
, *map_name
);
178 if (flags
!= 0 && (dict
->flags
& flags
) == 0)
180 if ((expansion
= dict_get(dict
, name
)) != 0) {
181 if (*expansion
== 0) {
182 msg_warn("%s lookup of %s returns an empty string result",
184 msg_warn("%s should return NO RESULT in case of NOT FOUND",
186 dict_errno
= DICT_ERR_RETRY
;
190 msg_info("%s: %s: %s: %s = %s", myname
, maps
->title
,
191 *map_name
, name
, expansion
);
193 } else if (dict_errno
!= 0) {
198 msg_info("%s: %s: %s: %s", myname
, maps
->title
, name
, dict_errno
?
199 "search aborted" : "not found");
203 /* maps_free - release storage */
205 MAPS
*maps_free(MAPS
*maps
)
209 for (map_name
= maps
->argv
->argv
; *map_name
; map_name
++) {
211 msg_info("maps_free: %s", *map_name
);
212 dict_unregister(*map_name
);
215 argv_free(maps
->argv
);
216 myfree((char *) maps
);
224 #include <vstring_vstream.h>
226 int main(int argc
, char **argv
)
228 VSTRING
*buf
= vstring_alloc(100);
233 msg_fatal("usage: %s maps", argv
[0]);
235 maps
= maps_create("whatever", argv
[1], DICT_FLAG_LOCK
);
237 while (vstring_fgets_nonl(buf
, VSTREAM_IN
)) {
238 if ((result
= maps_find(maps
, vstring_str(buf
), 0)) != 0) {
239 vstream_printf("%s\n", result
);
240 } else if (dict_errno
!= 0) {
241 msg_fatal("lookup error: %m");
243 vstream_printf("not found\n");
245 vstream_fflush(VSTREAM_OUT
);