[comp.sources.amiga] v91i025: VN res1.1 - vn news reader, Part05/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 025
Archive-name: news/vn-res1.1/part05

#!/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 5 (of 6)."
# Contents:  std.c vn.man
# Wrapped by tadguy@ab20 on Tue Feb 26 19:28:47 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'std.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'std.c'\"
else
echo shar: Extracting \"'std.c'\" \(25324 characters\)
sed "s/^X//" >'std.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <pwd.h>
X#include <ctype.h>
X
Xextern char *malloc();
X
X#ifndef	MINIX
X#ifndef	MSDOS
X#ifndef	amiga
X/* Minix is missing it */
X#include <sys/param.h>
X#endif
X#endif
X#endif
X
X#include "server.h"
X#include "config_std.h"
X#include "std.h"
X
X#ifdef	MINIX
X#define clearerr(p) (((p)->_flags) &= ~_ERR)
X#endif
X
X#ifdef amiga
Xextern char pr_buf[];
Xextern ttputc ();
X#endif
X
X#ifndef MAXPATHLEN
X#define MAXPATHLEN 240
X#endif
X
Xextern NODE *hashfind();
Xextern FILE *fopen();
Xextern char *index(), *rindex();
Xextern char *str_tstore(), *str_tpool(), *str_store();
Xextern char *strtok(), *strpbrk();
Xextern char *regex(), *regcmp();
X
X#ifdef MAILCHOOSE
Xextern int (*Massage)();
X#endif
X
X/*
X	global flags signifying options set
X*/
X#define GF_ALL 1	/* -x option - scan everything */
X#define GF_SPEC 2	/* -n option(s) - user specified groups */
X#define GF_OVER 4	/* command line specification - overide marks */
X
Xchar *Vns_version = "res1.1";
X
Xstatic char *Onews, *Newsrc;
Xstatic int Ntopt, Nntopt, Nwopt, Nnwopt;
X
Xstatic char *Wopt[NUMFILTER];		/* regular expressions for -w options */
Xstatic char *Topt[NUMFILTER];		/* for -t options */
Xstatic char *Negwopt[NUMFILTER];	/* for negated -w options */
Xstatic char *Negtopt[NUMFILTER];	/* for negated -t options */
X
Xstatic char *Options[OPTLINES];
Xstatic int Max_name, Optlines;
Xstatic unsigned Gflags = 0;
Xstatic char **Active;
Xstatic int Actnum;
Xstatic char *Mailer, *Poster;
X
Xstatic char *RT_head = RTHEAD;
Xstatic char *P_head = PHEAD;
Xstatic char *M_head = MHEAD;
Xstatic char *R_head = RHEAD;
Xstatic char *TO_head = TOHEAD;
Xstatic char *F_head = FHEAD;
Xstatic char *FT_head = FTHEAD;
Xstatic char *T_head = THEAD;
Xstatic char *DIS_head = DISHEAD;
Xstatic char *L_head = LHEAD;
Xstatic char *N_head = NHEAD;
X
Xstatic char *Fpfix = FPFIX;
X
Xstatic void specmark (), mail_cmd ();
X
Xstatic  g_dir (), emptyline (), fill_active (), art_active (), chkgroup (),
X	arg_opt (), newsrc_opt (), do_opt (), specfilter (),
X	findall (), digname ();
Xstatic char *nfgets (), *mail_trim ();
X
X/*
X**	environment setup.
X*/
Xvns_envir()
X{
X 	char dbuf[MAXPATHLEN], *rcname;
X	char *vn_env();
X	struct passwd *ptr, *getpwuid();
X#ifdef amiga
X	long	fh;	/* on the amiga creat or open locks a file */
X#endif
X#ifdef MAILCHOOSE
X	int mail_prompt();
X
X	Massage = mail_prompt;
X#endif
X
X	ptr = getpwuid (getuid());
X
X	rcname = vn_env("MAILER",DEF_MAIL);
X#ifdef INLETTER
X	sprintf(dbuf,"cat %%s | %s",rcname);
X#else
X	/* used as a format string TWICE (%%%% -> %% -> %) */
X	sprintf(dbuf,"cat %%%%s | %s %%s",rcname);
X#endif
X	Mailer = str_store(dbuf);
X	rcname = vn_env("VNPOSTER",DEF_POST);
X	sprintf(dbuf,"%s %%s",rcname);
X	Poster = str_store(dbuf);
X	rcname = vn_env("NEWSRC",DEF_NEWSRC);
X	if (*rcname != DIRSEP)
X	{
X#ifdef amiga
X		sprintf (dbuf, "%s%s",ptr->pw_dir,rcname);
X#else
X		sprintf (dbuf, "%s%c%s",ptr->pw_dir,DIRSEP,rcname);
X#endif
X		Newsrc = str_store (dbuf);
X	}
X	else
X		Newsrc = str_store (rcname);
X
X	/* above logic guarantees that Newsrc contains a '/' */
X 	strcpy(dbuf,Newsrc);
X#ifdef amiga
X 	strcpy(rindex(dbuf,':')+1,"vnXXXXXX");
X#else
X 	strcpy(rindex(dbuf,DIRSEP)+1,"vnXXXXXX");
X#endif
X	mktemp(dbuf);
X	Onews = str_store (dbuf);
X
X	if (access (Newsrc,0) != 0)
X#ifdef amiga
X	{ /* we must close a file we creat otherwise it is locked an
X	     inaccesible */
X		fh = creat (Newsrc,0666);
X		if (fh > 0)
X			close (fh);
X	}
X#else
X		creat (Newsrc,0666);
X#endif
X}
X
X/*
X	change directory to group
X*/
Xvns_gset(grp)
Xchar *grp;
X{
X	char dbuf [RECLEN];
X	g_dir (grp,dbuf);
X	if (chdir(dbuf) < 0)
X		printex("can't change to newsgroup directory");
X}
X
X/*
X	g_dir converts newsgroup name to directory string
X*/
Xstatic
Xg_dir(s,t)
Xchar *s,*t;
X{
X	char *ptr;
X#ifdef amiga
X	sprintf (t,"%s%s",SPOOLDIR,s);
X#else
X	sprintf (t,"%s%c%s",SPOOLDIR,DIRSEP,s);
X#endif
X	for (ptr=t+strlen(SPOOLDIR)+1; (ptr = index(ptr,'.')) != NULL; *ptr = DIRSEP)
X		;
X}
X
X/*
X** myfind is used for hashfind() calls which aren't supposed to fail.
X*/
Xstatic NODE *
Xmyfind(name)
Xchar *name;
X{
X	NODE *n;
X
X	n = hashfind(name);
X	if (n == NULL)
X		printex("Unexpected table lookup failure");
X	return (n);
X}
X
Xvns_news(argc,argv,lfirst,nun)
Xint argc;
Xchar **argv;
Xint *lfirst, *nun;
X{
X	FILE *fp;
X	static char marks[] =
X	{ 
X		NEWS_ON, NEWS_OFF, '\0' 
X	};
X	int line, len, num;
X	char buf [RECLEN], trail, optpflag, submark, *fret, *ptr;
X
X	++argv;
X	--argc;
X
X	/* fill table with active newsgroups */
X	fill_active ();
X
X	if (argc > 0)
X	{
X		Gflags |= GF_OVER;
X		arg_opt(argc,argv,lfirst,nun);
X		optpflag = 'y';
X	}
X	else
X		optpflag = 'n';
X
X	if ((fp = fopen (Newsrc,"r")) == NULL)
X		printex ("can't open %s for reading",Newsrc);
X
X	Optlines = 0;
X
X	for (line = 1; (fret = fgets(buf,RECLEN-1,fp)) != NULL && emptyline(buf) == 1; ++line)
X		;
X	if (fret != NULL && strncmp (buf,"options",7) == 0)
X	{
X		Options[0] = str_store(buf);
X		Optlines = 1;
X		trail = buf [strlen(buf)-2];
X		for ( ; (fret = fgets(buf,RECLEN-1,fp)) != NULL; ++line)
X		{
X			if (trail != '\\' && buf[0] != ' ' && buf[0] != '\t')
X				break;
X			if (Optlines >= OPTLINES)
X				printex ("%s - too many option lines (%d allowed)",Newsrc,OPTLINES);
X			Options[Optlines] = str_store(buf);
X			++Optlines;
X			if ((len = strlen(buf)) >= 2 && buf[len-2] != '\\')
X				trail = buf[len-2];
X			else
X				trail = '\0';
X		}
X	}
X
X	/* do the options from the newsrc file if there weren't command line args */
X	if (Optlines > 0 && optpflag == 'n')
X		newsrc_opt (lfirst,nun);
X
X	for ( ; fret != NULL; ++line, fret = fgets(buf,RECLEN-1,fp))
X	{
X		if (emptyline(buf) == 1)
X			continue;
X		if ((ptr = strpbrk(buf,marks)) == NULL)
X		{
X			fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
X			line,Newsrc,buf);
X			continue;
X		}
X		submark = *ptr;
X		*ptr = '\0';
X		++ptr;
X		num = 0;
X		for (ptr = strtok(ptr," ,-\n"); ptr != NULL; ptr = strtok(NULL," ,-\n"))
X		{
X			len = atoi (ptr);
X			for ( ; *ptr >= '0' && *ptr <= '9'; ++ptr)
X				;
X			if (*ptr != '\0' || len < num)
X			{
X				num = -1;
X				fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n",
X				line,Newsrc,buf);
X				break;
X			}
X			num = len;
X		}
X		if (num < 0)
X			continue;
X		chkgroup (buf,submark,num,0);
X	}
X	fclose (fp);
X
X	/* now take care of groups not specified in .newsrc */
X	art_active();
X
X	/* free up the option string storage */
X	for (num=0; num < Ntopt; ++num)
X		regfree (Topt[num]);
X	for (num=0; num < Nwopt; ++num)
X		regfree (Wopt[num]);
X	for (num=0; num < Nntopt; ++num)
X		regfree (Negtopt[num]);
X	for (num=0; num < Nnwopt; ++num)
X		regfree (Negwopt[num]);
X	Ntopt = Nwopt = Nntopt = Nnwopt = 0;
X
X	/* free the active list */
X	free ((char *) Active);
X}
X
Xstatic
Xemptyline(s)
Xchar *s;
X{
X	while (isspace(*s))
X		++s;
X	if (*s == '\0')
X		return (1);
X	return (0);
X}
X
X/*
X	fill hash table from active news group list
X	This is needed to be able to process options
X	before scanning user order.  Constructs an array
X	of active newsgroup names for the rest of vns_nws().
X*/
Xstatic
Xfill_active ()
X{
X	FILE *f;
X	char *nread, act_rec[RECLEN];
X	int num,lownum,rcount;
X
X	Max_name = 0;
X	if ((f = fopen (ACTFILE,"r")) == NULL)
X		printex ("couldn't open %s\n",ACTFILE);
X
X	/*
X	** we do things this way so that we only examine active records
X	** once, minimizing the window where changes could screw us up
X	** at the cost of possibly alloc'ing a few extra bytes.  We start
X	** with a count of one to have a positive rcount for alloc.
X	*/
X	for(rcount=1; fgets(act_rec, RECLEN-1, f) != NULL; ++rcount)
X		;
X	if ((Active = (char **) malloc(rcount*sizeof(char *))) == NULL)
X		printex("Memory allocation failure");
X	rewind(f);
X
X	Actnum = 0;
X	while (Actnum < rcount && fgets(act_rec, RECLEN-1, f) != NULL)
X	{
X		if (strtok (act_rec," \n") == NULL)
X			continue;
X		nread = strtok (NULL, " \n");
X		if (nread != NULL)
X			num = atoi(nread);
X		else
X			num = 0;
X		nread = strtok (NULL, " \n");
X		if (nread != NULL)
X			lownum = atoi(nread);
X		else
X			lownum = 0;
X		if (lownum > 0)
X			--lownum;
X		if (strlen(act_rec) > Max_name)
X			Max_name = strlen(act_rec);
X		/* enter newsgroup, point to permanent copy of name */
X		hashenter (act_rec, num, lownum);
X		Active[Actnum] = (myfind(act_rec))->nd_name;
X		++Actnum;
X	}
X
X	fclose (f);
X}
X
X/*
X	check active newsgroups not mentioned in NEWSRC file
X	(SFLG_SCAN not set)
X*/
Xstatic
Xart_active ()
X{
X	int i;
X	NODE *ptr;
X
X	for( i=0; i < Actnum; ++i)
X	{
X		ptr = myfind(Active[i]);
X		if ((ptr->state & SFLG_SCAN) == 0)
X			chkgroup (ptr->nd_name, NEWS_ON, 0, 1);
X	}
X}
X
X/*
X	check group for new articles:
X	s - group
X	c - subscription indicator from NEWSRC
X	n - number read
X	new - new newsgroup flag
X*/
Xstatic
Xchkgroup (s,c,n,new)
Xchar *s,c;
Xint n;
Xint new;
X{
X	NODE *ptr;
X	char sub;
X	int nrd;
X	int lowart;
X	int st;
X
X	if ((ptr = hashfind(s)) != NULL && (ptr->state & SFLG_SCAN) == 0)
X	{
X		ptr->state |= SFLG_SCAN;
X
X#ifdef SYN_CHECK
X		/* if "read" more than exist, reset */
X		if (n > ptr->highnum)
X		{
X			n = ptr->highnum - SYN_SETBACK;
X			fgprintf("%s: .newsrc out of synch, resetting\n",s);
X		}
X#endif
X		lowart = ptr->lownum;
X		if (n < ptr->lownum)
X			n = ptr->lownum;
X
X		nrd = n;
X		sub = c;
X
X		/*
X		** scan decision is rather complex, since GF_ALL setting
X		** overides "n" value, GF_SPEC indicates SFLG_SPEC flag used.
X		** if GF_OVER set, SFLG_SPEC overides subscription mark, else
X		** SFLG_SPEC AND subscribed is neccesary.
X		*/
X		if ((Gflags & GF_SPEC) != 0)
X		{
X			if ((ptr->state & SFLG_SPEC) == 0)
X				c = NEWS_OFF;
X			else
X			{
X				if ((Gflags & GF_OVER) != 0)
X					c = NEWS_ON;
X			}
X		}
X		if ((Gflags & GF_ALL) != 0)
X			n = lowart;
X		fw_group(s, new, sub == NEWS_ON, nrd, c == NEWS_ON);
X		if (c == NEWS_ON && ptr->highnum > n)
X		{
X			st = outgroup (s,n,ptr->highnum);
X			if (st > nrd)
X				fw_chg(new, sub == NEWS_ON, st, c == NEWS_ON);
X		}
X	}
X}
X
X/*
X	vns_write writes the .newsrc file
X*/
Xvns_write(news,ncount)
XNODE **news;
Xint ncount;
X{
X	FILE *fp;
X	NODE *p;
X	char c;
X	int i,rc;
X
X	if (link(Newsrc,Onews) < 0)
X		printex ("can't backup %s to %s before writing",Newsrc,Onews);
X
X	if (unlink(Newsrc) < 0 || (fp = fopen(Newsrc,"w")) == NULL)
X		printex ("can't open %s for writing (backed up in %s)",Newsrc,Onews);
X	else
X	{
X		clearerr(fp);
X		for (i=0; (rc = ferror(fp)) == 0 && i < Optlines; ++i)
X			fprintf (fp,"%s",Options[i]);
X		for (i=0; rc == 0 && i < ncount; ++i)
X		{
X			p = news[i];
X			if ((p->flags & FLG_SUB) == 0)
X				c = NEWS_OFF;
X			else
X				c = NEWS_ON;
X#ifdef OLDRC
X			fprintf (fp,"%s%c %d\n",p->nd_name,c,p->rdnum);
X#else
X			if (p->rdnum > 0)
X				fprintf(fp,"%s%c 1-%d\n",p->nd_name,c,p->rdnum);
X			else
X				fprintf(fp,"%s%c 0\n",p->nd_name,c);
X#endif
X			rc = ferror(fp);
X		}
X		fclose (fp);
X		if (rc != 0)
X			printex ("write of %s failed, old copy stored in %s",Newsrc,Onews);
X		else
X			unlink (Onews);
X	}
X}
X
X/*
X	arg_opt must be called prior to option scanning, since
X	it uses the options array.  This is a bit of a kludge,
X	but it saves a bunch of work.  NOTE - no command name argument
X*/
Xstatic
Xarg_opt (argc,argv,lfirst,nun)
Xint argc;
Xchar **argv;
Xint *lfirst, *nun;
X{
X	if (argc > OPTLINES)
X		printex ("too many command line options (%d allowed)\n",OPTLINES);
X	for (Optlines=0; Optlines < argc; ++Optlines)
X	{
X		Options[Optlines] = *argv;
X		++argv;
X	}
X	newsrc_opt(lfirst,nun);
X}
X
X/*
X	option setting routine:
X	sets global flags: GF_ALL for -x option GF_SPEC for -n.
X	sets up filter array for article scanning
X*/
Xstatic
Xnewsrc_opt(lfirst,nun)
Xint *lfirst, *nun;
X{
X	int i;
X	char curopt,tmp[RECLEN],*tok;
X
X	*nun = *lfirst = 0;
X	Ntopt = Nwopt = Nnwopt = Nntopt = 0;
X	curopt = '\0';
X	for (i=0; i < Optlines; ++i)
X	{
X		strcpy(tmp,Options[i]);
X		for (tok = strtok(tmp,",\\ \t\n"); tok != NULL; tok = strtok(NULL,",\\ \t\n"))
X		{
X			if (*tok != '-')
X				do_opt (curopt,tok);
X			else
X			{
X				for (++tok; index("nwt",*tok) == NULL; ++tok)
X				{
X					/* options with no strings */
X					switch(*tok)
X					{
X					case 'S':
X						Gflags &= ~GF_OVER;
X						break;
X					case '%':
X						*lfirst = 1;
X						break;
X					case 'U':
X						*nun = 1;
X						break;
X#ifdef OLDRC
X					case 'i':
X					/* Treat "-i" as synonym for "-x" */
X#endif
X					case 'x':
X						Gflags |= GF_ALL;
X					default:
X						break;
X					}
X				}
X				curopt = *tok;
X				if (*(++tok) != '\0')
X					do_opt (curopt,tok);
X			}
X		}
X	}
X}
X
X/* do_opt is for options with strings attached */
Xstatic
Xdo_opt (opt,str)
Xchar opt, *str;
X{
X	switch (opt)
X	{
X	case 'n':
X		Gflags |= GF_SPEC;
X		specmark(str);
X		break;
X	case 'w':
X		specfilter (FIL_AUTHOR,str);
X		break;
X	case 't':
X		specfilter (FIL_TITLE,str);
X		break;
X	default:
X#ifdef OLDRC
X		Gflags |= GF_SPEC;	/* Assume anything else is newsgroup */
X		specmark(str);
X#endif
X		break;
X	}
X}
X
Xstatic
Xspecfilter (comp,str)
Xchar comp,*str;
X{
X	int *count;
X	char **rex;
X
X	/*
X	** we may set rex one past end of array.  we will error before
X	** referencing it if that's the case, however.
X	*/
X	if (*str == '!')
X	{
X		if (comp == FIL_TITLE)
X		{
X			count = &Nntopt;
X			rex = Negtopt + *count;
X		}
X		else
X		{
X			count = &Nnwopt;
X			rex = Negwopt + *count;
X		}
X		++str;
X	}
X	else
X	{
X		if (comp == FIL_TITLE)
X		{
X			count = &Ntopt;
X			rex = Topt + *count;
X		}
X		else
X		{
X			count = &Nwopt;
X			rex = Wopt + *count;
X		}
X	}
X	if (*count >= NUMFILTER)
X		printex ("too many %c options, %d allowed",comp,NUMFILTER);
X	if ((*rex = regcmp(str,(char *) 0)) == NULL)
X		printex ("%c option regular expression syntax: %s",comp,str);
X	++(*count);
X}
X
X/*
X	handle the newsgroup specification string.
X	("all" convention - braack!!!)
X*/
Xstatic
Xvoid
Xspecmark (s)
Xchar *s;
X{
X	unsigned ormask,andmask;
X	int i,len;
X	char *ptr,*re,pattern[RECLEN];
X	NODE *nptr;
X
X	if (*s == '!')
X	{
X		++s;
X		ormask = 0;
X		andmask = ~SFLG_SPEC;
X		if (*s == '\0')
X			return;
X	}
X	else
X	{
X		ormask = SFLG_SPEC;
X		andmask = 0xffff;
X	}
X
X	/* convert "all" not bounded by alphanumerics to ".*". ".all" becomes ".*" */
X	for (ptr = s; (len = findall(ptr)) >= 0; ptr += len+1)
X	{
X		if (len > 0 && isalnum (s[len-1]))
X			continue;
X		if (isalnum (s[len+3]))
X			continue;
X		if (len > 0 && s[len-1] == '.')
X		{
X			--len;
X			strcpy (s+len,s+len+1);
X		}
X		s[len] = '.';
X		s[len+1] = '*';
X		strcpy (s+len+2,s+len+3);
X	}
X
X	/* now use regular expressions */
X	sprintf (pattern,"^%s$",s);
X	if ((re = regcmp(pattern,(char *) 0)) == NULL)
X		printex ("n option regular expression syntax: %s",s);
X	for (i=0; i < Actnum; ++i)
X	{
X		nptr = myfind(Active[i]);
X		if (regex(re,nptr->nd_name) != NULL)
X		{
X			nptr->state |= ormask;
X			nptr->state &= andmask;
X		}
X	}
X	regfree (re);
X}
X
Xstatic
Xfindall (s)
Xchar *s;
X{
X	int len;
X	for (len=0; *s != '\0'; ++s,++len)
X	{
X		if (*s == 'a' && strncmp(s,"all",3) == 0)
X			return (len);
X	}
X	return (-1);
X}
X
Xstatic
Xgrp_indic (s,ok)
Xchar *s;
Xint ok;
X{
X	if (ok)
X		fgprintf("    %s\n",s);
X	else
X		fgprintf("    %s - Can't access spool directory\n",s);
X}
X
X/*
X	enter newsgroup articles.
X	all articles between low and hi are to be included.
X
X	Returns the highest number less than an OPENED (not neccesarily
X	accepted) article to allow caller to revise "articles read"
X	number beyond non-existent articles.
X*/
Xoutgroup (s,low,hi)
Xchar *s;
Xint low,hi;
X{
X	int i;
X	char subj[RECLEN], lines[RECLEN], auth[RECLEN], gd[RECLEN];
X	int ret,op;
X
X	if ((hi-low) > MAXARTRANGE)
X		low = hi - MAXARTRANGE;
X
X	ret = low;
X	op = 1;
X
X	g_dir(s,gd);
X	if (chdir(gd) < 0)
X	{
X		grp_indic(s,0);
X		return (ret);
X	}
X	grp_indic(s,1);
X	for (i=low+1; i <= hi; ++i)
X	{
X		if (digname(i,subj,lines,auth,&op) >= 0)
X		{
X			fw_art(i,subj,lines,auth);
X		}
X		else
X		{
X			if (op)
X				ret = i;
X		}
X	}
X
X	return(ret);
X}
X
X/*
X** open article and interpret options, if any.  The op parameter is set
X** to ZERO if and only if an article is opened.  Used above as a flag to
X** indicate no articles opened yet.
X*/
Xstatic digname (n, subj, lines, auth, op)
Xint n;
Xchar *subj, *lines, *auth;
Xint *op;
X{
X	int i,j;
X	FILE *fp;
X	char t[RECLEN];
X
X	/* open article */
X	sprintf (t,"%d", n);
X	if ((fp = fopen(t,"r")) == NULL)
X		return (-1);
X	*op = 0;
X
X	/* get subject, from and lines by reading article */
X	subj[0] = lines[0] = auth[0] = '?';
X	subj[1] = lines[1] = auth[1] = '\0';
X	for (i = 0; i < HDR_LINES && nfgets(t,RECLEN-1,fp) != NULL; ++i)
X	{
X		if (index(CHFIRST,t[0]) == NULL)
X			continue;
X		t[strlen(t) - 1] = '\0';
X		if (strncmp(T_head,t,THDLEN) == 0)
X		{
X			for (j=0; j < Nntopt; ++j)
X			{
X				if (regex(Negtopt[j],t+THDLEN) != NULL)
X				{
X					fclose(fp);
X					return(-1);
X				}
X			}
X			if (Ntopt > 0)
X			{
X				for (j=0; j < Ntopt; ++j)
X				{
X					if (regex(Topt[j],t+THDLEN) != NULL)
X						break;
X				}
X				if (j >= Ntopt)
X				{
X					fclose(fp);
X					return(-1);
X				}
X			}
X			strcpy(subj,t+THDLEN);
X			continue;
X		}
X		if (strncmp(F_head,t,FHDLEN) == 0)
X		{
X			for (j=0; j < Nnwopt; ++j)
X			{
X				if (regex(Negwopt[j],t+FHDLEN) != NULL)
X				{
X					fclose(fp);
X					return(-1);
X				}
X			}
X			if (Nwopt > 0)
X			{
X				for (j=0; j < Nwopt; ++j)
X				{
X					if (regex(Wopt[j],t+FHDLEN) != NULL)
X						break;
X				}
X				if (j >= Nwopt)
X				{
X					fclose(fp);
X					return(-1);
X				}
X			}
X			strcpy(auth,t+FHDLEN);
X			continue;
X		}
X		if (strncmp(L_head,t,LHDLEN) == 0)
X		{
X			strcpy(lines,t+LHDLEN);
X			break;
X		}
X	}
X
X	fclose (fp);
X
X	/* reject empty or 1 line files */
X	if (i < 2)
X		return (-1);
X
X	return (0);
X}
X
X/*
X** special fgets for reading header lines, which unfolds continued lines
X** and throws away trailing stuff on buffer overflow.
X*/
Xstatic char *
Xnfgets(buf, size, fp)
Xchar	*buf;
Xint	size;
XFILE	*fp;
X{
X	register int c;
X
X	while (!feof(fp))
X	{
X		if ((c = getc(fp)) == '\n')
X		{
X			if ((c = getc(fp)) == '\t' || c == ' ')
X				continue;
X			ungetc(c, fp);
X			*buf = '\n';
X			++buf;
X			*buf = '\0';
X			++buf;
X			return (buf);
X		}
X
X		/* prevent "terminal bombs" */
X		if (c < ' ' || c == '\177')
X		{
X			switch(c)
X			{
X			case '\r':
X			case '\010':
X			case '\07':
X				break;
X			case '\177':
X				c = '~';
X				break;
X			case '\t':
X				c = ' ';
X				break;
X			default:
X				if (size > 1)
X				{
X					*buf = '^';
X					++buf;
X					--size;
X				}
X				c += 'A' - 1;
X				break;
X			}
X		}
X
X		if (size > 0)
X		{
X			*buf = c;
X			++buf;
X			--size;
X		}
X		if (c == '\r')
X		{
X			if ((c = getc(fp)) != '\n')
X			{
X				ungetc(c, fp);
X				continue;
X			}
X			if ((c = getc(fp)) != ' ' && c != '\t')
X			{
X				*buf = '\0';
X				++buf;
X				ungetc(c, fp);
X				return (buf);
X			}
X			--buf;
X			++size;
X			continue;
X		}
X	}
X
X	*buf = '\0';
X	++buf;
X	return (NULL);
X}
X
Xstatic char *Mail[2], *Show[6], *Post[4];
Xstatic char *Priv[8];
Xstatic char *Pool = NULL;
X
XFILE *
Xvns_aopen(art,hdr)
Xint art;
XARTHEADER *hdr;
X{
X	char buf[RECLEN];
X	char *dist, *reply, *from, *ngrp, *flto, *path, *resubj;
X	FILE *fp;
X	int n;
X
X	dist = resubj = path = reply = from = ngrp = flto = NULL;
X
X	sprintf(buf,"%d",art);
X	if ((fp = fopen(buf,"r")) == NULL)
X		return(NULL);
X
X	/*
X	** we only really need a lot extra if MAILCHOOSE, but allocating
X	** a temporary array of pointers isn't that much.  Similarly, a
X	** few assignments, and the "Priv" declaration are only needed
X	** with some define settings.  Not worth ifdef'ing.
X	*/
X	Pool = str_tpool(100);
X
X	hdr->artid = "<some article>";
X	hdr->from = "<somebody>";
X	hdr->priv = Priv;
X	hdr->postcmd = Poster;
X	hdr->mail = Mail;
X	hdr->show = Show;
X	hdr->post = Post;
X	hdr->priv_num = hdr->show_num = hdr->post_num = hdr->mail_num = 0;
X
X	/* for conditional is abnormal - expected exit is break */
X	for (n=0; n < HDR_LINES && fgets(buf,RECLEN-1,fp) != NULL; ++n)
X	{
X		/* bail out at first non-header line */
X		if (buf[0] == '\n')
X			break;
X		if (strncmp(buf,RT_head,RTHDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X			reply = str_tstore(Pool,buf+RTHDLEN);
X			continue;
X		}
X		if (strncmp(buf,P_head,PHDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X			path = str_tstore(Pool,buf+PHDLEN);
X			continue;
X		}
X		if (strncmp(buf,DIS_head,DISHDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X			dist = str_tstore(Pool,buf);
X			continue;
X		}
X		if (strncmp(buf,M_head,MHDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X			hdr->artid = str_tstore(Pool,buf+MHDLEN);
X			continue;
X		}
X		if (strncmp(buf,F_head,FHDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X			(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
X			from = hdr->from = (hdr->show)[hdr->show_num]+FHDLEN;
X			++(hdr->show_num);
X			continue;
X		}
X		if (strncmp(buf,T_head,THDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X			(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
X			if (strncmp(buf+THDLEN,Fpfix,FPFLEN) != 0)
X			{
X				sprintf(buf,"%s%s%s",T_head,Fpfix,
X					((hdr->show)[hdr->show_num])+THDLEN);
X				resubj = str_tstore(Pool,buf);
X			}
X			else
X				resubj = (hdr->show)[hdr->show_num];
X			++(hdr->show_num);
X			continue;
X		}
X		if (strncmp(buf,N_head,NHDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X
X			/* if multiple newsgroups, include in "show" */
X			if (index(buf,',') != NULL)
X			{
X				(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
X				ngrp = (hdr->show)[hdr->show_num] + NHDLEN;
X				++(hdr->show_num);
X			}
X			else
X				ngrp = str_tstore(Pool,buf+NHDLEN);
X			continue;
X		}
X		if (strncmp(buf,FT_head,FTHDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X			(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
X			flto = (hdr->show)[hdr->show_num] + FTHDLEN;
X			++(hdr->show_num);
X			continue;
X		}
X		if (strncmp(buf,L_head,LHDLEN) == 0)
X		{
X			buf [strlen(buf)-1] = '\0';
X			hdr->lines = atoi(buf+LHDLEN);
X			(hdr->show)[hdr->show_num] = str_tstore(Pool,buf);
X			++(hdr->show_num);
X			continue;
X		}
X	}
X
X	hdr->hlines = n;
X
X#ifdef MAILCHOOSE
X	(hdr->priv)[hdr->priv_num] = resubj;
X	++(hdr->priv_num);
X	if (reply != NULL)
X	{
X		(hdr->priv)[hdr->priv_num] = mail_trim(reply);
X		++(hdr->priv_num);
X	}
X	if (from != NULL)
X	{
X		(hdr->priv)[hdr->priv_num] = mail_trim(from);
X		++(hdr->priv_num);
X	}
X	if (path != NULL)
X	{
X		(hdr->priv)[hdr->priv_num] = mail_trim(path);
X		++(hdr->priv_num);
X	}
X#else
X#ifdef MAILSMART
X	if (reply == NULL)
X		if (from != NULL)
X			reply = from;
X		else
X		{
X			if (path != NULL)
X				reply = path;
X		}
X#else
X	if (path != NULL)
X		reply = path;
X#endif
X	if (reply != NULL)
X	       reply =  mail_trim(reply);
X	mail_cmd(hdr,reply,resubj);
X#endif /* MAILCHOOSE */
X
X	if (flto == NULL)
X	{
X		if ((flto = ngrp) == NULL)
X			flto = "group.unknown";
X	}
X	ngrp = rindex(flto,'.');
X
X	if (strncmp("mod.",flto,4) == 0 ||
X			(ngrp != NULL && strcmp(".announce",ngrp) == 0))
X	{
X		sprintf(buf,"Cannot post a follow-up to \"%s\", reply with mail to moderator",flto);
X		hdr->post_err = str_tstore(Pool,buf);
X		return (fp);
X	}
X
X	if (ngrp != NULL && strcmp(ngrp,".general") == 0)
X	{
X		*ngrp = '\0';
X		sprintf(buf,"%s%s.followup",N_head,flto);
X	}
X	else
X		sprintf(buf,"%s%s",N_head,flto);
X	flto = str_tstore(Pool,buf);
X
X	hdr->post_err = NULL;
X
X	if (resubj != NULL)
X	{
X		(hdr->post)[hdr->post_num] = resubj;
X		++(hdr->post_num);
X	}
X
X	(hdr->post)[hdr->post_num] = flto;
X	++(hdr->post_num);
X
X	sprintf(buf,"%s%s",R_head,hdr->artid);
X	(hdr->post)[hdr->post_num] = str_tstore(Pool,buf);
X	++(hdr->post_num);
X
X	if (dist != NULL)
X	{
X		(hdr->post)[hdr->post_num] = dist;
X		++(hdr->post_num);
X	}
X
X	return (fp);
X}
X
X#ifdef MAILCHOOSE
X/*
X** routine to prompt user for mail path approval
X*/
Xstatic
Xmail_prompt(hdr)
XARTHEADER *hdr;
X{
X	int i;
X	char buf[RECLEN],*ptr;
X
X	tty_set(SAVEMODE);
X	for (i=1; i < hdr->priv_num; ++i)
X	{
X#ifdef amiga
X		sprintf(pr_buf,"%d - %s\n",i,(hdr->priv)[i]);
X		tputs(pr_buf,1,ttputc);
X#else
X		printf("%d - %s\n",i,(hdr->priv)[i]);
X#endif
X	}
X#ifdef amiga
X	sprintf(pr_buf,"\nType number to choose one of the above, or input address: ");
X	tputs(pr_buf,1,ttputc);
X#else
X	printf("\nType number to choose one of the above, or input address: ");
X#endif
X	fgets(buf,RECLEN-1,stdin);
X	tty_set(RESTORE);
X
X	ptr = strtok(buf," \t\n");
X	if (ptr == NULL)
X		ptr = "";
X
X	i = strlen(ptr);
X	if (i == 1)
X	{
X		i = atoi(ptr);
X		if (i > 0 && i <= hdr->priv_num)
X			ptr = (hdr->priv)[i];
X		i = 1;
X	}
X
X	/*
X	** If the user keeps cycling through here on the same article,
X	** we will eventually run out of strings.  We made Pool large
X	** enough to make it unlikely (user will have to retry about 80
X	** times without switching articles).  Hardly elegant, but should
X	** be sufficient.
X	*/
X	if (i > 1 && hdr->priv_num < 8)
X	{
X		(hdr->priv)[hdr->priv_num] = str_tstore(Pool,ptr);
X		++(hdr->priv_num);
X	}
X	mail_cmd(hdr,ptr,(hdr->priv)[0]);
X}
X#endif
X
X/*
X** trim () off potential mail address, and make copy if needed.
X** addr must be allocated string.
X*/
Xstatic char *
Xmail_trim(addr)
Xchar *addr;
X{
X	char buf[RECLEN];
X	char *ptr;
X
X	if (index(addr,'(') == NULL)
X		return(addr);
X
X	strcpy(buf,addr);
X	ptr = index(buf,'(');
X	for (--ptr; *ptr == ' ' || *ptr == '\t'; --ptr)
X		;
X	++ptr;
X	*ptr = '\0';
X	return (str_tstore(Pool,buf));
X}
X
X/*
X** format mail command.  Subj must point to allocated string.
X*/
Xstatic
Xvoid
Xmail_cmd(hdr,addr,subj)
XARTHEADER *hdr;
Xchar *addr, *subj;
X{
X	char buf[RECLEN];
X
X	if (addr == NULL || *addr == '\0')
X	{
X		hdr->mail_err = "No address";
X		return;
X	}
X
X	hdr->mail_err = NULL;
X			;
X
X#ifdef INLETTER
X	hdr->mailcmd = Mailer;
X	sprintf(buf,"%s%s",TO_head,addr);
X	(hdr->mail)[0] = str_tstore(Pool,buf);
X	hdr->mail_num = 1;
X#else
X	sprintf(buf,Mailer,addr);
X	hdr->mailcmd = str_tstore(Pool,buf);
X	hdr->mail_num = 0;
X#endif
X	if (subj != NULL)
X	{
X		(hdr->mail)[hdr->mail_num] = subj;
X		++(hdr->mail_num);
X	}
X}
X
Xvns_aclose(fp)
XFILE *fp;
X{
X 	if (Pool != NULL)
X 		str_tfree(Pool);
X 	Pool = NULL;
X	fclose(fp);
X}
X
X/*
X** we don't use the count / name / mode arguments because this doesn't
X** implement any fancy article massaging
X*/
Xvoid
Xvns_asave(art,fp)
Xint art;
XFILE *fp;
X{
X	char buf[RECLEN];
X	FILE *fin;
X
X	sprintf(buf,"%d",art);
X	if ((fin = fopen(buf,"r")) == NULL)
X		return;
X
X	while (fgets(buf,RECLEN-1,fin) != NULL)
X		fputs(buf,fp);
X	fclose(fin);
X}
X
Xvns_exit()
X{
X}
END_OF_FILE
if test 25324 -ne `wc -c <'std.c'`; then
    echo shar: \"'std.c'\" unpacked with wrong size!
fi
# end of 'std.c'
fi
if test -f 'vn.man' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vn.man'\"
else
echo shar: Extracting \"'vn.man'\" \(24964 characters\)
sed "s/^X//" >'vn.man' <<'END_OF_FILE'
X.TH VN 1 6/1/88
X.UC
X.SH NAME
Xvn - visual news reader
X.SH SYNOPSIS
X.I vn [options]
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
XAs with other readers,
Xoptions may be given on the command line, in which case they will
Xsupersede those given in the
X.B \.newsrc
Xfile.
X.SH OPTIONS
X.I Vn
Xsupports the -n, -x and -t options of
X.I readnews
X(specify newsgroup, read all articles, and specify title).
XIn addition, there some other options: -U, -S, -%, -w, -t and some options
Xbeginning with +.  The "+" options are not recognized within the
X.B \.newsrc
Xfile, only on the command line, and are intended for use in environments
Xwith multiple NNTP installations.  If you are not using an NNTP version,
Xor only have one news installation accessible from a given machine, they
Xare probably of little use.
X.sp
XThe -w (writer
Xor author) 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
XSelects 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, i.e. the results of the
Xlogical "or's" of the -t's and of the -w's are logically "anded" together.
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 the 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
XThe -S option is useful in conjunction with command line -n options.  It is
Xreally not useful in the
X.B \.newsrc
Xfile, but existed before the "+" options were added.
XFor 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.  -S will modify this behavior.
XIf you use an -S option on the command line,
Xthe "!" unsubscriptions will still be used.
X.sp
XThe -% 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.
X.sp
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, i.e. 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
XThe "+" options mainly deal with NNTP.  If you are not using
Xan NNTP version (will be printed in the version message on startup,
Xversion will either be "res" or "nntp"), the +l, +m and +t options
Xare not recognized.
X.sp
XThe +n option must be followed by a filename, and directly specifies the
X.B \.newsrc
Xfile in a manner similar to the NEWSRC variable, which it will override
Xif defined.
X.sp
XThe +m option must be followed by a machine name, and specifies the
Xmachine to talk the news installation on.  This will normally default
Xto some site-determined machine, and may also be set via the VNMACHINE
Xvariable.  The option overrides the variable, if defined.  Note that
Xthis is useful only if you have multiple news INSTALLATIONS accessible
Xfrom your machine, ie. different spooling areas with possibly different
Xsets of articles and different newsgroups based on which machine you
Xcommunicate with to obtain the news.  A majority of sites will not
Xhave this situation, so if you find the explanation confusing, ignore it.
X.sp
XThe +l option makes an NNTP version behave in a non-NNTP fashion, ie.
Xit directly reads the articles and newsgroup information, rather than
Xcommunicating with NNTP.  An empty string for VNMACHINE corresponds to
Xthis.
X.sp
XThe +t option must be followed by a filename, and will cause a trace
Xof the interaction with the NNTP server to be collected into it.
XPrimarily useful for somebody installing the program.
X.SH "USER INTERFACE"
XWhen
X.I vn
Xis invoked,
Xthere will be a pause (with an explanatory "reading" message and
Xa series of newsgroup names) while 
X.I vn
Xreads 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.
XIf this is the first time you are using
X.I vn,
Xor if you are starting with an empty 
X.B \.newsrc
Xfile,
Xthis may take a 
X.I very
Xlong time;
Xthere is a
X.I lot
Xof news out there.
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
Xto your 
X.B \.newsrc
Xfile, 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;
Xthis is
Xshown with an asterisk.
X(Columns 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, or 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
XWhen 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 encryption.
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.
XThese can then
Xbe accessed the same way as 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
XThe order of page presentation is determined by
Xorder of the group lines in the
X.B \.newsrc
Xfile.
XNewsgroups which are not
Xmentioned in
X.B \.newsrc
Xwill be added, as mentioned previously, at then end of the file.
XLines corresponding to non-existent newsgroups will be deleted.
XYou will probably want to run
X.I vn
Xonce, then edit your
X.B \.newsrc
Xfile
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,
Xand 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
Xthis is really what you
Xwant to do.
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         > - next newsgroup [number of newsgroups]
X         < - previous newsgroup [number of newsgroups]
X	 d - unpack digest
X	 H - top of page
X	 L - bottom of page
X	 G - bottom of page (alternate L)
X	 M - middle of page
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 control-x - specify articles to mark
X	 h - toggle flag for display of headers when reading
X	 z - toggle ROT13 mode for reading
X<formfeed> - redraw screen
X	 ! - escape to UNIX to execute a command
X	 " - show vn version
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 placed in 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 exiting the
Xeditor you are prompted to make sure you still want to post or reply.
X.sp
XFor followups, your article is appended to "author_copy" for future
Xreference.
X(See CCFILE in the section on ENVIRONMENT VARIABLES).
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 or VNEDITOR variable, as for
X.I postnews.
X(See the section on ENVIRONMENT VARIABLES).
XIf EDITOR is not set, you get
X.I vi.
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
XWhen articles are saved from anywhere, a few special conventions apply.
X.sp
XIf the name begins with "|", you are specifying
Xa pipe to feed the article(s) to, rather than a file.  No other interpretation
Xis done in this case.
X.sp
XIf you specify a name not beginning with "/", the article will be saved
Xwith reference to your original directory, or with reference to the VNSAVE
Xvariable (see below).
X.sp
XIf you embed a "%d" in the name, that
Xwill be replaced with the article number, or the first number in a list
Xof articles.
X.sp
XIf you prepend "w:" to the
Xname, you can force an overwrite instead of an append.  The colon prefix
Xmay be used to open the file with any mode you please, actually.  If you
Xreally WANT a colon in the name, specify "a:" ahead of it.  The colon
Xprefix is stripped off before any other filename interpretation.
X.sp
XBoth the VNSAVE variable and the save name may use a leading "~" to
Xindicate the user's home or "~name" for another user's home.  It is assumed
Xthat a slash will separate the tilde expression from the rest of VNSAVE, or
Xthe rest of the file name if there are further directories.
X.sp
XWhen you are prompted for a savefile name, the last non-pipe
Xname you used
Xis presented, so you may use your erase/kill keys to edit it.
X.sp
XOld search strings / pattern match strings are also presented for edit in the
Xsame manner.
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 
X.I more
Xof course, the "j" and "k" on the page presentation are 
X.I vi
Xconvention, other page commands are somewhat 
X.I readnews
Xcompatible).
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 are allowed.
XLines not beginning 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 
X.B \.newsrc
Xfile.  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"
XFor all variables which do not begin with "VN", 
X.I vn
Xwill accept an override
Xby setting a variable VN<name> which will be preferred.  For instance
Xsetting VNEDITOR allows you to use a special editor for 
X.I vn
Xwithout affecting
Xuse of that variable by your shell, setting VNPS1 takes care of your
Xnormal UNIX prompt having multiple lines, or setting VNNEWSRC allows you to
Xuse 
X.I vn
Xwithout disturbing your 
X.B \.newsrc
Xfor other readers.
X.TP 24
XVNSAVE
XUsed as a directory to place saved articles in.  If it does not begin
Xwith "/", it will be taken with respect to the users home directory.  If
Xit ends with "/%s", a separate directory will be created for each
Xnewsgroup.
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 
X.I vi.
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 
X.B \.newsrc
Xas 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.TP 24
XVNMACHINE
XApplies only to NNTP versions - sets the machine to talk to.  See discussion
Xof options, above.
X.SH DIAGNOSTICS
XUser error messages.  Self explanatory.
X.SH AUTHOR
XBob McQueer.
X.sp
XSignificant enhancement / bugfixes / suggestions from:
X.sp
XLawrie Brown, John G Dobnick, Greg Earle, Rodney Goke, Andy Marrinson,
XJay Maynard, Marius Olafsson, George Pavel, Dave Tallman, Larry Tepper,
XKarl Williamson, Mark Wittenberg, Andrew Worsley
X.sp
XAnd undoubtedly some others who have been forgotten.  My apologies.
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 
X.I readnews
Xto 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 up to 60 old articles.  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.  During
Xthe reading phase, a warning message is printed that this is happening.
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 recommended
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 
X .B \.newsrc,
Xand 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.
END_OF_FILE
if test 24964 -ne `wc -c <'vn.man'`; then
    echo shar: \"'vn.man'\" unpacked with wrong size!
fi
# end of 'vn.man'
fi
echo shar: End of archive 5 \(of 6\).
cp /dev/null ark5isdone
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.