[comp.os.minix] Vn for Minix, part 2 of 4

nick@ultima.cs.uts.oz (Nick Andrew) (11/26/89)

#! /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 shell archive."
# Contents:  newdisp.c node.h page.h pagefile.c printex.c reader.c
#   reader.h reg.c regcompat.c
# Wrapped by nick@ultima on Sun Nov 26 22:15:46 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'newdisp.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'newdisp.c'\"
else
echo shar: Extracting \"'newdisp.c'\" \(920 characters\)
sed "s/^X//" >'newdisp.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** newgroups.c - display list of new groups since user's last ession.
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include "config.h"
X#include "tty.h"
X#include "node.h"
X
Xextern NODE **Newsorder;
Xextern int Ncount, Lrec, C_allow;
X
Xnew_groups ()
X{
X	int i,wrem,w;
X	int max;
X	char fs[24],c_end;
X
X	max = 0;
X	for (i=0; i < Ncount; ++i)
X		if (((Newsorder[i])->flags & FLG_NEW) != 0 &&
X				(w = strlen((Newsorder[i])->nd_name)) > max)
X			max = w;
X	sprintf (fs,"%%-%ds%%c",max);
X
X	if (max <= 0)
X		return (0);
X
X	term_set (ERASE);
X	printf ("New newsgroups:\n");
X
X	wrem = C_allow;
X	for (i=0; i < Ncount; ++i)
X	{
X		if (((Newsorder[i])->flags & FLG_NEW) == 0)
X			continue;
X		if ((wrem -= max) < max)
X		{
X			wrem = C_allow;
X			c_end = '\n';
X		}
X		else
X			c_end = ' ';
X		printf (fs,(Newsorder[i])->nd_name,c_end);
X	}
X	if (c_end != '\n')
X		putchar ('\n');
X
X	return (1);
X}
END_OF_FILE
if test 920 -ne `wc -c <'newdisp.c'`; then
    echo shar: \"'newdisp.c'\" unpacked with wrong size!
fi
# end of 'newdisp.c'
fi
if test -f 'node.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'node.h'\"
else
echo shar: Extracting \"'node.h'\" \(1580 characters\)
sed "s/^X//" >'node.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** node.h - NODE structure
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X/* newsgroup status flags */
X#define FLG_SUB 1	/* user subscribed to newsgroup */
X#define FLG_PAGE 2	/* a page exists to display */
X#define FLG_NEW 4	/* new newsgroup */
X#define FLG_ECHG 8	/* edit change by user */
X#define FLG_SEARCH 16	/* newsgroup was searched */
X#define FLG_ACC 32	/* newsgroup had articles accessed */
X#define FLG_STAT 64	/* stat's written */
X
X/*
X	newsgroup information (hash table node)
X
X	items unaccessed by server interface:
X		next - hashtable link
X		pnum - page number
X		pages - number of pages for news display
X		pgshwn - pages shown mask
X		pgrd - article number on highest conecutively shown page
X		order - order of appearance in Newsorder array.
X		orgrd - original articles read number
X
X	may be read following hashfind by server interface, but not written:
X		nd_name - name of newsgroup (key to reach node by)
X			this will be a permanent copy of the name.
X		highnum - high article number in group
X		lownum - low article number in group
X
X	legal for vns_write to read, but not written by server interface:
X		flags - bit mask of FLG_xxxx flags.
X		rdnum - articles read.
X
X	unused by vn user interface, intended for use by server interface:
X		state - state variable.  initted 0.
X		data - arbitrary data pointer.  initted NULL.
X*/
Xtypedef struct _node
X{
X	struct _node *next;
X	char *nd_name;
X	int highnum, lownum;
X	int pnum, pages, rdnum, orgrd, pgrd;
X	unsigned long pgshwn;
X	unsigned flags;
X	int order;
X	unsigned state;
X	char *data;
X} NODE;
END_OF_FILE
if test 1580 -ne `wc -c <'node.h'`; then
    echo shar: \"'node.h'\" unpacked with wrong size!
