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

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

	Geez I'm stupid ... neatly segregate the files into appropriately
sized shars, then forget to create and post one!  Here is the remaining
sharfile.

Sorry, Nick.


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  stat.c std.c std.h storage.c strings.c strtok.c svart.c
#   term_set.c tmpnam.c tty.h tty_set.c tune.h
# Wrapped by nick@nswitgould on Tue Nov 28 07:59:57 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'stat.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stat.c'\"
else
echo shar: Extracting \"'stat.c'\" \(4301 characters\)
sed "s/^X//" >'stat.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** stat.c - stat and log file collection
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X#include <stdio.h>
X#include <sys/types.h>
X#ifdef SYSV
X#include <fcntl.h>
X#endif
X
X#ifndef	MINIX
X/* Minix doesn't have sys/file.h for some reason */
X#include <sys/file.h>
X#endif
X
X#include <sys/stat.h>
X#include <pwd.h>
X#include "config.h"
X#include "node.h"
X
Xextern NODE *hashfind();
Xextern char *strtok();
Xextern int Ncount;
Xextern NODE **Newsorder;
X
X#ifdef VNLOGFILE
Xstatic char Start[80];
X#endif
X
Xstat_start()
X{
X#ifdef VNLOGFILE
X	char *ctime();
X	long now;
X
X	time(&now);
X	strcpy(Start,ctime(&now));
X#endif
X}
X
X/*
X** flag = 0, "NO NEWS" type session.
X**      = 1, regular session.
X**	= -1, aborted session
X**
X** CAUTION: routine CALLED from within printex() - do NOT
X** call printex().  Simply do message to stderr on fail.
X*/
Xstat_end(flag)
Xint flag;
X{
X	NODE *nd;
X	char *nl,*index();
X	char *how;
X	struct passwd *ptr, *getpwuid();
X	struct stat buf;
X	long now;
X	char bufr[80];
X	char name[60];
X	FILE *fp;
X	int fd;
X	long chk, rd, pg;
X	int i;
X
X#ifdef VNLOGFILE
X	if (stat(VNLOGFILE,&buf) == 0 && (fp = fopen(VNLOGFILE,"a")) != NULL)
X	{
X		time(&now);
X		strcpy(bufr,ctime(&now));
X		if ((nl = index(bufr,'\n')) != NULL)
X			*nl = '\0';
X		if ((nl = index(Start,'\n')) != NULL)
X			*nl = '\0';
X		if (flag == 0)
X			how = "NO NEWS";
X		else
X		{
X			if (flag > 0)
X				how = "OK";
X			else
X				how = "ABORTED";
X		}
X		ptr = getpwuid (getuid());
X		fprintf(fp, "%s\t%s - %s %s\n", ptr->pw_name, Start, bufr, how);
X		fclose (fp);
X	}
X#endif
X
X#ifdef VNSTATFILE
X	/*
X	** Stat file is done with a fixed record size, and maintaining the
X	** existing record order exactly so that concurrent users will do
X	** the least damage.  If two users actually read & update a single
X	** record simultaneously, we should just lose one user's counts.
X	** Short of implementing a locking scheme, we probably won't do
X	** much better.  Disadvantages are that deleted newsgroups never
X	** get cleaned out, order is set by the first user whose
X	** statistics are collected, it will break if anyone modifies it,
X	** and the file is a bit larger than it needs to be.
X	**
X	** record format:
X	**
X	** CCCCCC PPPPPP RRRRRR newsgroup name ....  \n
X	** ^      ^      ^      ^                    ^
X	** 0      7      14     21              char 79
X	**
X	** CCCCCC - count of sessions searching group
X	** PPPPPP - count of sessions actually finding pages for group
X	** RRRRRR - count of sessions actually accessing articles in group
X	*/
X	if ((fd = open(VNSTATFILE,O_RDWR)) > 0)
X	{
X		bufr[80] = '\0';
X
X		/*
X		** read a record, find the newsgroup, update counts.
X		** If changed, seek back & overwrite.  By using fixed
X		** length records, we should only lose something on
X		** concurrent writes of the same record, and by writing
X		** the ENTIRE record, we keep it consistent
X		*/
X		while ((i = read(fd,bufr,80)) == 80 && bufr[79] == '\n')
X		{
X			chk = atoi(bufr);
X			pg = atoi(bufr+7);
X			rd = atoi(bufr+14);
X			strcpy(name,bufr+21);
X			nl = strtok(name," \n");
X			if (nl == NULL || (nd = hashfind(nl)) == NULL)
X				continue;
X			nd->flags |= FLG_STAT;
X			if ((nd->flags & (FLG_SEARCH|FLG_ACC|FLG_PAGE)) == 0)
X				continue;
X			if ((nd->flags & FLG_SEARCH) != 0)
X				++chk;
X			if ((nd->flags & FLG_PAGE) != 0)
X				++pg;
X			if ((nd->flags & FLG_ACC) != 0)
X				++rd;
X			if (chk > 999999L)
X				chk = 999999L;
X			if (pg > 999999L)
X				pg = 999999L;
X			if (rd > 999999L)
X				rd = 999999L;
X			sprintf(bufr,"%6ld",chk);
X			bufr[6] = ' ';
X			sprintf(bufr+7,"%6ld",pg);
X			bufr[13] = ' ';
X			sprintf(bufr+14,"%6ld",rd);
X			bufr[20] = ' ';
X			lseek(fd,-80L,1);
X			write(fd,bufr,80);
X		}
X
X		/* format screwed up ? */
X		if (i != 0)
X		{
X			lseek(fd,(long) -i,1);
X			fprintf(stderr,"bad data in %s\n",VNSTATFILE);
X		}
X
X		/* may have aborted during vns_news() */
X		if (Newsorder == NULL)
X			Ncount = 0;
X
X		/* now append any groups not in file yet */
X		for (i = 0; i < Ncount; ++i)
X		{
X			nd = Newsorder[i];
X			if ((nd->flags & FLG_STAT) != 0)
X				continue;
X			chk = rd = pg = 0;
X			if ((nd->flags & FLG_SEARCH) != 0)
X				chk = 1;
X			if ((nd->flags & FLG_PAGE) != 0)
X				pg = 1;
X			if ((nd->flags & FLG_ACC) != 0)
X				rd = 1;
X			sprintf(bufr,"%6ld %6ld %6ld %-58s\n",
X					chk, pg, rd, nd->nd_name);
X			write(fd,bufr,80);
X		}
X		close(fd);
X	}
X#endif
X}
END_OF_FILE
if test 4301 -ne `wc -c <'stat.c'`; then
    echo shar: \"'stat.c'\" unpacked with wrong size!
