[comp.sources.amiga] v91i024: VN res1.1 - vn news reader, Part04/06

amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (02/27/91)

Submitted-by: eyal@echo.canberra.edu.au (Eyal Lebedinsky)
Posting-number: Volume 91, Issue 024
Archive-name: news/vn-res1.1/part04

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 4 (of 6)."
# Contents:  reader.c session.c
# Wrapped by tadguy@ab20 on Tue Feb 26 19:28:45 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'reader.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader.c'\"
else
echo shar: Extracting \"'reader.c'\" \(18716 characters\)
sed "s/^X//" >'reader.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** reader.c - article reading interface - "more" like.
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <ctype.h>
X#include <time.h>
X#include "tty.h"
X#include "config.h"
X#include "tune.h"
X#include "head.h"
X#include "reader.h"
X#include "brk.h"
X#include "node.h"
X#include "page.h"
X#include "vn.h"
X
X#ifdef amiga
X#define system(a)	Execute(a, 0, 0)
Xextern char pr_buf[];
Xextern ttputc ();
X#endif
X
X#define PERTAB 8	/* tab expansion factor */
X#define BACKTRACK 24
X
Xextern char *Printer,*Editor,*Mailer,*Poster,*Orgdir,*Savefile,*Savedir,*Ccfile;
Xextern int L_allow;
Xextern int C_allow;
Xextern int Rot;
Xextern int Headflag;
Xextern int Digest;
Xextern int More;
Xextern char *No_msg;
Xextern char *Roton_msg;
Xextern char *Rotoff_msg;
Xextern char *Hdon_msg;
Xextern char *Hdoff_msg;
Xextern char *Def_smode;
X
Xextern PAGE Page;
X
Xextern int (*Massage)();
Xextern int (*Postfunc)();
Xextern int (*Mailfunc)();
Xextern int (*Savemode)();
Xextern int (*Hookfunc)();
X
Xextern char Cxrtoi[], Cxitor[];
X
Xstatic FILE *Fpread;
Xstatic char *Fname;
Xstatic char *Lookahead;
Xstatic int Rlines;
Xstatic int Hlines;
Xstatic long Rew_pos;
X
Xstatic void save2_article (), followup (), printr (), searcher (), mail ();
Xstatic saver (), edcopy (), rot_line (), do_out (), rerrmsg ();
Xstatic char getpgch (), *rprompt ();
X
X
X/*
X	readfile presents article:
X		fn = name of article.
X		sn - name of next article, NULL if last.
X		pages - pages to advance on return, if applicable
X	returns 0 for "continue", <0 for "quit"
X
X	calls sig_set(BRK_READ / BRK_RFIN) around reading article.
X*/
Xreadfile (fn,sn,pages)
Xchar *fn;
Xchar *sn;
Xint *pages;
X{
X	ARTHEADER hdr;
X	FILE *fopen();
X	int lines,percent;
X	int i;
X	int top, bottom;
X	int step;
X	char c,  buf[RECLEN];
X	char lasave[RECLEN];
X	char pstr[24], dgname[48];
X	char getpgch(), *index(), *dige_extract(), *tgetstr();
X	char *any;
X	FILE *vns_aopen();
X	long ftell();
X
X	Fname = fn;
X	*pages = 0;
X	step = FALSE;	/* Boolean; to indicate user input a <RET> (PG_STEP) */
X
X	term_set(ERASE);
X	sig_set(BRK_READ,&Fpread);
X
X	any = "any key to continue .... ";
X
X	if (Digest)
X	{
X		lines = atoi(Fname);
X		if ((Fname = dige_extract(dgname,lines,&hdr,&Rew_pos)) == NULL)
X		{
X			rerrmsg("couldn't extract article %d from digest",lines);
X#ifdef amiga
X			sprintf(pr_buf,any);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf(any);
X#endif
X			getnoctl();
X			sig_set(BRK_RFIN);
X			return (0);
X		}
X		if ((Fpread = fopen(Fname,"r")) == NULL)
X		{
X			rerrmsg("couldn't open %s",Fname);
X#ifdef amiga
X			sprintf(pr_buf,any);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf(any);
X#endif
X			getnoctl();
X			sig_set(BRK_RFIN);
X			return (0);
X		}
X  		fseek(Fpread,Rew_pos,0);
X	}
X	else
X	{
X		if ((Fpread = vns_aopen(atoi(Fname),&hdr)) == NULL)
X		{
X			rerrmsg("couldn't open article %s",Fname);
X#ifdef amiga
X			sprintf(pr_buf,any);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf(any);
X#endif
X			getnoctl();
X			sig_set(BRK_RFIN);
X			return (0);
X		}
X		Rew_pos = ftell(Fpread);
X	}
X
X	Hlines = hdr.hlines;
X#ifdef amiga
X	sprintf (pr_buf,ANFORM,Fname,Cxrtoi[PG_HELP]);
X	tputs(pr_buf,1,ttputc);
X#else
X	printf (ANFORM,Fname,Cxrtoi[PG_HELP]);
X#endif
X
X	lines = 0;
X
X	if (Headflag)
X	{
X		rewind(Fpread);
X		Rlines = 0;
X	}
X	else
X	{
X		/* use do_out to guard against control sequences */
X		Rlines = Hlines;
X		for (i=0; i < hdr.show_num; ++i)
X			lines += do_out((hdr.show)[i],L_allow-lines);
X		lines += do_out("",L_allow-lines);
X	}
X
X	/* will return out of outer while loop */
X	Lookahead = NULL;
X	while (1)
X	{
X		/*
X		** lines counts folded lines from do_out.
X		** globals Hlines and Rlines refer to records.
X		** If Lookahead is null after this loop, we've
X		** hit EOF.
X		*/
X		if (Lookahead != NULL && More && !step)
X		{
X			char *looktmp;
X
X			/*
X			** Save Lookahead because `do_out' nukes it.
X			** Perhaps we could just use `printf' here
X			** but for now we'll play it safe. - GKE 12/26/87
X			*/
X			looktmp = Lookahead;
X			term_set(ERASE);
X			/* 
X			** The following presents the last line of the
X			** previous page in reversed video, as the first line
X			** of the current page, `rn'-stylee.  Since `rn'
X			** uses an option to enable/disable this, remove the
X			** two `term_set's if not to your liking.
X			*/
X			term_set(ONREVERSE);
X			do_out(lasave,1);
X			term_set(OFFREVERSE);
X			Lookahead = looktmp;
X		}
X		lines += do_out(Lookahead,L_allow-lines);
X		while (1)
X		{
X			if (Lookahead == NULL)
X			{
X				if (fgets(buf,RECLEN-1,Fpread) == NULL)
X					break;
X				Lookahead = buf;
X				if (Rot != 0 && Rlines >= Hlines)
X					rot_line(buf);
X				++Rlines;
X			}
X			if (lines >= L_allow)
X				break;
X			if (More)
X				strcpy(lasave,Lookahead);
X			lines += do_out(Lookahead,L_allow-lines);
X		}
X
X		if (Lookahead != NULL)
X		{
X			/*
X			** calculation is truncated rather than rounded,
X			** so we shouldn't get "100%".  Subtract 2 for
X			** 1 line lookahead and empty line at beginning
X			** of article.
X			*/
X			if (Headflag)
X			{
X				top = (Rlines-2);
X				bottom = hdr.lines + Hlines;
X			}
X			else
X			{
X				top = (Rlines-Hlines-2);
X				bottom = hdr.lines;
X			}
X			/*
X			** protect against division by zero -
X			** shouldn't actually come up zero at this
X			** point if vns_aopen is sane. 999 will let user
X			** know the percentage is obviously wrong.
X			*/
X			if (bottom != 0)
X				percent = (top*100L)/bottom;
X			else
X				percent = 999;
X			sprintf (pstr,PAGE_MID,percent);
X		}
X		else
X		{
X			if (sn == NULL)
X				strcpy (pstr,PAGE_END);
X			else
X			strcpy (pstr,PAGE_NEXT);
X		}
X		c = getpgch(pstr,&hdr);
X
X		/*
X			handle user input:
X			CAUTION!!  return cases must close Fpread.
X		*/
X		step = FALSE;
X		switch (c)
X		{
X		case PG_NEXT:
X			if (Digest)
X			{
X				fclose (Fpread);
X				unlink (Fname);
X			}
X			else
X				vns_aclose (Fpread);
X			sig_set(BRK_RFIN);
X			return (0);
X		case PG_FLIP:
X			*pages = 1;	/* fall through */
X		case PG_QUIT:
X			if (Digest)
X			{
X				fclose (Fpread);
X				unlink (Fname);
X			}
X			else
X				vns_aclose (Fpread);
X			sig_set(BRK_RFIN);
X			return (-1);
X		case PG_REWIND:
X			if (Headflag)
X			{
X				Rlines = 0;
X				rewind (Fpread);
X			}
X			else
X			{
X				fseek (Fpread,Rew_pos,0);
X				Rlines = Hlines;
X			}
X			Lookahead = NULL;
X			lines = 2 - RECBIAS;
X			break;
X		case PG_SEARCH:
X			searcher(buf);
X			lines = 2 - RECBIAS;
X			lines += do_out(buf,L_allow-lines);
X			break;
X		case PG_WIND:
X			fseek (Fpread,0L,2);
X			lines = 2 - RECBIAS;
X			Lookahead = NULL;
X			break;
X		case PG_STEP:
X			if (Lookahead == NULL)
X			{
X				if (Digest)
X				{
X					fclose (Fpread);
X					unlink (Fname);
X				}
X				else
X					vns_aclose (Fpread);
X				sig_set(BRK_RFIN);
X				return (0);
X			}
X			lines = L_allow - 1;
X			step = TRUE;	/* Temporarily disable paging */
X			break;
X		default:
X			if (Lookahead == NULL)
X			{
X				if (Digest)
X				{
X					fclose (Fpread);
X					unlink (Fname);
X				}
X				else
X					vns_aclose (Fpread);
X				sig_set(BRK_RFIN);
X				return (0);
X			}
X			lines = 2 - RECBIAS;
X			break;
X		}
X	}
X}
X
X/*
X	getpgch prints prompt and gets command from user
X	handles "mail", "save" and "followup" internally
X	as well as flag resets.
X*/
Xstatic char
Xgetpgch(prompt,hdr)
Xchar *prompt;
XARTHEADER *hdr;
X{
X	char c;
X	int ic;
X	int i;
X	char mbuf[RECLEN];
X
X	term_set (ONREVERSE);
X#ifdef amiga
X	sprintf(pr_buf,"%s\015",prompt);
X	tputs(pr_buf,1,ttputc);
X#else
X	printf("%s\015",prompt);
X#endif
X	term_set (OFFREVERSE);
X	while ((ic=getnoctl()) != EOF)
X	{
X		c = Cxitor[ic];
X		if (Hookfunc != NULL && (i = (*Hookfunc)(c,1,1,mbuf)) >= 0)
X		{
X			if (i == 0)
X			{
X				term_set (ZAP,0,PPR_MAX);
X#ifdef amiga
X				sprintf(pr_buf,"%s\n",mbuf);
X				tputs(pr_buf,1,ttputc);
X#else
X				printf("%s\n",mbuf);
X#endif
X			}
X			term_set (ONREVERSE);
X#ifdef amiga
X			sprintf(pr_buf,"%s\015",prompt);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf("%s\015",prompt);
X#endif
X			term_set (OFFREVERSE);
X			continue;
X		}
X		switch (c)
X		{
X		case SETROT:
X			term_set (ZAP,0,PPR_MAX);
X			if (Rot == 0)
X			{
X				Rot = 13;
X#ifdef amiga
X				sprintf (pr_buf,"%s\n",Roton_msg);
X				tputs(pr_buf,1,ttputc);
X#else
X				printf ("%s\n",Roton_msg);
X#endif
X			}
X			else
X			{
X				Rot = 0;
X#ifdef amiga
X				sprintf (pr_buf,"%s\n",Rotoff_msg);
X				tputs(pr_buf,1,ttputc);
X#else
X				printf ("%s\n",Rotoff_msg);
X#endif
X			}
X			if (Lookahead != NULL && Rlines > Hlines)
X				rot_line(Lookahead);
X			break;
X		case HEADTOG:
X			term_set (ZAP,0,PPR_MAX);
X			if (Headflag)
X			{
X				Headflag = FALSE;
X#ifdef amiga
X				sprintf (pr_buf,"%s\n",Hdoff_msg);
X				tputs(pr_buf,1,ttputc);
X#else
X				printf ("%s\n",Hdoff_msg);
X#endif
X			}
X			else
X			{
X				Headflag = TRUE;
X#ifdef amiga
X				sprintf (pr_buf,"%s\n",Hdon_msg);
X				tputs(pr_buf,1,ttputc);
X#else
X				printf ("%s\n",Hdon_msg);
X#endif
X			}
X			break;
X		case PG_HELP:
X			term_set (ZAP,0,PPR_MAX);
X			help_rd ();
X			break;
X		case PG_REPLY:
X			mail (hdr);
X			break;
X		case PG_FOLLOW:
X			followup (hdr);
X			break;
X		case SAVE:
X			saver ();
X			break;
X		case PRINT:
X			printr ();
X			break;
X		default:
X			term_set (ZAP,0,PPR_MAX);
X			return (c);
X		}
X
X		term_set (ONREVERSE);
X#ifdef amiga
X		sprintf(pr_buf,"%s\015",prompt);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("%s\015",prompt);
X#endif
X		term_set (OFFREVERSE);
X	}
X	term_set (ZAP,0,PPR_MAX);
X	return (c);
X}
X
X/*
X	save article.  Like its "session" counterpart, this loses storage
X	if the user specifies a new file, but it should not be significant
X*/
Xstatic
Xsaver ()
X{
X	char buf[RECLEN],msg[RECLEN],*str_store();
X
X	user_str (buf,"save file ? ",0,Savefile);
X	if (buf[0] != '\0' && buf[0] != '|')
X		Savefile = str_store(buf);
X	if (save_art(Fname,buf,msg) != 0)
X		rerrmsg(msg);
X	else {
X#ifdef amiga
X		sprintf(pr_buf,"%s\n",msg);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("%s\n",msg);
X#endif
X	}
X}
X
X/*
X	invoke editor on new temp file, mail using reply line,
X	possibly first allowing user to overide the reply (not INLETTER)
X*/
Xstatic
Xvoid
Xmail (hdr)
XARTHEADER *hdr;
X{
X	char *new, fn[L_tmpnam], cmd [RECLEN+60];
X	char *rprompt ();
X	int i;
X	FILE *fp, *fopen();
X
X	if (Massage != NULL)
X		(*Massage)(hdr);
X
X	if (hdr->mail_err != NULL)
X	{
X		rerrmsg(hdr->mail_err);
X		return;
X	}
X
X	tmpnam (fn);
X	if ((fp = fopen(fn,"w")) == NULL)
X	{
X		rerrmsg("can't open temp file, %s",fn);
X		return;
X	}
X
X	for (i = 0; i < hdr->mail_num; ++i)
X		fprintf(fp,"%s\n",(hdr->mail)[i]);
X	fprintf(fp,"\n");
X
X	fprintf(fp,"%s:\n",hdr->from);
X	edcopy (fp);
X	fclose (fp);
X
X	tty_set (SAVEMODE);
X
X	sprintf (cmd,"%s %s", Editor, fn);
X	chdir (Orgdir);
X	system (cmd);
X	vns_gset (Page.h.name);
X
X	new = rprompt ("still want to mail it ? ",cmd);
X	if (new != NULL && (*new == 'y' || *new == 'Y'))
X	{
X		if (Mailfunc == NULL)
X		{
X			sprintf (cmd, hdr->mailcmd, fn);
X			system (cmd);
X#ifdef amiga
X			sprintf (pr_buf,"given to mailer\n");
X			tputs(pr_buf,1,ttputc);
X#else
X			printf ("given to mailer\n");
X#endif
X		}
X		else
X			(*Mailfunc)(hdr,fn);
X	}
X	else {
X#ifdef amiga
X		sprintf (pr_buf,"not mailed\n");
X		tputs(pr_buf,1,ttputc);
X#else
X		printf ("not mailed\n");
X#endif
X	}
X
X	unlink (fn);
X
X	tty_set (RESTORE);
X	term_set (RESTART);
X}
X
X/*
X	post a followup article, invoking editor for user after creating
X	new temp file.  remove after posting.
X*/
Xstatic
Xvoid
Xfollowup (hdr)
XARTHEADER *hdr;
X{
X	char fn[L_tmpnam], *new, cmd [RECLEN], *rprompt();
X	int i;
X	FILE *f, *fopen();
X	char *rindex();
X
X	if (hdr->post_err != NULL)
X	{
X		rerrmsg(hdr->post_err);
X		return;
X	}
X
X	tmpnam (fn);
X	if ((f = fopen(fn,"w")) == NULL)
X	{
X		rerrmsg("can't open temp file, %s",fn);
X		return;
X	}
X
X	for (i=0; i < hdr->post_num; ++i)
X		fprintf(f,"%s\n",(hdr->post)[i]);
X	fprintf(f,"\n");
X
X	fprintf(f,"From article %s, by %s:\n", hdr->artid, hdr->from);
X		
X	edcopy (f);
X	fclose (f);
X	tty_set (SAVEMODE);
X	sprintf (cmd,"%s %s", Editor, fn);
X	chdir (Orgdir);
X	system (cmd);
X	vns_gset (Page.h.name);
X
X	new = rprompt("still want to post it ? ",cmd);
X	if (new != NULL && (*new == 'y' || *new == 'Y'))
X	{
X		if (Postfunc == NULL)
X		{
X			sprintf (cmd, hdr->postcmd, fn);
X			system (cmd);
X#ifdef amiga
X			sprintf (pr_buf,"given to posting program\n");
X			tputs(pr_buf,1,ttputc);
X#else
X			printf ("given to posting program\n");
X#endif
X		}
X		else
X			(*Postfunc)(hdr,fn);
X		save2_article (fn);
X	}
X	else {
X#ifdef amiga
X		sprintf (pr_buf,"not posted\n");
X		tputs(pr_buf,1,ttputc);
X#else
X		printf ("not posted\n");
X#endif
X	}
X	unlink (fn);
X	tty_set (RESTORE);
X	term_set (RESTART);
X}
X
X/*
X	get user buffer, return whitespace delimited token
X	buffer is allowed to overwrite prompt string.  This routine
X	should only be used when the terminal is in cooked mode.
X	In raw, use user_str().
X*/
Xstatic char *
Xrprompt(s,buf)
Xchar *s,*buf;
X{
X	char *strtok();
X
X#ifdef amiga
X	sprintf(pr_buf,"%s",s);
X	tputs(pr_buf,1,ttputc);
X#else
X	printf("%s",s);
X#endif
X	fgets (buf,RECLEN-1,stdin);
X	return (strtok(buf," \t\n"));
X}
X
X/*
X	edcopy copies article to file which user is editting for
X	a reply or followup, so it may be referenced.  It places
X	ED_MARK in the left hand margin.
X*/
Xstatic
Xedcopy(fp)
XFILE *fp;
X{
X	long current;
X	char buf[RECLEN];
X
X	/* save position, and seek to top of article */
X	current = ftell(Fpread);
X	fseek (Fpread,Rew_pos,0);
X
X	/* if line already begins with ED_MARK, forget about the space */
X	while (fgets(buf,RECLEN-1,Fpread) != NULL)
X	{
X		if (buf[0] == ED_MARK)
X			fprintf(fp,"%c%s",ED_MARK,buf);
X		else
X			fprintf(fp,"%c %s",ED_MARK,buf);
X	}
X
X	/* restore position */
X	fseek(Fpread,current,0);
X}
X
Xstatic
Xrot_line (s)
Xunsigned char *s;
X{
X	for ( ; *s != '\0'; ++s)
X	{
X		if (isupper(*s))
X		{
X			*s += Rot;
X			if (!isupper(*s))
X				*s -= 26;
X			continue;
X		}
X		if (islower(*s))
X		{
X			*s += Rot;
X			if (!islower(*s))
X				*s -= 26;
X		}
X	}
X}
X
X/*
X** output record.  folds record to terminal width on word boundaries,
X** returning number of lines output.  If limit is reached, remainder
X** of buffer waiting to be output is returned.  Processes several
X** special characters:
X**	form-feed - return "lim" lines so we stop on that line
X**	tabs - counts "expanded" width
X**	backspace - assumes they work, -1 width unless in first col.
X**	bell - pass through with zero width
X**	newline - end of record.
X**	del - turns into '_'
X**	other control - turned into '?'
X**		(prevents "letter bombs" containing inappropriate control
X**			sequences for the terminal).
X**
X** Sets Lookahead pointer to remainder of line or NULL.
X*/
Xstatic
Xdo_out(s,lim)
Xchar *s;
Xint lim;
X{
X	int len,i;
X	char cs,*word,*start;
X
X	Lookahead = NULL;
X	if (s == NULL)
X		return(0);
X	len = 0;
X	start = word = s;
X
X	/*
X	** NOTE: "normal" return is buried inside switch, at newline
X	** ending record
X	*/
X	for (i=0; i < lim; ++i)
X	{
X		for ( ; len < C_allow; ++s)
X		{
X			switch (*s)
X			{
X			case '\n':
X				*s = '\0';	/* fall through */
X			case '\0':
X#ifdef amiga
X				sprintf(pr_buf,"%s\n",start);
X				tputs(pr_buf,1,ttputc);
X#else
X				printf("%s\n",start);
X#endif
X				return(i+1);
X			case '\t':
X				len = ((len/PERTAB)+1)*PERTAB;
X				word = s;
X				break;
X			case '\b':
X				if (len > 0)
X					--len;
X				break;
X			case '\014':
X				*s = ' ';
X				i = lim-1;	/* fall through */
X			case ' ':
X				word = s+1;
X				++len;
X				break;
X			case '\177':
X				*s = '_';
X				++len;
X				break;
X			default:
X 				if (iscntrl(*s))
X					*s = '?';
X				++len;		/* fall through */
X			case '\07':
X				break;
X			}
X		}
X		cs = *s;
X		*s = '\0';
X		if ((len = strlen(word)) < BACKTRACK)
X		{
X			*s = cs;
X			s = word;
X			cs = *s;
X			*s = '\0';
X		}
X		else
X			len = 0;
X#ifdef amiga
X		sprintf(pr_buf,"%s\n",start);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("%s\n",start);
X#endif
X		start = s;
X		*s = cs;
X	}
X	Lookahead = start;
X	return(lim);
X}
X
Xstatic
Xvoid
Xsave2_article(tempfname)
Xchar *tempfname;
X{
X	FILE *in, *out;
X	int c;
X	time_t timenow, time();
X	char *today, *ctime();
X
X	if ((in = fopen(tempfname, "r")) == NULL)
X		return;
X	if ((out = fopen(Ccfile, "a")) == NULL)
X	{
X	    fclose(in);
X	    return;
X	}
X	timenow = time((time_t)0);
X	today = ctime(&timenow);
X	fprintf(out,"From vn %s",today);
X	while ((c=getc(in)) != EOF)
X		putc(c, out);
X	putc('\n', out);
X	fclose(in);
X	fclose(out);
X#ifdef amiga
X	sprintf (pr_buf,"a copy has been saved in %s\n", Ccfile);
X	tputs(pr_buf,1,ttputc);
X#else
X	printf ("a copy has been saved in %s\n", Ccfile);
X#endif
X}
X
X/*
X	send article to printer
X*/
Xstatic
Xvoid
Xprintr ()
X{
X	char cmd[RECLEN];
X	char fn[L_tmpnam];
X	long savepos;
X	FILE *f;
X
X	tmpnam (fn);
X	if ((f = fopen(fn,"w")) == NULL)
X	{
X		rerrmsg("can't open temp file, %s",fn);
X		return;
X	}
X
X	savepos = ftell(Fpread);
X	rewind(Fpread);
X	while (fgets(cmd,RECLEN-1,Fpread) != NULL)
X		fputs(cmd,f);
X	fclose(f);
X	fseek(Fpread,savepos,0);
X
X	tty_set (SAVEMODE);
X#ifdef amiga
X	sprintf(pr_buf,"Sent to printer\n");
X	tputs(pr_buf,1,ttputc);
X#else
X	printf("Sent to printer\n");
X#endif
X#ifdef amiga
X	sprintf (cmd,"%s >null: %s",Printer,fn);
X#else
X	sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
X#endif
X	system (cmd);
X	tty_set (RESTORE);
X	unlink (fn);
X}
X
X/*
X	search article for specified search pattern, returning the line on which
X		it is found in buf, a null buffer otherwise. The input file will
X		be positioned either after the line on which the pattern is
X		found, or unaaltered if match fails.
X*/
Xstatic
Xvoid
Xsearcher (buf)
Xchar	*buf;
X{
X	static char	searchstr[RECLEN] = "";
X	char	lasave[RECLEN];
X	char	*reg, *regcmp(), *regex();
X	long	current;
X	int	orlines;
X
X	/* save position, then request search pattern */
X	current = ftell(Fpread);
X	orlines = Rlines;
X
X	sprintf (lasave,SEARCHFORM,searchstr);
X	user_str (searchstr,lasave,0,searchstr);
X
X	/* Now compile the search string */
X	if(( reg = regcmp(searchstr, (char *)0)) == NULL) {
X		rerrmsg("Invalid search string \"%s\"", searchstr);
X		*buf = '\0';
X		return;
X	}
X
X	/* try lookahead buffer first */
X	if (Lookahead != NULL && regex(reg,Lookahead) != NULL)
X	{
X		strcpy(buf,Lookahead);
X		regfree(reg);
X		return;
X	}
X
X	/* Lookahead can point into buf */
X	if (Lookahead != NULL)
X		strcpy(lasave,Lookahead);
X
X	/* now start reading lines, rotating if necessary and do search */
X	while (fgets(buf,RECLEN-1,Fpread) != NULL)
X	{
X		if (Rot != 0 && Rlines >= Hlines)
X			rot_line(buf);
X		++Rlines;
X		if( regex(reg, buf) != NULL ){	/* Got it */
X#ifdef	MINIX
X/* inverse video mucks up this line somehow */
X			rerrmsg("\tSkipping ...\n\n");
X#else
X			rerrmsg("\n\tSkipping ....\n\n");
X#endif
X			regfree(reg);
X			return;
X		}
X	}
X
X	/* no dice, so restore position */
X	regfree(reg);
X	rerrmsg("Cannot find string \"%s\" in remainder of article", searchstr);
X	fseek(Fpread,current,0);
X	Rlines = orlines;
X	if (Lookahead != NULL)
X		strcpy(buf,lasave);
X	else
X		*buf = '\0';
X}
X
X/*
X** print a reverse video error message while reading an article.
X*/
Xstatic
Xrerrmsg(s,a,b,c,d,e)
Xchar *s;
Xlong a,b,c,d,e;
X{
X	term_set (ONREVERSE);
X#ifdef amiga
X	sprintf(pr_buf,"\n ");
X	tputs(pr_buf,1,ttputc);
X	sprintf(pr_buf,s,a,b,c,d,e);
X	tputs(pr_buf,1,ttputc);
X	sprintf(pr_buf," \07\n");
X	tputs(pr_buf,1,ttputc);
X#else
X	printf("\n ");
X	printf(s,a,b,c,d,e);
X	printf(" \07\n");
X#endif
X	term_set (OFFREVERSE);
X}
END_OF_FILE
if test 18716 -ne `wc -c <'reader.c'`; then
    echo shar: \"'reader.c'\" unpacked with wrong size!