fi
# end of 'node.h'
fi
if test -f 'page.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'page.h'\"
else
echo shar: Extracting \"'page.h'\" \(1152 characters\)
sed "s/^X//" >'page.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** page.h - display page structure
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X/*
X	page display format and dependent parameters
X*/
X#define HFORMAT "\n%s (page %d of %d):"
X#define DHFORMAT "\n%s (DIGEST EXTRACTION):"
X#define TFORMAT "%s ~ %s %s"
X#define AFORMAT "\n%c%c%d) "	/* begin with newline - see show routine */
X#define AFLEN 5		/* min. char. in article id - depends on AFORMAT */
X#define CFORMAT "page %d of %d (%d shown), newsgroup %d of %d"
X#define RECBIAS 2	/* lines before articles - depends on HFORMAT */
X#define WRCOL 1		/* column of written mark.  depends on AFORMAT */
X#define INFOLINE 0	/* HFORMAT TFORMAT leaves for use */
X#define REQLINES 7	/* required terminal lines for display, incl. help */
X
X/*
X	newsgroup information for page display
X	name - of group
X	group - pointer to table entry
X	artnum - number of articles
X*/
Xtypedef struct
X{
X	char *name;
X	NODE *group;
X	int artnum;
X} HEAD;
X
X/*
X	article information - id (spool) number, title string, mark, written.
X*/
Xtypedef struct
X{
X	int art_id;
X	char art_mark;
X	char art_t[MAX_C-AFLEN];
X} BODY;
X
Xtypedef struct
X{
X	HEAD h;
X	BODY *b;
X} PAGE;
END_OF_FILE
if test 1152 -ne `wc -c <'page.h'`; then
    echo shar: \"'page.h'\" unpacked with wrong size!