fi
# end of 'stat.c'
fi
if test -f 'std.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'std.c'\"
else
echo shar: Extracting \"'std.c'\" \(24307 characters\)
sed "s/^X//" >'std.c' <<'END_OF_FILE'
X#include <stdio.h>
X#include <pwd.h>
X#include <ctype.h>
X
X#ifndef	MINIX
X/* Minix is missing it */
X#include <sys/param.h>
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#ifndef MAXPATHLEN
X#define MAXPATHLEN 240
X#endif
X
Xextern NODE *hashfind();
Xextern FILE *fopen();
Xextern char *index(), *rindex();
Xextern char *malloc();
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
X/*
X**	environment setup.
X*/
Xvns_envir()
X{
X 	char dbuf[MAXPATHLEN], *rcname;
X	char *vn_env();
X	struct passwd *ptr, *getpwuid();
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 != '/')
X	{
X		sprintf (dbuf, "%s/%s",ptr->pw_dir,rcname);
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 	strcpy(rindex(dbuf,'/')+1,".vnXXXXXX");
X	mktemp(dbuf);
X	Onews = str_store (dbuf);
X
X	if (access (Newsrc,0) != 0)
X		creat (Newsrc,0666);
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	sprintf (t,"%s/%s",SPOOLDIR,s);
X	for (ptr=t+strlen(SPOOLDIR)+1; (ptr = index(ptr,'.')) != NULL; *ptr = '/')
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
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
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
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	char *nfgets();
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	char *mail_trim();
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		printf("%d - %s\n",i,(hdr->priv)[i]);
X	}
X	printf("\nType number to choose one of the above, or input address: ");
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
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*/
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 24307 -ne `wc -c <'std.c'`; then
    echo shar: \"'std.c'\" unpacked with wrong size!
fi
# end of 'std.c'
fi
if test -f 'std.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'std.h'\"
else
echo shar: Extracting \"'std.h'\" \(886 characters\)
sed "s/^X//" >'std.h' <<'END_OF_FILE'
X/*
X	newsrc states
X*/
X#define NEWS_ON ':'
X#define NEWS_OFF '!'
X
X#define SFLG_SCAN 1
X#define SFLG_SPEC 2
X
X#define FPFIX "Re: "
X#define FPFLEN 4
X
X#define FIL_AUTHOR 'w'
X#define FIL_TITLE 't'
X
X/*
X	header lines and associated lengths.  Strings should
X	actually be used only once.
X*/ 
X#define RHEAD "References: "
X#define RHDLEN 12
X#define MHEAD "Message-ID: "
X#define MHDLEN 12
X#define PHEAD "Path: "
X#define PHDLEN 6
X#define DHEAD "Date: "
X#define DHDLEN 6
X#define RTHEAD "Reply-To: "
X#define RTHDLEN 10
X#define TOHEAD "To: "
X#define TOHDLEN 4
X#define FHEAD "From: "
X#define FHDLEN 6
X#define FTHEAD "Followup-To: "
X#define FTHDLEN 13
X#define DISHEAD "Distribution: "
X#define DISHDLEN 14
X#define THEAD "Subject: "
X#define THDLEN 9
X#define LHEAD "Lines: "
X#define LHDLEN 7
X#define NHEAD "Newsgroups: "
X#define NHDLEN 12
X
X#define CHFIRST "FSL"	/* first char's of those used in page display */
END_OF_FILE
if test 886 -ne `wc -c <'std.h'`; then
    echo shar: \"'std.h'\" unpacked with wrong size!
