v08i066: The VN news reader, Part03/03

sources-request at mirror.UUCP sources-request at mirror.UUCP
Wed Feb 18 10:19:24 AEST 1987


Submitted by: rtech!rtech!bobm (Bob Mcqueer)
Mod.sources: Volume 8, Issue 66
Archive-name: vn/Part03

#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
# If all goes well, you will see the message "End of archive 3 (of 3)."
# Contents:  vn.c vn.man
# Wrapped by rs at mirror on Tue Feb 17 12:10:41 1987
PATH=/bin:/usr/bin:/usr/ucb; export PATH
echo shar: extracting "'vn.c'" '(25993 characters)'
if test -f 'vn.c' ; then 
  echo shar: will not over-write existing file "'vn.c'"
else
sed 's/^X//' >vn.c <<'@//E*O*F vn.c//'
X/*
Xvn news reader for visual page oriented display of news
Xaimed at scanning large numbers of articles.
X
XOriginal program by Bob McQueer in several versions 1983-1986.  Released
Xinto the public domain in 1986.  While no copyright notice appears, the
Xoriginal author asks that a history of changes crediting the proper people
Xbe maintained.
X
XBob McQueer
X{amdahl, sun, mtxinu, hoptoad, cpsc6a}!rtech!bobm
X
XHistory:
X
X	(bobm at rtech) 5/86 - first "public" version
X
X	(bobm at rtech) 12/86 - version incorporates:
X
X		bug fixes:
X			str_store NULL string bug
X			not picking up first article in newsgroup
X			RESTART terminal reset for exit to editor.
X			skip whitespace in "empty" digest lines while unpacking
X			DISTRIBUTION line in followups.
X			:100%: prompt on last line in reader.
X			interpretation of multiple negations -w -t options.
X
X			Many thanks to several people who noted the first
X			two bugs as well as fixes.
X
X			Thank you to Karl Williamson for helpful information
X			tracking down the "concept terminal" bug (RESTART).
X
X		SYSV ifdef's adapted from those done by Larry Tepper
X		at ATT Denver - sent in by Karl Williamson, drutx!khw.
X		Many people submitted SYSV ifdef's - thank you all.
X
X		print capability from reader from Karl Williamson,
X		drutx!khw
X
X		Changes to use alternate header lines for mail, from changes
X		by Andy Marrinson, andy at icom.UUCP (ihnp4!icom!andy).  Ifdef'ed
X		to allow local configuration (bobm at rtech).
X
X		"author_copy" file for followups, prevention of multiple
X		"re: "'s, insert blank line and original author line
X		before excerpted text from Andy Marrinson, andy at icom.UUCP
X
X		Search string capability in reader, from Lawrie Brown,
X		seismo!munnari!cdsadfa.oz!lpb (Australia).  Somewhat
X		modified by interaction with the :100%: bug.
X
X		Arrow key support, adapted from changes by Lawrie Brown.
X		Modified to simply not allow control keys for arrows (allowing
X		SOME controls is too prone to problems, esp. with .vnkey), and
X		to allow the PAGEARROW ifdef (bobm at rtech)
X
X		prevention of followups to "mod" and "announce", from
X		Lawrie Brown.
X
X		OLDRC ifdef adapted from changes by Lawrie Brown.  ADDRMUNGE
X		added to allow OZ domain addressing changes from Australia
X		to be grafted back in, and provide a hook for anybody else
X		wanting to do something similar.
X
X		Bob McQueer, bobm at rtech:
X
X			a menu selection from the % command to jump to
X			a new newsgroup
X
X			linked list on hash table - no longer a compiled
X			in limit for number of newsgroups
X
X			.vnkey keystroke mapping file.
X
X			options to get the % command list on entry, and to
X			change how unsubscribed groups are handled for updates.
X
X			allow configurable use of vs / ve pair for terminal
X			handling.
X
XKnown bugs:
X
X	non-erasure of stuff on prompt line when the new
X	string includes an escape sequence (like PS1 maybe)
X	because it doesn't realize that the escape sequence
X	won't overprint the existing stuff
X
X	control-w and update on exit may not update pages which have been
X	scanned in funny orders by jumping into the middle of groups
X
X	inaccurate numbers on '%' command results - reflect ranges, not
X	actual numbers of articles.
X
X	no arrow keys recognized which don't begin with <escape>
X
X	doesn't know about the version 2.11 'm' in active list, or
X	use the 'y' / 'n' either.
X
X	crash due to embedding $\(\) type substring specifiers in regular
X	expressions.  Obscure and hard to fix in a proper and portable way.
X*/
X#include <stdio.h>
X#include <setjmp.h>
X#include "config.h"
X#include "tty.h"
X#include "vn.h"
X
X/* UNIX error number */
Xextern int errno;
X
Xextern NODE **Newsorder;
Xextern char Erasekey, Killkey;
Xextern int Rot;
Xextern char *Ps1,*Printer;
Xextern char *Orgdir,*Savefile,*Savedir;
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[];
X
Xextern char *Aformat;
X
Xextern char *Contstr;
X
Xextern char *Kl,*Kr,*Ku,*Kd;
X
Xextern int Nounsub, Listfirst;
X
Xstatic int C_info;
Xstatic int Dskip, Drec;
X
Xstatic char *Unsub_msg = "Unsubscribed";
Xstatic char *Egroup_msg = "Entire newsgroup";
X
X/*
X	Help message table.  Character for command, plus its help
X	message.  Table order is order of presentation to user.
X*/
Xstatic struct HELPTAB
X{
X	char cmd, *msg;
X	int dig;
X	char *amsg;
X} 
XHelptab [] =
X{
X	{ QUIT, "quit", 1, NULL},
X	{ UP, "(or up arrow) move up [number of lines]", 1, NULL},
X	{ DOWN, "(or down arrow) move down [number of lines]", 1, NULL},
X#ifdef PAGEARROW
X	{ BACK, "(or left arrow) previous page [number of pages]", 1, NULL},
X	{ FORWARD, "(or right arrow) next page [number of pages]", 1, NULL},
X#else
X	{ BACK, "previous page [number of pages]", 1, NULL},
X	{ FORWARD, "next page [number of pages]", 1, NULL},
X#endif
X	{ DIGEST, "unpack digest", 1, "exit digest"},
X	{ READ, "read article [number of articles]", 1, NULL},
X	{ ALTREAD, "read article (alternate 'r')", 1, NULL},
X	{ READALL, "read all articles on page", 1, NULL},
X	{ READSTRING, "specify articles to read", 1, NULL},
X	{ SAVE, "save or pipe article [number of articles]", 1, NULL},
X	{ SAVEALL, "save or pipe all articles on page", 1, NULL},
X	{ SAVESTRING, "specify articles to save", 1, NULL},
X	{ ALTSAVE, "specify articles to save (alternate ctl-s)", 1, NULL},
X	{ PRINT, "print article [number of articles]", 1, NULL},
X	{ PRINTALL, "print all article on page", 1, NULL},
X	{ PRINTSTRING, "specify articles to print", 1, NULL},
X	{ UPDATE, "update .newsrc status to cursor", 0, NULL},
X	{ UPALL, "update .newsrc status for whole newsgroup", 0, NULL},
X	{ UPSEEN, "update .newsrc status for all pages displayed", 0, NULL},
X	{ ORGGRP, "recover original .newsrc status for newsgroup", 0, NULL},
X	{ ORGSTAT, "recover all original .newsrc status", 0, NULL},
X	{ SSTAT, "display count of groups and pages - shown and total", 0, NULL},
X	{ GRPLIST, "list newsgroups with new article, updated counts", 0, NULL},
X	{ NEWGROUP, "specify newsgroup to display and/or resubscribe to", 1, NULL},
X	{ UNSUBSCRIBE, "unsubscribe from group", 0, NULL},
X	{ MARK, "mark/unmark article [number of articles]", 1, NULL},
X	{ ART_MARK, "mark/unmark article [number of articles]", 1, NULL},
X	{ UNMARK, "erase marks on articles", 1, NULL},
X	{ HEADTOG, "toggle flag for display of headers when reading", 1, NULL},
X	{ SETROT, "toggle rotation for reading", 1, NULL},
X	{ REDRAW, "redraw screen", 1, NULL},
X	{ UNESC, "escape to UNIX to execute a command", 1, NULL},
X	{ HELP, "show this help menu", 1, NULL}
X};
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X	/*
X		initialize environment variables,
X		scan .newsrc file, using any command line options present.
X	 */
X	term_set (START);
X	envir_set ();
X	sig_set (BRK_IN);
X
X	scan_newsrc (argc-1,argv+1);
X	tty_set (BACKSTOP);
X
X	if (Lrec >= 0)
X		session ();
X	else
X	{
X		new_groups ();
X		fprintf (stderr,"\nNo News\n");
X	}
X
X	tty_set (COOKED);
X	wr_newsrc ();
X	term_set (STOP);
X}
X
X/*
X	main session handler processing input commands
X	locals:
X		count - count attached to command
X		highrec - highest line on current page
X		crec - current line
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, highrec, crec;
X	jmp_buf brkbuf;
X
X	tty_set (RAWMODE);
X	newg = new_groups();
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		printf ("\n%s",Contstr);
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(&crec,&highrec);
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		for (i=0; i < (j = sizeof(Helptab)/sizeof(struct HELPTAB)); ++i)
X			if (Helptab[i].cmd == c)
X				break;
X
X		if (i >= j || (Digest && !Helptab[i].dig))
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 (&crec,&highrec);
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			(Page.h.group)->state &= ~FLG_SUB;
X			wr_newsrc ();
X			prinfo (Unsub_msg);
X			term_set (MOVE,0,crec);
X			break;
X
X		case UPDATE:
X			(Page.h.group)->rdnum = Page.b[crec-RECBIAS].art_id;
X			wr_show ();
X			wr_newsrc();
X			term_set (MOVE,0,crec);
X			break;
X		case UPALL:
X			(Page.h.group)->rdnum = (Page.h.group)->art;
X			wr_newsrc();
X			wr_show();
X			prinfo (Egroup_msg);
X			term_set (MOVE,0,crec);
X			break;
X		case ORGGRP:
X			(Page.h.group)->rdnum = (Page.h.group)->orgrd;
X			wr_newsrc();
X			wr_show();
X			prinfo (Egroup_msg);
X			term_set (MOVE,0,crec);
X			break;
X		case UPSEEN:
X			up_seen();
X			prinfo ("All pages displayed to this point updated");
X			wr_show();
X			wr_newsrc();
X			term_set (MOVE,0,crec);
X			break;
X		case ORGSTAT:
X			for (i = 0; i < Ncount; ++i)
X				(Newsorder[i])->rdnum = (Newsorder[i])->orgrd;
X			prinfo ("Original data recovered");
X			wr_show();
X			wr_newsrc();
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 MARK:
X		case ART_MARK:
X			count += crec - 1;
X			if (count >= highrec)
X				count = highrec - 1;
X			for (i=crec; i <= count; ++i)
X			{
X				if (Page.b[i-RECBIAS].art_mark != ART_MARK)
X					Page.b[i-RECBIAS].art_mark = ART_MARK;
X				else
X					Page.b[i-RECBIAS].art_mark = ' ';
X				if (i != crec)
X					term_set (MOVE, 0, i);
X				printf ("%c\010",Page.b[i-RECBIAS].art_mark);
X			}
X			if (count != crec)
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 == ART_MARK)
X				{
X					Page.b[i].art_mark = ' ';
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, &crec, &highrec) >= 0)
X				show();
X			else
X				preinfo ("No more pages");
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			Dskip = count - 1;
X			Drec = crec - RECBIAS;
X			if (digest_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			genlist (alist,crec-RECBIAS,count);
X			savestr (alist);
X			term_set (MOVE,0,crec);
X			break;
X		case SAVEALL:
X			genlist (alist,0,L_allow);
X			savestr (alist);
X			term_set (MOVE,0,crec);
X			break;
X		case SAVESTRING:
X		case ALTSAVE:
X			userlist (alist);
X			savestr (alist);
X			term_set (MOVE,0,crec);
X			break;
X		case READ:
X		case ALTREAD:
X			genlist (alist,crec-RECBIAS,count);
X			readstr (alist,&crec,&highrec,count);
X			break;
X		case READALL:
X			genlist (alist,0,L_allow);
X			readstr (alist,&crec,&highrec,0);
X			break;
X		case READSTRING:
X			userlist (alist);
X			readstr (alist,&crec,&highrec,0);
X			break;
X		case PRINT:
X			genlist (alist,crec-RECBIAS,count);
X			printstr (alist);
X			term_set (MOVE,0,crec);
X			break;
X		case PRINTALL:
X			genlist (alist,0,L_allow);
X			printstr (alist);
X			term_set (MOVE, 0, crec);
X			break;
X		case PRINTSTRING:
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			fflush (stdout);
X			tty_set (SAVEMODE);
X			if (chdir(Orgdir) < 0)
X				printf ("change to original directory, %s, failed",Orgdir);
X			else
X			{
X				system (alist);
X				tty_set (RESTORE);
X				term_set (RESTART);
X			}
X			printf (Contstr);
X			getnoctl ();
X			cd_group ();
X			show ();
X			term_set (MOVE, 0, crec);
X			break;
X		default:
X			printex ("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 ? ",1);
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])->state & FLG_SUB) == 0)
X		{
X			(Newsorder[i])->rdnum = (Newsorder[i])->art;
X			continue;
X		}
X		if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
X			(Newsorder[i])->rdnum = (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])->state & 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 to allow it to happen globally.
X	(from readstr, for instance)
X*/
Xforward (count, crec, highrec)
Xint count, *crec, *highrec;
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 (digest_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	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		tty_set (COOKED);
X		fflush (stdout);
X		fprintf (stderr,s,a,b,c,d,e,f);
X		fprintf (stderr," (error code %d)\n",errno);
X		exit (1);
X	}
X	else
X		fprintf (stderr,s,a,b,c,d,e,f);
X}
X
X/*
X	getkey obtains user keystroke with count from leading
X	numerics, if any.  Picks up arrow key sequences and maps
X	them to other keys.  Also translates character through
X	Cxitop array since this routine is only used in session
X	loop.  Saves untranslating arrow keys.
X*/
Xgetkey (c)
Xchar *c;
X{
X	int i, j;
X	static char	ckseq[32];
X
X	/* Check for leading count */
X	for (i = 0; (*c = getchar() & 0x7f) >= '0' && *c <= '9'; i = i * 10 + *c - '0')
X		;
X
X	/* @#$!!! flakey front ends that won't map newlines in raw mode */
X	if (*c == '\012' || *c == '\015')
X		*c = '\n';
X
X	/* @#$!!! flakey terminals which send control sequences for cursors! */
X	if( *c == '\033' )
X	{
X		/*
X		** Check if part of cursor key input sequence
X		** (pitch unknown escape sequences)
X		*/
X		j = 0;
X		ckseq[j] = *c; ckseq[j+1] = '\0';
X		while(*c == Ku[j] || *c == Kd[j] || *c == Kl[j] || *c == Kr[j])
X		{
X			if( strcmp(ckseq, Ku) == 0 ) { *c = UP; break; }
X			if( strcmp(ckseq, Kd) == 0 ) { *c = DOWN; break; }
X#ifdef PAGEARROW
X			if( strcmp(ckseq, Kl) == 0 ) { *c = BACK; break; }
X			if( strcmp(ckseq, Kr) == 0 ) { *c = FORWARD; break; }
X#else
X			if( strcmp(ckseq, Kl) == 0 ) { *c = UP; break; }
X			if( strcmp(ckseq, Kr) == 0 ) { *c = DOWN; break; }
X#endif
X			*c = (getchar() & 0x7f);
X			ckseq[++j] = *c; ckseq[j+1] = '\0';
X		}
X	}
X	else
X		*c = Cxitop[*c];
X
X	if (i <= 0)
X		i = 1;
X	return (i);
X}
X
X
X/*
X	get user key ignoring most controls
X*/
Xgetnoctl ()
X{
X	char c;
X	while ((c = getchar() & 0x7f) < ' ' || c == '\177')
X	{
X		if (c == '\015' || c == '\012')
X			c = '\n';
X		if (c == '\n' || c == '\b' || c == '\t')
X			return (c);
X	}
X	return ((int) c);
X}
X
X/*
X	generate list of articles on current page,
X	count articles, starting with first.
X*/
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*/
Xprintstr (s)
Xchar *s;
X{
X	char *ptr, cmd [RECLEN], *strpbrk();
X	prinfo ("preparing print command ....");
X	for (ptr = s; (ptr = strpbrk(ptr, LIST_SEP)) != NULL; ++ptr)
X		*ptr = ' ';
X	while (*s == ' ')
X		++s;
X	if (Digest)
X		dig_list (s);
X	if (*s != '\0')
X	{
X		sprintf (cmd,"%s %s 2>/dev/null",Printer,s);
X		if (system (cmd) == 0)
X			prinfo ("Sent to printer");
X		else
X			preinfo ("Print failed");
X	}
X	else
X		preinfo (No_msg);
X	if (Digest)
X		dig_ulist (s);
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*/
Xsavestr (s)
Xchar *s;
X{
X	char *ptr, cmd [RECLEN], newfile [MAX_C+1], prompt[MAX_C];
X	char *strtok(), *strpbrk(), *str_store();
X
X	for (ptr = s; (ptr = strpbrk(ptr, LIST_SEP)) != NULL; ++ptr)
X		*ptr = ' ';
X	while (*s == ' ')
X		++s;
X	if (Digest)
X		dig_list (s);
X	if (*s != '\0')
X	{
X		sprintf (prompt,SAVFORM,Savefile);
X		user_str (newfile,prompt,1);
X		ptr = newfile;
X		if (*ptr == '|')
X		{
X			sprintf(cmd,"cat %s %s",s,ptr);
X			term_set (ERASE);
X			fflush (stdout);
X			tty_set (SAVEMODE);
X			system (cmd);
X			tty_set (RESTORE);
X			printf (Contstr);
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 (*ptr != '/' && *ptr != '$')
X				sprintf(cmd,"cat %s >>%s/%s 2>/dev/null",s,Savedir,ptr);
X			else
X				sprintf(cmd,"cat %s >>%s 2>/dev/null",s,ptr);
X			if (system (cmd) == 0)
X				prinfo ("Saved");
X			else
X				preinfo ("Could not append save file");
X		}
X	}
X	else
X		preinfo (No_msg);
X	if (Digest)
X		dig_ulist (s);
X}
X
X/*
X	basic page display routine.  erase screen and format current page
X*/
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		printf (DHFORMAT,Page.h.name);
X	else
X		printf (HFORMAT,Page.h.name,i,(Page.h.group)->pages);
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			printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
X			printf("%s",Page.b[i].art_t);
X			continue;
X		}
X
X		if ((Page.h.group)->rdnum >= Page.b[i].art_id)
X			printf(Aformat,Page.b[i].art_mark,ART_WRITTEN,Page.b[i].art_id);
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	}
X
X	sprintf(helpstr,HELPFORM,Cxptoi[HELP]);
X	if (!Digest && ((Page.h.group)->state & 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*/
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		printf("%c",c);
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*/
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->state & FLG_PAGE) == 0)
X	{
X		if ((p->state & FLG_SUB) == 0)
X		{
X			p->state |= FLG_SUB;
X			wr_newsrc ();
X			prinfo ("Not subscribed: resubscribed for next reading session");
X		}
X		else
X			prinfo ("No news for that group");
X		return (-1);
X	}
X	if ((p->state & FLG_SUB) == 0)
X	{
X		p->state |= FLG_SUB;
X		wr_newsrc ();
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.
X*/
Xuser_str (s,p,iline)
Xchar *s;
Xchar *p;
Xint iline;
X{
X	int i,idx;
X
X	if (iline)
X	{
X		prinfo ("%s",p);
X		idx = C_info;
X	}
X	else
X	{
X		printf ("%s",p);
X		idx = strlen(p);
X	}
X
X	for (i=0; idx < C_allow && (s[i] = getchar() & 0x7f) != '\012' && s[i] != '\015'; ++i)
X	{
X		if (s[i] == Erasekey)
X		{
X			if (i > 0)
X			{
X				term_set (RUBSEQ);
X				i -= 2;
X				--idx;
X			}
X			continue;
X		}
X		if (s[i] == Killkey)
X		{
X			prinfo ("%s",p);
X			i = -1;
X			continue;
X		}
X		if ((s[i] == ' ' || s[i] == '\t') && i == 0)
X		{
X			i = -1;
X			continue;
X		}
X		++idx;
X		putchar (s[i]);
X	}
X
X	if (iline)
X		C_info = idx;
X
X	s[i] = '\0';
X}
X
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)
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	printf (" %s ",buf);
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	fflush(stdout);
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	printf ("%s",buf);
X	l = strlen(buf);
X	if (l < C_info)
X		term_set (ZAP,l,C_info);
X	C_info = l;
X	fflush(stdout);
X}
X
X/*
X	help menu
X*/
Xhelp ()
X{
X	int i,lcount,lim; 
X	term_set (ERASE);
X	lim = L_allow + RECBIAS - 2;
X	printf("%s\n",HELP_HEAD);
X	lcount = HHLINES;
X	for (i=0; i < (sizeof(Helptab))/(sizeof(struct HELPTAB)); ++i)
X	{
X		if (Digest && !(Helptab[i].dig))
X			continue;
X		++lcount;
X		if (Digest && Helptab[i].amsg != NULL)
X			h_print (Cxptoi[Helptab[i].cmd],Helptab[i].amsg);
X		else
X			h_print (Cxptoi[Helptab[i].cmd],Helptab[i].msg);
X		if (lcount >= lim)
X		{
X			printf ("\n%s",Contstr);
X			getnoctl ();
X			term_set (MOVE,0,lim+1);
X			term_set (ZAP,0,strlen(Contstr));
X			term_set (MOVE,0,lim-1);
X			putchar ('\n');
X			lcount = 0;
X		}
X	}
X	if (lcount > 0)
X	{
X		printf ("\n%s",Contstr);
X		getnoctl ();
X	}
X}
X
X/*
X	h_print prints a character and a legend for a help menu.
X*/
Xh_print(c,s)
Xchar c,*s;
X{
X	if (strlen(s) > (C_allow - 14))
X		s [C_allow - 14] = '\0';
X	if (c > ' ' && c != '\177')
X		printf ("	 %c - %s\n",c,s);
X	else
X	{
X		switch (c)
X		{
X		case '\177':
X			printf ("  <delete> - %s\n",s);  
X			break;
X		case '\040':
X			printf ("   <space> - %s\n",s);  
X			break;
X		case '\033':
X			printf ("  <escape> - %s\n",s);  
X			break;
X		case '\n':
X			printf ("  <return> - %s\n",s);  
X			break;
X		case '\t':
X			printf ("     <tab> - %s\n",s);  
X			break;
X		case '\b':
X			printf (" <back sp> - %s\n",s);  
X			break;
X		case '\f':
X			printf ("<formfeed> - %s\n",s);  
X			break;
X		case '\07':
X			printf ("    <bell> - %s\n",s);  
X			break;
X		case '\0':
X			printf ("    <null> - %s\n",s);  
X			break;
X		default:
X			if (c < '\033')
X			{
X				c += 'a' - 1;
X				printf(" control-%c - %s\n",c,s);
X			}
X			else
X				printf("       %c0%o - %s\n",'\\',(int) c,s);
X			break;
X		}
X	}
X}
X
Xtot_list (rec,hirec)
Xint *rec;
Xint *hirec;
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		printf (ff, i, (Newsorder[i])->nd_name,
X				(Newsorder[i])->art - (Newsorder[i])->orgrd,
X				(Newsorder[i])->rdnum - (Newsorder[i])->orgrd);
X		++len;
X		if (len == L_allow && i < (Ncount-1))
X		{
X			printf("\nr - return, n - new group, other to continue ... ");
X			if ((c = getnoctl()) == 'r' || c == 'n')
X				break;
X			printf ("\n\n");
X			len = 0;
X		}
X	}
X	if (i >= Ncount)
X	{
X		printf("n - new group, other to return ... ");
X		c = getnoctl();
X	}
X	if (c == 'n')
X	{
X		printf("\n");
X		user_str(ff,"Newsgroup number ? ",0);
X		i = atoi(ff);
X		if (i < 0)
X			i = 0;
X		if (i >= Ncount)
X			i = Ncount-1;
X		find_page((Newsorder[i])->pnum);
X		*rec = RECBIAS;
X		*hirec = Page.h.artnum + RECBIAS;
X	}
X}
@//E*O*F vn.c//
if test 25993 -ne "`wc -c <'vn.c'`"; then
    echo shar: error transmitting "'vn.c'" '(should have been 25993 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'vn.man'" '(19673 characters)'