fi
# end of 'page.h'
fi
if test -f 'pagefile.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pagefile.c'\"
else
echo shar: Extracting \"'pagefile.c'\" \(4360 characters\)
sed "s/^X//" >'pagefile.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** pagefile.c - routines to deal with page display tempfile
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef SYSV
X#include <sys/types.h>
X#include <fcntl.h>
X#endif
X
X#ifndef	MINIX
X#include <sys/file.h>
X#endif
X
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X
Xextern int Ncount,Lrec,L_allow,Cur_page,C_allow;
Xextern NODE **Newsorder;
Xextern PAGE Page;
Xextern int Digest;
X
Xextern char *Aformat;
X
Xextern char *T_head, *F_head, *L_head;
X
Xstatic int Tdes;	/* temp file descriptor */
Xstatic int Pgsize;	/* block size for seeking file */
X
Xstatic NODE *Curgp = NULL;	/* current newsgroup being written */
Xstatic int Order = 0;		/* order counter */
X
X/*
X	routines which deal with the temp file containing
X	display pages.  Note the "invisible" file feature -
X	tempfile is unlinked from /usr/tmp immediately.  when
X	Tdes is closed by UNIX the disk space will be given back.
X*/
X
Xtemp_open ()
X{
X	char tmpart [L_tmpnam];
X	Lrec = -1;
X	tmpnam (tmpart);
X	Pgsize = sizeof (HEAD) + L_allow * sizeof(BODY);
X
X#ifdef	MINIX
X	/* Minix doesn'h have O_CREAT or 3-argument open */
X	if ((Tdes = open(tmpart,O_RDWR)) < 0) {
X		creat(tmpart,0644);
X		if ((Tdes = open(tmpart,O_RDWR)) < 0)
X			printex ("can't open %s",tmpart);
X	}
X#else
X	if ((Tdes = open(tmpart,O_RDWR|O_CREAT,0600)) < 0)
X		printex ("can't open %s",tmpart);
X#endif
X
X	unlink (tmpart);
X}
X
X/*
X** set newsgroup for tempfile write
X*/
Xfw_group(ng,new,sub,rd,look)
Xchar *ng;
Xint new;
Xint sub;
Xint rd;
Xint look;
X{
X	NODE *hashfind();
X
X	if (Curgp != NULL && Page.h.artnum > 0)
X		fw_flush();
X	
X	if ((Curgp = hashfind(ng)) == NULL)
X		printex("fw_group - non-existent newsgroup, \"%s\"",ng);
X	if (Curgp->order >= 0)
X		printex("fw_group - repeat call on newsgroup, \"%s\"",ng);
X	Curgp->order = Order;
X	++Order;
X	fw_chg(new,sub,rd,look);
X	Curgp->pages = 0;
X	Curgp->pnum = Lrec+1;
X	Page.h.name = Curgp->nd_name;
X	Page.h.group = Curgp;
X	Page.h.artnum = 0;
X}
X
Xfw_chg(new,sub,rd,look)
Xint new;
Xint sub;
Xint rd;
Xint look;
X{
X	Curgp->flags &= ~(FLG_NEW|FLG_SUB|FLG_SEARCH);
X	if (new)
X		Curgp->flags |= FLG_NEW;
X	if (sub)
X		Curgp->flags |= FLG_SUB;
X	if (look)
X		Curgp->flags |= FLG_SEARCH;
X	Curgp->rdnum = Curgp->orgrd = Curgp->pgrd = rd;
X}
X
X/*
X** write article to temp file.
X*/
Xfw_art(anum,subj,lines,author)
Xint anum;
Xchar *subj;
Xchar *lines;
Xchar *author;
X{
X	char tbuf[RECLEN];
X	int idx;
X
X	form_title(tbuf,subj,lines,author,anum);
X	idx = Page.h.artnum;
X	strcpy((Page.b)[idx].art_t, tbuf);
X	(Page.b)[idx].art_id = anum;
X	(Page.b)[idx].art_mark = ' ';
X
X	++(Page.h.artnum);
X	if (Page.h.artnum >= L_allow)
X		fw_flush();
X}
X
Xfw_done()
X{
X	if (Curgp != NULL && Page.h.artnum > 0)
X	{
X		/* correct if server was lying at fw_group() */
X		Curgp->flags |= FLG_SEARCH;
X		fw_flush();
X	}
X}
X
Xstatic
Xfw_flush()
X{
X	++(Curgp->pages);
X	++Lrec;
X	Curgp->flags |= FLG_PAGE;
X	do_write();
X	Page.h.artnum = 0;
X}
X
Xfind_page (n)
Xint n;
X{
X	long off,lseek();
X	int i,last;
X	Cur_page = n;
X	off = Pgsize;
X	off *= (long) n;
X	lseek (Tdes, off, 0);
X	if (read(Tdes, (char *) &(Page.h), sizeof(HEAD)) < sizeof(HEAD))
X		printex("bad temp file read");
X	i = Pgsize - sizeof(HEAD);
X	if (read(Tdes, (char *) Page.b, i) < i)
X		printex("bad temp file read");
X	last = -1;
X	for (i=0; i < Ncount; ++i)
X	{
X		if ((Newsorder[i])->pages > 0)
X		{
X			if ((Newsorder[i])->pnum > n)
X				break;
X			last = i;
X		}
X	}
X	if (last < 0)
X		printex ("can't find page %d",n);
X	Page.h.group = Newsorder[last];
X	Page.h.name = (Page.h.group)->nd_name;
X	vns_gset(Page.h.name);
X}
X
Xwrite_page ()
X{
X	long off,lseek();
X	if (!Digest)
X	{
X		off = Pgsize;
X		off *= (long) Cur_page;
X		lseek (Tdes, off, 0);
X		do_write();
X	}
X}
X
Xstatic do_write()
X{
X	int num;
X
X	if (write(Tdes, (char *) &(Page.h), sizeof(HEAD)) < sizeof(HEAD))
X		printex ("Bad temp file write");
X	num = L_allow * sizeof(BODY);
X	if (write(Tdes, (char *) Page.b, num) < num)
X		printex ("Bad temp file write");
X}
X
Xform_title (t,fn,fl,ff,n)
Xchar *t,*fn,*fl,*ff;
Xint n;
X{
X	char *ptr,*index();
X	int i;
X
X	if ((ptr = index(ff,'(')) != NULL && strlen(ptr) > 3)
X		ff = ptr;
X	sprintf (t,TFORMAT,fn,fl,ff);
X	sprintf(ff,Aformat,' ',' ',n);
X	i = C_allow - strlen(ff) + 1;	/* remember newline in Aformat */
X	t[i] = '\0';
X	ctl_xlt(t);
X	return (0);
X}
X
X/* replace control characters in titles */
Xstatic ctl_xlt(s)
Xchar *s;
X{
X	while (*s != '\0')
X	{
X		if (iscntrl(*s))
X			*s = '?';
X		++s;
X	}
X}
END_OF_FILE
if test 4360 -ne `wc -c <'pagefile.c'`; then
    echo shar: \"'pagefile.c'\" unpacked with wrong size!