fi
# end of 'std.h'
fi
if test -f 'storage.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'storage.c'\"
else
echo shar: Extracting \"'storage.c'\" \(2261 characters\)
sed "s/^X//" >'storage.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** storage.c - storage allocation routines
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X
Xextern char *malloc();
X
Xextern int L_allow;
X
Xextern PAGE Page;
X/*
X	Storage allocaters.
X*/
X
Xchar *str_store (s)
Xchar *s;
X{
X	static unsigned av_len = 0;	/* current storage available */
X	static char *avail;
X	int len;
X
X	if (s == NULL)
X		s = "";
X
X	if ((len = strlen(s)+1) > av_len)
X	{
X		if (len > STRBLKSIZE)
X			av_len = len;
X		else
X			av_len = STRBLKSIZE;
X		if ((avail = malloc(av_len)) == NULL)
X			printex ("can't allocate memory for string storage");
X	}
X	strcpy (avail,s);
X	s = avail;
X	avail += len;
X	av_len -= len;
X	return (s);
X}
X
X/*
X** called after number of terminal lines (L_allow) is known, to set
X** up storage for Page.
X*/
Xpage_alloc ()
X{
X	char *body;
X
X	if ((body = malloc(L_allow*sizeof(BODY))) == NULL)
X		printex ("can't allocate memory for display storage");
X
X	Page.b = (BODY *) body;
X}
X
XNODE
X*node_store()
X{
X	static int nd_avail = 0;
X	static NODE *nd;
X	NODE *ret;
X
X	if (nd_avail <= 0)
X	{
X		if ((nd = (NODE *) malloc(sizeof(NODE)*NDBLKSIZE)) == NULL)
X			printex ("can't allocate memory for newsgroup table");
X		nd_avail = NDBLKSIZE;
X	}
X	--nd_avail;
X	ret = nd;
X	++nd;
X	return(ret);
X}
X
X/*
X** temp string storage
X*/
X
Xtypedef struct
X{
X	int len;
X	int idx;
X	char **ptr;
X} STRINGPOOL;
X
Xchar *
Xstr_tpool(n)
Xint n;
X{
X	int size;
X	STRINGPOOL *p;
X
X	size = sizeof(STRINGPOOL) + n * sizeof(char **);
X
X	if ((p = (STRINGPOOL *) malloc(size)) == NULL)
X		printex("Cannot allocate temporary string storage");
X
X	p->ptr = (char **)(p+1);
X	p->len = n;
X	p->idx = 0;
X
X	return((char *) p);
X}
X
Xchar *
Xstr_tstore(cp,s)
Xchar *cp;
Xchar *s;
X{
X	STRINGPOOL *p;
X	int len;
X
X	p = (STRINGPOOL *) cp;
X	if (p->idx >= p->len)
X		printex("Temporary string storage overflow");
X	len = strlen(s)+1;
X	if ((cp = malloc(len)) == NULL)
X		printex("Cannot allocate copy of string");
X	strcpy(cp,s);
X	(p->ptr)[p->idx] = cp;
X	++(p->idx);
X
X	return(cp);
X}
X
Xchar **
Xstr_taptr(cp)
Xchar *cp;
X{
X	STRINGPOOL *p;
X
X	p = (STRINGPOOL *) cp;
X
X	return (p->ptr + p->idx);
X}
X
Xstr_tfree(cp)
Xchar *cp;
X{
X	STRINGPOOL *p;
X	int i;
X
X	p = (STRINGPOOL *) cp;
X	for (i=0; i < p->idx; ++i)
X		free((p->ptr)[i]);
X	free (cp);
X}
END_OF_FILE
if test 2261 -ne `wc -c <'storage.c'`; then
    echo shar: \"'storage.c'\" unpacked with wrong size!
fi
# end of 'storage.c'
fi
if test -f 'strings.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'strings.c'\"
else
echo shar: Extracting \"'strings.c'\" \(537 characters\)
sed "s/^X//" >'strings.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** strings.c - read only character strings
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X
Xchar *Version = "4/88";
X
Xchar *No_msg = "No articles";
Xchar *Hdon_msg = "Headers being printed";
Xchar *Hdoff_msg = "Headers being suppressed";
Xchar *Roton_msg = "ROT 13";
Xchar *Rotoff_msg = "NO ROT";
X
Xchar *Aformat = AFORMAT;
X
Xchar *Contstr = "  ******** any key to continue ********";
X
Xchar *Brk_fmt = "QUIT (signal %d)";
X
Xchar *List_sep = " \t,";
END_OF_FILE
if test 537 -ne `wc -c <'strings.c'`; then
    echo shar: \"'strings.c'\" unpacked with wrong size!
