diff -N -r -c sendmail-pristine/README.CDB sendmail-cdb/README.CDB
*** sendmail-pristine/README.CDB	Wed Dec 31 20:00:00 1969
--- sendmail-cdb/README.CDB	Fri May  7 18:39:01 1999
***************
*** 0 ****
--- 1,61 ----
+ Patches for using cdb with sendmail 8.9.3
+ 
+ This patch adds a sendmail map type for Dan Bernstein's cdb package. 
+ 
+ USAGE
+ 
+ To compile cdb support into sendmail, you should add the following lines to
+ your site.config.m4:
+ 
+ APPENDDEF(`confMAPDEF', `-DCDB')
+ APPENDDEF(`confLIBS', `-lcdb -lcdbmake')
+ 
+ and then just rebuild as you normally would (you'll need to use Build -c so 
+ that the Makefile gets rebuilt).
+ 
+ This of course assumes that you have already installed the cdb package from
+ http://pobox.com/~djb/software/cdb-0.55.tar.gz
+ 
+ Once compiled in, cdb can be used as any other maptype (alias rebuilding
+ included). Note that with aliases, it will not take precedence over hash or
+ dbm if the implicit map type is used. 
+ 
+ PERFORMANCE
+ 
+ In the rather limited testing I've done (mostly single lookups on large
+ alias databases), it tends to be about 20% faster than Berkeley DB when
+ doing a sendmail -bv <aliasname>. Builds tend to take a lot longer, though
+ if you ifdef out the duplicate key checking code, it'll take about 25% of
+ the time of a hash build. Even then, this performance is coupled with
+ a very small db size (the size of a cdb database in bytes is:
+ 2048 + sum of lengths of keys + sum of lengths of values + 4 * number of keys)
+ 
+ CODE NOTES
+ 
+ The cdb map code is based upon the code for the db_map_* functions. As a
+ result, it has the pre-open/pre-locking stuff left in (I'm not sure what
+ of that is necessary, I'll go over it later).
+ 
+ sm_cdb.h is added to the src directory, as much as I loathed having to do
+ so. Unfortunately, the API for cdbmake makes this nearly impossible any
+ other way. Both the file descriptor and cdbmake structure must persist
+ amongst the open, store, and close hooks (and the file position, though one
+ could get around that by doing an lseek(fd, 0, SEEK_END)).
+ 
+ The other problem caused by the cdbmake API is the lack of duplicate key
+ checking. As a result, I have to manually grovel through the linked list of
+ arrays kept in the cdbmake structure to check for duplicate keys, which 
+ makes builds actually slower than Berkeley DB. I may write a frontend to the
+ cdbmake functions (or replacements) to make builds more efficient in this 
+ regard.
+ 
+ I've tried to modify the documentation appropriately, but I'm not sure
+ I've made all necessary changes (and I'm not sure all the changes I made
+ were necessary). Feedback on this issue would be appreciated.
+ 
+ Oh, and please forgive me for the goto's in cdb_map_lookup, I'll clean
+ that up later, I promise. :)
+ 
+ FEEDBACK
+ 
+ Any comments can be sent to kdoherty@uu.net. 
diff -N -r -c sendmail-pristine/doc/op/op.me sendmail-cdb/doc/op/op.me
*** sendmail-pristine/doc/op/op.me	Fri Jan 22 18:58:30 1999
--- sendmail-cdb/doc/op/op.me	Fri May  7 17:05:40 1999
***************
*** 300,307 ****
  reads the DBM version of the alias file.
  It's ugly as sin,
  but it works.
  .lp
! If neither of these are defined,
  .i sendmail
  reads the alias file into memory on every invocation.
  This can be slow and should be avoided.
--- 300,314 ----
  reads the DBM version of the alias file.
  It's ugly as sin,
  but it works.
+ .ip CDB
+ Dan Bernstein's Constant DB package.
+ CDB provides a fast, simple interface for
+ lookups. Its primary drawback is an 
+ awkward DB creation API, making for slower 
+ DB builds (because of a nasty hack to 
+ check for duplicate keys).
  .lp
! If none of these are defined,
  .i sendmail
  reads the alias file into memory on every invocation.
  This can be slow and should be avoided.
***************
*** 1259,1269 ****
  .i gdbm
  package does not work.
  .)f
! or the Berkeley DB library.
  This form is in the file
  .i /etc/aliases.db
  (if using NEWDB)
  or
  .i /etc/aliases.dir
  and
  .i /etc/aliases.pag