if test -f 'vn.man' ; then 
  echo shar: will not over-write existing file "'vn.man'"
else
sed 's/^X//' >vn.man <<'@//E*O*F vn.man//'
X.TH VN 1 2/1/85
X.UC
X.SH NAME
Xvn - visual news reader
X.SH SYNOPSIS
X.I vn
X.SH DESCRIPTION
X.I Vn
Xis a news reader which uses the same 
X.B .newsrc
Xfile as
X.I readnews
X(1), but displays and interacts differently.  It is aimed at allowing
Xyou to rapidly scan a large number of newsgroups, looking for something
Xyou want to read.  The major premise is that you will be interested in a
Xsmall number of articles, but will be interested in keeping tabs on a large
Xnumber of newsgroups which may contain something interesting from time to time.
XIt also has the ability to unpackage digests.
X.sp
X.I Vn
Xsupports the -n, -x and -t options of
X.I readnews
X(newsgroup, read all articles, and title).  In addition, there
Xis a -w (writer) option which works like -t, but is a search string to
Xapply to the "From" header line rather than the subject.  In the -n, -t
Xand -w options, a leading ! on the string is taken to mean negation.
XThe rest of the string is a regular expression for the -w and -t options.
X.sp
XFor example:
X.sp
X-n net.dogs -w !fred -t [Bb]eagle
X.sp
XFor articles in net.dogs about beagles written by somebody other
Xthan fred.  Multiple -w -t options are treated as follows:
X.in +5
X.sp
XIf the article satisfies any of the negations, you won't see it,
Xregardless of the non-negated options.
X.sp
XMultiple -w options are logically "or'ed", as are multiple -t's.
X.sp
XIf both -w and -t are present, the article is seen only if it satisfies
Xat least one of the -w's and at least one of the -t's, ie. the results of the
Xlogical "or's" of the -t's and -w's are logically "anded".
X.sp
X.in -5
XThe -n options allow the "all" convention, replacing ".all" by
X".*" before using the regular expression calls.  -n options are processed
Xin order given, so that subsequent more specific -n's may partially
Xundo the effect of previous "alls".  Note that the -n option
Xtreatment is slightly different than the
X.I readnews
Xtreatment which says that "foo" implies "foo.all".
X.I Vn
Xaccepts this incompatibility to allow you an easier way of saying JUST "foo"
Xwithout any of its subgroups.
X.sp
XOptions may be given on the command line, in which case they will
Xsupersede those given in the
X.B .newsrc
Xfile.  For command line -n options, the "!" unsubscriptions in
X.B .newsrc
Xare also ignored.  This allows you to override all subscription information
Xby command line specification.  If you use an -S option on the command line,
Xthe "!" unsubscriptions will still be used.  -S is meaningless in the
X.B .newsrc
Xfile.
X.sp
XThere are three more options specific to
X.I vn:
Xthe -% and -U.  The -% option initially gives you the results of a "%"
Xcommand, rather than the page for the first newsgroup (see below).
XThis allows you to see what newsgroups are available before viewing any.
XThe -U option says that when your
X.B .newsrc
Xfile is updated via answering "yes" to the update query on
Xexit or using control-W, newsgroups marked with "!" are to be updated too.
XNormally, these groups are left alone, ie. updated only to the number that
Xwas already in your
X.B .newsrc,
Xor the lowest article number still around.
XYou may get flooded should you decide to resubscribe.
XIf you don't like this treatment, use -U.  Then, control-W and "yes" to
Xthe update on exit will update your unsubscribed newsgroups to the most
Xrecent article.
X.sp
XWhen
X.I vn
Xis invoked,
Xthere will be a pause (with an explanatory "reading" message and
Xa series of newsgroups) while vn reads the news.  The newsgroups listed
Xare ones articles are actually being found in.
XThe length of the pause depends
Xon how much news there is.  If there is a lot,
Xit may take a long time to get through the reading phase.
X.sp
XOnce the reading phase is over, interaction is rapid.
XIf
X.I vn
Xis backgrounded, it suppresses the "reading" output, so
Xthat it will not halt on tty output until it is ready to begin showing
Xarticles.
X.sp
X.I Vn
Xmay show you a list of newsgroups which were not mentioned in the
X.B .newsrc
Xfile.  Records for these newsgroups will be added, whether
Xthey were scanned for articles or not.  The first time
X.I vn
Xis used, the list may be quite long and scroll off the screen.
XThereafter, there should only be a list when new newsgroups are
Xcreated.  This display serves to let you know of their existence,
Xor of something happening to your
X.B .newsrc
Xfile.
X.sp
XThe basic display is a "page" which shows a newsgroup and a list of
Xtitles, number of
Xlines, and authors for new articles.
XArticles which have been updated in the
X.B .newsrc
Xfile  are flagged with an underscore preceding the article number.
XYou also have the ability to "mark" articles for the duration of a session,
Xshown with an asterisk (col. 1 and 2 are reserved for asterisk and
Xunderscore respectively - 
Xin normal usage they will be blank, so that the casual user will probably
Xbe unaware of their use until marking and updating are invoked)
X.sp
XThere is a help menu to go with this page.
XYou may read articles, save them, send them to the printer, either by cursor
Xposition, the whole page, or in specified sets.  Sets are specified either
Xas a set of article numbers, a regular expression to match the subject /
Xauthor / number of lines data on, or an asterisk to indicate the choice
Xof a set of previously marked articles.  Any of these methods also
Xaccept a leading "!" to indicate negation.
X.sp
XBy default, when you read articles only a couple of the dozen or so
Xheader lines are
Xshown.  There is an option to allow you to see all the
Xheader lines when you read articles.  The command controlling this toggles
Xbetween the two states.
X.sp
XA similar toggle is used to support ROT13.
X.sp
X.I Vn
Xis capable of manipulating digests.  The "d" command unpacks a digest,
Xand presents you with a page showing the unpacked articles, which can
Xbe accessed as for articles on normal newsgroup pages.
XWhen you leave the digest page(s), you reenter the normal flow of newsgroups.
XDigests can also be read as normal articles, of course.
X.sp
XOrder of pages is determined by
Xorder of groups in
X.B .newsrc.
XNewsgroups which are not
Xmentioned in
X.B .newsrc
Xwill be added, as mentioned previously, and tacked onto the end.
XLines corresponding to non-existent newsgroups will be deleted.
XYou will probably want to run
X.I vn
Xonce, then edit
X.B .newsrc
Xto the desired order of presentation.
X.sp
XUpdating the data for
X.B .newsrc
Xis under user control.  If you do
Xno "W", "w", "^w", o or O commands, no updating takes place, and you'll see the
Xarticles again the next time you read news.
XIf you quit without updating, you will be prompted to make sure you
Xdon't want to do so.
X.sp
XNote that "updating what you've seen" to
X.I vn
Xmeans that you've seen the page presentation, not that you've read the
Xarticle.  This is consistent with the overall assumption that you don't
Xwant to read most of what you are presented with.
X.sp
XBreaks result in a "really quit?" query, so you can recover from noisy
Xlines and prompts for commands you didn't really mean.  If you answer no,
Xyou are simply jumped back to the page.  Breaks while in the midst of scrolling
Xout an article you are reading jump you to the end of the article to stop
Xthe output.
X.sp
XCommands are single character (no return key required), except that
Xthey may be preceded with numeric characters, which may have
Xsome effect on their actions.  Commands which require further input
Xcause prompts for the information, this input being
Xterminated by return.  For prompted input, the erase and kill keys
Xwork.
X.sp
X.ce 1
XCommand Menu For Page:
X.sp
X.nf
X[...] = effect of optional number preceding command
Xpipes are specified by filenames beginning with |
Xarticles specified as a list of numbers, title search string, or
X	* to specify marked articles.  ! may be used to negate any
X
X	 q - quit
X	 k - (or up arrow) move up [number of lines]
X	 j - (or down arrow) move down [number of lines]
X <back sp> - (or left arrow) previous page [number of pages]
X  <return> - (or right arrow) next page [number of pages]
X	 d - unpack digest
X	 r - read article [number of articles]
X   <space> - read article (alternate 'r')
X	 R - read all articles on page
X control-r - specify articles to read
X	 s - save or pipe article [number of articles]
X	 S - save or pipe all articles on page
X control-s - specify articles to save
X control-t - specify articles to save (alternate ctl-s)
X	 p - print article [number of articles]
X	 P - print all article on page
X control-p - specify articles to print
X	 w - update .newsrc status to cursor
X	 W - update .newsrc status for whole newsgroup
X control-w - update .newsrc status for all pages displayed
X	 o - recover original .newsrc status for newsgroup
X	 O - recover all original .newsrc status
X	 # - display count of groups and pages - shown and total
X	 % - list newsgroups with new article, updated counts
X	 n - specify newsgroup to display and/or resubscribe to
X	 u - unsubscribe from group
X	 x - mark/unmark article [number of articles]
X	 * - mark/unmark article [number of articles]
X	 X - erase marks on articles
X	 h - toggle flag for display of headers when reading
X	 z - toggle rotation for reading
X<formfeed> - redraw screen
X	 ! - escape to UNIX to execute a command
X	 ? - show this help menu
X.fi
X.sp
XWhen you read articles, there is another help menu, for advancing through
Xthe articles, replying, posting followups, and saving the
Xarticles.  Breaks may be used to
Xstop the output of an article if you decide that you didn't really
Xwant to read it.  You can jump from the reading portion back to either
Xpage you came from or the NEXT page.
X.sp
XFor replying and posting followups, you will be thrown into an editor
Xto create the reply or article.
XThe article will be included in the file you are editing, marked with
X"> "'s for excerpting in your reply or followup.  After you exit the
Xeditor, you are prompted to make sure you still want to post or reply,
Xso you can abort.
X.sp
XFor followups, your article is appended to "author_copy" for future
Xreference.
X.sp
XHeader lines for the mailer / news poster are present in the file
Xyou are editing to allow you to modify them.  Remember to leave a blank
Xline between the header lines and your text.  It may be OK if you
Xdon't, but why tempt fate.
X.sp
XThe editor is determined by your EDITOR variable, as for
X.I postnews.
XIf EDITOR is not set, you get
X.I vi,
Xor the default determined at your site.
X.sp
X.ce 1
XReading menu:
X.sp
X.nf
X         n - next article, if any
X         q - quit reading articles, if any more to read
X         Q - quit reading, and turn to next page of articles
X         r - rewind article to beginning
X  <return> - next line
X         / - search for a pattern in the article
X         m - send mail to author of article
X         f - post followup to article
X         s - save article in a file
X         p - send article to the printer
X         ? - see this help menu
X	 z - toggle rotation flag
X	 h - toggle header suppression flag
X
X anything else to continue normal reading
X.fi
X.sp
XIf you don't like the choice of command keys, you
Xmay change them (default choices - basic control in article
Xreader is ala "more" of course, the "j" and "k" on the page presentation
Xare "vi" convention, other page commands are somewhat "readnews" compatible).
XIf you have a file named
X.B .vnkey
Xin your home directory this file will be read in order to obtain keystroke
Xtranslation.  The format is simple:
X.sp
XEach line begins with R or P indicating translation for the reader interaction,
Xor the page interaction (r and p accepted also).  Following the R or P is
Xa character, followed by an "=", followed by another character.  The character
Xon the left hand side of the equals sign is what you wish to input, and the
Xcharacter on the right hand side of the equals sign is what you wish to
Xtranslate it to.  No embedded spaces.
XLines not beginining with the proper characters are simply
Xignored, as are characters following the translated character.  Eg:
X.sp
X.in +5
XPd=j
X.br
XPu=k
X.in -5
X.sp
Xuses "u" and "d" instead of "j" and "k" on the page layout (presumably,
Xyou are also going to translate something else to "u" and "d" for the
Xunsubscribe and digest commands).  If you translate keys, it is up to you
Xto see that all commands can still be reached, and that former command keys
Xwhich are no longer used are mapped to something meaningless.  In particular,
Xyou are going to have difficulties if you make it impossible to input "q".  The
Xhelp menus will show the "new" keys, and bad mappings should show up as
Xmultiple definitions for the same key, or alternate mappings not showing
Xup on the help menu.
X.sp
XMapping the "=" key via "==" works.  Any keys not mentioned in the file
Xare translated to themselves.
X.sp
XControl keys are given as DECIMAL numbers with no backslashes or anything.
XThe decimal number is the ASCII code for the character, eg:
X.sp
X.in +5
XP24=12
X.br
XP12=?
X.in -5
Xuses "control-x" for the "control-l (formfeed)" refresh key, and maps the
Xcontrol-l to a "?".  BTW, mapping all undefined keys to "?" will mean that you
Xautomatically get the help display for any illegal key, should you wish for
Xsuch a thing.  The LAST one mapped will determine what key is given in
Xthe "? for help" lines, and the help display itself.
XRemembering that control-A through
Xcontrol-Z are ASCII codes 1 through 26 and delete = 127 may keep you from
Xhaving to consult an ASCII table.  Remember also that some controls, such
Xas control- C, Z, S or Q may be caught by the operating system for signal
Xgeneration or terminal control, and are thus unavailable.
X.sp
XBecause of arrow keys and the ability to prefix commands with counts,
Xnumeric characters and the escape key may not be used for page commands.
XAttempts to use them will simply do nothing.
X.sp
XControl keys are not available for the reader, except for newline,
Xbackspace, and tab.  The reason controls are filtered here has to do
Xwith nasty problems involving terminal mode switches on some systems,
Xspecifically a UTS frontend early versions were being used on.
X.sp
XIn either interaction, "return" and "linefeed" are mapped to the "newline"
Xcharacter at a level below the translation.  If you don't know the
XASCII for the "newline" char, it is recommended that you map both
XASCII 10 and 13 if you wish to map "return" to something.
X.SH FILES
X.TP 24
X/usr/tmp/*
XOne temporary file created by
X.I tmpnam
X(3), and immediately unlinked,
Xremains open in update mode for duration of session.
XDisk space freed by system close of file descriptor at exit.
XCan be large, as this file contains the "page" displays.
XTemporary files also created by
X.I tmpnam
X(3) for mailing replies, posting followups and creating digest "articles".
X.TP 24
X(login directory)/.newsrc
Xnews status file.  Updated following session.  See NEWSRC environment variable.
X.TP 24
X(login directory)/author_copy
XA copy of all articles posted using the followup command will be appended
Xto this file in /bin/mail format.  See CCFILE environment variable.
X.TP 24
X(login directory)/.vnkey
XKeystroke mapping file for changing command characters.
X.TP 24
X(login directory)/*.vnXXXXXX
XOne temporary file created by
X.I tmpnam
X(3) while updating the .newsrc file.  If the update fails, you are informed,
Xand this file
Xmay be used to recover the last update.  Unlinked following successful update.
X.TP 24
X(spool directory)/*
Xspooling directories containing articles.
X.TP 24
X/usr/lib/news/active
Xactive newsgroup list.
X.SH "ENVIRONMENT VARIABLES"
X.TP 24
XPS1
Xused to present prompt string for command on unix escape.
Xdefaults to "$ "
X.TP 24
XEDITOR
Xeditor used for mailing replies and posting followups.
Xdefaults to "ed".
X.TP 24
XPOSTER
Xposting program for followups.  defaults to "inews -h".
X.TP 24
XMAILER
Xused when mailing replies.  defaults to "sendmail -t".
X.TP 24
XPRINTER
Xprogram used with the print commands for sending articles to
Xthe printer.  defaults to "lpr".
X.TP 24
XNEWSRC
Xif set, can be used to override the choice of ".newsrc" as the
Xname for the status file.  Name will still be used relative to
Xthe login directory, unless it begins with "/".
X.TP 24
XCCFILE
Xif set, overrides the choice of "author_copy" as the name of the
Xfile to CC all articles posted with the followup command.  Name
Xwill still be used relative to the login directory, unless it begins
Xwith "/".
X.TP 24
XVNKEY
Xif set, overrides the choice of ".vnkey" as the name of the
Xfile to map keys from.  Name
Xwill still be used relative to the login directory, unless it begins
Xwith "/".
X.SH DIAGNOSTICS
Xuser error messages.  self explanatory.
X.SH AUTHOR
XR. L. McQueer
X.SH BUGS
XNote that
X.I readnews
Xwill rearrange the order of
X.B .newsrc.
XIf you
Xinterleave use of it with
X.I vn,
Xorder selection gets hosed.
X.sp
XIf you've really taken advantage of the ability of readnews to skip
Xarticles in the middle of the spooling numbers, be warned that
X.I vn
Xdoesn't have it, and will
Xassume you've read the articles in the middle.
X.sp
XIf the
X.B .newsrc
Xfile indicates that you've read articles in a newsgroup with a higher
Xnumber than the current spooling number for that newsgroup,
X.I vn
Xwill show you the entire newsgroup.  This is intended for recovery in
Xcases where article spooling has been reset, or to avoid missing articles
Xbecause you just changed machines and didn't bother to edit your
X.B .newsrc
Xfile.  Rather than miss stuff, you'll see some old stuff again.
X.sp
XSometimes a "break" during reading an article will not only halt the
Xarticle but suppress the prompt.  A command character will work anyway.
X.sp
XIf a prompt to be displayed on the dialogue line
Xcontains non-printing sequences, stuff on the
Xline may not get erased when you are prompted, because
X.I vn
Xthinks the string is long enough to overprint its current contents.
XThis usually comes up when you have escape sequences in your UNIX
Xprompt, and do a "!" command.
XThe "overprint" check is made to save a clear-line sequence (kludged in
Xby overprinting to the end with blanks if the terminal doesn't
Xhave one - annoying at 1200 baud).
X.sp
XOutput during the reading phase which was suppressed by backgrounding
X.I vn
Xdoes not get started by foregrounding it again without doing a
Xcontrol-z and a second foreground (it doesn't figure out its background /
Xforeground status on each output - only on startup and while handling
Xthe SIGTSTP signal).  Actually, this results in a method for having
X.I vn
Xdo its reading phase silently in the foreground without redirecting
Xoutput, should such a thing be desired.
X.sp
XVery many -w or -t options cause SLOW reading phases.  It is reccomended
Xthat these be used only when reading a few specific groups.
X.sp
XDigest extraction will split a single article into several if it contains
Xembedded ---- lines, the normal separator between articles in digests.
XThey will all have identical titles.
XDigest extraction may not work with human built digests which don't
Xuse the expected syntax for joining articles.  mod.computers.ibm-pc
Xand mod.computers.mac were used as models for the feature.
X.sp
XThe data given by the % command represents the difference between the
Xlast article number you've updated to in a newsgroup and the high
Xarticle number.  This may be significantly greater than the number of
Xactual articles for a newsgroup you haven't been reading, and for
Xnewsgroups that have had a lot of articles filtered out of them using
Xthe -w and -t options.  The numbers given for menu selection in the
X % command are the order numbers from the .newsrc, and have gaps for
Xunsubscribed newsgroups.
X.sp
XThe key mapping capability doesn't handle function keys.  Because of the
Xuse of controls as commands, terminals whose arrow keys echo something
Xother than a sequence beginning with escape can't use arrow keys.  For
Xthese terminals, a warning message is printed during the reading phase.
@//E*O*F vn.man//
if test 19673 -ne "`wc -c <'vn.man'`"; then
    echo shar: error transmitting "'vn.man'" '(should have been 19673 characters)'
fi
fi # end of overwriting check
echo shar: "End of archive 3 (of 3)."
cp /dev/null ark3isdone
DONE=true
for I in 1 2 3; do
    if test -! f ark${I}isdone; then
        echo "You still need to run archive ${I}."
        DONE=false
    fi
done
case $DONE in
    true)
        echo "You have run all 3 archives."
        echo 'Now read the README'
        ;;
esac
##  End of shell archive.
exit 0



More information about the Mod.sources mailing list