fi
# end of 'strings.c'
fi
if test -f 'strtok.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'strtok.c'\"
else
echo shar: Extracting \"'strtok.c'\" \(1082 characters\)
sed "s/^X//" >'strtok.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** strtok.c - strtok() and strpbrk() string routines using UCB index().
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X
Xchar *strpbrk (s,del)
Xchar *s, *del;
X{
X	char *ptr,*index();
X	if (s == NULL)
X		return (NULL);
X	for (; *del != '\0'; ++del)
X		if ((ptr = index(s,*del)) != NULL)
X			return (ptr);
X	return (NULL);
X}
X
Xchar *strtok(str,delim)
Xchar *str, *delim;
X{
X	char *tokstart, *tokend, *first_ch (), *last_ch();
X	static char *save=NULL;
X
X	if (str != NULL)
X		save = str;
X
X	if (save == NULL)
X		return (NULL);
X
X	tokstart = first_ch (save, delim);
X	tokend = last_ch (tokstart, delim);
X	save = first_ch (tokend, delim);
X	*tokend = '\0';
X
X	if (*tokstart == '\0')
X		return (NULL);
X
X	return (tokstart);
X}
X
Xstatic char *first_ch (str,delim)
Xchar *str,*delim;
X{
X	char *index ();
X	char *f;
X
X	for (f = str; *f != '\0' && index(delim,*f) != NULL; ++f)
X		;
X
X	return (f);
X}
X
Xstatic char *last_ch (str,delim)
Xchar *str,*delim;
X{
X	char *index ();
X	char *f;
X
X	for (f = str; *f != '\0' && index(delim,*f) == NULL; ++f)
X		;
X
X	return (f);
X}
END_OF_FILE
if test 1082 -ne `wc -c <'strtok.c'`; then
    echo shar: \"'strtok.c'\" unpacked with wrong size!
