[net.sources] news 2.10.2 src part 2

rick@seismo.UUCP (Rick Adams) (09/11/84)

if test ! -d src
then
	mkdir src
fi
echo x - src/csendbatch.sh
sed 's/^X//' >src/csendbatch.sh <<'*-*-END-of-src/csendbatch.sh-*-*'
X: '@(#)csendbatch	1.3	8/21/84'
Xfor rmt in $*
Xdo
X	while test $? -eq 0 -a \( -s BATCHDIR/$rmt -o -s BATCHDIR/$rmt.work \)
X	do
X		LIBDIR/batch BATCHDIR/$rmt 100000 | LIBDIR/compress -q | \
X			if test -s BATCHDIR/$rmt.cmd
X			then
X				BATCHDIR/$rmt.cmd
X			else
X				uux - UUXFLAGS $rmt!cunbatch
X			fi
X	done
Xdone
*-*-END-of-src/csendbatch.sh-*-*
echo x - src/cunbatch.sh
sed 's/^X//' >src/cunbatch.sh <<'*-*-END-of-src/cunbatch.sh-*-*'
Xexec LIBDIR/compress -d | BINDIR/rnews
*-*-END-of-src/cunbatch.sh-*-*
echo x - src/defs.dist
sed 's/^X//' >src/defs.dist <<'*-*-END-of-src/defs.dist-*-*'
X/*
X * defs.h - defines for news-related programs.
X *
X * If you remove any lines here or in your Makefile, make the change
X * to localize.sh so you won't have to redo it for each news release.
X *
X * If TMAIL is undefined, the -M option will be disabled.
X *
X * By convention, the version of the software you are running is taken
X * to be news_version below.
X */
X
X/*	@(#)defs.dist	2.34	9/3/84 */
X
X#define NEWS_VERSION   "B 2.10.2 9/3/84"
X
X#define DAYS	(60L*60L*24L)
X#define WEEKS	(7*DAYS)
X/* Things that very well may require local configuration */
X#ifndef HOME
X#define	ROOTID	10	/* uid of person allowed to cancel anything	*/
X#endif
X#define	N_UMASK 000	/* mask for umask call, 022 for secure system	*/
X#define DFLTEXP	2*WEEKS	/* default no. of seconds to expire in		*/
X#define DFLTSUB "general,all.general"	/* default subscription list	*/
X#define TMAIL	"/usr/ucb/Mail"	/* Mail program that understands -T	*/
X#define	ADMSUB	"general,all.announce"	/* Mandatory subscription list	*/
X#define PAGE	"/usr/ucb/more"	/* Default pager			*/
X#define NOTIFY	"usenet"	/* Tell him about certain ctl messages	*/
X				/* Default xmit command - remove -z if	*/
X#define DFTXMIT	"uux - -r -z %s!rnews < %s" /* your uux can't do it	*/
X#define UXMIT	"uux -r -z -c %s!rnews '<' %s" /* If uux -c is ok	*/
X#define DFTEDITOR "vi"		/* Default editor, see also postnews.	*/
X/* #define UUPROG "euuname"	/* omit for uuname, put in LIBDIR	*/
X#define MANUALLY		/* Don't execute rmgroups, just notify.	*/
X#define BATCH "unbatch"		/* name of unbatcher 		*/
X/* #define LOCALNAME 		/* There is no full name database. 	*/
X/* #define INTERNET		/* Internet mail works locally		*/
X#define MYDOMAIN ".UUCP"	/* Local domain				*/
X/* #define CHEAP		/* don't chown files to news		*/
X/* #define OLD			/* Add extra headers for old neighbors	*/
X/* #define UNAME		/* If uname call is available.		*/
X/* #define GHNAME		/* If gethostname call is available.	*/
X#define V7MAIL			/* Local mail format is V7 ("From ")	*/
X#define SORTACTIVE		/* if you want news presented in the order of the .newsrc */
X#define ZAPNOTES		/* if you want old style notes headers moved into the headers */
X/* #define BSD4_2		/* If you are running 4.2 BSD		*/
X/* #define BSD4_1C		/* If you are running 4.1C BSD		*/
X/* #define SENDMAIL "/usr/lib/sendmail -oi -oem" /* command line to run "sendmail" if you have it	*/
X#define MYORG "Frobozz Inc., St. Louis"	/* My organization.  Please	*/
X				/* include your city (and state, and	*/
X				/* country, if not obvious) in MYORG,	*/
X				/* and please keep it short.		*/
X
X/* Things you might want to change */
X#define NEWSRC  ".newsrc"	/* name of .newsrc file (in home dir)	*/
X#define LINES	512	/* maximum no. of lines in .newsrc		*/
X#define NEGCHAR	'!'	/* newsgroup negation character			*/
X#define DEADTIME 45	/* no. of seconds to wait on deadlock		*/
X#define FMETA	'%'	/* file meta-character for c option		*/
X#ifdef pdp11
X# define BUFLEN	128	/* standard buffer size				*/
X#else
X# define BUFLEN	256	/* standard buffer size				*/
X#endif
X#define LBUFLEN 1024	/* big buffer size				*/
X#define SYSPATH	"PATH=/local/bin:/bin:/usr/bin"	/* default, secure, vanilla path */
X#define LNCNT	16	/* Articles with > LNCNT lines go through pager */
X
X/* Things you probably won't want to change */
X#define PATHLEN 512	/* length of longest source string		*/
X#define	DATELEN	64	/* length of longest allowed date string	*/
X#define	NAMELEN	64	/* length of longest possible message ID	*/
X#define	SNLN	8	/* max significant characters in sysname	*/
X#define	PROTO	'A'	/* old protocol name				*/
X#define NETCHRS	"!:.@^%"/* Punct. chars used for various networks	*/
X#define	TRUE	1	/* boolean true					*/
X#define	FALSE	0	/* boolean false				*/
X#define AFSIZ  5000	/* legal newsgroup file size			*/
X#define	NGDELIM	','	/* delimit character in news group line		*/
*-*-END-of-src/defs.dist-*-*
echo x - src/digest.c
sed 's/^X//' >src/digest.c <<'*-*-END-of-src/digest.c-*-*'
X/*
X * digest - process ARPANET digests
X *
X * Alan Hastings	9/5/82
X *
X * digest(ifile, ofile, header)
X * FILE *ifile, *ofile;
X * struct header *header;
X *
X * returns:	TRUE	EOF reached, exit from readnews.
X *		FALSE	normal exit, continue reading news.
X */
X
Xstatic char *Sccsid = "@(#)digest.c	1.3	4/20/84";
X
X#include "rparams.h"
X
Xstruct art {
X	long	a_hdr;
X	long	a_bod;
X	int	a_blen;
X	int	a_hlen;
X};
X
X#define	loop		for(;;)
X#define	getnum(p, n)	for (n=0; *p>='0' && *p<='9'; p++) n = n*10 + *p-'0'
X#define	errchk(p)	if (*p) goto badopt
X
X#define	MAXART		128
X
Xstruct art	*arts;
Xint		lastart;
X
Xdigest(ifp, ofp, h)
XFILE *ifp, *ofp;
Xstruct hbuf *h;
X{
X	register int	n, curart;
X	struct art	artbuf[MAXART];
X	int		printh, eod, nomore;
X	char		cbuf[BUFLEN], *cmd;
X
X	arts = artbuf;
X	printh = TRUE;
X	nomore = eod = FALSE;
X	curart = 1;
X
X	if (dscan(ifp))
X		return(FALSE);
X
X	dprint(0, ifp, ofp);
X
X	loop {
X		if (nomore) break;
X		if (curart < 1) {
X			curart = 1;
X			eod = nomore = FALSE;
X		}
X		if (curart > lastart) curart = lastart;
X		if (eod) nomore = TRUE;
X		if (printh && !nomore)
X			(void) dhprint(curart, ifp, ofp);
X	getcmd:
X		loop {
X			sigtrap = FALSE;
X			fprintf(ofp, "Digest article %d of %d ", curart, lastart);
X			if (curart==lastart && nomore)
X				fprintf(ofp, "Last digest article ");
X			fprintf(ofp, "(%d lines) More? [%s] ",
X				arts[curart].a_blen, nomore?"snq":"ynq");
X			(void) fflush(ofp);
X			cmd = cbuf;
X			if (fgets(cmd, BUFLEN, stdin))
X				break;
X			if (!sigtrap)
X				return(TRUE);
X			putc('\n', ofp);
X		}
X		nstrip(cmd);
X		while (*cmd==' ' || *cmd=='\t')
X			cmd++;
X		printh = TRUE;
X
X		switch (*cmd++) {
X		case '#':
X			fprintf(ofp, "%d articles in digest\n", lastart);
X			(void) fflush(ofp);
X			printh = FALSE;
X			break;
X
X		case '$':
X			curart = lastart;
X			break;
X
X		case '!':
X			fwait(fsubr(ushell, cmd, (char *)NULL));
X			fprintf(ofp, "!\n");
X			printh = FALSE;
X			break;
X
X		case '\0':
X			if (nomore) {
X				putc('\n', ofp);
X				return(FALSE);
X			}
X			cmd--;
X		case 'y':
X		case 'p':
X			errchk(cmd);
X			dprint(curart++, ifp, ofp);
X			if (curart > lastart)
X				eod = TRUE;
X			break;
X
X		case 'n':
X			errchk(cmd);
X			if (++curart > lastart) {
X				putc('\n', ofp);
X				return(FALSE);
X			}
X			break;
X
X		case '+':
X			getnum(cmd, n);
X			errchk(cmd);
X			if (nomore) {
X				putc('\n', ofp);
X				return(FALSE);
X			}
X			if (n)	curart += n;
X			else {
X				curart += 1;
X				if (curart > lastart)
X					eod = TRUE;
X			}
X			break;
X
X		case '-':
X			getnum(cmd, n);
X			errchk(cmd);
X			eod = nomore = FALSE;
X			curart -= (n) ? n : 1;
X			break;
X
X		case '0': case '1': case '2': case '3': case '4':
X		case '5': case '6': case '7': case '8': case '9':
X			cmd--;
X			getnum(cmd, n);
X			errchk(cmd);
X			curart = n;
X			eod = nomore = FALSE;
X			break;
X
X		case 'q':
X		case 'x':
X			putc('\n', ofp);
X			return(FALSE);
X
X		case '?':
X			fprintf(ofp, "\nDigester options:\n\n");
X			fprintf(ofp, "y\tyes, print article.\n");
X			fprintf(ofp, "n\tno, go to next article.\n");
X			fprintf(ofp, "q\texit from digester.\n");
X			fprintf(ofp, "h\tprint article header.\n");
X			fprintf(ofp, "s file\tsave article in file.\n");
X			fprintf(ofp, "t\ttable of contents.\n");
X			fprintf(ofp, "+[n]\tforward n articles (1).\n");
X			fprintf(ofp, "-[n]\tback n articles (1).\n");
X			fprintf(ofp, "\nh and s may be followed by '-'\n");
X			(void) fflush(ofp);
X			break;
X
X		case 'h':
X			n = curart;
X			if (*cmd=='-') {
X				cmd++;
X				if (n > 1) n--;
X			}
X			errchk(cmd);
X			(void) dhprint(n, ifp, ofp);
X			nomore = printh = FALSE;
X			if (n!=curart)
X				putc('\n', ofp);
X			break;
X
X		case 's':
X		case 'w':
X			n = curart;
X			if (*cmd=='-') {
X				cmd++;
X				if (n > 1) n--;
X			}
X			while (*cmd==' ' || *cmd=='\t')
X				cmd++;
X			dsaveart(n, ifp, ofp, cmd);
X			nomore = printh = FALSE;
X			if (n!=curart)
X				putc('\n', ofp);
X			break;
X
X		case 'H':
X			errchk(cmd);
X			hprint(h, ofp, 1);
X			eod = nomore = FALSE;
X			break;
X
X		case 'T':
X		case 't':
X			errchk(cmd);
X			if (cmd[-1]=='T')
X				hprint(h, ofp, 0);
X			dprint(0, ifp, ofp);
X			eod = nomore = FALSE;
X			break;
X
X		default:
X	badopt:
X			if (!nomore)
X				fprintf(ofp, "y (yes), n (no), ");
X			fprintf(ofp, "q (quit), s file (save), h (header), t (table of contents)\n");
X			fprintf(ofp, "? for help\n");
X			goto getcmd;
X		}
X	}
X	putc('\n', ofp);
X	return(FALSE);
X}
X
Xdscan(ifp)
Xregister FILE *ifp;
X{
X	char		scanbuf[BUFLEN];
X	register int	n, len;
X	register char	*s;
X	register long	pos;
X	short		wasblank;
X
X	n = len = 0;
X	wasblank = FALSE;
X	s = scanbuf;
X	arts[0].a_bod = arts[1].a_hdr = ftell(ifp);
X	arts[0].a_hdr = 0L;
X	arts[1].a_bod = -1L;
X
X	loop {
X		if (sigtrap)
X			return(TRUE);
X		pos = ftell(ifp);
X		if (fgets(s, BUFLEN, ifp)==NULL)
X			*s = '\0';
X		if (wasblank && isheader(s)) {
X			long lastpos;
X			short isblank;
X			short nhlines;
X			arts[n++].a_blen = len;
X			len = 0;
X			nhlines = 0;
X			arts[n].a_hdr = pos;
X			isblank = FALSE;
X			do {
X				lastpos = pos;
X				wasblank = isblank;
X				nhlines++;
X				pos = ftell(ifp);
X				if (fgets(s, BUFLEN, ifp)==NULL)
X					*s = '\0';
X				else
X					len++;
X				isblank = (*s=='\n') ? TRUE : FALSE;
X				if (isblank && nhlines==1)
X					/* one liner--not a header */
X					break;
X			} while ((isblank && !wasblank) || isheader(s));
X			if ((!isblank && !wasblank) || nhlines < 2) {
X				/* oops! not a header... back off */
X				arts[n].a_hdr = arts[n-1].a_bod;
X				len += arts[--n].a_blen;
X			} else {
X				if (wasblank)
X					pos = lastpos;
X				arts[n].a_hlen = len;
X				arts[n].a_bod = arts[n+1].a_hdr = pos;
X				arts[n+1].a_bod = -1L;
X				arts[n+1].a_hlen = 3;	/* average header len */
X				len = 0;
X			}
X		}
X		if (*s=='\0')
X			break;
X		wasblank = (*s=='\n') ? TRUE : FALSE;
X		len++;
X	}
X	arts[n].a_blen = len;
X	arts[n+1].a_hdr = pos;
X	lastart = n;
X	return(FALSE);
X}
X
Xdhprint(art, ifp, ofp)
Xregister int art;
Xregister FILE *ifp, *ofp;
X{
X	register char	c;
X	register long	pos = arts[art].a_hdr;
X	register long	epos = arts[art].a_bod;
X	register int	nlines = 1;
X
X	putc('\n', ofp);
X	fseek(ifp, pos, 0);
X	while (pos++ < epos && !sigtrap) {
X		if ((c = getc(ifp))=='\n')
X			nlines++;
X		putc(c, ofp);
X	}
X	(void) fflush(ofp);
X	sigtrap = FALSE;
X	return(nlines);
X}
X
Xdprint(art, ifp, ofp)
Xint art;
XFILE *ifp, *ofp;
X{
X#ifdef	PAGE
X	register int	cnt;
X	FILE		*pfp, *popen();
X
X	if (art && arts[art].a_blen > 23-arts[art+1].a_hlen && *PAGER) {
X		if (!index(PAGER, FMETA)) {
X			if ((pfp = popen(PAGER, "w"))==NULL)
X				(void) dprinta(art, ifp, ofp);
X			else {
X				cnt = dprinta(art, ifp, pfp) % 23;
X				if (cnt > 23-arts[art+1].a_hlen)
X					while (cnt++ < 24)
X						putc('\n', pfp);
X				(void) pclose(pfp);
X			}
X		} else
X			pout(ofp);
X	} else
X#endif	PAGE
X		(void) dprinta(art, ifp, ofp);
X}
X
Xdprinta(art, ifp, ofp)
Xint art;
Xregister FILE *ifp, *ofp;
X{
X	register char	c;
X	register long	pos = arts[art].a_bod;
X	register long	epos = arts[art+1].a_hdr;
X	register int	nlines = 0;
X
X	fseek(ifp, pos, 0);
X	while (pos++ < epos && !sigtrap) {
X		if ((c = getc(ifp))=='\n')
X			nlines++;
X		putc(c, ofp);
X	}
X	(void) fflush(ofp);
X	sigtrap = FALSE;
X	return(nlines);
X}
X
Xdsaveart(art, ifp, ofp, name)
Xint art;
Xregister FILE *ifp, *ofp;
Xregister char *name;
X{
X	register FILE	*nfp;
X	char		fname[BUFLEN];
X	char		*strcat(), *strcpy(), *getenv();
X	register char	*nb;
X
X	while (*name==' ' || *name=='\t')
X		name++;
X
X	if (*name=='|') {
X		fprintf(ofp, "don't know how to pipe yet.\n");
X		(void) fflush(ofp);
X		return;
X	} else if (*name=='/')
X		(void) strcpy(fname, name);
X	else {
X		if (nb = getenv("NEWSBOX"))
X			(void) strcpy(fname, nb);
X		else
X			(void) strcpy(fname, userhome);
X		(void) strcat(fname, "/");
X		(void) strcat(fname, name);
X	}
X
X	fprintf(ofp, "Save digest article %d in \"%s\"", art, fname);
X	(void) fflush(ofp);
X	if ((nfp = fopen(fname, "a"))!=NULL) {
X		int ln;
X		ln = dhprint(art, ifp, nfp);
X		ln += dprinta(art, ifp, nfp);
X		fprintf(ofp, " [Appended] %d lines\n", ln);
X		(void) fclose(nfp);
X	} else
X		fprintf(ofp, " cannot append to.\n");
X}
X
Xisheader(s)
Xregister char *s;
X{
X	if (isupper(*s) || islower(*s)) {
X		while (*s && *s!=':' && !isspace(*s))
X			s++;
X		if (*s==':' && *++s==' ')
X			return(TRUE);
X	}
X	return(FALSE);
X}
*-*-END-of-src/digest.c-*-*
echo x - src/expire.c
sed 's/^X//' >src/expire.c <<'*-*-END-of-src/expire.c-*-*'
X/*
X * expire - expire daemon runs around and nails all articles that
X *		 have expired.
X *
X */
X
X#ifndef lint
Xstatic char	*SccsId = "@(#)expire.c	2.31	9/3/84";
X#endif lint
X
X#include "params.h"
X#include <errno.h>
X#if defined(BSD4_2) || defined(BSD4_1C)
X# include <sys/dir.h>
X#else
X# include "ndir.h"
X#endif
X
Xchar *Progname = "expire";	/* used by xerror to identify failing program */
X
X/*	Number of array entries to allocate at a time.	*/
X#define SPACE_INCREMENT	1000
X
Xextern char	groupdir[BUFSIZ], rcbuf[BUFLEN];
Xextern int	errno;
Xchar	NARTFILE[BUFSIZ], OARTFILE[BUFSIZ];
Xchar	PAGFILE[BUFLEN], DIRFILE[BUFLEN];
Xchar	NACTIVE[BUFSIZ], OACTIVE[BUFSIZ];
Xextern char *OLDNEWS;
Xint	verbose = 0;
Xint	ignorexp = 0;
Xint	doarchive = 0;
Xint	nohistory = 0;
Xint	dorebuild = 0;
Xint	usepost = 0;
Xint	frflag = 0;
Xint	updateactive = 0;
Xchar	baduser[BUFLEN], filename[BUFLEN];
X
X/*
X * This code uses realloc to get more of the multhist array.
X */
Xstruct multhist {
X	char	*mh_ident;
X	char	*mh_file;
X} *multhist;
Xunsigned int mh_size;
Xchar *calloc();
Xchar *realloc();
X
Xtypedef struct {
X	char *dptr;
X	int dsize;
X} datum;
X
Xlong	expincr;
Xlong	atol();
Xtime_t	cgtdate(), time();
XFILE *popen();
Xstruct passwd *pw;
Xstruct group *gp;
Xchar	arpat[LBUFLEN];
X
Xmain(argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	register FILE *fp = NULL;
X	struct hbuf h;
X	register time_t now, newtime;
X	char	ngpat[LBUFLEN];
X	char	afline[BUFLEN];
X	char	*p1, *p2, *p3;
X	FILE	*ohfd, *nhfd;
X	DIR	*ngdirp;
X	static struct direct *ngdir;
X	char fn[BUFLEN];
X	int uid, gid, duid, dgid;
X	int i;
X
X	pathinit();
X	umask(N_UMASK);
X
X	uid = getuid();
X	gid = getgid();
X	duid = geteuid();
X	dgid = getegid();
X	if (uid == 0 && geteuid() == 0) {
X		/*
X		 * Must go through with this kludge since
X		 * some systems do not honor the setuid bit
X		 * when root invokes a setuid program.
X		 */
X		if ((pw = getpwnam(NEWSUSR)) == NULL)
X			xerror("Cannot get NEWSUSR pw entry");
X
X		duid = pw->pw_uid;
X		if ((gp = getgrnam(NEWSGRP)) == NULL)
X			xerror("Cannot get NEWSGRP gr entry");
X		dgid = gp->gr_gid;
X		setuid(duid);
X		setgid(dgid);
X	}
X
X	expincr = DFLTEXP;
X	ngpat[0] = '\0';
X	while (argc > 1) {
X		switch (argv[1][1]) {
X		case 'v':
X			if (isdigit(argv[1][2]))
X				verbose = argv[1][2] - '0';
X			else if (argc > 2 && argv[2][0] != '-') {
X
X				argv++;
X				argc--;
X				verbose = atoi(argv[1]);
X			} else
X				verbose = 1;
X			if (verbose < 3)
X				setbuf(stdout, (char *)NULL);
X			break;
X		case 'e':	/* Use this as default expiration time */
X			if (argc > 2 && argv[2][0] != '-') {
X				argv++;
X				argc--;
X				expincr = atol(argv[1]) * DAYS;
X			} else if (isdigit(argv[1][2]))
X				expincr = atol(&argv[1][2]) * DAYS;
X			break;
X		case 'I':	/* Ignore any existing expiration date */
X			ignorexp = 2;
X			break;
X		case 'i':	/* Ignore any existing expiration date */
X			ignorexp = 1;
X			break;
X		case 'n':
X			if (argc > 2) {
X				argv++;
X				argc--;
X				while (argc > 1 && argv[1][0] != '-') {
X					strcat(ngpat, argv[1]);
X					ngcat(ngpat);
X					argv++;
X					argc--;
X				}
X				argv--;
X				argc++;
X			}
X			break;
X		case 'a':	/* archive expired articles */
X			if (access(OLDNEWS,0) < 0 ){
X				perror(OLDNEWS);
X				fprintf(stderr,"No archiving possible\n");
X				xxit(1);
X			}
X			doarchive++;
X			if (argc > 2) {
X				argv++;
X				argc--;
X				while (argc > 1 && argv[1][0] != '-') {
X					strcat(arpat, argv[1]);
X					ngcat(arpat);
X					argv++;
X					argc--;
X				}
X				argv--;
X				argc++;
X			}
X			break;
X		case 'h':	/* ignore history */
X			nohistory++;
X			break;
X		case 'r':	/* rebuild history file */
X			dorebuild++;
X			nohistory++;
X			break;
X		case 'p':
X			usepost++;
X			break;
X		case 'f':
X			frflag++;
X			if (argc > 2) {
X				strcpy(baduser, argv[2]);
X				argv++;
X				argc--;
X			}
X			break;
X		case 'u':
X			updateactive++;
X			break;
X		default:
X			printf("Usage: expire [ -v [level] ] [-e days ] [-i] [-a] [-r] [-h] [-p] [-u] [-f username] [-n newsgroups]\n");
X			xxit(1);
X		}
X		argc--;
X		argv++;
X	}
X	if (ngpat[0] == 0)
X		strcpy(ngpat, "all,");
X	if (arpat[0] == 0)
X		strcpy(arpat, "all,");
X	now = time((time_t)0);
X	if (chdir(SPOOL))
X		xerror("Cannot chdir %s", SPOOL);
X
X	if (verbose) {
X		printf("expire: nohistory %d, rebuild %d, doarchive %d\n",
X			nohistory, dorebuild, doarchive);
X		printf("newsgroups: %s\n",ngpat);
X		if (doarchive)
X			printf("archiving: %s\n",arpat);
X	}
X
X	sprintf(OARTFILE, "%s/%s", LIB, "ohistory");
X	sprintf(NARTFILE, "%s/%s", LIB, "nhistory");
X
X	sprintf(OACTIVE, "%s/%s", LIB, "oactive");
X	sprintf(NACTIVE, "%s/%s", LIB, "nactive");
X
X	if (updateactive)
X		goto doupdateactive;
X
X#ifdef DBM
X	if (!dorebuild)
X	{
X		sprintf(PAGFILE, "%s/%s", LIB, "nhistory.pag");
X		sprintf(DIRFILE, "%s/%s", LIB, "nhistory.dir");
X		close(creat(PAGFILE, 0666));
X		close(creat(DIRFILE, 0666));
X 		dbminit(NARTFILE);
X	}
X#endif
X
X	if (nohistory) {
X		ohfd = xfopen(ACTIVE, "r");
X		if (dorebuild) {
X			/* Allocate initial space for multiple newsgroup (for an
X			   article) array */
X			multhist = (struct multhist *)
X				calloc (SPACE_INCREMENT,
X					sizeof (struct multhist));
X			mh_size = SPACE_INCREMENT;
X
X			sprintf(afline, "sort -t\t +1 >%s", NARTFILE);
X			if ((nhfd = popen(afline, "w")) == NULL)
X				xerror("Cannot exec %s", NARTFILE);
X		} else
X			nhfd = xfopen("/dev/null", "w");
X	} else {
X		ohfd = xfopen(ARTFILE, "r");
X		nhfd = xfopen(NARTFILE, "w");
X	}
X
X	for(i=0;i<NUNREC;i++)
X		h.unrec[i] = NULL;
X
X	while (TRUE) {
X		if (nohistory) {
X			do {
X				if (ngdir == NULL) {
X					if ( ngdirp != NULL )
X						closedir(ngdirp);
X					if (fgets(afline, BUFLEN, ohfd) == NULL)
X						goto out;
X					strcpy(groupdir, afline);
X					p1 = index(groupdir, ' ');
X					if (p1 == NULL)
X						p1 = index(groupdir, '\n');
X					if (p1 != NULL)
X						*p1 = NULL;
X					if (!ngmatch(groupdir, ngpat))
X						continue;
X
X					/* Change a group name from
X					   a.b.c to a/b/c */
X					for (p1=groupdir; *p1; p1++)
X						if (*p1 == '.')
X							*p1 = '/';
X
X					if ((ngdirp = opendir(groupdir)) == NULL)
X						continue;
X
X				}
X				ngdir = readdir(ngdirp);
X			/*	Continue looking if not an article.	*/
X			} while ( ngdir == NULL || !islegal(fn,groupdir,ngdir->d_name));
X
X			p2 = fn;
X			if (verbose > 2)
X				printf("article: %s\n", fn);
X		} else {
X			if (fgets(afline, BUFLEN, ohfd) == NULL)
X				break;
X			if (verbose > 2)
X				printf("article: %s", afline);
X			p1 = index(afline, '\t');
X			if (p1)
X				p2 = index(p1 + 1, '\t');
X			else
X				continue;
X			if (!p2)
X				continue;
X			p2++;
X			strcpy(groupdir, p2);
X			p3 = index(groupdir, '/');
X			if (p3)
X				*p3 = 0;
X			else {
X				/*
X				 * Nothing after the 2nd tab.  This happens
X				 * when a control message is stored in the
X				 * history file.  Use the date in the history
X				 * file to decide expiration.
X				 */
X				h.expdate[0] = 0;
X				strcpy(h.recdate, p1+1);
X				goto checkdate;
X			}
X			if (!ngmatch(groupdir, ngpat)) {
X				fputs(afline, nhfd);
X				*p1 = 0;
X				remember(afline);
X				continue;
X			}
X			strcpy(fn, p2);
X			p1 = index(fn, ' ');
X			if (p1 == 0)
X				p1 = index(fn, '\n');
X			if (p1)
X				*p1 = 0;
X		}
X
X		strcpy(filename, dirname(fn));
X		if (access(filename, 4)
X		|| (fp = fopen(filename, "r")) == NULL) {
X			if (verbose)
X				printf("Can't open %s.\n", filename);
X			continue;
X		}
X		for(i=0;i<NUNREC;i++)
X			if (h.unrec[i] != NULL)
X				free(h.unrec[i]);
X			else
X				break;
X		if (hread(&h, fp, TRUE) == NULL) {
X			printf("Garbled article %s.\n", filename);
X			fclose(fp);
X			continue;
X		}
X		if (dorebuild) {
X			register char	*cp;
X			register struct multhist *mhp;
X
X			/* Format of filename until now was /SPOOL/a/b/c.4
X			   and this code changes it to a.b.c/4 (the correct
X			   kind of entry in the history file.  */
X			strcpy (filename, filename + strlen(SPOOL)+1);
X			for (p1 = filename; p1 != NULL && *p1 != '\0'; p1++)
X				if (*p1 == '/' && p1 != rindex (p1, '/'))
X					*p1 = '.';
X
X			if ((cp = index(h.nbuf, NGDELIM)) == NULL) {
Xsaveit:
X				fprintf(nhfd, "%s\t%s\t%s \n", h.ident, h.recdate, filename);
X				fclose(fp);
X				continue;
X			}
X			for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) {
X				if (mhp->mh_file == NULL)
X					continue;
X				if (strcmp(mhp->mh_ident, h.ident) != 0)
X					continue;
X				if (index(mhp->mh_file, ' ') != NULL)
X					cp = index(++cp, NGDELIM);
X				strcat(filename, " ");
X				strcat(filename, mhp->mh_file);
X				free(mhp->mh_file);
X				mhp->mh_file = NULL;
X				if (*cp == NULL || (cp = index(++cp, NGDELIM)) == NULL)
X					goto saveit;
X				else
X					break;
X			}
X
X			/* Here is where we realloc the multhist space rather
X			   than the old way of static allocation.  It's
X			   really trivial.  We just clear out the space
X			   in case it was reused.  The old static array was
X			   guaranteed to be cleared since it was cleared when
X			   the process started.  */
X			if (mhp >= multhist + mh_size) {
X				multhist = (struct multhist *)
X					realloc (multhist,
X					  sizeof (struct multhist) *
X					  (SPACE_INCREMENT + mh_size));
X				if (multhist == NULL)
X					xerror("Too many articles with multiple newsgroups");
X				for (mhp = multhist + mh_size;
X				  mhp < multhist+mh_size+SPACE_INCREMENT;
X					mhp++) {
X					mhp->mh_ident = NULL;
X					mhp->mh_file = NULL;
X				}
X				mhp = multhist + mh_size;
X				mh_size += SPACE_INCREMENT;
X			}
X
X			mhp->mh_ident = malloc(strlen(h.ident)+1);
X			strcpy(mhp->mh_ident, h.ident);
X			cp = malloc(strlen(filename) + 1);
X			if ( cp == NULL)
X				xerror("Out of memory");
X			strcpy(cp, filename);
X			mhp->mh_file = cp;
X			fclose(fp);
X			continue;
X		}
X
X		fclose(fp);
Xcheckdate:
X		if (h.expdate[0])
X			h.exptime = cgtdate(h.expdate);
X		newtime = cgtdate(usepost ? h.subdate : h.recdate) + expincr;
X		if (!h.expdate[0] || ignorexp == 2 ||
X		    (ignorexp == 1 && newtime < h.exptime))
X			h.exptime = newtime;
X		if (frflag ? strcmp(baduser,h.from)==0 : now >= h.exptime) {
X#ifdef DEBUG
X			printf("cancel %s\n", filename);
X#else
X			if (verbose)
X				printf("cancel %s\n", filename);
X			ulall(p2, &h);
X#endif
X		} else {
X			fputs(afline, nhfd);
X			if (!dorebuild)
X				remember(h.ident);
X			if (verbose > 2)
X				printf("Good article %s\n", rcbuf);
X		}
X	}
X
Xout:
X	if (dorebuild) {
X		register struct multhist *mhp;
X		for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++)
X			/* should "never" happen */
X			if (mhp->mh_file != NULL ) {
X				printf("Article: %s %s Cannot find all links\n", mhp->mh_ident, mhp->mh_file);
X				sprintf(filename,"%s/%s",SPOOL,mhp->mh_file);
X				for (p1 = filename; *p1 != ' ' && *p1 != '\0'; p1++)
X					if (*p1 == '.')
X						*p1 = '/';
X				*p1 = '\0';
X				if ((fp = fopen(filename, "r")) == NULL) {
X					if (verbose)
X						printf("Can't open %s.\n", filename);
X					continue;
X				}
X				for(i=0;i<NUNREC;i++)
X					if (h.unrec[i] != NULL)
X						free(h.unrec[i]);
X					else
X						break;
X				if (hread(&h, fp, TRUE) == NULL) {
X					printf("Garbled article %s.\n", filename);
X					fclose(fp);
X					continue;
X				}
X
X				fprintf(nhfd, "%s\t%s\t%s \n", h.ident, h.recdate, mhp->mh_file);
X				fclose(fp);
X				continue;
X			}
X		pclose(nhfd);
X		free (multhist);
X	}
X
X	if (dorebuild || !nohistory) {
X		rename(ARTFILE, OARTFILE);
X		rename(NARTFILE, ARTFILE);
X#ifdef DBM
X		if (dorebuild)
X			rebuilddbm ( );
X		else
X		{
X			char bfr[BUFLEN];
X			sprintf(bfr,"%s.pag", ARTFILE);
X			strcat(OARTFILE, ".pag");
X			strcat(NARTFILE, ".pag");
X			rename(bfr, OARTFILE);
X			rename(NARTFILE, bfr);
X			sprintf(bfr,"%s.dir", ARTFILE);
X			strcpy(rindex(OARTFILE, '.'), ".dir");
X			strcpy(rindex(NARTFILE, '.'), ".dir");
X			rename(bfr, OARTFILE);
X			rename(NARTFILE, bfr);
X		}
X#endif
X	}
X
Xdoupdateactive:
X	ohfd = xfopen(ACTIVE, "r");
X	nhfd = xfopen(NACTIVE, "w");
X	do {
X		long n;
X		long maxart, minart;
X		char cansub;
X		int gdsize;
X		struct stat stbuf;
X
X		if (fgets(afline, BUFLEN, ohfd) == NULL)
X			continue;
X		if (sscanf(afline,"%s %ld %ld %c",groupdir,&maxart, &minart,
X		    &cansub) < 4)
X			xerror("Active file corrupt");
X		minart = maxart > 0 ? maxart : 1L;
X		/* Change a group name from
X		   a.b.c to a/b/c */
X		for (p1=groupdir; *p1; p1++)
X			if (*p1 == '.')
X				*p1 = '/';
X
X		gdsize = strlen(groupdir);
X		if ((ngdirp = opendir(groupdir)) != NULL) {
X			while (ngdir = readdir(ngdirp)) {
X				groupdir[gdsize] = '/';
X				strcpy(&groupdir[gdsize+1],ngdir->d_name);
X				/* We have to do a stat because of micro.6809 */
X				if (stat(groupdir,&stbuf) < 0 ||
X				   !(stbuf.st_mode&S_IFREG) )
X					continue;
X				n = atol(ngdir->d_name);
X				if (n > 0 && n < minart)
X					minart = n;
X				if (n > 0 && n > maxart)
X					maxart = n;
X			}
X			closedir(ngdirp);
X		}
X		afline[gdsize] = '\0';
X		fprintf(nhfd,"%s %05ld %05ld %c\n", afline, maxart, minart, cansub);
X	} while ( !feof(ohfd));
X	fclose(nhfd);
X	fclose(ohfd);
X
X	rename(ACTIVE, OACTIVE);
X	rename(NACTIVE, ACTIVE);
X
X	xxit(0);
X}
X
X/* Unlink (using tail recursion) all the articles in 'artlist'. */
Xulall(artlist, h)
Xchar	*artlist;
Xstruct hbuf *h;
X{
X	register char	*p, *q;
X	int	last = 0;
X	char	newname[BUFLEN];
X	time_t	timep[2];
X	char *fn;
X
X	if (verbose > 2)
X		printf("ulall '%s', '%s'\n", artlist, h->subdate);
X	if (nohistory) {
X		last = 1;
X	} else {
X		while (*artlist == ' ' || *artlist == '\n' || *artlist == ',')
X			artlist++;
X		if (*artlist == 0)
X			return;
X		p = index(artlist, ' ');
X		if (p == 0) {
X			last = 1;
X			p = index(artlist, '\n');
X		}
X		if (p == 0) {
X			last = 1;
X			p = index(artlist, ',');
X		}
X		if (p == 0) {
X			last = 1;
X			fn = dirname(artlist);
X			unlink(fn);
X			return;
X		}
X		if (p)
X			*p = 0;
X	}
X	fn = dirname(artlist);
X	if (doarchive){
X		strcpy(newname, artlist);
X		q = index(newname,'/');
X		if (q) {
X			*q++ = NGDELIM;
X			*q = '\0';
X		}
X		if (ngmatch(newname, arpat)) {
X			q = fn + strlen(SPOOL) + 1;
X			sprintf(newname, "%s/%s", OLDNEWS, q);
X			if (verbose)
X				printf("link %s to %s\n", fn, newname);
X			if (link(fn, newname) == -1) {
X				if (mkparents(newname) == 0)
X					if (link(fn, newname) == -1)
X						fcopy(fn, newname);
X			}
X			timep[0] = timep[1] = cgtdate(h->subdate);
X			utime(newname, timep);
X		}
X	}
X	if (verbose)
X		printf("unlink %s\n", fn);
X	unlink(fn);
X	if (!last)
X		ulall(p + 1, h);
X}
X
Xfcopy(fn, newname)
Xchar *fn, *newname;
X{
X	int f1, f2;
X	int r;
X	char buf[BUFSIZ];
X	f1 = open(fn, 0);
X	if (f1 < 0)
X		return -1;
X	f2 = open(newname, 1);
X	if (f2 < 0) {
X		if (errno == ENOENT) {
X			f2 = creat(newname,0644);
X			if (f2 < 0)
X				return -1;
X		} else
X			return -1;
X	}
X	while((r=read(f1, buf, BUFSIZ)) > 0)
X		write(f2, buf, r);
X	close(f1);
X	close(f2);
X	return 0;
X}
X
X/*
X * If any parent directories of this dir don't exist, create them.
X */
Xmkparents(dirname)
Xchar *dirname;
X{
X	char buf[200], sysbuf[200];
X	register char *p;
X	int rc;
X	struct passwd *pw;
X
X	strcpy(buf, dirname);
X	p = rindex(buf, '/');
X	if (p)
X		*p = '\0';
X	if (access(buf,0) == 0)
X		return 0;
X	mkparents(buf);
X	sprintf(sysbuf, "mkdir %s", buf);
X	rc = system(sysbuf);
X	sprintf(sysbuf, "%s", buf);
X	if (verbose)
X		printf("mkdir %s, rc %d\n", sysbuf, rc);
X	chmod(sysbuf, 0755);
X	chown(sysbuf, duid, dgid);
X
X	return rc;
X}
X
X
X/*	Make sure this file is a legal article. */
Xislegal(fullname, path, name)
X	register char *fullname;
X	register char *path;
X	register char *name;
X{
X	struct stat buffer;
X
X	sprintf(fullname, "%s/%s", path, name);
X
X	/* make sure the article is numeric. */
X	while (*name != '\0')
X		if (!isascii(*name) || !isdigit(*name))
X			return 0;
X		else
X			name++;
X
X	/*  Now make sure we don't have a group like net.micro.432,
X	 *  which is numeric but not a regular file -- i.e., check
X	 *  for being a regular file.
X	 */
X	if ((stat(fullname, &buffer) == 0) &&
X		((buffer.st_mode & S_IFMT) == S_IFREG)) {
X		/* Now that we found a legal group in a/b/c/4
X		   notation, switch it to a.b.c/4 notation.  */
X		for (name = fullname; name != NULL && *name != '\0'; name++)
X			if (*name == '/' && name != rindex (name, '/'))
X				*name = '.';
X
X			return 1;
X	}
X	return 0;
X}
X
X#ifdef DBM
X/*
X * This is taken mostly intact from ../cvt/cvt.hist.c and is used at the
X * end by the options that make a new history file.
X * Routine to convert history file to dbm file.  The old 3 field
X * history file is still kept there, because we need it for expire
X * and for a human readable copy.  But we keep a dbm hashed copy
X * around by message ID so we can answer the yes/no question "have
X * we already seen this message".  The content is the ftell offset
X * into the real history file when we get the article - you can't
X * really do much with this because the file gets compacted.
X */
X
XFILE *fd;
X
Xchar namebuf[BUFSIZ];
Xchar lb[BUFSIZ];
X
Xrebuilddbm( )
X{
X	register char *p;
X	long fpos;
X	datum lhs, rhs;
X
X	umask(0);
X	sprintf(namebuf, "%s.dir", ARTFILE);
X	close(creat(namebuf, 0666));
X	sprintf(namebuf, "%s.pag", ARTFILE);
X	close(creat(namebuf, 0666));
X	sprintf(namebuf, "%s", ARTFILE);
X
X	fd = fopen(namebuf, "r");
X	if (fd == NULL) {
X		perror(namebuf);
X		xxit(2);
X	}
X
X	dbminit(namebuf);
X	while (fpos=ftell(fd), fgets(lb, BUFSIZ, fd) != NULL) {
X		p = index(lb, '\t');
X		if (p)
X			*p = 0;
X		p = lb;
X		while (*++p)
X			if (isupper(*p))
X				*p = tolower(*p);
X		lhs.dptr = lb;
X		lhs.dsize = strlen(lb) + 1;
X		rhs.dptr = (char *) &fpos;
X		rhs.dsize = sizeof fpos;
X		if (store(lhs, rhs) < 0)
X			fprintf(stderr, "store(%s) failed\n", lb);
X	}
X}
X#endif DBM
X
Xremember(article)
X	char	*article;
X{
X	static long number;
X	register char *rcp;
X	datum	lhs, rhs;
X
X#ifdef DBM
X	strcpy(lb, article);
X	rcp = lb;
X	while (*++rcp)
X		if (isupper(*rcp))
X			*rcp = tolower(*rcp);
X	lhs.dptr = lb;
X	lhs.dsize = strlen(lb)+1;
X
X	number++;
X
X	rhs.dptr = (char *) &number;
X	rhs.dsize = sizeof(number);
X
X	store(lhs, rhs);
X#endif
X}
X
X#if !defined(BSD4_2) && !defined(BSD4_1C)
Xrename(from,to)
Xregister char *from, *to;
X{
X	unlink(to);
X	if (link(from, to) < 0)
X		return -1;
X
X	unlink(from);
X	return 0;
X}
X#endif !BSD4_2 && ! BSD4_1C
X
Xxxit(i)
X{
X	exit(i);
X}
*-*-END-of-src/expire.c-*-*
echo x - src/ftime.c
sed 's/^X//' >src/ftime.c <<'*-*-END-of-src/ftime.c-*-*'
Xstatic char *SccsId = "@(#)ftime.c	2.4	4/20/84";
X
X#include <sys/types.h>
Xstruct timeb
X{
X	time_t	time;
X	unsigned short millitm;
X	short	timezone;
X	short	dstflag;
X};
X
Xextern long timezone;
Xextern int  daylight;
X
Xftime(tp)
Xstruct timeb *tp;
X{
X	long t;
X
X	time(&t);
X	tp->time = t;
X	tp->millitm = 0;
X	tp->timezone = timezone/60;
X	tp->dstflag = daylight;
X}
*-*-END-of-src/ftime.c-*-*
echo x - src/fullname.c
sed 's/^X//' >src/fullname.c <<'*-*-END-of-src/fullname.c-*-*'
X/*
X * fullname.c - this file is made separate so that different local
X * conventions can be applied.  The stock version understands two
X * conventions:
X *
X * (a) Berkeley finger: the gecos field in /etc/passwd begins with
X *     the full name, terminated with comma, semicolon, or end of
X *     field.  & expands to the login name.
X * (b) BTL RJE: the gecos field looks like
X *	: junk - full name ( junk :
X *     where the "junk -" is optional.
X *
X * If you have a different local convention, modify this file accordingly.
X */
X
X#ifndef lint
Xstatic char	*SccsId = "@(#)fullname.c	1.7	8/14/84";
X#endif !lint
X
X#include <stdio.h>
X#include <ctype.h>
X#include <pwd.h>
X#ifdef USG
Xstruct passwd *getpwent(), *getpwuid(), *getpwnam();
X#endif USG
X#include "defs.h"
X
X#ifndef LOCALNAME
X/*
X * Figure out who is sending the message and sign it.
X * We attempt to look up the user in the gecos field of /etc/passwd.
X */
Xchar *
Xfullname(un)
Xchar *un;
X{
X	static char inbuf[100];
X	struct passwd *pw;
X
X	pw = getpwnam(un);
X	if (pw == NULL)
X		return un;
X	buildfname(pw->pw_gecos, un, inbuf);
X	if (inbuf[0] == 0)
X		return un;
X	return inbuf;
X}
X
X#else
X
X/*
X * Alternative version of fullname which asks the user for his full name.
X * This is mainly suitable for systems that don't have a full name
X * database somewhere.  It puts the answer in $HOME/.name
X */
Xchar *
Xfullname(un)
Xchar *un;
X{
X	static char inbuf[100];
X	char fbuf[100];
X	FILE *fd;
X	char *p, *index(), *getenv();
X	int pid;
X
X	if (!isatty(2))
X		return un;
X	printf("What is your full name (for news article signatures): ");
X	fflush(stdout);
X	read(2, inbuf, sizeof inbuf);
X	if (inbuf[0] == 0)
X		return un;
X	p = index(inbuf, '\n');
X	if (p)
X		*p = 0;
X	if ((p = getenv("HOME")) == NULL) {
X		fprintf(stderr,
X		"inews: no HOME environment variable - .name not written\n");
X		return inbuf;
X	}
X	sprintf(fbuf, "%s/%s", p, ".name");
X	if ((pid = fork()) < 0) {
X		perror("inews");
X		return inbuf;
X	}
X	else if (pid != 0)
X		while (wait((int *)0) != pid)
X			;
X	else {
X		setuid(getuid());	/* become the user */
X		if ((fd = fopen(fbuf, "w")) == NULL)
X			fprintf(stderr, "inews: can't create %s\n", fbuf);
X		else {
X			fprintf(fd, "%s\n", inbuf);
X			fclose(fd);
X		}
X		exit(0);
X	}
X	return inbuf;
X}
X#endif
X
X#ifndef LOCALNAME
X/*
X**  BUILDFNAME -- build full name from gecos style entry.
X**	(routine lifted from sendmail)
X**
X**	This routine interprets the strange entry that would appear
X**	in the GECOS field of the password file.
X**
X**	Parameters:
X**		p -- name to build.
X**		login -- the login name of this user (for &).
X**		buf -- place to put the result.
X**
X**	Returns:
X**		none.
X**
X**	Side Effects:
X**		none.
X*/
X
Xbuildfname(p, login, buf)
X	register char *p;
X	char *login;
X	char *buf;
X{
X	register char *bp = buf;
X
X	if (*p == '*')
X		p++;
X	while (*p != '\0' && *p != ',' && *p != ';' && *p != ':' && *p != '(')
X	{
X		if (*p == '-') {
X			bp = buf;
X			p++;
X		}
X		else if (*p == '&')
X		{
X			strcpy(bp, login);
X			if (islower(*bp))
X				*bp = toupper(*bp);
X			while (*bp != '\0')
X				bp++;
X			p++;
X		}
X		else
X			*bp++ = *p++;
X	}
X	*bp = '\0';
X}
X#endif
*-*-END-of-src/fullname.c-*-*
echo x - src/funcs.c
sed 's/^X//' >src/funcs.c <<'*-*-END-of-src/funcs.c-*-*'
X/*
X * funcs - functions used by many programs
X */
X
X#ifndef lint
Xstatic char	*SccsId = "@(#)funcs.c	2.19	8/28/84";
X#endif !lint
X
X#include "params.h"
X#include <errno.h>
X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C)
X#include <fcntl.h>
X#endif !v7
X
X/*
X * Append NGDELIM to string.
X */
Xngcat(s)
Xregister char *s;
X{
X	if (*s) {
X		while (*s++)
X			;
X		s -= 2;
X		if (*s++ == NGDELIM)
X			return;
X	}
X	*s++ = NGDELIM;
X	*s = '\0';
X}
X
X/*
X * News group matching.
X *
X * nglist is a list of newsgroups.
X * sublist is a list of subscriptions.
X * sublist may have "meta newsgroups" in it.
X * All fields are NGDELIM separated,
X * and there is an NGDELIM at the end of each argument.
X *
X * Currently implemented glitches:
X * sublist uses 'all' like shell uses '*', and '.' like shell '/'.
X * If subscription X matches Y, it also matches Y.anything.
X */
Xngmatch(nglist, sublist)
Xregister char *nglist, *sublist;
X{
X	register char *n, *s;
X	register int rc;
X
X	rc = FALSE;
X	for (n = nglist; *n != '\0' && rc == FALSE;) {
X		for (s = sublist; *s != '\0';) {
X			if (*s != NEGCHAR)
X				rc |= ptrncmp(s, n);
X			else
X				rc &= ~ptrncmp(s+1, n);
X			while (*s++ != NGDELIM && *s != '\0')
X				;
X		}
X		while (*n++ != NGDELIM && *n != '\0')
X			;
X	}
X	return(rc);
X}
X
X/*
X * Compare two newsgroups for equality.
X * The first one may be a "meta" newsgroup.
X */
Xptrncmp(ng1, ng2)
Xregister char *ng1, *ng2;
X{
X	while (*ng1 != NGDELIM && *ng1 != '\0') {
X		if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') {
X			ng1 += 3;
X			while (*ng2 != NGDELIM && *ng2 != '.' && *ng2 != '\0')
X				if (ptrncmp(ng1, ng2++))
X					return(TRUE);
X			return (ptrncmp(ng1, ng2));
X		} else if (*ng1++ != *ng2++)
X			return(FALSE);
X	}
X	return (*ng2 == '.' || *ng2 == NGDELIM || *ng2 == '\0');
X}
X
X/*
X * Exec the shell.
X * This version resets uid, gid, and umask.
X * Called with fsubr(ushell, s, NULL)
X */
X/* ARGSUSED */
Xushell(s, dummy)
Xchar *s, *dummy;
X{
X	umask(savmask);
X	setgid(gid);
X	setuid(uid);
X	xshell(s);
X}
X
X/*
X * Exec the shell.
X * This version restricts PATH to bin and /usr/bin.
X * Called with fsubr(pshell, s, NULL)
X */
Xextern char	**environ;
X
X/* ARGSUSED */
Xpshell(s, dummy)
Xchar *s, *dummy;
X{
X	static char *penv[] = { SYSPATH, NULL };
X	register char **ep, *p;
X	register int found;
X
X	found = FALSE;
X	for (ep = environ; p = *ep; ep++) {
X		if (strncmp(p, "PATH=", 5) == 0) {
X			*ep = penv[0];
X			found = TRUE;
X		}
X	}
X	if (!found)
X		environ = &penv[0];
X	xshell(s);
X}
X
X/*
X * Exec the shell.
X */
Xxshell(s)
Xchar *s;
X{
X	execl(SHELL, SHELL, "-c", s, (char *)0);
X	xerror("No shell!");
X}
X
X/*
X * Fork and call a subroutine with two args.
X * Return pid without waiting.
X */
Xfsubr(f, s1, s2)
Xint (*f)();
Xchar *s1, *s2;
X{
X	register int pid;
X
X	while ((pid = fork()) == -1)
X		sleep((unsigned)1);
X	if (pid == 0) {
X		(*f)(s1, s2);
X		exit(0);
X	}
X	return(pid);
X}
X
X/*
X * Wait on a child process.
X */
Xfwait(pid)
Xregister int pid;
X{
X	register int w;
X	int status;
X	int (*onhup)(), (*onint)();
X
X	onint = signal(SIGINT, SIG_IGN);
X	onhup = signal(SIGHUP, SIG_IGN);
X	while ((w = wait(&status)) != pid && w != -1)
X		;
X	if (w == -1)
X		status = -1;
X	signal(SIGINT, onint);
X	signal(SIGHUP, onhup);
X	return(status);
X}
X
X/*
X * Strip trailing newlines, blanks, and tabs from 's'.
X * Return TRUE if newline was found, else FALSE.
X */
Xnstrip(s)
Xregister char *s;
X{
X	register char *p;
X	register int rc;
X
X	rc = FALSE;
X	p = s;
X	while (*p)
X		if (*p++ == '\n')
X			rc = TRUE;
X	while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t'));
X	*++p = '\0';
X	return(rc);
X}
X
X/*
X * Delete trailing NGDELIM.
X */
Xngdel(s)
Xregister char *s;
X{
X	if (*s++) {
X		while (*s++);
X		s -= 2;
X		if (*s == NGDELIM)
X			*s = '\0';
X	}
X}
X
X/*
X * Return the ptr in sp at which the character c appears;
X * NULL if not found
X *
X * These are the v7 index and rindex routines, stolen for portability.
X * (Some Unix systems call them strchr and strrchr, notably PWB 2.0
X * and its derivitives such as Unix/TS 2.0, Unix 3.0, etc.)  Others,
X * like v6, don't have them at all.
X */
X
Xchar *
Xindex(sp, c)
Xregister char *sp, c;
X{
X	do {
X		if (*sp == c)
X			return(sp);
X	} while (*sp++);
X	return(NULL);
X}
X
X/*
X * Return the ptr in sp at which the character c last
X * appears; NULL if not found
X */
X
Xchar *
Xrindex(sp, c)
Xregister char *sp, c;
X{
X	register char *r;
X
X	r = NULL;
X	do {
X		if (*sp == c)
X			r = sp;
X	} while (*sp++);
X	return(r);
X}
X
X/*
X * Local open routine.
X */
XFILE *
Xxfopen(name, fmode)
Xregister char *name, *fmode;
X{
X	register FILE *fp;
X	char	*fname;
X	extern int errno, sys_nerr;
X	extern char *sys_errlist[];
X
X	if ((fp = fopen(name, fmode)) == NULL) {
X#ifdef IHCC
X		/*
X		 * IHCC users only see the "filename" that was in trouble,
X		 * not the whole path.  (for security!)
X		 */
X		fname = rindex(name, '/') + 1;
X#else
X		fname = name;
X#endif
X		if (errno > sys_nerr)
X			sprintf(bfr, "Cannot open %s (%s): Error %d",
X			    fname, fmode, errno);
X		else
X			sprintf(bfr, "Cannot open %s (%s): %s",
X			    fname, fmode, sys_errlist[errno]);
X		xerror(bfr);
X	}
X	/* kludge for setuid not being honored for root */
X	if ((uid == 0) && (duid != 0) && ((fmode == "a") || (fmode == "w")))
X		chown(name, duid, dgid);
X	return(fp);
X}
X
Xprefix(full, pref)
Xregister char *full, *pref;
X{
X	register char fc, pc;
X
X	do {
X		fc = *full++;
X		pc = *pref++;
X		if (isupper(fc))
X			fc = tolower(fc);
X		if (isupper(pc))
X			pc = tolower(pc);
X	} while (fc == pc);
X	if (*--pref == 0)
X		return 1;
X	else
X		return 0;
X}
X
Xchar *
Xdirname(ngname)
Xchar *ngname;
X{
X	static char rbuf[BUFLEN];
X	register char *p;
X
X	sprintf(rbuf, "%s/%s", SPOOL, ngname);
X
X	/* Use the new style name for all new stuff. */
X	for (p=rbuf+strlen(SPOOL); *p; p++)
X		if (*p == '.')
X			*p = '/';
X	return rbuf;
X}
X
X/*
X * Return TRUE iff ngname is a valid newsgroup name
X */
Xvalidng(ngname)
Xchar *ngname;
X{
X	register FILE *fp;
X	register char *p, *q;
X	char abuf[BUFLEN];
X
X	fp = xfopen(ACTIVE, "r");
X	while(fgets(abuf, BUFLEN, fp) != NULL) {
X		p = abuf;
X		q = ngname;
X		while (*p++ == *q++)
X			;
X		if (*--q == '\0' && *--p == ' ') {
X			fclose(fp);
X			return TRUE;
X		}
X	}
X	fclose(fp);
X	return FALSE;
X}
X
X/* VARARGS1 */
Xxerror(message, arg1, arg2, arg3)
Xchar *message;
Xint arg1, arg2, arg3;
X{
X	char buffer[128];
X	extern char *Progname;
X
X	fflush(stdout);
X	sprintf(buffer, message, arg1, arg2, arg3);
X	logerr(buffer);
X	xxit(1);
X}
X
X/* VARARGS1 */
Xlog(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
Xchar *fmt;
X{
X	_dolog(0, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X}
X
X/* VARARGS1 */
Xlogerr(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
Xchar *fmt;
X{
X	_dolog(1, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X}
X
Xchar *lfsuffix[] = {
X	"log",
X	"errlog",
X	0
X};
X
X
X/*
X * Log the given message, with printf strings and parameters allowed,
X * on the log file, if it can be written.  The date and an attempt at
X * figuring out the remote system name are also logged.
X */
X/* VARARGS1 */
X_dolog(which, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
Xchar *fmt;
X{
X	FILE *logfile;
X	register char *p, *q, *logtime;
X	int i;
X	char logfname[BUFLEN];		/* the log file */
X	char rmtsys[BUFLEN];
X	char msg[BUFLEN];
X	char c;
X	time_t t;
X
X	if (header.relayversion[0]) {
X		for (p=header.relayversion; p; p=index(p+1, 's'))
X			if (strncmp(p, "site ", 5) == 0)
X				break;
X		if (p == NULL)
X			goto crackpath;
X		p += 4;
X		while (*p == ' ' || *p == '\t')
X			p++;
X		for (q=p; *q && *q!=' ' && *q != '\t'; q++)
X			;
X		c = *q;
X		strcpy(rmtsys, p);
X		*q = c;
X	} else {
Xcrackpath:
X		strcpy(rmtsys, header.path);
X		p = index(rmtsys, '!');
X		if (p == NULL)
X			p = index(rmtsys, ':');
X		if (p)
X			*p = 0;
X		else {
X			p = rindex(rmtsys, '@');
X			if (p)
X				strcpy(rmtsys, p+1);
X			else
X				strcpy(rmtsys, "local");
X		}
X	}
X
X	(void) time(&t);
X	logtime = ctime(&t);
X	logtime[16] = 0;
X	logtime += 4;
X
X
X	sprintf(msg, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X
X	if (which)
X		fprintf(stderr,"%s: %s\n", Progname, msg);
X
X	for (i=0; i<=which;i++) {
X		sprintf(logfname, "%s/%s", LIB, lfsuffix[i]);
X
X		if (access(logfname, 0) == 0 && (logfile = fopen(logfname, "a")) != NULL) {
X#if defined(USG) || defined(BSD4_2) || defined(BSD4_1C)
X			int flags;
X			flags = fcntl(fileno(logfile), F_GETFL, 0);
X			fcntl(fileno(logfile), F_SETFL, flags|O_APPEND);
X#else v7
X			lseek(fileno(logfile), 0L, 2);
X#endif v7
X			if (i)
X				fprintf(logfile, "%s\t%s\t%s: %s\n", logtime,
X					header.ident, Progname, msg);
X			else
X				fprintf(logfile, "%s\t%s\t%s\n", logtime,
X					rmtsys, msg);
X			fclose(logfile);
X		}
X	}
X}
*-*-END-of-src/funcs.c-*-*
echo x - src/funcs2.c
sed 's/^X//' >src/funcs2.c <<'*-*-END-of-src/funcs2.c-*-*'
X/*
X * funcs2 - functions used by both inews and readnews.
X */
X
X#ifndef lint
Xstatic char	*SccsId = "@(#)funcs2.c	1.5	8/28/84";
X#endif !lint
X
X#include "params.h"
X
X/*
X * Get user name and home directory.
X */
Xgetuser()
X{
X	static int flag = TRUE;
X	register struct passwd *p;
X
X	if (flag) {
X		if ((p = getpwuid(uid)) == NULL)
X			xerror("Cannot get user's name");
X		if ( username == NULL || username[0] == 0)
X			username = AllocCpy(p->pw_name);
X		userhome = AllocCpy(p->pw_dir);
X		flag = FALSE;
X	}
X	strcpy(header.path, username);
X}
X
Xstatic	FILE	*sysfile;
X
Xchar *fldget();
X
X/*
X * Open SUBFILE.
X */
Xs_openr()
X{
X	sysfile = xfopen(SUBFILE, "r");
X}
X
X/*
X * Read SUBFILE.
X */
Xs_read(sp)
Xregister struct srec *sp;
X{
X	register char *p;
Xagain:
X	p = bfr;
X	if (fgets(p, LBUFLEN, sysfile) == NULL)
X		return(FALSE);
X	if (!nstrip(p))
X		xerror("SUBFILE line too long.");
X	if (*p == '#')
X		goto again;
X	sp->s_xmit[0] = '\0';
X	sp->s_flags[0] = '\0';
X
X	p = fldget(sp->s_name, p);
X	if (*p++ == '\0')
X		xerror("Bad SUBFILE line.");
X/*
X * A sys file line reading "ME" means the name of the local system.
X */
X	if (strcmp(sp->s_name, "ME") == 0)
X		strcpy(sp->s_name, FULLSYSNAME);
X	p = fldget(sp->s_nbuf, p);
X	lcase(sp->s_nbuf);
X	ngcat(sp->s_nbuf);
X	if (*p++ == '\0')
X		return(TRUE);
X
X	p = fldget(sp->s_flags, p);
X	if (*p++ == '\0')
X		return(TRUE);
X
X	(void) fldget(sp->s_xmit, p);
X	return(TRUE);
X}
X
Xchar *
Xfldget(q, p)
Xregister char *q, *p;
X{
X	while (*p && *p != ':') {
X		if (*p == '\\' && p[1]==':')
X			p++;
X		*q++ = *p++;
X	}
X	*q = '\0';
X	return(p);
X}
X
X/*
X * Find the SUBFILE record for a system.
X */
Xs_find(sp, system)
Xregister struct srec *sp;
Xchar *system;
X{
X	s_openr();
X	while (s_read(sp))
X		if (strncmp(system, sp->s_name, SNLN) == 0) {
X			s_close();
X			return(TRUE);
X		}
X	s_close();
X	return(FALSE);
X}
X
X/*
X * Close sysfile.
X */
Xs_close()
X{
X	fclose(sysfile);
X}
X
Xtime_t
Xcgtdate(datestr)
Xchar *datestr;
X{
X	time_t	i;
X	char	junk[40],month[40],day[30],tod[60],year[50];
X
X	if ((i = getdate(datestr, (struct timeb *) NULL)) >= 0)
X		return i;
X	sscanf(datestr, "%s %s %s %s %s", junk, month, day, tod, year);
X	sprintf(bfr, "%s %s, %s %s", month, day, year, tod);
X	return getdate(bfr, (struct timeb *) NULL);
X}
X
Xlcase(s)
Xregister char *s;
X{
X	register char *ptr;
X
X	for (ptr = s; *ptr; ptr++)
X		if (isupper(*ptr))
X			*ptr = tolower(*ptr);
X}
X
Xohwrite(hp, fp)
Xregister struct hbuf *hp;
Xregister FILE *fp;
X{
X	ngdel(strcpy(bfr, hp->nbuf));
X	fprintf(fp, "A%s\n%s\n%s!%s\n%s\n%s\n", hp->oident, bfr, FULLSYSNAME, hp->path, hp->subdate, hp->title);
X}
X
X/*
X * Return a compact representation of the person who posted the given
X * message.  A sender or internet name will be used, otherwise
X * the last part of the path is used preceeded by an optional ".."
X */
Xchar *
Xtailpath(hp)
Xstruct hbuf *hp;
X{
X	char *p, *r;
X	static char resultbuf[BUFLEN];
X	char pathbuf[PATHLEN];
X	char *malloc();
X
X	/*
X	 * This only happens for articles posted by old news software
X	 * in non-internet format.
X	 */
X	resultbuf[0] = '\0';
X	strcpy(pathbuf, hp->path);
X	p = index(pathbuf, ' ');
X	if (p)
X		*p = '\0';	/* Chop off trailing " (name)" */
X	r = rindex(pathbuf, '!');
X	if (r == 0) {
X		r = pathbuf;
X	}
X	else {
X		while (r > pathbuf && *--r != '!')
X			;
X		if (r > pathbuf) {
X			r++;
X			strcpy(resultbuf, "..!");
X		}
X	}
X	strcat(resultbuf, r);
X	return resultbuf;
X}
X
X/*
X * arpadate is like ctime(3) except that the time is returned in
X * an acceptable ARPANET time format instead of ctime format.
X */
Xchar *
Xarpadate(longtime)
Xtime_t *longtime;
X{
X	register char *p, *q, *ud;
X	register int i;
X	static char b[40];
X	extern struct tm *gmtime();
X	extern char *asctime();
X
X	/*  Get current time. This will be used resolve the timezone. */
X	ud = asctime(gmtime(longtime));
X
X	/*  Crack the UNIX date line in a singularly unoriginal way. */
X	q = b;
X
X#ifdef notdef
X/* until every site installs the fix to getdate.y, the day
X   of the week can cause time warps */
X	p = &ud[0];		/* Mon */
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = *p++;
X	*q++ = ','; *q++ = ' ';
X#endif
X
X	p = &ud[8];		/* 16 */
X	if (*p == ' ')
X		p++;
X	else
X		*q++ = *p++;
X	*q++ = *p++; *q++ = ' ';
X
X	p = &ud[4];		/* Sep */
X	*q++ = *p++; *q++ = *p++; *q++ = *p++; *q++ = ' ';
X
X	p = &ud[22];		/* 1979 */
X	*q++ = *p++; *q++ = *p++; *q++ = ' ';
X
X	p = &ud[11];		/* 01:03:52 */
X	for (i = 8; i > 0; i--)
X		*q++ = *p++;
X
X	*q++ = ' ';
X	*q++ = 'G';		/* GMT */
X	*q++ = 'M';
X	*q++ = 'T';
X	*q = '\0';
X
X	return (b);
X}
X
Xchar *
Xreplyname(hptr)
Xstruct hbuf *hptr;
X{
X	register char *ptr;
X	register char *ptr2;
X	static char tbuf[PATHLEN];
X
X	ptr = hptr->path;
X	if (prefix(ptr, FULLSYSNAME))
X		ptr = index(ptr, '!') + 1;
X#ifdef INTERNET
X	if (hptr->from[0])
X		ptr = hptr->from;
X	if (hptr->replyto[0])
X		ptr = hptr->replyto;
X#endif
X	strcpy(tbuf, ptr);
X	ptr = index(tbuf, '(');
X	if (ptr) {
X		while (ptr[-1] == ' ')
X			ptr--;
X		*ptr = 0;
X	}
X#ifndef INTERNET
X	/*
X	 * Play games stripping off multiple berknet
X	 * addresses (a!b!c:d:e => a!b!d:e) here.
X	 */
X	for (ptr=tbuf; *ptr; ptr++)
X		if (index(NETCHRS, *ptr) && *ptr == ':' && (ptr2=index(ptr+1, ':')))
X				strcpy(ptr, ptr2);
X#endif !INTERNET
X	return tbuf;
X}
X
X#ifdef DBM
Xtypedef struct {
X	char *dptr;
X	int dsize;
X} datum;
X#endif DBM
X
X/*
X * Given an article ID, find the line in the history file that mentions it.
X * Return the text of the line, or NULL if not found.  A pointer to a
X * static area is returned.
X */
Xchar *
Xfindhist(artid)
Xchar *artid;
X{
X	static char lbuf[256];
X	char oidbuf[BUFSIZ];
X	FILE *hfp;
X	register char *p;
X#ifdef DBM
X	datum lhs, rhs;
X	datum fetch();
X#endif DBM
X
X	/* Try to understand old artid's as well.  Assume .UUCP domain. */
X	if (artid[0] != '<') {
X		p = index(artid, '.');
X		if (p)
X			*p++ = '\0';
X		sprintf(oidbuf, "<%s@%s.UUCP>", p, artid);
X		if (p)
X			*--p = '.';
X	} else
X		strcpy(oidbuf, artid);
X	p = oidbuf;
X	while (*++p)
X		if (isupper(*p))
X			*p = tolower(*p);
X
X	hfp = xfopen(ARTFILE, "r");
X#ifdef DBM
X	dbminit(ARTFILE);
X	lhs.dptr = oidbuf;
X	lhs.dsize = strlen(lhs.dptr) + 1;
X	rhs = fetch(lhs);
X	if (rhs.dptr) {
X		fseek(hfp, (long)rhs.dptr, 0);
X#endif DBM
X	while (fgets(lbuf, BUFLEN, hfp) != NULL) {
X		p = index(lbuf, '\t');
X		if (p == NULL)
X			p = index(lbuf, '\n');
X		*p = 0;
X		if (strcmp(lbuf, artid) == 0 || strcmp(lbuf, oidbuf) == 0) {
X			fclose(hfp);
X			*p = '\t';
X			*(lbuf + strlen(lbuf) - 1) = 0;	/* zap the \n */
X			return(lbuf);
X		}
X	}
X#ifdef DBM
X	}
X#endif DBM
X	fclose(hfp);
X	return(NULL);
X}
X
X/*
X * Hunt up the article "artid", and return the newsgroup/artnum
X * where it can be found.
X */
Xchar *
Xfindfname(artid)
Xchar *artid;
X{
X	char *line, *p, *q;
X	char *findhist();
X	static char fname[256];
X
X	line = findhist(artid);
X	if (line) {
X		/* Look for it stored as an article, where it should be */
X		p = index(line, '\t');
X		p = index(p+1, '\t');
X		p++;
X		if (*p) {
X			q = index(p, ' ');
X			if (q)
X				*q = 0;
X			strcpy(fname, p);
X			return fname;
X		}
X	}
X
X	return NULL;
X}
X
X/*
X * Hunt up the article "artid", fopen it for read, and return a
X * file descriptor to it.  We look everywhere we can think of.
X */
XFILE *
Xhfopen(artid)
Xchar *artid;
X{
X	char *p;
X	char *findhist();
X	FILE *rv = NULL;
X	char fname[256];
X
X	p = findfname(artid);
X	if (p) {
X		strcpy(fname, dirname(p));
X		rv = fopen(fname, "r");	/* NOT xfopen! */
X		if (rv != NULL)
X			return rv;
X	}
X
X	xerror("Cannot hfopen article %s", artid);
X#ifdef lint
X	return NULL;
X#endif lint
X}
*-*-END-of-src/funcs2.c-*-*
exit