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