fi
# end of 'strtok.c'
fi
if test -f 'svart.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'svart.c'\"
else
echo shar: Extracting \"'svart.c'\" \(4834 characters\)
sed "s/^X//" >'svart.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** svart.c - article save routine
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X#include <stdio.h>
X#include <pwd.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include "config.h"
X#include "tty.h"
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X
Xextern PAGE Page;
Xextern int Digest;
Xextern char *List_sep;
Xextern char *Home;
Xextern char *Savedir;
Xextern FILE *(*Saveopen)();
Xextern int (*Digsaver)();
X
X/*
X** save article in file.  Called from reader and session both.
X** handles "|" pipe convention.  Caller passes in return message buffer.
X*/
Xsave_art(art,idest,msg)
Xchar *art;
Xchar *idest;
Xchar *msg;
X{
X	char fn[L_tmpnam+1];
X	char cmd[RECLEN];
X	char *mode;
X	char *dest, dstore[RECLEN];
X	struct stat sbuf;
X	int rstat;
X	char *colon;
X	char *pcnt;
X	char *index();
X
X	/* temporary copy so we don't overwrite saved string */
X	strcpy((dest = dstore),idest);
X
X	if (*dest == '|')
X	{
X		tmpnam(fn);
X		if (art_xfer(fn,art,"w",NULL) != 0)
X		{
X			strcpy(msg,"Can't open temporary file");
X			return (-1);
X		}
X		sprintf(cmd,"cat %s %s",fn,dest);
X		tty_set (SAVEMODE);
X		rstat = system (cmd);
X		tty_set (RESTORE);
X		sprintf(msg,"Command returns %d",rstat);
X		return (rstat);
X	}
X
X	if (Saveopen != NULL)
X		return (art_xfer(dest,art,"a",msg));
X
X	if ((colon = index(dest,':')) != NULL)
X	{
X		mode = dest;
X		*colon = '\0';
X		dest = colon+1;
X	}
X	else
X		mode = "a";
X
X	if (*dest == '~')
X	{
X		if (twiddle(dest,msg) < 0)
X			return (-1);
X	}
X
X	if (*dest == '\0')
X		strcpy(dest,"%d");
X
X	if (*dest != '/')
X	{
X		if (noslash(dest,msg) < 0)
X			return (-1);
X	}
X
X	if ((pcnt = index(dest,'%')) != NULL && pcnt[1] == 'd')
X	{
X		if (Digest)
X			sprintf(cmd,dest,Digest);
X		else
X			sprintf(cmd,dest,atoi(art));
X		dest = cmd;
X	}
X
X	rstat = stat(dest,&sbuf);
X
X	if (art_xfer(dest,art,mode,msg) != 0)
X	{
X		sprintf(msg,"Can't open %s with mode %s",dest,mode);
X		return(-1);
X	}
X
X	if (rstat != 0)
X	{
X		sprintf(msg,"Created %s",dest);
X		return(0);
X	}
X
X	if (strcmp(mode,"a") == 0)
X	{
X		sprintf(msg,"Appended %s",dest);
X		return(0);
X	}
X
X	sprintf(msg,"Wrote (mode %s) %s",mode,dest);
X	return(0);
X}
X
Xstatic
Xnoslash(dest,msg)
Xchar *dest;
Xchar *msg;
X{
X	char *pcnt;
X	char buf[RECLEN];
X	char dir[RECLEN];
X	struct stat sbuf;
X
X	strcpy(buf,Page.h.name);
X#ifdef SYSV
X	buf[14] = '\0';
X#endif
X	if ((pcnt = index(Savedir,'%')) != NULL && pcnt[1] == 's')
X		sprintf(dir,Savedir,buf);
X	else
X		strcpy(dir,Savedir);
X	if (dir[0] == '~')
X	{
X		if (twiddle(dir,msg) < 0)
X			return (-1);
X	}
X	if (stat(dir,&sbuf) != 0)
X	{
X#ifdef SYSV
X		/*
X		** late enough releases of SYSV may have a mkdir() call, but
X		** this is an obscure feature anyway.  We'll accept the fork.
X		*/
X		sprintf(buf,"mkdir %s",dir);
X		if (system(buf) != 0)
X#else
X		if (mkdir(dir,0755) != 0)
X#endif
X		{
X			sprintf(msg,"Cannot make directory %s",dir);
X			return (-1);
X		}
X	}
X	sprintf(buf,"%s/%s",dir,dest);
X	strcpy(dest,buf);
X	return (0);
X}
X
Xstatic
Xtwiddle(dest,msg)
Xchar *dest, *msg;
X{
X	char *tail;
X	char *name;
X	char tmp;
X	char buf[RECLEN];
X	struct passwd *ptr, *getpwnam();
X
X	for (tail=name=dest+1; *tail != '/' && *tail != '\0'; ++tail)
X		;
X
X	if (*name == '\0' || *name == '/')
X		sprintf(buf,"%s%s",Home,tail);
X	else
X	{
X		tmp = *tail;
X		*tail = '\0';
X		ptr = getpwnam(name);
X		*tail = tmp;
X		if (ptr == NULL)
X		{
X			sprintf(msg,"Can't interpret ~%s",name);
X			return(-1);
X		}
X		sprintf(buf,"%s%s",ptr->pw_dir,tail);
X	}
X
X	strcpy(dest,buf);
X	return (0);
X}
X
X/*
X** transfer contents of a list of articles to a file.  If Digest, this
X** is simply a list of files.  If not, it is a list of articles to be
X** saved with vns_asave.  Parses list destructively with
X** strtok().  Return 0 for success, -1 for failure to open file.
X**
X** Called directly to copy a list of articles to a temp. file to
X** direct to printer.
X**
X** NOTE:
X**	The msg argument only matters if Saveopen is not NULL.  If so, it
X**	is non-NULL if *Saveopen is to be called, and points to the message
X**	buffer.  Will be called with msg = NULL to fill temp. files rather
X**	than user named files.  If *Saveopen is called, mode argument is
X**	actually returned by it, and only matters for vns_asave call.
X*/
Xart_xfer(fn,list,mode,msg)
Xchar *fn, *list, *mode, *msg;
X{
X	char *p;
X	FILE *fout, *fin;
X	int count;
X	char buf[RECLEN];
X	char *strtok();
X
X	if (Saveopen != NULL && msg != NULL)
X		fout = (*Saveopen)(fn,msg,&mode);
X	else
X		fout = fopen(fn,mode);
X	if (fout == NULL)
X		return (-1);
X
X	count = 0;
X	for (p = strtok(list,List_sep); p != NULL; p = strtok(NULL,List_sep))
X	{
X		if (Digest)
X		{
X			if (Digsaver != NULL)
X			{
X				(*Digsaver)(p,fout,count,fn,mode);
X				++count;
X				continue;
X			}
X			fin = fopen(p,"r");
X			if (fin == NULL)
X				continue;
X			while (fgets(buf,RECLEN-1,fin) != NULL)
X				fputs(buf,fout);
X			fclose(fin);
X			continue;
X		}
X		vns_asave(atoi(p),fout,count,fn,mode);
X		++count;
X	}
X	fclose(fout);
X	return(0);
X}
END_OF_FILE
if test 4834 -ne `wc -c <'svart.c'`; then
    echo shar: \"'svart.c'\" unpacked with wrong size!
