/*
 * digest - process ARPANET digests
 *
 * Alan Hastings	9/5/82
 *
 * digest(ifile, ofile, header)
 * FILE *ifile, *ofile;
 * struct header *header;
 *
 * returns:	TRUE	EOF reached, exit from readnews.
 *		FALSE	normal exit, continue reading news.
 */

#include "rparams.h"

struct art {
	long	a_hdr;
	long	a_bod;
	int	a_blen;
	int	a_hlen;
};

#define	loop		for(;;)
#define	getnum(p, n)	for (n=0; *p>='0' && *p<='9'; p++) n = n*10 + *p-'0'
#define	errchk(p)	if (*p) goto badopt

#define	MAXART		128

struct art	*arts;
int		lastart;

digest(ifp, ofp, h)
FILE *ifp, *ofp;
struct hbuf *h;
{
	register int	n, curart;
	struct art	artbuf[MAXART];
	int		printh, eod, nomore;
	char		cbuf[BUFLEN], *cmd;

	arts = artbuf;
	printh = TRUE;
	nomore = eod = FALSE;
	curart = 1;

	if (dscan(ifp))
		return(FALSE);

	dprint(0, ifp, ofp);

	loop {
		if (nomore) break;
		if (curart < 1) {
			curart = 1;
			eod = nomore = FALSE;
		}
		if (curart > lastart) curart = lastart;
		if (eod) nomore = TRUE;
		if (printh && !nomore)
			(void) dhprint(curart, ifp, ofp);
	getcmd:
		loop {
			sigtrap = FALSE;
			fprintf(ofp, "Digest article %d of %d ", curart, lastart);
			if (curart==lastart && nomore)
				fprintf(ofp, "Last digest article ");
			fprintf(ofp, "(%d lines) More? [%s] ",
				arts[curart].a_blen, nomore?"snq":"ynq");
			(void) fflush(ofp);
			cmd = cbuf;
			if (fgets(cmd, BUFLEN, stdin))
				break;
			if (!sigtrap)
				return(TRUE);
			putc('\n', ofp);
		}
		nstrip(cmd);
		while (*cmd==' ' || *cmd=='\t')
			cmd++;
		printh = TRUE;

		switch (*cmd++) {
		case '#':
			fprintf(ofp, "%d articles in digest\n", lastart);
			(void) fflush(ofp);
			printh = FALSE;
			break;

		case '$':
			curart = lastart;
			break;

		case '!':
			fwait(fsubr(ushell, cmd, (char *)NULL));
			fprintf(ofp, "!\n");
			printh = FALSE;
			break;

		case '\0':
			if (nomore) {
				putc('\n', ofp);
				return(FALSE);
			}
			cmd--;
		case 'y':
		case 'p':
			errchk(cmd);
			dprint(curart++, ifp, ofp);
			if (curart > lastart)
				eod = TRUE;
			break;

		case 'n':
			errchk(cmd);
			if (++curart > lastart) {
				putc('\n', ofp);
				return(FALSE);
			}
			break;

		case '+':
			getnum(cmd, n);
			errchk(cmd);
			if (nomore) {
				putc('\n', ofp);
				return(FALSE);
			}
			if (n)	curart += n;
			else {
				curart += 1;
				if (curart > lastart)
					eod = TRUE;
			}
			break;

		case '-':
			getnum(cmd, n);
			errchk(cmd);
			eod = nomore = FALSE;
			curart -= (n) ? n : 1;
			break;

		case '0': case '1': case '2': case '3': case '4':
		case '5': case '6': case '7': case '8': case '9':
			cmd--;
			getnum(cmd, n);
			errchk(cmd);
			curart = n;
			eod = nomore = FALSE;
			break;

		case 'q':
		case 'x':
			putc('\n', ofp);
			return(FALSE);

		case '?':
			fprintf(ofp, "\nDigester options:\n\n");
			fprintf(ofp, "y\tyes, print article.\n");
			fprintf(ofp, "n\tno, go to next article.\n");
			fprintf(ofp, "q\texit from digester.\n");
			fprintf(ofp, "h\tprint article header.\n");
			fprintf(ofp, "s file\tsave article in file.\n");
			fprintf(ofp, "t\ttable of contents.\n");
			fprintf(ofp, "+[n]\tforward n articles (1).\n");
			fprintf(ofp, "-[n]\tback n articles (1).\n");
			fprintf(ofp, "\nh and s may be followed by '-'\n");
			(void) fflush(ofp);
			break;

		case 'h':
			n = curart;
			if (*cmd=='-') {
				cmd++;
				if (n > 1) n--;
			}
			errchk(cmd);
			(void) dhprint(n, ifp, ofp);
			nomore = printh = FALSE;
			if (n!=curart)
				putc('\n', ofp);
			break;

		case 's':
		case 'w':
			n = curart;
			if (*cmd=='-') {
				cmd++;
				if (n > 1) n--;
			}
			while (*cmd==' ' || *cmd=='\t')
				cmd++;
			dsaveart(n, ifp, ofp, cmd);
			nomore = printh = FALSE;
			if (n!=curart)
				putc('\n', ofp);
			break;

		case 'H':
			errchk(cmd);
			hprint(h, !cflag, ofp, 1);
			eod = nomore = FALSE;
			break;

		case 'T':
		case 't':
			errchk(cmd);
			if (cmd[-1]=='T')
				hprint(h, !cflag, ofp, 0);
			dprint(0, ifp, ofp);
			eod = nomore = FALSE;
			break;

		default:
	badopt:
			if (!nomore)
				fprintf(ofp, "y (yes), n (no), ");
			fprintf(ofp, "q (quit), s file (save), h (header), t (table of contents)\n");
			fprintf(ofp, "? for help\n");
			goto getcmd;
		}
	}
	putc('\n', ofp);
	return(FALSE);
}

