[comp.sources.unix] v12i031: C News alpha release, Part06/14

rsalz@uunet.UU.NET (Rich Salz) (10/22/87)

Submitted-by: utzoo!henry (Henry Spencer)
Posting-number: Volume 12, Issue 31
Archive-name: cnews/part06


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 6 (of 14)."
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'batch/sendbatches' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'batch/sendbatches'\"
else
echo shar: Extracting \"'batch/sendbatches'\" \(3153 characters\)
sed "s/^X//" >'batch/sendbatches' <<'END_OF_FILE'
X# Master batching control.
XNEWSBIN=${NEWSBIN-/usr/lib/newsbin}
XNEWSCTL=${NEWSCTL-/usr/lib/news}
XNEWSARTS=${NEWSARTS-/usr/spool/news}
XPATH=$NEWSCTL/batch:$NEWSBIN/batch:/bin:/usr/bin ; export PATH
Xorigpath=$PATH
XNEWSUMASK=${NEWSUMASK-002}
Xumask $NEWSUMASK
X
X# Locking.
Xcd $NEWSCTL
Xecho $$ >LOCKbatch$$
Xif ln LOCKbatch$$ LOCKbatch >/dev/null 2>/dev/null
Xthen
X	rm LOCKbatch$$
X	trap "rm -f $NEWSCTL/LOCKbatch ; exit" 0 1 2 3 15
Xelse
X	rm LOCKbatch$$
X	exit 0
Xfi
X
X# Go to the heart of the matter.
Xcd $NEWSCTL/batch
X
X# Determine what systems are being requested, in what order.
Xcase $#
Xin
X	0)
X	ls | sed -n '/^b\./s///p' | sort >/tmp/nb$$sy
X	if test -r sites
X	then
X		egrep -v '^[ 	]*(#|$)' sites | awk '{ print $1, NR }' |
X							sort >/tmp/nb$$o
X		join -a1 -e 9999 -o 1.1 2.2 /tmp/nb$$sy /tmp/nb$$o >/tmp/nb$$t
X		sort +1 -n /tmp/nb$$t | awk '{ print $1 }' >/tmp/nb$$sy
X	fi
X	syses=`cat /tmp/nb$$sy`
X	rm -f /tmp/nb$$sy /tmp/nb$$o /tmp/nb$$t
X	;;
X
X	*)
X	case "$1"
X	in
X		-c)
X		if test ! -r sites
X		then
X			echo "$0: -c illegal in absence of sites file" >&2
X			exit 2
X		fi
X		shift
X		syses=`for class in $*
X			do
X				egrep -v '^[ 	]*(#|$)' sites |
X					egrep "[, 	]$class(\$|[, 	])" |
X					awk '{print $1}'
X			done`
X		;;
X
X		*)
X		syses="$*"
X		;;
X	esac
X	;;
Xesac
X
X# Start up logging.
Xmv $NEWSCTL/batchlog.o $NEWSCTL/batchlog.oo
Xmv $NEWSCTL/batchlog $NEWSCTL/batchlog.o
Xdate >$NEWSCTL/batchlog
X
X# Run through them.
Xfor sys in $syses
Xdo
X	# Move into his directory, include it in search path.
X	here=$NEWSCTL/batch/b.$sys
X	if test ! -d $here
X	then
X		echo "$0:  cannot find batch directory for site $sys" >&2
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	# How many batches should we send?
X	outstand=`queuelen $sys`
X	limit=`queuemax`
X	nbatch=`expr $limit - $outstand`
X	batchsize=`batchsize`
X	roomfor=`roomfor $batchsize`
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'
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.*`" = 'togo.*'
X		then
X			# No -- need some more batches.
X			if test ! -s togo
X			then
X				break		# Nothing left to do.
X			fi
X			batchprep $batchsize
X		fi
X
X		# Send some batches.
X		them=`ls | egrep '^togo\.' | sed "${nbatch}q"`
X		for f in $them
X		do
X			batchmake -d $NEWSARTS $f | batchmunch |
X							batchxmit $sys
X			rm $f
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=`roomfor $batchsize`
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)" >>$NEWSCTL/batchlog
X	fi
Xdone
END_OF_FILE
if test 3153 -ne `wc -c <'batch/sendbatches'`; then
    echo shar: \"'batch/sendbatches'\" unpacked with wrong size!
fi
# end of 'batch/sendbatches'
fi
if test -f 'expire/expire.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'expire/expire.1'\"
else
echo shar: Extracting \"'expire/expire.1'\" \(3912 characters\)
sed "s/^X//" >'expire/expire.1' <<'END_OF_FILE'
X.TH EXPIRE 1M local
X.DA 3 Oct 1987
X.SH NAME
Xexpire \- expire old news
X.SH SYNOPSIS
X.B /usr/lib/newsbin/expire/expire
X[
X.B \-a
Xarchdir
X] [
X.B \-p
X] [
X.B \-o
X]
X[ controlfile ]
X.SH DESCRIPTION
X.I Expire
Xexpires old news, removing it from the current-news directories and
X(if asked to) archiving it elsewhere.
XIt updates news's
X.I history
Xfile to match.
X.I Expire
Xshould be run nightly.
X.PP
X.IR Expire 's
Xoperations are controlled by a control file
X(which can be named or supplied on standard input),
Xwhich is not optional\(emthere is no default behavior.
XEach line of the control file should have four white-space-separated
Xfields, as follows.
X.PP
XThe first field is one or more newsgroups,
Xseparated by commas (no spaces!);
Xpartial specifications are acceptable (e.g. `comp' specifies all groups
Xwith that prefix).
X.PP
XThe second field is one letter, `m', `u', or `x', specifying that the line
Xapplies only to moderated groups, only to unmoderated groups, or to both,
Xrespectively.
X.PP
XThe third field specifies the expiry period in days.
XThe most general form is three numbers separated by dashes.
XThe units are days; decimal fractions are permitted.
XThe first number gives the retention period:
Xhow long must pass after an article's arrival before it is a candidate
Xfor expiry.
XThe third number gives the purge date:
Xhow long must pass after arrival
Xbefore the article will be expired unconditionally.
XThe middle number gives the default expiry date:
Xhow long after an article's arrival it is expired by default.
XAn explicit expiry date in the article will override the default expiry
Xdate but not the retention period or the purge date.
XIf the field contains only two numbers with a dash separating them,
Xthe retention period defaults to 0.
XIf the field contains only a number, the retention period defaults to 0
Xand the purge date defaults to `never'.
X.PP
XThe fourth field is an archiving directory,
Xor `@' which indicates that the default archiving directory (see \fB\-a\fR)
Xshould be used,
Xor `\-' which suppresses archiving.
X.PP
XThe first line of the control file which applies to a given article is
Xused to control its expiry.
XIt is an error for no line to apply;
Xthe last line should be something like `all\ x\ 14\ \-'
Xto ensure that at least one line is always applicable.
XCross-posted articles are treated as if they were independently posted
Xto each group.
X.PP
XThe
X.B \-a
Xoption specifies a default archiving directory;
Xif no default is given, it is illegal for the control file to contain
Xany `@' archive-directory fields.
X.PP
X.I Expire
Xcreates subdirectories under an archiving directory automatically,
Xbut will not create the archiving directory itself.
XArchiving directories must be given as full pathnames.
X.PP
XThe
X.B \-p
Xoption causes an `index' line to be printed for each archived article,
Xcontaining its pathname, message ID, date received, and `Subject:' line.
XThe
X.B \-o
Xoption tells
X.I expire
Xto use the obsolete 4-field history-file format used by early variants
Xof C news.
X.PP
X\fIExpire\fR and its auxiliaries recognize the standard
Xenvironment variables \fB$\&NEWSARTS\fR,
X\fB$\&NEWSCTL\fR, \fB$\&NEWSBIN\fR, and \fB$NEWSUMASK\fR
Xwhich indicate, respectively, non-default locations
Xfor news articles, news control files, and news programs,
Xand a non-default \fIumask\fR (see \fIumask\fR(2)) for file creation
X(the default \fIumask\fR is 002).
X.SH FILES
X.ta 4c
X.nf
X\fIlibrary\fR/history	history file
X\fIlibrary\fR/history.pag	\fIdbm\fR database for history file
X\fIlibrary\fR/history.dir	\fIdbm\fR database for history file
X.SH SEE ALSO
Xinews(1)
X.SH HISTORY
XWritten at U of Toronto by Henry Spencer, with contributions by Geoff Collyer.
X.SH BUGS
XArchiving is always done by copying, never by linking.
XThis has the side effect that cross-posted articles are archived as
Xseveral independent copies.
X.PP
XThe
X.B \-p
Xsubject-finder botches continued `Subject:' lines, although
Xthese are rare.
END_OF_FILE
if test 3912 -ne `wc -c <'expire/expire.1'`; then
    echo shar: \"'expire/expire.1'\" unpacked with wrong size!