fi
# end of 'reader.c'
fi
if test -f 'session.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'session.c'\"
else
echo shar: Extracting \"'session.c'\" \(24544 characters\)
sed "s/^X//" >'session.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** session.c - top session loop
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X#include <stdio.h>
X#include <setjmp.h>
X#include <ctype.h>
X#include "config.h"
X#include "tty.h"
X#include "brk.h"
X#include "head.h"
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X#include "vn.h"
X
X#ifdef amiga
X#define system(a)	Execute(a, 0, 0)
X#undef	getchar
X#define	getchar ttgetc
Xextern char pr_buf[];
Xextern ttputc ();
X#endif
X
Xextern NODE **Newsorder;
Xextern char Erasekey, Killkey;
Xextern int Rot;
Xextern char *Ps1,*Printer;
Xextern char *Orgdir,*Savefile;
Xextern int Ncount, Cur_page, Lrec, L_allow, C_allow;
Xextern int Headflag;
Xextern PAGE Page;
Xextern int Digest;
Xextern char *No_msg;
Xextern char *Hdon_msg;
Xextern char *Hdoff_msg;
Xextern char *Roton_msg;
Xextern char *Rotoff_msg;
Xextern char Cxitop[], Cxptoi[];
Xextern char *Aformat;
Xextern char *Contstr;
Xextern char *Kl,*Kr,*Ku,*Kd;
Xextern int Nounsub, Listfirst;
Xextern char *List_sep;
Xextern char *Version, *Vns_version;
X
Xextern char (*Marker)();
Xextern int (*Hookfunc)();
X
Xextern char     *strtok ();
X
Xstatic int C_info;
Xstatic int Dskip, Drec;
X
Xstatic char *Unsub_msg = "Unsubscribed";
Xstatic char *Egroup_msg = "Entire newsgroup";
X
Xstatic int Crec;
Xstatic int Highrec;
X
Xstatic  show (), wr_show (), spec_group (), tot_list (), do_update (),
X	new_read (), new_sub (), markstr (), forward (), genlist (),
X	printstr (), savestr ();
X
X#ifdef	MSDOS
X#undef	getchar
X#define	getchar	getraw
X#endif
X
X
X
X/*
X	main session handler processing input commands
X
X	NOTE: this is where a setjmp call is made to set the break reentry
X		location.  Keep the possible user states in mind.
X*/
Xsession ()
X{
X	char alist [RECLEN], c;
X	int newg, i, j, count;
X	jmp_buf brkbuf;
X
X	newg = new_groups();
X	tty_set (RAWMODE);
X	find_page (0);
X	Digest = 0;
X
X	/* reentry point for break from within session interaction */
X	setjmp (brkbuf);
X	sig_set (BRK_SESS,brkbuf);
X	Headflag = FALSE;
X	Rot = 0;
X
X	/* done this way so that user gets "really quit?" break treatment */
X	if (newg > 0)
X	{
X#ifdef amiga
X		sprintf (pr_buf,"\n%s",Contstr);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf ("\n%s",Contstr);
X#endif
X		getnoctl();
X		newg = 0;
X	}
X
X	/* list preview option - clear after first time for long jumps */
X	if (Listfirst)
X	{
X		/* tot_list settings will be overwritten in this case */
X		tot_list();
X		Listfirst = 0;
X	}
X
X	/* if breaking from a digest, recover original page */
X	if (Digest)
X	{
X		find_page(Cur_page);
X		Digest = 0;
X	}
X	show ();
X	Crec = RECBIAS;
X	Highrec = Page.h.artnum + RECBIAS;
X	term_set (MOVE,0,Crec);
X
X	/*
X		handle commands until QUIT, update global/local status
X		and display for each.
X	 */
X	for (count = getkey(&c); c != QUIT; count = getkey(&c))
X	{
X		if (Hookfunc != NULL)
X		{
X			if ((i = (*Hookfunc)(c,0,1,alist)) >= 0)
X			{
X				if (i == 0)
X					prinfo(alist);
X				else
X				{
X					term_set(ERASE);
X					show();
X				}
X				term_set (MOVE,0,Crec);
X				continue;
X			}
X		}
X
X		if ( srch_help(c,&i) != 0 || (Digest != 0 && i == 0))
X		{
X			preinfo (UDKFORM,Cxptoi[HELP]);
X			term_set (MOVE, 0, Crec);
X			continue;
X		}
X
X		switch (c)
X		{
X		case HEADTOG:
X			if (Headflag)
X			{
X				Headflag = FALSE;
X				prinfo (Hdoff_msg);
X			}
X			else
X			{
X				Headflag = TRUE;
X				prinfo (Hdon_msg);
X			}
X			term_set (MOVE,0,Crec);
X			break;
X		case SETROT:
X			if (Rot == 0)
X			{
X				Rot = 13;
X				prinfo (Roton_msg);
X			}
X			else
X			{
X				Rot = 0;
X				prinfo (Rotoff_msg);
X			}
X			term_set (MOVE,0,Crec);
X			break;
X		case SSTAT:
X			count_msg ();
X			term_set (MOVE,0,Crec);
X			break;
X		case GRPLIST:
X			tot_list ();
X			show();
X			term_set (MOVE,0,Crec);
X			break;
X		case REDRAW:
X			show();
X			term_set (MOVE,0,Crec);
X			break;
X		case UNSUBSCRIBE:
X			new_sub(Page.h.group,0);
X			do_update(Unsub_msg);
X			term_set (MOVE,0,Crec);
X			break;
X
X		case UPDATE:
X			new_read(Page.h.group,Page.b[Crec-RECBIAS].art_id);
X			wr_show ();
X			do_update("Updated to cursor");
X			term_set (MOVE,0,Crec);
X			break;
X		case UPALL:
X			new_read(Page.h.group,(Page.h.group)->highnum);
X			wr_show();
X			do_update(Egroup_msg);
X			term_set (MOVE,0,Crec);
X			break;
X		case ORGGRP:
X			new_read(Page.h.group,(Page.h.group)->orgrd);
X			wr_show();
X			do_update(Egroup_msg);
X			term_set (MOVE,0,Crec);
X			break;
X		case UPSEEN:
X			up_seen();
X			wr_show();
X			do_update("All pages displayed to this point updated");
X			term_set (MOVE,0,Crec);
X			break;
X		case ORGSTAT:
X			for (i = 0; i < Ncount; ++i)
X				new_read(Newsorder[i],(Newsorder[i])->orgrd);
X			wr_show();
X			do_update("Original data recovered");
X			term_set (MOVE,0,Crec);
X			break;
X 		case TOPMOVE:
X 			Crec = RECBIAS;
X 			term_set (MOVE, 0, Crec);
X 			break;
X 		case BOTMOVE:
X 		case ALTBOTTOM:
X 			Crec = Highrec - 1;
X 			term_set (MOVE, 0, Crec);
X 			break;
X 		case MIDMOVE:
X 			Crec = (RECBIAS + Highrec - 1) / 2;
X 			if (Crec < RECBIAS)
X 				Crec = RECBIAS;
X 			if (Crec >= Highrec)
X 				Crec = Highrec - 1;
X 			term_set (MOVE, 0, Crec);
X 			break;
X		case UP:
X			if (Crec != RECBIAS)
X			{
X				Crec -= count;
X				if (Crec < RECBIAS)
X					Crec = RECBIAS;
X				term_set (MOVE, 0, Crec);
X			}
X			else
X				putchar ('\07');
X			break;
X		case DOWN:
X			if (Crec < (Highrec - 1))
X			{
X				Crec += count;
X				if (Crec >= Highrec)
X					Crec = Highrec - 1;
X				term_set (MOVE, 0, Crec);
X			}
X			else
X				putchar ('\07');
X			break;
X		case MARKSTRING:
X			(Page.h.group)->flags |= FLG_ACC;
X			userlist (alist);
X			markstr (alist,c);
X			term_set (MOVE, 0, Crec);
X			write_page ();
X			break;
X		case MARK:
X		case ART_MARK:
X			genlist (alist,Crec-RECBIAS,count);
X			markstr (alist,c);
X			term_set (MOVE, 0, Crec);
X			write_page ();
X			break;
X		case UNMARK:
X			for (i=0; i < Page.h.artnum; ++i)
X			{
X				if (Page.b[i].art_mark != ' ')
X				{
X					if (Marker == NULL)
X						Page.b[i].art_mark = ' ';
X					else
X						Page.b[i].art_mark =
X						(*Marker)(Page.h.group,
X							Page.b[i].art_id,
X							Page.b[i].art_mark, c);
X					term_set (MOVE, 0, i+RECBIAS);
X					putchar (' ');
X				}
X			}
X			term_set (MOVE, 0, Crec);
X			write_page ();
X			break;
X		case BACK:
X			count *= -1;	/* fall through */
X		case FORWARD:
X			if (forward (count) >= 0)
X				show();
X			else
X				preinfo ("No more pages");
X			term_set (MOVE,0,Crec);
X			break;
X		case GRPBACK:
X			j = (Page.h.group)->order;
X			for (i = j-1; count > 0 && i >= 0; --i)
X			{
X				if ((Newsorder[i])->pages > 0)
X				{
X					j = i;
X					--count;
X				}
X			}
X			if (j == (Page.h.group)->order)
X				preinfo ("No more newsgroups");
X			else
X			{
X				forward ((Newsorder[j])->pnum - Cur_page);
X				show();
X			}
X			term_set (MOVE,0,Crec);
X			break;
X		case GRPFORWARD:
X			j = (Page.h.group)->order;
X			for (i= j+1; count > 0 && i < Ncount; ++i)
X			{
X				if ((Newsorder[i])->pages > 0)
X				{
X					j = i;
X					--count;
X				}
X			}
X			if (j == (Page.h.group)->order)
X				preinfo ("No more newsgroups");
X			else
X			{
X				forward ((Newsorder[j])->pnum - Cur_page);
X				show();
X			}
X			term_set (MOVE,0,Crec);
X			break;
X		case DIGEST:
X			if (Digest)
X			{
X				Digest = 0;
X				find_page (Cur_page);
X				show();
X				Crec = Drec + RECBIAS + 1;
X				Highrec = Page.h.artnum + RECBIAS;
X				if (Crec >= Highrec)
X					Crec = Highrec - 1;
X				term_set (MOVE,0,Crec);
X				break;
X			}
X			(Page.h.group)->flags |= FLG_ACC;
X			Dskip = count - 1;
X			Drec = Crec - RECBIAS;
X			if (dige_page(Drec,Dskip) >= 0)
X			{
X				show();
X				Crec = RECBIAS;
X				Highrec = Page.h.artnum + RECBIAS;
X				term_set (MOVE,0,Crec);
X				break;
X			}
X			Digest = 0;
X			preinfo ("Can't unpack the article");
X			term_set (MOVE,0,Crec);
X			break;
X		case NEWGROUP:
X			if ((i = spec_group()) < 0)
X			{
X				term_set (MOVE,0,Crec);
X				break;
X			}
X			Digest = 0;
X			show();
X			Crec = RECBIAS;
X			Highrec = Page.h.artnum + RECBIAS;
X			term_set (MOVE,0,Crec);
X			break;
X
X		case SAVE:
X			(Page.h.group)->flags |= FLG_ACC;
X			genlist (alist,Crec-RECBIAS,count);
X			savestr (alist);
X			term_set (MOVE,0,Crec);
X			break;
X		case SAVEALL:
X			(Page.h.group)->flags |= FLG_ACC;
X			genlist (alist,0,L_allow);
X			savestr (alist);
X			term_set (MOVE,0,Crec);
X			break;
X		case SAVESTRING:
X		case ALTSAVE:
X			(Page.h.group)->flags |= FLG_ACC;
X			userlist (alist);
X			savestr (alist);
X			term_set (MOVE,0,Crec);
X			break;
X		case READ:
X		case ALTREAD:
X			(Page.h.group)->flags |= FLG_ACC;
X			genlist (alist,Crec-RECBIAS,count);
X			readstr (alist,count);
X			break;
X		case READALL:
X			(Page.h.group)->flags |= FLG_ACC;
X			genlist (alist,0,L_allow);
X			readstr (alist,0);
X			break;
X		case READSTRING:
X			(Page.h.group)->flags |= FLG_ACC;
X			userlist (alist);
X			readstr (alist,0);
X			break;
X		case PRINT:
X			(Page.h.group)->flags |= FLG_ACC;
X			genlist (alist,Crec-RECBIAS,count);
X			printstr (alist);
X			term_set (MOVE,0,Crec);
X			break;
X		case PRINTALL:
X			(Page.h.group)->flags |= FLG_ACC;
X			genlist (alist,0,L_allow);
X			printstr (alist);
X			term_set (MOVE, 0, Crec);
X			break;
X		case PRINTSTRING:
X			(Page.h.group)->flags |= FLG_ACC;
X			userlist (alist);
X			printstr (alist);
X			term_set (MOVE, 0, Crec);
X			break;
X
X		case HELP:
X			help ();
X			show ();
X			term_set (MOVE, 0, Crec);
X			break;
X		case UNESC:
X			user_str (alist,Ps1,1,"");
X			term_set (ERASE);
X#ifdef amiga
X			ttflush ();
X#else
X			fflush (stdout);
X#endif
X			tty_set (SAVEMODE);
X			if (chdir(Orgdir) < 0) {
X#ifdef amiga
X				sprintf (pr_buf,"change to original directory, %s, failed",Orgdir);
X				tputs(pr_buf,1,ttputc);
X#else
X				printf ("change to original directory, %s, failed",Orgdir);
X#endif
X			} else
X			{
X				system (alist);
X				tty_set (RESTORE);
X				term_set (RESTART);
X			}
X#ifdef amiga
X			sprintf (pr_buf,Contstr);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf (Contstr);
X#endif
X			getnoctl ();
X			vns_gset(Page.h.name);
X			show ();
X			term_set (MOVE, 0, Crec);
X			break;
X		case PRTVERSION:
X			prinfo("%s %s", Version, Vns_version);
X			term_set (MOVE, 0, Crec);
X			break;
X		default:
X			preinfo("Unhandled key: %c", c);
X			break;
X		}
X	}
X
X	Digest = 0;
X	for (i=0; i < Ncount; ++i)
X	{
X		if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
X			break;
X	}
X	if (i < Ncount)
X	{
X		user_str (alist,"Some displayed pages not updated - update ? ",
X							1, QUIT_ANSWER);
X		if (alist[0] == 'y')
X			up_seen();
X	}
X	sig_set (BRK_OUT);
X}
X
X/*
X** update status of Newsgroups to all seen pages
X*/
Xup_seen()
X{
X	int i;
X
X	for (i = 0; i < Ncount; ++i)
X	{
X		if (Nounsub && ((Newsorder[i])->flags & FLG_SUB) == 0)
X		{
X			new_read(Newsorder[i],(Newsorder[i])->highnum);
X			continue;
X		}
X		if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
X			new_read(Newsorder[i],(Newsorder[i])->pgrd);
X	}
X}
X
X/*
X	count_msg displays count information
X*/
Xcount_msg ()
X{
X	int i, gpnum, gscan, gpage;
X	unsigned long mask;
X	gpnum = 1;
X	for (gscan = gpage = i = 0; i<Ncount; ++i)
X	{
X		if (((Newsorder[i])->flags & FLG_PAGE) != 0)
X		{
X			if (((Newsorder[i])->pnum + (Newsorder[i])->pages - 1) < Cur_page)
X				++gpnum;
X			++gpage;
X			for (mask=1; mask != 0L; mask <<= 1)
X				if (((Newsorder[i])->pgshwn & mask) != 0L)
X					++gscan;
X		}
X	}
X	prinfo (CFORMAT,Cur_page+1,Lrec+1,gscan,gpnum,gpage);
X}
X
X/*
X	forward utility handles paging
X*/
Xstatic
Xforward (count)
Xint count;
X{
X	if (!Digest)
X	{
X		if ((count < 0 && Cur_page <= 0) || (count > 0 && Cur_page >= Lrec))
X			return (-1);
X		Cur_page += count;
X		if (Cur_page < 0)
X			Cur_page = 0;
X		if (Cur_page > Lrec)
X			Cur_page = Lrec;
X		find_page (Cur_page);
X		Crec = RECBIAS;
X		Highrec = Page.h.artnum + RECBIAS;
X		return (0);
X	}
X	/*
X	** in digests, paging past the end of the digest returns to
X	** page extracted from.
X	*/
X	if (Dskip > 0 && (Dskip + count*L_allow) < 0)
X		Dskip = 0;
X	else
X		Dskip += count * L_allow;
X	find_page (Cur_page);
X	if (Dskip >= 0)
X	{
X		if (dige_page(Drec,Dskip) >= 0)
X		{
X			Crec = RECBIAS;
X			Highrec = Page.h.artnum + RECBIAS;
X			return (0);
X		}
X	}
X	Digest = 0;
X	Crec = Drec + RECBIAS + 1;
X	Highrec = Page.h.artnum + RECBIAS;
X	if (Crec >= Highrec)
X		Crec = Highrec - 1;
X	return (0);
X}
X
X/*
X	generate list of articles on current page,
X	count articles, starting with first.
X*/
Xstatic
Xgenlist (list,first,count)
Xchar *list;
Xint first,count;
X{
X	int i;
X	for (i=first; i < Page.h.artnum && count > 0; ++i)
X	{
X		sprintf (list,"%d ",Page.b[i].art_id);
X		list += strlen(list);
X		--count;
X	}
X}
X
X/*
X	send list of articles to printer
X*/
Xstatic
Xprintstr (s)
Xchar *s;
X{
X	char cmd [RECLEN];
X	char fn[L_tmpnam];
X	char dsave[RECLEN];	/* save list for unlinking */
X
X	prinfo ("preparing print command ....");
X
X	if (Digest)
X	{
X		dig_list (s);
X		strcpy(dsave,s);
X	}
X
X	if (*s != '\0')
X	{
X		tmpnam(fn);
X		if (art_xfer(fn,s,"w",NULL) != 0)
X		{
X			preinfo("Couldn't open temporary file");
X			return;
X		}
X#ifdef amiga
X		sprintf (cmd,"%s >null: %s",Printer,fn);
X		if (system (cmd) != 0)
X			prinfo ("Sent to printer");
X#else
X		sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
X		if (system (cmd) == 0)
X			prinfo ("Sent to printer");
X#endif
X		else
X			preinfo ("Print failed");
X		unlink(fn);
X	}
X	else
X		preinfo (No_msg);
X
X	if (Digest)
X		dig_ulist (dsave);
X}
X
X/*
X	read a list of articles.
X*/
Xreadstr (s,count)
Xchar *s;
Xint count;
X{
X	char *strtok();
X	char *fn[MAXARTLIST+1];
X	int pc, num, i;
X
X	/* we pre-process tokens to release strtok() for further use */
X	fn[0] = strtok(s,List_sep);
X	for (num=0; fn[num] != NULL; fn[(++num)] = strtok(NULL,List_sep))
X		if (num >= MAXARTLIST)
X			break;
X	fn[num] = NULL;
X
X	if (fn[0] != NULL)
X	{
X		term_set (ERASE);
X		for (i=0; i < num && readfile(fn[i], fn[i+1] ,&pc) >= 0; ++i)
X		{
X#ifndef	MINIX
X/* I don't believe this code is correct at all!!! */
X			if (Digest)
X				unlink (fn[i]);
X#endif  /*!MINIX*/
X		}
X
X#ifndef	MINIX
X/* I don't believe this code is correct at all!!! */
X		if (Digest && fn[i] != NULL)
X			unlink (fn[i]);
X#endif  /*!MINIX*/
X		if (pc != 0)
X			forward (pc);
X		else
X		{
X			Crec += count;
X			if (Crec >= Highrec)
X				Crec = Highrec - 1;
X		}
X		show ();
X		term_set (MOVE, 0, Crec);
X	}
X	else
X	{
X		preinfo ("%s",No_msg);
X		term_set (MOVE, 0, Crec);
X	}
X}
X
X/*
X	concatenate articles to save file with appropriate infoline messages.
X	prompt for save file, giving default.  If save file begins with "|"
X	handle as a filter to pipe to.  NOTE - every user specification of
X	a new Savefile "loses" some storage, but it shouldn't be a very great
X	amount.
X*/
Xstatic
Xsavestr (s)
Xchar *s;
X{
X	char *ptr, newfile [MAX_C+1], msg[RECLEN];
X	char *str_store();
X	char dsave[RECLEN];
X
X	if (Digest)
X	{
X		dig_list (s);
X		strcpy(dsave,s);
X	}
X
X	if (*s != '\0')
X	{
X		user_str (newfile,"save file ? ",1,Savefile);
X		ptr = newfile;
X		if (*ptr == '|')
X		{
X			term_set (ERASE);
X#ifdef amiga
X			ttflush ();
X#else
X			fflush (stdout);
X#endif
X			save_art(s,ptr,msg);
X#ifdef amiga
X			sprintf (pr_buf,"%s\n%s",msg,Contstr);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf ("%s\n%s",msg,Contstr);
X#endif
X			getnoctl ();
X			show ();
X		}
X		else
X		{
X			prinfo("saving ....");
X			if (*ptr == '\0')
X				ptr = Savefile;
X			else
X				Savefile = str_store(ptr);
X			if (save_art(s,Savefile,msg) != 0)
X				preinfo(msg);
X			else
X				prinfo(msg);
X		}
X	}
X	else
X		preinfo (No_msg);
X
X	if (Digest)
X		dig_ulist (dsave);
X}
X
X/*
X	basic page display routine.  erase screen and format current page
X*/
Xstatic
Xshow ()
X{
X	int i;
X	unsigned long mask;
X	char helpstr[40]; 
X
X	term_set (ERASE);
X	C_info = 0;
X	i = Cur_page - (Page.h.group)->pnum + 1;
X	if (Digest) {
X#ifdef amiga
X		sprintf (pr_buf,DHFORMAT,Page.h.name);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf (DHFORMAT,Page.h.name);
X#endif
X	} else {
X#ifdef amiga
X		sprintf (pr_buf,HFORMAT,Page.h.name,i,(Page.h.group)->pages);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf (HFORMAT,Page.h.name,i,(Page.h.group)->pages);
X#endif
X	}
X	
X	mask = 1L << (i-1);
X	(Page.h.group)->pgshwn |= mask;
X	mask = 1;
X	for (--i; i > 0 && (mask & (Page.h.group)->pgshwn) != 0 ; --i)
X		mask <<= 1;
X	if (i <= 0)
X		(Page.h.group)->pgrd = Page.b[(Page.h.artnum)-1].art_id;
X
X	for (i=0; i < Page.h.artnum; ++i)
X	{
X		if (Digest)
X		{
X#ifdef amiga
X			sprintf(pr_buf,Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X			tputs(pr_buf,1,ttputc);
X			sprintf(pr_buf,"%s",Page.b[i].art_t);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X			printf("%s",Page.b[i].art_t);
X#endif
X			continue;
X		}
X
X		if ((Page.h.group)->rdnum >= Page.b[i].art_id) {
X#ifdef amiga
X			sprintf(pr_buf,Aformat,Page.b[i].art_mark,ART_WRITTEN,Page.b[i].art_id);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf(Aformat,Page.b[i].art_mark,ART_WRITTEN,Page.b[i].art_id);
X#endif
X		} else {
X#ifdef amiga
X			sprintf(pr_buf,Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X#endif
X		}
X#ifdef amiga
X		sprintf(pr_buf,"%s",Page.b[i].art_t);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("%s",Page.b[i].art_t);
X#endif
X	}
X
X	sprintf(helpstr,HELPFORM,Cxptoi[HELP]);
X	if (!Digest && ((Page.h.group)->flags & FLG_SUB) == 0)
X		prinfo ("%s, %s",Unsub_msg,helpstr);
X	else
X		prinfo (helpstr);
X}
X
X/*
X	update written status marks on screen
X*/
Xstatic
Xwr_show ()
X{
X	int i,row;
X	char c;
X
X	row = RECBIAS;
X	for (i=0; i < Page.h.artnum; ++i)
X	{
X		term_set (MOVE,WRCOL,row);
X		if ((Page.h.group)->rdnum >= Page.b[i].art_id)
X			c = ART_WRITTEN;
X		else
X			c = ART_UNWRITTEN;
X#ifdef amiga
X		sprintf(pr_buf,"%c",c);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("%c",c);
X#endif
X		++row;
X	}
X}
X
X/*
X	obtain user input of group name, becomes current page if valid.
X	returns -1 or page number.  calling routine does the show, if needed
X*/
Xstatic
Xspec_group ()
X{
X	char nbuf [MAX_C + 1];
X	NODE *p, *hashfind();
X
X	user_str(nbuf,"Newsgroup ? ",1,"");
X
X	if (*nbuf == '\0' || (p = hashfind(nbuf)) == NULL)
X	{
X		preinfo ("Not a newsgroup");
X		return (-1);
X	}
X	if ((p->flags & FLG_PAGE) == 0)
X	{
X		if ((p->flags & FLG_SUB) == 0)
X		{
X			new_sub(p,FLG_SUB);
X			do_update("Not subscribed: resubscribed for next reading session");
X		}
X		else
X			prinfo ("No news for that group");
X		return (-1);
X	}
X	if ((p->flags & FLG_SUB) == 0)
X	{
X		new_sub(p,FLG_SUB);
X		do_update("Resubscribed");
X	}
X	find_page (p->pnum);
X	return (p->pnum);
X}
X
X/*
X	obtain user input with prompt p.  Optionally on info line.
X	handle erase and kill characters, suppresses leading
X	white space.  Use defstr as the editable default user input.
X	If on info line, cursor is not moved anywhere whe done, otherwise
X	a <CR><LF> is done after input.  Should be in raw mode to use
X	this routine.  Used from outside this source file so that we
X	only have to do erase / kill key stuff one place.
X*/
Xuser_str (s,p,iline,defstr)
Xchar *s;
Xchar *p;
Xint iline;
Xchar *defstr;
X{
X	int i,idx,len;
X	char c;
X
X	if (iline)
X	{
X 		prinfo ("%s%s",p,defstr);
X		idx = C_info;
X	}
X	else
X	{
X#ifdef amiga
X 		sprintf (pr_buf,"%s%s",p,defstr);
X		tputs(pr_buf,1,ttputc);
X#else
X 		printf ("%s%s",p,defstr);
X#endif
X		idx = strlen(p);
X	}
X
X	len = strlen(defstr);
X 	for (i=0; i < len; i++)
X 		s[i] = defstr[i];
X 
X 	for (i=len; idx < C_allow; ++i)
X	{
X		s[i] = getchar();
X		c = s[i] & CHMASK;
X		if (c == '\015' || c == '\012')
X			break;
X		if (c == Erasekey)
X		{
X			if (i > 0)
X			{
X				term_set (RUBSEQ);
X				i -= 2;
X				--idx;
X			}
X			else
X				i = -1;
X			continue;
X		}
X		if (c == Killkey)
X		{
X 			if (iline)
X 			{
X 				prinfo ("%s",p);
X 				idx = C_info;
X 			}
X 			else
X 			{
X#ifdef amiga
X 				sprintf (pr_buf,"\r%s",p);
X				tputs(pr_buf,1,ttputc);
X#else
X 				printf ("\r%s",p);
X#endif
X 				term_set(ZAP,strlen(p),idx);
X#ifdef amiga
X				ttflush ();
X#else
X 				fflush(stdout);
X#endif
X 				idx = strlen(p);
X 			}
X			i = -1;
X			continue;
X		}
X		/* no leading spaces */
X		if (c == ' ' && i == 0)
X		{
X			i = -1;
X			putchar('\07');
X			continue;
X		}
X		/* no controls */
X 		if (iscntrl(c))
X		{
X			--i;
X			putchar('\07');
X			continue;
X		}
X		++idx;
X		putchar (s[i]);
X#ifdef	MINIX
X		fflush(stdout);
X#endif
X	}
X
X	if (iline)
X		C_info = idx;
X	else {
X#ifdef amiga
X		sprintf(pr_buf,"\r\n");
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("\r\n");
X#endif
X	}
X
X	s[i] = '\0';
X}
X/*
X	print something on the information line,
X	clearing any characters not overprinted.
X	preinfo includes reverse video and a bell for error messages.
X*/
Xpreinfo (s,a,b,c,d,e,f)
Xchar	*s;
X{
X	int l;
X	char buf[RECLEN];
X
X	term_set (MOVE,0,INFOLINE);
X	putchar ('\07');
X	term_set (ONREVERSE);
X	sprintf (buf,s,a,b,c,d,e,f);
X#ifdef amiga
X	sprintf (pr_buf," %s",buf);
X	tputs(pr_buf,1,ttputc);
X#else
X	printf (" %s ",buf);
X#endif
X	term_set (OFFREVERSE);
X	l = strlen(buf) + 2;
X	if (l < C_info)
X		term_set (ZAP,l,C_info);
X	C_info = l;
X#ifdef amiga
X	ttflush ();
X#else
X	fflush(stdout);
X#endif
X}
X
Xprinfo (s,a,b,c,d,e,f)
Xchar *s;
Xlong a,b,c,d,e,f;
X{
X	int l;
X	char buf[RECLEN];
X	term_set (MOVE,0,INFOLINE);
X	sprintf (buf,s,a,b,c,d,e,f);
X#ifdef amiga
X	sprintf (pr_buf,"%s",buf);
X	tputs(pr_buf,1,ttputc);
X#else
X	printf ("%s ",buf);
X#endif
X	l = strlen(buf);
X	if (l < C_info)
X		term_set (ZAP,l,C_info);
X	C_info = l;
X#ifdef amiga
X	ttflush ();
X#else
X	fflush(stdout);
X#endif
X}
X
Xstatic
Xtot_list ()
X{
X	int i,max,len;
X	char c;
X	char ff[MAX_C+1];
X
X	term_set (ERASE);
X
X	for (max=i=0; i < Ncount; ++i)
X	{
X		if ((Newsorder[i])->pages == 0)
X			continue;
X		if ((len = strlen((Newsorder[i])->nd_name)) > max)
X			max = len;
X	}
X
X	sprintf (ff,"%%4d %%%ds: %%3d new %%3d updated\n",max);
X
X	for (len=i=0; i < Ncount; ++i)
X	{
X		if ((Newsorder[i])->pages == 0)
X			continue;
X#ifdef amiga
X		sprintf (pr_buf,ff, i, (Newsorder[i])->nd_name,
X				(Newsorder[i])->highnum - (Newsorder[i])->orgrd,
X				(Newsorder[i])->rdnum - (Newsorder[i])->orgrd);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf (ff, i, (Newsorder[i])->nd_name,
X				(Newsorder[i])->highnum - (Newsorder[i])->orgrd,
X				(Newsorder[i])->rdnum - (Newsorder[i])->orgrd);
X#endif
X		++len;
X		if (len == L_allow && i < (Ncount-1))
X		{
X#ifdef amiga
X			sprintf(pr_buf,"\nr - return, n - new group, other to continue ... ");
X			tputs(pr_buf,1,ttputc);
X#else
X			printf("\nr - return, n - new group, other to continue ... ");
X#endif
X			if ((c = getnoctl()) == 'r' || c == 'n')
X				break;
X			printf ("\n\n");
X			len = 0;
X		}
X	}
X	if (i >= Ncount)
X	{
X#ifdef amiga
X		sprintf(pr_buf,"n - new group, other to return ... ");
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("n - new group, other to return ... ");
X#endif
X		c = getnoctl();
X	}
X
X	/* c will remain 'n' while user chooses bad newsgroups */
X	while (c == 'n')
X	{
X#ifdef amiga
X		sprintf(pr_buf,"\n");
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("\n");
X#endif
X		user_str(ff,"Newsgroup number ? ",0,"");
X		i = atoi(ff);
X 		if (i < 0 || i >= Ncount || (Newsorder[i])->pages == 0)
X		{
X#ifdef amiga
X 			sprintf(pr_buf,"\nBad newsgroup number\n");
X			tputs(pr_buf,1,ttputc);
X 			sprintf(pr_buf,"n - new group, other to return ... ");
X			tputs(pr_buf,1,ttputc);
X#else
X 			printf("\nBad newsgroup number\n");
X 			printf("n - new group, other to return ... ");
X#endif
X			c = getnoctl();
X			continue;
X 		}
X 		find_page((Newsorder[i])->pnum);
X		Crec = RECBIAS;
X		Highrec = Page.h.artnum + RECBIAS;
X		c = '\0';
X	}
X}
X
X/*
X** call vns_write if anything has changed, then wipe FLG_ECHG bits
X** also produce message(s)
X*/
Xstatic
Xdo_update(msg)
Xchar *msg;
X{
X	int i;
X
X	for (i=0; i < Ncount; ++i)
X		if(((Newsorder[i])->flags & FLG_ECHG) != 0)
X			break;
X	if (i < Ncount)
X	{
X		prinfo("Writing news status");
X		vns_write(Newsorder,Ncount);
X		for (i=0; i < Ncount; ++i)
X			(Newsorder[i])->flags &= ~FLG_ECHG;
X	}
X	prinfo(msg);
X}
X
X/*
X** set a new rdnum value.  If a change, set FLG_ECHG
X*/
Xstatic
Xnew_read(n,rd)
XNODE *n;
Xint rd;
X{
X	if (n->rdnum != rd)
X	{
X		n->rdnum = rd;
X		n->flags |= FLG_ECHG;
X	}
X}
X
X/*
X** set a new subscription bit.  bit argument is either 0 or FLG_SUB.
X*/
Xstatic
Xnew_sub(n,bit)
XNODE *n;
Xunsigned bit;
X{
X	/*
X	** since bit is 0 or FLG_SUB, we could get tricky with ^
X	** but this is clearer
X	*/
X	if (bit != 0 && (n->flags & FLG_SUB) == 0)
X		n->flags |= FLG_SUB|FLG_ECHG;
X	else
X	{
X		if (bit == 0 && (n->flags & FLG_SUB) != 0)
X		{
X			n->flags &= ~FLG_SUB;
X			n->flags |= FLG_ECHG;
X		}
X	}
X}
X
X/*
X** utility to mark articles.  depends on fact that article numbers are
X** in ascending order on page.
X*/
Xstatic
Xmarkstr (list,ckey)
Xchar *list;
Xchar ckey;
X{
X	char *tok;
X	int art, count;
X	BODY *b;
X
X	count = 1;
X	b = Page.b;
X	for (tok = strtok(list,List_sep); tok != NULL;
X					tok = strtok(NULL,List_sep))
X	{
X		art = atoi(tok);
X		while (count < Page.h.artnum && b->art_id < art)
X		{
X			++count;
X			++b;
X		}
X		if (b->art_id == art)
X		{
X			/*
X			** Can't call Marker inside digests
X			*/
X			if (Marker == NULL || Digest)
X			{
X				if (b->art_mark != ART_MARK)
X					b->art_mark = ART_MARK;
X				else
X					b->art_mark = ' ';
X			}
X			else
X			{
X				b->art_mark =
X					(*Marker)(Page.h.group, art,
X						b->art_mark, ckey);
X			}
X			term_set (MOVE, 0, count-1+RECBIAS);
X#ifdef amiga
X			sprintf (pr_buf,"%c\010",b->art_mark);
X			tputs(pr_buf,1,ttputc);
X#else
X			printf ("%c\010",b->art_mark);
X#endif
X		}
X	}
X}
END_OF_FILE
if test 24544 -ne `wc -c <'session.c'`; then
    echo shar: \"'session.c'\" unpacked with wrong size!
fi
# end of 'session.c'
fi
echo shar: End of archive 4 \(of 6\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.