[net.sources] news 2.10.2 src part 9

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

cat <<'E_O_F'

These four files should replace the ones that were in yesterdays
posting. If you are ever in doubt, the latest sccsid should
be used.

The one I posted yesterday would throw away any mail replies.

Sorry for the confusion.
---rick
E_O_F
if test ! -d src
then
	mkdir src
	echo mkdir src
fi
rm -f src/defs.dist src/rparams.h src/readr.c src/visual.c src/postnews.c
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.35	9/5/84 */
X
X#define NEWS_VERSION   "B 2.10.2 9/5/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/rparams.h
sed 's/^X//' >src/rparams.h <<'*-*-END-of-src/rparams.h-*-*'
X/*
X * rparams.h - parameters for readnews, rfuncs, and readr.
X */
X
X/*	@(#)rparams.h	2.15	9/5/84	*/
X
X#include "params.h"
X
X/* flags for readnews */
X#define pflag	options[0].flag
X#define tflag	options[1].flag
X#define aflag	options[2].flag
X#define nflag	options[3].flag
X#define cflag	options[4].flag
X#define lflag	options[5].flag
X#define rflag	options[6].flag
X#define sflag	options[7].flag
X#define xflag	options[8].flag
X#define hflag	options[9].flag
X#define Mflag	options[10].flag
X#define fflag	options[11].flag
X#define uflag	options[12].flag
X#define eflag	options[13].flag
X
X#define	NEXT	0
X#define SPEC	1
X
X#define	FORWARD	0
X#define BACKWARD 1
X
X#define UNKNOWN 0001	/* possible modes for news program */
X#define MAIL	0004
X#define ANY	0007
X
X#define BITMAPSIZE	2048	/* Must be a power of 2 */
X
Xstruct optable {			/* options table. */
X	char	optlet;		/* option character. */
X	char	filchar;	/* if to pickup string, fill character. */
X	int	flag;		/* TRUE if have seen this opt. */
X	int	newstate;	/* STRING if takes arg, else OPTION */
X	int	oldmode;	/* OR of legal input modes. */
X	int	newmode;	/* output mode. */
X	char	*buf;		/* string buffer */
X};
X
X/* external declarations specific to readnews */
Xextern	char	*infile, *outfile, PAGER[];
Xextern	char	bitmap[], *temprc, *MAILER, *MAILPARSER;
X
X#ifndef ROOTID
Xextern	int	ROOTID;
X#endif
X
X#ifdef NOTIFY
Xextern	char	*TELLME;
X#endif
X
Xextern char	filename[],coptbuf[],datebuf[],titlebuf[],afline[];
Xextern char	newsrc[],groupdir[],rcbuf[],*rcline[],*argvrc[];
Xextern int	mode, ngrp, line, newrc(), readmode;
Xextern long	bit, obit, last, ngsize, minartno;
Xextern FILE	*rcfp,*actfp;
Xextern time_t	atime;
Xextern struct stat statbuf;
Xextern struct optable *optpt, options[];
Xextern int	actdirect, rcreadok, zapng;
X
X#ifndef lint
X/* lint gets very mad about i-minartno, this is one way of shutting it up */
X/* macros */
X#define get(i)	((i<minartno)? 0 : (bitmap[(i-minartno) >> 3] & (1 << (i-minartno) % 8)))
X#define set(i)	if (i>=minartno) bitmap[(i-minartno) >> 3] |= (1 << (i-minartno) % 8);else
X#define clear(i) if (i>=minartno) bitmap[(i-minartno) >> 3] &= ~(1 << (i-minartno) % 8);else
X#endif !lint
X
X#define FCLOSE(fp)	{if (fp != NULL) {fclose(fp);fp = NULL;}}
*-*-END-of-src/rparams.h-*-*
echo x - src/readr.c
sed 's/^X//' >src/readr.c <<'*-*-END-of-src/readr.c-*-*'
X/*
X * readr - /bin/mail and msgs interface and associated functions.
X */
X
X#ifndef lint
Xstatic char	*SccsId = "@(#)readr.c	2.46	9/5/84";
X#endif !lint
X
X#include "rparams.h"
X#if defined(BSD4_2) || defined(BSD4_1C)
X#include <sys/dir.h>
X#else
X#include "ndir.h"
X#endif !BSD4_2 && !BSD4_1C
X#include <setjmp.h>
X#include <errno.h>
X
Xextern int errno;
X
Xchar *Progname = "readnews";	/* used by xerror to identify failing program */
X
Xstatic char	lbuf[BUFLEN*2];
Xlong atol();
X
X#define	saveart	oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize
X#define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines))
X
Xchar *tft = "/tmp/folXXXXXX";
X
X/*
X * These were made static for u370 with its buggy cc.
X * I judged it better to have one copy with no ifdefs than
X * to conditionally compile them as automatic variables
X * in readr (which they originally were).  Performance
X * considerations might warrent moving some of the simple
X * things into register variables, but I don't know what
X * breaks the u370 cc.
X */
Xstatic char goodone[BUFLEN];		/* last decent article		*/
Xstatic char ogroupdir[BUFLEN];		/* last groupdir		*/
Xstatic char address[PATHLEN];		/* for reply copy		*/
Xstatic char edcmdbuf[128];
Xstatic int rfq = 0;			/* for last article		*/
Xstatic long ongsize;			/* Previous ngsize		*/
Xstatic long pngsize;			/* Printing ngsize		*/
Xstatic char *bptr;			/* temp pointer.		*/
Xstatic struct srec srec;		/* srec for sys file entries	*/
Xstatic char *tfilename;			/* temporary file name 		*/
Xstatic char ofilename1[BUFLEN];		/* previous file name		*/
Xstatic struct hbuf hbuf1, hbuf2,	/* for minusing			*/
X		*h = &hbuf1,		/* current header		*/
X		*hold = &hbuf2,		/* previous header		*/
X		*hptr;			/* temporary 			*/
Xstatic char *ptr1, *ptr2, *ptr3;	/* for reply manipulation	*/
Xstatic int  news = 0;
Xstatic int  abs = FALSE;		/* TRUE if we asked absolutely	*/
Xstatic char tf[100];
Xstatic long oobit;			/* last bit, really		*/
Xstatic int dgest = 0;
Xstatic FILE *ofp;			/* Current output file to terminal*/
Xstatic FILE *fp;			/* current article to be printed*/
Xstatic int holdup;			/* 1 iff should stop before hdr */
Xstatic int ignorenews;			/* 1 iff readnews -p > /dev/null*/
Xstatic time_t timelastsaved;		/* time newsrc last written out */
Xstatic jmp_buf sigjmpbuf;		/* for signal processing */
Xstatic int canlongjmp;			/* TRUE if setjmp on sigjmp valid */
X
Xint catchcont();
X
Xreadr()
X{
X
X#ifdef DEBUG
X	fprintf(stderr, "readr()\n");
X#endif
X	if (aflag) {
X		if (*datebuf) {
X			if ((atime = cgtdate(datebuf)) == -1)
X				xerror("Cannot parse date string");
X		} else
X			atime = 0;
X	}
X
X	if (pflag && ignoring())
X		ignorenews = TRUE;
X
X	if (xflag)
X		uflag = 0;
X	if (uflag)
X		(void) time(&timelastsaved);
X
X	ofp = stdout;
X	if (cflag && coptbuf[0] != '\0') {
X		umask(022);
X		mktemp(outfile);	/* get "unique" file name */
X		close(creat(outfile,0666));
X		ofp = xfopen(outfile, "w");
X		umask(N_UMASK);
X		cflag = FALSE;
X		pflag = TRUE;
X	}
X
X	/* loop reading articles. */
X	fp = NULL;
X	obit = -1;
X	nextng();
X	for ( ;; ) {
X		if (getnextart(FALSE))
X			break;
X#ifdef DEBUG
X		fprintf(stderr,"after getnextart, fp %x, pos %ld, bit %ld, group '%s', filename '%s'\n",
X			fp, ftell(fp), bit, groupdir, filename);
X#endif
X		strcpy(goodone, filename);
X		if (pflag || lflag || eflag) {
X			/* This code should be gotten rid of */
X			if (sigtrap) {
X				qfflush(ofp);
X				fprintf(ofp, "\n");
X				cdump(ofp);
X				xxit(0); /* kludge! drop when qfflush works */
X				return;
X			}
X			clear(bit);
X			nextbit();
X			FCLOSE(fp);
X			continue;
X		}
X		for ( ;; ) {
X			char *pp;
X			int nlines;
X			int (*ointr)();
X#ifdef	SIGCONT
X			int (*ocont)();
X#endif
X			setjmp(sigjmpbuf);
X			canlongjmp = TRUE;
X
X			sigtrap = FALSE;
X			if (!cflag) {
X				if (rfq)
X					sprintf(bfr, "Last article.  [qfr] ");
X				else {
X					nlines = NLINES(h, fp);
X					if (nlines <= 0) {
X						sprintf(bfr, "(0 lines) Next? [nqfr] ");
X						FCLOSE(fp);
X					} else {
X						sprintf(bfr, "(%d lines) More? [ynq] ", nlines);
X					}
X				}
X			} else
X				sprintf(bfr, "? ");
X			fprintf(ofp, "%s", bfr);
X			fflush(ofp);
X			bptr = lbuf;
X			ointr = signal(SIGINT, catchcont);
X#ifdef SIGCONT
X			ocont = signal(SIGCONT, catchcont);
X#endif
X			pp = fgets(bptr, BUFLEN, stdin);
X			canlongjmp = FALSE;
X			signal(SIGINT, ointr);
X#ifdef SIGCONT
X			signal(SIGCONT, ocont);
X#endif
X			if (pp != NULL)
X				break;
X			if (!sigtrap)
X				return;
X#ifdef SIGCONT
X			if (sigtrap != SIGCONT)
X#endif
X				fprintf(ofp, "\n");
X		}
X		nstrip(bptr);
X		while (*bptr == ' ' || *bptr == '\t')
X			bptr++;
X		if (command())
X			break;
X	}
X
X	if (!news)
X		fprintf(stderr, "No news.\n");
X	cout(ofp);
X}
X
X
X#define EOL() if (*bptr != '\0') { fprintf(ofp, "? for commands.\n"); return FALSE; }
X/*
X * Process one command, which has already been typed in.
X */
Xcommand()
X{
X	char *findhist();
X	long i;
X
X	switch (*bptr++) {
X
X	/* No.  Go on to next article. */
X	case 'n':
X		EOL();
X		readmode = NEXT;
X		if (!cflag)
X			FCLOSE(fp);
X		fprintf(ofp, "\n");
X		clear(bit);
X		saveart;
X		nextbit();
X		break;
X
X	/* Undigestify the article. */
X	case 'd':
X		dgest = 1;
X		/* fall through */
X
X	/* yes: print this article, go on. */
X	case 'y':
X		EOL();
X		/* fall through. */
X
X	/* The user hit return.  Default is 'y' unless rfq, then it's 'q'. */
X	case '\0':
X		if (!bptr[-1] && rfq)
X			return TRUE;
X		readmode = NEXT;
X		showtail(fp);
X		clear(bit);
X		saveart;
X		nextbit();
X		break;
X
X	/*
X	 * Unsubscribe to the newsgroup and go on to next group
X	 */
X	case 'u':
X		fprintf(ofp, "To unsubscribe, use 'U'\n");
X		break;
X
X	case 'U':
X		fprintf(ofp, "Unsubscribing to newsgroup: %s\n", groupdir);
X		obit = -1;
X		FCLOSE(fp);
X		if (cflag)
X			clear(bit);
X		else
X			putc('\n', ofp);
X		rfq = 0;
X		zapng = TRUE;
X		saveart;
X		if (nextng()) {
X			if (actdirect == BACKWARD)
X				fprintf(ofp, "Can't back up.\n");
X			else
X				return TRUE;
X		}
X		break;
X
X		/* Print the current version of news */
X	case 'v':
X		fprintf(ofp, "News version: %s\n", news_version);
X		break;
X
X		/* reprint the article */
X	case 'p':
X		EOL();
X		if (!cflag)
X			goto minus;
X		readmode = NEXT;
X		if (!cflag) {
X			FCLOSE(fp);
X			bit = last;
X			putc('\n', ofp);
X		}
X		obit = -1;
X		break;
X
X		/* decrypt joke */
X	case 'D':
X		caesar_command();
X		readmode = NEXT;
X		clear(bit);
X		saveart;
X		nextbit();
X		break;
X
X		/* write out the article someplace */
X	case 's':
X	case 'w':
X		{
X		char *grn = groupdir;
X		tfilename = filename;
X		if (*bptr == '-') {
X			bptr++;
X			grn = ogroupdir;
X			if (*ofilename1)
X				tfilename = ofilename1;
X		}
X		if (*bptr != '\0' && *bptr != ' ') {
X			fprintf(ofp, "Bad file name.\n");
X			break;
X		}
X		while (*bptr == ' ')
X			bptr++;
X		if (*bptr != '|' && *bptr != '/') {
X			char	hetyped[BUFLEN];
X			char	*boxptr;
X			strcpy(hetyped, bptr);
X			if (boxptr = getenv("NEWSBOX"))
X				if (index(boxptr, '%'))
X					sprintf(bptr, boxptr, grn);
X				else
X					strcpy(bptr, boxptr);
X			else if (hetyped[0] == '~' && hetyped[1] == '/') {
X				strcpy(hetyped, bptr+2);
X				strcpy(bptr, userhome);
X			} else
X				strcpy(bptr, ".");
X			strcat(bptr, "/");
X			if (hetyped[0] != '\0')
X				strcat(bptr, hetyped);
X			else
X				strcat(bptr, "Articles");
X		}
X		fwait(fsubr(save, tfilename, bptr));
X		}
X		break;
X
X		/* back up  */
X	case '-':
Xminus:
X		rfq = 0;
X		abs = TRUE;
X		if (!*ofilename1) {
X			fprintf(ofp, "Can't back up.\n");
X			break;
X		}
X		if (cflag)
X			clear(bit);
X		else {
X			FCLOSE(fp);
X			putc('\n', ofp);
X		}
X		hptr = h;
X		h = hold;
X		hold = hptr;
X		strcpy(bfr, filename);
X		strcpy(filename, ofilename1);
X		strcpy(ofilename1, bfr);
X		obit = bit;
X		if (strcmp(groupdir, ogroupdir)) {
X			strcpy(bfr, groupdir);
X			selectng(ogroupdir, TRUE);
X			strcpy(groupdir, ogroupdir);
X			strcpy(ogroupdir, bfr);
X			ngrp = 1;
X			back();
X		}
X		bit = oobit;
X		oobit = obit;
X		obit = -1;
X		(void) getnextart(TRUE);
X		return FALSE;
X
X		/* skip forwards */
X	case '+':
Xcaseplus:
X		if (*bptr == '\0')
X			strcat(bptr, "1");
X		rfq = 0;
X		if (cflag)
X			clear(bit);
X		saveart;
X		last = bit;
X		for (i = 0; i < atol(bptr); i++) {
X			nextbit();
X			if ((bit > pngsize) || (rflag && bit < 1))
X				break;
X		}
X		if (!cflag) {
X			putc('\n', ofp);
X			FCLOSE(fp);
X		}
X		obit = -1;
X		break;
X
X	/* exit - time updated to that of most recently read article */
X	case 'q':
X		EOL();
X		return TRUE;
X
X	/* exit - no time update. */
X	case 'x':
X		EOL();
X		xxit(0);
X
X	/* cancel the article. */
X	case 'c':
X		(void) cancel_command();
X		break;
X
X	/* escape to shell */
X	case '!':
X		fwait(fsubr(ushell, bptr, (char *)NULL));
X		fprintf(ofp, "\n");
X		hdr();
X		break;
X
X	/* mail reply */
X	case 'r':
X		(void) reply_command();
X		break;
X
X	/* send to some system */
X	case 'X':
X		xmit_command();
X		break;
X	/* mark the rest of the articles in this group as read */
X	case 'K':
X		saveart;
X		while (bit <= pngsize && bit >= minartno) {
X			clear(bit);
X			nextbit();
X		}
X		FCLOSE(fp);
X		break;
X
X	/* next newsgroup */
X	case 'P':
X		*bptr = '-';
X	case 'N':
X		FCLOSE(fp);
X		if (next_ng_command())
X			return TRUE;
X		break;
X
X	case 'b':	/* back up 1 article */
X		i = bit - 1;
X		goto tryartnum;
X	case '0':	/* specific no. */
X	case '1':
X	case '2':
X	case '3':
X	case '4':
X	case '5':
X	case '6':
X	case '7':
X	case '8':
X	case '9':
X		sscanf(--bptr, "%ld", &i);
X		if (i == 0) {
X			fprintf(ofp, "Bad article no.\n");
X			break;
X		}
X		if (i > pngsize) {
X			fprintf(ofp, "Not that many articles.\n");
X			break;
X		}
Xtryartnum:
X		readmode = SPEC;
X		abs = TRUE;
X		bit = i;
X		obit = -1;
X		if (!cflag) {
X			putc('\n', ofp);
X			FCLOSE(fp);
X		}
X		rfq = 0;
X		break;
X
X	/* specific message ID. */
X	case '<':
X		ptr1 = findhist(--bptr);
X		if (ptr1 == NULL) {
X			fprintf(ofp, "No such article: %s.\n", bptr);
X			break;
X		}
X		ptr2 = index(ptr1, '\t');
X		ptr3 = index(++ptr2, '\t');
X		ptr2 = index(++ptr3, ' ');
X		if (ptr2)
X			*ptr2 = '\0';
X		ptr2 = index(ptr3, '/');
X		*ptr2++ = '\0';
X		abs = TRUE;
X		if (cflag)
X			clear(bit);
X		else {
X			FCLOSE(fp);
X			putc('\n', ofp);
X		}
X		saveart;
X		strcpy(ogroupdir, ptr3);
X		if (strcmp(groupdir, ogroupdir)) {
X			strcpy(bfr, groupdir);
X			selectng(ogroupdir, TRUE);
X			strcpy(groupdir, ogroupdir);
X			strcpy(ogroupdir, bfr);
X			back();
X		}
X		sscanf(ptr2, "%ld", &bit);
X		oobit = obit;
X		obit = -1;
X		(void) getnextart(TRUE);
X		rfq = 0;
X		break;
X
X	/* follow-up article */
X	case 'f':
X		if (*bptr == '-')
X			tfilename = ofilename1;
X		else
X			tfilename = filename;
X		sprintf(bfr,"%s/%s %s", BIN, "postnews", tfilename);
X		system(bfr);
X		break;
X
X	/* erase - pretend we haven't seen this article. */
X	case 'e':
X		if (rfq || *bptr == '-') {
X			if (strcmp(groupdir, ogroupdir)) {
X				i = bit;
X				strcpy(bfr, groupdir);
X				selectng(ogroupdir, FALSE);
X				set(oobit);
X				fprintf(ofp,"Holding article %ld newsgroup %s\n", oobit, ogroupdir),
X				strcpy(groupdir, ogroupdir);
X				selectng(bfr, FALSE);
X				bit = i;
X			} else {
X				fprintf(ofp,"Holding article %ld\n", oobit);
X				set(oobit);
X			}
X		} else {
X			fprintf(ofp,"Holding article %ld\n", bit);
X			set(bit);
X			goto caseplus;	/* skip this article for now */
X		}
X		break;
X
X	case 'H':
X	case 'h':
X		if (!hflag)
X			dash(8, ofp);
X		if (*bptr == '-') {
X			if (oobit > 0)
X				fprintf(ofp, "Article %ld:\n", oobit);
X			hprint(hold, ofp, 1 + (bptr[-1]=='H'));
X		} else {
X			fprintf(ofp, "Article %ld of %ld: %s\n",
X				rfq ? oobit : bit, pngsize, h->ident);
X			hprint(h, ofp, 1 + (bptr[-1]=='H'));
X		}
X		if (!hflag)
X			dash(8, ofp);
X		break;
X
X	case '#':
X		fprintf(ofp, "Article %ld of %ld: newsgroup %s\n",
X			rfq ? oobit : bit, pngsize, rfq ? ogroupdir : groupdir);
X		break;
X
X		/* error */
X	case '?':
X		help(ofp);
X		break;
X	default:
X		fprintf(ofp, "? for commands.\n");
X		break;
X	}
X
X	return FALSE;
X}
X
Xcancel_command()
X{
X	tfilename = filename;
X	hptr = h;
X	if (*bptr == '-') {
X		if (*ofilename1) {
X			tfilename = ofilename1;
X			hptr = hold;
X		}
X		bptr++;
X	}
X	EOL();
X	readmode = SPEC;
X	strcpy(rcbuf, hptr->path);
X	ptr1 = index(rcbuf, ' ');
X	if (ptr1)
X		*ptr1 = 0;
X	if (uid != ROOTID && strcmp(username, rcbuf)) {
X		fprintf(ofp, "Can't cancel what you didn't write.\n");
X		return FALSE;
X	}
X	if (!cancel(ofp, hptr, 0) && hptr == h) {
X		clear(bit);
X		saveart;
X		nextbit();
X		obit = -1;
X		if (!cflag)
X			putc('\n', ofp);
X		FCLOSE(fp);
X	}
X	return TRUE;
X}
X
Xreply_command()
X{
X	register char	*pathptr;
X	int edit = 1;
X	char *ed;
X	FILE *tfp;
X	char	curberk[BUFLEN];
X	char *replyname();
X	char subj[BUFLEN];
X	char folbuf[BUFLEN];
X	struct stat statb;
X	long creatm;
X
X	hptr = h;
X	while (*bptr && index("d-", *bptr)) {
X		switch (*bptr) {
X		/* Followup the previous article. */
X		case '-':
X			hptr = hold;
X			break;
X
X		/* Don't edit the headers */
X		case 'd':
X			edit = 0;
X			break;
X		}
X		bptr++;
X	}
X	EOL();
X	ptr1 = index(MAILPARSER, ' ');
X	if (ptr1)
X		*ptr1 = '\0';
X	if (edit && access(MAILPARSER, 1)) {
X#ifdef IHCC
X		fprintf(stderr, "Can't edit headers, 'recmail' missing.\n");
X#else
X		fprintf(stderr, "Can't edit headers without %s\n", MAILPARSER);
X#endif
X		edit = 0;
X	}
X	if (ptr1)
X		*ptr1 = ' ';
X
X	*rcbuf = '\0';
X	*curberk = '\0';
X	pathptr = replyname(hptr);;
X	for (ptr1 = address, ptr2 = pathptr; *ptr2; ptr1++, ptr2++) {
X		if (index("\"\\$", *ptr2))
X			*ptr1++ = '\\';
X		*ptr1 = *ptr2;
X	}
X	*ptr1 = '\0';
X
X	folbuf[0] = '\0';		/* References */
X	if (hptr->followid[0]) {
X		strcpy(folbuf, hptr->followid);
X		strcat(folbuf, ", ");
X	}
X	strcat(folbuf, hptr->ident);
X
X	strcpy(subj, hptr->title);	/* Subject */
X	while (isspace(*bptr))
X		bptr++;
X	if (*bptr != '\0')
X		strcpy(subj, bptr);
X	if (!prefix(subj, "Re:")){
X		strcpy(bfr, subj);
X		sprintf(subj, "Re: %s", bfr);
X	}
X	if (!edit) {
X		fprintf(ofp, "To: %s\n", pathptr);
X		ed = index(MAILER, '%');
X		if (ed && ed[1] == 's')
X			fprintf(ofp, "Subject: %s\n", subj);
X		fflush(ofp);
X	}
X
X	/* Put the user in the editor to create the body of the followup. */
X	if (edit) {
X		strcpy(tf, tft);
X		mktemp(tf);
X
X		ed = getenv("EDITOR");
X		if (ed == NULL)
X			ed = DFTEDITOR;
X
X		if ((tfp = fopen(tf, "w")) == NULL) {
X			perror(tf);
X			creatm = 0L;
X		} else {
X			fprintf(tfp, "To: %s\n", pathptr);
X			fprintf(tfp, "Subject: %s\n", subj);
X			fprintf(tfp, "References: %s\n\n", folbuf);
X			fstat(fileno(tfp), &statb);
X			creatm = statb.st_mtime;
X			fclose(tfp);
X		}
X
X		sprintf(edcmdbuf, "%s %s", ed, tf);
X		system(edcmdbuf);
X		strcpy(rcbuf, MAILPARSER);
X		strcat(rcbuf, " -t");
X		strcat(rcbuf, " < ");
X		strcat(rcbuf, tf);
X		if (access(tf, 4) || stat(tf, &statb)) {
X			fprintf(stderr, "Reply not sent: no input file.\n");
X			return FALSE;
X		}
X		if (statb.st_mtime == creatm) {
X			fprintf(stderr, "Reply not sent: cancelled.\n");
X			unlink(tf);
X			return FALSE;
X		}
X		fprintf(ofp,"Sending reply.\n");
X		fflush(stdout);
X		if (fork() == 0) {
X			system(rcbuf);
X			unlink(tf);
X			_exit(0);
X		}
X	} else {
X		sprintf(rcbuf, MAILER, hptr->title);
X		sprintf(bfr, "%s %s", rcbuf, address);
X		system(bfr);
X	}
X	hdr();
X	return TRUE;
X}
X
Xxmit_command()
X{
X	tfilename = filename;
X	if (*bptr == '-') {
X		if (*ofilename1)
X			tfilename = ofilename1;
X		bptr++;
X	}
X	if (*bptr != '\0' && *bptr != ' ') {
X		fprintf(ofp, "Bad system name.\n");
X		return;
X	}
X	while (*bptr == ' ')
X		bptr++;
X	if (*bptr == '\0') {
X		fprintf(ofp, "Missing system name.\n");
X		return;
X	}
X	if (s_find(&srec, bptr) == NULL) {
X		fprintf(ofp, "%s not in SYSFILE\n", bptr);
X		return;
X	}
X	transmit(&srec, tfilename);
X}
X
Xnext_ng_command()
X{
X	obit = -1;
X	if (!*bptr || *bptr == '-') {
X		if (cflag)
X			clear(bit);
X		else
X			putc('\n', ofp);
X		if (*bptr)
X			actdirect = BACKWARD;
X		rfq = 0;
X		saveart;
X		if (nextng()) {
X			if (actdirect == BACKWARD)
X				fprintf(ofp, "Can't back up.\n");
X			else
X				return TRUE;
X		}
X		return FALSE;
X	}
X	while (isspace(*bptr))
X		bptr++;
X	if (!validng(bptr)) {
X		fprintf(ofp, "No such group.\n");
X		return FALSE;
X	}
X	if (cflag)
X		clear(bit);
X	else
X		putc('\n', ofp);
X	readmode = SPEC;
X	rfq = 0;
X	saveart;
X	back();
X	selectng(bptr, TRUE);
X	return FALSE;
X}
X
Xcaesar_command()
X{
X	char	temp[BUFLEN];
X	FILE	*pfp, *popen();
X
X	fprintf(stderr, "Caesar decoding:\n");
X	sprintf(temp, "%s/%s", LIB, "caesar");
X	if (*bptr) {
X		strcat(temp, " ");
X		strcat(temp, bptr);
X	}
X	if (NLINES(h, fp) > LNCNT && *PAGER) {
X		strcat(temp, " | ");
X		strcat(temp, PAGER);
X	}
X	pfp = popen(temp, "w");
X	tprint(fp, pfp, FALSE);
X	FCLOSE(fp);
X	pclose(pfp);
X}
X
X/*
X * Show the user the tail, if any, of the message on file
X * descriptor fd, and close fd.  The digester is considered,
X * and the pager is used if appropriate.
X */
Xshowtail(fd)
XFILE *fd;
X{
X	if (fd == NULL)
X		return;
X
X	if (dgest) {
X		digest(fd, ofp, h);
X	} else if (!lflag && !pflag && !eflag) {
X		pprint(fd);
X	}
X	fclose(fd);
X}
X
X/*
X * Print out the rest of the article through the pager.
X */
Xpprint(fd)
XFILE *fd;
X{
X#ifdef PAGE
X	/* Filter the tail of long messages through PAGER. */
X	if (NLINES(h, fd) > LNCNT && *PAGER) {
X		if (!index(PAGER, FMETA)) {
X			FILE *pfp, *popen();
X
X			pfp = popen(PAGER, "w");
X			if (pfp == NULL)
X				pfp = ofp;
X			/*
X			 * What follows is an attempt to prevent the
X			 * next message from scrolling part of this
X			 * message off the top of the screen before
X			 * the poor luser can read it.
X			 */
X			tprint(fd, pfp, FALSE);
X			pclose(pfp);
X		}
X		else
X			pout(ofp);
X		holdup = TRUE;
X	}
X	else
X#endif
X		tprint(fd, ofp, FALSE);
X}
X
X/*
X * Find the next article we want to consider, if we're done with
X * the last one, and show the header.
X */
Xgetnextart(minus)
Xint minus;
X{
X 	int noaccess;
X 	register DIR *dirp;
X 	register struct direct *dir;
X 	long nextnum, tnum;
X
X 	noaccess = 0;
X
X	if (minus)
X		goto nextart2;	/* Kludge for "-" command. */
X
X	if (bit == obit)	/* Return if still on same article as last time */
X		return 0;
X
X	sigtrap = FALSE;
X
Xnextart:
X#ifdef DEBUG
X	fprintf(stderr,"nextart:\n");
X#endif DEBUG
X	dgest = 0;
X
X	if (bit < minartno && !rflag)
X		bit = minartno;
X
X	/* If done with this newsgroup, find the next one. */
X	while (ngsize <= 0 || ((long) bit > ngsize) || (rflag && bit < minartno)) {
X		if (nextng()) {
X			if (actdirect == BACKWARD) {
X				fprintf(ofp, "Can't back up.\n");
X				actdirect = FORWARD;
X				continue;
X			} else
X				if (rfq++ || pflag || cflag)
X					return 1;
X		}
X		if (rflag)
X			bit = ngsize + 1;
X		else
X			bit = minartno - 1;
X		if (uflag) {
X			time_t now;
X			(void) time(&now);
X			if (now - timelastsaved > 5*60 /* 5 minutes */) {
X				fprintf(stderr,"[Saving .newsrc]\n");
X				writeoutrc();
X				timelastsaved = now;
X			}
X		}
X	}
X
Xnextart2:
X#ifdef DEBUG
X	fprintf(stderr, "article: %s/%ld\n", groupdir, bit);
X#endif
X	if (rcreadok)
X		rcreadok = 2;	/* have seen >= 1 article */
X	sprintf(filename, "%s/%ld", dirname(groupdir), bit);
X	if (rfq && goodone[0])
X		strcpy(filename, goodone);
X	if (sigtrap) {
X		if (sigtrap == SIGHUP)
X			return 1;
X		if (!rcreadok)
X			xxit(0);
X		fprintf(ofp, "Abort (n)?  ");
X		fflush(ofp);
X		gets(bfr);
X		if (*bfr == 'y' || *bfr == 'Y')
X			xxit(0);
X		sigtrap = FALSE;
X	}
X#ifdef DEBUG
X	fprintf(stderr, "filename = '%s'\n", filename);
X#endif
X	/* Decide if we want to show this article. */
X 	if ((fp = fopen(filename, "r")) == NULL) {
X 		/* since there can be holes in legal article numbers, */
X 		/* we wait till we hit 5 consecutive bad articles */
X 		/* before we haul off and scan the directory */
X 		if (++noaccess < 5)
X 			goto badart;
X		noaccess = 0;
X 		dirp = opendir(dirname(groupdir));
X 		if (dirp == NULL) {
X			if (errno != EACCES)
X				fprintf(stderr,"Can't open %s", dirname(groupdir));
X 			goto badart;
X 		}
X 		nextnum = rflag ? minartno - 1 : ngsize + 1;
X 		while ((dir = readdir(dirp)) != NULL) {
X 			tnum = atol(dir->d_name);
X 			if (tnum <= 0)
X 				continue;
X 			if (rflag ? (tnum > nextnum && tnum < bit)
X 				  : (tnum < nextnum && tnum > bit))
X 				nextnum = tnum;
X 		}
X 		closedir(dirp);
X 		if (rflag ? (nextnum >= bit) : (nextnum <= bit))
X 			goto badart;
X#ifdef DEBUG
X		fprintf(stderr,"nextnum = %ld\n",nextnum);
X#endif DEBUG
X 		do {
X 			clear(bit);
X 			nextbit();
X 		} while (rflag ? (nextnum < bit) : (nextnum > bit));
X 		obit = -1;
X 		abs = FALSE;
X 		goto nextart;
X 	} else
X 		noaccess = 0;
X
X 	if (ignorenews || hread(h, fp, TRUE) == NULL
X		|| (!rfq && !aselect(h, abs))) {
X badart:
X#ifdef DEBUG
X		fprintf(stderr, "Bad article '%s'\n", filename);
X#endif
X		FCLOSE(fp);
X		clear(bit);
X		obit = -1;
X		nextbit();
X		abs = FALSE;
X		goto nextart;
X	}
X	abs = FALSE;
X	actdirect = FORWARD;
X	news = TRUE;
X	hdr();
X	if (pflag)
X		tprint(fp, ofp, FALSE);
X	else if (cflag && !lflag && !eflag) {
X		fflush(ofp);
X		pprint(fp);
X	}
X	if (cflag || lflag || eflag || pflag) {
X		sigtrap = FALSE;
X		FCLOSE(fp);
X	}
X	obit = bit;
X	return 0;
X}
X
X/*
X * Print out whatever the appropriate header is
X */
Xhdr()
X{
X	char *briefdate();
X
X	if (rfq)
X		return;
X
X	if (lflag || eflag) {
X		hprint(h, ofp, 0);
X		return;
X	}
X
X	/* Print out a header */
X	if (ngrp) {
X		pngsize = ngsize;
X		ngrp--;
X		nghprint(groupdir);
X	}
X	if (!hflag)
X		fprintf(ofp, "Article %ld of %ld, %s.\n",
X			bit, pngsize, briefdate(h->subdate));
X	hprint(h, ofp, pflag ? 1 : 0);
X}
X
Xnghprint(title)
Xchar *title;
X{
X	char *tstr = "Newsgroup ";
X	int l = strlen(title) + strlen(tstr);
X
X	fprintf(ofp, "\n");
X	if (!hflag) {
X		dash(l, ofp);
X		fprintf(ofp, "%s%s\n", tstr, title);
X		dash(l, ofp);
X	} else {
X		fprintf(ofp, "%s%s, ", tstr, title);
X		if (bit == pngsize)
X			fprintf(ofp, "%ld\n", pngsize);
X		else
X			fprintf(ofp, "%ld-%ld\n", bit, pngsize);
X	}
X	fprintf(ofp, "\n");
X}
X
X/*
X * Routine to catch a continue signal.
X */
Xcatchcont(sig)
Xint sig;
X{
X	signal(sig, catchcont);
X	sigtrap = sig;
X	fflush(ofp);
X#ifdef SIGCONT
X	if (fp && sig == SIGCONT)
X		hdr();
X	if (sig != SIGCONT)
X#endif SIGCONT
X		putc('\n', ofp);
X	if (canlongjmp)
X		longjmp(sigjmpbuf,1);
X}
*-*-END-of-src/readr.c-*-*
echo x - src/visual.c
sed 's/^X//' >src/visual.c <<'*-*-END-of-src/visual.c-*-*'
X/*
X * readr - visual news interface.
X */
X
X#ifndef lint
Xstatic char	*SccsId = "@(#)visual.c	1.12	9/5/84";
Xstatic char Author[] = "@(#)visual interface written by Kenneth Almquist";
X#endif !lint
X
X#define GGRMAIL
X#ifdef USG
X#include <termio.h>
X#include <fcntl.h>
X#else
X#include <sgtty.h>
X#endif USG
X
X#include <errno.h>
X#include "rparams.h"
X#if defined(BSD4_2) || defined(BSD4_1C)
X#include <sys/dir.h>
X#else
X#include "ndir.h"
X#endif
X#ifdef BSD4_2
X#define BIT(_a) (1<<((_a)-1))
X#endif
X#ifdef MYDB
X#include "db.h"
X#endif MYDB
X
X#include <errno.h>
X
Xextern int errno;
X
X#ifdef SIGTSTP
X#include <setjmp.h>
X#endif
X
X#define ARTWLEN	(ROWS-2)/* number of lines used to display article */
X#define even(cols) ((cols&1) ? cols + 1 : cols)
X#ifdef STATTOP
X#define PRLINE	0	/* prompter line */
X#define SPLINE	1	/* secondary prompt line */
X#define ARTWIN	2	/* first line of article window */
X#define SECPRLEN 81	/* length of secondary prompter */
X#else
X#define PRLINE	(ROWS-1)/* prompter line */
X#define SPLINE	(ROWS-2)/* secondary prompt line */
X#define ARTWIN	0	/* first line of article window */
X#define SECPRLEN 100	/* length of secondary prompter */
X#endif
X
X#define PIPECHAR '|'	/* indicate save command should pipe to program */
X#define META	0200	/* meta character bit (as in emacs) */
X/* print (display) flags */
X#define HDRONLY	0001	/* print header only */
X#define NOPRT	0002	/* don't print at all */
X#define NEWART	0004	/* force article display to be regenerated */
X#define HELPMSG	0010	/* display currently contains help message */
X/* prun flags */
X#define CWAIT	0001	/* type "continue?" and wait for return */
X#define BKGRND	0002	/* run process in the background */
X/* values of curflag */
X#define CURP1	1	/* cursor after prompt */
X#define CURP2	2	/* cursor after secondary prompt */
X#define CURHOME	3	/* cursor at home position */
X/* flags for vsave routine */
X#define SVHEAD	01	/* write out article header */
X#define OVWRITE	02	/* overwrite the file if it already exists */
X/* other files */
X
X#define	saveart	oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize
X#define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines))
X
X/* terminal handler stuff */
Xextern int _junked;
X#define clearok(xxx, flag) _junked = flag
Xextern int COLS;
Xextern int ROWS;
Xextern int hasscroll;
X
XFILE *tmpfile();
Xchar *getmailname();
Xchar *findparent();
Xint onint(), onquit();
Xint onstop();
X
X/*
X * Kludge: space so that routines can access beyond
X * the end of arrays without messing me up.
X */
Xstatic char junk[64];
X
Xchar *Progname = "vnews";		/* for xerror */
X
X/* variables shared between vnews routines */
Xstatic char linebuf[LBUFLEN];		/* temporary workspace */
Xstatic FILE *tfp;			/* temporary file */
Xstatic char tfname[] = "/tmp/vnXXXXXX";	/* name of temp file */
Xstatic long artbody;			/* offset of body into article */
Xstatic int quitflg;			/* if set, then quit */
Xstatic int erased;			/* current article has been erased */
Xstatic int artlines;			/* # lines in article body */
Xstatic int artread;			/* entire article has been read */
Xstatic int hdrstart;			/* beginning of header */
Xstatic int hdrend;			/* end of header */
Xstatic int lastlin;			/* number of lines in tempfile */
Xstatic int tflinno = 0;			/* next line in tempfile */
Xstatic int maxlinno;			/* number of lines in file + folded */
Xstatic char secpr[SECPRLEN];		/* secondary prompt */
Xstatic char prompt[30];			/* prompter */
Xstatic short prflags;			/* print flags (controls updscr) */
Xstatic short curflag;			/* where to locate cursor */
Xstatic int dlinno;			/* top line on screen */
Xstatic char timestr[20];		/* current time */
Xstatic int ismail;			/* true if user has mail */
Xstatic char *mailf;			/* user's mail file */
Xstatic int alflag;			/* set if unprocessed alarm signal */
Xstatic int atend;			/* set if at end of article */
Xstatic char cerase;			/* erase character */
Xstatic char ckill;			/* kill character */
Xstatic char cintr;			/* interrupt character */
Xint ospeed;				/* terminal speed */
Xstatic int intflag;			/* set if interrupt received */
X
X#ifdef SIGTSTP
Xstatic int reading;			/* to keep stupid BSD from restarting reads */
Xjmp_buf intjmp, alrmjmp;
X#endif SIGTSTP
X
X#ifdef MYDB
Xstatic int hasdb;			/* true if article data base exists */
X#endif
X
X#ifdef DIGPAGE
Xstatic int endsuba;			/* end of sub-article in digest */
X#endif
X
X#ifdef MYDEBUG
XFILE *debugf;				/* file to write debugging info on */
X#endif
X
Xchar *tft = "/tmp/folXXXXXX";
X
X/*
X * These were made static for u370 with its buggy cc.
X * I judged it better to have one copy with no ifdefs than
X * to conditionally compile them as automatic variables
X * in readr (which they originally were).  Performance
X * considerations might warrent moving some of the simple
X * things into register variables, but I don't know what
X * breaks the u370 cc.
X */
Xstatic char goodone[BUFLEN];		/* last decent article		*/
Xstatic char ogroupdir[BUFLEN];		/* last groupdir		*/
Xstatic char edcmdbuf[128];
Xstatic int rfq = 0;			/* for last article		*/
Xstatic long ongsize;			/* Previous ngsize		*/
Xstatic long pngsize;			/* Printing ngsize		*/
Xstatic char *bptr;			/* temp pointer.		*/
Xstatic char *tfilename;			/* temporary file name 		*/
Xstatic char ofilename1[BUFLEN];		/* previous file name		*/
Xstatic struct hbuf hbuf1, hbuf2; 	/* for minusing			*/
Xstatic struct hbuf *h = &hbuf1,		/* current header		*/
X		*hold = &hbuf2,		/* previous header		*/
X		*hptr;			/* temporary			*/
Xstatic char *ptr1, *ptr2, *ptr3;	/* for reply manipulation	*/
Xstatic int  news = 0;
Xstatic int  aabs = FALSE;		/* TRUE if we asked absolutely	*/
Xstatic char *ed, tf[100];
Xstatic long oobit;			/* last bit, really		*/
Xstatic int dgest = 0;
Xstatic FILE *fp;			/* current article to be printed*/
X
Xreadr()
X{
X
X#ifdef MYDEBUG
X	debugf = fopen("DEBUG", "w");
X	setbuf(debugf, (char *)NULL);
X#endif
X	if (aflag) {
X		if (*datebuf) {
X			if ((atime = cgtdate(datebuf)) == -1)
X				xerror("Cannot parse date string");
X		} else
X			atime = 0;
X	}
X
X	if (sigtrap)
X		xxit(1);
X	mktemp(tfname);
X	close(creat(tfname,0666));
X	if ((tfp = fopen(tfname, "w+")) == NULL)
X		xerror("Can't create temp file");
X	unlink(tfname);
X	mailf = getmailname();
X#ifdef MYDB
X	if (opendb() >= 0) {
X		hasdb = 1;
X		fputs("Using article data base\n", stderr);	/*DEBUG*/
X		getng();
X	}
X#endif
X	ttysave();
X	signal(SIGINT, onint);
X	signal(SIGQUIT, onquit);
X	if (sigtrap)
X		xxit(1);
X	ttyraw();
X	timer();
X
X	/* loop reading articles. */
X	fp = NULL;
X	obit = -1;
X	nextng();
X	quitflg = 0;
X	while (quitflg == 0) {
X		if (getnextart(FALSE))
X			break;
X		strcpy(goodone, filename);
X		if (sigtrap)
X			return;
X		vcmd();
X	}
X
X	if (news)
X		botscreen();
X	ttycooked();
X	if (!news)
X		fprintf(stderr, "No news.\n");
X}
X
X/*
X * Read and execute a command.
X */
X
Xvcmd() {
X	register c;
X	char *p;
X	long count;
X	int countset;
X
X	appfile(fp, dlinno + ARTWLEN + 1);
X#ifdef DIGPAGE
X	endsuba = findend(dlinno);
X	if (artlines > dlinno + ARTWLEN
X	 || endsuba > 0 && endsuba < artlines
X#else
X	if (artlines > dlinno + ARTWLEN
X#endif
X	 || (prflags & HDRONLY) && artlines > hdrend) {
X		atend = 0;
X		if (prflags&HDRONLY)
X			strcpy(prompt,"more? ");
X		else
X			sprintf(prompt,"more(%d%%)? ",((dlinno+ARTWLEN-hdrend)*100)/maxlinno);
X	} else {
X		atend = 1;
X		strcpy(prompt, "next? ");
X		if (!erased)
X			clear(bit);		/* article read */
X	}
X	curflag = CURP1;
X	p = prompt + strlen(prompt);
X	countset = 0;
X	count = 0;
X	while ((c = vgetc()) >= '0' && c <= '9' || c==cerase || c ==ckill) {
X		if (c == cerase) {
X			count /= 10;
X			if (count == 0)
X				countset = 0;
X			continue;
X		}
X		if (c == ckill) {
X			countset = 0;
X			count = 0;
X			continue;
X		}
X		count = (count * 10) + (c - '0');
X		sprintf(p, "%ld", count);
X		countset = 1;
X	}
X	if (c == '\033') {			/* escape */
X		strcat(prompt, "M-");
X		c = vgetc();
X		if (c != cintr)
X			c |= META;
X	}
X	secpr[0] = '\0';
X	if (countset == 0)
X		count = 1;
X	docmd(c, count);
X	if (c != '?' && c != 'H')		/* UGGH */
X		prflags &=~ HELPMSG;
X	if (dlinno > hdrstart)
X		prflags &=~ HDRONLY;
X}
X
X
X/*
X * Process one command, which has already been typed in.
X */
Xdocmd(c, count)
Xchar c;
Xlong count;
X{
X	int i;
X	long nart;
X	char *findhist();
X
X	switch (c) {
X
X	/* Show more of current article, or advance to next article */
X	case '\n':
X	case ' ':
X	case '\06':	/* Control-F for vi compat */
X		prflags &=~ NOPRT;
X		if (atend)
X			goto next;
X		else if (prflags & HDRONLY) {
X			prflags &=~ HDRONLY;
X			if (hasscroll)
X				dlinno = hdrstart;}
X#ifdef DIGPAGE
X		else if (endsuba > 0)
X			dlinno = endsuba;
X#endif
X		else if ((appfile(fp, dlinno + 2 * ARTWLEN), artread)
X		 && hasscroll && artlines - dlinno <= ARTWLEN + 2)
X			dlinno = artlines - ARTWLEN;
X		else
X			dlinno += ARTWLEN;
X		break;
X
X	/* No.  Go on to next article. */
X	case '.':	/* useful if you have a keypad */
Xnext:	case 'n':
X		readmode = NEXT;
X		FCLOSE(fp);
X		clear(bit);
X		saveart;
X		nextbit();
X		break;
X
X
X	/* Back up count pages */
X	case META|'v':
X	case '\2':	/* Control-B */
X		dlinno -= ARTWLEN * count;
X		if (dlinno < 0)
X			dlinno = 0;
X		break;
X
X	/* forward half a page */
X	case '\4':	/* Control-D, as in vi */
X		dlinno += ARTWLEN/2 * count;
X		break;
X
X	/* backward half a page */
X	case '\25':	/* Control-U */
X		dlinno -= ARTWLEN/2 * count;
X		if (dlinno < 0)
X			dlinno = 0;
X		break;
X
X	/* forward count lines */
X	case '\16':	/* Control-N */
X	case '\32':	/* Control-Z */
X		dlinno += count;
X		break;
X
X	/* backwards count lines */
X	case '\20':	/* Control-P */
X	case '\31':	/* Control-Y */
X		dlinno -= count;
X		if (dlinno < 0)
X			dlinno = 0;
X		break;
X
X	/* Turn displaying of article back on */
X	case 'l':
X	case 'd':
X		prflags &=~ NOPRT;
X		break;
X
X	/* display header */
X	case 'h':
X		dlinno = hdrstart;
X		prflags |= HDRONLY;
X		prflags &=~ NOPRT;
X		break;
X
X	/*
X	 * Unsubscribe to the newsgroup and go on to next group
X	 */
X
X	case 'U':
X	case 'u':
X		strcat(prompt, "u");
X		c = vgetc();
X		if (c == 'g') {
X			obit = -1;
X			FCLOSE(fp);
X			zapng = TRUE;
X			saveart;
X			if (nextng()) {
X				if (actdirect == BACKWARD)
X					msg("Can't back up.");
X				else
X					quitflg = 1;	/* probably unnecessary */
X			}
X		} else {
X			if (c != cintr && c != ckill)
X				msg("Illegal command");
X		}
X		break;
X
X		/* Print the current version of news */
X	case 'v':
X		msg("News version: %s", news_version);
X		break;
X
X
X	/* Decrypt joke.  Always does rot 13 */
X	case 'D':
X		appfile(fp, 32767);
X		for (i = hdrend ; i < artlines ; i++) {
X			register char ch, *p;
X			tfget(linebuf, i);
X			for (p = linebuf ; (ch = *p) != '\0' ; p++) {
X				if (ch >= 'a' && c <= 'z')
X					*p = (ch - 'a' + 13) % 26 + 'a';
X				else if (ch >= 'A' && c <= 'Z')
X					*p = (ch - 'A' + 13) % 26 + 'A';
X			}
X			tfput(linebuf, i);
X		}
X		prflags |= NEWART;
X		prflags &=~ (HDRONLY|NOPRT);
X		break;
X
X		/* write out the article someplace */
X		/* w writes out without the header */
X	case 's':
X	case 'w': {
X		char *grn = groupdir;
X		int wflags;
X
X		msg("file: ");
X		curflag = CURP2;
X		while ((wflags = vgetc()) == ' ');
X		if (wflags == cintr) {
X			secpr[0] = '\0';
X			break;
X		}
X		if (wflags == '|') {
X			linebuf[0] = '|';
X			if (prget("| ", linebuf+1))
X				break;
X		} else {
X			pushback(wflags);
X			if (prget("file: ", linebuf))
X				break;
X		}
X		wflags = 0;
X		if (c == 's')
X			wflags |= SVHEAD;
X		if (count != 1)
X			wflags |= OVWRITE;
X		bptr = linebuf;
X		while( *bptr == ' ')
X			bptr++;	/* strip leading spaces */
X
X		if (*bptr != PIPECHAR && *bptr != '/') {
X			char	hetyped[BUFLEN];
X			char	*boxptr;
X			strcpy(hetyped, bptr);
X			if (boxptr = getenv("NEWSBOX"))
X				if (index(boxptr, '%'))
X					sprintf(bptr, boxptr, grn);
X				else
X					strcpy(bptr, boxptr);
X			else if (hetyped[0] == '~' && hetyped[1] == '/') {
X				strcpy(hetyped, bptr+2);
X				strcpy(bptr, userhome);
X			} else
X				bptr[0] = '\0';
X			if (bptr[0])
X				strcat(bptr, "/");
X			if (hetyped[0] != '\0')
X				strcat(bptr, hetyped);
X			else
X				strcat(bptr, "Articles");
X		}
X		vsave(bptr, wflags);
X		break;
X	}
X
X		/* back up  */
X	case '-':
X		aabs = TRUE;
X		if (!*ofilename1) {
X			msg("Can't back up.");
X			break;
X		}
X		FCLOSE(fp);
X		hptr = h;
X		h = hold;
X		hold = hptr;
X		strcpy(bfr, filename);
X		strcpy(filename, ofilename1);
X		strcpy(ofilename1, bfr);
X		obit = bit;
X		if (strcmp(groupdir, ogroupdir)) {
X			strcpy(bfr, groupdir);
X			selectng(ogroupdir, FALSE);
X			strcpy(groupdir, ogroupdir);
X			strcpy(ogroupdir, bfr);
X			ngrp = 1;
X			back();
X		}
X		bit = oobit;
X		oobit = obit;
X		obit = -1;
X		getnextart(TRUE);
X		return FALSE;
X
X		/* skip forwards */
X	case '+':
Xcaseplus:	if (count == 0)
X			break;
X		saveart;
X		last = bit;
X		for (i = 0; i < count; i++) {
X			nextbit();
X			if ((bit > pngsize) || (rflag && bit < 1))
X				break;
X		}
X		FCLOSE(fp);
X		obit = -1;
X		break;
X
X	/* exit - time updated to that of most recently read article */
X	case 'q':
X		quitflg = 1;
X		break;
X
X	case 'x':
X		onquit();
X		break;
X
X	/* cancel the article. */
X	case 'c':
X		strcpy(prompt, "cancel [n]? ");
X		if (vgetc() != 'y') {
X			msg("Article not cancelled");
X			break;
X		}
X		cancel_command();
X		break;
X
X	/* escape to shell */
X	case '!': {
X		register char *p;
X		int flags;
X
X		p = linebuf;
X		if (prget("!", p))
X			break;
X		flags = CWAIT;
X		if (*p == '\0') {
X			strcpy(linebuf, SHELL);
X			flags = 0;
X		}
X		while (*p) p++;
X		while (p > linebuf && p[-1] == ' ')
X			p--;
X		if (*--p == '&') {
X			*p = '\0';
X			flags = BKGRND;
X		} else if (*p == '|') {
X			*p = '\0';
X			sprintf(bfr, "(%s)|mail '%s'", linebuf, username);
X			strcpy(linebuf, bfr);
X			flags |= BKGRND;
X		} else {
X			prflags |= NOPRT;
X		}
X		shcmd(linebuf, flags);
X		break;
X	}
X
X	/* mail reply */
X	case 'r':
X		reply();
X		break;
X
X
X	/* next newsgroup */
X	case 'N':
X		FCLOSE(fp);
X		if (next_ng_command())
X			quitflg = 1;
X		break;
X
X	/*  mark the rest of the articles in this group as read */
X	case 'K':
X		saveart;
X		while (bit <= ngsize && bit > minartno) {
X			clear(bit);
X			nextbit();
X		}
X		FCLOSE(fp);
X		break;
X
X	/* Print the full header */
X	case 'H':
X		{
X		if (fp == NULL) {
X			msg("No current article");
X			break;
X		}
X		move(ARTWIN, 0);
X		fseek(fp, 0L, 0);
X		for (i=0;i<ARTWLEN;i++) {
X			if (fgets(linebuf, COLS, fp) == NULL)
X				break;
X			if (linebuf[0] == '\n')
X				break;
X			linebuf[COLS] = '\0';
X			addstr(linebuf);
X		}
X		for(;i<ARTWLEN; i++)
X			addstr(linebuf);
X		prflags |= HELPMSG|NEWART;
X		}
X		break;
X	case 'b':	/* backup 1 article */
X		count = bit - 1;
X		/* NO BREAK */
X
X	case 'A':	/* specific number */
X		if (count > pngsize) {
X			msg("not that many articles");
X			break;
X		}
X		readmode = SPEC;
X		aabs = TRUE;
X		bit = count;
X		obit = -1;
X		FCLOSE(fp);
X		break;
X
X	/* display parent article */
X	case 'p':
X#ifdef MYDB
X		if (hasdb && (ptr3 = findparent(h->ident, &nart)) != NULL) {
X			msg("parent: %s/%ld", ptr3, nart);	/*DEBUG*/
X			updscr();				/*DEBUG*/
X			goto selectart;
X		}
X#endif
X		if (h->followid[0] == '\0') {
X			msg("no references line");
X			break;
X		}
X		if ((ptr1 = rindex(h->followid, ' ')) != NULL)
X			ptr1++;
X		else
X			ptr1 = h->followid;
X		strcpy(linebuf, ptr1);
X		msg("%s", linebuf);
X		curflag = CURP2;
X		updscr();		/* may take this out later */
X		goto searchid;
X
X	/* specific message ID. */
X	case '<':
X		/* could improve this */
X		linebuf[0] = '<';
X		if (prget("<", linebuf+1))
X			break;
Xsearchid:	secpr[0] = '\0';
X		if (index(linebuf, '@') == NULL && index(linebuf, '>') == NULL) {
X			ptr1 = linebuf;
X			if (*ptr1 == '<')
X				ptr1++;
X			ptr2 = index(ptr1, '.');
X			if (ptr2 != NULL) {
X				*ptr2++ = '\0';
X				sprintf(bfr, "<%s@%s.UUCP>", ptr2, ptr1);
X				strcpy(linebuf, bfr);
X			}
X		}
X		if (index(linebuf, '>') == NULL)
X			strcat(linebuf, ">");
X
X		ptr1 = findhist(linebuf);
X		if (ptr1 == NULL) {
X			msg("%s not found", linebuf);
X			break;
X		}
X		ptr2 = index(ptr1, '\t');
X		ptr3 = index(++ptr2, '\t');
X		ptr2 = index(++ptr3, ' ');
X		if (ptr2)
X			*ptr2 = '\0';
X		ptr2 = index(ptr3, '/');
X		*ptr2++ = '\0';
X		sscanf(ptr2, "%ld", &nart);
X
X		/*
X		 * Go to a given article.  Ptr3 specifies the newsgroup
X		 * and nart specifies the article number.
X		 */
Xselectart:	aabs = TRUE;
X		FCLOSE(fp);
X		saveart;
X		strcpy(ogroupdir, ptr3);
X		if (strcmp(groupdir, ogroupdir)) {
X			strcpy(bfr, groupdir);
X			selectng(ogroupdir, TRUE);
X			strcpy(groupdir, ogroupdir);
X			strcpy(ogroupdir, bfr);
X			back();
X		}
X		bit = nart;
X		oobit = obit;
X		obit = -1;
X		getnextart(TRUE);
X		rfq = 0;
X		break;
X
X	/* follow-up article */
X	case 'f':
X		sprintf(bfr, "%s/%s %s", BIN, "postnews", goodone);
X		shcmd(bfr, CWAIT);
X		break;
X
X	/* erase - pretend we haven't seen this article. */
X	case 'e':
X		erased = 1;
X		set(bit);
X		goto caseplus;	/* skip this article for now */
X
X	case '#':
X		msg("Article %ld of %ld", rfq ? oobit : bit, pngsize);
X		break;
X
X		/* error */
X	case '?':
X		{
X			FILE *helpf;
X			sprintf(linebuf, "%s/vnews.help", LIB);
X			if ((helpf = fopen(linebuf, "r")) == NULL) {
X				msg("Can't open help file");
X				break;
X			}
X			move(ARTWIN, 0);
X			while (fgets(linebuf, LBUFLEN, helpf) != NULL)
X				addstr(linebuf);
X			fclose(helpf);
X			prflags |= HELPMSG|NEWART;
X		}
X		break;
X
X	default:
X		if (c != ckill && c != cintr)
X			msg("Illegal command");
X		break;
X	}
X
X	return FALSE;
X}
X
Xcancel_command()
X{
X	tfilename = filename;
X	/*readmode = SPEC; bug? */
X	strcpy(rcbuf, h->path);
X	ptr1 = index(rcbuf, ' ');
X	if (ptr1)
X		*ptr1 = 0;
X	if (uid != ROOTID && strcmp(username, rcbuf)) {
X		msg("Can't cancel what you didn't write.");
X		return;
X	}
X	if (!cancel(stderr, h, 0)) {
X		clear(bit);
X		saveart;
X		nextbit();
X		obit = -1;
X		fp = NULL;
X	}
X	FCLOSE(fp);
X}
X
X/*
X * Generate replies
X */
X
Xreply()
X{
X	char *arg[4];
X	register FILE *rfp;
X	char subj[132];
X	char *nogomsg;
X	register char *p;
X	char *replyname();
X	struct stat statb;
X	time_t creatm;
X
X	/* Put the user in the editor to create the body of the reply. */
X	ed = getenv("EDITOR");
X	if (ed == NULL || *ed == '\0')
X		ed = DFTEDITOR;
X	if (ed == NULL) {
X		msg("You don't have an editor");
X		return;
X	}
X
X	arg[0] = "/bin/sh";
X	arg[1] = "-c";
X
X	strcpy(tf, tft);
X	mktemp(tf);
X	close(creat(tf,0666));
X	if ((rfp = fopen(tf, "w")) == NULL) {
X		msg("Can't create %s", tf) ;
X		return;
X	}
X	strcpy(subj, h->title);
X	if (!prefix(subj, "Re:")){
X		strcpy(bfr, subj);
X		sprintf(subj, "Re: %s", bfr);
X	}
X
X#ifdef INTERNET
X	if (h->sender[0])
X		p = h->sender;
X	else
X#endif
X		p = replyname(h);
X	fprintf(rfp, "To: %s\n", p);
X	fprintf(rfp, "Subject: %s\n", subj);
X	fprintf(rfp, "In-reply-to: your article %s\n", h->ident);
X	sprintf(rcbuf, "exec %s -t < %s; rm %s", MAILPARSER, tf, tf);
X	nogomsg = "Mail not sent";
X	putc('\n', rfp);
X	fstat(fileno(rfp), &statb);
X	creatm = statb.st_mtime;
X	fclose(rfp);
X
X	sprintf(edcmdbuf, "exec %s %s", ed, tf);
X	arg[2] = edcmdbuf;
X	arg[3] = NULL;
X	if (prun(arg, 0) != 0) {
X		msg("Couldn't run editor");
X		unlink(tf);
X		return;
X	}
X
X	if (access(tf, 4) || stat(tf, &statb)) {
X		msg("%s: no input file.", nogomsg);
X		unlink(tf);
X		return;
X	}
X	if (statb.st_mtime == creatm) {
X		msg("%s: cancelled.", nogomsg);
X		unlink(tf);
X		return;
X	}
X
X	arg[2] = rcbuf;
X	arg[3] = NULL;
X	prun(arg, BKGRND);
X	prflags |= NOPRT;
X}
X
Xnext_ng_command()
X{
X	obit = -1;
X	if (prget("group? ", linebuf))
X		return FALSE;
X	bptr = linebuf;
X	if (!*bptr || *bptr == '-') {
X		if (*bptr)
X			actdirect = BACKWARD;
X		saveart;
X		if (nextng()) {
X			if (actdirect == BACKWARD)
X				msg("Can't back up.");
X			else
X				return TRUE;
X		}
X		return FALSE;
X	}
X	while (isspace(*bptr))
X		bptr++;
X	if (!validng(bptr)) {
X		msg("No such group.");
X		return FALSE;
X	}
X	readmode = SPEC;
X	saveart;
X	back();
X	selectng(bptr, TRUE);
X	return FALSE;
X}
X
X/*
X * Find the next article we want to consider, if we're done with
X * the last one, and show the header.
X */
Xgetnextart(minus)
Xint minus;
X{
X	int noaccess;
X	register DIR *dirp;
X	register struct direct *dir;
X	long nextnum, tnum;
X	long atol();
X
X	noaccess = 0;
X	if (minus)
X		goto nextart2;	/* Kludge for "-" command. */
X
X	if (bit == obit)	/* Return if still on same article as last time */
X		return 0;
X
Xnextart:
X	if (news) {
X		curflag = CURHOME;
X		_amove(0, 0);
X		vflush();
X	}
X	dgest = 0;
X
X	/* If done with this newsgroup, find the next one. */
X	while (ngsize <= 0 || ((long) bit > ngsize) || (rflag && bit < minartno)) {
X		if (nextng()) {
X			if (actdirect == BACKWARD) {
X				msg("Can't back up.");
X				actdirect = FORWARD;
X				continue;
X			}
X			else /* if (rfq++ || pflag || cflag) */
X				return 1;
X		}
X		if (rflag)
X			bit = ngsize + 1;
X		else
X			bit = -1;
X		noaccess = 2;
X	}
X
X	/* speed things up by not searching for article -1 */
X	if (bit < 0) {
X		bit = minartno - 1;
X		nextbit();
X		aabs = FALSE;
X		goto nextart;
X	}
X
Xnextart2:
X	if (rcreadok)
X		rcreadok = 2;	/* have seen >= 1 article */
X	sprintf(filename, "%s/%ld", dirname(groupdir), bit);
X	if (rfq && goodone[0])	/* ??? */
X		strcpy(filename, goodone);
X	if (sigtrap == SIGHUP)
X		return 1;
X	/* Decide if we want to show this article. */
X	if ((fp = fopen(filename, "r")) == NULL) {
X		/* since there can be holes in legal article numbers, */
X		/* we wait till we hit 5 consecutive bad articles */
X		/* before we haul off and scan the directory */
X		if (++noaccess < 5)
X			goto badart;
X		noaccess = 0;
X		dirp = opendir(dirname(groupdir));
X		if (dirp == NULL) {
X			if (errno != EACCES)
X				msg("Can't open %s", dirname(groupdir));
X			goto nextart;
X		}
X		nextnum = rflag ? minartno - 1 : ngsize + 1;
X		while ((dir = readdir(dirp)) != NULL) {
X			if (!dir->d_ino)
X				continue;
X			tnum = atol(dir->d_name);
X			if (tnum <= 0)
X				continue;
X			if (rflag ? (tnum > nextnum && tnum < bit)
X				  : (tnum < nextnum && tnum > bit))
X				nextnum = tnum;
X		}
X		closedir(dirp);
X		if (rflag ? (nextnum >= bit) : (nextnum <= bit))
X			goto badart;
X		do {
X			clear(bit);
X			nextbit();
X		} while (rflag ? (nextnum < bit) : (nextnum > bit));
X		obit = -1;
X		aabs = FALSE;
X		goto nextart;
X	} else
X		noaccess = 0;
X
X	if (hread(h, fp, TRUE) == NULL || (!rfq && !aselect(h, aabs))) {
Xbadart:
X		FCLOSE(fp);
X		clear(bit);
X		obit = -1;
X		nextbit();
X		aabs = FALSE;
X		goto nextart;
X	}
X	aabs = FALSE;
X	actdirect = FORWARD;
X	news = TRUE;
X	{	/* strip off any notesfile header */
X		register c;
X		register char *p = h->title + strlen(h->title) - 5;
X		if (p > h->title
X		 && (strcmp(p, " (nf)") == 0 || strcmp(p, "(nf)\"") == 0)) {
X			if ((c = getc(fp)) != '#') {
X				ungetc(c, fp);
X			} else {
X				while ((c = getc(fp)) != '\n' && c != EOF);
X				while ((c = getc(fp)) != '\n' && c != EOF);
X				while ((c = getc(fp)) != '\n' && c != EOF);
X			}
X		}
X	}
X	artbody = ftell(fp);
X	fmthdr();
X	artlines = lastlin;
X	artread = 0;
X	prflags |= NEWART;
X	prflags &=~ NOPRT;
X	if (! cflag && hdrend < ARTWLEN && !cflag)
X		prflags |= HDRONLY;
X	dlinno = 0;
X	maxlinno = NLINES(h, fp);
X	erased = 0;
X
X	obit = bit;
X	return 0;
X}
X
X/*
X * Print out whatever the appropriate header is
X */
Xfmthdr() {
X	char *briefdate();
X
X	lastlin = 0;
X	if (ngrp) {
X		pngsize = ngsize;
X		ngrp--;
X		if (!hflag) {
X			sprintf(linebuf, "Newsgroup %s", groupdir);  tfappend(linebuf);
X			tfappend("");
X		}
X	}
X	hdrstart = lastlin;
X	if (!hflag) {
X		sprintf(linebuf, "Article %s %s",
X			h->ident, briefdate(h->subdate));
X		tfappend(linebuf);
X	}
X	vhprint(h, pflag ? 1 : 0);
X	sprintf(linebuf, "(%d lines)", NLINES(h, fp)); tfappend(linebuf);
X	tfappend("");
X	hdrend = lastlin;
X}
X
X/*
X * Print the file header to the temp file.
X */
Xvhprint(hp, verbose)
Xregister struct hbuf *hp;
Xint	verbose;
X{
X	register char	*p1, *p2;
X	int	i;
X	char	fname[BUFLEN];
X	char *tailpath();
X
X	fname[0] = '\0';		/* init name holder */
X
X	p1 = index(hp->from, '(');	/* Find the sender's full name. */
X	if (p1 == NULL && hp->path[0])
X		p1 = index(hp->path, '(');
X	if (p1 != NULL) {
X		strcpy(fname, p1+1);
X		p2 = index(fname, ')');
X		if (p2 != NULL)
X			*p2 = '\0';
X	}
X
X	sprintf(linebuf, "Subject: %s", hp->title);
X	if ((i = strlen(linebuf) - 7) > 9
X	 && strcmp(linebuf + i, " - (nf)") == 0
X	 && (strncmp(linebuf+9, "Re: ", 4) != 0 || i < 9+39))
X		linebuf[i] = '\0';		/* clobber "- (nf)" */
X	tfappend(linebuf);
X	if (!hflag && hp->keywords[0])
X		sprintf(linebuf, "Keywords: %s", hp->keywords), tfappend(linebuf);
X	if (verbose) {
X		sprintf(linebuf, "From: %s", hp->from); tfappend(linebuf);
X		sprintf(linebuf, "Path: %s", hp->path); tfappend(linebuf);
X		if (hp->organization[0])
X			sprintf(linebuf, "Organization: %s", hp->organization), tfappend(linebuf);
X	}
X	else {
X		if (p1 != NULL)
X			*--p1 = '\0';		/* bump over the '(' */
X#ifdef INTERNET
X		/*
X		 * Prefer Path line if it's in internet format, or if we don't
X		 * understand internet format here, or if there is no reply-to.
X		 */
X		sprintf(linebuf, "From: %s", hp->from);
X#else
X		sprintf(linebuf, "Path: %s", tailpath(hp));
X#endif
X		if (fname[0] || hp->organization[0]) {
X			strcat(linebuf, " (");
X			if (fname[0] == '\0') {
X				strcpy(fname,hp->from);
X				p2 = index(fname,'@');
X				if (p2)
X					*p2 = '\0';
X			}
X			strcat(linebuf, fname);
X			if (hp->organization[0] && !hflag) {
X				strcat(linebuf, " @ ");
X				strcat(linebuf, hp->organization);
X			}
X			strcat(linebuf, ")");
X		}
X		tfappend(linebuf);
X		if (p1 != NULL)
X			*p1 = ' ';
X		if (hp->ctlmsg[0]) {
X			sprintf(linebuf, "Control: %s", hp->ctlmsg);
X			tfappend(linebuf);
X		}
X	}
X
X	strcpy(bfr, hp->nbuf);
X	ngdel(bfr);
X	if (verbose) {
X		sprintf(linebuf, "Newsgroups: %s", bfr); tfappend(linebuf);
X		sprintf(linebuf, "Date: %s", hp->subdate); tfappend(linebuf);
X		if (hp->sender[0])
X			sprintf(linebuf, "Sender: %s", hp->sender), tfappend(linebuf);
X		if (hp->replyto[0])
X			sprintf(linebuf, "Reply-To: %s", hp->replyto), tfappend(linebuf);
X		if (hp->followto[0])
X			sprintf(linebuf, "Followup-To: %s", hp->followto), tfappend(linebuf);
X	}
X	else if (strcmp(bfr, groupdir) != 0)
X		sprintf(linebuf, "Newsgroups: %s", bfr), tfappend(linebuf);
X}
X
X
X
X
X#ifdef MYDB
X
X
Xchar *
Xfindparent(id, num)
Xchar *id;
Xlong *num;
X{
X	register char *rcp;
X	struct artrec a;
X	char idbuf[BUFSIZE];
X	char *ngname();
X
X	strcpy(idbuf, id);
X	rcp = idbuf;
X	while(*++rcp)
X		if (isupper(*rcp))
X			*rcp = tolower(*rcp);
X
X	if (lookart(id, &a) == DNULL)
X		return NULL;
X	if (a.parent == DNULL)
X		return NULL;
X	readrec(a.parent, &a);
X	*num = a.groups[0].artno;
X	return ngname(a.groups[0].newsgroup);
X}
X
X#endif
X
X
X/*
X * Append file to temp file, handling control characters, folding lines, etc.
X * We don't grow the temp file to more than nlines so that a user won't have
X * to wait for 20 seconds to read in a monster file from net.sources.
X * What we really want is coroutines--any year now.
X */
X
X#define ULINE 0200
Xstatic char *maxcol;
X
Xappfile(iop, nlines)
Xregister FILE *iop;
X{
X	register int c;
X	register char *icol;	/* &linebuf[0] <= icol <= maxcol */
X
X	if (artread || artlines >= nlines || iop == NULL)
X		return;
X	maxcol = linebuf;
X	icol = linebuf;
X	while ((c = getc(iop)) != EOF) {
X		switch (c) {
X		case ' ':
X			if (icol == maxcol && icol < linebuf + LBUFLEN - 1) {
X				*icol++ = ' ';
X				maxcol = icol;
X			} else {
X				icol++;
X			}
X			break;
X		case '\t':
X			icol = (icol - linebuf &~ 07) + 8 + linebuf;
X			growline(icol);
X			break;
X		case '\b':
X			if (icol > linebuf) --icol;
X			break;
X		case '\n':
X			outline();
X			if (artlines >= nlines)
X				return;
X			icol = linebuf;
X			break;
X		case '\r':
X			icol = linebuf;
X			break;
X		case '\f':
X			outline(); outline(); outline();
X			if (artlines >= nlines)
X				return;
X			icol = linebuf;
X			break;
X		default:
X			if (c < ' ' || c > '~')
X				break;
X			else if (icol >= linebuf + LBUFLEN - 1)
X				icol++;
X			else if (icol == maxcol) {
X				*icol++ = c;
X				maxcol = icol; }
X			else if (*icol == ' ')
X				*icol++ = c;
X			else if (c == '_')
X				*icol++ |= ULINE;
X			else
X				*icol++ = (c | ULINE);
X			break;
X		}
X	}
X	if (maxcol != linebuf)		/* file not terminated with newline */
X		outline();
X	artread++;
X}
X
Xgrowline(col)
Xchar *col;
X{
X	while (maxcol < col && maxcol < linebuf + LBUFLEN - 1)
X		*maxcol++ = ' ';
X}
X
Xoutline()
X{
X	*maxcol = '\0';
X	if (strncmp(linebuf, ">From ", 6) == 0) {
X		register char *p;
X		for (p = linebuf ; (*p = p[1]) != '\0' ; p++);
X	}
X	tfappend(linebuf);
X	if (maxcol > linebuf)
X		artlines = lastlin;
X	maxcol = linebuf;
X}
X
Xprget(prompter, buf)
Xchar *prompter, *buf;
X{
X	char *p, *q, *r;
X	int c, lastc;
X
X	curflag = CURP2;
X	r = buf;
X	lastc = '\0';
X	for (;;) {
X		*r = '\0';
X		p = secpr;
X		for (q = prompter ; *q ; q++)
X			*p++ = *q;
X		for (q = buf ; *q ; q++) {
X			if (p < &secpr[SECPRLEN-1] && *q >= ' ' && *p <= '~')
X				*p++ = *q;
X		}
X		*p = '\0';
X		c = vgetc();
X		if (c == '\n' || c == cintr) {
X			break;
X		}
X		if (c == cerase) {
X			if (lastc == '\\')
X				r[-1] = c;
X			else if (r > buf)
X				r--;
X		} else if (c == ckill) {
X			if (lastc == '\\')
X				r[-1] = c;
X			else
X				r = buf;
X		} else {
X			*r++ = c;
X		}
X		lastc = c;
X	}
X	curflag = CURHOME;
X	secpr[0] = '\0';
X	return (c == cintr);
X}
X
X
X
X/*
X * Execute a shell command.
X */
X
Xshcmd(cmd, flags)
Xchar *cmd;
X{
X	char *arg[4];
X
X	arg[0] = SHELL, arg[1] = "-c", arg[2] = cmd, arg[3] = NULL;
X	return prun(arg, flags);
X}
X
X
Xprun(args, flags)
Xchar **args;
X{
X	int pid;
X	int i;
X	int (*savequit)();
X	char *env[100], **envp;
X	char a[BUFLEN + 2];
X	extern char **environ;
X	int pstatus, retval;
X
X	if (!(flags & BKGRND)) {
X		botscreen();
X		ttycooked();
X#ifdef SIGTSTP
X		signal(SIGTSTP, SIG_DFL);
X		signal(SIGTTIN, SIG_DFL);
X		signal(SIGTTOU, SIG_DFL);
X#endif
X	}
X	while ((pid = fork()) == -1)
X		sleep(1);		/* must not clear alarm */
X	if (pid == 0) {
X		for (i = 3 ; i < 20 ; i++)
X			close(i);
X		if (flags & BKGRND) {
X			signal(SIGINT, SIG_IGN);
X			signal(SIGQUIT, SIG_IGN);
X#ifdef SIGTSTP
X			signal(SIGTSTP, SIG_IGN);
X			signal(SIGTTIN, SIG_IGN);
X			signal(SIGTTOU, SIG_IGN);
X#endif
X			close(0); close(1);
X			open("/dev/null", 2);
X			dup(0);
X		}
X		/* set $A */
X		sprintf(a, "A=%s", filename);
X		env[0] = a;
X		for (envp = env + 1 ; *environ != NULL && envp < env + 98 ; environ++)
X			if ((*environ)[0] != 'A' || (*environ)[1] != '=')
X				*envp++ = *environ;
X		*envp = NULL;
X
X		umask(savmask);
X		execve(args[0], args, env);
X		fprintf(stderr, "%s: not found\n", args[0]);
X		exit(20);
X	}
X	if (!(flags & BKGRND)) {
X		savequit = signal(SIGQUIT, SIG_IGN);
X		while ((i = wait(&pstatus)) != pid && (i != -1 || errno == EINTR))
X			;
X		if (i == -1)
X			retval = 1;
X		else
X			retval = pstatus;
X		if (flags & CWAIT) {
X			fprintf(stderr, "continue? ");
X			while ((errno = 0, i = getchar()) != '\n'
X				&& (i != EOF || errno == EINTR));
X		}
X		signal(SIGQUIT, savequit);
X		ttyraw();
X		clearok(curscr, 1);
X#ifdef SIGTSTP
X		signal(SIGTSTP, onstop);
X		signal(SIGTTIN, onstop);
X		signal(SIGTTOU, onstop);
X#endif
X		return retval;
X	} else
X		return 0;
X}
X
X#ifdef DIGPAGE
X
X
X/*
X * Find end of current subarticle in digest.
X */
X
Xfindend(l)
X{
X	register i;
X	register char *p;
X
X	for (i = l ; i < l + ARTWLEN && i < lastlin ; i++) {
X		tfget(linebuf, i);
X		for (p = linebuf ; *p == '-' ; p++);
X		if (p > linebuf + 24)
X			return i + 1;
X	}
X	return 0;
X}
X
X#endif
X
X
X/*** Routines for handling temporary file ***/
X
X/*
X * Append to temp file.
X * Long lines are folded.
X */
X
Xtfappend(tline)
Xchar *tline;
X{
X	while (strlen(tline) > COLS) {
X		tfput(tline, lastlin++);
X		tline += COLS;
X		maxlinno++;
X	}
X	tfput(tline, lastlin++);
X}
X
X
Xtfput(tline, linno)
Xchar *tline;
X{
X	register char *p;
X	register FILE *rtfp;		/* try to make it a litte faster */
X	register int i;
X
X	p = tline, i = even(COLS);
X	tfseek(linno, 1);
X	rtfp = tfp;
X	while (--i >= 0) {
X		if (*p)
X			putc(*p++, rtfp);
X		else
X			putc('\0', rtfp);
X	}
X	tflinno++;
X}
X
X
Xtfget(tline, linno)
Xchar *tline;
X{
X	tfseek(linno, 0);
X	fread(tline, even(COLS), 1, tfp);
X	tline[COLS] = '\0';
X	tflinno++;
X}
X
X
Xtfseek(linno, wrflag)
X{
X	static int lastwrflag = 1;
X
X	if (linno != tflinno || wrflag != lastwrflag) {
X		fseek(tfp, (long)linno * even(COLS), 0);
X		tflinno = linno;
X		lastwrflag = wrflag;
X	}
X}
X
X/* VARARGS1 */
Xmsg(s, a1, a2, a3, a4)
Xchar *s;
X{
X	sprintf(secpr, s, a1, a2, a3, a4);
X}
X
X
X/*
X * Update the display.
X * The display is entirely controlled by this routine,
X * which means that this routine may get pretty snarled.
X */
X
Xstatic int savelinno = -1;		/* dlinno on last call to updscr */
Xstatic int savepr;			/* prflags on last call */
X
Xupdscr()
X{
X	int count;
X	int i;
X
X	if (checkin())
X		return;
X	if ((prflags & HELPMSG) == 0
X	 && (dlinno != savelinno || savepr != prflags)
X	 && quitflg == 0) {
X		if (dlinno != savelinno)
X			prflags &=~ NOPRT;
X		count = ARTWLEN;
X		if (prflags & NOPRT)
X			count = 0;
X		if ((prflags & HDRONLY) && count > hdrend)
X			count = hdrend - dlinno;
X#ifdef DIGPAGE
X		if (endsuba > 0 && count > endsuba - dlinno)
X			count = endsuba - dlinno;
X#endif
X		if ((prflags & NEWART) == 0)
X			ushift(ARTWIN, ARTWIN+ARTWLEN-1, dlinno - savelinno);
X		if (count > lastlin - dlinno)
X			count = lastlin - dlinno;
X		for (i = ARTWIN ; i < ARTWIN + ARTWLEN ; i++)
X			clrline(i);
X		for (i = 0 ; i < count ; i++) {
X			tfget(linebuf, dlinno + i);
X			mvaddstr(ARTWIN + i, 0, linebuf);
X		}
X		prflags &=~ NEWART;
X		savepr = prflags;
X		savelinno = dlinno;
X	}
X	clrline(SPLINE), clrline(PRLINE);
X#ifdef STATTOP
X	mvaddstr(PRLINE, 0, prompt);
X#else
X	if (strlen(secpr) <= COLS)
X		mvaddstr(PRLINE, 0, prompt);
X#endif
X	mvaddstr(PRLINE, 48, timestr);
X	mvaddstr(PRLINE, 20, groupdir);
X	addch(' '); addnum(bit); addch('/'); addnum(pngsize); addch(' ');
X	if (ismail)
X		mvaddstr(PRLINE, 62, ismail > 1? "MAIL" : "mail");
X	mvaddstr(SPLINE, 0, secpr);
X	if (curflag == CURP1)
X		move(PRLINE, strlen(prompt));
X	else if (curflag == CURHOME)
X		move(0, 0);
X	refresh();
X}
X
X
Xaddnum(n)
Xregister long n;
X{
X	if (n >= 10)
X		addnum(n / 10);
X	addch((char)(n % 10 + '0'));
X}
X
X
X
X/*** alarm handler ***/
X
X/*
X * Called on alarm signal.
X * Simply sets flag, signal processed later.
X */
X
Xonalarm()
X{
X#ifdef SIGTSTP
X	int dojump = reading;
X
X	reading = FALSE;
X	alflag++;
X	if (dojump)
X		longjmp(alrmjmp, 1);
X#else !SIGTSTP
X	alflag++;
X#endif
X}
X
X
X/*
X * Process alarm signal (or start clock)
X */
X
Xtimer()
X{
X	time_t tod;
X	int hour;
X	int i;
X	struct tm *t;
X	struct stat statb;
X	struct tm *localtime();
X	static char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
X	static long oldmsize = 1000000L;
X	static int rccount = 10;
X
X	alflag = 0;
X	signal(SIGALRM, onalarm);
X	(void) time(&tod);
X	t = localtime(&tod);
X	i = 60 - t->tm_sec;
X	alarm(i > 30? 30 : i);			/* reset alarm */
X	hour = t->tm_hour % 12;
X	if (hour == 0)  hour = 12;
X	sprintf(timestr, "%.3s %d %d:%02d",
X		months + 3 * t->tm_mon, t->tm_mday, hour, t->tm_min);
X#ifdef GGRMAIL
X	if (mailf == NULL || stat(mailf, &statb) < 0) {
X		statb.st_size = 0;
X	}
X	if(statb.st_size > oldmsize) {
X		ismail = 1;
X		beep();
X	} else if (statb.st_size < oldmsize) {
X		ismail = 0;
X	}
X#else
X	ismail = 0;
X	if (mailf != NULL && stat(mailf, &statb) >= 0 && statb.st_size > 0L) {
X		ismail = 1;
X		if (oldmsize < statb.st_size) {
X			ismail = 2;		/* new mail */
X			beep();
X		}
X	} else {
X		statb.st_size = 0L;
X	}
X#endif
X	oldmsize = statb.st_size;
X	if (uflag && !xflag && --rccount < 0) {
X		writeoutrc();
X		if (secpr[0] == '\0')
X			strcpy(secpr, ".newsrc updated");
X		rccount = 10;
X	}
X}
X
X
Xchar *
Xgetmailname()
X{
X	static char mailname[32];
X	register char *p;
X
X	if( (p = getenv("MAIL")) != NULL)
X		return p;
X	if (username[0] == '\0' || strlen(username) > 15)
X		return NULL;
X#ifdef USG
X	sprintf(mailname, "/usr/mail/%s", username);
X#else
X	sprintf(mailname, "/usr/spool/mail/%s", username);
X#endif
X	return mailname;
X}
X
X
X
X/*** Terminal I/O ***/
X
X#define INBUFSIZ 8
X
Xchar inbuf[INBUFSIZ];			/* input buffer */
Xchar outbuf[BUFSIZ];			/* output buffer */
Xint innleft = 0;			/* # of chars in input buffer */
Xint outnleft = BUFSIZ;			/* room left in output buffer */
Xchar *innext;				/* next input character */
Xchar *outnext = outbuf;			/* next space in output buffer */
X#ifdef USG
Xint oflags;				/* fcntl flags (for nodelay read) */
X#endif
X
X
X/*
X * Input a character
X */
X
Xvgetc()
X{
X	register c;
X#if defined(BSD4_2) || defined(BSD4_1C)
X	int readfds, exceptfds;
X#endif
X
Xrecurse:
X	if (--innleft >= 0) {
X		c = *innext++;
X	} else {
X		if (alflag)
X			timer();
X		updscr();	/* update the display */
X		for (;;) {
X			if (innleft > 0 || alflag)
X				goto recurse;
X			intflag = 0;
X#ifdef USG
X			if (oflags & O_NDELAY) {
X				oflags &=~ O_NDELAY;
X				fcntl(0, F_SETFL, oflags);
X			}
X#endif
X#ifdef SIGTSTP
X			if (setjmp(alrmjmp))
X				continue;
X			if (setjmp(intjmp))
X				return cintr;
X			reading = TRUE;
X#endif SIGTSTP
X#if defined(BSD4_2) || defined(BSD4_1C)
X			/* Use a select because it can be interrupted. */
X			readfds = 1; exceptfds = 1;
X			select(1, &readfds, (int *)0, &exceptfds, (int *)0);
X			if (!(readfds & 1))
X				break;
X#endif
X			innleft = read(0, inbuf, INBUFSIZ);
X#ifdef SIGTSTP
X			reading = FALSE;
X#endif SIGTSTP
X			if (innleft > 0)
X				break;
X			if (innleft == 0) {
X				quitflg++;
X				return cintr;
X			}
X			if (errno != EINTR)
X				abort();	/* "Can't happen" */
X			if (intflag) {
X				intflag--;
X				return cintr;
X			}
X		}
X		innext = inbuf + 1;
X		innleft--;
X		c = inbuf[0];
X	}
X#ifndef USG
X#ifndef CBREAK
X	c &= 0177;
X	if (c == '\034')	/* FS character */
X		onquit();
X#endif
X#endif
X	if (c == '\f') {
X		clearok(curscr, 1);
X		goto recurse;
X	}
X	if (c == '\r')
X		c = '\n';
X	return c;
X}
X
X
X/*
X * Push a character back onto the input stream.
X */
X
Xpushback(c)
X{
X	if (innext <= inbuf)
X		abort();
X	*--innext = c;
X	innleft++;
X}
X
X/*
X * Check for terminal input
X */
X
Xcheckin()
X{
X#ifdef FIONREAD
X	int count;
X#endif
X#ifdef STATTOP
X	if (innleft > 0)
X#else
X	if (innleft > 0 || alflag)
X#endif
X		return 1;
X#if defined(USG) || defined(FIONREAD)
X	if (ospeed == B9600)
X		return 0;
X	vflush();
X	if (ospeed <= B300)
X		ttyowait();
X#ifdef USG
X	if ((oflags & O_NDELAY) == 0) {
X		oflags |= O_NDELAY;
X		fcntl(0, F_SETFL, oflags);
X	}
X	if ((innleft = read(0, inbuf, INBUFSIZ)) > 0) {
X		innext = inbuf;
X		return 1;
X	}
X#endif
X#ifdef FIONREAD
X	count = 0;			/* in case FIONREAD fails */
X	ioctl(0, FIONREAD, (char *)&count);
X	if (count)
X		return 1;
X#endif
X#endif
X	return 0;
X}
X
X
X
X/*
X * flush terminal input queue.
X */
X
Xclearin()
X{
X#ifdef USG
X	ioctl(0, TCFLSH, (char *)0);
X#else
X#ifdef TIOCFLUSH
X	ioctl(0, TIOCFLUSH, (char *)0);
X#else
X	struct sgttyb tty;
X	ioctl(0, TIOCGETP, &tty);
X	ioctl(0, TIOCSETP, &tty);
X#endif
X#endif
X	innleft = 0;
X}
X
Xvputc(c)
X{
X	if (--outnleft < 0) {
X		vflush();
X		outnleft--;
X	}
X	*outnext++ = c;
X}
X
X/*
X * Flush the output buffer
X */
X
Xvflush()
X{
X	register char *p;
X	register int i;
X	unsigned oalarm;
X
X	oalarm = alarm(0);
X	for (p = outbuf ; p < outnext ; p += i) {
X		if ((i = write(1, p, outnext - p)) < 0) {
X			if (errno != EINTR)
X				abort();	/* "Can't happen" */
X			i = 0;
X		}
X	}
X	outnleft = BUFSIZ;
X	outnext = outbuf;
X	alarm(oalarm);
X}
X
X
X
X
X/*** terminal modes ***/
X
X#ifdef USG
Xstatic struct termio oldtty, newtty;
X
X/*
X * Save tty modes
X */
X
Xttysave()
X{
X	if (ioctl(1, TCGETA, &oldtty) < 0)
X		xerror("Can't get tty modes");
X	newtty = oldtty;
X	newtty.c_iflag &=~ (INLCR|IGNCR|ICRNL);
X	newtty.c_oflag &=~ (OPOST);
X	newtty.c_lflag &=~ (ICANON|ECHO|ECHOE|ECHOK|ECHONL);
X	newtty.c_lflag |=  (NOFLSH);
X	newtty.c_cc[VMIN] = 1;
X	newtty.c_cc[VTIME] = 0;
X	cerase = oldtty.c_cc[VERASE];
X	ckill = oldtty.c_cc[VKILL];
X	cintr = oldtty.c_cc[VINTR];
X	ospeed = oldtty.c_cflag & CBAUD;
X	initterm();
X}
X
X
X/*
X * Set tty modes for visual processing
X */
X
Xttyraw()
X{
X	while (ioctl(1, TCSETAF, &newtty) < 0 && errno == EINTR)
X		;
X	rawterm();
X}
X
Xttyowait()
X{	/* wait for output queue to drain */
X	while (ioctl(1, TCSETAW, &newtty) < 0 && errno == EINTR)
X		;
X}
X
X/*
X * Restore tty modes
X */
X
Xttycooked()
X{
X	cookedterm();
X	while (ioctl(1, TCSETAF, &oldtty) < 0 && errno == EINTR)
X		;
X	oflags &=~ O_NDELAY;
X	fcntl(0, F_SETFL, oflags) ;
X}
X
X#else
X
Xstatic struct sgttyb oldtty, newtty;
X
X/*
X * Save tty modes
X */
X
Xttysave()
X{
X#ifdef CBREAK
X	struct tchars tchars;	/* special characters, including interrupt */
X#endif
X#ifdef SIGTSTP
X	/* How to get/change terminal modes in a job control environment.
X	   This code is right from the 4.1 bsd jobs(3) manual page.
X	 */
X	int tpgrp, getpgrp();
X
Xretry:
X#ifdef BSD4_2
X	sigblock(BIT(SIGTSTP)|BIT(SIGTTIN)|BIT(SIGTTOU));
X#else !BSD4_2
X	signal(SIGTSTP, SIG_HOLD);
X	signal(SIGTTIN, SIG_HOLD);
X	signal(SIGTTOU, SIG_HOLD);
X#endif !BSD4_2
X	if (ioctl(2, TIOCGPGRP, (char *)&tpgrp) < 0)
X		goto nottty;
X	if (tpgrp != getpgrp(0)) { /* not in foreground */
X		signal(SIGTTOU, SIG_DFL);
X#ifdef BSD4_2
X		sigsetmask(sigblock(0) & ~BIT(SIGTTOU));
X#endif BSD4_2
X		kill(0, SIGTTOU);
X		/* job stops here waiting for SIGCONT */
X		goto retry;
X	}
X	signal(SIGTTIN, onstop);
X	signal(SIGTTOU, onstop);
X	signal(SIGTSTP, onstop);
X#ifdef BSD4_2
X	sigsetmask(sigblock(0) & ~(BIT(SIGTSTP)|BIT(SIGTTIN)|BIT(SIGTTOU)));
X#endif BSD4_2
X#endif SIGTSTP
X	if (ioctl(1, TIOCGETP, (char *)&oldtty) < 0)
Xnottty:		xerror("Can't get tty modes");
X	newtty = oldtty;
X	newtty.sg_flags &=~ (CRMOD|ECHO|XTABS);
X#ifdef CBREAK
X	newtty.sg_flags |= CBREAK;
X	ioctl(1, TIOCGETC, (char *)&tchars);
X	cintr = tchars.t_intrc;
X#else !CBREAK
X	newtty.sg_flags |= RAW;
X	cintr = '\0177';	/* forcibly this on V6 systems */
X#endif !CBREAK
X	cerase = oldtty.sg_erase;
X	ckill = oldtty.sg_kill;
X	ospeed = oldtty.sg_ospeed;
X	initterm();
X}
X
X
X/*
X * Set tty modes for visual processing
X */
X
Xttyraw()
X{
X	while (ioctl(1, TIOCSETN, (char *)&newtty) < 0 && errno == EINTR)
X		;
X	rawterm();
X}
X
Xttyowait()
X{	/* wait for output queue to drain */
X#ifdef TIOCDRAIN	/* This ioctl is a local mod on linus */
X	ioctl(1, TIOCDRAIN, (char *)0);
X#endif
X}
X
X
X/*
X * Restore tty modes
X */
X
Xttycooked()
X{
X	cookedterm();
X	while (ioctl(1, TIOCSETN, (char *)&oldtty) < 0 && errno == EINTR)
X		;
X}
X
X#endif
X
X
X
X/*** signal handlers ***/
X
Xonint() {
X#ifdef SIGTSTP
X	int dojump = reading;
X
X	reading = FALSE;
X#endif SIGTSTP
X	if (!news) {
X		ttycooked();
X		xxit(1);
X	}
X	signal(SIGINT, onint);
X	clearin();			/* flush input queue */
X#ifdef SIGTSTP
X	if (dojump)
X		longjmp(intjmp, 1);
X#endif SIGTSTP
X	intflag++;
X}
X
Xonquit()
X{
X	botscreen();
X	vflush();
X	ttycooked();
X#ifdef SORTACTIVE
X	unlink(ACTIVE);
X#endif SORTACTIVE
X#ifdef COREDUMP
X	abort();
X#else
X	exit(0);
X#endif
X}
X
X#ifdef SIGTSTP
X
Xonstop(signo)
Xint signo;
X{
X	/* restore old terminal state */
X	botscreen();
X	vflush();
X	ttycooked();
X	signal(signo, SIG_DFL);
X#ifdef BSD4_2
X	sigblock(BIT(SIGALRM)|BIT(SIGINT));
X	sigsetmask(sigblock(0) & ~BIT(signo));
X#endif BSD4_2
X	kill(0, signo);	/* stop here until continued */
X
X	fprintf(stderr,"Vnews restarted.");
X	signal(signo, onstop);
X	/* restore our special terminal state */
X	ttyraw();
X	clearok(curscr, 1);
X	updscr();
X#ifdef BSD4_2
X	sigsetmask(sigblock(0) & ~(BIT(SIGALRM)|BIT(SIGINT)));
X#endif BSD4_2
X}
X
X#endif
X
X
X/*** stolen from rfuncs2.c and modified ***/
X
Xvsave(to, flags)
Xregister char *to;
X{
X	register FILE *ufp;
X	int	isprogram = 0;
X	int	isnew = 1;
X	long	saveoff;
X	char	temp[20];
X	char	*fname;
X	char	prog[BUFLEN + 24];
X
X	saveoff = ftell(fp);
X	fseek(fp, artbody, 0);
X	fname = to;
X	if (*to == PIPECHAR) {
X		if (strlen(to) > BUFLEN) {
X			msg("Command name too long");
X			goto out;
X		}
X		flags |= OVWRITE;
X		strcpy(temp, "/tmp/vnXXXXXX");
X		mktemp(temp);
X		fname = temp;
X		_amove(ROWS - 1, 0);
X		vflush();
X	}
X	if ((flags & OVWRITE) == 0) {
X		ufp = fopen(fname, "r");
X		if (ufp != NULL) {
X			fclose(ufp);
X			isnew = 0;
X		}
X	}
X	umask(savmask);
X
X	if (*to == PIPECHAR)
X		isprogram++;
X	if ((ufp = fopen(fname, (flags & OVWRITE) == 0? "a" : "w")) == NULL) {
X		msg("Cannot open %s", fname);
X		goto out;
X	}
X	/*
X	 * V7MAIL code is here to conform to V7 mail format.
X	 * If you need a different format to be able to
X	 * use your local mail command (such as four ^A's
X	 * on the end of articles) substitute it here.
X	 */
X	if (flags & SVHEAD) {
X#ifdef V7MAIL
X		h->subtime = cgtdate(h->subdate);
X		fprintf(ufp, "From %s %s",
X#ifdef INTERNET
X				h->from,
X#else
X				h->path,
X#endif
X					ctime(&h->subtime));
X#endif
X		hprint(h, ufp, 2);
X#ifdef V7MAIL
X		tprint(fp, ufp, TRUE);
X		putc('\n', ufp);	/* force blank line at end (ugh) */
X#else
X		tprint(fp, ufp, FALSE);
X#endif
X	} else {
X		tprint(fp, ufp, FALSE);
X	}
X
X	fclose(ufp);
X	if (isprogram) {
X		sprintf(prog, "(%s)<%s", to + 1, fname);
X		shcmd(prog, CWAIT);
X		prflags |= NOPRT;
X	} else {
X		if ((flags & OVWRITE) == 0)
X			msg("file: %s %s", to, isnew ? "created" : "appended");
X		else
X			msg("file: %s written", to);
X	}
X
Xout:
X	if (isprogram) {
X		unlink(fname);
X	}
X	umask(N_UMASK);
X	fseek(fp, saveoff, 0);
X}
*-*-END-of-src/visual.c-*-*
echo x - src/postnews.c
sed 's/^X//' >src/postnews.c <<'*-*-END-of-src/postnews.c-*-*'
X/*
X * Postnews: post a news message to Usenet.  This C version replaces a shell
X * script, and does more intelligent prompting and filtering than possible
X * in a shell script.
X */
X
X#ifndef lint
Xstatic char	*SccsId = "@(#)postnews.c	1.13	9/5/84";
X#endif !lint
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <pwd.h>
X#ifdef USG
Xstruct passwd *getpwent(), *getpwuid(), *getpwnam();
X#endif USG
X#include "defs.h"
X#define ARCHIVES_DEF "NEWSARCHIVE"
X
Xchar tempfname[50];		/* file name used for making article */
Xchar original[BUFLEN];		/* file name of original, used in followup */
Xchar homedir[BUFLEN];		/* HOME environment setting */
Xchar ccname[BUFLEN];		/* file name for article copy */
X
X/* article header information */
Xchar subject[BUFLEN];
Xchar distribution[BUFLEN];
Xchar references[BUFLEN];
Xchar newsgroups[BUFLEN];
Xchar moderator[BUFLEN];
X
Xchar *Progname = "postnews";		/* for xerror */
X
Xtime_t fmodtime;
Xint ismod = 0;
Xextern char *LIB, *SPOOL, *ACTIVE, *MAILPARSER;
Xchar buf[BUFLEN];
X
Xstruct distr {
X	char abbr[24];
X	char descr[128];
X} distr[16];
X
XFILE *xfopen();
X
Xmain(argc, argv)
Xchar *argv[];
X{
X	init();
X
X	if (argc == 2) {
X		if (strncmp(SPOOL, argv[1], strlen(SPOOL)))
X			xerror("Can only followup to articles in %s", SPOOL);
X		followup(argv[1]);
X		strcpy(original, argv[1]);
X	} else
X	if (askyes("Is this message in response to some other message? ","no")) {
X		char ng[BUFLEN], num[BUFLEN];
X		long i, j;
X		register char *c;
X		int fd;
X		char canpost;
X
X		getpr("In what newsgroup was the article posted? ",ng);
X		if (!valid_ng(ng, &i, &j, &canpost))
X			if (canpost != 'n' )
X				byebye("There is no such newsgroup.");
X			else
X				byebye("You are not allowed to post to that group.");
X
X		printf("Valid article numbers are from %ld to %ld\n", j, i);
X
X		for(;;) {
X			getpr("\nWhat was the article number? ", num);
X			if (num == 0)
X				continue;
X			sprintf(original, "%s/%s", SPOOL, ng);
X			for (c=original+strlen(SPOOL)+1; *c ;++c)
X				if (*c == '.')
X					*c = '/';
X			strcat(original, "/");
X			strcat(original, num);
X
X			if ((fd=open(original,0)) >= 0) {
X				close(fd);
X				printf("\narticle %s\n", original);
X				if (article_line(original, "From: ", buf))
X					printf("%s\n", buf);
X				if (article_line(original, "Subject: ", buf))
X					printf("%s\n", buf);
X				if (askyes("Is this the one you want? ", ""))
X					break;
X			} else
X				printf("I can't find that article.\n");
X		}
X
X		followup(original);
X	} else {
X		do {
X			getpr("Subject: ", subject);
X		} while (*subject == '\0');
X
X		while (!get_newsgroup())
X			;
X		get_distribution();
X	}
X
X	if (pre_checks())
X		exit(1);
X	edit_article();
X	post_checks();
X
X	save_article();
X	post_article();
X}
X
X/*
X * Find out the topic of interest.
X */
Xget_newsgroup()
X{
X	int n;
X	long i;
X	char canpost;
X
X	printf("Newsgroups (enter one at a time, end with a blank line):\n");
X	printf("For a list of newsgroups, type ?\n");
X	n = 0;
X	newsgroups[0] = '\0';
X
X	for(;;) {
X		getpr("> ", buf);
X		if (buf[0] == '\0')
X			if (n == 0)
X				return FALSE;
X			else
X				return TRUE;
X		if (buf[0] == '?'){
X			/* too lazy to do it myself.... */
X			printf("These are the currently active groups:\n");
X			sprintf(buf,"exec cat %s/newsgroups", LIB);
X			system(buf);
X			continue;
X		}
X		if (valid_ng(buf, &i, &i, &canpost)) {
X			if (n++ != 0)
X				strcat(newsgroups, ",");
X			strcat(newsgroups, buf);
X		} else {
X			if (canpost == 'n')
X				printf("You are not allowed to post to %s\n",
X					buf);
X			else
X				printf("%s is not a valid newsgroup.\n", buf);
X		}
X	}
X}
X
X/*
X * Find out how widely the author wants the message distributed.
X */
Xget_distribution()
X{
X	register int i;
X	register char *r;
X	char def[BUFLEN];
X	char *index();
X
X	strcpy(def, newsgroups);
X	r = index(def, '.');
X	if (r) {
X		*r = '\0';
X		if (strcmp(def, "net") == 0)
X			strcpy(def, "world");
X	} else
X		strcpy(def, "local");
X
X	if (strcmp(def,"to") == 0) {
X		distribution[0] = '\0';
X		return;		/* He's probably testing something */
X	}
X	if (ngmatch("net.test", newsgroups))
X		strcpy(def, "local");
X	for(;;) {
X		sprintf(buf, "Distribution (default='%s', '?' for help) : ", def);
X		getpr(buf, distribution);
X		if (distribution[0] == '\0')
X			strcpy(distribution, def);
X
X		/* Did the user ask for help? */
X		if (distribution[0] == '?') {
X			printf("How widely should your article be distributed?\n");
X			for (i=0; distr[i].abbr[0]; i++)
X				printf("%s\t%s\n", distr[i].abbr, distr[i].descr);
X			continue;
X		}
X
X		/* Check that it's a proper distribution */
X		for (i=0; distr[i].abbr[0]; i++) {
X			if (strncmp(distr[i].abbr, distribution, sizeof(distr[0].abbr)) == 0) {
X				/* Found a match. Do any special rewriting. */
X				if (strcmp(distribution, "world") == 0)
X					strcpy(distribution, "net");
X				return;
X			}
X		}
X
X		printf("Type ? for help.\n");
X	}
X}
X
X/*
X * Do sanity checks before the author types in the message.
X */
Xpre_checks()
X{
X	check_mod();
X	if (recording(newsgroups))
X		return 1;
X	return 0;
X}
X
X/*
X * Check to see if the newsgroup is moderated.
X */
Xcheck_mod()
X{
X	register FILE *fd;
X	char ng[64], mod[BUFLEN];
X
X	sprintf(buf, "%s/%s", LIB, "moderators");
X	fd = xfopen(buf, "r");
X
X	while (!feof(fd)) {
X		if (fgets(buf, sizeof buf, fd) == NULL) {
X			fclose(fd);
X			return;
X		}
X		twosplit(buf, ng, mod);
X		if (ngmatch(newsgroups, ng)) {
X			strcpy(moderator, mod);
X			ismod = 1;
X			return;
X		}
X	}
X}
X
X/*
X * Set up the temp file with headers.
X */
Xedit_article()
X{
X	FILE *tf, *of;
X	char *editor;
X	char *endflag = "";
X	char *p;
X	char *getenv();
X	struct stat stbuf;
X
X	editor = getenv("EDITOR");
X	strcpy(tempfname, "/tmp/postXXXXXX");
X	mktemp(tempfname);
X
X	/* insert a header */
X	tf = xfopen(tempfname, "w");
X	fprintf(tf, "Subject: %s\n", subject);
X	fprintf(tf, "Newsgroups: %s\n", newsgroups);
X	if (distribution[0] != '\0')
X		fprintf(tf, "Distribution: %s\n", distribution);
X	if (ismod)
X		fprintf(tf, "To: %s\n", moderator);
X
X	if (references[0] != '\0') {
X		fprintf(tf, "References: %s\n\n", references);
X
X		of = xfopen(original, "r");
X		while (fgets(buf, BUFSIZ, of) != NULL)
X			if (buf[0] == '\n')	/* skip headers */
X				break;
X		while (fgets(buf, BUFSIZ, of) != NULL)
X			fprintf(tf, "> %s", buf);
X		fclose(of);
X	}
X
X	fprintf(tf, "\n*** REPLACE THIS LINE WITH YOUR MESSAGE ***\n");
X	fflush(tf);
X	fstat(fileno(tf), &stbuf);
X	fmodtime = stbuf.st_mtime;
X	fclose(tf);
X
X	/* edit the file */
X	if (editor == NULL)
X		editor = DFTEDITOR;
X
X	p = editor + strlen(editor) - 2;
X	if (strcmp(p, "vi") == 0 && references[0] == '\0')
X		endflag = "+";
X
X	sprintf(buf, "exec %s %s %s", editor, endflag, tempfname);
X
X	system(buf);
X}
X
X/*
X * Do sanity checks after the author has typed in the message.
X */
Xpost_checks()
X{
X	char group[BUFLEN];
X	char *c;
X	struct stat stbuf;
X
X	if (stat(tempfname, &stbuf) < 0) {
X		printf("File deleted - no message posted.\n");
X		unlink(tempfname);
X		exit(1);
X	}
X
X	if (stbuf.st_mtime == fmodtime || stbuf.st_size < 5) {
X		printf("File not modified - no message posted.\n");
X		unlink(tempfname);
X		exit(1);
X	}
X
X	/* Sanity checks for certain newsgroups */
X	if (ngmatch(newsgroups, "all.wanted") && ngmatch(distribution,"net,na,usa,att,btl")) {
X		printf("Is your message something that might go in your local\n");
X		printf("newspaper, for example a used car ad, or an apartment\n");
X		printf("for rent? ");
X		if (askyes("","")) {
X			printf("It's pointless to distribute your article widely, since\n");
X			printf("people more than a hundred miles away won't be interested.\n");
X			printf("Please use a more restricted distribution.\n");
X			get_distribution();
X			modify_article(tempfname,"Distribution: ",distribution,"replace");
X		}
X	}
X
X	if (ngmatch(newsgroups, "all.jokes")) {
X		if (askyes("Could this be offensive to anyone? ","")) {
X			getpr("Whom might it offend? ", group);
X			sprintf(buf," - offensive to %s (ROT13)",group);
X			modify_article(tempfname, "Subject: ", buf, "append");
X			encode(tempfname);
X		}
X	}
X
X	if (ngmatch(newsgroups, "net.general")) {
X		c = newsgroups;
X		while (*c != ',' && *c)
X			++c;
X		if (*c == ',') {
X			printf("Everybody reads net.general, so it doesn't make sense to\n");
X			printf("post to newsgroups in addition to net.general.	If your\n");
X			printf("article belongs in one of these other newsgroups, then you\n");
X			printf("should not post to net.general.	If it is important enough\n");
X			printf("for net.general, then you shouldn't post it in other places\n");
X			printf("as well.	Please reenter the newsgroups.\n");
X			get_newsgroup();
X			modify_article(tempfname,"Newsgroups: ",newsgroups,"replace");
X		}
X		else {
X			printf("net.general is for important announcements.\n");
X			printf("It is not for items for which you couldn't think\n");
X			printf("of a better place - those belong in net.misc.\n");
X			if (!askyes("Are you sure your message belongs in net.general? ","")) {
X				get_newsgroup();
X				modify_article(tempfname, "Newsgroups: ", newsgroups, "replace");
X			}
X		}
X	}
X}
X
X/*
X * Save a copy of the article in the users NEWSARCHIVE directory.
X */
Xsave_article()
X{
X	FILE *in, *out;
X	int c;
X	time_t timenow, time();
X	char *today, *ctime();
X
X
X	in = xfopen(tempfname, "r");
X	out = xfopen(ccname, "a");
X	timenow = time((time_t)0);
X	today = ctime(&timenow);
X	fprintf(out,"From postnews %s",today);
X	while ((c=getc(in)) != EOF)
X		putc(c, out);
X	putc('\n', out);
X	fclose(in);
X	fclose(out);
X}
X
X/*
X * Post the article to the net.
X */
Xpost_article()
X{
X	int status;
X
X	printf("%s article...\n", ismod ? "Mailing" : "Posting" );
X	if (ismod)
X		sprintf(buf, "exec %s -t < %s", MAILPARSER, tempfname);
X	else
X		sprintf(buf, "exec %s/%s -h < %s", LIB, "inews", tempfname);
X	status = system(buf);
X
X	if (status)
X		printf("Article not %s - exit status %d\n", ismod ? "mailed" : "posted", status);
X	else
X		printf("Article %s successfully.\n", ismod ? "mailed" : "posted" );
X
X	if (ccname[0])
X		printf("A copy has been saved in %s\n", ccname);
X
X	unlink(tempfname);
X}
X
X/*
X * Initialization.
X */
Xinit()
X{
X	FILE *fd;
X	register char *p;
X	int i;
X	char *getenv();
X
X	references[0] = '\0';
X	distribution[0] = '\0';
X
X	p = getenv("HOME");
X	if (p == NULL) {
X		p = getenv("LOGDIR");
X		if (p == NULL) {
X			struct passwd *pw;
X			pw = getpwuid(getuid());
X			if (pw == NULL) {
X				fprintf(stderr,"You're not in /etc/passwd\n");
X				exit(1);
X			}
X			p = pw->pw_dir;
X		}
X	}
X	strcpy(homedir, p);
X
X
X	p = getenv(ARCHIVES_DEF);
X	if (p == NULL)
X		sprintf(ccname, "%s/author_copy", homedir);
X	else
X		strcpy(ccname, p);
X
X	pathinit();
X	sprintf(buf, "%s/%s", LIB, "distributions");
X	fd = xfopen(buf, "r");
X	for (i=0; !feof(fd); i++) {
X		if (fgets(buf, sizeof buf, fd) == NULL)
X			break;
X		twosplit(buf, distr[i].abbr,distr[i].descr);
X	}
X	fclose(fd);
X}
X
X/*
X * Split a line of the form
X *		text whitespace text
X * into two strings.	Also trim off any trailing newline.
X * This is destructive on src.
X */
Xtwosplit(src, dest1, dest2)
Xchar *src, *dest1, *dest2;
X{
X	register char *p;
X
X	nstrip(src);
X	for (p=src; isalnum(*p) || ispunct(*p); p++)
X		;
X	*p++ = 0;
X	for ( ; isspace(*p); p++)
X		;
X	strcpy(dest1, src);
X	strcpy(dest2, p);
X}
X
X/*
X * Get a yes or no answer to a question.	A default may be used.
X */
Xaskyes(msg, def)
Xchar *msg, *def;
X{
X
X	printf("%s", msg);
X	buf[0] = 0;
X	gets(buf);
X	switch(buf[0]) {
X	case 'y':
X	case 'Y':
X		return TRUE;
X	case 'n':
X	case 'N':
X		return FALSE;
X	case '\0':
X		switch(*def) {
X		case 'y':
X		case 'Y':
X			return TRUE;
X		case 'n':
X		case 'N':
X			return FALSE;
X		}
X	default:
X		printf("Please answer yes or no.\n");
X		return askyes(msg, def);
X	}
X}
X
X/*
X * Get a character string into buf, using prompt msg.
X */
Xgetpr(msg, bfr)
Xchar *msg, *bfr;
X{
X	static int numeof = 0;
X	printf("%s", msg);
X	gets(bfr);
X	nstrip(bfr);
X	if (feof(stdin)) {
X		if (numeof++ > 3) {
X			fprintf(stderr,"Too many EOFs\n");
X			exit(1);
X		}
X		clearerr(stdin);
X	}
X}
X
Xbyebye(mesg)
Xchar *mesg;
X{
X	printf("%s\n", mesg);
X	exit(1);
X}
X
X/*
X * make a modification to the header of an article
X *
X *	 fname -- name of article
X *	 field -- header field to modify
X *	 line	-- modification line
X *	 how	 -- 'a' or 'A' to append line to existing header line
X *			anything else to replace existing line
X *
X * example:
X *	 modify_article("/tmp/article" , "Subject: " , "new subject" , "replace");
X *
X *
X */
Xmodify_article(fname, field, line, how)
Xchar *fname, *field, *line, *how;
X{
X	FILE *fpart, *fptmp;
X	char *temp2fname = "/tmp/postXXXXXX";
X	int i;
X
X	mktemp(temp2fname);
X
X	fptmp = xfopen(temp2fname, "w");
X	fpart = xfopen(fname, "r");
X
X	i = strlen(field);
X	while (fgets(buf, BUFLEN, fpart) != NULL) {
X		if (strncmp(field, buf, i) == 0) {
X			nstrip(buf);
X			if (*how=='a' || *how=='A')
X				/* append to current field */
X				sprintf(buf, "%s%s\n", buf, line);
X			else
X				/* replace current field */
X				sprintf(buf, "%s%s\n", field, line);
X		}
X		fputs(buf, fptmp);
X	}
X
X	fclose(fpart);
X	fclose(fptmp);
X
X	fptmp = xfopen(temp2fname, "r");
X	fpart = xfopen(fname, "w");
X
X	i = strlen(field);
X	while (fgets(buf,BUFLEN,fptmp) != NULL)
X		fputs(buf, fpart);
X
X	fclose(fpart);
X	fclose(fptmp);
X	unlink(temp2fname);
X}
X
X
X/* verify that newsgroup exists, and get number of entries */
Xvalid_ng(ng, maxart, minart, canpost)
Xchar *ng;
Xlong *maxart, *minart;
Xchar *canpost;
X{
X	char ng_check[BUFLEN], ng_read[BUFLEN];
X	FILE *fp;
X
X	fp = xfopen(ACTIVE, "r");
X	while (fgets(ng_read, BUFLEN, fp) != NULL) {
X		sscanf(ng_read, "%s %ld %ld %c", ng_check, maxart, minart, canpost);
X		if (strcmp(ng_check, ng) == 0) {
X			fclose(fp);
X			if (*canpost == 'y')
X				return TRUE;
X			else
X				return FALSE;
X		}
X	}
X	*canpost = 'i';
X	*maxart = 0;
X	*minart = 0;
X	fclose(fp);
X	return FALSE;
X}
X
X/* get the line specified by field from an article */
Xarticle_line(article, field, line)
Xchar *article, *field, *line;
X{
X	FILE *fp;
X	char *c;
X	int i = strlen(field);
X
X	fp = xfopen(article,"r");
X	while ((c=fgets(line,BUFLEN,fp)) != NULL && strncmp(field,line,i) != 0)
X		;
X	fclose(fp);
X	if (c != NULL) {
X		nstrip(line);
X		return TRUE;
X	} else {
X		line[0] = '\0';
X		return FALSE;
X	}
X}
X
X
X/* get the header information for a followup article */
Xfollowup(baseart)
Xregister char *baseart;
X{
X	/* subject */
X	if (article_line(baseart, "Subject: ", buf))
X		sprintf(subject, "Re: %s", buf+9);
X	else
X		strcpy(subject, "Re: orphan response");
X
X	/* newsgroup */
X	if (article_line(baseart, "Newsgroups: ", buf))
X		strcpy(newsgroups, buf+12);
X	if (ngmatch(newsgroups, "net.general"))
X		strcpy(newsgroups,"net.followup");
X
X	/* distribution */
X	if (article_line(baseart, "Distribution: ", buf))
X		strcpy(distribution, buf+14);
X
X	/* references */
X	if (article_line(baseart, "References: ", buf)) {
X		strcpy(references, buf+12);
X		strcat(references, " ");
X	}
X	if (article_line(baseart, "Message-ID: ", buf))
X		strcat(references, buf+12);
X}
X
Xencode(article)
Xchar *article;
X{
X	FILE *fpart, *fphead, *fpcoded;
X	char *headerfile = "/tmp/pheadXXXXXX";
X	char *codedfile = "/tmp/pcodeXXXXXX";
X
X	mktemp(headerfile);
X	mktemp(codedfile);
X
X	fpart = xfopen(article, "r");
X
X	/* place article header in "headerfile" file */
X	fphead = xfopen(headerfile, "w");
X	while (fgets(buf, BUFLEN, fpart) != NULL) {
X		fputs(buf, fphead);
X		if (buf[0] == '\n')
X			break;
X	}
X	fclose(fphead);
X
X	/* place article body in "codedfile" file */
X	fpcoded = xfopen(codedfile, "w");
X	while (fgets(buf, BUFLEN, fpart) != NULL)
X		fputs(buf, fpcoded);
X	fclose(fpcoded);
X	fclose(fpart);
X
X	/* encode body and put back together with header */
X	unlink(article);
X	link(headerfile, article);
X	unlink(headerfile);
X
X	sprintf(buf,"exec %s/%s 13 < %s >> %s\n", LIB, "caesar", codedfile, article);
X	printf("Encoding article -- please stand by\n");
X	if (system(buf)) {
X		printf("encoding failed");
X		exit(2);
X	}
X	unlink(codedfile);
X}
X
X
X/*
X * Print a recorded message warning the poor luser what he is doing
X * and demand that he understands it before proceeding.  Only do
X * this for newsgroups listed in LIBDIR/recording.
X */
Xrecording(ngrps)
Xchar *ngrps;
X{
X	char recbuf[BUFLEN];
X	FILE *fd;
X	char nglist[BUFLEN], fname[BUFLEN];
X	int  c, n, yes;
X
X	sprintf(recbuf, "%s/%s", LIB, "recording");
X	fd = fopen(recbuf, "r");
X	if (fd == NULL)
X		return 0;
X	while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) {
X		sscanf(recbuf, "%s %s", nglist, fname);
X		if (ngmatch(ngrps, nglist)) {
X			fclose(fd);
X			if (fname[0] == '/')
X				strcpy(recbuf, fname);
X			else
X				sprintf(recbuf, "%s/%s", LIB, fname);
X			fd = fopen(recbuf, "r");
X			if (fd == NULL)
X				return 0;
X			while ((c = getc(fd)) != EOF)
X				putc(c, stderr);
X			fprintf(stderr, "Do you understand this?  Hit <return> to proceed, <BREAK> to abort: ");
X			n = read(2, recbuf, 100);
X			c = recbuf[0];
X			yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0);
X			if (n <= 0 || !yes)
X				return -1;
X		}
X	}
X	return 0;
X}
X
Xxxit(i)
X{
X	exit(i);
X}
*-*-END-of-src/postnews.c-*-*
exit