fi
# end of 'expire/expire.1'
fi
if test -f 'expire/ns.p' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'expire/ns.p'\"
else
echo shar: Extracting \"'expire/ns.p'\" \(3614 characters\)
sed "s/^X//" >'expire/ns.p' <<'END_OF_FILE'
Xmkdir ns ns/foo ns/bar ns/bletch
Xmkdir ns/foo/one ns/foo/two ns/foo/three
Xmkdir ns/bar/one ns/bar/two ns/bar/five
Xmkdir ns/bletch/one ns/bletch/four ns/bletch/six
X
X# The "should-expire" headers are for checking afterward.
X
X# In foo/one, run through the simple cases of dates before and after
X# expiry dates.  Also where the Subject: line is in the article.
Xoldfile 11 ns/foo/one/95 <<!
XMessage-ID: <aya.foo/one/95>
XShould-expire: yes
XSubject: foo one/95
X
Xbody
X!
Xoldfile 10 ns/foo/one/96 <<!
XMessage-ID: <bn.foo/one/96>
XShould-expire: no
XSubject: foo one/96
X
Xbody
X!
Xoldfile 11 ns/foo/one/97 <<!
XMessage-ID: <cya.foo/one/97>
XShould-expire: yes
XSubject: foo one/97
XExpires: `olddate 1`
X
Xbody
X!
Xoldfile 10 ns/foo/one/98 <<!
XSubject: foo one/98
XMessage-ID: <dn.foo/one/98>
XShould-expire: no
XExpires: `olddate -1`
X
Xbody
X!
Xoldfile 11 ns/foo/one/99 <<!
XMessage-ID: <en.foo/one/99>
XShould-expire: no
XExpires: `olddate -1`
XSubject: foo one/99
XMumble: frotz
X
Xbody
X!
Xoldfile 10 ns/foo/one/100 <<!
XSubject: foo one/100
XMessage-ID: <fya.foo/one/100>
XShould-expire: yes
XExpires: `olddate 1`
X
Xbody
X!
X
X# bar/one just has a simple pair
Xoldfile 11 ns/bar/one/99 <<!
XMessage-ID: <gya.bar/one/99>
XShould-expire: yes
XSubject: bar one/99
X
Xbody
X!
Xoldfile 10 ns/bar/one/100 <<!
XMessage-ID: <hn.bar/one/100>
XShould-expire: no
XSubject: bar one/100
X
Xbody
X!
X
X# bletch/one just has a simple pair
Xoldfile 11 ns/bletch/one/99 <<!
XMessage-ID: <iya.bletch/one/99>
XShould-expire: yes
XSubject: bletch one/99
X
Xbody
X!
Xoldfile 10 ns/bletch/one/100 <<!
XMessage-ID: <jn.bletch/one/100>
XShould-expire: no
XSubject: bletch one/100
X
Xbody
X!
X
X# foo.two has a simple pair again
Xoldfile 14 ns/foo/two/99 <<!
XMessage-ID: <kn.foo/two/99>
XShould-expire: no
XSubject: foo two/99
X
Xbody
X!
Xoldfile 16 ns/foo/two/100 <<!
XMessage-ID: <lym.foo/two/100>
XShould-expire: yes
XSubject: foo two/100
X
Xbody
X!
X
X# bar.two, another simple pair
Xoldfile 14 ns/bar/two/99 <<!
XMessage-ID: <mn.bar/two/99>
XShould-expire: no
XSubject: bar two/99
X
Xbody
X!
Xoldfile 16 ns/bar/two/100 <<!
XMessage-ID: <nym.bar/two/100>
XShould-expire: yes
XSubject: bar two/100
X
Xbody
X!
X
X# foo.three adds a purge date
Xoldfile 4 ns/foo/three/98 <<!
XMessage-ID: <on.foo/three/98>
XShould-expire: no
XSubject: foo three/98
X
Xbody
X!
Xoldfile 6 ns/foo/three/99 <<!
XMessage-ID: <pyu.foo/three/99>
XShould-expire: yes
XSubject: foo three/99
X
Xbody
X!
Xoldfile 16 ns/foo/three/100 <<!
XMessage-ID: <qyu.foo/three/100>
XShould-expire: yes
XExpires: `olddate -1`
XSubject: foo three/100
X
Xbody
X!
X
X# bletch.four has both a retain date and a purge date
Xoldfile 9 ns/bletch/four/97 <<!
XMessage-ID: <rn.bletch/four/97>
XShould-expire: no
XSubject: bletch four/97
X
Xbody
X!
Xoldfile 11 ns/bletch/four/98 <<!
XMessage-ID: <sym.bletch/four/98>
XShould-expire: yes
XSubject: bletch four/98
X
Xbody
X!
Xoldfile 3 ns/bletch/four/99 <<!
XMessage-ID: <tn.bletch/four/99>
XShould-expire: no
XExpires: `olddate 1`
XSubject: bletch four/99
X
Xbody
X!
Xoldfile 25 ns/bletch/four/100 <<!
XMessage-ID: <uym.bletch/four/100>
XShould-expire: yes
XExpires: `olddate -1`
XSubject: bletch four/100
X
Xbody
X!
X
X# bar.five gets the catchall at the end and is another simple pair.
Xoldfile 31 ns/bar/five/99 <<!
XMessage-ID: <vy-.bar/five/99>
XShould-expire: yes
XSubject: bar five/99
X
Xbody
X!
Xoldfile 29 ns/bar/five/100 <<!
XMessage-ID: <wn.bar/five/100>
XShould-expire: no
XSubject: bar five/100
X
Xbody
X!
X
X# bletch.six is not in the active file, but is otherwise orthodox
Xoldfile 31 ns/bletch/six/99 <<!
XMessage-ID: <xy-.bletch/six/99>
XShould-expire: yes
XSubject: bletch six/99
X
Xbody
X!
Xoldfile 29 ns/bletch/six/100 <<!
XMessage-ID: <yn.bletch/six/100>
XShould-expire: no
XSubject: bletch six/100
X
Xbody
X!
END_OF_FILE
if test 3614 -ne `wc -c <'expire/ns.p'`; then
    echo shar: \"'expire/ns.p'\" unpacked with wrong size!