fi
# end of 'pagefile.c'
fi
if test -f 'printex.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'printex.c'\"
else
echo shar: Extracting \"'printex.c'\" \(760 characters\)
sed "s/^X//" >'printex.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** printex.c - print fatal error message and exit.
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X#include <stdio.h>
X#include <setjmp.h>
X#include "config.h"
X#include "tty.h"
X
Xextern int errno;	/* unix error number */
X
X/*
X	error/abnormal condition cleanup and abort routine
X	pass stack to printf
X*/
Xprintex (s,a,b,c,d,e,f)
Xchar *s;
Xlong a,b,c,d,e,f;
X{
X	static int topflag=0;
X	if (topflag == 0)
X	{
X		++topflag;
X		term_set (STOP);
X#ifndef	MINIX
X		tty_set (COOKED);
X#else
X/* COOKED is defined in Minix! */
X		tty_set (XCOOKED);
X#endif
X		fflush (stdout);
X		fprintf (stderr,s,a,b,c,d,e,f);
X		fprintf (stderr," (error code %d)\n",errno);
X		vns_exit(1);
X		stat_end(-1);
X		exit (1);
X	}
X	else
X		fprintf (stderr,s,a,b,c,d,e,f);
X}
END_OF_FILE
if test 760 -ne `wc -c <'printex.c'`; then
    echo shar: \"'printex.c'\" unpacked with wrong size!
fi
# end of 'printex.c'
fi
if test -f 'reader.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader.c'\"
else
echo shar: Extracting \"'reader.c'\" \(16175 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 "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#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
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			printf(any);
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			printf(any);
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			printf(any);
X			getnoctl();
X			sig_set(BRK_RFIN);
X			return (0);
X		}
X		Rew_pos = ftell(Fpread);
X	}
X
X	Hlines = hdr.hlines;
X	printf (ANFORM,Fname,Cxrtoi[PG_HELP]);
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	printf("%s\015",prompt);
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				printf("%s\n",mbuf);
X			}
X			term_set (ONREVERSE);
X			printf("%s\015",prompt);
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				printf ("%s\n",Roton_msg);
X			}
X			else
X			{
X				Rot = 0;
X				printf ("%s\n",Rotoff_msg);
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				printf ("%s\n",Hdoff_msg);
X			}
X			else
X			{
X				Headflag = TRUE;
X				printf ("%s\n",Hdon_msg);
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		printf("%s\015",prompt);
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		printf("%s\n",msg);
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
Xmail (hdr)
XARTHEADER *hdr;
X{
X	char *new, fn[L_tmpnam], cmd [RECLEN+60], *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			printf ("given to mailer\n");
X		}
X		else
X			(*Mailfunc)(hdr,fn);
X	}
X	else
X		printf ("not mailed\n");
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
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			printf ("given to posting program\n");
X		}
X		else
X			(*Postfunc)(hdr,fn);
X		save2_article (fn);
X	}
X	else
X		printf ("not posted\n");
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	printf("%s",s);
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				printf("%s\n",start);
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		printf("%s\n",start);
X		start = s;
X		*s = cs;
X	}
X	Lookahead = start;
X	return(lim);
X}
X
Xstatic
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	printf ("a copy has been saved in %s\n", Ccfile);
X}
X
X/*
X	send article to printer
X*/
Xstatic
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	printf("Sent to printer\n");
X	sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
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
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	printf("\n ");
X	printf(s,a,b,c,d,e);
X	printf(" \07\n");
X	term_set (OFFREVERSE);
X}
END_OF_FILE
if test 16175 -ne `wc -c <'reader.c'`; then
    echo shar: \"'reader.c'\" unpacked with wrong size!
