v13i023: VN newsreader, 1/88 version, Part05/05

Rich Salz rsalz at bbn.com
Sat Feb 6 02:47:57 AEST 1988


Submitted-by: Bob Mcqueer <amdahl!rtech!rtech!bobm at UUNET.UU.NET>
Posting-number: Volume 13, Issue 23
Archive-name: vn.jan.88/part05

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	session.c
#	reader.c
#	config.h
export PATH; PATH=/bin:$PATH
echo shar: extracting "'session.c'" '(19476 characters)'
if test -f 'session.c'
then
	echo shar: will not over-write existing file "'session.c'"
else
cat << \SHAR_EOF > 'session.c'
/*
** vn news reader.
**
** session.c - top session loop
**
** see copyright disclaimer / history in vn.c source file
*/
#include <stdio.h>
#include <setjmp.h>
#include "config.h"
#include "tty.h"
#include "brk.h"
#include "head.h"
#include "tune.h"
#include "node.h"
#include "page.h"
#include "vn.h"

extern NODE **Newsorder;
extern char Erasekey, Killkey;
extern int Rot;
extern char *Ps1,*Printer;
extern char *Orgdir,*Savefile;
extern int Ncount, Cur_page, Lrec, L_allow, C_allow;
extern int Headflag;
extern PAGE Page;
extern int Digest;
extern char *No_msg;
extern char *Hdon_msg;
extern char *Hdoff_msg;
extern char *Roton_msg;
extern char *Rotoff_msg;
extern char Cxitop[], Cxptoi[];
extern char *Aformat;
extern char *Contstr;
extern char *Kl,*Kr,*Ku,*Kd;
extern int Nounsub, Listfirst;
extern char *List_sep;
extern char *Version, *Vns_version;

extern int (*Headedit)();

static int C_info;
static int Dskip, Drec;

static char *Unsub_msg = "Unsubscribed";
static char *Egroup_msg = "Entire newsgroup";

static int Crec;
static int Highrec;