fi
# end of 'expire/ns.p'
fi
if test -f 'expire/xargs.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'expire/xargs.c'\"
else
echo shar: Extracting \"'expire/xargs.c'\" \(3713 characters\)
sed "s/^X//" >'expire/xargs.c' <<'END_OF_FILE'
X/*
X * xargs - gather up filenames from input and run command on them
X */
X
X#include <stdio.h>
X#include <sys/param.h>
X
X#define	STREQ(a, b)	(strcmp((a), (b)) == 0)
X
X#ifndef lint
Xstatic char Sccsid[] = "@(#)xargs.c	1.2 of 6 May 86";
X#endif
X
Xchar argchars[NCARGS];		/* Characters of arguments. */
Xchar *argfree = argchars;	/* First free char in argchars. */
Xchar *argbase = argchars;	/* First char after constant args. */
X
Xchar *argptrs[NCARGS/sizeof(char *)];	/* Pointers to arguments. */
Xint nargs = 0;			/* Number of entries in argptrs. */
Xint base = 0;			/* Number of constant entries. */
X
Xint size = 0;			/* Size of total argument bundle so far. */
Xint basesize = 0;		/* Size of constant args. */
X#ifndef XARGMAX
X#define	XARGMAX	(NCARGS - 50)	/* 50 is misc. overhead plus safety margin. */
X#endif
X
X#ifndef OKSTAT
X#define	OKSTAT	1		/* Highest exit status considered normal. */
X#endif
X
Xextern char **environ;
X
Xchar *progname;
Xextern char *mkprogname();
X
X/*
X * main - parse arguments, handle options, main control
X */
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	int c;
X	int errflg = 0;
X	char *cmd;
X	register char **envp;
X	char buf[BUFSIZ];
X	register int len;
X	int maxstat = 0;
X	int thisstat;
X	extern int optind;
X	extern char *optarg;
X
X	progname = mkprogname(argv[0]);
X
X	while ((c = getopt(argc, argv, "")) != EOF)
X		switch (c) {
X		case '?':
X		default:
X			errflg++;
X			break;
X		}
X	if (errflg || optind == argc) {
X		fprintf(stderr, "Usage: %s command [arg] ...\n", progname);
X		exit(2);
X	}
X
X	/* Plug in the constant arguments. */
X	cmd = argv[optind];
X	for (; optind < argc; optind++) {
X		argptrs[nargs++] = argv[optind];
X		size += strlen(argv[optind]) + 1 + sizeof(char *);
X	}
X
X	/* Add in the size of the environment. */
X	for (envp = environ; *envp != NULL; envp++)
X		size += strlen(*envp) + 1 + sizeof(char *);
X
X	/* Establish base. */
X	argbase = argfree;
X	base = nargs;
X	basesize = size;
X	if (basesize >= XARGMAX) {
X		fprintf(stderr, "%s: command too big\n", progname);
X		exit(2);
X	}
X
X	/* And do it. */
X	while (fgets(buf, (int)sizeof(buf), stdin) != NULL) {
X		len = strlen(buf);
X		if (buf[len-1] == '\n')
X			buf[len-1] = '\0';
X		if (basesize + len + 1 + sizeof(char *) >= XARGMAX) {
X			fprintf(stderr, "%s: filename too long: ", progname);
X			fputs(buf, stdout);
X			putchar('\n');
X		} else {
X			if (size + len + 1 + sizeof(char *) >= XARGMAX) {
X				argptrs[nargs++] = NULL;
X				thisstat = runone(cmd, argptrs);
X				if (thisstat > maxstat)
X					maxstat = thisstat;
X				argfree = argbase;
X				nargs = base;
X				size = basesize;
X			}
X			(void) strcpy(argfree, buf);
X			argptrs[nargs++] = argfree;
X			argfree += len + 1;
X			size += len + 1 + sizeof(char *);
X		}
X	}
X	if (nargs > base) {	/* If there are any loose ends... */
X		argptrs[nargs++] = NULL;
X		thisstat = runone(cmd, argptrs);
X		if (thisstat > maxstat)
X			maxstat = thisstat;
X	}
X
X	exit(maxstat);
X}
X
X/*
X * runone - run the command
X */
Xint				/* status of command */
Xrunone(cmd, ptrs)
Xchar *cmd;
Xchar **ptrs;
X{
X	register int pid;
X	int status;
X	int stexit, stcause;
X	register int wpid;
X
X#ifdef DEBUG
X	fprintf(stderr, "run %s ... %s %s ...\n", cmd, ptrs[0], ptrs[1]);
X#endif
X	while ((pid = fork()) < 0)
X		sleep(10);
X	if (pid == 0) {		/* Daughter. */
X		close(0);
X		if (open("/dev/null", 0) != 0) {
X			fprintf(stderr, "%s: can't open /dev/null\n", progname);
X			exit(2);
X		}
X		execvp(cmd, ptrs);
X		fprintf(stderr, "%s: can't find `%s'\n", progname, cmd);
X		exit(2);
X	} else {		/* Parent. */
X		do {
X			wpid = wait(&status);
X		} while (wpid >= 0 && wpid != pid);
X		stexit = (status>>8)&0377;
X		stcause = status&0377;
X		if (stcause != 0 || stexit > OKSTAT) {
X			fprintf(stderr, "%s: `%s' failed\n", progname, cmd);
X			exit(2);
X		}
X		return(stexit);
X	}
X	/* NOTREACHED */
X}
END_OF_FILE
if test 3713 -ne `wc -c <'expire/xargs.c'`; then
    echo shar: \"'expire/xargs.c'\" unpacked with wrong size!
fi
# end of 'expire/xargs.c'
fi
if test -f 'libcnews/path.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libcnews/path.c'\"
else
echo shar: Extracting \"'libcnews/path.c'\" \(3615 characters\)
sed "s/^X//" >'libcnews/path.c' <<'END_OF_FILE'
X/*
X * news path names (and umask)
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include "news.h"
X#include "newspaths.h"
X
X#ifndef NULL
X#define	NULL	0
X#endif
X
X#ifndef NEWSCTL
X#define NEWSCTL "/usr/lib/news"
X#endif
X#ifndef NEWSARTS
X#define NEWSARTS "/usr/spool/news"
X#endif
X#ifndef NEWSBIN
X#define	NEWSBIN	"/usr/lib/newsbin"
X#endif
X#ifndef NEWSUMASK
X#define	NEWSUMASK	002
X#endif
X
Xstatic char *pwd = NULL;	/* Current directory, NULL means unknown. */
Xstatic int dirsset = NO;	/* Have the following been set? */
Xstatic char *arts;
Xstatic char *bin;
Xstatic char *ctl;
X#define	DIRS()	if (!dirsset) setdirs()
Xvoid setdirs();
X
Xextern char *strcpy();
Xextern char *strcat();
Xextern char *getenv();
X
Xextern void unprivileged();	/* user-supplied privilege dropper */
X
X/*
X - spoolfile - historical synonym for artfile
X */
Xchar *
Xspoolfile(base)
Xchar *base;
X{
X	static char wholefile[MAXFILE];
X
X	DIRS();
X
X	if (base == NULL) {	/* he just wants the directory */
X		(void) strcpy(wholefile, arts);
X		return wholefile;
X	}
X
X	if (pwd != NULL && STREQ(pwd, arts))
X		(void) strcpy(wholefile, "");
X	else {
X		(void) strcpy(wholefile, arts);
X		(void) strcat(wholefile, SFNDELIM);
X	}
X	(void) strcat(wholefile, base);
X
X	return wholefile;
X}
X
X/*
X - artfile - best pathname for a file in NEWSARTS
X */
Xchar *
Xartfile(base)
Xchar *base;
X{
X	return spoolfile(base);
X}
X
X/*
X - fullartfile - full pathname for a file in NEWSARTS
X */
Xchar *
Xfullartfile(base)
Xchar *base;
X{
X	register char *p;
X	register char *pwdsave;
X
X	pwdsave = pwd;
X	pwd = NULL;		/* fool spoolfile() into giving full path */
X	p = spoolfile(base);
X	pwd = pwdsave;
X	return p;
X}
X
X/*
X - fullspoolfile - historical synonym for fullartfile
X */
Xchar *
Xfullspoolfile(base)
Xchar *base;
X{
X	return fullartfile(base);
X}
X
X/*
X - libfile - historical synonym for ctlfile
X */
Xchar *
Xlibfile(base)
Xchar *base;
X{
X	static char wholefile[MAXFILE];
X
X	DIRS();
X
X	(void) strcpy(wholefile, ctl);
X	if (base != NULL) {
X		(void) strcat(wholefile, SFNDELIM);
X		(void) strcat(wholefile, base);
X	}
X	return wholefile;
X}
X
X/*
X - ctlfile - full pathname for a file in NEWSCTL
X */
Xchar *
Xctlfile(base)
Xchar *base;
X{
X	return libfile(base);
X}
X
X/*
X - binfile - full pathname for a file in NEWSBIN
X */
Xchar *
Xbinfile(base)
Xchar *base;
X{
X	static char wholefile[MAXFILE];
X
X	DIRS();
X
X	(void) strcpy(wholefile, bin);
X	if (base != NULL) {
X		(void) strcat(wholefile, SFNDELIM);
X		(void) strcat(wholefile, base);
X	}
X	return wholefile;
X}
X
X/*
X - cd - change to a directory, with checking
X */
Xvoid
Xcd(dir)
Xchar *dir;
X{
X	if (chdir(dir) < 0)
X		errunlock("cannot chdir(%s)", dir);
X	pwd = dir;
X}
X
X/*
X - setdirs - set up directories from environment, for use by other functions
X *
X * Invokes user-supplied function unprivileged() if non-standard values used.
X */
Xstatic void
Xsetdirs()
X{
X	register char *p;
X	register int nonstd = NO;
X
X	if (dirsset)
X		return;
X
X	p = getenv("NEWSARTS");
X	if (p == NULL)
X		arts = NEWSARTS;
X	else {
X		arts = p;
X		nonstd = YES;
X	}
X
X	p = getenv("NEWSCTL");
X	if (p == NULL)
X		ctl = NEWSCTL;
X	else {
X		ctl = p;
X		nonstd = YES;
X	}
X
X	p = getenv("NEWSBIN");
X	if (p == NULL)
X		bin = NEWSBIN;
X	else {
X		bin = p;
X		nonstd = YES;
X	}
X
X	dirsset = YES;
X	if (nonstd)
X		unprivileged();
X}
X
X/*
X - newsumask - return suitable value of umask for news stuff
X */
Xint
Xnewsumask()
X{
X	register char *p;
X	register char *scan;
X	register int mask;
X
X	p = getenv("NEWSUMASK");
X	if (p == NULL)
X		return(NEWSUMASK);
X	else {
X		mask = 0;
X		for (scan = p; *scan != '\0'; scan++)
X			if ('0' <= *scan && *scan <= '7' && mask <= 077)
X				mask = (mask << 3) | (*scan - '0');
X			else	/* Garbage, ignore it. */
X				return(NEWSUMASK);
X		return(mask);
X	}
X}
END_OF_FILE
if test 3615 -ne `wc -c <'libcnews/path.c'`; then
    echo shar: \"'libcnews/path.c'\" unpacked with wrong size!
