1 /* 2 * Copyright (c) 1992 Eric P. Allman. 3 * Copyright (c) 1992 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)map.c 5.5 (Berkeley) 12/09/92"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 #include <sys/file.h> 15 16 #ifdef DBM_MAP 17 #include <ndbm.h> 18 #endif 19 #if defined(HASH_MAP) || defined(BTREE_MAP) 20 #include <db.h> 21 #endif 22 23 24 #ifdef DBM_MAP 25 26 /* 27 ** DBM_MAP_INIT -- DBM-style map initialization 28 ** 29 ** Parameters: 30 ** map -- the pointer to the actual map 31 ** mapname -- the name of the map (for error messages) 32 ** args -- a pointer to the config file line arguments 33 ** 34 ** Returns: 35 ** TRUE -- if it could successfully open the map. 36 ** FALSE -- otherwise. 37 ** 38 ** Side Effects: 39 ** Gives an error if it can't open the map. 40 */ 41 42 bool 43 dbm_map_init(map, mapname, args) 44 MAP *map; 45 char *mapname; 46 char *args; 47 { 48 DBM *dbm; 49 50 map_parseargs(map, &args, mapname); 51 if (map->map_file == NULL) 52 return FALSE; 53 dbm = dbm_open(map->map_file, O_RDONLY, 0644); 54 if (dbm == NULL) 55 { 56 if (!bitset(MF_OPTIONAL, map->map_flags)) 57 syserr("Cannot open DBM database %s", map->map_file); 58 return FALSE; 59 } 60 map->map_db = (void *) dbm; 61 return TRUE; 62 } 63 /* 64 ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 65 ** 66 ** Parameters: 67 ** map -- the map to look up in. 68 ** buf -- a pointer to to the buffer containing the key. 69 ** This is a null terminated string. 70 ** bufsiz -- the size of buf -- note that this is in general 71 ** larger that strlen(buf), and buf can be changed 72 ** in place if desired. 73 ** av -- arguments from the config file (can be interpolated 74 ** into the final result). 75 ** 76 ** Returns: 77 ** A pointer to the rewritten result. 78 ** NULL if not found in the map. 79 */ 80 81 char * 82 dbm_map_lookup(map, buf, bufsiz, av) 83 MAP *map; 84 char buf[]; 85 int bufsiz; 86 char **av; 87 { 88 datum key, val; 89 90 key.dptr = buf; 91 key.dsize = strlen(buf); 92 if (!bitset(MF_NOFOLDCASE, map->map_flags)) 93 { 94 register char *p; 95 96 for (p = buf; *p != '\0'; p++) 97 if (isupper(*p)) 98 *p = tolower(*p); 99 } 100 if (bitset(MF_INCLNULL, map->map_flags)) 101 key.dsize++; 102 val = dbm_fetch(map->map_db, key); 103 if (val.dptr == NULL) 104 return NULL; 105 map_rewrite(val.dptr, val.dsize, buf, bufsiz, av); 106 return buf; 107 } 108 109 #endif /* DBM_MAP */ 110 111 #ifdef BTREE_MAP 112 113 /* 114 ** BTREE_MAP_INIT -- BTREE-style map initialization 115 ** 116 ** Parameters: 117 ** map -- the pointer to the actual map 118 ** mapname -- the name of the map (for error messages) 119 ** args -- a pointer to the config file line arguments 120 ** 121 ** Returns: 122 ** TRUE -- if it could successfully open the map. 123 ** FALSE -- otherwise. 124 ** 125 ** Side Effects: 126 ** Gives an error if it can't open the map. 127 */ 128 129 bool 130 bt_map_init(map, mapname, args) 131 MAP *map; 132 char *mapname; 133 char *args; 134 { 135 DB *db; 136 137 map_parseargs(map, &args, mapname); 138 if (map->map_file == NULL) 139 return FALSE; 140 db = dbopen(map->map_file, O_RDONLY, 0644, DB_BTREE, NULL); 141 if (db == NULL) 142 { 143 if (!bitset(MF_OPTIONAL, map->map_flags)) 144 syserr("Cannot open BTREE database %s", map->map_file); 145 return FALSE; 146 } 147 map->map_db = (void *) db; 148 return TRUE; 149 } 150 151 #endif /* BTREE_MAP */ 152 153 #ifdef HASH_MAP 154 155 /* 156 ** HASH_MAP_INIT -- HASH-style map initialization 157 ** 158 ** Parameters: 159 ** map -- the pointer to the actual map 160 ** mapname -- the name of the map (for error messages) 161 ** args -- a pointer to the config file line arguments 162 ** 163 ** Returns: 164 ** TRUE -- if it could successfully open the map. 165 ** FALSE -- otherwise. 166 ** 167 ** Side Effects: 168 ** Gives an error if it can't open the map. 169 */ 170 171 bool 172 hash_map_init(map, mapname, args) 173 MAP *map; 174 char *mapname; 175 char *args; 176 { 177 DB *db; 178 179 map_parseargs(map, &args, mapname); 180 if (map->map_file == NULL) 181 return FALSE; 182 db = dbopen(map->map_file, O_RDONLY, 0644, DB_HASH, NULL); 183 if (db == NULL) 184 { 185 if (!bitset(MF_OPTIONAL, map->map_flags)) 186 syserr("Cannot open HASH database %s", map->map_file); 187 return FALSE; 188 } 189 map->map_db = (void *) db; 190 return TRUE; 191 } 192 193 #endif /* HASH_MAP */ 194 195 #if defined(BTREE_MAP) || defined(HASH_MAP) 196 197 /* 198 ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 199 ** 200 ** Parameters: 201 ** map -- the map to look up in. 202 ** buf -- a pointer to to the buffer containing the key. 203 ** This is a null terminated string. 204 ** bufsiz -- the size of buf -- note that this is in general 205 ** larger that strlen(buf), and buf can be changed 206 ** in place if desired. 207 ** av -- arguments from the config file (can be interpolated 208 ** into the final result). 209 ** 210 ** Returns: 211 ** A pointer to the rewritten result. 212 ** NULL if not found in the map. 213 */ 214 215 char * 216 db_map_lookup(map, buf, bufsiz, av) 217 MAP *map; 218 char buf[]; 219 int bufsiz; 220 char **av; 221 { 222 DBT key, val; 223 224 key.data = buf; 225 key.size = strlen(buf); 226 if (!bitset(MF_NOFOLDCASE, map->map_flags)) 227 { 228 register char *p; 229 230 for (p = buf; *p != '\0'; p++) 231 if (isupper(*p)) 232 *p = tolower(*p); 233 } 234 if (bitset(MF_INCLNULL, map->map_flags)) 235 key.size++; 236 if (((DB *) map->map_db)->get((DB *) map->map_db, &key, &val, 0) != 0) 237 return NULL; 238 map_rewrite(val.data, val.size, buf, bufsiz, av); 239 return buf; 240 } 241 242 #endif /* BTREE_MAP || HASH_MAP */ 243 /* 244 ** MAP_PARSEARGS -- parse config line arguments for database lookup 245 ** 246 ** Parameters: 247 ** map -- the map being initialized. 248 ** pp -- an indirect pointer to the config line. It will 249 ** be replaced with a pointer to the next field 250 ** on the line. 251 ** mapname -- the name of the map (for errors). 252 ** 253 ** Returns: 254 ** none 255 ** 256 ** Side Effects: 257 ** null terminates the filename; stores it in map 258 */ 259 260 map_parseargs(map, pp, mapname) 261 MAP *map; 262 char **pp; 263 char *mapname; 264 { 265 register char *p = *pp; 266 267 for (;;) 268 { 269 while (isspace(*p)) 270 p++; 271 if (*p != '-') 272 break; 273 switch (*++p) 274 { 275 case 'N': 276 map->map_flags |= MF_INCLNULL; 277 break; 278 279 case 'o': 280 map->map_flags |= MF_OPTIONAL; 281 break; 282 283 case 'f': 284 map->map_flags |= MF_NOFOLDCASE; 285 break; 286 287 case 'a': 288 map->map_app = ++p; 289 break; 290 } 291 while (*p != '\0' && !isspace(*p)) 292 p++; 293 if (*p != '\0') 294 *p++ = 0; 295 } 296 if (map->map_app != NULL) 297 map->map_app = newstr(map->map_app); 298 299 if (*p == '\0') 300 { 301 syserr("No file name for map %s", mapname); 302 return NULL; 303 } 304 map->map_file = p; 305 while (*p != '\0' && !isspace(*p)) 306 p++; 307 if (*p != '\0') 308 *p++ = '\0'; 309 map->map_file = newstr(map->map_file); 310 *pp = p; 311 } 312 /* 313 ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 314 ** 315 ** Parameters: 316 ** s -- the string to rewrite, NOT necessarily null terminated. 317 ** slen -- the length of s. 318 ** buf -- the place to write it. 319 ** buflen -- the length of buf. 320 ** av -- arguments to interpolate into buf. 321 ** 322 ** Returns: 323 ** none. 324 ** 325 ** Side Effects: 326 ** none. 327 */ 328 329 map_rewrite(s, slen, buf, buflen, av) 330 register char *s; 331 int slen; 332 char buf[]; 333 int buflen; 334 char **av; 335 { 336 register char *bp; 337 char *buflim; 338 register char c; 339 char **avp; 340 register char *ap; 341 342 if (tTd(23, 1)) 343 { 344 printf("map_rewrite(%.*s), av =\n", slen, s); 345 for (avp = av; *avp != NULL; avp++) 346 printf("\t%s\n", *avp); 347 } 348 349 bp = buf; 350 buflim = &buf[buflen - 2]; 351 while (--slen >= 0 && (c = *s++) != '\0') 352 { 353 if (c != '%') 354 { 355 pushc: 356 if (bp < buflim) 357 *bp++ = c; 358 continue; 359 } 360 if (--slen < 0 || (c = *s++) == '\0') 361 c = '%'; 362 if (c == '%') 363 goto pushc; 364 if (!isdigit(c)) 365 { 366 *bp++ = '%'; 367 goto pushc; 368 } 369 c -= '0'; 370 for (avp = av; --c >= 0 && *avp != NULL; avp++) 371 continue; 372 if (*avp == NULL) 373 continue; 374 375 /* transliterate argument into output string */ 376 for (ap = *avp; (c = *ap++) != '\0'; ) 377 { 378 if (bp < buflim) 379 *bp++ = c; 380 } 381 } 382 *bp++ = '\0'; 383 if (tTd(23, 1)) 384 printf("map_rewrite => %s\n", buf); 385 } 386