/*
	main session handler processing input commands

	NOTE: this is where a setjmp call is made to set the break reentry
		location.  Keep the possible user states in mind.
*/
session ()
{
	char alist [RECLEN], c;
	int newg, i, count;
	jmp_buf brkbuf;

	newg = new_groups();
	tty_set (RAWMODE);
	find_page (0);
	Digest = 0;

	/* reentry point for break from within session interaction */
	setjmp (brkbuf);
	sig_set (BRK_SESS,brkbuf);
	Headflag = FALSE;
	Rot = 0;

	/* done this way so that user gets "really quit?" break treatment */
	if (newg > 0)
	{
		printf ("\n%s",Contstr);
		getnoctl();
		newg = 0;
	}

	/* list preview option - clear after first time for long jumps */
	if (Listfirst)
	{
		/* tot_list settings will be overwritten in this case */
		tot_list();
		Listfirst = 0;
	}

	/* if breaking from a digest, recover original page */
	if (Digest)
	{
		find_page(Cur_page);
		Digest = 0;
	}
	show ();
	Crec = RECBIAS;
	Highrec = Page.h.artnum + RECBIAS;
	term_set (MOVE,0,Crec);

	/*
		handle commands until QUIT, update global/local status
		and display for each.
	 */
	for (count = getkey(&c); c != QUIT; count = getkey(&c))
	{
		if ( srch_help(c,&i) != 0 || (Digest != 0 && i == 0))
		{
			preinfo (UDKFORM,Cxptoi[HELP]);
			term_set (MOVE, 0, Crec);
			continue;
		}

		switch (c)
		{
		case HEADTOG:
			if (Headedit != NULL)
			{
				term_set(ERASE);
				(*Headedit)();
				show();
				term_set (MOVE,0,Crec);
				break;
			}
			if (Headflag)
			{
				Headflag = FALSE;
				prinfo (Hdoff_msg);
			}
			else
			{
				Headflag = TRUE;
				prinfo (Hdon_msg);
			}
			term_set (MOVE,0,Crec);
			break;
		case SETROT:
			if (Rot == 0)
			{
				Rot = 13;
				prinfo (Roton_msg);
			}
			else
			{
				Rot = 0;
				prinfo (Rotoff_msg);
			}
			term_set (MOVE,0,Crec);
			break;
		case SSTAT:
			count_msg ();
			term_set (MOVE,0,Crec);
			break;
		case GRPLIST:
			tot_list ();
			show();
			term_set (MOVE,0,Crec);
			break;
		case REDRAW:
			show();
			term_set (MOVE,0,Crec);
			break;
		case UNSUBSCRIBE:
			new_sub(Page.h.group,0);
			do_update(Unsub_msg);
			term_set (MOVE,0,Crec);
			break;

		case UPDATE:
			new_read(Page.h.group,Page.b[Crec-RECBIAS].art_id);
			wr_show ();
			do_update("Updated to cursor");
			term_set (MOVE,0,Crec);
			break;
		case UPALL:
			new_read(Page.h.group,(Page.h.group)->highnum);
			wr_show();
			do_update(Egroup_msg);
			term_set (MOVE,0,Crec);
			break;
		case ORGGRP:
			new_read(Page.h.group,(Page.h.group)->orgrd);
			wr_show();
			do_update(Egroup_msg);
			term_set (MOVE,0,Crec);
			break;
		case UPSEEN:
			up_seen();
			wr_show();
			do_update("All pages displayed to this point updated");
			term_set (MOVE,0,Crec);
			break;
		case ORGSTAT:
			for (i = 0; i < Ncount; ++i)
				new_read(Newsorder[i],(Newsorder[i])->orgrd);
			wr_show();
			do_update("Original data recovered");
			term_set (MOVE,0,Crec);
			break;
 		case TOPMOVE:
 			Crec = RECBIAS;
 			term_set (MOVE, 0, Crec);
 			break;
 		case BOTMOVE:
 		case ALTBOTTOM:
 			Crec = Highrec - 1;
 			term_set (MOVE, 0, Crec);
 			break;
 		case MIDMOVE:
 			Crec = (RECBIAS + Highrec - 1) / 2;
 			if (Crec < RECBIAS)
 				Crec = RECBIAS;
 			if (Crec >= Highrec)
 				Crec = Highrec - 1;
 			term_set (MOVE, 0, Crec);
 			break;
		case UP:
			if (Crec != RECBIAS)
			{
				Crec -= count;
				if (Crec < RECBIAS)
					Crec = RECBIAS;
				term_set (MOVE, 0, Crec);
			}
			else
				putchar ('\07');
			break;
		case DOWN:
			if (Crec < (Highrec - 1))
			{
				Crec += count;
				if (Crec >= Highrec)
					Crec = Highrec - 1;
				term_set (MOVE, 0, Crec);
			}
			else
				putchar ('\07');
			break;
		case MARK:
		case ART_MARK:
			count += Crec - 1;
			if (count >= Highrec)
				count = Highrec - 1;
			for (i=Crec; i <= count; ++i)
			{
				if (Page.b[i-RECBIAS].art_mark != ART_MARK)
					Page.b[i-RECBIAS].art_mark = ART_MARK;
				else
					Page.b[i-RECBIAS].art_mark = ' ';
				if (i != Crec)
					term_set (MOVE, 0, i);
				printf ("%c\010",Page.b[i-RECBIAS].art_mark);
			}
			if (count != Crec)
				term_set (MOVE, 0, Crec);
			write_page ();
			break;
		case UNMARK:
			for (i=0; i < Page.h.artnum; ++i)
			{
				if (Page.b[i].art_mark == ART_MARK)
				{
					Page.b[i].art_mark = ' ';
					term_set (MOVE, 0, i+RECBIAS);
					putchar (' ');
				}
			}
			term_set (MOVE, 0, Crec);
			write_page ();
			break;
		case BACK:
			count *= -1;	/* fall through */
		case FORWARD:
			if (forward (count) >= 0)
				show();
			else
				preinfo ("No more pages");
			term_set (MOVE,0,Crec);
			break;
		case DIGEST:
			if (Digest)
			{
				Digest = 0;
				find_page (Cur_page);
				show();
				Crec = Drec + RECBIAS + 1;
				Highrec = Page.h.artnum + RECBIAS;
				if (Crec >= Highrec)
					Crec = Highrec - 1;
				term_set (MOVE,0,Crec);
				break;
			}
			(Page.h.group)->flags |= FLG_ACC;
			Dskip = count - 1;
			Drec = Crec - RECBIAS;
			if (digest_page(Drec,Dskip) >= 0)
			{
				show();
				Crec = RECBIAS;
				Highrec = Page.h.artnum + RECBIAS;
				term_set (MOVE,0,Crec);
				break;
			}
			Digest = 0;
			preinfo ("Can't unpack the article");
			term_set (MOVE,0,Crec);
			break;
		case NEWGROUP:
			if ((i = spec_group()) < 0)
			{
				term_set (MOVE,0,Crec);
				break;
			}
			Digest = 0;
			show();
			Crec = RECBIAS;
			Highrec = Page.h.artnum + RECBIAS;
			term_set (MOVE,0,Crec);
			break;

		case SAVE:
			(Page.h.group)->flags |= FLG_ACC;
			genlist (alist,Crec-RECBIAS,count);
			savestr (alist);
			term_set (MOVE,0,Crec);
			break;
		case SAVEALL:
			(Page.h.group)->flags |= FLG_ACC;
			genlist (alist,0,L_allow);
			savestr (alist);
			term_set (MOVE,0,Crec);
			break;
		case SAVESTRING:
		case ALTSAVE:
			(Page.h.group)->flags |= FLG_ACC;
			userlist (alist);
			savestr (alist);
			term_set (MOVE,0,Crec);
			break;
		case READ:
		case ALTREAD:
			(Page.h.group)->flags |= FLG_ACC;
			genlist (alist,Crec-RECBIAS,count);
			readstr (alist,count);
			break;
		case READALL:
			(Page.h.group)->flags |= FLG_ACC;
			genlist (alist,0,L_allow);
			readstr (alist,0);
			break;
		case READSTRING:
			(Page.h.group)->flags |= FLG_ACC;
			userlist (alist);
			readstr (alist,0);
			break;
		case PRINT:
			(Page.h.group)->flags |= FLG_ACC;
			genlist (alist,Crec-RECBIAS,count);
			printstr (alist);
			term_set (MOVE,0,Crec);
			break;
		case PRINTALL:
			(Page.h.group)->flags |= FLG_ACC;
			genlist (alist,0,L_allow);
			printstr (alist);
			term_set (MOVE, 0, Crec);
			break;
		case PRINTSTRING:
			(Page.h.group)->flags |= FLG_ACC;
			userlist (alist);
			printstr (alist);
			term_set (MOVE, 0, Crec);
			break;

		case HELP:
			help ();
			show ();
			term_set (MOVE, 0, Crec);
			break;
		case UNESC:
			user_str (alist,Ps1,1,"");
			term_set (ERASE);
			fflush (stdout);
			tty_set (SAVEMODE);
			if (chdir(Orgdir) < 0)
				printf ("change to original directory, %s, failed",Orgdir);
			else
			{
				system (alist);
				tty_set (RESTORE);
				term_set (RESTART);
			}
			printf (Contstr);
			getnoctl ();
			vns_gset(Page.h.name);
			show ();
			term_set (MOVE, 0, Crec);
			break;
		case PRTVERSION:
			prinfo("%s %s", Version, Vns_version);
			term_set (MOVE, 0, Crec);
			break;
		default:
			preinfo("Unhandled key: %c", c);
			break;
		}
	}

	Digest = 0;
	for (i=0; i < Ncount; ++i)
	{
		if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
			break;
	}
	if (i < Ncount)
	{
		user_str (alist,"Some displayed pages not updated - update ? ",
							1, QUIT_ANSWER);
		if (alist[0] == 'y')
			up_seen();
	}
	sig_set (BRK_OUT);
}

/*
** update status of Newsgroups to all seen pages
*/
up_seen()
{
	int i;

	for (i = 0; i < Ncount; ++i)
	{
		if (Nounsub && ((Newsorder[i])->flags & FLG_SUB) == 0)
		{
			new_read(Newsorder[i],(Newsorder[i])->highnum);
			continue;
		}
		if ((Newsorder[i])->rdnum < (Newsorder[i])->pgrd)
			new_read(Newsorder[i],(Newsorder[i])->pgrd);
	}
}

/*
	count_msg displays count information
*/
count_msg ()
{
	int i, gpnum, gscan, gpage;
	unsigned long mask;
	gpnum = 1;
	for (gscan = gpage = i = 0; i<Ncount; ++i)
	{
		if (((Newsorder[i])->flags & FLG_PAGE) != 0)
		{
			if (((Newsorder[i])->pnum + (Newsorder[i])->pages - 1) < Cur_page)
				++gpnum;
			++gpage;
			for (mask=1; mask != 0L; mask <<= 1)
				if (((Newsorder[i])->pgshwn & mask) != 0L)
					++gscan;
		}
	}
	prinfo (CFORMAT,Cur_page+1,Lrec+1,gscan,gpnum,gpage);
}