fi
# end of 'libcnews/path.c'
fi
if test -f 'mail/coder/uudecode.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mail/coder/uudecode.c'\"
else
echo shar: Extracting \"'mail/coder/uudecode.c'\" \(3280 characters\)
sed "s/^X//" >'mail/coder/uudecode.c' <<'END_OF_FILE'
X
X/* based on 5.1 (Berkeley) 7/2/83 */
X
X/*
X * uudecode [input]
X *
X * create the specified file, decoding as you go.
X * used with uuencode.
X */
X#include <stdio.h>
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
Xmain(argc, argv)
Xchar **argv;
X{
X	FILE *in, *out;
X	int mode = 0777;
X	char dest[128];
X	char buf[80];
X	char *strcpy(), *strcat();
X
X	/* optional input arg */
X	if (argc > 1) {
X		if ((in = fopen(argv[1], "r")) == NULL) {
X			perror(argv[1]);
X			exit(1);
X		}
X		argv++; argc--;
X	} else
X		in = stdin;
X
X	if (argc != 1) {
X		(void) fprintf(stderr, "Usage: uudecode [infile]\n");
X		exit(2);
X	}
X
X	/* search for header line */
X	for (;;) {
X		if (fgets(buf, sizeof buf, in) == NULL) {
X			(void) fprintf(stderr, "No begin line\n");
X			exit(3);
X		}
X		if (strncmp(buf, "begin ", 6) == 0)
X			break;
X	}
X	dest[0] = '\0';
X	(void) sscanf(buf, "begin %o %s", &mode, dest);
X
X	/* handle ~user/file format */
X	if (dest[0] == '~') {
X		char *sl;
X		struct passwd *getpwnam();
X		char *index();
X		struct passwd *user;
X		char dnbuf[100];
X
X		sl = index(dest, '/');
X		if (sl == NULL) {
X			(void) fprintf(stderr, "Illegal ~user\n");
X			exit(3);
X		}
X		*sl++ = 0;
X		user = getpwnam(dest+1);
X		if (user == NULL) {
X			(void) fprintf(stderr, "No such user as %s\n", dest);
X			exit(4);
X		}
X		(void) strcpy(dnbuf, user->pw_dir);
X		(void) strcat(dnbuf, "/");
X		(void) strcat(dnbuf, sl);
X		(void) strcpy(dest, dnbuf);
X	}
X
X	/* create output file */
X	out = fopen(dest, "w");
X	if (out == NULL) {
X		perror(dest);
X		exit(4);
X	}
X	(void) chmod(dest, mode);
X
X	decode(in, out);
X
X	if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) {
X		(void) fprintf(stderr, "No end line\n");
X		exit(5);
X	}
X	exit(0);
X}
X
X/*
X * copy from in to out, decoding as you go along.
X */
Xdecode(in, out)
XFILE *in;
XFILE *out;
X{
X	register char *ibp, *obp;
X	register int inbyte, outbyte;
X	register int loops, incount;
X	char inbuf[120];		/* allow for uuencode to grow lines */
X	char outbuf[120];
X
X/* single character decode */
X#define DEC(c)	(((c) - ' ') & 077)	/* N.B.: c is evaluated exactly once */
X
X	for (; ; ) {
X		if (fgets(inbuf, sizeof inbuf, in) == NULL) {
X			(void) printf("Short file\n");
X			exit(10);		/* premature EOF */
X		}
X		incount = DEC(inbuf[0]);
X		if (incount <= 0)
X			break;			/* EOF */
X
X		ibp = &inbuf[1];		/* skip line length */
X		obp = outbuf;
X		for (loops = incount / 3; --loops >= 0; ) {	/* inner loop */
X			/*
X			 * output a group of 3 bytes (4 input characters).
X			 * the input chars are pointed to by ibp, they are to
X			 * be output via obp.  incount is used to tell us
X			 * not to output all of them at the end of the line.
X			 */
X			outbyte = DEC(*ibp++) << 2;
X			*obp++ = outbyte | ((inbyte = DEC(*ibp++)) >> 4);
X			outbyte = inbyte << 4;
X			*obp++ = outbyte | ((inbyte = DEC(*ibp++)) >> 2);
X			*obp++ = (inbyte << 6) | DEC(*ibp++);
X		}
X		loops = incount % 3;
X		if (loops > 0) {
X			/*
X			 * finish off the remaining bytes (loops < 3).
X			 */
X			if (--loops >= 0) {
X				outbyte = DEC(*ibp++) << 2;
X				*obp++ = outbyte | ((inbyte = DEC(*ibp++)) >> 4);
X			}
X			if (--loops >= 0) {
X				outbyte = inbyte << 4;
X				*obp++ = outbyte | ((inbyte = DEC(*ibp++)) >> 2);
X			}
X			if (--loops >= 0)
X				*obp++ = (inbyte << 6) | DEC(*ibp++);
X		}
X		*obp = '\0';
X		(void) fwrite(outbuf, 1, obp - outbuf, out);
X	}
X}
END_OF_FILE
if test 3280 -ne `wc -c <'mail/coder/uudecode.c'`; then
    echo shar: \"'mail/coder/uudecode.c'\" unpacked with wrong size!