fi
# end of 'svart.c'
fi
if test -f 'term_set.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'term_set.c'\"
else
echo shar: Extracting \"'term_set.c'\" \(4953 characters\)
sed "s/^X//" >'term_set.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** term_set.c - terminal control, hides termcap interface
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include "tty.h"
X#include "config.h"
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X
Xextern int L_allow, C_allow;
Xextern char *Ku, *Kd, *Kl, *Kr;	
X
Xstatic outc (c)
Xchar c;
X{
X	putchar (c);
X}
X
X/*
X	term_set controls terminal through termcap
X	START sets global parameters related to terminal also,
X	as well as allocating display buffer which depends on
X	terminal lines, and allocating escape strings.  RESTART
X	simply re-issues the initialization - used following system
X	calls that could have goofed up the terminal state.
X*/
X
X/*
X** Escape strings.
X*/
X
Xstatic char *Cm,*Cl,*So,*Se,*Te,*Bc,*Ce,*Ti,*Ks,*Ke;
X#ifdef USEVS
Xstatic char *Vs,*Ve;
X#endif
X
Xstatic int Backspace;		/* backspace works */
Xstatic int Overstrike;		/* terminal overstrikes */
X
Xstatic t_setup()
X{
X	char *tgetstr(), *vn_env(), *str_store();
X	char *c, tc_buf[2048],optstr[2048];
X	char *tvar;
X
X	tvar = vn_env("TERM",DEF_TERM);
X
X	c = optstr;
X	if (tgetent(tc_buf,tvar) != 1)
X		printex ("%s - unknown terminal",tvar);
X
X	/* get needed capabilities */
X	Cm = str_store(tgetstr("cm",&c));
X	Cl = str_store(tgetstr("cl",&c));
X	So = str_store(tgetstr("so",&c));
X	Se = str_store(tgetstr("se",&c));
X	Te = str_store(tgetstr("te",&c));
X	Ti = str_store(tgetstr("ti",&c));
X	Bc = str_store(tgetstr("bc",&c));
X	Ce = str_store(tgetstr("ce",&c));
X	Kd = str_store(tgetstr("kd",&c));
X	Ke = str_store(tgetstr("ke",&c));
X	Kl = str_store(tgetstr("kl",&c));
X	Kr = str_store(tgetstr("kr",&c));
X	Ks = str_store(tgetstr("ks",&c));
X	Ku = str_store(tgetstr("ku",&c));
X#ifdef USEVS
X	Vs = str_store(tgetstr("vs",&c));
X	Ve = str_store(tgetstr("ve",&c));
X#endif
X	Backspace = tgetflag("bs");
X	Overstrike = tgetflag("os");
X
X	if ( *Cm == '\0' || *Cl == '\0')
X	{
X		printex ("cursor control and erase capability needed");
X	}
X
X	/*
X	** Checks for arrow keys which don't issue something beginning
X	** with <ESC>.  This is more paranoid than we need to be, strictly
X	** speaking - we could get away with any string which didn't
X	** conflict with controls used for commands.  However, that would
X	** be a maintenance headache - we will simply reserve <ESC> as the
X	** only char not to be used for commands, and punt on terminals
X	** which don't send reasonable arrow keys.  It would be confusing
X	** to have keys work partially, also.  I know of no terminal with
X	** one arrow key beginning with an escape, and another beginning
X	** with something else, but let's be safe.  This also insists on
X	** definitions for all 4 arrows, which seems reasonable.
X	*/
X
X	if ((*Ku != '\0' && *Ku != '\033') || *Kl != *Ku || *Kr != *Ku || *Kd != *Ku)
X	{
X		fgprintf("WARNING: arrow keys will not work for this terminal");
X		Ku = Kd = Kl = Kr = Kd = Ke = "";
X	}
X
X	if (Overstrike)
X		fgprintf ("WARNING: terminal overstrikes - can't update display without erase\n");
X
X	if ((L_allow = tgetnum("li")) < REQLINES)
X	{
X		if (L_allow < 0)
X			printex ("can't determine number of lines on terminal");
X		printex ("too few lines for display - %d needed", REQLINES);
X	}
X
X	/*
X	** C_allow set so as to not use extreme right column.
X	** Avoids "bad wraparound" problems - we're deciding it's best
X	** to ALWAYS assume no automargin, and take care of it ourselves
X	*/
X	if((C_allow = tgetnum("co")) > MAX_C)
X		C_allow = MAX_C;
X	else
X		--C_allow;
X	if (C_allow < MIN_C)
X	{
X		if (C_allow < 0)
X			printex("can't determine number of columns on terminal.");
X		printex ("too few columns for display - %d needed",MIN_C);
X	}
X
X	L_allow -= RECBIAS;
X	page_alloc();
X	tputs(Ti,1,outc);
X	tputs(Ks,1,outc);
X#ifdef USEVS
X	tputs(Vs,1,outc);
X#endif
X}
X
X/* VARARGS */
Xterm_set(cmd,x,y)
Xint cmd,x,y;
X{
X	char *tgoto();
X	int i;
X	switch (cmd)
X	{
X	case MOVE:
X		tputs (tgoto(Cm,x,y),1,outc);
X		break;
X	case ERASE:
X		tputs(Cl,1,outc);
X		break;
X	case ONREVERSE:
X		tputs(So,1,outc);
X		break;
X	case OFFREVERSE:
X		tputs(Se,1,outc);
X		break;
X	case START:
X		t_setup();
X		break;
X	case RESTART:
X		tputs(Ti,1,outc);
X		tputs(Ks,1,outc);
X#ifdef USEVS
X		tputs(Vs,1,outc);
X#endif
X		break;
X	case STOP:
X		term_set (MOVE,0,L_allow+RECBIAS-1);
X		printf ("\n");
X		tputs(Ke,1,outc);
X		tputs(Te,1,outc);
X#ifdef USEVS
X		tputs(Ve,1,outc);
X#endif
X		break;
X	case RUBSEQ:
X		if (Overstrike)
X		{
X			/* space overprint is futile */
X			if (Backspace)
X				putchar('\010');
X			else
X				tputs(Bc,1,outc);
X			break;
X		}
X		if (Backspace)
X			printf("%c %c",'\010','\010');
X		else
X		{
X			tputs(Bc,1,outc);  
X			putchar(' ');  
X			tputs(Bc,1,outc);
X		}
X		break;
X	case ZAP:
X		if (Ce != NULL && *Ce != '\0')
X			tputs(Ce,1,outc);
X		else
X		{
X			if (Overstrike)
X				break;		/* punt */
X			for (i=x; i < y; ++i)
X				putchar(' ');
X			if (Backspace)
X			{
X				for (i=x; i < y; ++i)
X					putchar('\010');
X			}
X			else
X			{
X				for (i=x; i < y; ++i)
X					tputs(Bc,1,outc);
X			}
X		}
X		break;
X	default:
X		printex ("term_set unknown code (%d)",cmd);
X		break;
X	}
X	return (0);
X}
END_OF_FILE
if test 4953 -ne `wc -c <'term_set.c'`; then
    echo shar: \"'term_set.c'\" unpacked with wrong size!
