Postfix3.3.1
maps.c
[詳解]
1 /*++
2 /* NAME
3 /* maps 3
4 /* SUMMARY
5 /* multi-dictionary search
6 /* SYNOPSIS
7 /* #include <maps.h>
8 /*
9 /* MAPS *maps_create(title, map_names, flags)
10 /* const char *title;
11 /* const char *map_names;
12 /* int flags;
13 /*
14 /* const char *maps_find(maps, key, flags)
15 /* MAPS *maps;
16 /* const char *key;
17 /* int flags;
18 /*
19 /* MAPS *maps_free(maps)
20 /* MAPS *maps;
21 /* DESCRIPTION
22 /* This module implements multi-dictionary searches. it goes
23 /* through the high-level dictionary interface and does file
24 /* locking. Dictionaries are opened read-only, and in-memory
25 /* dictionary instances are shared.
26 /*
27 /* maps_create() takes list of type:name pairs and opens the
28 /* named dictionaries.
29 /* The result is a handle that must be specified along with all
30 /* other maps_xxx() operations.
31 /* See dict_open(3) for a description of flags.
32 /* This includes the flags that specify preferences for search
33 /* string case folding.
34 /*
35 /* maps_find() searches the specified list of dictionaries
36 /* in the specified order for the named key. The result is in
37 /* memory that is overwritten upon each call.
38 /* The flags argument is either 0 or specifies a filter:
39 /* for example, DICT_FLAG_FIXED | DICT_FLAG_PATTERN selects
40 /* dictionaries that have fixed keys or pattern keys.
41 /*
42 /* maps_free() releases storage claimed by maps_create()
43 /* and conveniently returns a null pointer.
44 /*
45 /* Arguments:
46 /* .IP title
47 /* String used for diagnostics. Typically one specifies the
48 /* type of information stored in the lookup tables.
49 /* .IP map_names
50 /* Null-terminated string with type:name dictionary specifications,
51 /* separated by whitespace or commas.
52 /* .IP flags
53 /* With maps_create(), flags that are passed to dict_open().
54 /* With maps_find(), flags that control searching behavior
55 /* as documented above.
56 /* .IP maps
57 /* A result from maps_create().
58 /* .IP key
59 /* Null-terminated string with a lookup key. Table lookup is case
60 /* sensitive.
61 /* DIAGNOSTICS
62 /* Panic: inappropriate use; fatal errors: out of memory, unable
63 /* to open database. Warnings: null string lookup result.
64 /*
65 /* maps_find() returns a null pointer when the requested
66 /* information was not found, and logs a warning when the
67 /* lookup failed due to error. The maps->error value indicates
68 /* if the last lookup failed due to error.
69 /* BUGS
70 /* The dictionary name space is flat, so dictionary names allocated
71 /* by maps_create() may collide with dictionary names allocated by
72 /* other methods.
73 /*
74 /* This functionality could be implemented by allowing the user to
75 /* specify dictionary search paths to dict_lookup() or dict_eval().
76 /* However, that would either require that the dict(3) module adopts
77 /* someone else's list notation syntax, or that the dict(3) module
78 /* imposes syntax restrictions onto other software, neither of which
79 /* is desirable.
80 /* LICENSE
81 /* .ad
82 /* .fi
83 /* The Secure Mailer license must be distributed with this software.
84 /* AUTHOR(S)
85 /* Wietse Venema
86 /* IBM T.J. Watson Research
87 /* P.O. Box 704
88 /* Yorktown Heights, NY 10598, USA
89 /*--*/
90 
91 /* System library. */
92 
93 #include <sys_defs.h>
94 #include <string.h>
95 
96 /* Utility library. */
97 
98 #include <argv.h>
99 #include <mymalloc.h>
100 #include <msg.h>
101 #include <dict.h>
102 #include <stringops.h>
103 #include <split_at.h>
104 
105 /* Global library. */
106 
107 #include "mail_conf.h"
108 #include "maps.h"
109 
110 /* maps_create - initialize */
111 
112 MAPS *maps_create(const char *title, const char *map_names, int dict_flags)
113 {
114  const char *myname = "maps_create";
115  char *temp;
116  char *bufp;
117  static char sep[] = CHARS_COMMA_SP;
118  static char parens[] = CHARS_BRACE;
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  maps->error = 0;
131 
132  /*
133  * For each specified type:name pair, either register a new dictionary,
134  * or increment the reference count of an existing one.
135  */
136  if (*map_names) {
137  bufp = temp = mystrdup(map_names);
138  map_type_name_flags = vstring_alloc(10);
139 
140 #define OPEN_FLAGS O_RDONLY
141 
142  while ((map_type_name = mystrtokq(&bufp, sep, parens)) != 0) {
143  vstring_sprintf(map_type_name_flags, "%s(%o,%s)",
144  map_type_name, OPEN_FLAGS,
145  dict_flags_str(dict_flags));
146  if ((dict = dict_handle(vstring_str(map_type_name_flags))) == 0)
147  dict = dict_open(map_type_name, OPEN_FLAGS, dict_flags);
148  if ((dict->flags & dict_flags) != dict_flags)
149  msg_panic("%s: map %s has flags 0%o, want flags 0%o",
150  myname, map_type_name, dict->flags, dict_flags);
151  dict_register(vstring_str(map_type_name_flags), dict);
152  argv_add(maps->argv, vstring_str(map_type_name_flags), ARGV_END);
153  }
154  myfree(temp);
155  vstring_free(map_type_name_flags);
156  }
157  return (maps);
158 }
159 
160 /* maps_find - search a list of dictionaries */
161 
162 const char *maps_find(MAPS *maps, const char *name, int flags)
163 {
164  const char *myname = "maps_find";
165  char **map_name;
166  const char *expansion;
167  DICT *dict;
168 
169  /*
170  * In case of return without map lookup (empty name or no maps).
171  */
172  maps->error = 0;
173 
174  /*
175  * Temp. workaround, for buggy callers that pass zero-length keys when
176  * given partial addresses.
177  */
178  if (*name == 0)
179  return (0);
180 
181  for (map_name = maps->argv->argv; *map_name; map_name++) {
182  if ((dict = dict_handle(*map_name)) == 0)
183  msg_panic("%s: dictionary not found: %s", myname, *map_name);
184  if (flags != 0 && (dict->flags & flags) == 0)
185  continue;
186  if ((expansion = dict_get(dict, name)) != 0) {
187  if (*expansion == 0) {
188  msg_warn("%s lookup of %s returns an empty string result",
189  maps->title, name);
190  msg_warn("%s should return NO RESULT in case of NOT FOUND",
191  maps->title);
192  maps->error = DICT_ERR_RETRY;
193  return (0);
194  }
195  if (msg_verbose)
196  msg_info("%s: %s: %s: %s = %s", myname, maps->title,
197  *map_name, name, expansion);
198  return (expansion);
199  } else if ((maps->error = dict->error) != 0) {
200  msg_warn("%s:%s lookup error for \"%.100s\"",
201  dict->type, dict->name, name);
202  break;
203  }
204  }
205  if (msg_verbose)
206  msg_info("%s: %s: %s: %s", myname, maps->title, name, maps->error ?
207  "search aborted" : "not found");
208  return (0);
209 }
210 
211 /* maps_free - release storage */
212 
214 {
215  char **map_name;
216 
217  for (map_name = maps->argv->argv; *map_name; map_name++) {
218  if (msg_verbose)
219  msg_info("maps_free: %s", *map_name);
220  dict_unregister(*map_name);
221  }
222  myfree(maps->title);
223  argv_free(maps->argv);
224  myfree((void *) maps);
225  return (0);
226 }
227 
228 #ifdef TEST
229 
230 #include <vstring.h>
231 #include <vstream.h>
232 #include <vstring_vstream.h>
233 
234 int main(int argc, char **argv)
235 {
236  VSTRING *buf = vstring_alloc(100);
237  MAPS *maps;
238  const char *result;
239 
240  if (argc != 2)
241  msg_fatal("usage: %s maps", argv[0]);
242  msg_verbose = 2;
243  maps = maps_create("whatever", argv[1], DICT_FLAG_LOCK);
244 
245  while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
246  maps->error = 99;
247  vstream_printf("\"%s\": ", vstring_str(buf));
248  if ((result = maps_find(maps, vstring_str(buf), 0)) != 0) {
249  vstream_printf("%s\n", result);
250  } else if (maps->error != 0) {
251  vstream_printf("lookup error\n");
252  } else {
253  vstream_printf("not found\n");
254  }
256  }
257  maps_free(maps);
258  vstring_free(buf);
259  return (0);
260 }
261 
262 #endif
int msg_verbose
Definition: msg.c:177
#define vstring_fgets_nonl(s, p)
void myfree(void *ptr)
Definition: mymalloc.c:207
#define ARGV_END
Definition: argv.h:52
#define CHARS_BRACE
Definition: sys_defs.h:1763
char * mystrdup(const char *str)
Definition: mymalloc.c:225
void dict_register(const char *dict_name, DICT *dict_info)
Definition: dict.c:312
ARGV * argv_free(ARGV *argvp)
Definition: argv.c:136
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
#define VSTREAM_OUT
Definition: vstream.h:67
char * name
Definition: dict.h:80
int flags
Definition: dict.h:81
int main(int argc, char **argv)
Definition: anvil.c:1010
#define DICT_ERR_RETRY
Definition: dict.h:178
Definition: maps.h:22
char ** argv
Definition: argv.h:20
void argv_add(ARGV *argvp,...)
Definition: argv.c:197
char * mystrtokq(char **src, const char *sep, const char *parens)
Definition: mystrtok.c:80
DICT * dict_open(const char *, int, int)
Definition: dict_open.c:421
#define VSTREAM_IN
Definition: vstream.h:66
ARGV * argv_alloc(ssize_t len)
Definition: argv.c:149
void dict_unregister(const char *dict_name)
Definition: dict.c:354
#define OPEN_FLAGS
Definition: dict.h:78
char * type
Definition: dict.h:79
#define dict_get(dp, key)
Definition: dict.h:236
MAPS * maps_create(const char *title, const char *map_names, int dict_flags)
Definition: maps.c:112
char * title
Definition: maps.h:23
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
DICT * dict_handle(const char *dict_name)
Definition: dict.c:333
#define DICT_FLAG_LOCK
Definition: dict.h:116
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
struct ARGV * argv
Definition: maps.h:24
const char * dict_flags_str(int dict_flags)
Definition: dict.c:647
int error
Definition: dict.h:94
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
MAPS * maps_free(MAPS *maps)
Definition: maps.c:213
#define CHARS_COMMA_SP
Definition: sys_defs.h:1761
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
int error
Definition: maps.h:25
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
const char * maps_find(MAPS *maps, const char *name, int flags)
Definition: maps.c:162
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
void msg_info(const char *fmt,...)
Definition: msg.c:199