fi
# end of 'mail/coder/uudecode.c'
fi
if test -f 'rna/active.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rna/active.c'\"
else
echo shar: Extracting \"'rna/active.c'\" \(3032 characters\)
sed "s/^X//" >'rna/active.c' <<'END_OF_FILE'
X/*
X * active file handling routines
X *
X * format of file:
X *	<groupname> ' ' <5 digit #> ' ' <5 digit #> ' ' flag '\n'
X *			  (seq)		  (low)
X */
X
X#include "defs.h"
X
Xstatic char actname[]	 = ACTIVE;
Xstatic int lineno;
Xstatic active	*alist;
X
X/*
X * getseq - Get next sequence number for this group
X *	    and update active file.
X *	    If group missing append to file.
X */
Xchar *
Xgetseq(group)
Xchar *group;
X{
X	register FILE	*f;
X	register int i;
X	char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
X	extern char *itoa();
X
X	f = fopenl(actname);
X	lineno = 0;
X	while (getline(f, gbuf, dbuf, dbuf2))
X		if (CMP(gbuf, group) == 0) {
X			i = atoi(dbuf);
X			i++;
X			fseek(f, -12L, 1);
X			(void) fprintf(f, "%05d", i);
X			fclose(f);
X#if !AUSAM
X			unlock(actname);
X#endif
X			return itoa(i);
X		}
X	(void) fprintf(f, "%s 00001 00001 y\n", group);
X	fclose(f);
X#if !AUSAM
X	unlock(actname);
X#endif
X	return itoa(1);
X}
X
X
Xstatic
Xgetline(f, g, d, d2)
Xregister FILE *f;
Xchar *g, *d, *d2;
X{
X	register int c;
X	register char *s;
X
X	lineno++;
X	s = g;
X	while ((c = getc(f)) != ' ' && c != EOF)
X		*s++ = c;
X	*s = '\0';
X
X	if (c != EOF) {
X		s = d;
X		while ((c = getc(f)) != EOF && isdigit(c))
X			*s++ = c;
X		*s = '\0';
X
X		s = d2;
X		if (c == ' ')
X			while ((c = getc(f)) != EOF && isdigit(c))
X				*s++ = c;
X		*s = '\0';
X
X		if (c == ' ')
X			while ((c = getc(f)) != EOF && c != '\n')
X				;		/* eat flag */
X	}
X
X	if (c != EOF && (c != '\n' || !*d || !*d2))
X		error("%s: bad format: line %d", actname, lineno);
X	return c != EOF;
X}
X
X
X/*
X * build internal active file structure
X */
Xactive *
Xreadactive()
X{
X	register FILE	*f;
X	register active	*ap, *last;
X	char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
X
X	alist = last = NIL(active);
X	f = fopenf(actname, "r");
X	lineno = 0;
X	while (getline(f, gbuf, dbuf, dbuf2)) {
X		ap = NEW(active);
X		ap->a_name = newstr(gbuf);
X		ap->a_seq = atoi(dbuf);
X		ap->a_low = atoi(dbuf2);
X		ap->a_next = NIL(active);
X		if (!alist)
X			alist = ap;
X		else
X			last->a_next = ap;
X		last = ap;
X	}
X	fclose(f);
X	return alist;
X}
X
X
X/*
X * return pointer to named group
X */
Xactive *
Xactivep(grp)
Xregister char *grp;
X{
X	register active	*ap;
X
X	for (ap = alist; ap; ap = ap->a_next)
X		if (CMP(grp, ap->a_name) == 0)
X			break;
X	return ap;
X}
X
X
X/*
X * setlow - set the low number for this group
X */
Xsetlow(group, low)
Xchar *group;
Xint low;
X{
X	register FILE	*f;
X	char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
X	extern char *itoa();
X
X	f = fopenl(actname);
X	lineno = 0;
X	while (getline(f, gbuf, dbuf, dbuf2))
X		if (CMP(gbuf, group) == 0) {
X			fseek(f, -6L, 1);
X			(void) fprintf(f, "%05d", low);
X			break;
X		}
X	fclose(f);
X#if !AUSAM
X	unlock(actname);
X#endif
X}
X
X
X
X/*
X * initgrp - initialise an entry for this group
X */
Xinitgrp(group)
Xchar *group;
X{
X	register FILE	*f;
X	char gbuf[BUFSIZ / 2], dbuf[BUFSIZ / 4], dbuf2[BUFSIZ / 4];
X
X	f = fopenl(actname);
X	lineno = 0;
X	while (getline(f, gbuf, dbuf, dbuf2))
X		if (CMP(gbuf, group) == 0) {
X#if !AUSAM
X			unlock(actname);
X#endif
X			return;
X		}
X	(void) fprintf(f, "%s 00000 00001\n", group);
X
X}
END_OF_FILE
if test 3032 -ne `wc -c <'rna/active.c'`; then
    echo shar: \"'rna/active.c'\" unpacked with wrong size!
fi
# end of 'rna/active.c'
fi
if test -f 'rna/history.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rna/history.c'\"
else
echo shar: Extracting \"'rna/history.c'\" \(3647 characters\)
sed "s/^X//" >'rna/history.c' <<'END_OF_FILE'
X/*
X * History file
X * each line contains a message-id, install or expire time
X * names of linked files
X */
X
X#include "defs.h"
X
Xstatic char histname[]	 = HISTORY;
Xstatic char *histid;			/* messageid to save */
Xstatic char *histline;			/* list of linked files */
Xstatic long etime;			/* expire time */
X
Xtypedef enum stypes { 
X	chk, delete } stype;
X
X/*
X * do things with history file
X * chk - see if id present
X * delete - delete article with id
X */
Xstatic bool
Xsearchhist(id, type)
Xchar *id;
Xstype type;
X{
X	register FILE	*f;
X	register char *s, *name;
X	register bool	found;
X	char buf[BUFSIZ * 2];
X
X	extern char *newsdir;
X
X	f = fopenl(histname);
X
X	found = false;
X	while (fgets(buf, sizeof(buf), f)) {
X		if (s = strchr(buf, ' '))
X			*s = '\0';
X		else
X			error("Bad format: %s", histname);
X		if (CMP(buf, id) == 0) {
X			found = true;
X			break;
X		}
X	}
X	if (found && type == delete) {
X		if ((name = strchr(s + 1, ' ')) == NIL(char))
X			error("Bad format: %s", histname);
X		name++;
X		while (name && (s = strpbrk(name, " \n"))) {
X			*s = '\0';
X			name = newstr3(newsdir, "/", name);
X			remove(name);
X			free(name);
X			name = s + 1;
X		}
X	}
X	fclose(f);
X#if !AUSAM
X	unlock(histname);
X#endif
X	return found;
X}
X
X
X/*
X * delete files given id
X */
Xbool
Xcancel(id)
Xchar *id;
X{
X	bool searchhist();
X
X	return searchhist(id, delete);
X}
X
X
X/*
X * check if article has been recieved
X */
Xbool
Xchkhist(id)
Xchar *id;
X{
X	bool searchhist();
X
X	return searchhist(id, chk);
X}
X
X
X/*
X * scan history, clearing uflag list entry if id not seen
X */
Xscanhist(ulist, usize)
Xchar **ulist;
Xint usize;
X{
X	register FILE	*f;
X	register char *s, **found;
X	register int i;
X	char *key[1];
X	char buf[BUFSIZ * 2];
X	bool		 * seen;
X
X	extern char *newsdir;
X
X	seen = (bool * ) myalloc((int) sizeof(bool) * usize);
X	memset((char *)seen, 0, (int) sizeof(bool) * usize);
X
X	f = fopenf(histname, "r");
X	while (fgets(buf, sizeof(buf), f)) {
X		if (s = strchr(buf, ' '))
X			*s = '\0';
X		else
X			error("Bad format: %s", histname);
X		key[0] = buf;
X		found = (char **) bsearch((char *) key, (char *) ulist, (unsigned) usize,
X		     sizeof(char *), strpcmp);
X		if (found)
X			seen[found - ulist] = true;
X	}
X	fclose(f);
X
X	for (i = 0; i < usize; i++)
X		if (!seen[i]) {
X			free(ulist[i]);
X			ulist[i] = NIL(char);
X		}
X	free((char *)seen);
X}
X
X
X/*
X * open hist file, write id and time
X */
Xopenhist(hp)
Xheader *hp;
X{
X
X	histid = newstr(hp->h_messageid);
X	if (hp->h_expires)
X		etime = atot(hp->h_expires);
X	else
X		etime = 0L;
X	histline = NIL(char);
X}
X
X
X/*
X * write name of file article resides into history file
X */
Xwritehist(fname)
Xchar *fname;
X{
X	histline = (histline ? catstr2(histline, " ", fname) : newstr(fname));
X}
X
X
X/*
X * close history file
X */
Xclosehist()
X{
X	register FILE	*f;
X	extern long now;
X
X	f = fopenl(histname);
X	fseek(f, 0L, 2);
X	(void) fprintf(f, "%s %s%ld %s\n", histid, etime ? "E" : "", etime ? etime :
X	    now, histline);
X	fclose(f);
X#if !AUSAM
X	unlock(histname);
X#endif
X	free(histid); 
X	free(histline);
X}
X
X
X/*
X * remove a news item
X * check owner first
X */
Xstatic
Xremove(fname)
Xchar *fname;
X{
X	header			h;
X	FILE			 * f;
X	register char *s, *mname;
X
X#if AUSAM
X	extern struct pwent pe;
X#else
X	extern struct passwd *pp;
X#endif
X	extern char systemid[];
X	extern bool		su;
X	extern bool		pflag;
X
X	if (!su && !pflag) {
X		f = fopenf(fname, "r");
X		gethead(f, &h);
X		fclose(f);
X		if (s = strchr(h.h_from, ' '))
X			*s = '\0';
X		mname = newstr5(
X#if AUSAM
X				pe.pw_strings[LNAME],
X#else
X				pp->pw_name,
X#endif
X			"@", systemid, ".", MYDOMAIN);
X		if (CMP(mname, h.h_from) != 0)
X			error("Can't cancel articles you didn't write.");
X		free(mname);
X	}
X	if (unlink(fname) != 0)
X		error("Couldn't unlink %s", fname);
X
X}
END_OF_FILE
if test 3647 -ne `wc -c <'rna/history.c'`; then
    echo shar: \"'rna/history.c'\" unpacked with wrong size!