fi
# end of 'term_set.c'
fi
if test -f 'tmpnam.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tmpnam.c'\"
else
echo shar: Extracting \"'tmpnam.c'\" \(420 characters\)
sed "s/^X//" >'tmpnam.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** tmpnam.c - tmpnam() replacement for UCB, also uses non-generic name.
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include "config.h"
X
Xchar *tmpnam (buf)
Xchar *buf;
X{
X	static char *ptr = VNTEMPNAME;
X
X	/* depends on string initialized above */
X	sprintf (ptr+TMP_XOFFSET,"XXXXXX");
X
X	mktemp (ptr);
X
X	if (buf != NULL)
X		strcpy (buf,ptr);
X
X	return (ptr);
X}
END_OF_FILE
if test 420 -ne `wc -c <'tmpnam.c'`; then
    echo shar: \"'tmpnam.c'\" unpacked with wrong size!
fi
# end of 'tmpnam.c'
fi
if test -f 'tty.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tty.h'\"
else
echo shar: Extracting \"'tty.h'\" \(451 characters\)
sed "s/^X//" >'tty.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** tty.h - codes for tty_set and term_set
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#define MOVE 100
X#define ERASE 101
X#define START 102
X#define STOP 103
X#define RUBSEQ 104
X#define ZAP 105
X#define ONREVERSE 106
X#define OFFREVERSE 107
X#define RESTART 108
X
X#define RAWMODE 200
X#ifndef	MINIX
X#define COOKED 201
X#else
X#define XCOOKED 201
X#endif
X#define SAVEMODE 202
X#define RESTORE 203
X#define BACKSTOP 204
END_OF_FILE
if test 451 -ne `wc -c <'tty.h'`; then
    echo shar: \"'tty.h'\" unpacked with wrong size!
fi
# end of 'tty.h'
fi
if test -f 'tty_set.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tty_set.c'\"
else
echo shar: Extracting \"'tty_set.c'\" \(2713 characters\)
sed "s/^X//" >'tty_set.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** tty_set.c - interface to ioctl (system tty interface)
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#ifdef	MINIX
X/* Minix uses non-SysV type ioctls */
X#undef	SYSV
X#endif
X
X#ifdef SYSV
X#include <termio.h>
X#else
X#include <sgtty.h>
X#endif
X
X#include "tty.h"
X
Xextern char Erasekey,Killkey;
X
X#ifdef SYSV
Xstatic struct termio C_tp, O_tp;
X#else
Xstatic struct sgttyb C_tp;
Xstatic unsigned short O_lflag;
X#endif
X
Xstatic unsigned S_flag=0;
Xstatic int R_ignore=0;		/* up/down counter of reset calls to ignore */
X
X#define IO_GOT 1	/* have polled for original terminal mode */
X#define IO_RAW 2	/* in RAW (CBREAK actually) mode */
X
X/*
X	tty_set handles ioctl calls.  SAVEMODE, RESTORE are used around
X	system calls and interrupts to assure cooked mode, and restore
X	raw if raw on SAVEMODE.  The pair results in no calls to ioctl
X	if we are cooked already when SAVEMODE is called, and may be nested,
X	provided we desire no "restore" of cooked mode after restoring raw.
X
X	When we get the original terminal mode, we also save erase and kill.
X
X	sig_set makes an ioctl call to get process group leader.  Otherwise
X	ioctl calls should come through here.
X*/
Xtty_set(cmd)
Xint cmd;
X{
X	int rc;
X	unsigned mask;
X
X	switch (cmd)
X	{
X	case BACKSTOP:
X#ifdef JOBCONTROL
X		if ((rc = ioctl(1,TIOCLGET,&mask)) != 0)
X			break;
X		mask |= LTOSTOP;
X		rc = ioctl(1,TIOCLSET,&mask);
X#else
X		rc = 0;
X#endif
X		break;
X	case RAWMODE:
X		if ((S_flag & IO_RAW) != 0)
X		{
X			rc = 0;
X			break;
X		}
X		if ((S_flag & IO_GOT) == 0)
X		{
X			/* Save original modes, get erase / kill */
X#ifdef SYSV
X			rc = ioctl(0,TCGETA,&C_tp);
X			O_tp = C_tp;
X			Erasekey = C_tp.c_cc[VERASE];
X			Killkey = C_tp.c_cc[VKILL];
X#else
X			rc = ioctl(0,TIOCGETP,&C_tp);
X			O_lflag = C_tp.sg_flags;
X			Erasekey = C_tp.sg_erase;
X			Killkey = C_tp.sg_kill;
X#endif
X		}
X#ifdef SYSV
X		C_tp.c_lflag &= ~(ECHO | ICANON);
X		C_tp.c_cc[VMIN] = 1;
X		rc = ioctl(0,TCSETAW,&C_tp);
X#else
X		C_tp.sg_flags |= CBREAK;
X		C_tp.sg_flags &= ~ECHO;
X		rc = ioctl(0,TIOCSETP,&C_tp);
X#endif
X		S_flag = IO_GOT|IO_RAW;
X		break;
X#ifndef	MINIX
X	case COOKED:
X#else
X	case XCOOKED:
X#endif
X		if ((S_flag & IO_RAW) != 0)
X		{
X#ifdef SYSV
X			C_tp = O_tp;
X			rc = ioctl(0,TCSETAW,&C_tp);
X#else
X			C_tp.sg_flags = O_lflag;
X			rc = ioctl(0,TIOCSETP,&C_tp);
X#endif
X			S_flag &= ~IO_RAW;
X		}
X		else
X			rc = 0;
X		break;
X	case SAVEMODE:
X		if ((S_flag & IO_RAW) != 0)
X		{
X#ifndef	MINIX
X			tty_set(COOKED);
X#else
X			tty_set(XCOOKED);
X#endif
X			R_ignore = 0;
X		}
X		else
X			++R_ignore;
X		rc = 0;
X		break;
X	case RESTORE:
X		if (R_ignore <= 0)
X		{
X			tty_set(RAWMODE);
X		}
X		else
X			--R_ignore;
X		rc = 0;
X		break;
X	default:
X		rc = -1;
X	}
X	if (rc < 0)
X		printex ("ioctl failure, tty_set: %d",cmd);
X}
END_OF_FILE
if test 2713 -ne `wc -c <'tty_set.c'`; then
    echo shar: \"'tty_set.c'\" unpacked with wrong size!
