156822Seric /* 256822Seric * Copyright (c) 1992 Eric P. Allman. 356822Seric * Copyright (c) 1992 Regents of the University of California. 456822Seric * All rights reserved. 556822Seric * 656822Seric * %sccs.include.redist.c% 756822Seric */ 856822Seric 956822Seric #ifndef lint 10*57014Seric static char sccsid[] = "@(#)map.c 5.4 (Berkeley) 12/08/92"; 1156822Seric #endif /* not lint */ 1256822Seric 1356822Seric #include "sendmail.h" 1456822Seric #include <sys/file.h> 1556822Seric 1656822Seric #ifdef DBM_MAP 1756822Seric #include <ndbm.h> 1856822Seric #endif 1956822Seric #if defined(HASH_MAP) || defined(BTREE_MAP) 2056822Seric #include <db.h> 2156822Seric #endif 2256822Seric 2356822Seric 2456822Seric #ifdef DBM_MAP 2556822Seric 2656822Seric /* 2756822Seric ** DBM_MAP_INIT -- DBM-style map initialization 2856822Seric ** 2956822Seric ** Parameters: 3056822Seric ** map -- the pointer to the actual map 3156822Seric ** mapname -- the name of the map (for error messages) 3256822Seric ** args -- a pointer to the config file line arguments 3356822Seric ** 3456822Seric ** Returns: 3556822Seric ** TRUE -- if it could successfully open the map. 3656822Seric ** FALSE -- otherwise. 3756822Seric ** 3856822Seric ** Side Effects: 3956822Seric ** Gives an error if it can't open the map. 4056822Seric */ 4156822Seric 4256822Seric bool 4356822Seric dbm_map_init(map, mapname, args) 4456822Seric MAP *map; 4556822Seric char *mapname; 4656822Seric char *args; 4756822Seric { 4856822Seric DBM *dbm; 4956822Seric 5056822Seric map_parseargs(map, &args, mapname); 5156822Seric if (map->map_file == NULL) 5256822Seric return FALSE; 5356822Seric dbm = dbm_open(map->map_file, O_RDONLY, 0644); 5456822Seric if (dbm == NULL) 5556822Seric { 5656836Seric if (!bitset(MF_OPTIONAL, map->map_flags)) 5756836Seric syserr("Cannot open DBM database %s", map->map_file); 5856822Seric return FALSE; 5956822Seric } 6056822Seric map->map_db = (void *) dbm; 6156822Seric return TRUE; 6256822Seric } 6356822Seric /* 6456822Seric ** DBM_MAP_LOOKUP -- look up a datum in a DBM-type map 6556822Seric ** 6656822Seric ** Parameters: 6756822Seric ** map -- the map to look up in. 6856822Seric ** buf -- a pointer to to the buffer containing the key. 6956822Seric ** This is a null terminated string. 7056822Seric ** bufsiz -- the size of buf -- note that this is in general 7156822Seric ** larger that strlen(buf), and buf can be changed 7256822Seric ** in place if desired. 7356822Seric ** av -- arguments from the config file (can be interpolated 7456822Seric ** into the final result). 7556822Seric ** 7656822Seric ** Returns: 7756822Seric ** A pointer to the rewritten result. 7856822Seric ** NULL if not found in the map. 7956822Seric */ 8056822Seric 8156822Seric char * 8256822Seric dbm_map_lookup(map, buf, bufsiz, av) 8356822Seric MAP *map; 8456822Seric char buf[]; 8556822Seric int bufsiz; 8656822Seric char **av; 8756822Seric { 8856822Seric datum key, val; 8956822Seric 9056822Seric key.dptr = buf; 9156822Seric key.dsize = strlen(buf); 92*57014Seric if (bitset(MF_FOLDCASE, map->map_flags)) 93*57014Seric { 94*57014Seric register char *p; 95*57014Seric 96*57014Seric for (p = buf; *p != '\0'; p++) 97*57014Seric if (isupper(*p)) 98*57014Seric *p = tolower(*p); 99*57014Seric } 10056822Seric if (bitset(MF_INCLNULL, map->map_flags)) 10156822Seric key.dsize++; 10256822Seric val = dbm_fetch(map->map_db, key); 10356822Seric if (val.dptr == NULL) 10456822Seric return NULL; 10556822Seric map_rewrite(val.dptr, val.dsize, buf, bufsiz, av); 10656822Seric return buf; 10756822Seric } 10856822Seric 10956822Seric #endif /* DBM_MAP */ 11056822Seric 11156822Seric #ifdef BTREE_MAP 11256822Seric 11356822Seric /* 11456822Seric ** BTREE_MAP_INIT -- BTREE-style map initialization 11556822Seric ** 11656822Seric ** Parameters: 11756822Seric ** map -- the pointer to the actual map 11856822Seric ** mapname -- the name of the map (for error messages) 11956822Seric ** args -- a pointer to the config file line arguments 12056822Seric ** 12156822Seric ** Returns: 12256822Seric ** TRUE -- if it could successfully open the map. 12356822Seric ** FALSE -- otherwise. 12456822Seric ** 12556822Seric ** Side Effects: 12656822Seric ** Gives an error if it can't open the map. 12756822Seric */ 12856822Seric 12956822Seric bool 13056822Seric bt_map_init(map, mapname, args) 13156822Seric MAP *map; 13256822Seric char *mapname; 13356822Seric char *args; 13456822Seric { 13556822Seric DB *db; 13656822Seric 13756822Seric map_parseargs(map, &args, mapname); 13856822Seric if (map->map_file == NULL) 13956822Seric return FALSE; 14056822Seric db = dbopen(map->map_file, O_RDONLY, 0644, DB_BTREE, NULL); 14156822Seric if (db == NULL) 14256822Seric { 14356836Seric if (!bitset(MF_OPTIONAL, map->map_flags)) 14456836Seric syserr("Cannot open BTREE database %s", map->map_file); 14556822Seric return FALSE; 14656822Seric } 14756822Seric map->map_db = (void *) db; 14856822Seric return TRUE; 14956822Seric } 15056822Seric 15156822Seric #endif /* BTREE_MAP */ 15256822Seric 15356822Seric #ifdef HASH_MAP 15456822Seric 15556822Seric /* 15656822Seric ** HASH_MAP_INIT -- HASH-style map initialization 15756822Seric ** 15856822Seric ** Parameters: 15956822Seric ** map -- the pointer to the actual map 16056822Seric ** mapname -- the name of the map (for error messages) 16156822Seric ** args -- a pointer to the config file line arguments 16256822Seric ** 16356822Seric ** Returns: 16456822Seric ** TRUE -- if it could successfully open the map. 16556822Seric ** FALSE -- otherwise. 16656822Seric ** 16756822Seric ** Side Effects: 16856822Seric ** Gives an error if it can't open the map. 16956822Seric */ 17056822Seric 17156822Seric bool 17256822Seric hash_map_init(map, mapname, args) 17356822Seric MAP *map; 17456822Seric char *mapname; 17556822Seric char *args; 17656822Seric { 17756822Seric DB *db; 17856822Seric 17956822Seric map_parseargs(map, &args, mapname); 18056822Seric if (map->map_file == NULL) 18156822Seric return FALSE; 18256822Seric db = dbopen(map->map_file, O_RDONLY, 0644, DB_HASH, NULL); 18356822Seric if (db == NULL) 18456822Seric { 18556836Seric if (!bitset(MF_OPTIONAL, map->map_flags)) 18656836Seric syserr("Cannot open HASH database %s", map->map_file); 18756822Seric return FALSE; 18856822Seric } 18956822Seric map->map_db = (void *) db; 19056822Seric return TRUE; 19156822Seric } 19256822Seric 19356822Seric #endif /* HASH_MAP */ 19456822Seric 19556822Seric #if defined(BTREE_MAP) || defined(HASH_MAP) 19656822Seric 19756822Seric /* 19856822Seric ** DB_MAP_LOOKUP -- look up a datum in a BTREE- or HASH-type map 19956822Seric ** 20056822Seric ** Parameters: 20156822Seric ** map -- the map to look up in. 20256822Seric ** buf -- a pointer to to the buffer containing the key. 20356822Seric ** This is a null terminated string. 20456822Seric ** bufsiz -- the size of buf -- note that this is in general 20556822Seric ** larger that strlen(buf), and buf can be changed 20656822Seric ** in place if desired. 20756822Seric ** av -- arguments from the config file (can be interpolated 20856822Seric ** into the final result). 20956822Seric ** 21056822Seric ** Returns: 21156822Seric ** A pointer to the rewritten result. 21256822Seric ** NULL if not found in the map. 21356822Seric */ 21456822Seric 21556822Seric char * 21656822Seric db_map_lookup(map, buf, bufsiz, av) 21756822Seric MAP *map; 21856822Seric char buf[]; 21956822Seric int bufsiz; 22056822Seric char **av; 22156822Seric { 22256822Seric DBT key, val; 22356822Seric 22456822Seric key.data = buf; 22556822Seric key.size = strlen(buf); 22656847Seric if (bitset(MF_FOLDCASE, map->map_flags)) 22756847Seric { 22856847Seric register char *p; 22956847Seric 23056847Seric for (p = buf; *p != '\0'; p++) 23156847Seric if (isupper(*p)) 23256847Seric *p = tolower(*p); 23356847Seric } 23456822Seric if (bitset(MF_INCLNULL, map->map_flags)) 23556822Seric key.size++; 23656836Seric if (((DB *) map->map_db)->get((DB *) map->map_db, &key, &val, 0) != 0) 23756822Seric return NULL; 23856822Seric map_rewrite(val.data, val.size, buf, bufsiz, av); 23956822Seric return buf; 24056822Seric } 24156822Seric 24256822Seric #endif /* BTREE_MAP || HASH_MAP */ 24356822Seric /* 24456822Seric ** MAP_PARSEARGS -- parse config line arguments for database lookup 24556822Seric ** 24656822Seric ** Parameters: 24756822Seric ** map -- the map being initialized. 24856822Seric ** pp -- an indirect pointer to the config line. It will 24956822Seric ** be replaced with a pointer to the next field 25056822Seric ** on the line. 25156822Seric ** mapname -- the name of the map (for errors). 25256822Seric ** 25356822Seric ** Returns: 25456822Seric ** none 25556822Seric ** 25656822Seric ** Side Effects: 25756822Seric ** null terminates the filename; stores it in map 25856822Seric */ 25956822Seric 26056822Seric map_parseargs(map, pp, mapname) 26156822Seric MAP *map; 26256822Seric char **pp; 26356822Seric char *mapname; 26456822Seric { 26556822Seric register char *p = *pp; 26656822Seric 26756822Seric for (;;) 26856822Seric { 26956822Seric while (isspace(*p)) 27056822Seric p++; 27156822Seric if (*p != '-') 27256822Seric break; 27356822Seric switch (*++p) 27456822Seric { 27556822Seric case 'N': 27656822Seric map->map_flags |= MF_INCLNULL; 27756822Seric break; 27856836Seric 27956836Seric case 'o': 28056836Seric map->map_flags |= MF_OPTIONAL; 28156836Seric break; 28256836Seric 28356847Seric case 'f': 28456847Seric map->map_flags |= MF_FOLDCASE; 28556847Seric break; 28656847Seric 28756836Seric case 'a': 28856836Seric map->map_app = ++p; 28956836Seric break; 29056822Seric } 29156822Seric while (*p != '\0' && !isspace(*p)) 29256822Seric p++; 29356836Seric if (*p != '\0') 29456836Seric *p++ = 0; 29556822Seric } 29656836Seric if (map->map_app != NULL) 29756836Seric map->map_app = newstr(map->map_app); 29856822Seric 29956822Seric if (*p == '\0') 30056822Seric { 30156822Seric syserr("No file name for map %s", mapname); 30256822Seric return NULL; 30356822Seric } 30456822Seric map->map_file = p; 30556822Seric while (*p != '\0' && !isspace(*p)) 30656822Seric p++; 30756822Seric if (*p != '\0') 30856822Seric *p++ = '\0'; 30956836Seric map->map_file = newstr(map->map_file); 31056822Seric *pp = p; 31156822Seric } 31256822Seric /* 31356822Seric ** MAP_REWRITE -- rewrite a database key, interpolating %n indications. 31456822Seric ** 31556822Seric ** Parameters: 31656822Seric ** s -- the string to rewrite, NOT necessarily null terminated. 31756822Seric ** slen -- the length of s. 31856822Seric ** buf -- the place to write it. 31956822Seric ** buflen -- the length of buf. 32056822Seric ** av -- arguments to interpolate into buf. 32156822Seric ** 32256822Seric ** Returns: 32356822Seric ** none. 32456822Seric ** 32556822Seric ** Side Effects: 32656822Seric ** none. 32756822Seric */ 32856822Seric 32956822Seric map_rewrite(s, slen, buf, buflen, av) 33056822Seric register char *s; 33156822Seric int slen; 33256822Seric char buf[]; 33356822Seric int buflen; 33456822Seric char **av; 33556822Seric { 33656822Seric register char *bp; 33756822Seric char *buflim; 33856822Seric register char c; 33956822Seric char **avp; 34056822Seric register char *ap; 34156822Seric 34256822Seric if (tTd(23, 1)) 34356822Seric { 34456822Seric printf("map_rewrite(%.*s), av =\n", slen, s); 34556822Seric for (avp = av; *avp != NULL; avp++) 34656822Seric printf("\t%s\n", *avp); 34756822Seric } 34856822Seric 34956822Seric bp = buf; 35056822Seric buflim = &buf[buflen - 2]; 35156822Seric while (--slen >= 0 && (c = *s++) != '\0') 35256822Seric { 35356822Seric if (c != '%') 35456822Seric { 35556822Seric pushc: 35656822Seric if (bp < buflim) 35756822Seric *bp++ = c; 35856822Seric continue; 35956822Seric } 36056822Seric if (--slen < 0 || (c = *s++) == '\0') 36156822Seric c = '%'; 36256822Seric if (c == '%') 36356822Seric goto pushc; 36456822Seric if (!isdigit(c)) 36556822Seric { 36656822Seric *bp++ = '%'; 36756822Seric goto pushc; 36856822Seric } 36956822Seric c -= '0'; 37056822Seric for (avp = av; --c >= 0 && *avp != NULL; avp++) 37156822Seric continue; 37256822Seric if (*avp == NULL) 37356822Seric continue; 37456822Seric 37556822Seric /* transliterate argument into output string */ 37656822Seric for (ap = *avp; (c = *ap++) != '\0'; ) 37756822Seric { 37856822Seric if (bp < buflim) 37956822Seric *bp++ = c; 38056822Seric } 38156822Seric } 38256822Seric *bp++ = '\0'; 38356822Seric if (tTd(23, 1)) 38456822Seric printf("map_rewrite => %s\n", buf); 38556822Seric } 386