Description: Upstream changes introduced in version 4.3.2-7
 This patch has been created by dpkg-source during the package build.
 Here's the last changelog entry, hopefully it gives details on why
 those changes were made:
 .
 suck (4.3.2-7) unstable; urgency=low
 .
   * debian/control add quilt in Build-depedns. New patch 01_rpost-ssl to add
     ssl support to rpost (Closes: #501343).
   * Added libperl-dev in Build-depends.
   * Fix typo in get-news rpostopts --> rpostoptions (Closes: #605272).
   * Fix read file configuration with number (Closes: #410372).
 .
 The person named in the Author field signed this changelog entry.
Author: Christian Marillat <marillat@debian.org>
Bug-Debian: http://bugs.debian.org/410372
Bug-Debian: http://bugs.debian.org/501343
Bug-Debian: http://bugs.debian.org/605272

---
The information above should follow the Patch Tagging Guidelines, please
checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here
are templates for supplementary fields that you might want to add:

Origin: <vendor|upstream|other>, <url of original patch>
Bug: <url in upstream bugtracker>
Bug-Debian: http://bugs.debian.org/<bugnumber>
Bug-Ubuntu: https://launchpad.net/bugs/<bugnumber>
Forwarded: <no|not-needed|url proving that it has been forwarded>
Reviewed-By: <name and email of someone who approved the patch>
Last-Update: <YYYY-MM-DD>

--- /dev/null
+++ suck-4.3.2/chkhistory_multi.c
@@ -0,0 +1,33 @@
+/* Select chistory version at runtime rather than compile time.
+ * ckkhistory_cnews and chkhistory_inn are alternate compilations of
+ * chkhistory_db.c
+ */
+
+#include <config.h>
+#include "suck_config.h"
+#include "suck.h"
+#include "both.h"
+
+void chhistory_other(PMaster master);
+void chhistory_cnews(PMaster master);
+void chhistory_inn(PMaster master);
+
+void chkhistory(PMaster master) {
+    if(master->debug == TRUE) {
+        do_debug("chkhistory_multi: %d\n", master->history_type);
+	do_debug("history_file: %s\n", master->history_file);
+    }
+    switch(master->history_type) {
+	case HIST_NONE:
+	    break;
+	case HIST_OTHER:
+	    chkhistory_other(master);
+	    break;
+	case HIST_CNEWS:
+	    chkhistory_cnews(master);
+	    break;
+	case HIST_INN:
+	    chkhistory_inn(master);
+	    break;
+    }
+}
--- /dev/null
+++ suck-4.3.2/cndbz.h
@@ -0,0 +1,19 @@
+/* hack by Blars to allow linking both inn2 and cnews routines */
+/* This redefines the cnews dbz routines not to conflict with libinn */
+
+#define dbzagain cn_dbzagain
+#define dbzcancel cn_dbzcancel
+#define dbzdbmclose cn_dbzdbmclose
+#define dbzdbmfetch cn_dbzdbmfetch
+#define dbzdbminit cn_dbzdbminit
+#define dbzdbmstore cn_dbzdbmstore
+#define dbzdebug cn_dbzdebug
+#define dbzfetch cn_dbzfetch
+#define dbzfiledesc cn_dbzfiledesc
+#define dbzfresh cn_dbzfresh
+#define dbzincore cn_dbzincore
+#define dbzsize cn_dbzsize
+#define dbzstore cn_dbzstore
+#define dbzsync cn_dbzsync
+#define dbztagmask cn_dbztagmask
+#define dbzwritethrough cn_dbzwritethrough
--- /dev/null
+++ suck-4.3.2/libdbz/dbz.h
@@ -0,0 +1,39 @@
+/* for dbm and dbz */
+typedef struct {
+	char *dptr;
+	int dsize;
+} datum;
+
+/* standard dbm functions */
+extern int dbminit();
+extern datum fetch();
+extern int store();
+extern int delete();		/* not in dbz */
+extern datum firstkey();	/* not in dbz */
+extern datum nextkey();		/* not in dbz */
+extern int dbmclose();		/* in dbz, but not in old dbm */
+
+/* new stuff for dbz */
+extern int dbzdbminit();
+extern datum dbzdbmfetch();
+extern int dbzdbmstore();
+extern int dbzdbmclose();
+extern int dbzfresh();
+extern int dbzagain();
+extern datum dbzfetch();
+extern int dbzstore();
+extern int dbzsync();
+extern long dbzsize();
+extern long dbztagmask();
+extern int dbzincore();
+extern int dbzwritethrough();
+extern void (*dbzfiledesc())();
+extern int dbzcancel();
+extern int dbzdebug();
+
+/*
+ * In principle we could handle unlimited-length keys by operating a chunk
+ * at a time, but it's not worth it in practice.  Setting a nice large
+ * bound on them simplifies the code and doesn't hurt anything.
+ */
+#define DBZMAXKEY	255
--- /dev/null
+++ suck-4.3.2/libdbz/makefile
@@ -0,0 +1,226 @@
+# cnews dbz makefile hacked by Blars for use with suck:
+#	remove dbzdbm
+#	don't use ../conf or ../include
+
+# =()<@<INCLUDE>@>()=
+# .include "../include/config.make"
+# make header file
+# pathname variables
+# =()<NEWSARTS=@<NEWSARTS>@>()=
+NEWSARTS=/var/spool/news
+# =()<NEWSOV=@<NEWSOV>@>()=
+NEWSOV=/var/spool/news
+# =()<NEWSBIN=@<NEWSBIN>@>()=
+NEWSBIN=/usr/lib/news
+# =()<NEWSCTL=@<NEWSCTL>@>()=
+NEWSCTL=/var/lib/news
+# =()<NEWSCONFIG=@<NEWSCONFIG>@>()=
+NEWSCONFIG=/usr/lib/news/config
+
+# workaround for System V make bug
+SHELL=/bin/sh
+
+# directories where things go
+UIBIN=/usr/lib/news
+RBIN=/usr/lib/news/input
+
+# compilation stuff
+# LIB is for makefile dependencies, LIBS for cc invocations
+LIB=../libcnews.a
+LIBS=../libcnews.a 
+MCFLAGS=$(MORECFLAGS) -O2  -DFASTSTRCHR -I.
+LDFLAGS=$(CFLAGS) -s
+LINTFLAGS=$(MORELINTFLAGS) -I.
+
+# directories etc.
+MAKE=make
+TO=$(CONF)/cpto
+IN=$(CONF)/cmpto $(CMPOPT)
+CF=$(CONF)/checkfile $(CMPOPT)
+MKDIR=$(CONF)/mkdirs
+MX=chmod +x
+# ++roman: no need for ranlib on Linux, ar s does it; and use $(AR) for
+# cross compiling 
+AR=ar
+#UPDATE=$(CONF)/update.ran ../libcnews.a
+UPDATE=$(AR) rusv ../libcnews.a
+LIBCMP=$(CONF)/libcmp ../libcnews.a
+
+# misc configuration bits
+SPACEFOR=statfs
+DOSPACEFOR=dospacefor
+QUEUELEN=tay
+UID=news
+GID=news
+SIZE=big
+DBZ=libdbz
+STDIO=sysstdio
+SERVER=
+REPORTTO=newsmaster
+URGENTTO=newscrisis
+
+# fake files needed
+HFAKE= sys/timeb.h
+OFAKE= fgetline.o fsync.o
+
+RFC=-DHAVERFCIZE
+DEBUG=-DDBZDEBUG
+
+# database sizes for performance tests, regression, and regression prime-find
+TSIZE=12007
+RSIZE=4019
+RPSIZE=2679
+
+# history files for regression and performance tests
+RHIST=hist3.3
+R2HIST=hist10
+THIST=hist13
+
+OBJS=dbz.o
+ALL=$(OBJS)
+
+u:	$(ALL)
+	$(UPDATE) $(OBJS)
+
+o:	$(OBJS)
+
+# the following is made explicit to simplify modifications on systems (mostly
+# x86 System Vs) where -O fouls up dbz.o somehow
+dbz.o:	dbz.c ../cndbz.h
+	$(CC) $(CFLAGS) $(MCFLAGS) -include "../cndbz.h" -c dbz.c
+
+t:	tdbz fake
+
+lint:
+	lint $(LINTFLAGS) dbzmain.c dbz.c
+
+rdbz tdbz fake byteflip:	$(LIB)
+
+rdbz.o:	dbz.c
+	cp dbz.c rdbz.c
+	$(CC) $(CFLAGS) $(DEBUG) -DDEFSIZE=$(RSIZE) -c rdbz.c
+	rm -f rdbz.c
+
+rdbzmain.o:	dbzmain.c
+	cp dbzmain.c rdbzmain.c
+	$(CC) $(CFLAGS) $(RFC) -c rdbzmain.c
+	rm -f rdbzmain.c
+
+tdbz.o:	dbz.c
+	cp dbz.c tdbz.c
+	$(CC) $(CFLAGS) -DDEFSIZE=$(TSIZE) -c tdbz.c
+	rm -f tdbz.c
+
+tdbz:	dbzmain.o tdbz.o dbzdbm.o
+	$(CC) $(LDFLAGS) dbzmain.o tdbz.o dbzdbm.o $(LIBS) -o $@
+
+rdbz:	rdbzmain.o rdbz.o dbzdbm.o
+	$(CC) $(LDFLAGS) rdbzmain.o rdbz.o dbzdbm.o $(LIBS) -o $@
+
+fake:	fake.o random.o
+	$(CC) $(LDFLAGS) fake.o random.o $(LIBS) -o $@
+
+byteflip:	byteflip.o
+	$(CC) $(LDFLAGS) byteflip.o $(LIBS) -o $@
+
+hist10:	fake
+	./fake -t -e 75 10000 >$@
+
+hist3.3:	fake
+	./fake -t -e 75 3300 >$@
+
+hist13:	fake
+	./fake -t -e 75 13000 >$@
+
+r:	rclean rdbz $(RHIST) $(R2HIST) byteflip getmap revbytes altbytes
+	: 'WARNING:  creates about 2MB of debris...'
+	: crude check of synthetic history file
+	( sed 25q $(RHIST) ; tail -25 $(RHIST) ) >histjunk
+	cmp histjunk firstlast25
+	rm -f histjunk
+	: basic tests, exercising as many options as possible
+	cp $(RHIST) dbase
+	mkdir xx
+	chmod -w xx
+	./rdbz -E 1000 -0 -M -i -S -u -U -C xx dbase
+	rmdir xx
+	sed '/>	0/d' $(RHIST) >dbase.used
+	test "`cat dbase.used | wc -l`" -eq "`sed -n '2s/ .*//p' dbase.dir`" ;
+	./rdbz -v dbase
+	cp $(RHIST) dbase2
+	./rdbz -E 1000 -0 -p $(RPSIZE) -t '	' dbase2
+	cmp $(RHIST) dbase
+	cmp dbase dbase2
+	cmp dbase.dir dbase2.dir
+	cmp dbase.pag dbase2.pag
+	./rdbz -E 1000 -0 -c dbase
+	./rdbz -E 1000 -0 -c -i -q -M -U dbase
+	: build a database and then add to it
+	sed 1000q $(RHIST) >dbase2
+	sed 1,1000d $(RHIST) >dbase2.add
+	./rdbz -E 1000 -0 -w dbase2
+	./rdbz -E 1000 -0 -a dbase2 dbase2.add
+	cmp dbase dbase2
+	cmp dbase.dir dbase2.dir
+	cmp dbase.pag dbase2.pag
+	: build based on existing one, test extraction and readonly files
+	./rdbz -E 1000 -0 -f dbase dbase2
+	test "`cat dbase.used | wc -l`" -eq "`awk 'NR==2{print $$1}' dbase2.dir`" ;
+	test "`cat dbase.used | wc -l`" -eq "`awk 'NR==2{print $$2}' dbase2.dir`" ;
+	chmod -w dbase2.dir dbase2.pag
+	./rdbz -E 1000 -x dbase2 dbase >dbase.temp
+	cmp dbase.used dbase.temp
+	: try some small case perversions
+	sed 's/\(@[^ 	]*\)A/\1a/' dbase >dbase.ick
+	./rdbz -E 1000 -x dbase2 dbase.ick >dbase.temp
+	cmp dbase.used dbase.temp
+	sed -n 's/A\([^ 	]*@\)/a\1/p' dbase >dbase.ick
+	./rdbz -x dbase2 dbase.ick >dbase.temp
+	test ! -s dbase.temp ;
+	rm -f dbase2.dir dbase2.pag
+	: try it without tags, case-insensitive, with case perversions
+	./rdbz -E 1000 -0 -p '0 b 1' dbase2
+	tr '[A-M][n-z]' '[a-m][N-Z]' <dbase2 >dbase.ick
+	./rdbz -E 1000 -x dbase2 dbase.ick >dbase.temp
+	cmp dbase.used dbase.temp
+	rm -f dbase.temp dbase.ick
+	: test various perversions of byte ordering
+	awk -f revbytes dbase.dir >dbase2.dir
+	chmod +x getmap
+	./byteflip `./getmap dbase.dir` `./getmap dbase2.dir` <dbase.pag >dbase2.pag
+	cp dbase dbase2
+	./rdbz -E 1000 -0 -c dbase2
+	awk -f altbytes dbase.dir >dbase2.dir
+	dd conv=swab <dbase.pag >dbase2.pag
+	./rdbz -E 1000 -0 -c dbase2
+	cp dbase2 dbase3
+	./rdbz -E 1000 -0 -f dbase2 dbase3
+	./rdbz -E 1000 -0 -c dbase3
+	test " `./getmap dbase2.dir`" = " `./getmap dbase3.dir`" ;
+	: test massive overflow, throw in case sensitivity and tag mask
+	cp $(R2HIST) dbase
+	./rdbz -E 1000 -0 -p '0 0 7ffc0000' dbase
+	./rdbz -E 1000 -0 -cq dbase
+	sed 100q dbase | egrep '[aA].*	' | tr aA Aa >dbase.ick
+	./rdbz -x dbase dbase.ick >dbase.temp
+	test ! -s dbase.temp ;
+	: check tag autoshrinking, tag size computing
+	test " `awk 'NR == 1 { print $$7 }' dbase.dir`" = " 8191" ;
+	./rdbz -E 1000 -0 -f dbase dbase
+	test " `awk 'NR == 1 { print $$7 }' dbase.dir`" = " 8190" ;
+	cp $(RHIST) dbase
+	./rdbz -E 1000 -0 -p '0 0 0' -T 1000000 dbase
+	test " `awk 'NR == 1 { print $$7 }' dbase.dir`" = " 127" ;
+	./rdbz -E 1000 -0 -p '0 0 0' -T 500000000 dbase
+	test " `awk 'NR == 1 { print $$7 }' dbase.dir`" = " 3" ;
+	: success!
+
+rclean:
+	rm -f dbase dbase[23] dbase.* dbase[23].* fake fake.o random.o
+	rm -f rdbz rdbz.o rdbzmain.? $(RHIST) $(R2HIST) byteflip byteflip.o
+	rm -f histjunk core
+	test ! -d xx || rmdir xx
+
+clean:	rclean
+	rm -f *.o dbz [a-z]dbz [a-z][a-z]dbz junk* PostScript.out
+	rm -f hist* dbase* *.bak mon.out gmon.out core dbm.h
--- /dev/null
+++ suck-4.3.2/libdbz/getmap
@@ -0,0 +1,5 @@
+awk 'NR == 1 {
+	for (i = 9; i <= NF; i++)
+		printf "%s ", $i
+	printf "\n"
+}' $*
--- /dev/null
+++ suck-4.3.2/libdbz/random.c
@@ -0,0 +1,31 @@
+/*
+ * random-number generator for testing
+ */
+static unsigned long next = 1;
+
+/*
+ - range - generate a random number within an inclusive range
+ *
+ * Algorithm from ANSI C standard.  Limitation:  max-min <= 32767.
+ */
+int
+range(min, max)
+int min;
+int max;
+{
+	register int temp;
+
+	next = next * 1103515245 + 12345;
+	temp = (int)((next/65536)%32768);
+	return(temp%(max - min + 1) + min);
+}
+
+/*
+ - seed - seed random number generator
+ */
+void
+seed(n)
+long n;
+{
+	next = (unsigned long)n;
+}
--- /dev/null
+++ suck-4.3.2/libdbz/byteflip.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+#define	MAXWORD	32
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+	register int len;
+	int inmap[MAXWORD];
+	int outmap[MAXWORD];
+	char in[MAXWORD];
+	char out[MAXWORD];
+	register int i;
+	register int a;
+
+	a = 1;
+	len = atoi(argv[a++]);
+	if (len > MAXWORD)
+		abort();	/* kind of drastic... */
+	for (i = 0; i < len; i++)
+		inmap[i] = atoi(argv[a++]);
+	if (atoi(argv[a++]) != len)
+		abort();
+	for (i = 0; i < len; i++)
+		outmap[i] = atoi(argv[a++]);
+
+	while (fread(in, 1, len, stdin) == len) {
+		for (i = 0; i < len; i++)
+			out[outmap[i]] = in[inmap[i]];
+		fwrite(out, 1, len, stdout);
+	}
+	exit(0);
+}
--- /dev/null
+++ suck-4.3.2/libdbz/dbzdbm.c
@@ -0,0 +1,45 @@
+/*
+ * dbm emulation on top of dbz
+ */
+
+#include <dbz.h>
+
+/*
+ - dbminit - open a database, creating it (using defaults) if necessary
+ */
+int 				/* 0 success, -1 failure */
+dbminit(name)
+char *name;
+{
+	return(dbzdbminit(name));
+}
+
+/*
+ - dbmclose - close a database
+ */
+int
+dbmclose()
+{
+	return(dbzdbmclose());
+}
+
+/*
+ - fetch - get an entry from the database
+ */
+datum				/* dptr NULL, dsize 0 means failure */
+fetch(key)
+datum key;
+{
+	return(dbzdbmfetch(key));
+}
+
+/*
+ - store - add an entry to the database
+ */
+int				/* 0 success, -1 failure */
+store(key, data)
+datum key;
+datum data;
+{
+	return(dbzdbmstore(key, data));
+}
--- /dev/null
+++ suck-4.3.2/libdbz/dbz.1
@@ -0,0 +1,221 @@
+.TH DBZ 1 "11 Feb 1992"
+.BY "C News"
+.SH NAME
+dbz \- operate on dbz databases of text
+.SH SYNOPSIS
+.B dbz
+[
+.BR \- { axmc }
+] [
+.B \-t
+c
+] [
+.B \-l
+length
+] [
+.BR \- { qiue }
+] [
+.B \-f
+old
+] [
+.B \-p
+parms
+] database file ...
+.SH DESCRIPTION
+.I Dbz
+is a shell-level interface to the
+.IR dbz (3z)
+database routines for indexed access to a text file.
+.PP
+The
+.I database
+file must be a text file,
+one line per database record,
+with the key the first field on the line.
+The
+.B \-t
+option sets the field-separator character; the default is tab.
+Setting the separator character to NUL (with
+.BR "\-t\ ''" )
+makes the whole line the key.
+Lines must not exceed 1023 bytes in length including the newline;
+this limit can be increased with the
+.B \-l
+option.
+The limitations and restrictions of
+.IR dbz (3z)
+must also be observed;
+in particular, it remains the user's responsibility to ensure that
+no attempt is made to store two entries (whether identical or not)
+with the same key.
+.PP
+In the absence of options,
+.I dbz
+creates a
+.IR dbz (3z)
+index for the database;
+the index comprises files
+.IB database .pag
+and
+.IB database .dir
+in the same directory.
+Any previous index is silently overwritten.
+The
+.BR \-a ,
+.BR \-x ,
+.BR \-m ,
+and
+.B \-c
+options specify other operations.
+.PP
+With
+.BR \-a ,
+.I dbz
+appends lines from the
+.IR file (s)
+(standard input if none)
+to the database, updating both the
+text file and the indexes.
+.PP
+With
+.BR \-x ,
+.I dbz
+reads keys from the
+.IR file (s)
+(standard input if none)
+and prints (on standard output) the corresponding lines, if any,
+from the database.
+The input is in the form of database lines, although only the keys are
+significant.
+The
+.B \-q
+option makes
+.B \-x
+print the input lines whose keys are found instead of the database
+lines; this is somewhat faster.
+.PP
+With
+.BR \-m ,
+operation is the same as for
+.B \-x
+except that the keys which are \fInot\fR present in the database are printed.
+.PP
+With
+.BR \-c ,
+.I dbz
+checks the database for internal consistency.
+The
+.B \-q
+option causes this check to be done more quickly but less thoroughly
+(each key is looked up in the index, but no check is made to be sure
+that the index entry points to the right place).
+.PP
+The
+.B \-i
+option suppresses the use of
+.IR dbz (3z)'s
+.I incore
+facility.
+This makes accesses slower, but keeps the files current
+during updating
+and reduces
+startup/shutdown overhead.
+.PP
+Normally,
+.I dbz
+checks whether a key is already in the database before adding it.
+The
+.B \-u
+option suppresses this check, speeding things up at the expense of safety.
+.PP
+A new index is normally created with default size,
+case mapping, and tagging.
+The default size is right for 90-100,000 records.
+The default case mapping is right for RFC822 message-ids.
+See
+.IR dbz (3z)
+for what tagging is about.
+(Note, these defaults can be changed when
+.IR dbz (3z)
+is installed.)
+.PP
+If the
+.B \-f
+option is given,
+size, case mapping, and tagging
+are instead initialized based on the
+database
+.IR old .
+This is mostly useful when
+creating a new generation of an existing database.
+(See the description of
+.I dbzagain
+in
+.IR dbz (3z)
+for details.)
+.PP
+If the
+.B \-p
+option is given, the
+.I parms
+string specifies the size, case mapping, and tagging.
+If
+.I parms
+is a single decimal number,
+that is taken as the expected number of records
+in the index, with case mapping and tagging defaulted.
+Alternatively,
+.I parms
+can be three fields\(ema decimal number, a case-mapping code character, and a
+hexadecimal tag mask\(emseparated by white space.
+The decimal number is, again, the expected number of records;
+0 means ``use the default''.
+See
+.IR dbz (3z)
+for possible choices of case-mapping code,
+but in particular,
+.B 0
+means ``no case mapping''.
+See
+.IR dbz (3z)
+for details on tag masks;
+0 means ``use the default''.
+.PP
+If the
+.B \-e
+option is given, the decimal number in
+.B \-p
+is taken to be the exact table size, not the expected number of records,
+and invocation of
+.I dbzsize
+(see
+.IR dbz (3z))
+to predict a good size for that number of records is suppressed.
+.PP
+The
+.B \&.pag
+file is normally about 6 bytes per record (based on the estimate given to
+.B \-p
+or the previous history of the
+.B \-f
+database).
+The
+.B \&.dir
+file is tiny.
+.SH SEE ALSO
+dbz(3z)
+.SH HISTORY
+Written at U of Toronto by Henry Spencer, for the C News project.
+See
+.IR dbz (3z)
+for the history of the underlying database routines.
+.SH BUGS
+There are a number of undocumented options with obscure effects,
+meant for debugging and regression testing of
+.IR dbz (3z).
+.PP
+Permissions for the index files probably ought to be taken from those
+of the base file.
+.PP
+The line-length limit is a blemish, alleviated only slightly by
+.BR \-l .
--- /dev/null
+++ suck-4.3.2/libdbz/README
@@ -0,0 +1,17 @@
+This is the new, improved, lemon-freshened :-) dbz.
+
+Just "make" will get you dbz.o and the dbz program.  "make r" runs an
+extensive set of regression tests; most of the mysterious oddments lying
+around here are to do with that.  "make rclean" cleans up after "make r".
+
+You probably want to inspect the #ifdef list early in dbz.c before
+compiling, although the defaults should work all right on most systems.
+
+If you are not building this as part of C News, you will need to change
+the -I option in FLAGS in the Makefile to "-I.", and delete the DBMLIBS
+and RFC lines entirely.  That will break some of the regression tests;
+at some point I'll fix this.
+
+If you are using this independently from C News, you probably still want
+to look through ../notebook/problems, as some of the portability problems
+described in there can affect dbz.
--- /dev/null
+++ suck-4.3.2/libdbz/firstlast25
@@ -0,0 +1,50 @@
+<m....VO1.9q.@s95e1zKsIj7LrIwa1>	600000000~-	90fz0706yo.1Env21x8b
+<H5.i.R6ZQ2@Vg6.5mqj8..z>	200000000~-
+<1Hy.ufmjqe371x5.o@HEEl0tAp4>	700000000~-
+<T6.c9.xM4i@943..7z.c..3h>	600000000~-
+<Exus7LsME4fPL9v8@2.ouu97O25z9cdft>	700000000~-
+<6kUzkf.v74@iC1iGj882RQ0zli>	400000000~-
+<J.7YT7dV.Kkul8Bh0fc@Rar.EnMx2lm0.6Yeob>	600000000~-
+<.wVJi1DX42@5.4i6.jaZ6qw9Ln1.>	500000000~-
+<uUd9e18vxzevae7uY@33a480208l0.4p2q>	300000000~-
+<43hQ.5shbE7@912400.ajES6x0sXl.M>	400000000~-
+<g25r..2r.0WOZ6k3@tb3.U9xrR.uw61a2y0>	600000000~-
+<923s5e67d5Oq085Y.1@6Pik68584>	900000000~-
+<.5.n5cx5aD62i9q8@Ai60Sc.4x>	200000000~-
+<9N9n@3.1ql87.yj2xFs.zLqI>	700000000~-	Q2.kni8kZps7kF5uiEv32B38y4z.p
+<.X.fw.6LtoT.0@pp6bp.5s6yh74.>	400000000~-
+<54c1w@7..u1.99m9T4j.BNGBiK>	600000000~-	.F3hb.OFh06V..p
+<j12Mtn6q9@m2.m1X1s>	500000000~-
+<o1WJV9G4H.zf0BX44w@W7.76xn33>	000000000~-
+<0C605s6plaAgfM.ap40@e6d66n.uv01W.j.8ph.>	100000000~-	m.x7TY8.8DQ5
+<.2.14xdn.@D0g.W.uZ.75gyyg.q1G>	100000000~-
+<.A..03.@5v..64.5v3.3tbjUo.>	500000000~-
+<72..c19ms65.WCf0G3.@83seEG9nnhM.O.j22>	900000000~-
+<D..xX.kti9@u739li.xvy2>	000000000~-	NPLL42XVfM
+<6HO.nFal1ufl3.8b@3.n0k7a.IDgNy>	700000000~-	Wv4j3Itccnh0Zp3
+<x5RjUnIpd03xBBnuN@z0puc82Q26Ou.0T6>	400000000~-	k67.hvXwv6X745R4rh2ybuFN3n.
+<62dIeg.fW92.ov375@x76mf5c6.37.v>	000000000~-
+<chdpqs.0mgZOp.@Dxl9v..94e7ar2>	900000000~-
+<.9Xr.7V91..oe5CG.hX@p5x3jos3s27R6O3yj1>	400000000~-
+<Mm6dr.231dH35ua@SE1u0za3V1M43lRn9>	100000000~-
+<JIhw2@.Qdf.8v28Tnf1M>	200000000~-
+<z4FCa.q4MF..EE0.2@W9U63e33h9w3lcFFl>	400000000~-
+<87.W3r6is4.@svVqQCBiNqz400A.qwj>	200000000~-
+<0liI7Lu0Mx435m7M99@87Xw.8j63.9.>	500000000~-
+<tRtht5M.6d0@06gj.qm3.s9>	200000000~-	e27S.BKVD70P.o
+<Jpga8@m68yvw.b4b>	200000000~-
+<.2.69hy3JT1@Aq3.r83o.9>	700000000~-
+<.W7EurYppo4fhzs.I@8651m2W7v>	700000000~-
+<3m02.@22074.a5ct2j3>	900000000~-
+<.fy9Epa@.1.kNGCNokFwB8ezo1WM>	800000000~-
+<c758d64.FS4yY7L5@43sw.kI6>	900000000~-
+<vLd0.t@.kq70oHl96ixdnXd.GVv>	100000000~-	9A6Ejq5t55I4VJ6.q1
+<d3.4@n17p4N.77N7W..7.8>	300000000~-
+<f2lv064.8@4jokk3e07>	400000000~-
+<rr7hoxA.U7.JXxnpvd@1rbMO437vHnakx>	000000000~-
+<.0p3G7novlrYz9kjI@Sx.2w.yqzerZl12781.k>	700000000~-
+<51ny.pQ7ay4@nfU2l1f0ixG09584.m>	000000000~-	38K5bhK7cr6.bg.5MlC2Fxq06Ziuw.
+<2.cau.9s@.n4Pk0Jd9g>	300000000~-
+<bEH1Bwa.662i@zm.3g.gx4.lp3>	300000000~-	c8.t4Q0.8t0.m50
+<.t13789u5AqM4m3.z0T@P17e.ypf>	200000000~-	q17z.fZ3.FyD533WthqZs8q7
+<M4r1I@Ovaev.dp>	100000000~-
--- /dev/null
+++ suck-4.3.2/libdbz/altbytes
@@ -0,0 +1,7 @@
+NR == 1 {
+	printf "%s %s %s %s %s %s %s %s %s", $1, $2, $3, $4, $5, $6, $7, $8, $9
+	for (i = 10; i <= NF; i += 2)
+		printf " %s %s", $(i+1), $i
+	printf "\n"
+}
+NR > 1 { print }
--- /dev/null
+++ suck-4.3.2/libdbz/dbzmain.c
@@ -0,0 +1,598 @@
+/*
+ * dbz - use and test dbz in various ways
+ *
+ * -Log-
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dbz.h>
+
+#ifdef FUNNYSEEKS
+#include <unistd.h>
+#else
+#define	SEEK_SET	0
+#endif
+
+#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
+
+#ifndef lint
+static char RCSid[] = "$Header$";
+#endif
+
+char *progname;
+
+char *inname = "(no file)";		/* filename for messages etc. */
+long lineno;				/* line number for messages etc. */
+
+char *base_name;
+char *pagname;
+char *dir_name;
+char *str2dup();
+FILE *base;
+
+int op = 'b';			/* what to do, default build a new table */
+char *badop = "only one of -a -x -c -m -v can be given";
+int baseinput = 1;		/* is the base file also the input? */
+
+char *from = NULL;		/* old table to use for dbzagain() */
+int omitzero = 0;		/* omit lines tagged with 0 */
+long every = 0;			/* report every n lines */
+int syncs = 0;			/* dbzsync() on each report */
+int quick = 0;			/* quick checking, not too thorough */
+int sweep = 0;			/* sweep file checking all offsets */
+int useincore = 1;		/* should we use incore facility? */
+long xxx = 0;			/* debugging variable */
+int printx = 0;			/* print xxx after all is done */
+int unique = 1;			/* before store(), check with fetch() */
+int usefresh = 0;		/* use dbzfresh? */
+long siz = 0;			/* -p size */
+char map = 'C';			/* -p map */
+long tag = 0;			/* -p tag mask */
+int exact = 0;			/* do not run dbzsize(siz) */
+int dbzint = 1;			/* use new interface? */
+char fs = '\t';			/* field separator, default tab */
+int unopen = 0;			/* make base unopenable during dbminit? */
+char *change = NULL;		/* chdir here before dbmclose */
+long tagsize = 0;		/* if non-zero, file size for tag sizing */
+int dowt = 0;			/* do writethrough? */
+
+#define	DEFBUF	1024		/* default line-buffer size */
+int buflen = DEFBUF;		/* line length limit */
+char lbuf[DEFBUF];
+char *line = lbuf;
+char cbuf[DEFBUF];
+char *cmp = cbuf;
+
+void fail();
+void dofile();
+void runs();
+void dosweep();
+void verify();
+void mkfiles();
+void crfile();
+void doline();
+void process();
+datum dofetch();
+int dostore();
+
+#ifdef HAVERFCIZE
+extern char *rfc822ize();
+#else
+#define	rfc822ize(n)	(n)
+#endif
+
+/*
+ - main - parse arguments and handle options
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+	int c;
+	int errflg = 0;
+	extern int optind;
+	extern char *optarg;
+	int doruns = 0;
+
+	progname = argv[0];
+
+	while ((c = getopt(argc, argv, "axcmvt:l:R0E:SqOiX:Yuf:p:eMUC:T:wd")) != EOF)
+		switch (c) {
+		case 'a':	/* append to existing table */
+			if (op != 'b')
+				fail(badop, "");
+			op = 'a';
+			baseinput = 0;
+			break;
+		case 'x':	/* extract from existing table */
+			if (op != 'b')
+				fail(badop, "");
+			op = 'x';
+			baseinput = 0;
+			break;
+		case 'c':	/* check existing table */
+			if (op != 'b')
+				fail(badop, "");
+			op = 'c';
+			break;
+		case 'm':	/* extract missing (complement of -x) */
+			if (op != 'b')
+				fail(badop, "");
+			op = 'm';
+			baseinput = 0;
+			break;
+		case 'v':	/* verify that this is a dbz file */
+			if (op != 'b')
+				fail(badop, "");
+			op = 'v';
+			break;
+		case 't':	/* set field separator */
+			if (strlen(optarg) > (size_t)1)
+				fail("only one field separator allowed", "");
+			fs = *optarg;
+			break;
+		case 'l':	/* override line-length limit */
+			buflen = atoi(optarg) + 1;
+			if (buflen <= 2)
+				fail("bad -l value `%s'", optarg);
+			line = malloc(buflen);
+			cmp = malloc(buflen);
+			if (line == NULL || cmp == NULL)
+				fail("cannot allocate %s-byte buffers", optarg);
+			break;
+		case 'R':	/* print run statistics */
+			doruns = 1;
+			break;
+		case '0':	/* omit lines tagged (by fake -t) with 0 */
+			omitzero = 1;
+			break;
+		case 'E':	/* report every n items */
+			every = atol(optarg);
+			break;
+		case 'S':	/* dbzsync() on each -E report */
+			syncs = 1;
+			break;
+		case 'q':	/* quick check or extract */
+			quick = 1;
+			break;
+		case 'O':	/* sweep file checking all offsets */
+			sweep = 1;
+			break;
+		case 'i':	/* don't use incore */
+			useincore = 0;
+			break;
+		case 'X':	/* set xxx */
+			xxx = atoi(optarg);
+			break;
+		case 'Y':	/* print xxx afterward */
+			printx = 1;
+			break;
+		case 'u':	/* don't check uniqueness */
+			unique = 0;
+			break;
+		case 'f':	/* init from existing table's parameters */
+			from = optarg;
+			break;
+		case 'p':	/* parameters for dbzfresh */
+			if (sscanf(optarg, "%ld %1s %lx", &siz, &map, &tag) != 3) {
+				map = '?';
+				tag = 0;
+				if (sscanf(optarg, "%ld", &siz) != 1)
+					fail("bad -n value `%s'", optarg);
+			}
+			usefresh = 1;
+			break;
+		case 'e':	/* -p size is exact, don't dbzsize() it */
+			exact = 1;
+			break;
+		case 'M':	/* use old dbm interface + rfc822ize */
+			dbzint = 0;
+			break;
+		case 'U':	/* make base unopenable during init */
+			unopen = 1;
+			break;
+		case 'C':	/* change directories before dbmclose */
+			change = optarg;
+			break;
+		case 'd':	/* Debugging. */
+			if (dbzdebug(1) < 0)
+				fail("dbz debugging not available", "");
+			break;
+		case 'T':	/* file size for tag sizing */
+			tagsize = atol(optarg);
+			break;
+		case 'w':	/* do writethrough */
+			dowt = 1;
+			break;
+		case '?':
+		default:
+			errflg++;
+			break;
+		}
+	if (errflg || optind >= argc || (optind+1 < argc && baseinput)) {
+		fprintf(stderr, "usage: %s ", progname);
+		fprintf(stderr, "[-{axcmv}] database [file] ...\n");
+		exit(2);
+	}
+
+	(void) dbzincore(useincore);
+	(void) dbzwritethrough(dowt);
+	base_name = argv[optind];
+	pagname = str2dup(base_name, ".pag");
+	dir_name = str2dup(base_name, ".dir");
+
+	if (op == 'v') {
+		verify(dir_name);
+		/* NOTREACHED */
+	}
+
+	mkfiles();
+	optind++;
+
+	if (baseinput)		/* implies no further arguments */
+		process(base, base_name);
+	else if (optind >= argc)
+		process(stdin, "stdin");
+	else
+		for (; optind < argc; optind++)
+			dofile(argv[optind]);
+
+	if (change != NULL)
+		(void) chdir(change);
+	if (dbmclose() < 0)
+		fail("dbmclose failed", "");
+	if (doruns)
+		runs(pagname);
+	if (sweep)
+		dosweep(base_name, pagname);
+	if (printx)
+		printf("%ld\n", xxx);
+	exit(0);
+}
+
+/*
+ - verify - just check whether the .dir file looks right or not
+ */
+void				/* does not return */
+verify(dir)
+char *dir;
+{
+	FILE *f;
+	char buf[4];
+	size_t n;
+
+	f = fopen(dir, "r");
+	if (f == NULL)
+		exit(1);
+	n = fread(buf, sizeof(buf), 1, f);
+	(void) fclose(f);
+
+	if (n != 1 || memcmp(buf, "dbz ", (size_t)4) != 0)
+		exit(1);
+
+	exit(0);
+	/* NOTREACHED */
+}
+
+/*
+ - dofile - open a file and invoke process()
+ */
+void
+dofile(name)
+char *name;
+{
+	register FILE *in;
+
+	if (STREQ(name, "-"))
+		process(stdin, "-");
+	else {
+		in = fopen(name, "r");
+		if (in == NULL)
+			fail("cannot open `%s'", name);
+		process(in, name);
+		(void) fclose(in);
+	}
+}
+
+/*
+ - mkfiles - create empty files and open them up
+ */
+void
+mkfiles()
+{
+	if (op == 'b' && !dbzint) {
+		crfile(dir_name);
+		crfile(pagname);
+	}
+
+	base = fopen(base_name, (op == 'a') ? "a" : "r");
+	if (base == NULL)
+		fail("cannot open `%s'", base_name);
+	if (unopen)
+		(void) chmod(base_name, 0);
+	if (from != NULL) {
+		if (dbzagain(base_name, from) < 0)
+			fail("dbzagain(`%s'...) failed", base_name);
+	} else if (op == 'b' && dbzint) {
+		if (!exact)
+			siz = dbzsize(siz);
+		if (tagsize != 0)
+			tag = dbztagmask(tagsize);
+		if (dbzfresh(base_name, siz, (int)fs, map, tag) < 0)
+			fail("dbzfresh(`%s'...) failed", base_name);
+	} else if (dbminit(base_name) < 0)
+		fail("dbminit(`%s') failed", base_name);
+	if (unopen)
+		(void) chmod(base_name, 0600);	/* hard to restore original */
+}
+
+/*
+ - crfile - create a file
+ */
+void
+crfile(name)
+char *name;
+{
+	register int f;
+
+	f = creat(name, 0666);
+	if (f < 0)
+		fail("cannot create `%s'", name);
+	(void) close(f);
+}
+
+/*
+ - process - process input file
+ */
+void
+process(in, name)
+FILE *in;
+char *name;
+{
+	register long place;
+
+	inname = name;
+	lineno = 0;
+
+	for (;;) {
+		place = ftell(in);
+		if (fgets(line, buflen, in) == NULL)
+			return;
+		lineno++;
+		if (every > 0 && lineno%every == 0) {
+			fprintf(stderr, "%ld\n", lineno);
+			if (dbzsync() < 0)
+				fail("dbzsync failed", "");
+		}
+		doline(line, place);
+	}
+	/* NOTREACHED */
+}
+
+/*
+ - doline - process input line
+ */
+void
+doline(lp, inoffset)
+char *lp;
+long inoffset;
+{
+	register char *p;
+	register char pc;
+	datum key, value;
+	long place = inoffset;
+	register int shouldfind;
+	register int llen;
+	char keytext[DBZMAXKEY+1];
+
+	p = NULL;
+	if (fs != '\0')
+		p = strchr(lp, fs);
+	if (p == NULL)
+		p = lp + strlen(lp);
+	if (p > lp && *(p-1) == '\n')
+		p--;
+	if (p - lp > DBZMAXKEY)
+		fail("key of `%s' too long", lp);
+	pc = *p;
+	*p = '\0';
+	(void) strcpy(keytext, lp);
+	*p = pc;
+	key.dptr = (dbzint) ? keytext : rfc822ize(keytext);
+	key.dsize = strlen(keytext)+1;
+
+	switch (op) {
+	case 'a':
+		place = ftell(base);
+		llen = strlen(lp);
+		if (fwrite(lp, 1, llen, base) != llen)
+			fail("write error in `%s'", base_name);
+		/* FALLTHROUGH */
+	case 'b':
+		if (omitzero && p != NULL && *(p+1) == '0')
+			return;
+		if (unique) {
+			value = dofetch(key);
+			if (value.dptr != NULL)
+				fail("`%s' already present", lp);
+		}
+		value.dptr = (char *)&place;
+		value.dsize = (int)sizeof(place);
+		if (dostore(key, value) < 0)
+			fail("store failed on `%s'", lp);
+		break;
+	case 'c':
+		value = dofetch(key);
+		shouldfind = (omitzero && p != NULL && *(p+1) == '0') ? 0 : 1;
+		if (!shouldfind && (value.dptr != NULL || value.dsize != 0))
+			fail("`%s' found, shouldn't be", lp);
+		if (shouldfind && (value.dptr == NULL ||
+					value.dsize != sizeof(place)))
+			fail("can't find `%s'", lp);
+		if (shouldfind && !quick) {
+			(void) memcpy((char *)&place, value.dptr, sizeof(place));
+			if (place != inoffset)
+				fail("offset mismatch on `%s'", lp);
+			if (fseek(base, place, SEEK_SET) != 0)
+				fail("fseek failed on `%s'", lp);
+			if (fgets(cmp, buflen, base) == NULL)
+				fail("can't read line for `%s'", lp);
+			if (!STREQ(lp, cmp))
+				fail("compare failed on `%s'", lp);
+		}
+		break;
+	case 'x':
+		value = dofetch(key);
+		if (value.dptr != NULL && !quick) {
+			(void) memcpy((char *)&place, value.dptr, sizeof(place));
+			if (fseek(base, place, SEEK_SET) != 0)
+				fail("fseek failed on `%s'", lp);
+			if (fgets(cmp, buflen, base) == NULL)
+				fail("can't read line for `%s'", lp);
+			fputs(cmp, stdout);
+		} else if (value.dptr != NULL)
+			fputs(lp, stdout);
+		break;
+	case 'm':
+		value = dofetch(key);
+		if (value.dptr == NULL) {
+			fputs(keytext, stdout);
+			putchar('\n');
+		}
+		break;
+	default:
+		fail("unknown operator -- can't happen", "");
+		break;
+	}
+}
+
+/*
+ - runs - print run statistics
+ */
+void
+runs(file)
+char *file;
+{
+	register FILE *fd;
+	long it;
+	register long run;
+
+	fd = fopen(file, "r");
+	if (fd == NULL)
+		fail("cannot reopen `%s'", file);
+	run = 0;
+	while (fread((char *)&it, sizeof(it), 1, fd) == 1) {
+		if (it != 0)
+			run++;
+		else if (run > 0) {
+			printf("%ld\n", run);
+			run = 0;
+		}
+	}
+	(void) fclose(fd);
+}
+
+/*
+ - dosweep - sweep pag file checking for valid offsets
+ */
+void
+dosweep(fn, pn)
+char *fn;
+char *pn;
+{
+	register FILE *pf;
+	long it;
+	char nl;
+	register FILE *hf;
+
+	hf = fopen(fn, "r");
+	if (hf == NULL)
+		fail("cannot reopen `%s'", fn);
+	pf = fopen(pn, "r");
+	if (pf == NULL)
+		fail("cannot reopen `%s'", pn);
+	while (fread((char *)&it, sizeof(it), 1, pf) == 1) {
+		it = (it & 0x80000000) ? (it&~0xf8000000) : it;
+		if (it != 0 && it != 1) {	/* 0 empty, 1 known okay */
+			it--;		/* get rid of bias */
+			(void) fseek(hf, it-1, SEEK_SET);
+			nl = getc(hf);
+			if (nl != '\n')
+				fprintf(stderr, "offset 0%lo does not point to line\n",
+								(long)it);
+		}
+	}
+	(void) fclose(hf);
+	(void) fclose(pf);
+}
+
+/*
+ - fail - complain and die
+ */
+void
+fail(s1, s2)
+char *s1;
+char *s2;
+{
+#	define	MAXS2	50
+	char s2buf[MAXS2+10];
+
+	fprintf(stderr, "%s: (file `%s', line %ld) ", progname, inname, lineno);
+	if (strlen(s2) <= (size_t)MAXS2)
+		fprintf(stderr, s1, s2);
+	else {
+		sprintf(s2buf, "%.*s...", MAXS2, s2);
+		fprintf(stderr, s1, s2buf);
+	}
+	fprintf(stderr, "\n");
+	exit(1);
+}
+
+/*
+ - str2dup - concatenate strings and malloc result
+ */
+char *
+str2dup(s1, s2)
+char *s1;
+char *s2;
+{
+	register char *p;
+
+	p = malloc((size_t)strlen(s1) + strlen(s2) + 1);
+	if (p == NULL)
+		fail("can't allocate space for strings", "");
+	(void) strcpy(p, s1);
+	(void) strcat(p, s2);
+	return(p);
+}
+
+/*
+ - dofetch - do a fetch or dbzfetch
+ */
+datum
+dofetch(key)
+datum key;
+{
+	if (dbzint)
+		return(dbzfetch(key));
+	else
+		return(fetch(key));
+}
+
+/*
+ - dostore - do a store or dbzstore
+ */
+int
+dostore(key, value)
+datum key;
+datum value;
+{
+	if (dbzint)
+		return(dbzstore(key, value));
+	else
+		return(store(key, value));
+}
--- /dev/null
+++ suck-4.3.2/libdbz/revbytes
@@ -0,0 +1,7 @@
+NR == 1 {
+	printf "%s %s %s %s %s %s %s %s %s", $1, $2, $3, $4, $5, $6, $7, $8, $9
+	for (i = NF; i > 9; i--)
+		printf " %s", $i
+	printf "\n"
+}
+NR > 1 { print }
--- /dev/null
+++ suck-4.3.2/libdbz/fake.c
@@ -0,0 +1,140 @@
+/*
+ * fake - make up random lines resembling history-file entries, reproducibly
+ *
+ * -Log-
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define	MAXSTR	500		/* For sizing strings -- DON'T use BUFSIZ! */
+#define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
+
+#ifndef lint
+static char RCSid[] = "$Header$";
+#endif
+
+int midonly = 0;		/* just message ids, rest not realistic */
+int tag = 0;			/* tag lines with random digit for later use */
+int expired = -1;		/* percentage of lines to be expired */
+
+int debug = 0;
+char *progname;
+
+char *inname;				/* filename for messages etc. */
+long lineno;				/* line number for messages etc. */
+
+void doline();
+void addchars();
+void seed();
+
+/*
+ - main - parse arguments and handle options
+ */
+main(argc, argv)
+int argc;
+char *argv[];
+{
+	int c;
+	int errflg = 0;
+	FILE *in;
+	struct stat statbuf;
+	extern int optind;
+	extern char *optarg;
+	void process();
+	register long no;
+	char line[MAXSTR];
+
+	progname = argv[0];
+
+	while ((c = getopt(argc, argv, "ms:te:d")) != EOF)
+		switch (c) {
+		case 'm':	/* message-ids only */
+			midonly = 1;
+			break;
+		case 's':	/* seed */
+			seed(atol(optarg));
+			break;
+		case 't':	/* tag lines with a random digit */
+			tag = 1;
+			break;
+		case 'e':	/* percentage to be expired */
+			expired = atoi(optarg);
+			break;
+		case 'd':	/* Debugging. */
+			debug++;
+			break;
+		case '?':
+		default:
+			errflg++;
+			break;
+		}
+	if (errflg || optind != argc - 1) {
+		fprintf(stderr, "usage: %s ", progname);
+		fprintf(stderr, "[-m] [-s seed] length\n");
+		exit(2);
+	}
+
+	for (no = atol(argv[optind]); no > 0; no--) {
+		doline(line);
+		puts(line);
+	}
+	exit(0);
+}
+
+/*
+ - doline - generate random history pseudo-line
+ */
+void
+doline(buf)
+char *buf;
+{
+	char tagch[2];
+
+	(void) strcpy(buf, "<");
+	addchars(buf, range(4, 20));
+	(void) strcat(buf, "@");
+	addchars(buf, range(8, 20));
+	if (midonly)
+		(void) strcat(buf, ">\tx");
+	else {
+		if (tag) {
+			tagch[0] = "1234567890"[range(0,9)];
+			tagch[1] = '\0';
+			(void) strcat(buf, ">\t");
+			(void) strcat(buf, tagch);
+			(void) strcat(buf, "00000000~-");
+		} else
+			(void) strcat(buf, ">\t1234567890~-");
+	}
+	if (range(1, 100) > expired) {
+		if (midonly)
+			(void) strcat(buf, "\tx");
+		else {
+			(void) strcat(buf, "\t");
+			addchars(buf, range(10, 30));
+		}
+	}
+}
+
+/*
+ - addchars - generate n random characters suitable for history file
+ */
+void
+addchars(buf, len)
+char *buf;
+int len;
+{
+	register int i;
+	register char *p = buf + strlen(buf);
+	static char vocab[] = "1234567890.abcde.fghij.klmno.pqrst.uvwxyz.\
+1234567890.ABCDE.FGHIJ.KLMNO.PQRST.UVWXYZ.1234567890.\
+1234567890.abcde.fghij.klmno.pqrst.uvwxyz.1234567890";
+
+	for (i = len; i > 0; i--)
+		*p++ = vocab[range(0, sizeof(vocab)-2)];
+	*p++ = '\0';
+}
--- /dev/null
+++ suck-4.3.2/libdbz/dbz.3z
@@ -0,0 +1,547 @@
+.TH DBZ 3Z "3 Feb 1991"
+.BY "C News"
+.SH NAME
+dbminit, fetch, store, dbmclose \- somewhat dbm-compatible database routines
+.br
+dbzfresh, dbzagain, dbzfetch, dbzstore \- database routines
+.br
+dbzsync, dbzsize, dbzincore, dbzcancel, dbzdebug \- database routines
+.SH SYNOPSIS
+.nf
+.B #include <dbz.h>
+.PP
+.B dbminit(base)
+.B char *base;
+.PP
+.B datum
+.B fetch(key)
+.B datum key;
+.PP
+.B store(key, value)
+.B datum key;
+.B datum value;
+.PP
+.B dbmclose()
+.PP
+.B dbzfresh(base, size, fieldsep, cmap, tagmask)
+.B char *base;
+.B long size;
+.B int fieldsep;
+.B int cmap;
+.B long tagmask;
+.PP
+.B dbzagain(base, oldbase)
+.B char *base;
+.B char *oldbase;
+.PP
+.B datum
+.B dbzfetch(key)
+.B datum key;
+.PP
+.B dbzstore(key, value)
+.B datum key;
+.B datum value;
+.PP
+.B dbzsync()
+.PP
+.B long
+.B dbzsize(nentries)
+.B long nentries;
+.PP
+.B dbzincore(newvalue)
+.PP
+.B dbzcancel()
+.PP
+.B dbzdebug(newvalue)
+.SH DESCRIPTION
+These functions provide an indexing system for rapid random access to a
+text file (the
+.I base 
+.IR file ).
+Subject to certain constraints, they are call-compatible with
+.IR dbm (3),
+although they also provide some extensions.
+(Note that they are
+.I not
+file-compatible with
+.I dbm
+or any variant thereof.)
+.PP
+In principle,
+.I dbz
+stores key-value pairs, where both key and value are arbitrary sequences
+of bytes, specified to the functions by
+values of type
+.IR datum ,
+typedefed in the header file to be a structure with members
+.I dptr
+(a value of type
+.I char *
+pointing to the bytes)
+and
+.I dsize
+(a value of type
+.I int
+indicating how long the byte sequence is).
+.PP
+In practice,
+.I dbz
+is more restricted than
+.IR dbm .
+A
+.I dbz
+database
+must be an index into a base file,
+with the database
+.IR value s
+being
+.IR fseek (3)
+offsets into the base file.
+Each such
+.I value
+must ``point to'' a place in the base file where the corresponding
+.I key
+sequence is found.
+A key can be no longer than
+.SM DBZMAXKEY
+(a constant defined in the header file) bytes.
+No key can be an initial subsequence of another,
+which in most applications requires that keys be
+either bracketed or terminated in some way (see the
+discussion of the
+.I fieldsep
+parameter of
+.IR dbzfresh ,
+below,
+for a fine point on terminators).
+.PP
+.I Dbminit
+opens a database,
+an index into the base file
+.IR base ,
+consisting of files
+.IB base .dir
+and
+.IB base .pag
+which must already exist.
+(If the database is new, they should be zero-length files.)
+Subsequent accesses go to that database until
+.I dbmclose
+is called to close the database.
+The base file need not exist at the time of the
+.IR dbminit ,
+but it must exist before accesses are attempted.
+.PP
+.I Fetch
+searches the database for the specified
+.IR key ,
+returning the corresponding
+.IR value
+if any.
+.I Store
+stores the
+.IR key - value
+pair in the database.
+.I Store
+will fail unless the database files are writeable.
+See below for a complication arising from case mapping.
+.PP
+.I Dbzfresh
+is a variant of
+.I dbminit
+for creating a new database with more control over details.
+Unlike for
+.IR dbminit ,
+the database files need not exist:
+they will be created if necessary,
+and truncated in any case.
+.PP
+.IR Dbzfresh 's
+.I size
+parameter specifies the size of the first hash table within the database,
+in key-value pairs.
+Performance will be best if
+.I size
+is a prime number and
+the number of key-value pairs stored in the database does not exceed
+about 2/3 of
+.IR size .
+(The
+.I dbzsize
+function, given the expected number of key-value pairs,
+will suggest a database size that meets these criteria.)
+Assuming that an
+.I fseek
+offset is 4 bytes,
+the
+.B .pag
+file will be
+.RI 4* size
+bytes
+(the
+.B .dir
+file is tiny and roughly constant in size)
+until
+the number of key-value pairs exceeds about 80% of
+.IR size .
+(Nothing awful will happen if the database grows beyond 100% of
+.IR size ,
+but accesses will slow down somewhat and the
+.B .pag
+file will grow somewhat.)
+.PP
+.IR Dbzfresh 's
+.I fieldsep
+parameter specifies the field separator in the base file.
+If this is not
+NUL (0), and the last character of a
+.I key
+argument is NUL, that NUL compares equal to either a NUL or a
+.I fieldsep
+in the base file.
+This permits use of NUL to terminate key strings without requiring that
+NULs appear in the base file.
+The
+.I fieldsep
+of a database created with
+.I dbminit
+is the horizontal-tab character.
+.PP
+For use in news systems, various forms of case mapping (e.g. uppercase to
+lowercase) in keys are available.
+The
+.I cmap
+parameter to
+.I dbzfresh
+is a single character specifying which of several mapping algorithms to use.
+Available algorithms are:
+.RS
+.TP
+.B 0
+case-sensitive:  no case mapping
+.TP
+.B B
+same as
+.B 0
+.TP
+.B NUL
+same as
+.B 0
+.TP
+.B =
+case-insensitive:  uppercase and lowercase equivalent
+.TP
+.B b
+same as
+.B =
+.TP
+.B C
+RFC822 message-ID rules, case-sensitive before `@' (with certain exceptions)
+and case-insensitive after
+.TP
+.B ?
+whatever the local default is, normally
+.B C
+.RE
+.PP
+Mapping algorithm
+.B 0
+(no mapping) is faster than the others and is overwhelmingly the correct
+choice for most applications.
+Unless compatibility constraints interfere, it is more efficient to pre-map
+the keys, storing mapped keys in the base file, than to have
+.I dbz
+do the mapping on every search.
+.PP
+For historical reasons,
+.I fetch
+and
+.I store
+expect their
+.I key
+arguments to be pre-mapped, but expect unmapped keys in the base file.
+.I Dbzfetch
+and
+.I dbzstore
+do the same jobs but handle all case mapping internally,
+so the customer need not worry about it.
+.PP
+.I Dbz
+stores only the database
+.IR value s
+in its files, relying on reference to the base file to confirm a hit on a key.
+References to the base file can be minimized, greatly speeding up searches,
+if a little bit of information about the keys can be stored in the
+.I dbz
+files.
+This is ``free'' if there are some unused bits in an
+.I fseek
+offset,
+so that the offset can be
+.I tagged
+with some information about the key.
+The
+.I tagmask
+parameter of
+.I dbzfresh
+allows specifying the location of unused bits.
+.I Tagmask
+should be a mask with
+one group of
+contiguous
+.B 1
+bits.
+The bits in the mask should
+be unused (0) in
+.I most
+offsets.
+The bit immediately above the mask (the
+.I flag
+bit) should be unused (0) in
+.I all
+offsets;
+.I (dbz)store
+will reject attempts to store a key-value pair in which the
+.I value
+has the flag bit on.
+Apart from this restriction, tagging is invisible to the user.
+As a special case, a
+.I tagmask
+of 1 means ``no tagging'', for use with enormous base files or
+on systems with unusual offset representations.
+.PP
+A
+.I size
+of 0
+given to
+.I dbzfresh
+is synonymous with the local default;
+the normal default is suitable for tables of 90-100,000
+key-value pairs.
+A
+.I cmap
+of 0 (NUL) is synonymous with the character
+.BR 0 ,
+signifying no case mapping
+(note that the character
+.B ?
+specifies the local default mapping,
+normally
+.BR C ).
+A
+.I tagmask
+of 0 is synonymous with the local default tag mask,
+normally 0x7f000000 (specifying the top bit in a 32-bit offset
+as the flag bit, and the next 7 bits as the mask,
+which is suitable for base files up to circa 24MB).
+Calling
+.I dbminit(name)
+with the database files empty is equivalent to calling
+.IR dbzfresh(name,0,'\et','?',0) .
+.PP
+When databases are regenerated periodically, as in news,
+it is simplest to pick the parameters for a new database based on the old one.
+This also permits some memory of past sizes of the old database, so that
+a new database size can be chosen to cover expected fluctuations.
+.I Dbzagain
+is a variant of
+.I dbminit
+for creating a new database as a new generation of an old database.
+The database files for
+.I oldbase
+must exist.
+.I Dbzagain
+is equivalent to calling
+.I dbzfresh
+with the same field separator, case mapping, and tag mask as the old database,
+and a
+.I size
+equal to the result of applying
+.I dbzsize
+to the largest number of entries in the
+.I oldbase
+database and its previous 10 generations.
+.PP
+When many accesses are being done by the same program,
+.I dbz
+is massively faster if its first hash table is in memory.
+If an internal flag is 1,
+an attempt is made to read the table in when
+the database is opened, and
+.I dbmclose
+writes it out to disk again (if it was read successfully and
+has been modified).
+.I Dbzincore
+sets the flag to
+.I newvalue
+(which should be 0 or 1)
+and returns the previous value;
+this does not affect the status of a database that has already been opened.
+The default is 0.
+The attempt to read the table in may fail due to memory shortage;
+in this case
+.I dbz
+quietly falls back on its default behavior.
+.IR Store s
+to an in-memory database are not (in general) written out to the file
+until
+.IR dbmclose
+or
+.IR dbzsync ,
+so if robustness in the presence of crashes
+or concurrent accesses
+is crucial, in-memory databases
+should probably be avoided.
+.PP
+.I Dbzsync
+causes all buffers etc. to be flushed out to the files.
+It is typically used as a precaution against crashes or concurrent accesses
+when a
+.IR dbz -using
+process will be running for a long time.
+It is a somewhat expensive operation,
+especially
+for an in-memory database.
+.PP
+.I Dbzcancel
+cancels any pending writes from buffers.
+This is typically useful only for in-core databases, since writes are
+otherwise done immediately.
+Its main purpose is to let a child process, in the wake of a
+.IR fork ,
+do a
+.I dbmclose
+without writing its parent's data to disk.
+.PP
+If
+.I dbz
+has been compiled with debugging facilities available (which makes it
+bigger and a bit slower),
+.I dbzdebug
+alters the value (and returns the previous value) of an internal flag
+which (when 1; default is 0) causes
+verbose and cryptic debugging output on standard output.
+.PP
+Concurrent reading of databases is fairly safe,
+but there is no (inter)locking,
+so concurrent updating is not.
+.PP
+The database files include a record of the byte order of the processor
+creating the database, and accesses by processors with different byte
+order will work, although they will be slightly slower.
+Byte order is preserved by
+.IR dbzagain .
+However,
+agreement on the size and internal structure of an
+.I fseek
+offset is necessary, as is consensus on
+the character set.
+.PP
+An open database occupies three
+.I stdio
+streams and their corresponding file descriptors;
+a fourth is needed for an in-memory database.
+Memory consumption is negligible (except for
+.I stdio
+buffers) except for in-memory databases.
+.SH SEE ALSO
+dbz(1), dbm(3)
+.SH DIAGNOSTICS
+Functions returning
+.I int
+values return 0 for success, \-1 for failure.
+Functions returning
+.I datum
+values return a value with
+.I dptr
+set to NULL for failure.
+.I Dbminit
+attempts to have
+.I errno
+set plausibly on return, but otherwise this is not guaranteed.
+An
+.I errno
+of
+.B EDOM
+from
+.I dbminit
+indicates that the database did not appear to be in
+.I dbz
+format.
+.SH HISTORY
+The original
+.I dbz
+was written by
+Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us).
+Later contributions by David Butler and Mark Moraes.
+Extensive reworking,
+including this documentation,
+by Henry Spencer (henry@zoo.toronto.edu) as
+part of the C News project.
+Hashing function by Peter Honeyman.
+.SH BUGS
+The
+.I dptr
+members of returned
+.I datum
+values point to static storage which is overwritten by later calls.
+.PP
+Unlike
+.IR dbm ,
+.I dbz
+will misbehave if an existing key-value pair is `overwritten' by
+a new
+.I (dbz)store
+with the same key.
+The user is responsible for avoiding this by using
+.I (dbz)fetch
+first to check for duplicates;
+an internal optimization remembers the result of the
+first search so there is minimal overhead in this.
+.PP
+Waiting until after
+.I dbminit
+to bring the base file into existence
+will fail if
+.IR chdir (2)
+has been used meanwhile.
+.PP
+The RFC822 case mapper implements only a first approximation to the
+hideously-complex RFC822 case rules.
+.PP
+The prime finder in
+.I dbzsize
+is not particularly quick.
+.PP
+Should implement the
+.I dbm
+functions
+.IR delete ,
+.IR firstkey ,
+and
+.IR nextkey .
+.PP
+On C implementations which trap integer overflow,
+.I dbz
+will refuse to
+.I (dbz)store
+an
+.I fseek
+offset equal to the greatest
+representable
+positive number,
+as this would cause overflow in the biased representation used.
+.PP
+.I Dbzagain
+perhaps ought to notice when many offsets
+in the old database were
+too big for
+tagging, and shrink the tag mask to match.
+.PP
+Marking
+.IR dbz 's
+file descriptors
+.RI close-on- exec
+would be a better approach to the problem
+.I dbzcancel
+tries to address, but that's harder to do portably.
--- /dev/null
+++ suck-4.3.2/libdbz/dbz.c
@@ -0,0 +1,1898 @@
+/*
+
+dbz.c  V3.4
+
+Copyright 1988 Jon Zeeff (zeeff@b-tech.ann-arbor.mi.us)
+You can use this code in any manner, as long as you leave my name on it
+and don't hold me responsible for any problems with it.
+
+Hacked on by gdb@ninja.UUCP (David Butler); Sun Jun  5 00:27:08 CDT 1988
+
+Various improvments + INCORE by moraes@ai.toronto.edu (Mark Moraes)
+
+Major reworking by Henry Spencer as part of the C News project.
+
+These routines replace dbm as used by the usenet news software
+(it's not a full dbm replacement by any means).  It's fast and
+simple.  It contains no AT&T code.
+
+In general, dbz's files are 1/20 the size of dbm's.  Lookup performance
+is somewhat better, while file creation is spectacularly faster, especially
+if the incore facility is used.
+
+If you are seized by the urge to hack mmap() calls into this stuff, please
+try to resist it.  Instead, spend that energy beating on your system supplier
+to fix his read() and write() calls to exploit the same memory-mapping
+tricks mmap() uses.  That way, all kinds of software can get more efficient
+*without* having non-portable grunge like mmap() hacked into it.
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#ifndef __STDC__
+extern int errno;
+#endif
+
+
+#include <dbz.h>
+
+/*
+ * #ifdef index.  "LIA" = "leave it alone unless you know what you're doing".
+ *
+ * FUNNYSEEKS	SEEK_SET is not 0, get it from <unistd.h>
+ * INDEX_SIZE	backward compatibility with old dbz; avoid using this
+ * NMEMORY	number of days of memory for use in sizing new table (LIA)
+ * INCORE	backward compatibility with old dbz; use dbzincore() instead
+ * DBZDEBUG	enable debugging
+ * DEFSIZE	default table size (not as critical as in old dbz)
+ * OLDBNEWS	default case mapping as in old B News; set NOBUFFER
+ * BNEWS	default case mapping as in current B News; set NOBUFFER
+ * DEFCASE	default case-map algorithm selector
+ * NOTAGS	fseek offsets are strange, do not do tagging (see below)
+ * NPAGBUF	size of .pag buffer, in longs (LIA)
+ * SHISTBUF	size of ASCII-file buffer, in bytes (LIA)
+ * MAXRUN	length of run which shifts to next table (see below) (LIA)
+ * OVERFLOW	long-int arithmetic overflow must be avoided, will trap
+ * NOBUFFER	do not buffer hash-table i/o, B News locking is defective
+ */
+
+#ifdef FUNNYSEEKS
+#include <unistd.h>
+#else
+#define	SEEK_SET	0
+#endif
+#ifdef OVERFLOW
+#include <limits.h>
+#endif
+
+static int dbzversion = 3;	/* for validating .dir file format */
+
+/*
+ * The dbz database exploits the fact that when news stores a <key,value>
+ * tuple, the `value' part is a seek offset into a text file, pointing to
+ * a copy of the `key' part.  This avoids the need to store a copy of
+ * the key in the dbz files.  However, the text file *must* exist and be
+ * consistent with the dbz files, or things will fail.
+ *
+ * The basic format of the database is a simple hash table containing the
+ * values.  A value is stored by indexing into the table using a hash value
+ * computed from the key; collisions are resolved by linear probing (just
+ * search forward for an empty slot, wrapping around to the beginning of
+ * the table if necessary).  Linear probing is a performance disaster when
+ * the table starts to get full, so a complication is introduced.  The
+ * database is actually one *or more* tables, stored sequentially in the
+ * .pag file, and the length of linear-probe sequences is limited.  The
+ * search (for an existing item or an empty slot) always starts in the
+ * first table, and whenever MAXRUN probes have been done in table N,
+ * probing continues in table N+1.  This behaves reasonably well even in
+ * cases of massive overflow.  There are some other small complications
+ * added, see comments below.
+ *
+ * The table size is fixed for any particular database, but is determined
+ * dynamically when a database is rebuilt.  The strategy is to try to pick
+ * the size so the first table will be no more than 2/3 full, that being
+ * slightly before the point where performance starts to degrade.  (It is
+ * desirable to be a bit conservative because the overflow strategy tends
+ * to produce files with holes in them, which is a nuisance.)
+ */
+
+/*
+ * The following is for backward compatibility.
+ */
+#ifdef INDEX_SIZE
+#define	DEFSIZE	INDEX_SIZE
+#endif
+
+/*
+ * ANSI C says an offset into a file is a long, not an off_t, for some
+ * reason.  This actually does simplify life a bit, but it's still nice
+ * to have a distinctive name for it.  Beware, this is just for readability,
+ * don't try to change this.
+ */
+#define	of_t	long
+#define	SOF	(sizeof(of_t))
+
+/*
+ * We assume that unused areas of a binary file are zeros, and that the
+ * bit pattern of `(of_t)0' is all zeros.  The alternative is rather
+ * painful file initialization.  Note that okayvalue(), if OVERFLOW is
+ * defined, knows what value of an offset would cause overflow.
+ */
+#define	VACANT		((of_t)0)
+#define	BIAS(o)		((o)+1)		/* make any valid of_t non-VACANT */
+#define	UNBIAS(o)	((o)-1)		/* reverse BIAS() effect */
+
+/*
+ * In a Unix implementation, or indeed any in which an of_t is a byte
+ * count, there are a bunch of high bits free in an of_t.  There is a
+ * use for them.  Checking a possible hit by looking it up in the base
+ * file is relatively expensive, and the cost can be dramatically reduced
+ * by using some of those high bits to tag the value with a few more bits
+ * of the key's hash.  This detects most false hits without the overhead of
+ * seek+read+strcmp.  We use the top bit to indicate whether the value is
+ * tagged or not, and don't tag a value which is using the tag bits itself.
+ * We're in trouble if the of_t representation wants to use the top bit.
+ * The actual bitmasks and offset come from the configuration stuff,
+ * which permits fiddling with them as necessary, and also suppressing
+ * them completely (by defining the masks to 0).  We build pre-shifted
+ * versions of the masks for efficiency.
+ */
+static of_t tagbits;		/* pre-shifted tag mask */
+static of_t taghere;		/* pre-shifted tag-enable bit */
+static of_t tagboth;		/* tagbits|taghere */
+#define	HASTAG(o)	((o)&taghere)
+#define	TAG(o)		((o)&tagbits)
+#define	NOTAG(o)	((o)&~tagboth)
+#define	CANTAG(o)	(((o)&tagboth) == 0)
+#define	MKTAG(v)	(((v)<<conf.tagshift)&tagbits)
+
+/*
+ * A new, from-scratch database, not built as a rebuild of an old one,
+ * needs to know table size, casemap algorithm, and tagging.  Normally
+ * the user supplies this info, but there have to be defaults.
+ */
+#ifndef DEFSIZE
+#define	DEFSIZE	300007
+#endif
+#ifdef OLDBNEWS
+#define	DEFCASE	'0'		/* B2.10 -- no mapping */
+#define	NOBUFFER		/* B News locking is defective */
+#endif
+#ifdef BNEWS
+#define	DEFCASE	'='		/* B2.11 -- all mapped */
+#define	NOBUFFER		/* B News locking is defective */
+#endif
+#ifndef DEFCASE			/* C News compatibility is the default */
+#define	DEFCASE	'C'		/* C News -- RFC822 mapping */
+#endif
+#ifndef NOTAGS
+#define	TAGENB	0x80L		/* tag enable is top bit, tag is next 5 */
+#define	TAGMASK	0x7c
+#define	TAGSHIFT	24
+#else
+#define	TAGENB	0L		/* no tags */
+#define	TAGMASK	0
+#define	TAGSHIFT	0
+#endif
+
+/*
+ * We read configuration info from the .dir file into this structure,
+ * so we can avoid wired-in assumptions for an existing database.
+ *
+ * Among the info is a record of recent peak usages, so that a new table
+ * size can be chosen intelligently when rebuilding.  10 is a good
+ * number of usages to keep, since news displays marked fluctuations
+ * in volume on a 7-day cycle.
+ */
+struct dbzconfig {
+	int olddbz;		/* .dir file empty but .pag not? */
+	of_t tsize;		/* table size */
+#	ifndef NMEMORY
+#	define	NMEMORY	10	/* # days of use info to remember */
+#	endif
+#	define	NUSEDS	(1+NMEMORY)
+	of_t used[NUSEDS];	/* entries used today, yesterday, ... */
+	int valuesize;		/* size of table values, == SOF */
+	int bytemap[SOF];	/* byte-order map */
+	char casemap;		/* case-mapping algorithm (see cipoint()) */
+	char fieldsep;		/* field separator in base file, if any */
+	of_t tagenb;		/* unshifted tag-enable bit */
+	of_t tagmask;		/* unshifted tag mask */
+	int tagshift;		/* shift count for tagmask and tagenb */
+	of_t ntagless[NUSEDS];	/* how many entries went tagless today, ... */
+};
+static struct dbzconfig conf;
+static int getconf();
+static long getno();
+static int putconf();
+static void mybytemap();
+static of_t bytemap();
+
+/* 
+ * For a program that makes many, many references to the database, it
+ * is a large performance win to keep the table in core, if it will fit.
+ * Note that this does hurt robustness in the event of crashes, and
+ * dbzdbmclose() *must* be called to flush the in-core database to disk.
+ * The code is prepared to deal with the possibility that there isn't
+ * enough memory.  There *is* an assumption that a size_t is big enough
+ * to hold the size (in bytes) of one table, so dbzdbminit() tries to figure
+ * out whether this is possible first.
+ *
+ * The preferred way to ask for an in-core table is to do dbzincore(1)
+ * before dbzdbminit().  The default is not to do it, although -DINCORE
+ * overrides this for backward compatibility with old dbz.
+ *
+ * We keep only the first table in core.  This greatly simplifies the
+ * code, and bounds memory demand.  Furthermore, doing this is a large
+ * performance win even in the event of massive overflow.
+ */
+#ifdef INCORE
+static int incore = 1;
+#else
+static int incore = 0;
+#endif
+
+/*
+ * Making the in-core table write-through is a win in some odd situations
+ * where one is doing much reading and very little writing.
+ */
+static int writethrough = 0;
+
+/*
+ * Stdio buffer for .pag reads.  Buffering more than about 16 does not help
+ * significantly at the densities we try to maintain, and the much larger
+ * buffers that most stdios default to are much more expensive to fill.
+ * With small buffers, stdio is performance-competitive with raw read(),
+ * and it's much more portable.
+ */
+#ifndef NPAGBUF
+#define	NPAGBUF	16
+#endif
+#ifndef NOBUFFER
+#ifdef _IOFBF
+static of_t pagbuf[NPAGBUF];	/* only needed if !NOBUFFER && _IOFBF */
+#endif
+#endif
+
+/*
+ * Stdio buffer for base-file reads.  Message-IDs (all news ever needs to
+ * read) are essentially never longer than 64 bytes, and the typical stdio
+ * buffer is so much larger that it is much more expensive to fill.
+ */
+#ifndef SHISTBUF
+#define	SHISTBUF	64
+#endif
+#ifdef _IOFBF
+static char basebuf[SHISTBUF];		/* only needed if _IOFBF exists */
+#endif
+
+/*
+ * Callback routine for performing obscene acts on file descriptors.
+ * This gives the user some control when dbz opens a file descriptor with
+ * the intention of keeping it open, and lets him (e.g.) set close-on-exec
+ * bits on the descriptor.  The callback routine gets a FILE * as its
+ * parameter, and must not mess with it in dbz-visible ways.
+ */
+static void (*callback)() = NULL;
+
+/*
+ * Data structure for recording info about searches.
+ */
+struct searcher {
+	of_t place;		/* current location in file */
+	int tabno;		/* which table we're in */
+	int run;		/* how long we'll stay in this table */
+#		ifndef MAXRUN
+#		define	MAXRUN	100
+#		endif
+	long hash;		/* the key's hash code (for optimization) */
+	of_t tag;		/* tag we are looking for */
+	int seen;		/* have we examined current location? */
+	int aborted;		/* has i/o error aborted search? */
+};
+static void start();
+#define	FRESH	((struct searcher *)NULL)
+static of_t search();
+#define	NOTFOUND	((of_t)-1)
+static int okayvalue();
+static int set();
+
+/*
+ * Arguably the searcher struct for a given routine ought to be local to
+ * it, but a fetch() is very often immediately followed by a store(), and
+ * in some circumstances it is a useful performance win to remember where
+ * the fetch() completed.  So we use a global struct and remember whether
+ * it is current.
+ */
+static struct searcher srch;
+static struct searcher *prevp;	/* &srch or FRESH */
+
+/* byte-ordering stuff */
+static int mybmap[SOF];			/* my byte order (see mybytemap()) */
+static int bytesame;			/* is database order same as mine? */
+#define	MAPIN(o)	((bytesame) ? (o) : bytemap((o), conf.bytemap, mybmap))
+#define	MAPOUT(o)	((bytesame) ? (o) : bytemap((o), mybmap, conf.bytemap))
+
+/*
+ * The double parentheses needed to make this work are ugly, but the
+ * alternative (under most compilers) is to pack around 2K of unused
+ * strings -- there's just no way to get rid of them.  The "else" is
+ * likewise ugly, but swallows the following ";" and keeps it from
+ * making syntactic trouble.
+ */
+#ifdef DBZDEBUG
+#define DEBUG(args) if (debug) { (void) printf args ; } else
+static int debug;			/* controlled by dbzdebug() */
+#else
+#define	DEBUG(args)	;
+#endif
+
+/* misc. forwards */
+static long hash();
+static void crcinit();
+static char *cipoint();
+static char *mapcase();
+static int isprime();
+static FILE *latebase();
+
+/* file-naming stuff */
+static char dir[] = ".dir";
+static char pag[] = ".pag";
+static char *enstring();
+
+/* central data structures */
+static FILE *basef;		/* descriptor for base file */
+static char *basefname;		/* name for not-yet-opened base file */
+static FILE *dirf;		/* descriptor for .dir file */
+static int dirronly;		/* dirf open read-only? */
+static FILE *pagf = NULL;	/* descriptor for .pag file */
+static of_t pagpos;		/* posn in pagf; only search may set != -1 */
+static int pagronly;		/* pagf open read-only? */
+static of_t *corepag;		/* incore version of .pag file, if any */
+static FILE *bufpagf;		/* well-buffered pagf, for incore rewrite */
+static of_t *getcore();
+static int putcore();
+static int written;		/* has a store() been done? */
+
+/*
+ - dbzfresh - set up a new database, no historical info
+ */
+int				/* 0 success, -1 failure */
+dbzfresh(name, size, fs, cmap, tagmask)
+char *name;			/* base name; .dir and .pag must exist */
+long size;			/* table size (0 means default) */
+int fs;				/* field-separator character in base file */
+int cmap;			/* case-map algorithm (0 means default) */
+of_t tagmask;			/* 0 default, 1 no tags */
+{
+	register char *fn;
+	struct dbzconfig c;
+	register of_t m;
+	register FILE *f;
+
+	if (pagf != NULL) {
+		DEBUG(("dbzfresh: database already open\n"));
+		return(-1);
+	}
+	if (size != 0 && size < 2) {
+		DEBUG(("dbzfresh: preposterous size (%ld)\n", size));
+		return(-1);
+	}
+
+	/* get default configuration */
+	if (getconf((FILE *)NULL, (FILE *)NULL, &c) < 0)
+		return(-1);	/* "can't happen" */
+
+	/* and mess with it as specified */
+	if (size != 0)
+		c.tsize = size;
+	c.fieldsep = fs;
+	switch (cmap) {
+	case 0:
+	case '0':
+	case 'B':		/* 2.10 compat */
+		c.casemap = '0';	/* '\0' nicer, but '0' printable! */
+		break;
+	case '=':
+	case 'b':		/* 2.11 compat */
+		c.casemap = '=';
+		break;
+	case 'C':
+		c.casemap = 'C';
+		break;
+	case '?':
+		c.casemap = DEFCASE;
+		break;
+	default:
+		DEBUG(("dbzfresh case map `%c' unknown\n", cmap));
+		return(-1);
+		break;
+	}
+	switch (tagmask) {
+	case 0:			/* default */
+		break;
+	case 1:			/* no tags */
+		c.tagshift = 0;
+		c.tagmask = 0;
+		c.tagenb = 0;
+		break;
+	default:
+		m = tagmask;
+		c.tagshift = 0;
+		while (!(m&01)) {
+			m >>= 1;
+			c.tagshift++;
+		}
+		c.tagmask = m;
+		c.tagenb = (m << 1) & ~m;
+		break;
+	}
+
+	/* write it out */
+	fn = enstring(name, dir);
+	if (fn == NULL)
+		return(-1);
+	f = fopen(fn, "w");
+	free(fn);
+	if (f == NULL) {
+		DEBUG(("dbzfresh: unable to write config\n"));
+		return(-1);
+	}
+	if (putconf(f, &c) < 0) {
+		(void) fclose(f);
+		return(-1);
+	}
+	if (fclose(f) == EOF) {
+		DEBUG(("dbzfresh: fclose failure\n"));
+		return(-1);
+	}
+
+	/* create/truncate .pag */
+	fn = enstring(name, pag);
+	if (fn == NULL)
+		return(-1);
+	f = fopen(fn, "w");
+	free(fn);
+	if (f == NULL) {
+		DEBUG(("dbzfresh: unable to create/truncate .pag file\n"));
+		return(-1);
+	} else
+		(void) fclose(f);
+
+	/* and punt to dbzdbminit for the hard work */
+	return(dbzdbminit(name));
+}
+
+/*
+ - dbzsize - what's a good table size to hold this many entries?
+ */
+long
+dbzsize(contents)
+long contents;			/* 0 means what's the default */
+{
+	register long n;
+
+	if (contents <= 0) {	/* foulup or default inquiry */
+		DEBUG(("dbzsize: preposterous input (%ld)\n", contents));
+		return(DEFSIZE);
+	}
+	n = (contents/2)*3;	/* try to keep table at most 2/3 full */
+	if (!(n&01))		/* make it odd */
+		n++;
+	DEBUG(("dbzsize: tentative size %ld\n", n));
+	while (!isprime(n))	/* and look for a prime */
+		n += 2;
+	DEBUG(("dbzsize: final size %ld\n", n));
+
+	return(n);
+}
+
+/*
+ - isprime - is a number prime?
+ *
+ * This is not a terribly efficient approach.
+ */
+static int			/* predicate */
+isprime(x)
+register long x;
+{
+	static int quick[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 0 };
+	register int *ip;
+	register long div;
+	register long stop;
+
+	/* hit the first few primes quickly to eliminate easy ones */
+	/* this incidentally prevents ridiculously small tables */
+	for (ip = quick; (div = *ip) != 0; ip++)
+		if (x%div == 0) {
+			DEBUG(("isprime: quick result on %ld\n", x));
+			return(0);
+		}
+
+	/* approximate square root of x */
+	for (stop = x; x/stop < stop; stop >>= 1)
+		continue;
+	stop <<= 1;
+
+	/* try odd numbers up to stop */
+	for (div = *--ip + 2; div < stop; div += 2)
+		if (x%div == 0)
+			return(0);
+
+	return(1);
+}
+
+/*
+ - dbztagmask - what's a good tag mask for a file this size?
+ *
+ * This assumes that TAGENB is the high-order bit of a long.
+ */
+long
+dbztagmask(filesize)
+register long filesize;
+{
+	register long m;
+	register int nbits;
+
+	/*
+	 * First, see how many bits are unused.  We cut it off at 7 on the
+	 * theory that a 1-in-128 rate of false probes should be okay, given
+	 * that the .pag file gets resized to limit the length of runs anyway.
+	 */
+	m = TAGENB << (TAGSHIFT-1);
+	nbits = 1;
+	while ((m&filesize) == 0 && nbits < 7) {	/* extend downward */
+		m |= m >> 1;
+		nbits++;
+	}
+
+	if ((m&filesize) == 0)		/* reached max bits and still fine */
+		return(m);
+
+	/* We now have a mask that is one bit too big. */
+	m &= m << 1;			/* shorten it */
+
+	if (m == 0)			/* file is just too big */
+		return(1);
+
+	return(m);
+}
+
+/*
+ - dbzagain - set up a new database to be a rebuild of an old one
+ */
+int				/* 0 success, -1 failure */
+dbzagain(name, oldname)
+char *name;			/* base name; .dir and .pag must exist */
+char *oldname;			/* base name; all must exist */
+{
+	register char *fn;
+	struct dbzconfig c;
+	register int i;
+	register long top;
+	register FILE *f;
+	register int newtable;
+	register long newsize;
+
+	if (pagf != NULL) {
+		DEBUG(("dbzagain: database already open\n"));
+		return(-1);
+	}
+
+	/* pick up the old configuration */
+	fn = enstring(oldname, dir);
+	if (fn == NULL)
+		return(-1);
+	f = fopen(fn, "r");
+	free(fn);
+	if (f == NULL) {
+		DEBUG(("dbzagain: cannot open old .dir file\n"));
+		return(-1);
+	}
+	i = getconf(f, (FILE *)NULL, &c);
+	(void) fclose(f);
+	if (i < 0) {
+		DEBUG(("dbzagain: getconf failed\n"));
+		return(-1);
+	}
+
+	/* tinker with it */
+	/* first, find peak of usage history, if there's enough history */
+	top = 0;
+	newtable = 0;
+	for (i = 0; i < NUSEDS; i++) {
+		if (top < c.used[i])
+			top = c.used[i];
+		if (c.used[i] == 0)
+			newtable = 1;	/* hasn't got full usage history yet */
+	}
+	if (top == 0) {
+		DEBUG(("dbzagain: old table has no contents!\n"));
+		newtable = 1;
+	}
+
+	/* shift the history, and decide on table size */
+	for (i = NUSEDS-1; i > 0; i--) {
+		c.used[i] = c.used[i-1];
+		c.ntagless[i] = c.ntagless[i-1];
+	}
+	c.used[0] = 0;
+	c.ntagless[0] = 0;
+	newsize = dbzsize(top);
+	if (!newtable || newsize > c.tsize)	/* don't shrink new table */
+		c.tsize = newsize;
+
+	/* decide whether the tag needs changing */
+	if (c.ntagless[1] != 0) {
+		c.tagmask &= c.tagmask << 1;	/* clear bottom bit */
+		if (c.tagmask == 0)		/* oops, no more room... */
+			c.tagenb = 0;		/* just can't tag at all */
+	}
+	/*
+	 * You might think that you'd want to adaptively grow the tag
+	 * as well as shrinking it.  It's very hard to do that well,
+	 * so for now we don't try.
+	 */
+
+	/* write it out */
+	fn = enstring(name, dir);
+	if (fn == NULL)
+		return(-1);
+	f = fopen(fn, "w");
+	free(fn);
+	if (f == NULL) {
+		DEBUG(("dbzagain: unable to write new .dir\n"));
+		return(-1);
+	}
+	i = putconf(f, &c);
+	(void) fclose(f);
+	if (i < 0) {
+		DEBUG(("dbzagain: putconf failed\n"));
+		return(-1);
+	}
+
+	/* create/truncate .pag */
+	fn = enstring(name, pag);
+	if (fn == NULL)
+		return(-1);
+	f = fopen(fn, "w");
+	free(fn);
+	if (f == NULL) {
+		DEBUG(("dbzagain: unable to create/truncate .pag file\n"));
+		return(-1);
+	} else
+		(void) fclose(f);
+
+	/* and let dbzdbminit do the work */
+	return(dbzdbminit(name));
+}
+
+/*
+ - dbzdbminit - open a database, creating it (using defaults) if necessary
+ *
+ * We try to leave errno set plausibly, to the extent that underlying
+ * functions permit this, since many people consult it if dbzdbminit() fails.
+ */
+int 				/* 0 success, -1 failure */
+dbzdbminit(name)
+char *name;
+{
+	register int i;
+	register size_t s;
+	register char *dirfname;
+	register char *pagfname;
+
+	if (pagf != NULL) {
+		DEBUG(("dbzdbminit: dbzdbminit already called once\n"));
+		errno = 0;
+		return(-1);
+	}
+
+	/* open the .dir file */
+	dirfname = enstring(name, dir);
+	if (dirfname == NULL)
+		return(-1);
+	dirf = fopen(dirfname, "r+");
+	if (dirf == NULL) {
+		dirf = fopen(dirfname, "r");
+		dirronly = 1;
+	} else
+		dirronly = 0;
+	free(dirfname);
+	if (dirf == NULL) {
+		DEBUG(("dbzdbminit: can't open .dir file\n"));
+		return(-1);
+	}
+	if (callback != NULL)
+		(*callback)(dirf);
+
+	/* open the .pag file */
+	pagfname = enstring(name, pag);
+	if (pagfname == NULL) {
+		(void) fclose(dirf);
+		return(-1);
+	}
+	pagf = fopen(pagfname, "r+b");
+	if (pagf == NULL) {
+		pagf = fopen(pagfname, "rb");
+		if (pagf == NULL) {
+			DEBUG(("dbzdbminit: .pag open failed\n"));
+			(void) fclose(dirf);
+			free(pagfname);
+			return(-1);
+		}
+		pagronly = 1;
+	} else if (dirronly)
+		pagronly = 1;
+	else
+		pagronly = 0;
+#ifdef NOBUFFER
+	/*
+	 * B News does not do adequate locking on its database accesses.
+	 * Why it doesn't get into trouble using dbm is a mystery.  In any
+	 * case, doing unbuffered i/o does not cure the problem, but does
+	 * enormously reduce its incidence.
+	 */
+	(void) setbuf(pagf, (char *)NULL);
+#else
+#ifdef _IOFBF
+	(void) setvbuf(pagf, (char *)pagbuf, _IOFBF, sizeof(pagbuf));
+#endif
+#endif
+	pagpos = -1;
+	/* don't free pagfname, need it below */
+	if (callback != NULL)
+		(*callback)(pagf);
+
+	/* open the base file */
+	basef = fopen(name, "r");
+	if (basef == NULL) {
+		DEBUG(("dbzdbminit: basefile open failed\n"));
+		basefname = enstring(name, "");
+		if (basefname == NULL) {
+			(void) fclose(pagf);
+			(void) fclose(dirf);
+			free(pagfname);
+			pagf = NULL;
+			return(-1);
+		}
+	} else
+		basefname = NULL;
+#ifdef _IOFBF
+	if (basef != NULL)
+		(void) setvbuf(basef, basebuf, _IOFBF, sizeof(basebuf));
+#endif
+	if (callback != NULL)
+		(*callback)(basef);
+
+	/* pick up configuration */
+	if (getconf(dirf, pagf, &conf) < 0) {
+		DEBUG(("dbzdbminit: getconf failure\n"));
+		(void) fclose(basef);
+		(void) fclose(pagf);
+		(void) fclose(dirf);
+		free(pagfname);
+		pagf = NULL;
+		errno = EDOM;	/* kind of a kludge, but very portable */
+		return(-1);
+	}
+	tagbits = conf.tagmask << conf.tagshift;
+	taghere = conf.tagenb << conf.tagshift;
+	tagboth = tagbits | taghere;
+	mybytemap(mybmap);
+	bytesame = 1;
+	for (i = 0; i < SOF; i++)
+		if (mybmap[i] != conf.bytemap[i])
+			bytesame = 0;
+
+	/* get first table into core, if it looks desirable and feasible */
+	s = (size_t)conf.tsize * SOF;
+	if (incore && (of_t)(s/SOF) == conf.tsize) {
+		bufpagf = fopen(pagfname, (pagronly) ? "rb" : "r+b");
+		if (bufpagf != NULL) {
+			corepag = getcore(bufpagf);
+			if (callback != NULL)
+				(*callback)(bufpagf);
+		}
+	} else {
+		bufpagf = NULL;
+		corepag = NULL;
+	}
+	free(pagfname);
+
+	/* misc. setup */
+	crcinit();
+	written = 0;
+	prevp = FRESH;
+	DEBUG(("dbzdbminit: succeeded\n"));
+	return(0);
+}
+
+/*
+ - enstring - concatenate two strings into a malloced area
+ */
+static char *			/* NULL if malloc fails */
+enstring(s1, s2)
+char *s1;
+char *s2;
+{
+	register char *p;
+
+	p = malloc((size_t)strlen(s1) + (size_t)strlen(s2) + 1);
+	if (p != NULL) {
+		(void) strcpy(p, s1);
+		(void) strcat(p, s2);
+	} else {
+		DEBUG(("enstring(%s, %s) out of memory\n", s1, s2));
+	}
+	return(p);
+}
+
+/*
+ - dbzdbmclose - close a database
+ */
+int
+dbzdbmclose()
+{
+	register int ret = 0;
+
+	if (pagf == NULL) {
+		DEBUG(("dbzdbmclose: not opened!\n"));
+		return(-1);
+	}
+
+	if (fclose(pagf) == EOF) {
+		DEBUG(("dbzdbmclose: fclose(pagf) failed\n"));
+		ret = -1;
+	}
+	pagf = basef;		/* ensure valid pointer; dbzsync checks it */
+	if (dbzsync() < 0)
+		ret = -1;
+	if (bufpagf != NULL && fclose(bufpagf) == EOF) {
+		DEBUG(("dbzdbmclose: fclose(bufpagf) failed\n"));
+		ret = -1;
+	}
+	if (corepag != NULL)
+		free((char *)corepag);
+	corepag = NULL;
+	if (fclose(basef) == EOF) {
+		DEBUG(("dbzdbmclose: fclose(basef) failed\n"));
+		ret = -1;
+	}
+	if (basefname != NULL)
+		free(basefname);
+	basef = NULL;
+	pagf = NULL;
+	if (fclose(dirf) == EOF) {
+		DEBUG(("dbzdbmclose: fclose(dirf) failed\n"));
+		ret = -1;
+	}
+
+	DEBUG(("dbzdbmclose: %s\n", (ret == 0) ? "succeeded" : "failed"));
+	return(ret);
+}
+
+/*
+ - dbzsync - push all in-core data out to disk
+ */
+int
+dbzsync()
+{
+	register int ret = 0;
+
+	if (pagf == NULL) {
+		DEBUG(("dbzsync: not opened!\n"));
+		return(-1);
+	}
+	if (!written)
+		return(0);
+
+	if (corepag != NULL && !writethrough) {
+		if (putcore(corepag, bufpagf) < 0) {
+			DEBUG(("dbzsync: putcore failed\n"));
+			ret = -1;
+		}
+	}
+	if (!conf.olddbz)
+		if (putconf(dirf, &conf) < 0)
+			ret = -1;
+
+	DEBUG(("dbzsync: %s\n", (ret == 0) ? "succeeded" : "failed"));
+	return(ret);
+}
+
+/*
+ - dbzcancel - cancel writing of in-core data
+ * Mostly for use from child processes.
+ * Note that we don't need to futz around with stdio buffers, because we
+ * always fflush them immediately anyway and so they never have stale data.
+ */
+int
+dbzcancel()
+{
+	if (pagf == NULL) {
+		DEBUG(("dbzcancel: not opened!\n"));
+		return(-1);
+	}
+
+	written = 0;
+	return(0);
+}
+
+/*
+ - dbzfetch - fetch() with case mapping built in
+ */
+datum
+dbzfetch(key)
+datum key;
+{
+	char buffer[DBZMAXKEY + 1];
+	datum mappedkey;
+	register size_t keysize;
+
+	DEBUG(("dbzfetch: (%s)\n", key.dptr));
+
+	/* Key is supposed to be less than DBZMAXKEY */
+	keysize = key.dsize;
+	if (keysize >= DBZMAXKEY) {
+		keysize = DBZMAXKEY;
+		DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY));
+	}
+
+	mappedkey.dptr = mapcase(buffer, key.dptr, keysize);
+	buffer[keysize] = '\0';	/* just a debug aid */
+	mappedkey.dsize = keysize;
+
+	return(dbzdbmfetch(mappedkey));
+}
+
+/*
+ - dbzdbmfetch - get an entry from the database
+ *
+ * Disgusting fine point, in the name of backward compatibility:  if the
+ * last character of "key" is a NUL, that character is (effectively) not
+ * part of the comparison against the stored keys.
+ */
+datum				/* dptr NULL, dsize 0 means failure */
+dbzdbmfetch(key)
+datum key;
+{
+	char buffer[DBZMAXKEY + 1];
+	static of_t key_ptr;		/* return value points here */
+	datum output;
+	register size_t keysize;
+	register size_t cmplen;
+	register char *sepp;
+
+	DEBUG(("dbzdbmfetch: (%s)\n", key.dptr));
+	output.dptr = NULL;
+	output.dsize = 0;
+	prevp = FRESH;
+
+	/* Key is supposed to be less than DBZMAXKEY */
+	keysize = key.dsize;
+	if (keysize >= DBZMAXKEY) {
+		keysize = DBZMAXKEY;
+		DEBUG(("keysize is %d - truncated to %d\n", key.dsize, DBZMAXKEY));
+	}
+
+	if (pagf == NULL) {
+		DEBUG(("dbzdbmfetch: database not open!\n"));
+		return(output);
+	} else if (basef == NULL) {	/* basef didn't exist yet */
+		basef = latebase();
+		if (basef == NULL)
+			return(output);
+	}
+
+	cmplen = keysize;
+	sepp = &conf.fieldsep;
+	if (key.dptr[keysize-1] == '\0') {
+		cmplen--;
+		sepp = &buffer[keysize-1];
+	}
+	start(&srch, &key, FRESH);
+	while ((key_ptr = search(&srch)) != NOTFOUND) {
+		DEBUG(("got 0x%lx\n", (long)key_ptr));
+
+		/* fetch the key */
+		if (fseek(basef, key_ptr, SEEK_SET) != 0) {
+			DEBUG(("dbzdbmfetch: seek failed\n"));
+			return(output);
+		}
+		if (fread(buffer, 1, keysize, basef) != keysize) {
+			DEBUG(("dbzdbmfetch: read failed\n"));
+			return(output);
+		}
+
+		/* try it */
+		buffer[keysize] = '\0';		/* terminated for DEBUG */
+		(void) mapcase(buffer, buffer, keysize);
+		DEBUG(("dbzdbmfetch: buffer (%s) looking for (%s) size = %d\n", 
+						buffer, key.dptr, keysize));
+		if (memcmp(key.dptr, buffer, cmplen) == 0 &&
+				(*sepp == conf.fieldsep || *sepp == '\0')) {
+			/* we found it */
+			output.dptr = (char *)&key_ptr;
+			output.dsize = SOF;
+			DEBUG(("dbzdbmfetch: successful\n"));
+			return(output);
+		}
+	}
+
+	/* we didn't find it */
+	DEBUG(("dbzdbmfetch: failed\n"));
+	prevp = &srch;			/* remember where we stopped */
+	return(output);
+}
+
+/*
+ - latebase - try to open a base file that wasn't there at the start
+ */
+static FILE *
+latebase()
+{
+	register FILE *it;
+
+	if (basefname == NULL) {
+		DEBUG(("latebase: name foulup\n"));
+		return(NULL);
+	}
+	it = fopen(basefname, "r");
+	if (it == NULL) {
+		DEBUG(("latebase: still can't open base\n"));
+	} else {
+		DEBUG(("latebase: late open succeeded\n"));
+		free(basefname);
+		basefname = NULL;
+#ifdef _IOFBF
+		(void) setvbuf(it, basebuf, _IOFBF, sizeof(basebuf));
+#endif
+		if (callback != NULL)
+			(*callback)(it);
+	}
+	return(it);
+}
+
+/*
+ - dbzstore - store() with case mapping built in
+ */
+int
+dbzstore(key, data)
+datum key;
+datum data;
+{
+	char buffer[DBZMAXKEY + 1];
+	datum mappedkey;
+	register size_t keysize;
+
+	DEBUG(("dbzstore: (%s)\n", key.dptr));
+
+	/* Key is supposed to be less than DBZMAXKEY */
+	keysize = key.dsize;
+	if (keysize >= DBZMAXKEY) {
+		DEBUG(("dbzstore: key size too big (%d)\n", key.dsize));
+		return(-1);
+	}
+
+	mappedkey.dptr = mapcase(buffer, key.dptr, keysize);
+	buffer[keysize] = '\0';	/* just a debug aid */
+	mappedkey.dsize = keysize;
+
+	return(dbzdbmstore(mappedkey, data));
+}
+
+/*
+ - dbzdbmstore - add an entry to the database
+ */
+int				/* 0 success, -1 failure */
+dbzdbmstore(key, data)
+datum key;
+datum data;
+{
+	of_t value;
+
+	if (pagf == NULL) {
+		DEBUG(("dbzdbmstore: database not open!\n"));
+		return(-1);
+	} else if (basef == NULL) {	/* basef didn't exist yet */
+		basef = latebase();
+		if (basef == NULL)
+			return(-1);
+	}
+	if (pagronly) {
+		DEBUG(("dbzdbmstore: database open read-only\n"));
+		return(-1);
+	}
+	if (data.dsize != SOF) {
+		DEBUG(("dbzdbmstore: value size wrong (%d)\n", data.dsize));
+		return(-1);
+	}
+	if (key.dsize >= DBZMAXKEY) {
+		DEBUG(("dbzdbmstore: key size too big (%d)\n", key.dsize));
+		return(-1);
+	}
+
+	/* copy the value in to ensure alignment */
+	(void) memcpy((char *)&value, data.dptr, SOF);
+	DEBUG(("dbzdbmstore: (%s, %ld)\n", key.dptr, (long)value));
+	if (!okayvalue(value)) {
+		DEBUG(("dbzdbmstore: reserved bit or overflow in 0x%lx\n", value));
+		return(-1);
+	}
+
+	/* find the place, exploiting previous search if possible */
+	start(&srch, &key, prevp);
+	while (search(&srch) != NOTFOUND)
+		continue;
+
+	prevp = FRESH;
+	conf.used[0]++;
+	DEBUG(("dbzdbmstore: used count %ld\n", conf.used[0]));
+	written = 1;
+	return(set(&srch, value));
+}
+
+/*
+ - dbzincore - control attempts to keep .pag file in core
+ */
+int				/* old setting */
+dbzincore(value)
+int value;
+{
+	register int old = incore;
+
+	incore = value;
+	return(old);
+}
+
+/*
+ - dbzwritethrough - enable/disable immediate writing to disk of in-core writes
+ */
+int				/* old setting */
+dbzwritethrough(value)
+int value;
+{
+	register int old = writethrough;
+
+	writethrough = value;
+	return(old);
+}
+
+/*
+ - dbzfiledesc - provide hook for doing obscene things to file descriptors
+ */
+typedef void (*fp)();
+fp
+dbzfiledesc(diddler)
+void (*diddler)();		/* NULL means do nothing */
+{
+	register void (*old)() = callback;
+
+	callback = diddler;
+	return(old);
+}
+
+/*
+ - getconf - get configuration from .dir file
+ */
+static int			/* 0 success, -1 failure */
+getconf(df, pf, cp)
+register FILE *df;		/* NULL means just give me the default */
+register FILE *pf;		/* NULL means don't care about .pag */
+register struct dbzconfig *cp;
+{
+	register int c;
+	register int i;
+	int err = 0;
+
+	c = (df != NULL) ? getc(df) : EOF;
+	if (c == EOF) {		/* empty file, no configuration known */
+		cp->olddbz = 0;
+		if (df != NULL && pf != NULL && getc(pf) != EOF)
+			cp->olddbz = 1;
+		cp->tsize = DEFSIZE;
+		cp->fieldsep = '\t';
+		for (i = 0; i < NUSEDS; i++) {
+			cp->used[i] = 0;
+			cp->ntagless[i] = 0;
+		}
+		cp->valuesize = SOF;
+		mybytemap(cp->bytemap);
+		cp->casemap = DEFCASE;
+		cp->tagenb = TAGENB;
+		cp->tagmask = TAGMASK;
+		cp->tagshift = TAGSHIFT;
+		DEBUG(("getconf: defaults (%ld, %c, (0x%lx/0x%lx<<%d))\n",
+			cp->tsize, cp->casemap, cp->tagenb, 
+			cp->tagmask, cp->tagshift));
+		return(0);
+	}
+	(void) ungetc(c, df);
+
+	/* first line, the vital stuff */
+	if (getc(df) != 'd' || getc(df) != 'b' || getc(df) != 'z')
+		err = -1;
+	if (getno(df, &err) != dbzversion)
+		err = -1;
+	cp->tsize = getno(df, &err);
+	cp->fieldsep = (char)getno(df, &err);
+	while ((c = getc(df)) == ' ')
+		continue;
+	cp->casemap = c;
+	cp->tagenb = getno(df, &err);
+	cp->tagmask = getno(df, &err);
+	cp->tagshift = getno(df, &err);
+	cp->valuesize = getno(df, &err);
+	if (cp->valuesize != SOF) {
+		DEBUG(("getconf: wrong of_t size (%d)\n", cp->valuesize));
+		err = -1;
+		cp->valuesize = SOF;	/* to protect the loops below */
+	}
+	for (i = 0; i < cp->valuesize; i++)
+		cp->bytemap[i] = getno(df, &err);
+	if (getc(df) != '\n')
+		err = -1;
+	DEBUG(("size %ld, sep %d, cmap %c, tags 0x%lx/0x%lx<<%d, ", cp->tsize,
+			cp->fieldsep, cp->casemap, cp->tagenb, cp->tagmask,
+			cp->tagshift));
+	DEBUG(("bytemap (%d)", cp->valuesize));
+#ifdef DBZDEBUG
+	for (i = 0; i < cp->valuesize; i++) {
+		DEBUG((" %d", cp->bytemap[i]));
+	}
+#endif
+	DEBUG(("\n"));
+
+	/* second line, the usages */
+	for (i = 0; i < NUSEDS; i++)
+		cp->used[i] = getno(df, &err);
+	if (getc(df) != '\n')
+		err = -1;
+	DEBUG(("used %ld %ld %ld...\n", cp->used[0], cp->used[1], cp->used[2]));
+
+	/* third line, currently only the tagless count */
+	if ((c = getc(df)) != EOF) {
+		(void) ungetc(c, df);
+		for (i = 0; i < NUSEDS; i++)
+			cp->ntagless[i] = getno(df, &err);
+		if (getc(df) != '\n')
+			err = -1;
+	} else
+		for (i = 0; i < NUSEDS; i++)
+			cp->ntagless[i] = 0;
+
+	if (err < 0) {
+		DEBUG(("getconf error\n"));
+		return(-1);
+	}
+	return(0);
+}
+
+/*
+ - getno - get a long
+ */
+static long
+getno(f, ep)
+FILE *f;
+int *ep;
+{
+	register char *p;
+#	define	MAXN	50
+	char getbuf[MAXN];
+	register int c;
+
+	while ((c = getc(f)) == ' ')
+		continue;
+	if (c == EOF || c == '\n') {
+		DEBUG(("getno: missing number\n"));
+		*ep = -1;
+		return(0);
+	}
+	p = getbuf;
+	*p++ = c;
+	while ((c = getc(f)) != EOF && c != '\n' && c != ' ')
+		if (p < &getbuf[MAXN-1])
+			*p++ = c;
+	if (c == EOF) {
+		DEBUG(("getno: EOF\n"));
+		*ep = -1;
+	} else
+		(void) ungetc(c, f);
+	*p = '\0';
+
+	if (strspn(getbuf, "-1234567890") != strlen(getbuf)) {
+		DEBUG(("getno: `%s' non-numeric\n", getbuf));
+		*ep = -1;
+	}
+	return(atol(getbuf));
+}
+
+/*
+ - putconf - write configuration to .dir file
+ */
+static int			/* 0 success, -1 failure */
+putconf(f, cp)
+register FILE *f;
+register struct dbzconfig *cp;
+{
+	register int i;
+	register int ret = 0;
+
+	if (fseek(f, (of_t)0, SEEK_SET) != 0) {
+		DEBUG(("fseek failure in putconf\n"));
+		ret = -1;
+	}
+	fprintf(f, "dbz %d %ld %d %c %ld %ld %d %d", dbzversion, cp->tsize,
+				cp->fieldsep, cp->casemap, cp->tagenb,
+				cp->tagmask, cp->tagshift, cp->valuesize);
+	for (i = 0; i < cp->valuesize; i++)
+		fprintf(f, " %d", cp->bytemap[i]);
+	fprintf(f, "\n");
+	for (i = 0; i < NUSEDS; i++)
+		fprintf(f, "%ld%c", cp->used[i], (i < NUSEDS-1) ? ' ' : '\n');
+	for (i = 0; i < NUSEDS; i++)
+		fprintf(f, "%ld%c", cp->ntagless[i], (i < NUSEDS-1) ? ' ' : '\n');
+
+	(void) fflush(f);
+	if (ferror(f))
+		ret = -1;
+
+	DEBUG(("putconf status %d\n", ret));
+	return(ret);
+}
+
+/*
+ - getcore - try to set up an in-core copy of .pag file
+ */
+static of_t *			/* pointer to copy, or NULL */
+getcore(f)
+FILE *f;
+{
+	register of_t *p;
+	register size_t i;
+	register size_t nread;
+	register of_t *it;
+
+	it = (of_t *)malloc((size_t)conf.tsize * SOF);
+	if (it == NULL) {
+		DEBUG(("getcore: malloc failed\n"));
+		return(NULL);
+	}
+
+	nread = fread((char *)it, SOF, (size_t)conf.tsize, f);
+	if (ferror(f)) {
+		DEBUG(("getcore: read failed\n"));
+		free((char *)it);
+		return(NULL);
+	}
+
+	p = it + nread;
+	i = (size_t)conf.tsize - nread;
+	while (i-- > 0)
+		*p++ = VACANT;
+
+	return(it);
+}
+
+/*
+ - putcore - try to rewrite an in-core table
+ */
+static int			/* 0 okay, -1 fail */
+putcore(tab, f)
+of_t *tab;
+FILE *f;
+{
+	if (fseek(f, (of_t)0, SEEK_SET) != 0) {
+		DEBUG(("fseek failure in putcore\n"));
+		return(-1);
+	}
+	(void) fwrite((char *)tab, SOF, (size_t)conf.tsize, f);
+	(void) fflush(f);
+	return((ferror(f)) ? -1 : 0);
+}
+
+/*
+ - start - set up to start or restart a search
+ */
+static void
+start(sp, kp, osp)
+register struct searcher *sp;
+register datum *kp;
+register struct searcher *osp;		/* may be FRESH, i.e. NULL */
+{
+	register long h;
+
+	h = hash(kp->dptr, kp->dsize);
+	if (osp != FRESH && osp->hash == h) {
+		if (sp != osp)
+			*sp = *osp;
+		DEBUG(("search restarted\n"));
+	} else {
+		sp->hash = h;
+		sp->tag = MKTAG(h / conf.tsize);
+		DEBUG(("tag 0x%lx\n", sp->tag));
+		sp->place = h % conf.tsize;
+		sp->tabno = 0;
+		sp->run = (conf.olddbz) ? conf.tsize : MAXRUN;
+		sp->aborted = 0;
+	}
+	sp->seen = 0;
+}
+
+/*
+ - search - conduct part of a search
+ */
+static of_t			/* NOTFOUND if we hit VACANT or error */
+search(sp)
+register struct searcher *sp;
+{
+	register of_t dest;
+	register of_t value;
+	of_t val;		/* buffer for value (can't fread register) */
+	register of_t place;
+
+	if (sp->aborted)
+		return(NOTFOUND);
+
+	for (;;) {
+		/* determine location to be examined */
+		place = sp->place;
+		if (sp->seen) {
+			/* go to next location */
+			if (--sp->run <= 0) {
+				sp->tabno++;
+				sp->run = MAXRUN;
+			}
+			place = (place+1)%conf.tsize + sp->tabno*conf.tsize;
+			sp->place = place;
+		} else
+			sp->seen = 1;	/* now looking at current location */
+		DEBUG(("search @ %ld\n", place));
+
+		/* get the tagged value */
+		if (corepag != NULL && place < conf.tsize) {
+			DEBUG(("search: in core\n"));
+			value = MAPIN(corepag[place]);
+		} else {
+			/* seek, if necessary */
+			dest = place * SOF;
+			if (pagpos != dest) {
+				if (fseek(pagf, dest, SEEK_SET) != 0) {
+					DEBUG(("search: seek failed\n"));
+					pagpos = -1;
+					sp->aborted = 1;
+					return(NOTFOUND);
+				}
+				pagpos = dest;
+			}
+
+			/* read it */
+			if (fread((char *)&val, sizeof(val), 1, pagf) == 1)
+				value = MAPIN(val);
+			else if (ferror(pagf)) {
+				DEBUG(("search: read failed\n"));
+				pagpos = -1;
+				sp->aborted = 1;
+				return(NOTFOUND);
+			} else
+				value = VACANT;
+
+			/* and finish up */
+			pagpos += sizeof(val);
+		}
+
+		/* vacant slot is always cause to return */
+		if (value == VACANT) {
+			DEBUG(("search: empty slot\n"));
+			return(NOTFOUND);
+		};
+
+		/* check the tag */
+		value = UNBIAS(value);
+		DEBUG(("got 0x%lx\n", value));
+		if (!HASTAG(value)) {
+			DEBUG(("tagless\n"));
+			return(value);
+		} else if (TAG(value) == sp->tag) {
+			DEBUG(("match\n"));
+			return(NOTAG(value));
+		} else {
+			DEBUG(("mismatch 0x%lx\n", TAG(value)));
+		}
+	}
+	/* NOTREACHED */
+}
+
+/*
+ - okayvalue - check that a value can be stored
+ */
+static int			/* predicate */
+okayvalue(value)
+of_t value;
+{
+	if (HASTAG(value))
+		return(0);
+#ifdef OVERFLOW
+	if (value == LONG_MAX)	/* BIAS() and UNBIAS() will overflow */
+		return(0);
+#endif
+	return(1);
+}
+
+/*
+ - set - store a value into a location previously found by search
+ */
+static int			/* 0 success, -1 failure */
+set(sp, value)
+register struct searcher *sp;
+of_t value;
+{
+	register of_t place = sp->place;
+	register of_t v = value;
+
+	if (sp->aborted)
+		return(-1);
+
+	if (CANTAG(v) && !conf.olddbz) {
+		v |= sp->tag | taghere;
+		if (v != UNBIAS(VACANT))	/* BIAS(v) won't look VACANT */
+#ifdef OVERFLOW
+			if (v != LONG_MAX)	/* and it won't overflow */
+#endif
+			value = v;
+	} else if (!conf.olddbz)
+		conf.ntagless[0]++;
+	DEBUG(("tagged value is 0x%lx\n", value));
+	value = BIAS(value);
+	value = MAPOUT(value);
+
+	/* If we have the index file in memory, use it */
+	if (corepag != NULL && place < conf.tsize) {
+		corepag[place] = value;
+		DEBUG(("set: incore\n"));
+		if (!writethrough)
+			return(0);
+	}
+
+	/* seek to spot */
+	pagpos = -1;		/* invalidate position memory */
+	if (fseek(pagf, place * (of_t)SOF, SEEK_SET) != 0) {
+		DEBUG(("set: seek failed\n"));
+		sp->aborted = 1;
+		return(-1);
+	}
+
+	/* write in data */
+	if (fwrite((char *)&value, SOF, 1, pagf) != 1) {
+		DEBUG(("set: write failed\n"));
+		sp->aborted = 1;
+		return(-1);
+	}
+	/* fflush improves robustness, and buffer re-use is rare anyway */
+	if (fflush(pagf) == EOF) {
+		DEBUG(("set: fflush failed\n"));
+		sp->aborted = 1;
+		return(-1);
+	}
+
+	DEBUG(("set: succeeded\n"));
+	return(0);
+}
+
+/*
+ - mybytemap - determine this machine's byte map
+ *
+ * A byte map is an array of ints, sizeof(of_t) of them.  The 0th int
+ * is the byte number of the high-order byte in my of_t, and so forth.
+ */
+static void
+mybytemap(map)
+int map[];			/* -> int[SOF] */
+{
+	union {
+		of_t o;
+		char c[SOF];
+	} u;
+	register int *mp = &map[SOF];
+	register int ntodo;
+	register int i;
+
+	u.o = 1;
+	for (ntodo = (int)SOF; ntodo > 0; ntodo--) {
+		for (i = 0; i < SOF; i++)
+			if (u.c[i] != 0)
+				break;
+		if (i == SOF) {
+			/* trouble -- set it to *something* consistent */
+			DEBUG(("mybytemap: nonexistent byte %d!!!\n", ntodo));
+			for (i = 0; i < SOF; i++)
+				map[i] = i;
+			return;
+		}
+		DEBUG(("mybytemap: byte %d\n", i));
+		*--mp = i;
+		while (u.c[i] != 0)
+			u.o <<= 1;
+	}
+}
+
+/*
+ - bytemap - transform an of_t from byte ordering map1 to map2
+ */
+static of_t			/* transformed result */
+bytemap(ino, map1, map2)
+of_t ino;
+int *map1;
+int *map2;
+{
+	union oc {
+		of_t o;
+		char c[SOF];
+	};
+	union oc in;
+	union oc out;
+	register int i;
+
+	in.o = ino;
+	for (i = 0; i < SOF; i++)
+		out.c[map2[i]] = in.c[map1[i]];
+	return(out.o);
+}
+
+/*
+ * This is a simplified version of the pathalias hashing function.
+ * Thanks to Steve Belovin and Peter Honeyman
+ *
+ * hash a string into a long int.  31 bit crc (from andrew appel).
+ * the crc table is computed at run time by crcinit() -- we could
+ * precompute, but it takes 1 clock tick on a 750.
+ *
+ * This fast table calculation works only if POLY is a prime polynomial
+ * in the field of integers modulo 2.  Since the coefficients of a
+ * 32-bit polynomial won't fit in a 32-bit word, the high-order bit is
+ * implicit.  IT MUST ALSO BE THE CASE that the coefficients of orders
+ * 31 down to 25 are zero.  Happily, we have candidates, from
+ * E. J.  Watson, "Primitive Polynomials (Mod 2)", Math. Comp. 16 (1962):
+ *	x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + x^0
+ *	x^31 + x^3 + x^0
+ *
+ * We reverse the bits to get:
+ *	111101010000000000000000000000001 but drop the last 1
+ *         f   5   0   0   0   0   0   0
+ *	010010000000000000000000000000001 ditto, for 31-bit crc
+ *	   4   8   0   0   0   0   0   0
+ */
+
+#define POLY 0x48000000L	/* 31-bit polynomial (avoids sign problems) */
+
+static long CrcTable[128];
+
+/*
+ - crcinit - initialize tables for hash function
+ */
+static void
+crcinit()
+{
+	register int i, j;
+	register long sum;
+
+	for (i = 0; i < 128; ++i) {
+		sum = 0L;
+		for (j = 7 - 1; j >= 0; --j)
+			if (i & (1 << j))
+				sum ^= POLY >> j;
+		CrcTable[i] = sum;
+	}
+	DEBUG(("crcinit: done\n"));
+}
+
+/*
+ - hash - Honeyman's nice hashing function
+ */
+static long
+hash(name, size)
+register char *name;
+register int size;
+{
+	register long sum = 0L;
+
+	while (size--) {
+		sum = (sum >> 7) ^ CrcTable[(sum ^ (*name++)) & 0x7f];
+	}
+	DEBUG(("hash: returns (%ld)\n", sum));
+	return(sum);
+}
+
+/*
+ * case-mapping stuff
+ *
+ * Borrowed from C News, by permission of the authors.  Somewhat modified.
+ *
+ * We exploit the fact that we are dealing only with headers here, and
+ * headers are limited to the ASCII characters by RFC822.  It is barely
+ * possible that we might be dealing with a translation into another
+ * character set, but in particular it's very unlikely for a header
+ * character to be outside -128..255.
+ *
+ * Life would be a whole lot simpler if tolower() could safely and portably
+ * be applied to any char.
+ */
+
+#define	OFFSET	128		/* avoid trouble with negative chars */
+
+/* must call casencmp before invoking TOLOW... */
+#define	TOLOW(c)	(cmap[(c)+OFFSET])
+
+/* ...but the use of it in CISTREQN is safe without the preliminary call (!) */
+/* CISTREQN is an optimised case-insensitive strncmp(a,b,n)==0; n > 0 */
+#define CISTREQN(a, b, n) \
+	(TOLOW((a)[0]) == TOLOW((b)[0]) && casencmp(a, b, n) == 0)
+
+#define	MAPSIZE	(256+OFFSET)
+static char cmap[MAPSIZE];	/* relies on init to '\0' */
+static int mprimed = 0;		/* has cmap been set up? */
+
+/*
+ - mapprime - set up case-mapping stuff
+ */
+static void
+mapprime()
+{
+	register char *lp;
+	register char *up;
+	register int c;
+	register int i;
+	static char lower[] = "abcdefghijklmnopqrstuvwxyz";
+	static char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+	for (lp = lower, up = upper; *lp != '\0'; lp++, up++) {
+		c = *lp;
+		cmap[c+OFFSET] = c;
+		cmap[*up+OFFSET] = c;
+	}
+	for (i = 0; i < MAPSIZE; i++)
+		if (cmap[i] == '\0')
+			cmap[i] = (char)(i-OFFSET);
+	mprimed = 1;
+}
+
+/*
+ - casencmp - case-independent strncmp
+ */
+static int			/* < == > 0 */
+casencmp(s1, s2, len)
+char *s1;
+char *s2;
+int len;
+{
+	register char *p1;
+	register char *p2;
+	register int n;
+
+	if (!mprimed)
+		mapprime();
+
+	p1 = s1;
+	p2 = s2;
+	n = len;
+	while (--n >= 0 && *p1 != '\0' && TOLOW(*p1) == TOLOW(*p2)) {
+		p1++;
+		p2++;
+	}
+	if (n < 0)
+		return(0);
+
+	/*
+	 * The following case analysis is necessary so that characters
+	 * which look negative collate low against normal characters but
+	 * high against the end-of-string NUL.
+	 */
+	if (*p1 == '\0' && *p2 == '\0')
+		return(0);
+	else if (*p1 == '\0')
+		return(-1);
+	else if (*p2 == '\0')
+		return(1);
+	else
+		return(TOLOW(*p1) - TOLOW(*p2));
+}
+
+/*
+ - mapcase - do case-mapped copy
+ */
+static char *			/* returns src or dst */
+mapcase(dst, src, siz)
+char *dst;			/* destination, used only if mapping needed */
+char *src;			/* source; src == dst is legal */
+size_t siz;
+{
+	register char *s;
+	register char *d;
+	register char *c;	/* case break */
+	register char *e;	/* end of source */
+
+
+	c = cipoint(src, siz);
+	if (c == NULL)
+		return(src);
+
+	if (!mprimed)
+		mapprime();
+	s = src;
+	e = s + siz;
+	d = dst;
+
+	while (s < c)
+		*d++ = *s++;
+	while (s < e)
+		*d++ = TOLOW(*s++);
+
+	return(dst);
+}
+
+/*
+ - cipoint - where in this message-ID does it become case-insensitive?
+ *
+ * The RFC822 code is not quite complete.  Absolute, total, full RFC822
+ * compliance requires a horrible parsing job, because of the arcane
+ * quoting conventions -- abc"def"ghi is not equivalent to abc"DEF"ghi,
+ * for example.  There are three or four things that might occur in the
+ * domain part of a message-id that are case-sensitive.  They don't seem
+ * to ever occur in real news, thank Cthulhu.  (What?  You were expecting
+ * a merciful and forgiving deity to be invoked in connection with RFC822?
+ * Forget it; none of them would come near it.)
+ */
+static char *			/* pointer into s, or NULL for "nowhere" */
+cipoint(s, siz)
+char *s;
+size_t siz;
+{
+	register char *p;
+	static char post[] = "postmaster";
+	static int plen = sizeof(post)-1;
+
+	switch (conf.casemap) {
+	case '0':		/* unmapped, sensible */
+		return(NULL);
+		break;
+	case 'C':		/* C News, RFC 822 conformant (approx.) */
+		p = memchr(s, '@', siz);
+		if (p == NULL)			/* no local/domain split */
+			return(NULL);		/* assume all local */
+		if (p - (s+1) == plen && CISTREQN(s+1, post, plen)) {
+			/* crazy -- "postmaster" is case-insensitive */
+			return(s);
+		}
+		return(p);
+		break;
+	case '=':		/* 2.11, neither sensible nor conformant */
+		return(s);	/* all case-insensitive */
+		break;
+	}
+
+	DEBUG(("cipoint: unknown case mapping `%c'\n", conf.casemap));
+	return(NULL);		/* just leave it alone */
+}
+
+/*
+ - dbzdebug - control dbz debugging at run time
+ */
+int				/* old value */
+dbzdebug(value)
+int value;
+{
+#ifdef DBZDEBUG
+	register int old = debug;
+
+	debug = value;
+	return(old);
+#else
+	return(-1);
+#endif
+}
--- /dev/null
+++ suck-4.3.2/include/dbz.h
@@ -0,0 +1,39 @@
+/* for dbm and dbz */
+typedef struct {
+	char *dptr;
+	int dsize;
+} datum;
+
+/* standard dbm functions */
+extern int dbminit();
+extern datum fetch();
+extern int store();
+extern int delete();		/* not in dbz */
+extern datum firstkey();	/* not in dbz */
+extern datum nextkey();		/* not in dbz */
+extern int dbmclose();		/* in dbz, but not in old dbm */
+
+/* new stuff for dbz */
+extern int dbzdbminit();
+extern datum dbzdbmfetch();
+extern int dbzdbmstore();
+extern int dbzdbmclose();
+extern int dbzfresh();
+extern int dbzagain();
+extern datum dbzfetch();
+extern int dbzstore();
+extern int dbzsync();
+extern long dbzsize();
+extern long dbztagmask();
+extern int dbzincore();
+extern int dbzwritethrough();
+extern void (*dbzfiledesc())();
+extern int dbzcancel();
+extern int dbzdebug();
+
+/*
+ * In principle we could handle unlimited-length keys by operating a chunk
+ * at a time, but it's not worth it in practice.  Setting a nice large
+ * bound on them simplifies the code and doesn't hurt anything.
+ */
+#define DBZMAXKEY	255