fi
# end of 'tty_set.c'
fi
if test -f 'tune.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tune.h'\"
else
echo shar: Extracting \"'tune.h'\" \(2198 characters\)
sed "s/^X//" >'tune.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** tune.h - system tuning parameters
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X/*
X**	buffer size needed for tmpnam()
X*/
X#ifndef L_tmpnam
X#define L_tmpnam 48
X#endif
X
X/*
X** hash table size.  linked list type of table which can expand to
X** arbitrary density, including densities > 100%.  Number of entries
X** will be number of newsgroups in active list.  This should be a prime
X** number ("long division" of string modulo table size hash function).
X*/
X#define HASHSIZE 809
X
X/*
X**	maximum number of columns on terminal.  If made smaller, there
X**	will be a savings in the size of the temporary file used
X**	for holding displays, at the penalty of not being able to use
X**	the entire screen width on terminals actually possessing more
X**	columns than this.  A block roughly on the order of this value
X**	times the number of lines the terminal has is maintained per page in
X**	the temp file, and read / written as displays are interacted
X**	with.  MIN_C put here because MAX_C > MIN_C.  MIN_C is the minumum
X**	number of columns for which a "reasonable" display can be produced.
X**	before making it smaller, look at all uses of C_allow and variable
X**	to see that a setting that small won't screw up array bounds.
X*/
X#define MAX_C 132
X#define MIN_C 36
X
X/*
X**	large size for general purpose local buffers.  only used in automatic
X**	variable declarations.  Used with fgets for buffer size when reading
X**	file records, to hold pathnames, commands, etc.  Reduce if you blow
X**	out stack storage.  If reduced too far, may eventually show up
X**	as syntax errors on interacting with vns_ routines, or command line
X**	botches.
X*/
X#define RECLEN 1200
X
X/* block sizes for allocation routines */
X#define STRBLKSIZE 1800	/* string storage allocation block */
X#define NDBLKSIZE 50	/* NODE structures to allocate at a time */
X
X/*
X** maximum number of articles to allow for processing in a single user
X** list.  Used only to declare an array of pointers on the stack, so it
X** can be fair sized without much problem.  In practicality, there is
X** no use for it being larger than the greatest line length available
X** on the CRT's being used.
X*/
X#define MAXARTLIST 200
END_OF_FILE
if test 2198 -ne `wc -c <'tune.h'`; then
    echo shar: \"'tune.h'\" unpacked with wrong size!
fi
# end of 'tune.h'
fi
echo shar: End of shell archive.
exit 0
-- 
		"Zeta Microcomputer Software"
ACSnet:    nick@ultima.cs.uts.oz
UUCP:      ...!uunet!munnari!ultima.cs.uts.oz!nick
Fidonet:   Nick Andrew on 3:713/602 (Zeta)