--- 1266,1280 ----
  .i gdbm
  package does not work.
  .)f
! , the Berkeley DB, or
! the CDB library.
  This form is in the file
  .i /etc/aliases.db
  (if using NEWDB)
  or
+ .i /etc/aliases.cdb
+ (if using CDB)
+ or
  .i /etc/aliases.dir
  and
  .i /etc/aliases.pag
***************
*** 1337,1343 ****
  .sh 3 "Rebuilding the alias database"
  .pp
  The
! .i hash
  or
  .i dbm
  version of the database
--- 1348,1355 ----
  .sh 3 "Rebuilding the alias database"
  .pp
  The
! .i hash ,
! .i cdb ,
  or
  .i dbm
  version of the database
***************
*** 2626,2631 ****
--- 2638,2644 ----
  Allow maps (e.g.,
  .i hash ,
  .i btree ,
+ .i cdb ,
  and
  .i dbm
  files)
***************
*** 4838,4843 ****
--- 4851,4860 ----
  (if
  .sm NEWDB
  is specified),
+ .q cdb
+ (if
+ .sm CDB
+ is specified),
  .q dbm
  (if
  .sm NDBM
***************
*** 6357,6362 ****
--- 6374,6385 ----
  must be compiled with
  .b NDBM
  defined.
+ .ip cdb
+ Database lookups using the cdb(3) library.
+ .i Sendmail
+ must be compiled with
+ .b CDB
+ defined.
  .ip btree
  Database lookups using the btree interface to the Berkeley DB
  library.
***************
*** 6718,6730 ****
  .q \&.pag
  and
  .q \&.dir
! to the given filename;
  the
  .i hash
  and
  .i btree
  maps append
! .q \&.db .
  For example, the map specification
  .(b
  Kuucp dbm \-o \-N /usr/lib/uucpmap
--- 6741,6757 ----
  .q \&.pag
  and
  .q \&.dir
! to the given filename, whereas
  the
  .i hash
  and
  .i btree
  maps append
! .q \&.db ,
! and the
! .i cdb
! map appends 
! .q \&.cdb .
  For example, the map specification
  .(b
  Kuucp dbm \-o \-N /usr/lib/uucpmap
***************
*** 6958,6963 ****
--- 6985,6993 ----
  .i sendmail
  will read DBM files,
  but will create and use NEWDB files.
+ .ip CDB
+ If set, use the cdb package by Dan Bernstein.
+ This package is faster than DBM, NDBM, or NEWDB.
  .ip NIS
  Include support for NIS.
  If set together with
***************
*** 8183,8188 ****
--- 8213,8222 ----
  .ip /etc/aliases.db
  The alias file in
  .i hash \|(3)
+ format.
+ .ip /etc/aliases.cdb
+ The alias file in
+ .i cdb \|(3)
  format.
  .ip /etc/aliases.{pag,dir}
  The alias file in
diff -N -r -c sendmail-pristine/src/README sendmail-cdb/src/README
*** sendmail-pristine/src/README	Thu Feb  4 19:25:04 1999
--- sendmail-cdb/src/README	Fri May  7 11:25:19 1999
***************
*** 106,111 ****
--- 106,113 ----
  		libdb.a.
  NDBM		The older NDBM implementation -- the very old V7 DBM
  		implementation is no longer supported.
+ CDB		Dan Bernstein's Constant DataBase. Designed to use a minimal
+ 		number of system calls for optimum lookup speed.
  NIS		Network Information Services.  To use this you must have
  		NIS support on your system.
  NISPLUS		NIS+ (the revised NIS released with Solaris 2).  You must
diff -N -r -c sendmail-pristine/src/conf.c sendmail-cdb/src/conf.c
*** sendmail-pristine/src/conf.c	Tue Apr 27 18:45:47 1999
--- sendmail-cdb/src/conf.c	Fri May  7 18:41:03 1999
***************
*** 362,367 ****
--- 362,373 ----
  {
  	register STAB *s;
  
+ #ifdef CDB
+ 	MAPDEF("cdb", ".cdb", MCF_ALIASOK|MCF_REBUILDABLE,
+ 		map_parseargs, cdb_map_open, cdb_map_close,
+ 		cdb_map_lookup, cdb_map_store);
+ #endif
+ 
  #ifdef NEWDB
  	MAPDEF("hash", ".db", MCF_ALIASOK|MCF_REBUILDABLE,
  		map_parseargs, hash_map_open, db_map_close,
***************
*** 594,599 ****
--- 600,613 ----
  			strcpy(buf, "aliases.files null");
  			(void) makemapentry(buf);
  		}
+ #ifdef CDB
+ 		else if (strcmp(maptype[i], "cdb") == 0 &&
+ 		    stab("aliases.cdb", ST_MAP, ST_FIND) == NULL)
+ 		{
+ 			strcpy(buf, "aliases.cdb null");
+ 			(void) makemapentry(buf);
+ 		}
+ #endif
  #ifdef NISPLUS
  		else if (strcmp(maptype[i], "nisplus") == 0 &&
  		    stab("aliases.nisplus", ST_MAP, ST_FIND) == NULL)
***************
*** 909,914 ****
--- 923,931 ----
  	if (strcmp(service, "aliases") == 0)
  	{
  		maptype[svcno++] = "files";
+ #ifdef CDB
+ 		maptype[svcno++] = "cdb";
+ #endif
  # ifdef AUTO_NIS_ALIASES
  #  ifdef NISPLUS
  		maptype[svcno++] = "nisplus";
diff -N -r -c sendmail-pristine/src/map.c sendmail-cdb/src/map.c
*** sendmail-pristine/src/map.c	Tue Apr 27 18:45:48 1999
--- sendmail-cdb/src/map.c	Fri May  7 17:02:48 1999
***************
*** 1901,1906 ****
--- 1901,2471 ----
  }
  
  #endif
+ 
+ /*
+ **  CDB Modules
+ */
+ 
+ #ifdef CDB
+ #include "sm_cdb.h"
+ 
+ /*
+ ** CDB_MAP_OPEN -- open a CDB database
+ */
+ 
+ bool
+ cdb_map_open(map, mode)
+ 	MAP *map;
+ 	int mode;
+ {
+ 	int i;
+ 	int omode;
+ 	int smode = S_IREAD;
+ 	int fd, dfd;
+ 	int sff;
+ 	int saveerrno;
+ 	struct stat st;
+ 	char buf[MAXNAME + 1];
+ 	struct cdbmake *cdbm;
+ 
+ 	/* do initial file and directory checks */
+ 	snprintf(buf, sizeof buf - 4, "%s", map->map_file);
+ 	i = strlen(buf);
+ 	if (i < 4 || strcmp(&buf[i - 4], ".cdb") != 0)
+ 		(void) strcat(buf, ".cdb");
+ 
+ 	mode &= O_ACCMODE;
+ 	omode = mode;
+ 
+ 	sff = SFF_ROOTOK|SFF_REGONLY;
+ 	if (mode == O_RDWR)
+ 	{
+ 		sff |= SFF_CREAT;
+ 		if (!bitset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
+ 			sff |= SFF_NOSLINK;
+ 		if (!bitset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
+ 			sff |= SFF_NOHLINK;
+ 		smode = S_IWRITE;
+ 	}
+ 	else
+ 	{
+ 		if (!bitset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
+ 			sff |= SFF_NOWLINK;
+ 	}
+ 	if (!bitset(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail))
+ 		sff |= SFF_SAFEDIRPATH;
+ 	i = safefile(buf, RunAsUid, RunAsGid, RunAsUserName, sff, smode, &st);
+ 	if (i == ENOENT && AutoRebuild &&
+ 	    bitset(MCF_REBUILDABLE, map->map_class->map_cflags) &&
+ 	    (bitset(MF_IMPL_CDB, map->map_mflags) ||
+ 	     bitset(MF_ALIAS, map->map_mflags)) &&
+ 	    mode == O_RDONLY)
+ 	{
+ 		bool impl = bitset(MF_IMPL_CDB, map->map_mflags);
+ 		extern bool impl_map_open __P((MAP *, int));
+ 
+ 		/* may be able to rebuild */
+ 		map->map_mflags &= ~MF_IMPL_CDB;
+ 		if (!rebuildaliases(map, TRUE))
+ 			return FALSE;
+ 		if (impl)
+ 			return impl_map_open(map, O_RDONLY);
+ 		else
+ 		        return cdb_map_open(map, O_RDONLY);
+ 	}
+ 
+ 	if (i != 0)
+ 	{
+ 		char *prob = "unsafe";
+ 
+ 		/* cannot open this map */
+ 		if (i == ENOENT)
+ 			prob = "missing";
+ 		if (tTd(38, 2))
+ 			printf("\t%s map file: %s\n", prob, errstring(i));
+ 		errno = i;
+ 		if (!bitset(MF_OPTIONAL, map->map_mflags))
+ 			syserr("cdb map \"%s\": %s map file %s",
+ 				map->map_mname, prob, buf);
+ 		return FALSE;
+ 	}
+ 	if (st.st_mode == ST_MODE_NOFILE)
+ 		omode |= O_CREAT|O_EXCL;
+ 
+ 	map->map_lockfd = -1;
+ 
+ #if LOCK_ON_OPEN
+ 	if (mode == O_RDWR)
+ 		omode |= O_TRUNC|O_EXLOCK;
+ 	else
+ 		omode |= O_SHLOCK;
+ #else
+ 	/*
+ 	**  Pre-lock the file to avoid race conditions.  In particular,
+ 	**  since dbopen returns NULL if the file is zero length, we
+ 	**  must have a locked instance around the dbopen.
+ 	*/
+ 
+ 	fd = open(buf, omode, DBMMODE);
+ 	if (fd < 0)
+ 	{
+ 		if (!bitset(MF_OPTIONAL, map->map_mflags))
+ 			syserr("cdb_map_open: cannot pre-open database %s", buf);
+ 		return FALSE;
+ 	}
+ 
+ 	/* make sure no baddies slipped in just before the open... */
+ 	if (filechanged(buf, fd, &st))
+ 	{
+ 		int save_errno = errno;
+ 
+ 		(void) close(fd);
+ 		errno = save_errno;
+ 		syserr("cdb_map_open(%s): file changed after pre-open", buf);
+ 		return FALSE;
+ 	}
+ 
+ 	/* if new file, get the "before" bits for later filechanged check */
+ 	if (st.st_mode == ST_MODE_NOFILE && fstat(fd, &st) < 0)
+ 	{
+ 		int save_errno = errno;
+ 
+ 		(void) close(fd);
+ 		errno = save_errno;
+ 		syserr("cdb_map_open(%s): cannot fstat pre-opened file",
+ 			buf);
+ 		return FALSE;
+ 	}
+ 
+ 	/* actually lock the pre-opened file */
+ 	if (!lockfile(fd, buf, NULL, mode == O_RDONLY ? LOCK_SH : LOCK_EX))
+ 		syserr("cdb_map_open: cannot lock %s", buf);
+ 
+ 	/* set up mode bits for dbopen */
+ 	if (mode == O_RDWR)
+ 		omode |= O_TRUNC;
+ 	omode &= ~(O_EXCL|O_CREAT);
+ #endif
+ 
+ #if !LOCK_ON_OPEN
+ 	if (mode == O_RDWR)
+ 		map->map_lockfd = fd;
+ 	else
+ 		(void) close(fd);
+ #endif
+ 
+ 	fd = open(buf, omode, DBMMODE);
+ 	saveerrno = errno;
+ 
+ 	if (fd < 0)
+ 	{
+ 		if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
+ 		    aliaswait(map, ".cdb", FALSE))
+ 			return TRUE;
+ #if !LOCK_ON_OPEN
+ 		if (map->map_lockfd >= 0)
+ 			(void) close(map->map_lockfd);
+ #endif
+ 		errno = saveerrno;
+ 		if (!bitset(MF_OPTIONAL, map->map_mflags))
+ 			syserr("Cannot open cdb database %s", buf);
+ 		return FALSE;
+ 	}
+ 
+ 	if (filechanged(buf, fd, &st))
+ 	{
+ 		int save_errno = errno;
+ 
+ 		close(fd);
+ #if !LOCK_ON_OPEN
+ 		if (map->map_lockfd >= 0)
+ 			close(map->map_lockfd);
+ #endif
+ 		errno = save_errno;
+ 		syserr("cdb_map_open(%s): file changed after open", buf);
+ 		return FALSE;
+ 	}
+ 
+ 	if (mode == O_RDWR)
+ 		map->map_mflags |= MF_LOCKED;
+ #if LOCK_ON_OPEN
+ 	if (fd >= 0 && mode == O_RDONLY)
+ 	{
+ 		(void) lockfile(fd, buf, NULL, LOCK_UN);
+ 	}
+ #endif
+ 
+ 	/* try to make sure that at least the database header is on disk */
+ 	if (mode == O_RDWR)
+ 	{
+ #if _FFR_TRUSTED_USER
+ 		if (geteuid() == 0 && TrustedUid != 0)
+ 		{
+ 			if (fchown(fd, TrustedUid, -1) < 0)
+ 			{
+ 				int err = errno;
+ 
+ 				sm_syslog(LOG_ALERT, NOQID,
+ 					  "ownership change on %s failed: %s",
+ 					  buf, errstring(err));
+ 				message("050 ownership change on %s failed: %s",
+ 					buf, errstring(err));
+ 			}
+ 		}
+ #endif
+ 	}
+ 
+ 	if (fd >= 0 && fstat(fd, &st) >= 0)
+ 		map->map_mtime = st.st_mtime;
+ 
+ 	if (mode == O_RDONLY) 
+ 	{
+ 	        map->map_db1 = (ARBPTR_T)mode;
+ 		map->map_db2 = (ARBPTR_T)fd;
+ 	}
+ 	else
+ 	{
+ 		cdbm = malloc(sizeof(struct cdbmake));
+ 		cdbmake_init(cdbm);
+ 		map->map_db1 = (ARBPTR_T)mode;
+ 		map->map_db2 = (ARBPTR_T)malloc(sizeof(struct sm_cdbmake));
+ 		((struct sm_cdbmake *)map->map_db2)->fd = fd;
+ 		memcpy(&(((struct sm_cdbmake *)map->map_db2)->cdbm), 
+ 		       cdbm, sizeof(struct cdbmake));
+ 		for (i = 0; i < sizeof(cdbm->final);i++)
+ 		        write(fd, "\0", 1);
+ 		((struct sm_cdbmake *)map->map_db2)->pos = sizeof(cdbm->final);
+ 	}
+ 	if (mode == O_RDONLY && bitset(MF_ALIAS, map->map_mflags) &&
+ 	    !aliaswait(map, ".cdb", TRUE))
+ 		return FALSE;
+ 
+ 	return TRUE;
+ }
+ 
+ 
+ /*
+ ** CDB_MAP_LOOKUP -- look up a key's value in an opened CDB database
+ */
+ 
+ char *
+ cdb_map_lookup(map, name, av, statp)
+ 	MAP *map;
+ 	char *name;
+ 	char **av;
+ 	int *statp;
+ {
+         int fd = (int)map->map_db2;
+ 	int i;
+ 	int st;
+ 	int saveerrno;
+ 	struct stat stbuf;
+ 	char keybuf[MAXNAME + 1];
+ 	char buf[MAXNAME + 1];
+ 	char *data;
+ 	uint32 klen, dlen;
+ 
+ 	if (tTd(38, 20))
+ 	        printf("cdb_map_lookup(%s, %s)\n",
+ 			map->map_mname, name);
+ 
+ 	if ((int)map->map_db1 != O_RDONLY) 
+ 	{
+ 		*statp = EX_SOFTWARE;
+ 	        return NULL;
+ 	}
+ 
+ 	i = strlen(map->map_file);
+ 	if (i > MAXNAME)
+ 		i = MAXNAME;
+ 	strncpy(buf, map->map_file, i);
+ 	buf[i] = '\0';
+ 	if (i > 4 && strcmp(&buf[i - 4], ".cdb") == 0)
+ 		buf[i - 4] = '\0';
+ 
+ 	klen = strlen(name);
+ 	bcopy(name, keybuf, klen);
+ 	keybuf[klen] = '\0';
+ 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ 		makelower(keybuf);
+   lockdb:
+ 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ 		(void) lockfile(fd, buf, ".cdb", LOCK_SH);
+ 	if (fd < 0 || fstat(fd, &stbuf) < 0 || stbuf.st_mtime > map->map_mtime)
+ 	{
+ 		/* Reopen the database to sync the cache */
+ 		int omode = bitset(map->map_mflags, MF_WRITABLE) ? O_RDWR
+ 								 : O_RDONLY;
+ 
+ 		map->map_class->map_close(map);
+ 		map->map_mflags &= ~(MF_OPEN|MF_WRITABLE);
+ 		if (map->map_class->map_open(map, omode))
+ 		{
+ 			map->map_mflags |= MF_OPEN;
+ 			map->map_pid = getpid();
+ 			if ((omode && O_ACCMODE) == O_RDWR)
+ 				map->map_mflags |= MF_WRITABLE;
+ 			goto lockdb;
+ 		}
+ 		else
+ 		{
+ 			if (!bitset(MF_OPTIONAL, map->map_mflags))
+ 			{
+ 				extern MAPCLASS BogusMapClass;
+ 
+ 				*statp = EX_TEMPFAIL;
+ 				map->map_class = &BogusMapClass;
+ 				map->map_mflags |= MF_OPEN;
+ 				map->map_pid = getpid();
+ 				syserr("Cannot reopen cdb database %s",
+ 					map->map_file);
+ 			}
+ 			return NULL;
+ 		}
+ 	}
+ 
+ 	st = 1;
+ 	if (bitset(MF_TRY0NULL, map->map_mflags))
+ 	{
+ 	        if (cdb_seek(fd, keybuf, klen, &dlen) != 1) 
+ 		{
+ 		        *statp = EX_NOUSER;
+ 			st = 1;
+ 			if (!bitset(MF_TRY1NULL, map->map_mflags))
+ 			        goto cdb_error;
+ 		}
+ 		else
+ 		{
+ 		        st = 0;
+ 		}
+ 	}
+ 	if (st != 0 && bitset(MF_TRY1NULL, map->map_mflags))
+ 	{
+ 	        if (cdb_seek(fd, keybuf, ++klen, &dlen) != 1) 
+ 		{
+ 		        *statp = EX_NOUSER;
+ 			st = 1;
+ 			goto cdb_error;
+ 		}
+ 		else
+ 		{
+ 		        map->map_mflags &= ~MF_TRY0NULL;
+ 			st = 0;
+ 		}
+ 	}
+ 	if (dlen == 0) 
+ 	{
+ 	        *statp = EX_UNAVAILABLE;
+ 		st = 1;
+ 		goto cdb_error;
+ 	}
+ 	if ((data = (char *)malloc(dlen + 1)) == NULL) 
+ 	{
+ 	        *statp = EX_OSERR;
+ 		st = -1;
+ 		goto cdb_error;
+ 	}
+ 	if ((i = read(fd, data, dlen)) != dlen) 
+ 	{
+ 	        *statp = EX_UNAVAILABLE;
+ 		st = -1;
+ 		goto cdb_error;
+ 	}
+ 	data[dlen] = '\0';
+ 
+ cdb_error:
+ 	saveerrno = errno;
+ 	if (fd >= 0 && !bitset(MF_LOCKED, map->map_mflags))
+ 		(void) lockfile(fd, buf, ".cdb", LOCK_UN);
+ 	if (st != 0)
+ 	{
+ 		errno = saveerrno;
+ 		if (st < 0)
+ 			syserr("cdb_map_lookup: get (%s)", name);
+ 		return NULL;
+ 	}
+ 	if (bitset(MF_MATCHONLY, map->map_mflags))
+ 		return map_rewrite(map, name, strlen(name), NULL);
+ 	else
+ 		return map_rewrite(map, data, dlen, av);
+ }
+ 
+ 
+ /*
+ ** CDB_MAP_STORE -- Store a key and value in a CDB map
+ */
+ 
+ void
+ cdb_map_store(map, lhs, rhs)
+ 	register MAP *map;
+ 	char *lhs;
+ 	char *rhs;
+ {
+         register struct sm_cdbmake *sm_cdbm = 
+ 	        (struct sm_cdbmake *)map->map_db2;
+ 	struct cdbmake *cdbm = &(sm_cdbm->cdbm);
+ 	int fd = sm_cdbm->fd;
+ 	int i;
+ 	char keybuf[MAXNAME + 1];
+ 	char buf[MAXNAME + 1];
+ 	uint32 klen, dlen, hashnum, tmpklen;
+ 	char packbuf[8];
+ 	struct cdbmake_hplist *hplist; /* this is required for some hairy
+ 					  cdb internal stuff to check for
+ 					  duplicate entries */
+ 
+ 	if (tTd(38, 12))
+ 	        printf("cdb_map_store(%s, %s, %s)\n",
+ 			map->map_mname, lhs, rhs);
+ 
+ 	if ((int)map->map_db1 == O_RDONLY) 
+ 	{
+ 	        return;
+ 	}
+ 
+ 	klen = strlen(lhs);
+ 	if (klen > sizeof keybuf - 1)
+ 	        klen = sizeof keybuf - 1;
+ 	bcopy(lhs, keybuf, klen);
+ 	keybuf[klen] = '\0';
+ 	if (!bitset(MF_NOFOLDCASE, map->map_mflags))
+ 	{
+ 		makelower(keybuf);
+ 	}
+ 	
+ 	dlen = strlen(rhs);
+ 
+ 	if (bitset(MF_INCLNULL, map->map_mflags))
+ 	{
+ 		klen++;
+ 		dlen++;
+ 	}
+ 
+ 	/* Get the hash of the string so we can check for it in the hplist */
+ 	hashnum = CDBMAKE_HASHSTART;
+ 	for (i = 0;i < klen;i++) {
+ 	        hashnum = cdbmake_hashadd(hashnum, keybuf[i]);
+ 	}
+ 
+ 	/* Check for a duplicate key */
+ 	/*
+ 	 * NOTE: Using append with cdb would be very difficult because 
+ 	 *       appending to an existing datum would skew the position numbers
+ 	 *       for any subsequent keys. One possible solution would be to
+ 	 *       rewrite the key name with nulls in the previous instance of
+ 	 *       the key, but this seems like really bad juju to me.
+ 	 */
+ 	if (!bitset(MF_APPEND, map->map_mflags))
+ 	{
+ 	        /* 
+ 		 * cdb keeps a linked list of arrays of the hashnum and file
+ 		 * position of each key inserted into the database. We 
+                  * iterate through the linked list of arrays, checking first
+ 		 * against hash number, then against the key length, and 
+ 		 * finally key string.
+ 		 */
+ 	        for (hplist = cdbm->head;hplist;hplist = hplist->next) 
+ 		{
+ 	                for (i = 0;i < hplist->num;i++)
+ 			{
+ 			        if (hplist->hp[i].h == hashnum)
+ 				{
+ 				        lseek(fd, (off_t)hplist->hp[i].p, SEEK_SET);
+ 					read(fd, buf, 4);
+ 					tmpklen = cdb_unpack(buf);
+ 					if (tmpklen != klen) 
+ 					{
+ 					        continue;
+ 					}
+ 					else
+ 					{
+ 					        lseek(fd, (off_t) 4, SEEK_CUR);
+ 						read(fd, buf, tmpklen);
+ 						if (!strncmp(keybuf, buf, klen)) 
+ 						{
+ 						        message("050 Warning: duplicate alias name %s", lhs);
+ 						}
+ 					}
+ 				}
+ 			}
+ 		}
+ 		lseek(fd, (off_t) 0, SEEK_END);
+ 	}
+ 
+ 	/* Pack the sizes of key and data into packbuf (this is done to avoid
+ 	   endianness problems) */
+ 	cdbmake_pack(packbuf, klen);
+ 	cdbmake_pack(packbuf + 4, dlen);
+ 
+ 	if (write(fd, packbuf, 8) < 8) 
+ 	{
+ 	        syserr("readaliases: cdb put (%s)", lhs);
+ 	}
+ 
+ 	write(fd, keybuf, klen);
+ 	write(fd, rhs, dlen);
+ 
+ 	if (!cdbmake_add(cdbm, hashnum, sm_cdbm->pos, malloc)) 
+ 	{
+ 	        syserr("readaliases: cdb put (%s)", lhs);
+ 	}
+ 	sm_cdbm->pos += (uint32)8;
+ 	sm_cdbm->pos += klen;
+ 	sm_cdbm->pos += dlen;
+ }
+ 
+ /*
+ ** CDB_MAP_CLOSE -- close the CDB database file descriptor
+ */
+ 
+ void
+ cdb_map_close(map)
+         MAP *map;
+ {
+ 	if ((int)map->map_db1 == O_RDWR) 
+ 	{
+ 	        struct sm_cdbmake *sm_cdbm = (struct sm_cdbmake *)map->map_db2;
+ 		struct cdbmake *cdbm = &(sm_cdbm->cdbm);
+ 		int fd = sm_cdbm->fd;
+ 		uint32 klen, dlen, hashnum, len;
+ 		char packbuf[8];
+ 		int i, j;
+ 		
+ 		/* Insert a check to see if this is aliases here */
+ 		cdb_map_store(map, "@", "@");
+ 	        if (!cdbmake_split(cdbm, malloc)) {
+ 		        /* Error handling? */
+ 		}
+ 		for (i = 0;i < 256;i++) {
+ 		        len = cdbmake_throw(cdbm, sm_cdbm->pos, i);
+ 			for (j = 0;j < len;j++) {
+ 			        cdbmake_pack(packbuf, cdbm->hash[j].h);
+ 				cdbmake_pack(packbuf + 4, cdbm->hash[j].p);
+ 				if (write(fd, packbuf, 8) < 8) {
+ 				}
+ 				sm_cdbm->pos += 8;
+ 			}
+ 		}
+ 		lseek(fd, 0, SEEK_SET);
+ 		write(fd, cdbm->final, sizeof(cdbm->final));
+ #if !LOCK_ON_OPEN
+ 		if (map->map_lockfd >= 0)
+ 		        (void) close(map->map_lockfd);
+ #endif
+ 	        close((int)((struct sm_cdbmake *)map->map_db2)->fd);
+ 		free(map->map_db2);
+ 	}
+ 	else {
+ #if !LOCK_ON_OPEN
+ 	        if (map->map_lockfd >= 0)
+ 		        (void) close(map->map_lockfd);
+ #endif
+ 	        close((int)map->map_db2);
+ 	}
+ }
+ 
+ #endif
+ 
  /*
  **  NIS Modules
  */
***************
*** 4176,4181 ****
--- 4741,4750 ----
  	if (bitset(MF_IMPL_NDBM, map->map_mflags))
  		return ndbm_map_lookup(map, name, av, pstat);
  #endif
+ #ifdef CDB
+ 	if (bitset(MF_IMPL_CDB, map->map_mflags))
+ 		return cdb_map_lookup(map, name, av, pstat);
+ #endif
  	return stab_map_lookup(map, name, av, pstat);
  }
  
***************
*** 4200,4205 ****
--- 4769,4778 ----
  	if (bitset(MF_IMPL_NDBM, map->map_mflags))
  		ndbm_map_store(map, lhs, rhs);
  #endif
+ #ifdef CDB
+ 	if (bitset(MF_IMPL_CDB, map->map_mflags))
+ 		cdb_map_store(map, lhs, rhs);
+ #endif
  	stab_map_store(map, lhs, rhs);
  }
  
***************
*** 4238,4245 ****
  	else
  		map->map_mflags &= ~MF_IMPL_NDBM;
  #endif
! 
! #if defined(NEWDB) || defined(NDBM)
  	if (Verbose)
  		message("WARNING: cannot open alias database %s%s",
  			map->map_file,
--- 4811,4826 ----
  	else
  		map->map_mflags &= ~MF_IMPL_NDBM;
  #endif
! #ifdef CDB
! 	map->map_mflags |= MF_IMPL_CDB;
! 	if (cdb_map_open(map, mode)) 
! 	{
! 	        return TRUE;
! 	}
! 	else
! 	        map->map_mflags &= ~MF_IMPL_CDB;
! #endif
! #if defined(NEWDB) || defined(NDBM) || defined(CDB)
  	if (Verbose)
  		message("WARNING: cannot open alias database %s%s",
  			map->map_file,
***************
*** 4280,4285 ****
--- 4861,4874 ----
  	{
  		ndbm_map_close(map);
  		map->map_mflags &= ~MF_IMPL_NDBM;
+ 	}
+ #endif
+ 
+ #ifdef CDB
+ 	if (bitset(MF_IMPL_CDB, map->map_mflags))
+ 	{
+ 		cdb_map_close(map);
+ 		map->map_mflags &= ~MF_IMPL_CDB;
  	}
  #endif
  }
diff -N -r -c sendmail-pristine/src/sm_cdb.h sendmail-cdb/src/sm_cdb.h
*** sendmail-pristine/src/sm_cdb.h	Wed Dec 31 20:00:00 1969
--- sendmail-cdb/src/sm_cdb.h	Wed Apr 28 15:45:23 1999
***************
*** 0 ****
--- 1,17 ----
+ /*
+  * sm_cdb.h -- Structs for easier management of CDB within sendmail.
+  */
+ 
+ #ifdef CDB
+ # ifndef SM_CDB_H
+ #  define SM_CDB_H
+ #  include <uint32.h>
+ #  include <cdbmake.h>
+ #  include <cdb.h>
+ struct sm_cdbmake {
+         int fd;
+         struct cdbmake cdbm;
+         uint32 pos;
+ };
+ # endif
+ #endif


----- End forwarded message -----

-- 
Elie Rosenblum                                              elier@uu.net
Team Lead - Mail Hosting / Transport                      (703)-645-4269
UUNET Server Operations

----- End forwarded message -----

-- 
  / __  | Richard Rognlie / Sendmail Consultant / Sendmail, Inc.
 / /  \ | richard@sendmail.com     (O) 703.391.1755
 \__/ / |                          (C) 703.626.0726
     /  | *BSD and Linux:  The Ultimate Windows NT Service Packs

