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