[comp.sources.unix] v19i082: Cnews production release, Part05/19

rsalz@uunet.uu.net (Rich Salz) (06/27/89)

Submitted-by: utzoo!henry
Posting-number: Volume 19, Issue 82
Archive-name: cnews2/part05

: ---CUT HERE---
echo 'batch/sendbatches':
sed 's/^X//' >'batch/sendbatches' <<'!'
X#! /bin/sh
X# Master batching control.
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/batch:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xorigpath="$PATH"
X
Xparms=$NEWSCTL/batchparms
Xlog=$NEWSCTL/batchlog		# also same with suffixes .o and .oo
X
X# lock against multiple simultaneous execution
Xlock="$NEWSCTL/LOCKbatch"
Xltemp="$NEWSCTL/L.$$"
Xecho $$ >$ltemp
Xtrap "rm -f $ltemp ; exit 0" 0 1 2 15
Xif newslock $ltemp $lock
Xthen
X	trap "rm -f $ltemp $lock ; exit 0" 0 1 2 15
Xelse
X	exit 0
Xfi
X
Xcd $NEWSARTS/out.going
X
X# Determine what systems are being requested, in what order.
Xcase "$1"
Xin
X	-d)
X	debug=yes
X	shift
X	;;
Xesac
Xcase $#
Xin
X	0)
X	if egrep '^/default/[ 	]' $parms >/dev/null	# default line found
X	then
X		syses=`ls -tr | egrep -v '^[@.]'`	# oldest first
X	else
X		syses="`egrep '^[^/#]' $parms | awk '{ print $1 }'`"
X	fi
X	;;
X
X	*)
X	syses="$*"
X	;;
Xesac
Xcase $debug
Xin
X	yes)
X	for sys in $syses
X	do
X		echo $sys
X	done
X	exit 0
X	;;
Xesac
X
X# Start up logging.
Xmv $log.o $log.oo
Xmv $log $log.o
Xdate >$log
X
X# Run through them.
Xfor sys in $syses
Xdo
X	# Move into his directory, include it in search path.
X	here=$NEWSARTS/out.going/$sys
X	if test ! -d $here
X	then
X		echo "$0: cannot find batch directory for \`$sys'" >>$log
X		continue
X	fi
X	cd $here
X	PATH=$here:$origpath ; export PATH
X	NEWSSITE=$sys ; export NEWSSITE		# For site-specific programs.
X
X	# Is there anything to do?
X	files=`echo togo*`
X	if test "$files" = 'togo*' || test "$files" = "togo" -a ! -s togo
X	then
X		continue			# no
X	fi
X
X	# Pick up the batchparms line.
X	ctlline="`egrep \"^$sys[ 	]\" $parms | sed 1q`"
X	if test " $ctlline" = " "
X	then
X		ctlline="`egrep '^/default/[ 	]' $parms | sed 1q`"
X	fi
X	set $ctlline
X	if test " $#" -ne 6
X	then
X		echo "$0: bad or missing batchparms line for \`$sys'" >>$log
X		continue
X	fi
X	batchsize=$2
X	limit=$3
X	batcher=$4
X	muncher=$5
X	sender=$6
X
X	# How many to send?
X	outstand=`queuelen $sys`
X	nbatch=`expr $limit - $outstand`
X	roomfor=`spacefor $batchsize outbound $sys`
X	if test " $nbatch" -gt " $roomfor"
X	then
X		nbatch=$roomfor
X	fi
X
X	# If not allowed to send, remember reason.
X	status='batches flowing'
X	if test " $nbatch" -le 0
X	then
X		if test " $roomfor" -le 0
X		then
X			status='disk too full for batching'
X		else
X			status='queue full, no recent movement'
X		fi
X	fi
X
X	# Try sending some.
X	while test " $nbatch" -gt 0
X	do
X		# Does he have batches prepared already?
X		if test "`echo togo.[0-9]`" = 'togo.[0-9]'
X		then
X			# No -- need some more batches.
X			if test ! -s togo && test ! -s togo.next
X			then
X				break		# Nothing left to do.
X			fi
X			batchsplit $batchsize
X		fi
X
X		# Send some batches.
X		them=`ls | egrep '^togo\.[0-9]' | sed "${nbatch}q"`
X		for f in $them
X		do
X			if $batcher -d $NEWSARTS $f | $muncher | $sender $sys
X			then
X				rm $f
X			else
X				echo "$0: batching for \`$sys' failed" >>$log
X				exit 1
X			fi
X		done
X		ndone=`echo $them | wc -w`
X		nbatch=`expr $nbatch - $ndone`
X
X		# Recheck the space -- it can fall for other reasons.
X		roomfor=`spacefor $batchsize outbound $sys`
X		if test " $nbatch" -gt " $roomfor"
X		then
X			nbatch=$roomfor
X		fi
X	done
X
X	# Report status, if appropriate.
X	nart=`cat togo* | wc -l | awk '{print $1}'`
X	if test " $nart" -gt 0
X	then
X		echo "$sys	backlog $nart ($status)" >>$log
X	fi
Xdone
!
echo 'batch/batchih':
sed 's/^X//' >'batch/batchih' <<'!'
X#! /bin/sh
X# ihave batch preparer
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/batch:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xcase "$1"
Xin
X	-d)
X	shift ; shift		# ignore -d option
X	;;
Xesac
X
Xdest=`expr "$NEWSSITE" : "^\([^.]*\)\.ihave$"`
Xcase "$dest"
Xin
X	'')
X	dest="$NEWSSITE"
X	;;
Xesac
Xme="`newshostname`"
X
Xecho "Newsgroups: to.$dest"
Xecho "Subject: ihave $me"
Xecho "Control: ihave $me"
Xecho
Xexec cat $*
!
echo 'batch/compcun':
sed 's/^X//' >'batch/compcun' <<'!'
X#! /bin/sh
X# Invoke compress, adding silly 2.11-compatible header.
X# 12-bit compression is the lowest common denominator among news sites,
X# and is often almost as good as the much-more-costly 16-bit compression.
X
Xecho "#! cunbatch"
Xcompress -b 12
Xstatus=$?
Xcase "$status"
Xin
X	2)
X	status=0		# compress stupidity
X	;;
Xesac
Xexit $status
!
echo 'batch/batcher.c':
sed 's/^X//' >'batch/batcher.c' <<'!'
X/*
X * batcher - send a bunch of news articles as an unbatch script
X *
X * Usage: batcher [-d dir] listfile
X *
X *	where listfile is a file containing a list, one per line, of
X *	full pathnames of files containing articles.  Only the first
X *	field of each line is looked at, so there can be more if needed
X *	for other things.
X *
X *	The -d option specifies a directory where most articles are
X *	likely to be; the program chdirs there to speed things up.
X */
X
X#include <stdio.h>
X#include <string.h>
X#include <signal.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "fgetmfs.h"
X
X#ifndef READSIZE
X#define READSIZE 8192	/* allows for even 4.2 worst case file systems */
X#endif
Xchar buffer[READSIZE];
X
Xchar *progname;
X
Xchar *dir = NULL;		/* NULL means don't bother chdiring. */
Xint dirlen;			/* strlen(dir) */
Xint debug = 0;			/* Debugging? */
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int c;
X	int errflg = 0;
X	extern int optind;
X	extern char *optarg;
X	register FILE *list;
X	char *article;
X	int ret;
X
X	progname = argv[0];
X	while ((c = getopt(argc, argv, "d:x")) != EOF)
X		switch (c) {
X		case 'd':	/* Directory containing many articles. */
X			dir = optarg;
X			dirlen = strlen(dir);
X			break;
X		case 'x':	/* Debugging. */
X			debug++;
X			break;
X		case '?':
X		default:
X			errflg++;
X			break;
X		}
X	if (errflg || optind != argc-1) {
X		(void) fprintf(stderr,
X			"Usage: batcher [-d dir] listfile\n");
X		exit(2);
X	}
X
X	list = fopen(argv[optind], "r");
X	if (list == NULL)
X		error("unable to open `%s'", argv[optind]);
X
X	if (dir != NULL)
X		if (chdir(dir) < 0)
X			error("can't chdir to `%s'", dir);
X
X	while ((article = fgetms(list)) != NULL) {
X		process(article);
X		free(article);
X	}
X	if (!feof(list))
X		error("fgetmfs failure", "");
X
X	exit(0);
X}
X
X/*
X - process - process an article
X */
Xprocess(article)
Xchar *article;
X{
X	char *p;
X	register int artfile;
X	register int count;
X	struct stat sbuf;
X
X	*(article + strcspn(article, "\n\t ")) = '\0';
X	if (dir != NULL && strncmp(article, dir, dirlen) == 0 &&
X			article[dirlen] == '/')
X		p = article+dirlen+1;
X	else
X		p = article;
X
X	artfile = open(p, 0);
X	if (artfile < 0) {
X		/*
X		 * Can't read the article.  This isn't necessarily a
X		 * disaster, since things like cancellations will do
X		 * this.  Mumble and carry on.
X		 */
X		if (debug)
X			warning("can't find `%s'", p);
X		return;
X	}
X
X	if (fstat(artfile, &sbuf) < 0)
X		error("internal disaster, can't fstat", "");
X	if ((sbuf.st_mode&S_IFMT) != S_IFREG) {
X		close(artfile);
X		return;		/* Don't try to batch directories etc. */
X	}
X
X	(void) printf("#! rnews %ld\n", sbuf.st_size);
X	fflush(stdout);
X
X	while ((count = read(artfile, buffer, sizeof buffer)) > 0)
X		if (write(1, buffer, count) != count)
X			error("write failure in `%s'", article);
X	if (count < 0)
X		error("read failure in `%s'", article);
X
X	(void) close(artfile);
X}
!
echo 'batch/c7encode.c':
sed 's/^X//' >'batch/c7encode.c' <<'!'
X#include <stdio.h>
X
X#ifdef SCCSID
Xstatic char	*SccsId = "@(#)encode.c	1.3	5/15/85";
X#endif /* SCCSID */
X
X/*
X * Produce a 7 bit printable encoding of stdin on stdout.
X *
X * Encoding uses acsii chars from ' ' .. 'z'
X * (040 .. 0172) (0x20 - 0x7a) inclusive
X *
X * Method is to expand 3 chars -> 4 6 bit ones.
X * Then collect 13 6 bit chars, and spread the 13th over
X * the preceding 12, so that each of the 12 chars is now
X * 6.5 bits.  These 2 6.5 bit chars are a little hard
X * to represent on most common machines (one of these days
X * sane hosts will have 1/2 bits just for this program)
X * so we take a pair of them, and represent that in 13 bits.
X * 13 bits (max value 8191) can be represented as
X *	A * 91 + B
X * where A < 91, B < 91  (91^2 == 8281, so it fits!)
X *
X * Each of A and B is encoded as a character by adding 32
X * to make it printable (ie: 0x20).
X *
X * The termination conditions are foul beyond belief.  Don't
X * monkey with them!
X *
X * If you think its a fluke that 040 .. 0171 just happen to
X * be the chars that Piet Beertema's uucp 'f' protocol transmits
X * as single bytes, you're insane.  0172 chars are produced
X * with lower frequency than any other (given random data)
X * so the doubling that occurs with that we will just suffer.
X * (A newer 'f' proto, sometime, will probably not use 0172)
X */
X
X/*
X * the following pair of characters cannot legally occur
X * in normal output (since 90*91 + 90 == 8280, which > 2^13)
X * so we use them to indicate that the data that follows is the
X * terminator.  The character immediately following this
X * pair is the length of the (expanded) terminator (which
X * otherwise might be indeterminable)
X */
X#define	ENDMARK1	((90*91 + 90) / 91 + ' ')
X#define	ENDMARK2	((90*91 + 90) % 91 + ' ')
X
Xmain()
X{
X	register char *p;
X	register char *e;
X	register c;
X	char b3[3];
X
X	p = b3;
X	e = b3 + 3;
X	while ((c = getchar()) != EOF) {
X		*p++ = c;
X		if (p == e) {
X			encode(b3, 3);
X			p = b3;
X		}
X	}
X	encode(b3, p - b3);
X	flushout();
X	exit(0);
X}
X
Xstatic char b13[13];
Xstatic int cnt = 0;
X
Xencode(c, n)
X	register char *c;
X	int n;
X{
X	register char *p;
X	register i = cnt;
X	register j;
X	char b4[4];
X
X	p = b4;
X
X	p[0] = (c[0] >> 2) & 0x3f;
X	p[1] = ((c[0] & 0x3) << 4) | ((c[1] >> 4) & 0xf);
X	p[2] = ((c[1] & 0xF) << 2) | ((c[2] >> 6) & 0x3);
X	if (n == 3)
X		p[3] = c[2] & 0x3f;
X	else
X		p[3] = n;
X
X	c = &b13[i];
X	for (j = 4; --j >= 0; i++) {
X		if (i == 13) {
X			dumpcode(b13, 13);
X			c = b13;
X			i = 0;
X		}
X		*c++ = *p++;
X	}
X	cnt = i;
X}
X
Xflushout()
X{
X	putchar(ENDMARK1);
X	putchar(ENDMARK2);
X	putchar(cnt + ' ');
X	dumpcode(b13, cnt);
X}
X
Xdumpcode(p, n)
X	register char *p;
X	register int n;
X{
X	register last;
X	register c;
X
X	if (n == 13)
X		n--, last = p[12];
X	else if (n & 1)
X		last = (1 << (6-1));
X	else
X		last = 0;
X
X	for ( ; n > 0; n -= 2) {
X		c = *p++ << 6;
X		c |= *p++;
X		if (last & (1 << (6-1)))
X			c |= (1 << 12);
X		last <<= 1;
X
X		/*
X		 * note: 91^2 > 2^13, 90^2 < 2^13, (91 + ' ') is printable
X		 */
X
X		/* oh for a compiler that would only do one division... */
X		putchar((c / 91) + ' ');
X		putchar((c % 91) + ' ');
X	}
X}
!
echo 'batch/coder.h':
sed 's/^X//' >'batch/coder.h' <<'!'
Xchar header[] = "Decode the following with bdecode\n";
Xchar codeset[] =
X	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-";
X
X#define ENCODE(c)	codeset[c]
X
Xextern short crctab[];
X#define CRC(crc, c)	 crc = (crc >> 8) ^ crctab[(crc^c) & 0xff]
!
echo 'batch/viamail':
sed 's/^X//' >'batch/viamail' <<'!'
X#! /bin/sh
X# send via mail, unprotected (typically used for bencode output only)
X
X( echo ; cat ) | mail $1!rnews
!
echo 'batch/viainews':
sed 's/^X//' >'batch/viainews' <<'!'
X#! /bin/sh
X# Feed batch to inews, for ihave/sendme mostly.
X
Xexec inews -h -W
!
echo 'batch/nocomp':
sed 's/^X//' >'batch/nocomp' <<'!'
X#! /bin/sh
X# Null muncher, for uncompressed links.
X
Xexec cat $*
!
echo 'batch/bencode.c':
sed 's/^X//' >'batch/bencode.c' <<'!'
X/*
X * bencode [file]
X */
X#include <stdio.h>
X#include "coder.h"
X#define MAXPERLINE 78		/* max chars/line */
Xchar *myname;
X
Xmain(argc,argv) 
X	char **argv;
X{
X	register FILE *fin = stdin, *fout = stdout; /* faster in a register */
X	register int c, bcount, ccount = MAXPERLINE-1;
X	register long word, nbytes;
X	register int crc;
X
X	myname = argv[0];
X	if (sizeof(word) < 4)
X		fprintf(stderr, "%s: word size too small\n", myname), exit(1);
X	if (argc == 2 && (fin = fopen(argv[1], "r")) == NULL) {
X		fprintf(stderr, "%s: ", myname);
X		perror(argv[1]);
X		exit(1);
X	}
X	else if (argc > 2) {
X		fprintf(stderr, "Usage: %s [file]\n", myname);
X		exit(1);
X	}
X
X#define PUTC(c) \
X	putc(c, fout); \
X	if (--ccount == 0) { \
X		putc('\n', fout); \
X		ccount = MAXPERLINE-1; \
X	}
X
X	fputs(header, fout);
X	word = 0;
X	bcount = 3;
X	crc = 0;
X	for (nbytes = 0; (c = getc(fin)) != EOF; nbytes++) {
X		CRC(crc, c);
X		word <<= 8;
X		word |= c;
X		if (--bcount == 0) {
X			PUTC(ENCODE((word >> 18) & 077));
X			PUTC(ENCODE((word >> 12) & 077));
X			PUTC(ENCODE((word >>  6) & 077));
X			PUTC(ENCODE((word      ) & 077));
X			word = 0;
X			bcount = 3;
X		}
X	}
X	/*
X	 * A trailing / marks end of data.
X	 * The last partial encoded word follows in hex,
X	 * preceded by a byte count.
X	 */
X	if (ccount != MAXPERLINE-1)	/* avoid empty lines */
X		putc('\n', fout);
X	fprintf(fout, "/%d%x\n", 3-bcount, word);
X	/*
X	 * And finally the byte count and CRC.
X	 */
X	fprintf(fout, "%ld %x\n", nbytes, crc & 0xffff);
X	exit(0);
X}
!
echo 'batch/crctab.c':
sed 's/^X//' >'batch/crctab.c' <<'!'
X/* generated using the CRC-16 polynomial x^16 + x^15 + x^2 + 1 = 0120001 */
Xshort crctab[256] = {
X	0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
X	0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
X	0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
X	0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
X	0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
X	0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
X	0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
X	0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
X	0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
X	0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
X	0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
X	0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
X	0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
X	0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
X	0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
X	0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
X	0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
X	0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
X	0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
X	0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
X	0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
X	0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
X	0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
X	0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
X	0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
X	0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
X	0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
X	0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
X	0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
X	0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
X	0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
X	0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
X};
!
echo 'batch/compb':
sed 's/^X//' >'batch/compb' <<'!'
X#! /bin/sh
X# like comp except use bencode
X
X# =()<. ${NEWSCONFIG-@<NEWSCONFIG>@}>()=
X. ${NEWSCONFIG-/usr/lib/news/bin/config}
X
XPATH=$NEWSCTL/bin:$NEWSBIN/batch:$NEWSBIN:$NEWSPATH ; export PATH
Xumask $NEWSUMASK
X
Xcompress -b 12 | bencode
Xexit 0				# compress exit status sometimes stupid
!
echo 'batch/viapmail':
sed 's/^X//' >'batch/viapmail' <<'!'
X#! /bin/sh
X# send via mail (protected against stupid mailers)
X
X( echo ; sed 's/^/N/' ) | mail $1!rnews
!
echo 'contrib/putenv.alt.c':
sed 's/^X//' >'contrib/putenv.alt.c' <<'!'
X/*
X * From: chip@ateng.ateng.com (Chip Salzenberg)
X * Newsgroups: comp.unix.wizards
X * Subject: Re: replacement for putenv()
X * Date: 13 Feb 89 16:51:05 GMT
X * 
X * Here is a rather nice replacement for putenv().  I wrote it for the BSD port
X * of my deliver program.  (I know it's source, but it's short.)  Its nicest
X * feature is the avoidance of memory waste when it is called several times.
X */
X
Xint
Xputenv(s)
Xchar *s;
X{
X	static char **env_array;
X	static int env_size;
X	char *e;
X	int i, j;
X
X	if (env_array == NULL) {
X		for (i = 0; environ[i]; ++i)
X			;
X		env_size = i + 10;   	   /* arbitrary */
X		env_array = (char **) malloc(env_size * sizeof(char *));
X		if (env_array == NULL)
X			return 1;
X		memcpy((char *)env_array, (char *)environ,
X		       (int) ((i + 1) * sizeof(char *)));
X		environ = env_array;
X	} else if (environ != env_array)
X		fprintf(stderr, "putenv: warning: someone moved environ!\n");
X
X	if ((e = strchr(s, '=')) != NULL)
X		++e;
X	else
X		e = s + strlen(s);
X
X	j = 0;
X	for (i = 0; env_array[i]; ++i)
X		if (strncmp(env_array[i], s, e - s) != 0)
X			env_array[j++] = env_array[i];
X
X	if (j + 1 >= env_size) {
X		env_size += 10;                 /* arbitrary */
X		env_array = (char **) realloc((char *)env_array,
X					env_size * sizeof(char **));
X		if (env_array == NULL)
X			return 1;
X	}
X
X	env_array[j++] = s;
X	env_array[j] = NULL;
X
X	environ = env_array;
X	return 0;
X}
!
echo 'contrib/dbz':
sed 's/^X//' >'contrib/dbz' <<'!'
XFrom utgpu!jarvis.csri.toronto.edu!mailrus!sharkey!b-tech!zeeff Tue Feb  7 17:19:31 EST 1989
XArticle: 1900 of news.software.b:
XPath: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!sharkey!b-tech!zeeff
XFrom: zeeff@b-tech.ann-arbor.mi.us (Jon Zeeff)
XNewsgroups: news.software.b
XSubject: Re: Dbz and news 2.11
XMessage-ID: <5095@b-tech.ann-arbor.mi.us>
XDate: 4 Feb 89 18:56:09 GMT
XReferences: <20@bungia.Bungia.MN.ORG>
XReply-To: zeeff@b-tech.ann-arbor.mi.us (Jon Zeeff)
XDistribution: usa
XOrganization: Branch Technology Ann Arbor, MI
XLines: 322
X
XIn article <20@bungia.Bungia.MN.ORG> ahby@bungia.MN.ORG (Shane P. McCarron) writes:
X>Some time ago the dbz sources were posted for use with news 2.11.
X>Patches have been posted, and a number of sites are using these
X>routines to make news run faster on machines without dbm libraries.  I
X>seem to remember some controversy surrounding the use of these
X>routines.  Something about their containing AT&T proprietary stuff?  I
X>realize that by asking this I am going to get a hundred answers, all
X>of them different.  What I am really looking for is ONE AUTHORITATIVE
X>ANSWER.  Can anyone out there say for sure whether this code is freely
X>distributable or not?
X
XAs the author, I suppose I can supply an authorative answer.  Dbz 
Xcontains no AT&T code at all.  The only thing in it not written by me 
Xis the hashing, and that is taken from pathalias (with permission).  
X
XHere it is if anyone missed it:
X
X
X/*
Xdbz.c  V1.5
X
XCopyright 1988 Jon Zeeff (umix!b-tech!zeeff)
XYou can use this code in any manner, as long as you leave my name on it
Xand don't hold me responsible for any problems with it.
X
XHacked on by gdb@ninja.UUCP (David Butler); Sun Jun  5 00:27:08 CDT 1988
X
XThese routines replace dbm as used by the usenet news software
X(it's not a full dbm replacement by any means).  It's fast and
Xsimple.  It contains no AT&T code.
X
XBSD sites will notice some savings in disk space.  Sys V sites without
Xdbm will notice much faster operation.
X
XNote: .pag files created by version 1.[0-3] need to be recreated before
X      using this version.
X
XThis code relies on the fact that news stores a pointer to the history
Xfile as the dbm data.  It doesn't store another copy of the key like
Xdbm does so it saves disk space.  All you can do is fetch() and
Xstore() data.
X
XJust make news with the DBM option and link with dbz.o.
X*/
X
X/*
X   Set this to the something several times larger than the maximum # of
X   lines in a history file.  It should be a prime number.
X*/
X#define INDEX_SIZE 99991L
X
X#define DEBUG if (0) printf	          /* for no debugging */
X/* #define DEBUG if (1) printf		  /* for debugging */
X/* #define DEBUG if (debug) printf        /* for "rn" type debugging */
X
X/* Note: let the optimizer remove any if(0) or if(1) code above */
X
X#include <fcntl.h>
X#include <string.h>
X#include <ctype.h>
X
Xlong lseek();
X
Xstatic long get_ptr();
Xstatic int put_ptr();
Xstatic void lcase();
Xstatic long hash();
Xstatic void crcinit();
X
Xtypedef struct {
X	char *dptr;
X	int dsize;
X} datum;
X
Xstatic int Data_fd;		/* points to /usr/lib/news/[n]history */
Xstatic int Index_fd = -1;	/* points to /usr/lib/news/[n]history.pag */
X
Xint 
Xdbminit(name)
Xchar *name;
X{
X        char index_file[1024];	/* index file name */
X	void crcinit();
X
X	if (Index_fd >= 0) {
X		DEBUG("dbminit: dbminit aready called once\n");
X		return(-1);    /* init already called once */
X	}
X
X	strcpy(index_file, name);
X	strcat(index_file, ".pag");
X
X	/* if we don't have permission to open the pag file for read/write */
X	/* then we may never attempt a store().  If we do, it will fail */
X
X	if ((Index_fd = open(index_file, O_RDWR)) < 0 &&
X	    (Index_fd = open(index_file, O_RDONLY)) < 0 &&
X	    (Index_fd = open(index_file, O_CREAT | O_RDWR, 0644)) < 0) 
X	{
X		DEBUG("dbminit: Index_file open failed\n");
X		return(-1);
X	}
X
X	if ((Data_fd = open(name, O_RDONLY)) < 0) {
X
X		/* The only time the data file does not exist is when */
X		/* expire is running (as "news") and it is ok to create it */
X		/* If we don't have "permission" the create will fail, too */
X
X		if (close(creat(name, 0644)) < 0 ||
X		    (Data_fd = open(name, O_RDONLY)) < 0) {
X			DEBUG("dbminit: Data_file open failed\n");
X			close(Index_fd);
X			Index_fd = -1;
X			return(-1);
X		}
X	}
X
X	crcinit();	/* initialize the crc table */
X	DEBUG("dbminit: succeeded\n");
X	return(0);
X}
X
Xint
Xdbmclose()
X{
X	if (Index_fd >= 0) {
X		close(Index_fd);
X		Index_fd = -1;
X		close(Data_fd);
X	}
X	DEBUG("dbmclose: succeeded\n");
X	return(0);
X}
X
X/* get an entry from the database */
Xdatum
Xfetch(key)
Xdatum key;
X{
X	long index_ptr;
X	long index_size = INDEX_SIZE;
X        char buffer[1024];
X	static long data_ptr;
X	datum output;
X	long hash();
X	long get_ptr();
X	void lcase();
X
X	DEBUG("fetch: (%s)\n", key.dptr);
X
X	for (index_ptr = hash(key.dptr, key.dsize);
X	    --index_size && (data_ptr = get_ptr(index_ptr)) >= 0L;
X	    index_ptr = ++index_ptr % INDEX_SIZE) {
X
X		lseek(Data_fd, data_ptr, 0);
X		read(Data_fd, buffer, (unsigned)key.dsize);
X
X		/* key should be article id and no tab */
X
X		/* lcase(buffer, key.dsize);	lcase is a B news botch */
X		if (buffer[key.dsize - 1] == '\t') {
X			buffer[key.dsize - 1] = '\0';
X		}
X
X		DEBUG("fetch: buffer (%s)\n", buffer);
X		if (strncmp(key.dptr, buffer, key.dsize) == 0) {
X			/* we found it */
X			output.dptr = (char *)&data_ptr;
X			output.dsize = sizeof(long);
X			DEBUG("fetch: successful\n");
X			return(output);
X		}
X	}
X
X	/* we didn't find it */
X
X	output.dptr = (char *)0;
X	output.dsize = 0;
X	DEBUG("fetch: failed\n");
X	return(output);
X}
X
X/* add an entry to the database */
Xstore(key, data)
Xdatum key;
Xdatum data;
X{
X	/* lint complains about a possible pointer alignment problem here */
X	/* it is not a problem because dptr is the first element of a */
X	/* structure and should be aligned for anything */
X	DEBUG("store: (%s, %ld)\n", key.dptr, *((long *)data.dptr));
X	return(put_ptr(hash(key.dptr, key.dsize), *((long *)data.dptr)));
X}
X
X/* get a data file pointer from the specified location in the index file */
X
Xstatic long
Xget_ptr(index_ptr)
Xlong index_ptr;
X{
X	long data_ptr;
X
X	DEBUG("get_ptr: (%ld)\n", index_ptr);
X
X	/* seek to where it should be */
X	lseek(Index_fd, (long)(index_ptr * sizeof(long)) ,0);
X
X	/* read it */
X	if (read(Index_fd, (char *)&data_ptr, sizeof(long)) != sizeof(long) ||
X	    data_ptr == 0L) {
X		DEBUG("get_ptr: failed\n");
X		return(-1L);
X	}
X	DEBUG("get_ptr: succeeded\n");
X	return(--data_ptr);	/* remove the offset we added in put_ptr */
X}
X
X/* put a data file pointer into the specified location in the index file */
X/* move down further if slots are full (linear probing) */
Xstatic
Xput_ptr(index_ptr, data_ptr)
Xlong index_ptr;
Xlong data_ptr;
X{
X	long get_ptr();
X	long index_size = INDEX_SIZE;
X
X	/* find an empty slot */
X	while (--index_size && get_ptr(index_ptr) >= 0L) {
X		index_ptr = ++index_ptr % INDEX_SIZE;
X	}
X
X	if (index_size == 0L) {
X		DEBUG("put_ptr: hash table overflow - failed\n");
X		return(-1);
X	}
X
X	/* seek to spot */
X	lseek(Index_fd, (long)(index_ptr * sizeof(long)), 0);
X
X	++data_ptr;   /* add one so that we can use 0 as no pointer */
X
X	/* write in data */
X	if (write(Index_fd, (char *)&data_ptr, sizeof(long)) != sizeof(long)) {
X		DEBUG("put_ptr: write failed\n");
X		return(-1);
X	}
X
X	DEBUG("put_ptr: succeeded\n");
X	return(0);
X}
X
Xstatic void
Xlcase(s, n)
Xregister char *s;
Xregister int n;
X{
X	for (; n > 0; --n, ++s) {
X		*s = tolower(*s);
X	}
X}
X
X/* This is a simplified version of the pathalias hashing function.
X * Thanks to Steve Belovin and Peter Honeyman
X *
X * hash a string into a long int.  31 bit crc (from andrew appel).
X * the crc table is computed at run time by crcinit() -- we could
X * precompute, but it takes 1 clock tick on a 750.
X *
X * This fast table calculation works only if POLY is a prime polynomial
X * in the field of integers modulo 2.  Since the coefficients of a
X * 32-bit polynomial won't fit in a 32-bit word, the high-order bit is
X * implicit.  IT MUST ALSO BE THE CASE that the coefficients of orders
X * 31 down to 25 are zero.  Happily, we have candidates, from
X * E. J.  Watson, "Primitive Polynomials (Mod 2)", Math. Comp. 16 (1962):
X *	x^32 + x^7 + x^5 + x^3 + x^2 + x^1 + x^0
X *	x^31 + x^3 + x^0
X *
X * We reverse the bits to get:
X *	111101010000000000000000000000001 but drop the last 1
X *         f   5   0   0   0   0   0   0
X *	010010000000000000000000000000001 ditto, for 31-bit crc
X *	   4   8   0   0   0   0   0   0
X */
X
X#define POLY 0x48000000L	/* 31-bit polynomial (avoids sign problems) */
X
Xstatic long CrcTable[128];
X
Xstatic void
Xcrcinit()
X{	register int i, j;
X	register long sum;
X
X	for (i = 0; i < 128; ++i) {
X		sum = 0L;
X		for (j = 7 - 1; j >= 0; --j)
X			if (i & (1 << j))
X				sum ^= POLY >> j;
X		CrcTable[i] = sum;
X	}
X	DEBUG("crcinit: done\n");
X}
X
Xstatic long
Xhash(name, size)
Xregister char *name;
Xregister int size;
X{
X	register long sum = 0L;
X
X	while (size--) {
X		sum = (sum >> 7) ^ CrcTable[(sum ^ (*name++)) & 0x7f];
X	}
X	DEBUG("hash: returns (%ld)\n", sum % INDEX_SIZE);
X	return(sum % INDEX_SIZE);
X}
X
X-- 
X  Jon Zeeff			zeeff@b-tech.ann-arbor.mi.us
X  Ann Arbor, MI			mailrus!b-tech!zeeff
X
X
!
echo 'contrib/dirfns':
sed 's/^X//' >'contrib/dirfns' <<'!'
Xecho 'directory.3':
Xsed 's/^X//' >'directory.3' <<'!'
XX.TH DIRECTORY 3 imported
XX.DA 9 Oct 1985
XX.SH NAME
XXopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations
XX.SH SYNOPSIS
XX.B #include <sys/types.h>
XX.br
XX.B #include <ndir.h>
XX.PP
XX.SM
XX.B DIR
XX.B *opendir(filename)
XX.br
XX.B char *filename;
XX.PP
XX.SM
XX.B struct direct
XX.B *readdir(dirp)
XX.br
XX.B DIR *dirp;
XX.PP
XX.SM
XX.B long
XX.B telldir(dirp)
XX.br
XX.B DIR *dirp;
XX.PP
XX.SM
XX.B seekdir(dirp, loc)
XX.br
XX.B DIR *dirp;
XX.br
XX.B long loc;
XX.PP
XX.SM
XX.B rewinddir(dirp)
XX.br
XX.B DIR *dirp;
XX.PP
XX.SM
XX.B closedir(dirp)
XX.br
XX.B DIR *dirp;
XX.SH DESCRIPTION
XXThis library provides high-level primitives for directory scanning,
XXsimilar to those available for 4.2BSD's (very different) directory system.
XX.\"The purpose of this library is to simulate
XX.\"the new flexible length directory names of 4.2bsd UNIX
XX.\"on top of the old directory structure of v7.
XXIt incidentally provides easy portability to and from 4.2BSD (insofar
XXas such portability is not compromised by other 4.2/VAX dependencies).
XX.\"It allows programs to be converted immediately
XX.\"to the new directory access interface,
XX.\"so that they need only be relinked
XX.\"when moved to 4.2bsd.
XX.\"It is obtained with the loader option
XX.\".BR \-lndir .
XX.PP
XX.I Opendir
XXopens the directory named by
XX.I filename
XXand associates a
XX.I directory stream
XXwith it.
XX.I Opendir
XXreturns a pointer to be used to identify the
XX.I directory stream
XXin subsequent operations.
XXThe pointer
XX.SM
XX.B NULL
XXis returned if
XX.I filename
XXcannot be accessed or is not a directory.
XX.PP
XX.I Readdir
XXreturns a pointer to the next directory entry.
XXIt returns
XX.B NULL
XXupon reaching the end of the directory or detecting
XXan invalid
XX.I seekdir
XXoperation.
XX.PP
XX.I Telldir
XXreturns the current location associated with the named
XX.I directory stream.
XX.PP
XX.I Seekdir
XXsets the position of the next
XX.I readdir
XXoperation on the
XX.I directory stream.
XXThe new position reverts to the one associated with the
XX.I directory stream
XXwhen the
XX.I telldir
XXoperation was performed.
XXValues returned by
XX.I telldir
XXare good only for the lifetime of the DIR pointer from 
XXwhich they are derived.
XXIf the directory is closed and then reopened, 
XXthe 
XX.I telldir
XXvalue may be invalidated
XXdue to undetected directory compaction in 4.2BSD.
XXIt is safe to use a previous
XX.I telldir
XXvalue immediately after a call to
XX.I opendir
XXand before any calls to
XX.I readdir.
XX.PP
XX.I Rewinddir
XXresets the position of the named
XX.I directory stream
XXto the beginning of the directory.
XX.PP
XX.I Closedir
XXcauses the named
XX.I directory stream
XXto be closed,
XXand the structure associated with the DIR pointer to be freed.
XX.PP
XXA
XX.I direct
XXstructure is as follows:
XX.PP
XX.RS
XX.nf
XXstruct	direct {
XX	/* unsigned */ long	d_ino;	/* inode number of entry */
XX	unsigned short	d_reclen;	/* length of this record */
XX	unsigned short	d_namlen;	/* length of string in d_name */
XX	char	d_name[MAXNAMLEN + 1];	/* name must be no longer than this */
XX};
XX.fi
XX.RE
XX.PP
XXThe
XX.I d_reclen
XXfield is meaningless in non-4.2BSD systems and should be ignored.
XXThe use of a
XX.I long
XXfor
XX.I d_ino
XXis also a 4.2BSDism;
XX.I ino_t
XX(see
XX.IR types (5))
XXshould be used elsewhere.
XXThe macro
XX.I DIRSIZ(dp)
XXgives the minimum memory size needed to hold the
XX.I direct
XXvalue pointed to by
XX.IR dp ,
XXwith the minimum necessary allocation for
XX.IR d_name .
XX.PP
XXThe preferred way to search the current directory for entry ``name'' is:
XX.PP
XX.RS
XX.nf
XX	len = strlen(name);
XX	dirp = opendir(".");
XX	if (dirp == NULL) {
XX		fprintf(stderr, "%s: can't read directory .\\n", argv[0]);
XX		return NOT_FOUND;
XX	}
XX	while ((dp = readdir(dirp)) != NULL)
XX		if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) {
XX			closedir(dirp);
XX			return FOUND;
XX		}
XX	closedir(dirp);
XX	return NOT_FOUND;
XX.RE
XX.\".SH LINKING
XX.\"This library is accessed by specifying ``-lndir'' as the
XX.\"last argument to the compile line, e.g.:
XX.\".PP
XX.\"	cc -I/usr/include/ndir -o prog prog.c -lndir
XX.SH "SEE ALSO"
XXopen(2),
XXclose(2),
XXread(2),
XXlseek(2)
XX.SH HISTORY
XXWritten by
XXKirk McKusick at Berkeley (ucbvax!mckusick).
XXMiscellaneous bug fixes from elsewhere.
XXThe size of the data structure has been decreased to avoid excessive
XXspace waste under V7 (where filenames are 14 characters at most).
XXFor obscure historical reasons, the include file is also available
XXas
XX.IR <ndir/sys/dir.h> .
XXThe Berkeley version lived in a separate library (\fI\-lndir\fR),
XXwhereas ours is
XXpart of the C library, although the separate library is retained to
XXmaximize compatibility.
XX.PP
XXThis manual page has been substantially rewritten to be informative in
XXthe absence of a 4.2BSD manual.
XX.SH BUGS
XXThe
XX.I DIRSIZ
XXmacro actually wastes a bit of space due to some padding requirements
XXthat are an artifact of 4.2BSD.
XX.PP
XXThe returned value of
XX.I readdir
XXpoints to a static area that will be overwritten by subsequent calls.
XX.PP
XXThere are some unfortunate name conflicts with the \fIreal\fR V7
XXdirectory structure definitions.
X!
Xecho 'dir.h':
Xsed 's/^X//' >'dir.h' <<'!'
XX/*	dir.h	4.4	82/07/25	*/
XX
XX/*
XX * A directory consists of some number of blocks of DIRBLKSIZ
XX * bytes, where DIRBLKSIZ is chosen such that it can be transferred
XX * to disk in a single atomic operation (e.g. 512 bytes on most machines).
XX *
XX * Each DIRBLKSIZ byte block contains some number of directory entry
XX * structures, which are of variable length.  Each directory entry has
XX * a struct direct at the front of it, containing its inode number,
XX * the length of the entry, and the length of the name contained in
XX * the entry.  These are followed by the name padded to a 4 byte boundary
XX * with null bytes.  All names are guaranteed null terminated.
XX * The maximum length of a name in a directory is MAXNAMLEN.
XX *
XX * The macro DIRSIZ(dp) gives the amount of space required to represent
XX * a directory entry.  Free space in a directory is represented by
XX * entries which have dp->d_reclen >= DIRSIZ(dp).  All DIRBLKSIZ bytes
XX * in a directory block are claimed by the directory entries.  This
XX * usually results in the last entry in a directory having a large
XX * dp->d_reclen.  When entries are deleted from a directory, the
XX * space is returned to the previous entry in the same directory
XX * block by increasing its dp->d_reclen.  If the first entry of
XX * a directory block is free, then its dp->d_ino is set to 0.
XX * Entries other than the first in a directory do not normally have
XX * dp->d_ino set to 0.
XX */
XX#define DIRBLKSIZ	512
XX#ifdef VMUNIX
XX#define	MAXNAMLEN	255
XX#else
XX#define	MAXNAMLEN	14
XX#endif
XX
XXstruct	direct {
XX	/* unsigned */ long	d_ino;	/* inode number of entry */
XX	unsigned short	d_reclen;	/* length of this record */
XX	unsigned short	d_namlen;	/* length of string in d_name */
XX	char	d_name[MAXNAMLEN + 1];	/* name must be no longer than this */
XX};
XX
XX/*
XX * The DIRSIZ macro gives the minimum record length which will hold
XX * the directory entry.  This requires the amount of space in struct direct
XX * without the d_name field, plus enough space for the name with a terminating
XX * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
XX */
XX#undef DIRSIZ
XX#define DIRSIZ(dp) \
XX    ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
XX
XX#ifndef KERNEL
XX/*
XX * Definitions for library routines operating on directories.
XX */
XXtypedef struct _dirdesc {
XX	int	dd_fd;
XX	long	dd_loc;
XX	long	dd_size;
XX	char	dd_buf[DIRBLKSIZ];
XX} DIR;
XX#ifndef NULL
XX#define NULL 0
XX#endif
XXextern	DIR *opendir();
XXextern	struct direct *readdir();
XXextern	long telldir();
XX#ifdef void
XXextern	void seekdir();
XXextern	void closedir();
XX#endif
XX#define rewinddir(dirp)	seekdir((dirp), (long)0)
XX#endif KERNEL
X!
Xecho 'makefile':
Xsed 's/^X//' >'makefile' <<'!'
XXDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o
XXCFLAGS=-O -I. -Dvoid=int
XXDEST=..
XX
XXall:	$(DIR)
XX
XXmv:	$(DIR)
XX	mv $(DIR) $(DEST)
XX
XXcpif:	dir.h
XX	cp dir.h /usr/include/ndir.h
XX
XXclean:
XX	rm -f *.o
X!
Xecho 'closedir.c':
Xsed 's/^X//' >'closedir.c' <<'!'
XXstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82";
XX
XX#include <sys/types.h>
XX#include <dir.h>
XX
XX/*
XX * close a directory.
XX */
XXvoid
XXclosedir(dirp)
XX	register DIR *dirp;
XX{
XX	close(dirp->dd_fd);
XX	dirp->dd_fd = -1;
XX	dirp->dd_loc = 0;
XX	free((char *)dirp);
XX}
X!
Xecho 'opendir.c':
Xsed 's/^X//' >'opendir.c' <<'!'
XX/* Copyright (c) 1982 Regents of the University of California */
XX
XXstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82";
XX
XX#include <sys/types.h>
XX#include <sys/stat.h>
XX#include <dir.h>
XX
XX/*
XX * open a directory.
XX */
XXDIR *
XXopendir(name)
XX	char *name;
XX{
XX	register DIR *dirp;
XX	register int fd;
XX	struct stat statbuf;
XX	char *malloc();
XX
XX	if ((fd = open(name, 0)) == -1)
XX		return NULL;
XX	if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) {
XX		close(fd);
XX		return NULL;
XX	}
XX	if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
XX		close (fd);
XX		return NULL;
XX	}
XX	dirp->dd_fd = fd;
XX	dirp->dd_loc = 0;
XX	dirp->dd_size = 0;	/* so that telldir will work before readdir */
XX	return dirp;
XX}
X!
Xecho 'readdir.c':
Xsed 's/^X//' >'readdir.c' <<'!'
XX/* Copyright (c) 1982 Regents of the University of California */
XX
XXstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82";
XX
XX#include <sys/types.h>
XX#include <dir.h>
XX
XX/*
XX * read an old stlye directory entry and present it as a new one
XX */
XX#define	ODIRSIZ	14
XX
XXstruct	olddirect {
XX	ino_t	od_ino;
XX	char	od_name[ODIRSIZ];
XX};
XX
XX/*
XX * get next entry in a directory.
XX */
XXstruct direct *
XXreaddir(dirp)
XX	register DIR *dirp;
XX{
XX	register struct olddirect *dp;
XX	static struct direct dir;
XX
XX	for (;;) {
XX		if (dirp->dd_loc == 0) {
XX			dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 
XX			    DIRBLKSIZ);
XX			if (dirp->dd_size <= 0) {
XX				dirp->dd_size = 0;
XX				return NULL;
XX			}
XX		}
XX		if (dirp->dd_loc >= dirp->dd_size) {
XX			dirp->dd_loc = 0;
XX			continue;
XX		}
XX		dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
XX		dirp->dd_loc += sizeof(struct olddirect);
XX		if (dp->od_ino == 0)
XX			continue;
XX		dir.d_ino = dp->od_ino;
XX		strncpy(dir.d_name, dp->od_name, ODIRSIZ);
XX		dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
XX		dir.d_namlen = strlen(dir.d_name);
XX		dir.d_reclen = DIRBLKSIZ;
XX		return (&dir);
XX	}
XX}
X!
Xecho 'seekdir.c':
Xsed 's/^X//' >'seekdir.c' <<'!'
XXstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83";
XX
XX#include <sys/param.h>
XX#include <dir.h>
XX
XX/*
XX * seek to an entry in a directory.
XX * Only values returned by "telldir" should be passed to seekdir.
XX */
XXvoid
XXseekdir(dirp, loc)
XX	register DIR *dirp;
XX	long loc;
XX{
XX	long curloc, base, offset;
XX	struct direct *dp;
XX	extern long lseek();
XX
XX	curloc = telldir(dirp);
XX	if (loc == curloc)
XX		return;
XX	base = loc & ~(DIRBLKSIZ - 1);
XX	offset = loc & (DIRBLKSIZ - 1);
XX	(void) lseek(dirp->dd_fd, base, 0);
XX	dirp->dd_size = 0;
XX	dirp->dd_loc = 0;
XX	while (dirp->dd_loc < offset) {
XX		dp = readdir(dirp);
XX		if (dp == NULL)
XX			return;
XX	}
XX}
X!
Xecho 'telldir.c':
Xsed 's/^X//' >'telldir.c' <<'!'
XXstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82";
XX
XX#include <sys/types.h>
XX#include <dir.h>
XX
XX/*
XX * return a pointer into a directory
XX */
XXlong
XXtelldir(dirp)
XX	DIR *dirp;
XX{
XX	long lseek();
XX
XX	return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc);
XX}
X!
Xecho done
!
echo 'contrib/README':
sed 's/^X//' >'contrib/README' <<'!'
XThis directory contains some software from others that might be of use
Xin getting C News running in an unusual environment.
X
XWE MAKE ABSOLUTELY NO GUARANTEES ABOUT QUALITY OR USABILITY.  EVERYTHING
XHERE IS SUPPLIED "AS IS".  SOMETIMES WE HAVEN'T EVEN TESTED IT.
!
echo 'contrib/nntpmail/README':
sed 's/^X//' >'contrib/nntpmail/README' <<'!'
XThis directory contains.
X
Xmailing_lists		support for moderating, redistributing and
X			gatewaying mailing lists into newsgroups/vice-versa.
Xmail_to_group		support for being able to "mail comp.unix.wizards"
Xnntp_support		support for posting articles remotely using
X			NNTP.
Xpost_via_mail		support for posting articles remotely by mailing
X			them there. Poor man's NNTP.
!
echo 'contrib/nntpmail/post_via_mail/README':
sed 's/^X//' >'contrib/nntpmail/post_via_mail/README' <<'!'
XThis directory contains C news support for posting news to a remote
Xserver by mailing the article to a special alias.
X
Xfrontend_inews	parse options, masquerades news headers so they can
X		go through mail, mail the article to the remote
X		alias.  Install as $NEWSLIB/inews
X
Xserver_inews	The special alias on the news server should invke this
X		e.g.
X		feednews: "|/usr/lib/newsbin/server_inews"
X
X		Make sure the nntp server invokes server_inews and
X		not fake_inews (instant infinite loop!).
X
X		You can find this file in ../nntp_support
X
Xusenet		a version of ../mail_to_newsgroup/usenet that works
X		by remailing the article.
!
echo 'contrib/nntpmail/post_via_mail/frontend_inews':
sed 's/^X//' >'contrib/nntpmail/post_via_mail/frontend_inews' <<'!'
X#! /bin/sh
X# inews [-p] [-d k] [-x site] [-hMD] [-t subj] [-n ng] [-e exp] [-F ref] \
X#  [-d dist] [-a mod] [-f from] [-o org] [-C ng] [file...] - inject news:
X#
X#     pseudo inews that supports the use of a central posting server accessed
X#     via mail.  This provides less opportunities to inject fake messages, and
X#     relies on mail to do fancy things like hiding names of workstations and
X#     providing full-name return addresses.
X#
X# Jean-Francois Lamy (lamy@ai.toronto.edu) 88-02-11
X
X#NEWSCTL=${NEWSCTL-/usr/lib/news}
X#NEWSBIN=${NEWSBIN-/usr/lib/newsbin}
X#NEWSARTS=${NEWSARTS-/usr/spool/news}
XNEWSCTL=/local/share/news
XNEWSBIN=/local/lib/news
XNEWSARTS=/var/spool/news
XPATH=$NEWSBIN:$NEWSCTL:$NEWSBIN/relay:/bin:/usr/bin:/usr/ucb; export PATH
X
Xallowed=sandra\|rayan\|lamy		# tailor: local news admin (may be "")
Xhdrspresent=no
X
Xwhoami=/tmp/in$$who		# just created to determine effective uid
Xinput=/tmp/in$$in		# uncensored input
Xcensart=/tmp/in$$cens		# censored input
Xrmlist="$input $censart"
Xegrep=egrep
X
X# figure out where the remote server is.  We mail even if we are on the
X# server, in order to garantee proper return addresses
X   servaddr=feednews@news-server.csri.toronto.edu
X
Xumask 2
Xtrap '' 1 2 15			# ignore signals to avoid losing articles
X
X# "inews -p": invoke rnews
Xcase "$1" in
X-p)
X	shift
X	exec rnews $*		# rnews, bailing out at or near line 1
X	;;
Xesac
X
X# parse arguments for options, cat headers onto $input; cat files onto $input
X>$input
Xwhile :
Xdo
X	case $# in
X	0)	break ;;		# arguments exhausted
X	esac
X
X	case "$1" in
X	-debug)	shift; debug="$1" ;;		# peculiar to C news
X	-x)	shift; exclusion="-x $1" ;;	# you're welcome, erik (2.11)
X	-h)	hdrspresent=yes ;;
X	-M)	# TODO: what's this *really* do? dunno, find out
X		;;
X	-D)	# obsolete, undocumented: meant "don't check for recordings".
X		# last present in B 2.10.1, invoked by readnews for followups.
X		;;
X	-t)	shift; echo "Subject: $1" >>$input ;;
X	-n)	shift; echo "Newsgroups: $1" >>$input ;;
X	-e)	shift; echo "Expires: $1" >>$input ;;
X	-F)	# undocumented in B 2.10.1, documented in B 2.11.
X		shift; echo "References: $1" >>$input ;;
X	-d)	shift; echo "Distribution: $1" >>$input ;;
X	-a)	shift; echo "Approved: $1" >>$input ;;
X
X	# pass next options as environment variables to client.censor
X
X	-f)	shift; PASSEDFROM="$1" ;;	# complex due to Sender:
X	-o)	shift; ORGANIZATION="$1"; export ORGANIZATION ;;
X
X	-[cC])
X		# megakludge-o-rama
X		# first, permit only to super-users
X		>$whoami
X		whoever = "`ls -l $whoami | awk '{print $3}'`"
X		case $whoever in
X		root|$allowed)	: a winner ;;
X		*)
X			echo "$0: $1 restricted to super-users " >&2
X			exit 1
X			;;
X		esac
X		rm -f $whoami
X		case "$1" in
X		-C)	cat <<! >>$input		# generate -C header
XNewsgroups: $ng
XSubject: newgroup $2
XControl: newgroup $2
XApproved: $whoever@`hostname`.`domainname`
X
Xcreated by inews -C
X!		 	
X			shift
X			;;
X		-c)	cat <<! >>$input		# generate -c header
XNewsgroups: $ng
XSubject: $2
XControl: $2
XApproved: $whoever@`hostname`.`domainname`
X
Xcreated by inews -c.
X!
X			shift
X			;;
X		esac
X		;;
X	-*)
X		echo "$0: bad option $1" >&2
X		exit 1
X		;;
X	*)
X		case "$hdrspresent" in
X		no)	echo "" >>$input; hdrspresent=yes ;;
X		esac
X		cat "$1" >>$input		# is a filename; append file
X		fileseen=yes
X		;;
X	esac
X	shift		# pass option or filename (any value was done above)
Xdone
X
X# if no files named, read stdin
Xcase "$fileseen" in
Xyes)	;;
X*)
X	case "$hdrspresent" in
X	no)	echo "" >>$input; hdrspresent=yes ;;
X	esac
X	# capture incoming news in case inews fails
X	if cat >>$input; then
X		: far out
X	else
X		echo "$0: lost news; cat returned status $?" >&2
X		exit 1
X	fi
X	;;
Xesac
X
X(
X# trivial censoring, before passing on to mailer.
XORGANIZATION=${ORGANIZATION=`cat ${NEWSCTL}/organi?ation`}
Xawk "BEGIN		{ subject = 0; body = 0; skipping = 0 ;
X			  newsgroups = 0; distribution = 0; organization = 0;
X			  print \"To: $servaddr\" }
Xbody == 1		{ print; next }
X/[A-Za-z-]*:[ ]*$/	{ next }
X/^$|^[ ][ \t]*$/        { if (!body) {
X			    if (!organization) 
X			       print \"Organization: $ORGANIZATION\";
X			    if (!newsgroups) print \"Newsgroups: $groups\";
X			    if (!subject) print \"Subject: (none)\"; 
X			  }
X			  print; body = 1; next
X			}
X/^Organization:/	{ organization = 1; skipping = 0; print; next }
X/^Newsgroups:/		{ newsgroups = 1; skipping = 0; print; next }
X/^Distribution:/	{ distribution = 1; skipping = 0; print; next }
X/^Subject:/		{ subject = 1; skipping = 0; print; next }
X/^To:|^Cc:|^X-To:/	{ skipping = 1; next }
X/^From |^Return-Path:/	{ skipping = 1; next }
X/^Apparently-To:/	{ skipping = 1; next }
X/^[ 	]/		{ if (skipping) next }
X			{ print }
X" <$input >$censart
Xif test -r $HOME/.signature; then
X   echo "-- " >>$censart
X   sed 5q $HOME/.signature >>$censart	# glue on first bit of signature
Xfi
X
Xif /usr/lib/sendmail -t ${PASSEDFROM+-f"$PASSEDFROM"} <$censart
Xthen
X	rm -f $rmlist		# far out, it worked
X	exit 0
Xelse
X	status=$?
X	echo\
X"$0: could not send article to server; sendmail returned status $status" >&2
X	echo "$0: processed news article can be found in $input" >&2
X	exit $status
Xfi
X) &
!
echo 'contrib/nntpmail/post_via_mail/usenet':
sed 's/^X//' >'contrib/nntpmail/post_via_mail/usenet' <<'!'
X#!/bin/sh
X#
X# post.news
X#
X# meant to be invoked as a sendmail-compatible mailer from zmailer.  Arguments
X# are the newsgroups to which the article should be posted. A complete
X# message, including To:, From: and From_ line expected on stdin.
X# 
X# To use this script as a transport agent, add the following to scheduler.cntl:
X#	usenet/*	1m	10 0 0	root	daemon	sm -c $channel news
X# The definition of the news transport agent in sm.cf should contain
X#	news	m	/usr/lib/zmail/post.news	post.news $u
X# (adjust this to reflect the actual location of the installed copy of this
X# script, of course)
X#
X# Jean-Francois Lamy (lamy@ai.toronto.edu), 88-02-13
X# based on code by Rayan Zachariassen.
X
X# Notes:
X# - The news program invoked by this script should trust From: lines
X#   (otherwise workstation name hiding, full-name id generation and
X#   all other smarts done by router.cf will be lost)
X# - router.cf checks local parts with embedded dots for membership in the
X#   active newsgroups file and routes them through this transport agent. One
X#   word newsgroup names are not tested in that fashion, because of the risk
X#   of obscure clashes with user-ids.  Explicit aliases of the form
X#      gradnews: gradnews@localnews
X#   should be used for those (such names are not a good idea to start with).
X#   If such aliases are used, add a line in hosts.transports that reads
X#      localnews usenet!
X#   This tells the router that mail to fake host localnews is to be sent to the
X#   local host (there is nothing after the !) on channel usenet. 
X
X# this version forwards the article via mail to a server that will trust
X# the return address.
Xserver="feednews@news-server.csri.toronto.edu"
X
Xcase x$DISTRIBUTE in
Xx)	org="`cat /local/share/news/organi?ation`"
X	[ "$org" ] || org = "Department of Computer Science, University of Toronto"
X	orgflag=1
X	;;
X*)	orgflag=0
X	;;
Xesac
Xfrom=/tmp/from$$
X
Xfor i in $@
Xdo
X	groups="${groups+$groups,}$i"
Xdone
X
Xawk "BEGIN		{ subject = 0; body = 0; skipping = 0 ;
X			  newsgroups = 0; distribution = 0;
X			  organization = $orgflag;
X			  print \"To: $server\" }
Xbody == 1		{ print; next }
X/^$|^[ ][ \\t]*$/	{ if (!body) {
X			    np = split(path,parts,\"!\");
X			    if (!organization && np == 1)
X			        print \"Organization: $org\";
X			    if (!newsgroups) print \"Newsgroups: $groups\";
X			    if (!subject) print \"Subject: (none)\"; 
X			  }
X			  print; body = 1; next
X			}
X/^To:|^X-To:|^Cc:|^Apparently-To:/	{ skipping=1 ; next }
X/^Newsgroups:/		{ newsgroups = 1; skipping = 0; printf(\"%s\",\$0);
X			  if (\"$groups\" != \"\")
X			     printf(\",%s\\n\",\"$groups\");
X			  else printf(\"\\n\");
X			  next }
X/^Distribution:/	{ distribution = 1; skipping = 0; print; next }
X/^Subject:/		{ subject = 1; skipping = 0; print; next }
X/^From |^Return-Path:/	{ print \$2 > from ; path = \$2 ; skipping = 1; next }
X/^[ 	]/		{ if (skipping) next }
X/^[A-Za-z-]*:[ \\t]*$/	{ if (!body) next }
X			{ print }
X" from="$from" - >/tmp/bug$$
X
Xif [ -s $from ]; then
X	/usr/lib/sendmail -f"`cat $from`" </tmp/bug$$
Xfi
Xrm $from /tmp/bug$$
Xexit 0
!
echo 'contrib/nntpmail/mailing_lists/README':
sed 's/^X//' >'contrib/nntpmail/mailing_lists/README' <<'!'
XMANAGING AND REDISTRIBUTING MAILING LISTS
X
XThe tools described below allow you to set up a mailing list that is
X- archived in a single file if you wish
X- archived in one file per volume/issue if you wish
X- gatewayed to a newsgroup (bi-directionally if you wish)
X- well-behaved (the bounces go back to the owner, not to the whole list)
X- protected from unauthorized perusal if you wish.
X
XThis requires something like the following aliases to be set-up.
X
X    example: "|/local/lib/mail/bin/moderate example-owner example-people",
X	    "|/local/lib/mail/bin/distribute -a example -n list.example"
X    example-request: lamy
X    example-owner: lamy
X    example-people:	":include:/local/share/mail/lists/example"
X
XFor bi-directional gatewaying you need to edit the sys file on the news
Xserver:
X
X    list.example:list.example/all::/news/bin/mailgateway example@ai.toronto.edu
X
XThe tools used are as follows:
X
Xa) redistributing a mailing list
X
Xmoderate:     used for setting up mail aliases so that bounces don't pester
X	      the whole membership.  Typically the members of the list will
X	      be another alias that invokes "distribute" (below) so that
X	      the contents get archived or/and fed to newsgroups.
X
Xb) gatewaying mailing lists to newsgroups, archival
X
Xdistribute:   takes a message, forwards it to mail recipients, gateways
X	      into newsgroups, and archives the articles either one article
X	      per file or mailbox style.
X
Xappendfile:   setuid append program; required so that sensitive lists can
X	      be protected.
X
X
Xc) gatewaying of newsgroups into mailing lists (bidirectionally as well).
X
Xmailgateway:  Used on the news server, and invoked from the sys file, this
X	      script allows notification of people who can't/won't read news.
X	      Messages posted to a newsgroup are fed to a mailing list, except
X	      if the message appears to have come from the mailing list in the
X	      first place.  This is detected by looking for the Approved:
X	      header "distribute" tacks on.  News control messages are
X	      weeded out.
!
echo 'contrib/nntpmail/mailing_lists/appendfile/Makefile':
sed 's/^X//' >'contrib/nntpmail/mailing_lists/appendfile/Makefile' <<'!'
XNAME=appendfile
XDESTDIR=/ai/lib/mail/bin
XMANEXT=1
XMANDIR=/ai/man/man$(MANEXT)
XCFLAGS=-O
X
Xall: $(NAME)
X$(NAME): $(NAME).c
X	cc $(CFLAGS) $(NAME).c -o $(NAME)
X
Xinstall: all
X	install -s -m 755 $(NAME) $(DESTDIR)
X#	install -c -m a=r $(NAME).man $(MANDIR)/$(NAME).$(MANEXT)
X
Xclean:
X	rm -f *.o $(NAME) \#* *~
!
echo 'contrib/nntpmail/mailing_lists/appendfile/appendfile.c':
sed 's/^X//' >'contrib/nntpmail/mailing_lists/appendfile/appendfile.c' <<'!'
X#define BUFSIZ	1024
X#include <sys/file.h>
X
Xmain(argc,argv)
Xint	argc;
Xchar	**argv;
X{
X	char	*ofile, buf[BUFSIZ];
X	int	fd, n, p, neednl;
X
X	argc--, argv++;
X	neednl = 0;
X	p = 1;
X	if (**argv == '-') {
X		if ((fd = open(argv[0]+1,O_WRONLY|O_APPEND|O_CREAT,0644)) < 0
X		    || dup2(fd, 1) < 0) {
X			perror(argv[0]+1);
X			exit(1);
X		}
X		argc--, argv++;
X	}
X	while (argc--) {
X		if ((fd = open(*argv, 0)) < 0) {
X			perror(*argv++);
X			continue;
X		}
X		argv++;
X		if (neednl)
X			write(1, "\n", 1);
X		while ((n = read(fd, buf, BUFSIZ)) > 0) {
X			write(1, buf, n);
X			if (n == 1)
X				neednl = !(buf[0] == '\n' && buf[p-1] == '\n');
X			else
X				neednl = !(buf[n-1] == '\n' && buf[n-2]=='\n');
X			p = n;
X		}
X		close(fd);
X	}
X	if (neednl)
X		write(1, "\n", 1);
X	exit(0);
X}
!
echo done


-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.