Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / maps.c
blob824a65137313025e912b4083681c31b8e87639bc
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* maps 3
6 /* SUMMARY
7 /* multi-dictionary search
8 /* SYNOPSIS
9 /* #include <maps.h>
11 /* MAPS *maps_create(title, map_names, flags)
12 /* const char *title;
13 /* const char *map_names;
14 /* int flags;
16 /* const char *maps_find(maps, key, flags)
17 /* MAPS *maps;
18 /* const char *key;
19 /* int flags;
21 /* MAPS *maps_free(maps)
22 /* MAPS *maps;
23 /* DESCRIPTION
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.
47 /* Arguments:
48 /* .IP title
49 /* String used for diagnostics. Typically one specifies the
50 /* type of information stored in the lookup tables.
51 /* .IP map_names
52 /* Null-terminated string with type:name dictionary specifications,
53 /* separated by whitespace or commas.
54 /* .IP flags
55 /* With maps_create(), flags that are passed to dict_open().
56 /* With maps_find(), flags that control searching behavior
57 /* as documented above.
58 /* .IP maps
59 /* A result from maps_create().
60 /* .IP key
61 /* Null-terminated string with a lookup key. Table lookup is case
62 /* sensitive.
63 /* DIAGNOSTICS
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.
70 /* BUGS
71 /* The dictionary name space is flat, so dictionary names allocated
72 /* by maps_create() may collide with dictionary names allocated by
73 /* other methods.
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
80 /* is desirable.
81 /* LICENSE
82 /* .ad
83 /* .fi
84 /* The Secure Mailer license must be distributed with this software.
85 /* AUTHOR(S)
86 /* Wietse Venema
87 /* IBM T.J. Watson Research
88 /* P.O. Box 704
89 /* Yorktown Heights, NY 10598, USA
90 /*--*/
92 /* System library. */
94 #include <sys_defs.h>
95 #include <string.h>
97 /* Utility library. */
99 #include <argv.h>
100 #include <mymalloc.h>
101 #include <msg.h>
102 #include <dict.h>
103 #include <stringops.h>
104 #include <split_at.h>
106 /* Global library. */
108 #include "mail_conf.h"
109 #include "maps.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";
116 char *temp;
117 char *bufp;
118 static char sep[] = " \t,\r\n";
119 MAPS *maps;
120 char *map_type_name;
121 VSTRING *map_type_name_flags;
122 DICT *dict;
125 * Initialize.
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.
135 if (*map_names) {
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);
153 myfree(temp);
154 vstring_free(map_type_name_flags);
156 return (maps);
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";
164 char **map_name;
165 const char *expansion;
166 DICT *dict;
169 * Temp. workaround, for buggy callers that pass zero-length keys when
170 * given partial addresses.
172 if (*name == 0)
173 return (0);
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)
179 continue;
180 if ((expansion = dict_get(dict, name)) != 0) {
181 if (*expansion == 0) {
182 msg_warn("%s lookup of %s returns an empty string result",
183 maps->title, name);
184 msg_warn("%s should return NO RESULT in case of NOT FOUND",
185 maps->title);
186 dict_errno = DICT_ERR_RETRY;
187 return (0);
189 if (msg_verbose)
190 msg_info("%s: %s: %s: %s = %s", myname, maps->title,
191 *map_name, name, expansion);
192 return (expansion);
193 } else if (dict_errno != 0) {
194 break;
197 if (msg_verbose)
198 msg_info("%s: %s: %s: %s", myname, maps->title, name, dict_errno ?
199 "search aborted" : "not found");
200 return (0);
203 /* maps_free - release storage */
205 MAPS *maps_free(MAPS *maps)
207 char **map_name;
209 for (map_name = maps->argv->argv; *map_name; map_name++) {
210 if (msg_verbose)
211 msg_info("maps_free: %s", *map_name);
212 dict_unregister(*map_name);
214 myfree(maps->title);
215 argv_free(maps->argv);
216 myfree((char *) maps);
217 return (0);
220 #ifdef TEST
222 #include <vstring.h>
223 #include <vstream.h>
224 #include <vstring_vstream.h>
226 int main(int argc, char **argv)
228 VSTRING *buf = vstring_alloc(100);
229 MAPS *maps;
230 const char *result;
232 if (argc != 2)
233 msg_fatal("usage: %s maps", argv[0]);
234 msg_verbose = 2;
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");
242 } else {
243 vstream_printf("not found\n");
245 vstream_fflush(VSTREAM_OUT);
247 maps_free(maps);
248 vstring_free(buf);
249 return (0);
252 #endif