/*
	forward utility handles paging
*/
static
forward (count)
int count;
{
	if (!Digest)
	{
		if ((count < 0 && Cur_page <= 0) || (count > 0 && Cur_page >= Lrec))
			return (-1);
		Cur_page += count;
		if (Cur_page < 0)
			Cur_page = 0;
		if (Cur_page > Lrec)
			Cur_page = Lrec;
		find_page (Cur_page);
		Crec = RECBIAS;
		Highrec = Page.h.artnum + RECBIAS;
		return (0);
	}
	/*
	** in digests, paging past the end of the digest returns to
	** page extracted from.
	*/
	if (Dskip > 0 && (Dskip + count*L_allow) < 0)
		Dskip = 0;
	else
		Dskip += count * L_allow;
	find_page (Cur_page);
	if (Dskip >= 0)
	{
		if (digest_page(Drec,Dskip) >= 0)
		{
			Crec = RECBIAS;
			Highrec = Page.h.artnum + RECBIAS;
			return (0);
		}
	}
	Digest = 0;
	Crec = Drec + RECBIAS + 1;
	Highrec = Page.h.artnum + RECBIAS;
	if (Crec >= Highrec)
		Crec = Highrec - 1;
	return (0);
}

/*
	generate list of articles on current page,
	count articles, starting with first.
*/
static
genlist (list,first,count)
char *list;
int first,count;
{
	int i;
	for (i=first; i < Page.h.artnum && count > 0; ++i)
	{
		sprintf (list,"%d ",Page.b[i].art_id);
		list += strlen(list);
		--count;
	}
}

/*
	send list of articles to printer
*/
static
printstr (s)
char *s;
{
	char cmd [RECLEN];
	char fn[L_tmpnam];
	char dsave[RECLEN];	/* save list for unlinking */

	prinfo ("preparing print command ....");

	if (Digest)
	{
		dig_list (s);
		strcpy(dsave,s);
	}

	if (*s != '\0')
	{
		tmpnam(fn);
		if (art_xfer(fn,s,"w") != 0)
		{
			preinfo("Couldn't open temporary file");
			return;
		}
		sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
		if (system (cmd) == 0)
			prinfo ("Sent to printer");
		else
			preinfo ("Print failed");
		unlink(fn);
	}
	else
		preinfo (No_msg);

	if (Digest)
		dig_ulist (dsave);
}

/*
	read a list of articles.
*/
readstr (s,count)
char *s;
int count;
{
	char *strtok();
	char *fn[MAXARTLIST+1];
	int pc, num, i;

	/* we pre-process tokens to release strtok() for further use */
	fn[0] = strtok(s,List_sep);
	for (num=0; fn[num] != NULL; fn[(++num)] = strtok(NULL,List_sep))
		if (num >= MAXARTLIST)
			break;
	fn[num] = NULL;

	if (fn[0] != NULL)
	{
		term_set (ERASE);
		for (i=0; i < num && readfile(fn[i], fn[i+1] ,&pc) >= 0; ++i)
		{
			if (Digest)
				unlink (fn[i]);
		}
		if (Digest && fn[i] != NULL)
			unlink (fn[i]);
		if (pc != 0)
			forward (pc);
		else
		{
			Crec += count;
			if (Crec >= Highrec)
				Crec = Highrec - 1;
		}
		show ();
		term_set (MOVE, 0, Crec);
	}
	else
	{
		preinfo ("%s",No_msg);
		term_set (MOVE, 0, Crec);
	}
}

/*
	concatenate articles to save file with appropriate infoline messages.
	prompt for save file, giving default.  If save file begins with "|"
	handle as a filter to pipe to.  NOTE - every user specification of
	a new Savefile "loses" some storage, but it shouldn't be a very great
	amount.
*/
static
savestr (s)
char *s;
{
	char *ptr, newfile [MAX_C+1], msg[RECLEN];
	char *str_store();
	char dsave[RECLEN];

	if (Digest)
	{
		dig_list (s);
		strcpy(dsave,s);
	}

	if (*s != '\0')
	{
		user_str (newfile,"save file ? ",1,Savefile);
		ptr = newfile;
		if (*ptr == '|')
		{
			term_set (ERASE);
			fflush (stdout);
			save_art(s,ptr,msg);
			printf ("%s\n%s",msg,Contstr);
			getnoctl ();
			show ();
		}
		else
		{
			prinfo("saving ....");
			if (*ptr == '\0')
				ptr = Savefile;
			else
				Savefile = str_store(ptr);
			if (save_art(s,Savefile,msg) != 0)
				preinfo(msg);
			else
				prinfo(msg);
		}
	}
	else
		preinfo (No_msg);

	if (Digest)
		dig_ulist (dsave);
}

/*
	basic page display routine.  erase screen and format current page
*/
static
show ()
{
	int i;
	unsigned long mask;
	char helpstr[40]; 

	term_set (ERASE);
	C_info = 0;
	i = Cur_page - (Page.h.group)->pnum + 1;
	if (Digest)
		printf (DHFORMAT,Page.h.name);
	else
		printf (HFORMAT,Page.h.name,i,(Page.h.group)->pages);

	mask = 1L << (i-1);
	(Page.h.group)->pgshwn |= mask;
	mask = 1;
	for (--i; i > 0 && (mask & (Page.h.group)->pgshwn) != 0 ; --i)
		mask <<= 1;
	if (i <= 0)
		(Page.h.group)->pgrd = Page.b[(Page.h.artnum)-1].art_id;

	for (i=0; i < Page.h.artnum; ++i)
	{
		if (Digest)
		{
			printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
			printf("%s",Page.b[i].art_t);
			continue;
		}

		if ((Page.h.group)->rdnum >= Page.b[i].art_id)
			printf(Aformat,Page.b[i].art_mark,ART_WRITTEN,Page.b[i].art_id);
		else
			printf(Aformat,Page.b[i].art_mark,ART_UNWRITTEN,Page.b[i].art_id);
		printf("%s",Page.b[i].art_t);
	}

	sprintf(helpstr,HELPFORM,Cxptoi[HELP]);
	if (!Digest && ((Page.h.group)->flags & FLG_SUB) == 0)
		prinfo ("%s, %s",Unsub_msg,helpstr);
	else
		prinfo (helpstr);
}