fi
# end of 'reader.c'
fi
if test -f 'reader.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reader.h'\"
else
echo shar: Extracting \"'reader.h'\" \(1537 characters\)
sed "s/^X//" >'reader.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** reader.h - article reading interface definitions
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#define PAGE_MID ":more (%2d%%):"
X#define PAGE_NEXT ":next article:"
X#define PAGE_END ":end:"
X#define PAGE_NO ":?:"
X#define PPR_MAX 18	/* maximum length of PAGE prompts */
X
X/*
X	reading commands: no control chars, add help message to helppg
X	SAVE, PRINT, HEADTOG and SETROT are also recognized
X*/
X#define HPG_HEAD "toggle header print flag"
X#define HPG_ROT "toggle rotation"
X#define HPG_SAVE "save article in a file"
X#define HPG_PRINT "print article"
X#define PG_NEXT 'n'
X#define HPG_NEXT "next article, if any"
X#define PG_QUIT 'q'
X#define HPG_QUIT "quit reading articles, if any more to read"
X#define PG_FLIP 'Q'
X#define HPG_FLIP "quit reading, and turn to next page of articles"
X#define PG_FOLLOW 'f'
X#define HPG_FOLLOW "post followup to article"
X#define PG_REPLY 'm'
X#define HPG_REPLY "send mail to author of article"
X#define PG_HELP '?'
X#define HPG_HELP "see this help menu"
X#define PG_REWIND 'r'
X#define HPG_REWIND "rewind article to beginning"
X#define PG_WIND 'e'
X#define HPG_WIND "seek to end of article (to next/end prompt)"
X#define PG_STEP '\n'
X#define HPG_STEP "next line"
X#define PG_SEARCH '/'
X#define HPG_SEARCH "search for regular expression in remainder of article"
X#define SEARCHFORM "search pattern (%s) ? "
X#define HPG_DEF "\n anything else to continue normal reading"
X#define HPG_EDEF "\n anything else to try reading next article, if any"
X
X#define ANFORM ":%s - %c for help:\n"
END_OF_FILE
if test 1537 -ne `wc -c <'reader.h'`; then
    echo shar: \"'reader.h'\" unpacked with wrong size!
