xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/maps.c (revision bbde328be4e75ea9ad02e9715ea13ca54b797ada)
1 /*	$NetBSD: maps.c,v 1.1.1.1 2009/06/23 10:08:47 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	maps 3
6 /* SUMMARY
7 /*	multi-dictionary search
8 /* SYNOPSIS
9 /*	#include <maps.h>
10 /*
11 /*	MAPS	*maps_create(title, map_names, flags)
12 /*	const char *title;
13 /*	const char *map_names;
14 /*	int	flags;
15 /*
16 /*	const char *maps_find(maps, key, flags)
17 /*	MAPS	*maps;
18 /*	const char *key;
19 /*	int	flags;
20 /*
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.
28 /*
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.
36 /*
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.
43 /*
44 /*	maps_free() releases storage claimed by maps_create()
45 /*	and conveniently returns a null pointer.
46 /*
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.
66 /*
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.
74 /*
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 /*--*/
91 
92 /* System library. */
93 
94 #include <sys_defs.h>
95 #include <string.h>
96 
97 /* Utility library. */
98 
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>
105 
106 /* Global library. */
107 
108 #include "mail_conf.h"
109 #include "maps.h"
110 
111 /* maps_create - initialize */
112 
113 MAPS   *maps_create(const char *title, const char *map_names, int dict_flags)
114 {
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;
123 
124     /*
125      * Initialize.
126      */
127     maps = (MAPS *) mymalloc(sizeof(*maps));
128     maps->title = mystrdup(title);
129     maps->argv = argv_alloc(2);
130 
131     /*
132      * For each specified type:name pair, either register a new dictionary,
133      * or increment the reference count of an existing one.
134      */
135     if (*map_names) {
136 	bufp = temp = mystrdup(map_names);
137 	map_type_name_flags = vstring_alloc(10);
138 
139 #define OPEN_FLAGS	O_RDONLY
140 
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);
152 	}
153 	myfree(temp);
154 	vstring_free(map_type_name_flags);
155     }
156     return (maps);
157 }
158 
159 /* maps_find - search a list of dictionaries */
160 
161 const char *maps_find(MAPS *maps, const char *name, int flags)
162 {
163     const char *myname = "maps_find";
164     char  **map_name;
165     const char *expansion;
166     DICT   *dict;
167 
168     /*
169      * Temp. workaround, for buggy callers that pass zero-length keys when
170      * given partial addresses.
171      */
172     if (*name == 0)
173 	return (0);
174 
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);
188 	    }
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;
195 	}
196     }
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);
201 }
202 
203 /* maps_free - release storage */
204 
205 MAPS   *maps_free(MAPS *maps)
206 {
207     char  **map_name;
208 
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);
213     }
214     myfree(maps->title);
215     argv_free(maps->argv);
216     myfree((char *) maps);
217     return (0);
218 }
219 
220 #ifdef TEST
221 
222 #include <vstring.h>
223 #include <vstream.h>
224 #include <vstring_vstream.h>
225 
226 int     main(int argc, char **argv)
227 {
228     VSTRING *buf = vstring_alloc(100);
229     MAPS   *maps;
230     const char *result;
231 
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);
236 
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");
244 	}
245 	vstream_fflush(VSTREAM_OUT);
246     }
247     maps_free(maps);
248     vstring_free(buf);
249     return (0);
250 }
251 
252 #endif
253