/*
	update written status marks on screen
*/
static
wr_show ()
{
	int i,row;
	char c;

	row = RECBIAS;
	for (i=0; i < Page.h.artnum; ++i)
	{
		term_set (MOVE,WRCOL,row);
		if ((Page.h.group)->rdnum >= Page.b[i].art_id)
			c = ART_WRITTEN;
		else
			c = ART_UNWRITTEN;
		printf("%c",c);
		++row;
	}
}

/*
	obtain user input of group name, becomes current page if valid.
	returns -1 or page number.  calling routine does the show, if needed
*/
static
spec_group ()
{
	char nbuf [MAX_C + 1];
	NODE *p, *hashfind();

	user_str(nbuf,"Newsgroup ? ",1,"");

	if (*nbuf == '\0' || (p = hashfind(nbuf)) == NULL)
	{
		preinfo ("Not a newsgroup");
		return (-1);
	}
	if ((p->flags & FLG_PAGE) == 0)
	{
		if ((p->flags & FLG_SUB) == 0)
		{
			new_sub(p,FLG_SUB);
			do_update("Not subscribed: resubscribed for next reading session");
		}
		else
			prinfo ("No news for that group");
		return (-1);
	}
	if ((p->flags & FLG_SUB) == 0)
	{
		new_sub(p,FLG_SUB);
		do_update("Resubscribed");
	}
	find_page (p->pnum);
	return (p->pnum);
}

/*
	obtain user input with prompt p.  Optionally on info line.
	handle erase and kill characters, suppresses leading
	white space.  Use defstr as the editable default user input.
	If on info line, cursor is not moved anywhere whe done, otherwise
	a <CR><LF> is done after input.  Should be in raw mode to use
	this routine.  Used from outside this source file so that we
	only have to do erase / kill key stuff one place.
*/
user_str (s,p,iline,defstr)
char *s;
char *p;
int iline;
char *defstr;
{
	int i,idx,len;

	if (iline)
	{
 		prinfo ("%s%s",p,defstr);
		idx = C_info;
	}
	else
	{
 		printf ("%s%s",p,defstr);
		idx = strlen(p);
	}

	len = strlen(defstr);
 	for (i=0; i < len; i++)
 		s[i] = defstr[i];
 
	for (i=len; idx < C_allow && (s[i] = getchar() & 0x7f) != '\012' && s[i] != '\015'; ++i)
	{
		if (s[i] == Erasekey)
		{
			if (i > 0)
			{
				term_set (RUBSEQ);
				i -= 2;
				--idx;
			}
			else
				i = -1;
			continue;
		}
		if (s[i] == Killkey)
		{
 			if (iline)
 			{
 				prinfo ("%s",p);
 				idx = C_info;
 			}
 			else
 			{
 				printf ("\r%s",p);
 				term_set(ZAP,strlen(p),idx);
 				fflush(stdout);
 				idx = strlen(p);
 			}
			i = -1;
			continue;
		}
		/* no leading spaces */
		if (s[i] == ' ' && i == 0)
		{
			i = -1;
			putchar('\07');
			continue;
		}
		/* no controls */
		if (s[i] < ' ' || s[i] == '\177')
		{
			--i;
			putchar('\07');
			continue;
		}
		++idx;
		putchar (s[i]);
	}

	if (iline)
		C_info = idx;
	else
		printf("\r\n");

	s[i] = '\0';
}

/*
	print something on the information line,
	clearing any characters not overprinted.
	preinfo includes reverse video and a bell for error messages.
*/
preinfo (s,a,b,c,d,e,f)
{
	int l;
	char buf[RECLEN];

	term_set (MOVE,0,INFOLINE);
	putchar ('\07');
	term_set (ONREVERSE);
	sprintf (buf,s,a,b,c,d,e,f);
	printf (" %s ",buf);
	term_set (OFFREVERSE);
	l = strlen(buf) + 2;
	if (l < C_info)
		term_set (ZAP,l,C_info);
	C_info = l;
	fflush(stdout);
}

prinfo (s,a,b,c,d,e,f)
char *s;
long a,b,c,d,e,f;
{
	int l;
	char buf[RECLEN];
	term_set (MOVE,0,INFOLINE);
	sprintf (buf,s,a,b,c,d,e,f);
	printf ("%s",buf);
	l = strlen(buf);
	if (l < C_info)
		term_set (ZAP,l,C_info);
	C_info = l;
	fflush(stdout);
}

static
tot_list ()
{
	int i,max,len;
	char c;
	char ff[MAX_C+1];

	term_set (ERASE);

	for (max=i=0; i < Ncount; ++i)
	{
		if ((Newsorder[i])->pages == 0)
			continue;
		if ((len = strlen((Newsorder[i])->nd_name)) > max)
			max = len;
	}

	sprintf (ff,"%%4d %%%ds: %%3d new %%3d updated\n",max);

	for (len=i=0; i < Ncount; ++i)
	{
		if ((Newsorder[i])->pages == 0)
			continue;
		printf (ff, i, (Newsorder[i])->nd_name,
				(Newsorder[i])->highnum - (Newsorder[i])->orgrd,
				(Newsorder[i])->rdnum - (Newsorder[i])->orgrd);
		++len;
		if (len == L_allow && i < (Ncount-1))
		{
			printf("\nr - return, n - new group, other to continue ... ");
			if ((c = getnoctl()) == 'r' || c == 'n')
				break;
			printf ("\n\n");
			len = 0;
		}
	}
	if (i >= Ncount)
	{
		printf("n - new group, other to return ... ");
		c = getnoctl();
	}

	/* c will remain 'n' while user chooses bad newsgroups */
	while (c == 'n')
	{
		printf("\n");
		user_str(ff,"Newsgroup number ? ",0,"");
		i = atoi(ff);
 		if (i < 0 || i >= Ncount || (Newsorder[i])->pages == 0)
		{
 			printf("\nBad newsgroup number\n");
 			printf("n - new group, other to return ... ");
			c = getnoctl();
			continue;
 		}
 		find_page((Newsorder[i])->pnum);
		Crec = RECBIAS;
		Highrec = Page.h.artnum + RECBIAS;
		c = '\0';
	}
}

/*
** call vns_write if anything has changed, then wipe FLG_ECHG bits
** also produce message(s)
*/
static
do_update(msg)
char *msg;
{
	int i;

	for (i=0; i < Ncount; ++i)
		if(((Newsorder[i])->flags & FLG_ECHG) != 0)
			break;
	if (i < Ncount)
	{
		prinfo("Writing news status");
		vns_write(Newsorder,Ncount);
		for (i=0; i < Ncount; ++i)
			(Newsorder[i])->flags &= ~FLG_ECHG;
	}
	prinfo(msg);
}