fi
# end of 'reader.h'
fi
if test -f 'reg.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'reg.c'\"
else
echo shar: Extracting \"'reg.c'\" \(1656 characters\)
sed "s/^X//" >'reg.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** reg.c - implementation of regex / regcmp on top of UCB library
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X
X#define RGBLKSIZE 20
X
Xstruct _regtab
X{
X	struct _regtab *link;
X	char *regstr;
X};
X
Xtypedef struct _regtab REGTAB;
X
Xstatic REGTAB *Chain = NULL;
Xstatic REGTAB *Free = NULL;
Xstatic REGTAB *Compiled = NULL;
X
Xregfree(s)
Xchar *s;
X{
X	REGTAB *ptr,*cmp,*old;
X
X	cmp = (REGTAB *) s;
X	old = NULL;
X
X	for (ptr = Chain; ptr != NULL; ptr = (old = ptr)->link)
X	{
X		if (ptr == cmp)
X		{
X			if (old == NULL)
X				Chain = Chain->link;
X			else
X				old->link = ptr->link;
X			ptr->link = Free;
X			Free = ptr;
X			break;
X		}
X	}
X}
X
Xchar *regcmp(str)
Xchar *str;
X{
X	int i;
X	char *str_store();
X	char *re_comp();
X
X	if (re_comp(str) != NULL)
X	{
X		Compiled = NULL;	/* make sure we're OK */
X		return(NULL);
X	}
X
X	if (Free == NULL)
X	{
X		Free = (REGTAB *) malloc(RGBLKSIZE * sizeof(REGTAB));
X		if (Free == NULL)
X			printex ("regcmp: memory allocation failure");
X		for (i = 0; i < RGBLKSIZE - 1; ++i)
X			Free[i].link = Free + i + 1;
X		Free[i].link = NULL;
X	}
X
X	Compiled = Free;
X	Free = Free->link;
X
X	Compiled->link = Chain;
X	Chain = Compiled;
X	Compiled->regstr = str_store(str);
X
X	return ((char *) Compiled);
X}
X
Xchar *regex(reg,str)
Xchar *reg,*str;
X{
X	REGTAB *cmp;
X
X	cmp = (REGTAB *) reg;
X
X	if (cmp == Compiled)
X	{
X		if (re_exec(str))
X			return(str);
X		return (NULL);
X	}
X
X	for (Compiled = Chain; Compiled != NULL; Compiled = Compiled->link)
X	{
X		if (Compiled == cmp)
X			break;
X	}
X
X	if (Compiled == NULL)
X		printex ("regex: bad pointer");
X
X	re_comp(Compiled->regstr);
X
X	if (re_exec(str))
X		return(str);
X
X	return(NULL);
X}
END_OF_FILE
if test 1656 -ne `wc -c <'reg.c'`; then
    echo shar: \"'reg.c'\" unpacked with wrong size!
fi
# end of 'reg.c'
fi
if test -f 'regcompat.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'regcompat.c'\"
else
echo shar: Extracting \"'regcompat.c'\" \(1093 characters\)
sed "s/^X//" >'regcompat.c' <<'END_OF_FILE'
X/* regcompat.c */
X/* file: regcompat.c
X** author: Peter S. Housel 11/21/88
X** Compatibility routines for regular expressions. more.c uses the
X** re_comp() and re_exec() routines, while Minix only has regcomp() and
X** regexec() (from Henry Spencer's freely redistributable regexp package).
X** Note that the third argument to regexec() is a beginning-of-line flag
X** and was probably added by Andrew Tannenbaum. It will probably be ignored
X** if your copy of the regexp routines only expects two args.
X**/
X
X#include <regexp.h>
X/* following just for debugging #define NULL	0 */
X#include <stdio.h>
X
Xstatic regexp *re_exp = NULL;	/* currently compiled regular expression */
Xstatic char *re_err = NULL;	/* current regexp error */
X
Xchar *re_comp(str)
Xchar *str;
X{
X if(str == NULL)
X    return NULL;
X
X if(re_exp != NULL)
X    free(re_exp);
X
X if((re_exp = regcomp(str)) != NULL)
X    return NULL;
X
X return re_err != NULL ? re_err : "string didn't compile";
X}
X
Xint re_exec(str)
Xchar *str;
X{
X if(re_exp == NULL)
X    return -1;
X return regexec(re_exp, str, 1);
X}
X
Xregerror(str)
Xchar *str;
X{
X re_err = str;
X}
END_OF_FILE
if test 1093 -ne `wc -c <'regcompat.c'`; then
    echo shar: \"'regcompat.c'\" unpacked with wrong size!
fi
# end of 'regcompat.c'
fi
echo shar: End of shell archive.
exit 0
-- 
			"Zeta Microcomputer Software"
ACSnet:    nick@nswitgould.cs.uts.oz	nick@ultima.cs.uts.oz
UUCP:      ...!uunet!munnari!ultima.cs.uts.oz!nick
Fidonet:   Nick Andrew on 3:713/602 (Zeta)