fi
# end of 'rna/history.c'
fi
if test -f 'rnews/README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnews/README'\"
else
echo shar: Extracting \"'rnews/README'\" \(3793 characters\)
sed "s/^X//" >'rnews/README' <<'END_OF_FILE'
XThis is an alpha test release.  Do not distribute modified copies of it;
Xsee the COPYRIGHT file for details.
X
XSend bug reports to utzoo!cnews-alpha.  This software is believed to
Xwork, though it could doubtless stand some improvement.  The code is
Xgoing to be cleaned up and possibly sped up before general release.
X
X
X``yer about to be boarded, ye scurvy network news dogs! har har ...''
X		-- Oliver Wendell Jones, Bloom County Hacker & Cracker
X
X``No news is good news.''
X``When bigger machines are built, netnews will saturate them.''
X``USENET -- All the news that's fit to `N'.''
X		-- /usr/games/fortune
X
X``B news is Bad news.''
X``Net news is the television of computing.''
X		-- Geoff Collyer
X
XDoes your inews wallow in the mud like a pregnant sow? Does your expire
Xflop on its back, wiggle its feet and gurgle pathetically?  Then you
Xneed new, improved *C news*, the sentient being's news system: no more
Xodious Relay-Version headers, no more sluggish machines caused by
Xoverfed news software.  Real locking.  No line-eater bugs.
X
XAvailable from fine news administrators everywhere.  C news.
X___
X
XAssumptions:
X	you already have B news and possibly rn running
X	you personally installed B news
X	you are now upgrading to C news
X
XBefore using make for anything else, you must
X
X	make variant
X
Xwhere variant is your UNIX variant: v7, v8, v9, bsd42 or usg.
XIt will tell you to edit the makefile DEPSRC and DEPOBJ definitions to match.
X
XIf you need a roadmap, see ../usr.lib/README.
X
X../expire and ../time require that /usr/include/time.h exists.
XIf it doesn't exist on your (4.2BSD) system, thanks to gratuitous
Xtinkering (at UCB), execute
X
X	cd /usr/include; ln -s sys/time.h
X
XThis may require super-user privileges, which should be easy to obtain
Xon 4.2.
X
XAfter compiling inews, install it as /usr/lib/news/realinews,
Xsetuid-news.  On older systems, you will to also install a small
Xprogram, setnewids, setuid-root.  If this worries you, read
Xsetnewsids.c; all it does is execute setgid(), setuid() to the "news"
Xgroup and user if they exist, otherwise realinews's real ids. Install
Xsh/inews as /usr/bin/inews, rnews.sh as /usr/bin/rnews and
X/usr/bin/cunbatch.  You can test realinews by giving NEWSCTL, NEWSBIN
Xor NEWSARTS environment variables to change the library, binary or
Xspool directories and I encourage this.
X
XIf you plan to run rn, you'll need the latest rn patches to allow Xref:
Xto work without Relay-Version:.
X
XYou can get postnews from B news & Pnews from rn.
X
XYour sys file should not refer to a given batch file (with the F or f
Xflags) more than once, or the batch file will be scrambled; this will be
Xfixed and isn't a disaster as the C batcher is quite flexible and can
Xcompensate.  The Ln flag isn't yet fully implemented.
X
XIf your `domain' isn't "uucp", you will need to put your domain name in
X/usr/lib/news/domain.  No upper case letters in your new domain please,
Xthere is no call for it and it just looks ugly.
X
XYou must remove /usr/lib/news/LOCK* and /usr/lib/news/lock.* somewhere
Xin /etc/rc*.  Thus you must only permit rnews to run on file servers.
X
XYou'll need compress for compressing or uncompressing batches of news.
XSee the contact person of your news feed or the moderator of the
Xnewsgroup comp.sources.unix.
X
XSee the anews directory for conversion filters from A to B and back.
X
XYou'll need to install /usr/lib/news/gngp (see ../gngp) before inews
Xwill work.
X
XB-2.11-isms: your /usr/lib/news/mailpaths file must be updated to point
Xat your nearest backbone site.  A 5th sys file field for Distribution:
Xpatterns is here (add them in sys after the subscription list, separated
Xby "/"), and a 6th field for excluded hosts is half-here, separated by
X"/" from the system name.  Active file support for 4 fields and the m
Xflag are here.
X
XGood Luck.
X
X	Geoff Collyer
END_OF_FILE
if test 3793 -ne `wc -c <'rnews/README'`; then
    echo shar: \"'rnews/README'\" unpacked with wrong size!
fi
# end of 'rnews/README'
fi
if test -f 'rnews/active.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnews/active.c'\"
else
echo shar: Extracting \"'rnews/active.c'\" \(3462 characters\)
sed "s/^X//" >'rnews/active.c' <<'END_OF_FILE'
X/*
X * active file access functions (in-memory version)
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "active.h"
X#include "news.h"
X#include "newspaths.h"
X
X#define MAXNGS 2000
X
Xstatic FILE *fp = NULL;
Xstatic char filerelname[] = "active";
Xstatic char *active = NULL;	/* points at entire active file */
Xstatic int actsize;		/* bytes in active: type int determined by fread */
Xstatic unsigned artlines;	/* lines in artlnps actually used */
X/* TODO: make this a linked list or realloc to avoid the MAXNGS limit */
Xstatic char *artlnps[MAXNGS];	/* point at lines in active file */
X
Xlong
Xincartnum(ng, inc)
Xchar *ng;
Xint inc;
X{
X	register int nglen = strlen(ng);
X	register char *pos;
X	register unsigned line = 0;
X	register long nextart = -1;
X	char artnumstr[ARTNUMWIDTH + 1];
X	extern char ldzeropad[];
X
X	if (artload() != ST_OKAY)
X		return nextart;
X	while (pos = artlnps[line], line++ < artlines && pos[0] != '\0')
X		if (STREQN(pos, ng, nglen) && pos[nglen] == ' ') {
X			nextart = atol(&pos[nglen + 1]) + inc;
X			(void) sprintf(artnumstr, ldzeropad,
X				ARTNUMWIDTH, ARTNUMWIDTH, nextart);
X			(void) strncpy(&pos[nglen + 1], artnumstr, ARTNUMWIDTH);
X			break;
X		}
X	return nextart;
X}
X
Xint
Xartload()				/* reload any cached data */
X{
X	int status = 0;
X
X	if (fp == NULL)
X		if ((fp = fopenwclex(libfile(filerelname), "r+")) == NULL)
X			status |= ST_DROPPED;
X	if (fp != NULL && active == NULL) {	/* file open, no cache */
X		struct stat sb;
X
X		if (fstat(fileno(fp), &sb) < 0)
X			warning("can't fstat %s", libfile(filerelname));
X		else if (actsize = sb.st_size, /* squeeze into an int */
X		    (unsigned)actsize != sb.st_size)
X			warning("%s won't fit into memory", libfile(filerelname));
X		else if ((active = malloc((unsigned)actsize+1)) == NULL)
X			warning("can't allocate memory for %s", libfile(filerelname));
X		else {
X			rewind(fp);
X			/* TODO: read with fgets to avoid linescan() */
X			if (fread(active, 1, actsize, fp) != actsize) {
X				warning("error reading %s", libfile(filerelname));
X				free(active);
X				active = NULL;
X			} else {
X				active[actsize] = '\0';	/* make a proper string */
X				if ((artlines = linescan(active, artlnps,
X				    MAXNGS)) >= MAXNGS) {
X				    	extern char *progname;
X
X					(void) fprintf(stderr,
X						"%s: too many newsgroups in %s\n",
X						progname, libfile(filerelname));
X					free(active);
X					active = NULL;
X				}
X			}
X		}
X		if (active == NULL)
X			status |= ST_DROPPED;	/* give up! */
X	}
X	return status;
X}
X
Xint
Xartsync()				/* sync to disk any cached data */
X{
X	int status = 0;
X
X	if (fp != NULL) {
X		rewind(fp);
X		if (active != NULL && fwrite(active, actsize, 1, fp) != 1 ||
X		    fclose(fp) == EOF) {
X			warning("error writing %s", libfile(filerelname));
X			status |= ST_DROPPED;
X		}
X	}
X	fp = NULL;
X	if (active != NULL)
X		free(active);		/* give back memory active used */
X	active = NULL;
X	return status;
X}
X
X/*
X * Store in lnarray the addresses of the starts of lines in s.
X * Return the number of lines found; if greater than nent,
X * store only nent and return nent.
X */
Xint
Xlinescan(s, lnarray, nent)
Xregister char *s;
Xregister char **lnarray;
Xregister int nent;
X{
X	register int i = 0;
X	register char *nlp = s;
X
X	if (i < nent)
X		lnarray[i++] = s;
X	while (i < nent && (nlp = index(nlp, '\n')) != NULL)
X		lnarray[i++] = ++nlp;
X	return i;
X}
X
X/* ARGSUSED hdrs */
Xmoderated(hdrs)
Xstruct headers *hdrs;
X{
X	/* TODO: look at 4th field of active file; needs new active.c hook */
X	return NO;			/* stub */
X}
END_OF_FILE
if test 3462 -ne `wc -c <'rnews/active.c'`; then
    echo shar: \"'rnews/active.c'\" unpacked with wrong size!
fi
# end of 'rnews/active.c'
fi
if test -f 'rnews/makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnews/makefile'\"
else
echo shar: Extracting \"'rnews/makefile'\" \(3080 characters\)
sed "s/^X//" >'rnews/makefile' <<'END_OF_FILE'
X# makefile for C news relaynews
X
X# define NOSTOREVAL if your dbm store() returns no value (as in orig. v7)
X# -I. for fcntl.h if present
XDEFINES= -I../include -I. -DSTATIC=
X# -Dvoid=int			# if your compiler doesn't understand void's
X# -DMAXLONG=017777777777L	# if your compiler lacks "unsigned long" type
X# -Dindex=strchr -Drindex=strrchr	# if not on (System III or V or PWB)
X
XCFLAGS=-O -f68881 $(DEFINES) # -pg # -Z: John Bruner's Z0MAGIC (unmapped first page)
XLIBS= -ldbm # -lstdio
XLLIBS=-llocal
XPROPTS=-l132
XP=impr -p
X
XPOSSDEPFILES=fcntl.h gethostname.c getwd.c dbm.c mkdir.c ftime.c clsexec.c memcpy.c
X# adjust next three lines for your OS; sources are links to vers/*/*.c
XDEPHDR=
XDEPSRC= clsexec.c memcpy.c zeropad.c
XDEPOBJ= clsexec.o memcpy.o zeropad.o
X
XLIBSRCS= ../libcnews/*.c
XLIBOBJS= ../libcnews/libcnews.a ../libc/libc.a
XSRC=relaynews.c active.c caches.c checkdir.c control.c fileart.c \
X	headers.c history.c hostname.c io.c msgs.c procart.c \
X	string.c sys.c transmit.c $(DEPSRC) $(LIBSRCS)
XOBJ=relaynews.o active.o caches.o checkdir.o control.o fileart.o \
X	headers.o history.o hostname.o io.o msgs.o procart.o \
X	string.o sys.o transmit.o $(DEPOBJ) $(LIBOBJS)
XFILES=$(NONCFILES) $(CFILES)
XNONCFILES= TODO* COPYRIGHT README ads/README ads/[0-9]* \
X	inews anne.jones tear rnews makefile
XCFILES= ../include/*.h cpu.h headers.h system.h $(DEPHDR) $(SRC)
XLINT=lint
XLINTFLAGS=-haz $(DEFINES)
X
Xrelaynews: $(OBJ) ../libcnews/*.c
X	(cd ../libcnews; make)
X	$(CC) $(CFLAGS) $(OBJ) $(LIBS) -o $@
Xlint: $(SRC)
X	$(LINT) $(LINTFLAGS) $(SRC) $(LIBS) $(LLIBS) | egrep -v ':$$'
Xlintport: $(SRC)
X	$(LINT) $(LINTFLAGS) -p $(SRC) $(LIBS) $(LLIBS)
X
XTODO.grep: TODO
X	-egrep TODO TODO ../include/*.h *.h *.c sh/* >$@
X	-egrep TODO ../libc/memcpy.fast/src/*.c ../libcnews/*.c >>$@
X
Xv7 v8 v9 usg bsd42: clean
X	for file in vers/$@/*.c; do ln $$file; done
X	@echo 'Now edit makefile DEPSRC and DEPOBJ definitions to match:'
X	@echo vers/$@/*.c | sed 's;vers/$@/;;g'
X
Xprint: printc printnonc
X	touch $@
Xprintc: $(CFILES)
X	/usr/bin/pp -T300 -fR $? | dimp -t | impr
X	touch $@
Xprintnonc: $(NONCFILES)
X	pr $(PROPTS) $? | $P
X	touch $@
Xdistr: $(FILES)
X	(echo relaynews update of `date`; echo ""; bundle $?) | /bin/mail cnews-updates
X	touch $@
Xclean:
X	rm -f core a.out relaynews *.o $(POSSDEPFILES)
X
X# header dependencies follow
Xactive.o:	active.h ../include/news.h ../include/newspaths.h
Xcaches.o:	../include/news.h
Xcheckdir.o:	../include/news.h
Xcontrol.o:	../include/news.h ../include/newspaths.h headers.h history.h
Xfileart.o:	../include/news.h ../include/newspaths.h active.h headers.h system.h
Xheaders.o:	../include/news.h headers.h
Xhistory.o:	../include/news.h ../include/newspaths.h headers.h
Xhostname.o:	../include/news.h ../include/newspaths.h
Xio.o:		../include/news.h
Xmsgs.o:		../include/news.h
Xprocart.o:	../include/news.h active.h headers.h system.h
Xrelaynews.o:	../include/news.h ../include/newspaths.h active.h cpu.h headers.h system.h
Xstring.o:	../include/news.h
Xsys.o:		../include/news.h ../include/newspaths.h system.h
Xtransmit.o:	../include/news.h ../include/newspaths.h headers.h system.h
END_OF_FILE
if test 3080 -ne `wc -c <'rnews/makefile'`; then
    echo shar: \"'rnews/makefile'\" unpacked with wrong size!
fi
# end of 'rnews/makefile'
fi
if test -f 'rnews/speed/mem/active.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnews/speed/mem/active.c'\"
else
echo shar: Extracting \"'rnews/speed/mem/active.c'\" \(3682 characters\)
sed "s/^X//" >'rnews/speed/mem/active.c' <<'END_OF_FILE'
X/*
X * active file access functions (in-memory version)
X *	TODO: use hashing for speed & to eliminate MAXNGS
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "news.h"
X
X#define MAXNGS 2000
X
Xstatic FILE *fp = NULL;
Xstatic char filerelname[] = "active";
Xstatic char *active = NULL;	/* points at entire active file */
Xstatic int actsize;		/* bytes in active: type int determined by fread */
Xstatic unsigned artlines;	/* lines in artlnps actually used */
X/* TODO: make this a linked list to avoid the MAXNGS limit? */
Xstatic char *artlnps[MAXNGS];	/* point at lines in active file */
X
X/* TODO: make these two macros in a header file? */
Xlong
Xnxtartnum(ng)
Xchar *ng;
X{
X	long incartnum();
X
X	return incartnum(ng, 1);
X}
X
Xlong
Xprevartnum(ng)
Xchar *ng;
X{
X	long incartnum();
X
X	return incartnum(ng, -1);
X}
X
Xstatic long
Xincartnum(ng, inc)
Xchar *ng;
Xint inc;
X{
X	register int nglen = strlen(ng);
X	register char *pos;
X	register unsigned line = 0;
X	register long nextart = -1;
X	char artnumstr[ARTNUMWIDTH + 1];
X	extern char ldzeropad[];
X	char *sprintf(), *strncpy();
X	long atol();
X
X	if (artload() != ST_OKAY)
X		return nextart;
X	while (pos = artlnps[line], line++ < artlines && pos[0] != '\0')
X		if (STREQN(pos, ng, nglen) && pos[nglen] == ' ') {
X			nextart = atol(&pos[nglen + 1]) + inc;
X			(void) sprintf(artnumstr, ldzeropad,
X				ARTNUMWIDTH, ARTNUMWIDTH, nextart);
X			(void) strncpy(&pos[nglen + 1], artnumstr, ARTNUMWIDTH);
X			break;
X		}
X	return nextart;
X}
X
Xint
Xartload()				/* reload any cached data */
X{
X	int status = 0;
X	char *libfile();
X	FILE *fopenwclex();
X
X	if (fp == NULL)
X		if ((fp = fopenwclex(libfile(filerelname), "r+")) == NULL)
X			status |= ST_DROPPED;
X	if (fp != NULL && active == NULL) {	/* file open, no cache */
X		struct stat sb;
X		char *malloc();
X
X		if (fstat(fileno(fp), &sb) < 0)
X			warning("can't fstat %s", libfile(filerelname));
X		else if (actsize = sb.st_size, /* squeeze into an int */
X		    (unsigned)actsize != sb.st_size)
X			warning("%s won't fit into memory", libfile(filerelname));
X		else if ((active = malloc((unsigned)actsize+1)) == NULL)
X			warning("can't allocate memory for %s", libfile(filerelname));
X		else {
X			rewind(fp);
X			/* TODO: read with fgets to avoid linescan() */
X			if (fread(active, 1, actsize, fp) != actsize) {
X				warning("error reading %s", libfile(filerelname));
X				free(active);
X				active = NULL;
X			} else {
X				active[actsize] = '\0';	/* make a proper string */
X				if ((artlines = linescan(active, artlnps,
X				    MAXNGS)) >= MAXNGS) {
X				    	extern char *progname;
X
X					(void) fprintf(stderr,
X						"%s: too many newsgroups in %s\n",
X						progname, libfile(filerelname));
X					free(active);
X					active = NULL;
X				}
X			}
X		}
X		if (active == NULL)
X			status |= ST_DROPPED;	/* give up! */
X	}
X	return status;
X}
X
Xint
Xartsync()				/* sync to disk any cached data */
X{
X	int status = 0;
X	char *libfile();
X
X	if (fp != NULL) {
X		rewind(fp);
X		if (active != NULL && fwrite(active, actsize, 1, fp) != 1) {
X			warning("error writing %s", libfile(filerelname));
X			status |= ST_DROPPED;
X		}
X		if (fclose(fp) == EOF)
X			status |= ST_DROPPED;
X	}
X	fp = NULL;
X	if (active != NULL)
X		free(active);		/* give back memory active used */
X	active = NULL;
X	return status;
X}
X
X/*
X * Store in lnarray the addresses of the starts of lines in s.
X * Return the number of lines found; if greater than nent,
X * store only nent and return nent.
X */
Xint
Xlinescan(s, lnarray, nent)
Xregister char *s;
Xregister char **lnarray;
Xregister int nent;
X{
X	register int i = 0;
X	register char *nlp = s;
X	char *index();
X
X	if (i < nent)
X		lnarray[i++] = s;
X	while (i < nent && (nlp = index(nlp, '\n')) != NULL)
X		lnarray[i++] = ++nlp;
X	return i;
X}
END_OF_FILE
if test 3682 -ne `wc -c <'rnews/speed/mem/active.c'`; then
    echo shar: \"'rnews/speed/mem/active.c'\" unpacked with wrong size!
fi
# end of 'rnews/speed/mem/active.c'
fi
if test -f 'rnews/speed/mem/sys.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnews/speed/mem/sys.c'\"
else
echo shar: Extracting \"'rnews/speed/mem/sys.c'\" \(4014 characters\)
sed "s/^X//" >'rnews/speed/mem/sys.c' <<'END_OF_FILE'
X/*
X * inews sys file reading functions (in-memory version)
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "news.h"
X#include "system.h"
X
Xstatic FILE *fp = NULL;		/* descriptor for libfile("sys") */
Xstatic char filerelname[] = "sys";
Xstatic char defaultcmd[] = "exit 1";	/* reminder to bozo admins */
Xstatic struct system *firstsys = NULL;	/* cache */
Xstatic struct system *currsys = NULL;	/* current system */
X
Xstruct system *
Xoursys()			/* return our sys entry */
X{
X	register struct system *sys;
X	static struct system fakesys;
X	char *hostname();
X	struct system *nextsys();
X
X	rewsys();
X	while ((sys = nextsys()) != NULL && !STREQ(sys->sy_name, hostname()))
X		;
X	if (sys == NULL) {		/* no entry; cook one up */
X		fakesys.sy_name = hostname();
X		fakesys.sy_ngs = "all";
X		fakesys.sy_flags = 0;
X		fakesys.sy_lochops = 0;
X		fakesys.sy_cmd = defaultcmd;
X		fakesys.sy_next = NULL;
X		sys = &fakesys;
X	}
X	return sys;
X}
X
X/*
X * Returned pointer points at a static struct whose members
X * point at static storage.
X */
Xstruct system *
Xnextsys()				/* return next sys entry */
X{
X	struct system *retsys;
X	char *libfile();
X	FILE *fopenwclex();
X
X	if (firstsys == NULL && fp == NULL)
X		if ((fp = fopenwclex(libfile(filerelname), "r")) == NULL)
X			return NULL;
X	if (fp != NULL && firstsys == NULL)	/* file open, no cache */
X		readsys();			/* read & parse fp */
X	retsys = currsys;			/* save current ptr. */
X	if (currsys != NULL)
X		currsys = currsys->sy_next;	/* advance current ptr. */
X	return retsys;
X}
X
Xrewsys()
X{
X	currsys = firstsys;
X}
X
Xstatic char *curr, *next;			/* parsing state */
X
Xstatic
Xreadsys()
X{
X	char sysline[MAXLINE];
X
X	rewind(fp);
X	/* TODO: write & use cfgets to read continued lines (need bigger MAXLINE) */
X	while (fgets(sysline, sizeof sysline, fp) != NULL)
X		if (sysline[0] != '#' && sysline[0] != '\n') {	/* not a comment */
X			register struct system *sysp;
X			char *flagstring;
X			char *malloc();
X
X			sysp = (struct system *)malloc(sizeof *sysp);
X			if (sysp == NULL)
X				errunlock("out of memory for system structs", "");
X
X			/* parse into sysp */
X			trim(sysline);
X			next = sysline;
X			parse(&sysp->sy_name);
X			parse(&sysp->sy_ngs);
X			parse(&flagstring);
X			parse(&sysp->sy_cmd);
X			/* could check for extra fields here */
X			sysp->sy_flags = flgtobits(flagstring);
X			sysp->sy_lochops = 0;		/* Ln value someday */
X			free(flagstring);		/* malloced by parse */
X			sysp->sy_next = NULL;
X
X			/* fill in any defaults */
X			if (sysp->sy_cmd[0] == '\0') {
X				free(sysp->sy_cmd);	/* malloced by parse */
X				sysp->sy_cmd = defaultcmd;	/* NB not malloced */
X			}
X
X			/* stash *sysp away on the tail of the current list */
X			if (firstsys == NULL)
X				firstsys = sysp;		/* 1st system */
X			else
X				currsys->sy_next = sysp;	/* tack on tail */
X			currsys = sysp;
X		}
X	(void) fclose(fp);		/* file no longer needed */
X	fp = NULL;			/* mark file closed */
X	rewsys();
X}
X
Xparse(into)
Xregister char **into;
X{
X	char *strsave(), *parsecolon();
X
X	curr = next;
X	if (curr == NULL)
X		*into = strsave("");
X	else {
X		next = parsecolon(curr);
X		*into = strsave(curr);
X	}
X	if (*into == NULL)
X		errunlock("out of memory for sys strings", "");
X}
X
Xchar *
Xparsecolon(line)		/* return NULL or ptr. to byte after colon */
Xchar *line;
X{
X	register char *colon;
X
X	INDEX(line, ':', colon);
X	if (colon != NULL)
X		*colon++ = '\0';	/* turn colon into a NUL */
X	return colon;
X}
X
Xstatic int
Xflgtobits(s)
Xregister char *s;
X{
X	register int bits = 0;
X
X	for (; *s != '\0'; s++)
X		switch (*s) {
X		case 'A':
X			errunlock("A news format not supported", "");
X			/* NOTREACHED */
X		case 'B':				/* mostly harmless */
X			break;
X		case 'F':
X			bits |= FLG_BATCH;
X			break;
X		case 'L':
X			bits |= FLG_LOCAL;
X			/* TODO: parse Ln, but maybe not here */
X			break;
X		case 'N':
X			bits |= FLG_IHAVE;
X			errunlock("N flag given but I-have/send-me is not supported", "");
X			/* NOTREACHED */
X		case 'U':
X			bits |= FLG_PERM;
X			break;
X		default:
X			errunlock("unknown sys flag `%s' given", s);
X			/* NOTREACHED */
X		}
X	return bits;
X}
END_OF_FILE
if test 4014 -ne `wc -c <'rnews/speed/mem/sys.c'`; then
    echo shar: \"'rnews/speed/mem/sys.c'\" unpacked with wrong size!
fi
# end of 'rnews/speed/mem/sys.c'
fi
echo shar: End of archive 6 \(of 14\).
##  End of shell archive.
exit 0