/*
** set a new rdnum value.  If a change, set FLG_ECHG
*/
static
new_read(n,rd)
NODE *n;
int rd;
{
	if (n->rdnum != rd)
	{
		n->rdnum = rd;
		n->flags |= FLG_ECHG;
	}
}

/*
** set a new subscription bit.  bit argument is either 0 or FLG_SUB.
*/
static
new_sub(n,bit)
NODE *n;
unsigned bit;
{
	/*
	** since bit is 0 or FLG_SUB, we could get tricky with ^
	** but this is clearer
	*/
	if (bit != 0 && (n->flags & FLG_SUB) == 0)
		n->flags |= FLG_SUB|FLG_ECHG;
	else
	{
		if (bit == 0 && (n->flags & FLG_SUB) != 0)
		{
			n->flags &= ~FLG_SUB;
			n->flags |= FLG_ECHG;
		}
	}
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'reader.c'" '(15750 characters)'
if test -f 'reader.c'
then
	echo shar: will not over-write existing file "'reader.c'"
else
cat << \SHAR_EOF > 'reader.c'
/*
** vn news reader.
**
** reader.c - article reading interface - "more" like.
**
** see copyright disclaimer / history in vn.c source file
*/

#include <stdio.h>
#include <sys/types.h>
#include "tty.h"
#include "config.h"
#include "tune.h"
#include "head.h"
#include "reader.h"
#include "brk.h"
#include "node.h"
#include "page.h"
#include "vn.h"

#define PERTAB 8	/* tab expansion factor */
#define BACKTRACK 24

extern char *Printer,*Editor,*Mailer,*Poster,*Orgdir,*Savefile,*Savedir,*Ccfile;
extern int L_allow;
extern int C_allow;
extern int Rot;
extern int Headflag;
extern int Digest;
extern int More;
extern char *No_msg;
extern char *Roton_msg;
extern char *Rotoff_msg;
extern char *Hdon_msg;
extern char *Hdoff_msg;

extern PAGE Page;

extern int (*Massage)();
extern int (*Postfunc)();
extern int (*Mailfunc)();

extern char Cxrtoi[], Cxitor[];

static FILE *Fpread;
static char *Fname;
static char *Lookahead;
static int Rlines;
static int Hlines;
static long Rew_pos;

/*
	readfile presents article:
		fn = name of article.
		sn - name of next article, NULL if last.
		pages - pages to advance on return, if applicable
	returns 0 for "continue", <0 for "quit"

	calls sig_set(BRK_READ / BRK_RFIN) around reading article.
*/
readfile (fn,sn,pages)
char *fn;
char *sn;
int *pages;
{
	ARTHEADER hdr;
	FILE *fopen();
	int lines,percent;
	int i;
	int top, bottom;
	int step;
	char c,  buf[RECLEN];
	char lasave[RECLEN];
	char pstr[24], dgname[48];
	char getpgch(), *index(), *digest_extract(), *tgetstr();
	char *any;
	FILE *vns_aopen();
	long ftell();

	Fname = fn;
	*pages = 0;
	step = FALSE;	/* Boolean; to indicate user input a <RET> (PG_STEP) */

	term_set(ERASE);
	sig_set(BRK_READ,&Fpread);

	any = "any key to continue .... ";

	if (Digest)
	{
		lines = atoi(Fname);
		if ((Fname = digest_extract(dgname,lines,&hdr,&Rew_pos)) == NULL)
		{
			rerrmsg("couldn't extract article %d from digest",lines);
			printf(any);
			getnoctl();
			sig_set(BRK_RFIN);
			return (0);
		}
		if ((Fpread = fopen(Fname,"r")) == NULL)
		{
			rerrmsg("couldn't open %s",Fname);
			printf(any);
			getnoctl();
			sig_set(BRK_RFIN);
			return (0);
		}
		fseek(Fpread,Rew_pos,0);
	}
	else
	{
		if ((Fpread = vns_aopen(atoi(Fname),&hdr)) == NULL)
		{
			rerrmsg("couldn't open article %s",Fname);
			printf(any);
			getnoctl();
			sig_set(BRK_RFIN);
			return (0);
		}
		Rew_pos = ftell(Fpread);
	}

	Hlines = hdr.hlines;
	printf (ANFORM,Fname,Cxrtoi[PG_HELP]);

	lines = 0;

	if (Headflag)
	{
		rewind(Fpread);
		Rlines = 0;
	}
	else
	{
		/* use do_out to guard against control sequences */
		Rlines = Hlines;
		for (i=0; i < hdr.show_num; ++i)
			lines += do_out((hdr.show)[i],L_allow-lines);
		lines += do_out("",L_allow-lines);
	}

	/* will return out of outer while loop */
	Lookahead = NULL;
	while (1)
	{
		/*
		** lines counts folded lines from do_out.
		** globals Hlines and Rlines refer to records.
		** If Lookahead is null after this loop, we've
		** hit EOF.
		*/
		if (Lookahead != NULL && More && !step)
		{
			char *looktmp;

			/*
			** Save Lookahead because `do_out' nukes it.
			** Perhaps we could just use `printf' here
			** but for now we'll play it safe. - GKE 12/26/87
			*/
			looktmp = Lookahead;
			term_set(ERASE);
			/* 
			** The following presents the last line of the
			** previous page in reversed video, as the first line
			** of the current page, `rn'-stylee.  Since `rn'
			** uses an option to enable/disable this, remove the
			** two `term_set's if not to your liking.
			*/
			term_set(ONREVERSE);
			do_out(lasave,1);
			term_set(OFFREVERSE);
			Lookahead = looktmp;
		}
		lines += do_out(Lookahead,L_allow-lines);
		while (1)
		{
			if (Lookahead == NULL)
			{
				if (fgets(buf,RECLEN-1,Fpread) == NULL)
					break;
				Lookahead = buf;
				if (Rot != 0 && Rlines >= Hlines)
					rot_line(buf);
				++Rlines;
			}
			if (lines >= L_allow)
				break;
			if (More)
				strcpy(lasave,Lookahead);
			lines += do_out(Lookahead,L_allow-lines);
		}

		if (Lookahead != NULL)
		{
			/*
			** calculation is truncated rather than rounded,
			** so we shouldn't get "100%".  Subtract 2 for
			** 1 line lookahead and empty line at beginning
			** of article.
			*/
			if (Headflag)
			{
				top = (Rlines-2)*100;
				bottom = hdr.lines + Hlines;
			}
			else
			{
				top = (Rlines-Hlines-2)*100;
				bottom = hdr.lines;
			}
			/*
			** protect against division by zero -
			** shouldn't actually come up zero at this
			** point if vns_aopen is sane. 999 will let user
			** know the percentage is obviously wrong.
			*/
			if (bottom != 0)
				percent = top/bottom;
			else
				percent = 999;
			sprintf (pstr,PAGE_MID,percent);
		}
		else
		{
			if (sn == NULL)
				strcpy (pstr,PAGE_END);
			else
			strcpy (pstr,PAGE_NEXT);
		}
		c = getpgch(pstr,&hdr);

		/*
			handle user input:
			CAUTION!!  return cases must close Fpread.
		*/
		step = FALSE;
		switch (c)
		{
		case PG_NEXT:
			if (Digest)
			{
				fclose (Fpread);
				unlink (Fname);
			}
			else
				vns_aclose (Fpread);
			sig_set(BRK_RFIN);
			return (0);
		case PG_FLIP:
			*pages = 1;	/* fall through */
		case PG_QUIT:
			if (Digest)
			{
				fclose (Fpread);
				unlink (Fname);
			}
			else
				vns_aclose (Fpread);
			sig_set(BRK_RFIN);
			return (-1);
		case PG_REWIND:
			if (Headflag)
			{
				Rlines = 0;
				rewind (Fpread);
			}
			else
			{
				fseek (Fpread,Rew_pos,0);
				Rlines = Hlines;
			}
			Lookahead = NULL;
			lines = 2 - RECBIAS;
			break;
		case PG_SEARCH:
			searcher(buf);
			lines = 2 - RECBIAS;
			lines += do_out(buf,L_allow-lines);
			break;
		case PG_WIND:
			fseek (Fpread,0L,2);
			lines = 2 - RECBIAS;
			Lookahead = NULL;
			break;
		case PG_STEP:
			if (Lookahead == NULL)
			{
				if (Digest)
				{
					fclose (Fpread);
					unlink (Fname);
				}
				else
					vns_aclose (Fpread);
				sig_set(BRK_RFIN);
				return (0);
			}
			lines = L_allow - 1;
			step = TRUE;	/* Temporarily disable paging */
			break;
		default:
			if (Lookahead == NULL)
			{
				if (Digest)
				{
					fclose (Fpread);
					unlink (Fname);
				}
				else
					vns_aclose (Fpread);
				sig_set(BRK_RFIN);
				return (0);
			}
			lines = 2 - RECBIAS;
			break;
		}
	}
}

/*
	getpgch prints prompt and gets command from user
	handles "mail", "save" and "followup" internally
	as well as flag resets.
*/
static char
getpgch(prompt,hdr)
char *prompt;
ARTHEADER *hdr;
{
	char c;
	int ic;
	term_set (ONREVERSE);
	printf("%s\015",prompt);
	term_set (OFFREVERSE);
	while ((ic=getnoctl()) != EOF)
	{
		switch (c = Cxitor[ic])
		{
		case SETROT:
			term_set (ZAP,0,PPR_MAX);
			if (Rot == 0)
			{
				Rot = 13;
				printf ("%s\n",Roton_msg);
			}
			else
			{
				Rot = 0;
				printf ("%s\n",Rotoff_msg);
			}
			if (Lookahead != NULL && Rlines > Hlines)
				rot_line(Lookahead);
			break;
		case HEADTOG:
			term_set (ZAP,0,PPR_MAX);
			if (Headflag)
			{
				Headflag = FALSE;
				printf ("%s\n",Hdoff_msg);
			}
			else
			{
				Headflag = TRUE;
				printf ("%s\n",Hdon_msg);
			}
			break;
		case PG_HELP:
			term_set (ZAP,0,PPR_MAX);
			help_rd ();
			break;
		case PG_REPLY:
			mail (hdr);
			break;
		case PG_FOLLOW:
			followup (hdr);
			break;
		case SAVE:
			saver ();
			break;
		case PRINT:
			printr ();
			break;
		default:
			term_set (ZAP,0,PPR_MAX);
			return (c);
		}

		term_set (ONREVERSE);
		printf("%s\015",prompt);
		term_set (OFFREVERSE);
	}
	term_set (ZAP,0,PPR_MAX);
	return (c);
}

/*
	save article.  Like its "session" counterpart, this loses storage
	if the user specifies a new file, but it should not be significant
*/
static
saver ()
{
	char buf[RECLEN],msg[RECLEN],*str_store();

	user_str (buf,"save file ? ",0,Savefile);
	if (buf[0] != '\0' && buf[0] != '|')
		Savefile = str_store(buf);
	if (save_art(Fname,buf,msg) != 0)
		rerrmsg(msg);
	else
		printf("%s\n",msg);
}

/*
	invoke editor on new temp file, mail using reply line,
	possibly first allowing user to overide the reply (not INLETTER)
*/
static
mail (hdr)
ARTHEADER *hdr;
{
	char *new, fn[L_tmpnam], cmd [RECLEN+60], *rprompt ();
	int i;
	FILE *fp, *fopen();

	if (Massage != NULL)
		(*Massage)(hdr);

	if (hdr->mail_err != NULL)
	{
		rerrmsg(hdr->mail_err);
		return;
	}

	tmpnam (fn);
	if ((fp = fopen(fn,"w")) == NULL)
	{
		rerrmsg("can't open temp file, %s",fn);
		return;
	}

	for (i = 0; i < hdr->mail_num; ++i)
		fprintf(fp,"%s\n",(hdr->mail)[i]);
	fprintf(fp,"\n");

	fprintf(fp,"%s:\n",hdr->from);
	edcopy (fp);
	fclose (fp);

	tty_set (SAVEMODE);

	sprintf (cmd,"%s %s", Editor, fn);
	chdir (Orgdir);
	system (cmd);
	vns_gset (Page.h.name);

	new = rprompt ("still want to mail it ? ",cmd);
	if (new != NULL && (*new == 'y' || *new == 'Y'))
	{
		if (Mailfunc == NULL)
		{
			sprintf (cmd, hdr->mailcmd, fn);
			system (cmd);
			printf ("given to mailer\n");
		}
		else
			(*Mailfunc)(hdr,fn);
	}
	else
		printf ("not mailed\n");

	unlink (fn);

	tty_set (RESTORE);
	term_set (RESTART);
}

/*
	post a followup article, invoking editor for user after creating
	new temp file.  remove after posting.
*/
static
followup (hdr)
ARTHEADER *hdr;
{
	char fn[L_tmpnam], *new, cmd [RECLEN], *rprompt();
	int i;
	FILE *f, *fopen();
	char *rindex();

	if (hdr->post_err != NULL)
	{
		rerrmsg(hdr->post_err);
		return;
	}

	tmpnam (fn);
	if ((f = fopen(fn,"w")) == NULL)
	{
		rerrmsg("can't open temp file, %s",fn);
		return;
	}

	for (i=0; i < hdr->post_num; ++i)
		fprintf(f,"%s\n",(hdr->post)[i]);
	fprintf(f,"\n");

	fprintf(f,"From article %s, by %s:\n", hdr->artid, hdr->from);
		
	edcopy (f);
	fclose (f);
	tty_set (SAVEMODE);
	sprintf (cmd,"%s %s", Editor, fn);
	chdir (Orgdir);
	system (cmd);
	vns_gset (Page.h.name);

	new = rprompt("still want to post it ? ",cmd);
	if (new != NULL && (*new == 'y' || *new == 'Y'))
	{
		if (Postfunc == NULL)
		{
			sprintf (cmd, hdr->postcmd, fn);
			system (cmd);
			printf ("given to posting program\n");
		}
		else
			(*Postfunc)(hdr,fn);
		save_article (fn);
	}
	else
		printf ("not posted\n");
	unlink (fn);
	tty_set (RESTORE);
	term_set (RESTART);
}

/*
	get user buffer, return whitespace delimited token
	buffer is allowed to overwrite prompt string.  This routine
	should only be used when the terminal is in cooked mode.
	In raw, use user_str().
*/
static char *
rprompt(s,buf)
char *s,*buf;
{
	char *strtok();

	printf("%s",s);
	fgets (buf,RECLEN-1,stdin);
	return (strtok(buf," \t\n"));
}

/*
	edcopy copies article to file which user is editting for
	a reply or followup, so it may be referenced.  It places
	ED_MARK in the left hand margin.
*/
static
edcopy(fp)
FILE *fp;
{
	long current;
	char buf[RECLEN];

	/* save position, and seek to top of article */
	current = ftell(Fpread);
	fseek (Fpread,Rew_pos,0);

	/* if line already begins with ED_MARK, forget about the space */
	while (fgets(buf,RECLEN-1,Fpread) != NULL)
	{
		if (buf[0] == ED_MARK)
			fprintf(fp,"%c%s",ED_MARK,buf);
		else
			fprintf(fp,"%c %s",ED_MARK,buf);
	}

	/* restore position */
	fseek(Fpread,current,0);
}

static
rot_line (s)
unsigned char *s;
{
	for ( ; *s != '\0'; ++s)
	{
		if (*s >= 'A' && *s <= 'Z')
		{
			*s += Rot;
			if (*s > 'Z')
				*s -= 26;
			continue;
		}
		if (*s >= 'a' && *s <= 'z')
		{
			*s += Rot;
			if (*s > 'z')
				*s -= 26;
		}
	}
}

/*
** output record.  folds record to terminal width on word boundaries,
** returning number of lines output.  If limit is reached, remainder
** of buffer waiting to be output is returned.  Processes several
** special characters:
**	form-feed - return "lim" lines so we stop on that line
**	tabs - counts "expanded" width
**	backspace - assumes they work, -1 width unless in first col.
**	bell - pass through with zero width
**	newline - end of record.
**	del - turns into '_'
**	other control - 'A' - 1 added ('01' = ctl-A).  Makes escape = "[".
**		(prevents "letter bombs" containing inappropriate control
**			sequences for the terminal).
**
** Sets Lookahead pointer to remainder of line or NULL.
*/
static
do_out(s,lim)
char *s;
int lim;
{
	int len,i;
	char cs,*word,*start;

	Lookahead = NULL;
	if (s == NULL)
		return(0);
	len = 0;
	start = word = s;

	/*
	** NOTE: "normal" return is buried inside switch, at newline
	** ending record
	*/
	for (i=0; i < lim; ++i)
	{
		for ( ; len < C_allow; ++s)
		{
			switch (*s)
			{
			case '\n':
				*s = '\0';	/* fall through */
			case '\0':
				printf("%s\n",start);
				return(i+1);
			case '\t':
				len = ((len/PERTAB)+1)*PERTAB;
				word = s;
				break;
			case '\b':
				if (len > 0)
					--len;
				break;
			case '\014':
				*s = ' ';
				i = lim-1;	/* fall through */
			case ' ':
				word = s+1;
				++len;
				break;
			case '\177':
				*s = '_';
				++len;
				break;
			default:
				if (*s < ' ')
					*s += 'A' - 1;
				++len;		/* fall through */
			case '\07':
				break;
			}
		}
		cs = *s;
		*s = '\0';
		if ((len = strlen(word)) < BACKTRACK)
		{
			*s = cs;
			s = word;
			cs = *s;
			*s = '\0';
		}
		else
			len = 0;
		printf("%s\n",start);
		start = s;
		*s = cs;
	}
	Lookahead = start;
	return(lim);
}

static
save_article(tempfname)
char *tempfname;
{
	FILE *in, *out;
	int c;
	time_t timenow, time();
	char *today, *ctime();

	if ((in = fopen(tempfname, "r")) == NULL)
		return;
	if ((out = fopen(Ccfile, "a")) == NULL)
	{
	    fclose(in);
	    return;
	}
	timenow = time((time_t)0);
	today = ctime(&timenow);
	fprintf(out,"From vn %s",today);
	while ((c=getc(in)) != EOF)
		putc(c, out);
	putc('\n', out);
	fclose(in);
	fclose(out);
	printf ("a copy has been saved in %s\n", Ccfile);
}

/*
	send article to printer
*/
static
printr ()
{
	char cmd[RECLEN];
	char fn[L_tmpnam];
	long savepos;
	FILE *f;

	tmpnam (fn);
	if ((f = fopen(fn,"w")) == NULL)
	{
		rerrmsg("can't open temp file, %s",fn);
		return;
	}

	savepos = ftell(Fpread);
	rewind(Fpread);
	while (fgets(cmd,RECLEN-1,Fpread) != NULL)
		fputs(cmd,f);
	fclose(f);
	fseek(Fpread,savepos,0);

	tty_set (SAVEMODE);
	printf("Sent to printer\n");
	sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
	system (cmd);
	tty_set (RESTORE);
	unlink (fn);
}

/*
	search article for specified search pattern, returning the line on which
		it is found in buf, a null buffer otherwise. The input file will
		be positioned either after the line on which the pattern is
		found, or unaaltered if match fails.
*/
static
searcher (buf)
char	*buf;
{
	static char	searchstr[RECLEN] = "";
	char	lasave[RECLEN];
	char	*reg, *regcmp(), *regex();
	long	current;
	int	orlines;

	/* save position, then request search pattern */
	current = ftell(Fpread);
	orlines = Rlines;

	sprintf (lasave,SEARCHFORM,searchstr);
	user_str (searchstr,lasave,0,searchstr);

	/* Now compile the search string */
	if(( reg = regcmp(searchstr, (char *)0)) == NULL) {
		rerrmsg("Invalid search string \"%s\"", searchstr);
		*buf = '\0';
		return;
	}

	/* try lookahead buffer first */
	if (Lookahead != NULL && regex(reg,Lookahead) != NULL)
	{
		strcpy(buf,Lookahead);
		regfree(reg);
		return;
	}

	/* Lookahead can point into buf */
	if (Lookahead != NULL)
		strcpy(lasave,Lookahead);

	/* now start reading lines, rotating if necessary and do search */
	while (fgets(buf,RECLEN-1,Fpread) != NULL)
	{
		if (Rot != 0 && Rlines >= Hlines)
			rot_line(buf);
		++Rlines;
		if( regex(reg, buf) != NULL ){	/* Got it */
			rerrmsg("\n\tSkipping ....\n\n");
			regfree(reg);
			return;
		}
	}

	/* no dice, so restore position */
	regfree(reg);
	rerrmsg("Cannot find string \"%s\" in remainder of article", searchstr);
	fseek(Fpread,current,0);
	Rlines = orlines;
	if (Lookahead != NULL)
		strcpy(buf,lasave);
	else
		*buf = '\0';
}

/*
** print a reverse video error message while reading an article.
*/
static
rerrmsg(s,a,b,c,d,e)
char *s;
long a,b,c,d,e;
{
	term_set (ONREVERSE);
	printf("\n ");
	printf(s,a,b,c,d,e);
	printf(" \07\n");
	term_set (OFFREVERSE);
}
SHAR_EOF
fi # end of overwriting check
echo shar: extracting "'config.h'" '(4043 characters)'
if test -f 'config.h'
then
	echo shar: will not over-write existing file "'config.h'"
else
cat << \SHAR_EOF > 'config.h'
/*
** vn news reader.
**
** config.h - system configuration parameters
**
** see copyright disclaimer / history in vn.c source file
*/

#define DEF_ED "/usr/ucb/vi"	/* editor to use if no EDITOR variable */
#define DEF_PS1 "$ "		/* ! command prompt if no PS1 */
#define DEF_SAVE ""		/* save file */

#define DEF_PRINT "/usr/ucb/lpr"		/* print command */

#define DEF_CCFILE "author_copy"
#define DEF_KEYXLN ".vnkey"

/*
** this is the "pre-typed" string the user will be presented with
** in answer to the "update" question following the QUIT command.
** Set to "" if you don't like it answering "yes" for you, or "y"
** if you only want to have to erase one character to say "no", etc.
*/
#define QUIT_ANSWER "yes"

/*
** default terminal assumed if TERM variable is unset.  Since TERM has to
** be set for most UNIX tools, you probably want to make this something
** which will cause failure, unless EVERYBODY has the same kind of terminal
** or you don't really use a standard UNIX environment.
*/
#define DEF_TERM "<unspecified TERM variable>"

/*
** foreground flag for messages.  applies only if JOBCONTROL undefined
** (SYS V). set to 1 to see newsgroup messages, etc. during reading phase,
** 0 for "silent" operation - be warned that this may suppress some
** non-fatal diagnostic messages - find all references to fgprintf to
** see what is suppressed.
*/
#define NOJOB_FG 1

/*
** arrow key treatment.  If PAGEARROW is defined, right and left arrow
** keys will be synonyms for <return> (next-page) and <backspace> (previous).
** Otherwise, the right arrow will function as down, and the left as up.
** Made configurable because while there is no lateral motion on the screen
** to associate with the right and left arrows, you might not like them
** changing pages on you.
*/
#define PAGEARROW

/*
** if USEVS is defined, terminal initialization / exit for vn will include the
** "vs"/"ve" pair as well as "ti"/"te".  This doesn't matter on a lot of
** terminals, but may make vn display behaviour closer to "vi" since vs/ve
** is vi's "visual mode" sequence.  For instance, I believe the commonly
** used definitions for these strings on multi-page concepts allows the
** program to run in the first page of the terminal, preserving the more
** recent part of your session on exit
**
** #define USEVS
*/

/*
** temp file name template for mktemp().  Used in tmpnam.c, does not apply
** if you use a system library tmpnam().   BE CAREFUL - VNTEMPNAME MUST
** contain a string of 6 X's for mktemp() (actually, a place where 6 X's
** are intended to go).  TMP_XOFFSET absolutely MUST point to the first of
** the X's.  Yes, writing into a literal string is sloppy.  To the best of
** my knowledge, tmpnam.c is the only place you'll find vn code doing it.
** We make this configurable in case you want temp files somewhere else.
*/
#define VNTEMPNAME "/usr/tmp/vnXXXXXX"
#define TMP_XOFFSET 11

/*
** VNLOGFILE and VNSTATFILE.  If these files EXIST, the corresponding data
** collection will be turned on.  If they don't it will be turned off.
** To turn it back on again, create the files empty.  Garbage in VNLOGFILE
** won't hurt collection but VNSTATFILE requires very strict syntax, so
** make sure its always an empty file or EXACTLY the right syntax.  See stat.c
**
** VNLOGFILE logs user sessions.  VNSTATFILE keeps a running breakdown
** of newsgroup activity.  I add these with some hesitancy, as I find
** use of things like this for Gestapo-like purposes repugnant in the
** extreme.  However, they can also be useful for system tuning purposes
** such as verifying what newsgroups are being read, and when load on
** the system due to newsreading is occurring.
**
** If VNLOGFILE and VNSTATFILE are NOT DEFINED, the code for doing logging
** and statistical collection will not be compiled in, saving some overhead,
** and avoiding calls to system functions like ctime() and time() which may
** have system dependent quirks.
**
#define VNLOGFILE "/usr/rti/fe/bobm/vn.log"
#define VNSTATFILE "/usr/rti/fe/bobm/vn.stat"
*/
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0
-- 
For comp.sources.unix stuff, mail to sources at uunet.uu.net.



More information about the Comp.sources.unix mailing list