dscan(ifp)
register FILE *ifp;
{
	char		scanbuf[BUFLEN];
	register int	n, len;
	register char	*s;
	register long	pos;
	short		wasblank;

	n = len = 0;
	wasblank = FALSE;
	s = scanbuf;
	arts[0].a_bod = arts[1].a_hdr = ftell(ifp);
	arts[0].a_hdr = 0L;
	arts[1].a_bod = -1L;

	loop {
		if (sigtrap)
			return(TRUE);
		pos = ftell(ifp);
		if (fgets(s, BUFLEN, ifp)==NULL)
			*s = '\0';
		if (wasblank && isheader(s)) {
			long lastpos;
			short isblank;
			short nhlines;
			arts[n++].a_blen = len;
			len = 0;
			nhlines = 0;
			arts[n].a_hdr = pos;
			isblank = FALSE;
			do {
				lastpos = pos;
				wasblank = isblank;
				nhlines++;
				pos = ftell(ifp);
				if (fgets(s, BUFLEN, ifp)==NULL)
					*s = '\0';
				else
					len++;
				isblank = (*s=='\n') ? TRUE : FALSE;
				if (isblank && nhlines==1)
					/* one liner--not a header */
					break;
			} while ((isblank && !wasblank) || isheader(s));
			if ((!isblank && !wasblank) || nhlines < 2) {
				/* oops! not a header... back off */
				arts[n].a_hdr = arts[n-1].a_bod;
				len += arts[--n].a_blen;
			} else {
				if (wasblank)
					pos = lastpos;
				arts[n].a_hlen = len;
				arts[n].a_bod = arts[n+1].a_hdr = pos;
				arts[n+1].a_bod = -1L;
				arts[n+1].a_hlen = 3;	/* average header len */
				len = 0;
			}
		}
		if (*s=='\0')
			break;
		wasblank = (*s=='\n') ? TRUE : FALSE;
		len++;
	}
	arts[n].a_blen = len;
	arts[n+1].a_hdr = pos;
	lastart = n;
	return(FALSE);
}

dhprint(art, ifp, ofp)
register int art;
register FILE *ifp, *ofp;
{
	register char	c;
	register long	pos = arts[art].a_hdr;
	register long	epos = arts[art].a_bod;
	register int	nlines = 1;

	putc('\n', ofp);
	fseek(ifp, pos, 0);
	while (pos++ < epos && !sigtrap) {
		if ((c = getc(ifp))=='\n')
			nlines++;
		putc(c, ofp);
	}
	(void) fflush(ofp);
	sigtrap = FALSE;
	return(nlines);
}

dprint(art, ifp, ofp)
int art;
FILE *ifp, *ofp;
{
#ifdef	PAGE
	register int	cnt;
	FILE		*pfp, *popen();

	if (art && arts[art].a_blen > 23-arts[art+1].a_hlen && *PAGER) {
		if (!index(PAGER, FMETA)) {
			if ((pfp = popen(PAGER, "w"))==NULL)
				(void) dprinta(art, ifp, ofp);
			else {
				cnt = dprinta(art, ifp, pfp) % 23;
				if (cnt > 23-arts[art+1].a_hlen)
					while (cnt++ < 24)
						putc('\n', pfp);
				(void) pclose(pfp);
			}
		} else
			pout(ofp);
	} else
#endif	PAGE
		(void) dprinta(art, ifp, ofp);
}

dprinta(art, ifp, ofp)
int art;
register FILE *ifp, *ofp;
{
	register char	c;
	register long	pos = arts[art].a_bod;
	register long	epos = arts[art+1].a_hdr;
	register int	nlines = 0;

	fseek(ifp, pos, 0);
	while (pos++ < epos && !sigtrap) {
		if ((c = getc(ifp))=='\n')
			nlines++;
		putc(c, ofp);
	}
	(void) fflush(ofp);
	sigtrap = FALSE;
	return(nlines);
}

dsaveart(art, ifp, ofp, name)
int art;
register FILE *ifp, *ofp;
register char *name;
{
	register FILE	*nfp;
	char		fname[BUFLEN];
	char		*strcat(), *strcpy(), *getenv();
	register char	*nb;

	while (*name==' ' || *name=='\t')
		name++;

	if (*name=='|') {
		fprintf(ofp, "don't know how to pipe yet.\n");
		(void) fflush(ofp);
		return;
	} else if (*name=='/')
		(void) strcpy(fname, name);
	else {
		if (nb = getenv("NEWSBOX"))
			(void) strcpy(fname, nb);
		else
			(void) strcpy(fname, userhome);
		(void) strcat(fname, "/");
		(void) strcat(fname, name);
	}

	fprintf(ofp, "Save digest article %d in \"%s\"", art, fname);
	(void) fflush(ofp);
	if ((nfp = fopen(fname, "a"))!=NULL) {
		int ln;
		ln = dhprint(art, ifp, nfp);
		ln += dprinta(art, ifp, nfp);
		fprintf(ofp, " [Appended] %d lines\n", ln);
		(void) fclose(nfp);
	} else
		fprintf(ofp, " cannot append to.\n");
}

isheader(s)
register char *s;
{
	if (isupper(*s) || islower(*s)) {
		while (*s && *s!=':' && !isspace(*s))
			s++;
		if (*s==':' && *++s==' ')
			return(TRUE);
	}
	return(FALSE);
}



