[comp.sources.amiga] v91i048: VN res1.1-2 - vn news reader, Part02/06

amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator) (03/14/91)

Submitted-by: eyal@echo.canberra.edu.au (Eyal Lebedinsky)
Posting-number: Volume 91, Issue 048
Archive-name: news/vn-res-1.1-2/part02

#!/bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 6)."
# Contents:  config.h digest.c envir_set.c makefile pagefile.c
#   readme.amiga rnumbox.c sig_set.c stat.c svart.c term_set.c
#   tty_set.c umbox.c
# Wrapped by tadguy@ab20 on Wed Mar 13 19:10:09 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'config.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'config.h'\"
else
echo shar: Extracting \"'config.h'\" \(4922 characters\)
sed "s/^X//" >'config.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** config.h - system configuration parameters
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#ifdef amiga
X#define DEF_ED "emacs"		/* editor to use if no EDITOR variable */
X#else
X#define DEF_ED "/bin/mined"	/* editor to use if no EDITOR variable */
X#endif
X
X#define DEF_PS1 "$ "		/* ! command prompt if no PS1 */
X#define DEF_SAVE ""		/* save file */
X
X#ifdef amiga
X#define DEF_PRINT "print"	/* print command */
X#else
X#define DEF_PRINT "/usr/bin/lpr" /* print command */
X#endif
X
X#define DEF_CCFILE "author_copy"
X#define DEF_KEYXLN ".vnkey"
X
X/*
X** this is the "pre-typed" string the user will be presented with
X** in answer to the "update" question following the QUIT command.
X** Set to "" if you don't like it answering "yes" for you, or "y"
X** if you only want to have to erase one character to say "no", etc.
X*/
X#define QUIT_ANSWER ""
X
X/*
X** default terminal assumed if TERM variable is unset.  Since TERM has to
X** be set for most UNIX tools, you probably want to make this something
X** which will cause failure, unless EVERYBODY has the same kind of terminal
X** or you don't really use a standard UNIX environment.
X*/
X#ifdef amiga
X#define DEF_TERM "amiga-n"
X#else
X#define DEF_TERM "minix"
X#endif
X
X/*
X** foreground flag for messages.  applies only if JOBCONTROL undefined
X** (SYS V). set to 1 to see newsgroup messages, etc. during reading phase,
X** 0 for "silent" operation - be warned that this may suppress some
X** non-fatal diagnostic messages - find all references to fgprintf to
X** see what is suppressed.
X*/
X#define NOJOB_FG 1
X
X/*
X** bit mask for interpreting command characters.  Set it to 0xff, and
X** we should be able to handle 8 bit characters for control keys -
X** leaving it 0x7f protects against possible parity bits in ascii
X** characters.  A lot of the general paranoia about character handling
X** in raw mode comes from one of the earliest versions which was
X** run on an amdahl using an IBM series 1 front end - it had a very
X** brain damaged implementation of ioctl().
X*/
X#define CHMASK 0x7f
X
X/*
X** arrow key treatment.  If PAGEARROW is defined, right and left arrow
X** keys will be synonyms for <return> (next-page) and <backspace> (previous).
X** Otherwise, the right arrow will function as down, and the left as up.
X** Made configurable because while there is no lateral motion on the screen
X** to associate with the right and left arrows, you might not like them
X** changing pages on you.
X*/
X#define PAGEARROW
X
X/*
X** if USEVS is defined, terminal initialization / exit for vn will include the
X** "vs"/"ve" pair as well as "ti"/"te".  This doesn't matter on a lot of
X** terminals, but may make vn display behaviour closer to "vi" since vs/ve
X** is vi's "visual mode" sequence.  For instance, I believe the commonly
X** used definitions for these strings on multi-page concepts allows the
X** program to run in the first page of the terminal, preserving the more
X** recent part of your session on exit
X**
X** #define USEVS
X*/
X
X/*
X** temp file name template for mktemp().  Used in tmpnam.c, does not apply
X** if you use a system library tmpnam().   BE CAREFUL - VNTEMPNAME MUST
X** contain a string of 6 X's for mktemp() (actually, a place where 6 X's
X** are intended to go).  TMP_XOFFSET absolutely MUST point to the first of
X** the X's.  Yes, writing into a literal string is sloppy.  To the best of
X** my knowledge, tmpnam.c is the only place you'll find vn code doing it.
X** We make this configurable in case you want temp files somewhere else.
X*/
X#ifdef amiga
X#define VNTEMPNAME "t:vnXXXXXX"
X#define TMP_XOFFSET 4
X#else
X#define VNTEMPNAME "/usr/tmp/vnXXXXXX"
X#define TMP_XOFFSET 11
X#endif
X
X/*
X** VNLOGFILE and VNSTATFILE.  If these files EXIST, the corresponding data
X** collection will be turned on.  If they don't it will be turned off.
X** To turn it back on again, create the files empty.  Garbage in VNLOGFILE
X** won't hurt collection but VNSTATFILE requires very strict syntax, so
X** make sure its always an empty file or EXACTLY the right syntax.  See stat.c
X**
X** VNLOGFILE logs user sessions.  VNSTATFILE keeps a running breakdown
X** of newsgroup activity.  I add these with some hesitancy, as I find
X** use of things like this for Gestapo-like purposes repugnant in the
X** extreme.  However, they can also be useful for system tuning purposes
X** such as verifying what newsgroups are being read, and when load on
X** the system due to newsreading is occurring.
X**
X** If VNLOGFILE and VNSTATFILE are NOT DEFINED, the code for doing logging
X** and statistical collection will not be compiled in, saving some overhead,
X** and avoiding calls to system functions like ctime() and time() which may
X** have system dependent quirks.
X**
X*/
X#ifdef amiga
X#define VNLOGFILE "t:vn.log"
X#define VNSTATFILE "t:vn.stat"
X#else
X#define VNLOGFILE "/usr/tmp/vn.log"
X#define VNSTATFILE "/usr/tmp/vn.stat"
X#endif
X
X#ifdef amiga
X#undef putchar
X#define putchar ttputc
X#endif
X
END_OF_FILE
if test 4922 -ne `wc -c <'config.h'`; then
    echo shar: \"'config.h'\" unpacked with wrong size!
fi
# end of 'config.h'
fi
if test -f 'digest.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'digest.c'\"
else
echo shar: Extracting \"'digest.c'\" \(5727 characters\)
sed "s/^X//" >'digest.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** digest.c - digest unpacking routines
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include "config.h"
X#include "head.h"
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X
Xextern int Digest;
Xextern int L_allow;
Xextern int C_allow;
Xextern PAGE Page;
X
Xextern FILE *vns_aopen();
X
Xstatic char *Ext_pool = NULL;
Xstatic char *Show[3];
X
Xstatic char *Dhead = "Date: ";
Xstatic char *Fhead = "From: ";
Xstatic char *Lhead = "Lines: ";
Xstatic char *Thead = "Subject: ";
X
X#define THDLEN 9
X#define LHDLEN 7
X#define FHDLEN 6
X#define DHDLEN 6
X
Xstatic dig_advance ();
X
Xdige_page (idx,skip)
Xint idx;
X{
X	char name[24];
X	FILE *fp;
X	int i,len,hl;
X	char subj[RECLEN],date[RECLEN],from[RECLEN],junk[RECLEN],*str_store();
X	long pos;
X	ARTHEADER hdr;
X
X	Digest = Page.b[idx].art_id;
X
X	if ((fp = vns_aopen(Digest,&hdr)) == NULL)
X		return (-1);
X
X	subj[0] = date[0] = from[0] = junk[0] = '\0';
X
X	/* skip over some articles if requested to */
X	for (i=skip; i > 0; --i)
X	{
X		if (dig_advance(fp,from,subj,date,junk,&pos,&hl) < 0)
X			return (-1);
X	}
X
X	for (i=0; i < L_allow &&
X			(len = dig_advance(fp,from,subj,date,junk,&pos,&hl)) >= 0; ++i)
X	{
X		Page.b[i].art_id = i+1+skip;
X		Page.b[i].art_mark = ' ';
X		subj [C_allow] = '\0';
X		from [C_allow] = '\0';
X		sprintf (name,"%d",len);
X		form_title (date,subj,name,from,100);
X		strcpy (Page.b[i].art_t,date);
X	}
X
X	vns_aclose (fp);
X
X	if (i == 0)
X		return (-1);
X
X	Page.h.artnum = i;
X	return (i);
X}
X
X/*
X	returns name of file containing "article", NULL for failure
X*/
Xchar * dige_extract (s,art,hdr,start)
Xchar *s;
Xint art;
XARTHEADER *hdr;
Xlong *start;
X{
X	FILE *fout,*fin;
X	long pos;
X	int lines,hl;
X	char subj[RECLEN],date[RECLEN],from[RECLEN],bufr[RECLEN];
X	char extra[RECLEN];
X	char *index();
X#ifndef  amiga
X	long ftell();
X#endif
X	char *str_tpool(), *str_tstore();
X
X	if (Ext_pool != NULL)
X		str_tfree(Ext_pool);
X	Ext_pool = str_tpool(3);
X
X	if ((fin = vns_aopen(Digest,hdr)) == NULL)
X		return (NULL);
X
X	for ( ; art > 0; --art)
X	{
X		from[0] = subj[0] = date[0] = '\0';
X		if ((lines = dig_advance(fin,from,subj,date,extra,&pos,&hl)) < 0)
X		{
X			vns_aclose(fin);
X			return (NULL);
X		}
X	}
X
X	tmpnam(s);
X
X	if ((fout = fopen(s,"w")) == NULL)
X	{
X		vns_aclose(fin);
X		unlink (s);
X		return (NULL);
X	}
X
X	fseek(fin,0L,0);
X
X	hdr->show_num = 0;
X	hdr->show = Show;
X	hdr->lines = lines;
X	hdr->hlines = hl;
X	if (subj[0] != '\0')
X	{
X		sprintf (bufr,"%s%s",Thead,subj);
X		Show[hdr->show_num] = str_tstore(Ext_pool,bufr);
X		++(hdr->show_num);
X	}
X	if (from[0] != '\0')
X	{
X		sprintf (bufr,"%s%s",Fhead,from);
X		Show[hdr->show_num] = str_tstore(Ext_pool,bufr);
X		++(hdr->show_num);
X	}
X	if (date[0] != '\0')
X	{
X		sprintf (bufr,"%s%s",Dhead,date);
X		Show[hdr->show_num] = str_tstore(Ext_pool,bufr);
X		++(hdr->show_num);
X	}
X
X	while (fgets(bufr,RECLEN-1,fin) != NULL && bufr[0] != '\n')
X	{
X		if (strncmp(bufr,Fhead,FHDLEN) == 0)
X		{
X			fprintf (fout,"%s%s\n",Fhead,from);
X			continue;
X		}
X		if (strncmp(bufr,Thead,THDLEN) == 0)
X		{
X			fprintf (fout,"%s%s\n",Thead,subj);
X			continue;
X		}
X		if (strncmp(bufr,Dhead,DHDLEN) == 0)
X		{
X			fprintf (fout,"%s%s\n",Dhead,date);
X			continue;
X		}
X		/* defer line count header - it comes last */
X		if (strncmp(bufr,Lhead,LHDLEN) == 0)
X			continue;
X		fprintf (fout,"%s",bufr);
X	}
X
X	/* toss in extra header lines, line count header, extra newline */
X	fprintf (fout,"%s%s%d\n\n",extra,Lhead,lines);
X	*start = ftell(fout);
X
X	fseek (fin,pos,0);
X
X	while (fgets(bufr,RECLEN-1,fin) != NULL && strncmp(bufr,"--------",8) != 0)
X		fprintf(fout,"%s",bufr);
X
X	vns_aclose (fin);
X	fclose (fout);
X	return (s);
X}
X
Xdig_list (s)
Xchar *s;
X{
X	char *ptr,*out,*new,ns[L_tmpnam],tmp[RECLEN],*strtok();
X	ARTHEADER hdr;
X	long pos;
X	int i;
X
X	prinfo ("Extracting articles .....");
X	strcpy (tmp,s);
X	out = s;
X
X	for (ptr = strtok(tmp," "); ptr != NULL; ptr = strtok(NULL," "))
X	{
X		i = atoi(ptr);
X		if ((new = dige_extract(ns,i,&hdr,&pos)) != NULL)
X		{
X			sprintf (out,"%s ",new);
X			out += strlen(new) + 1;
X		}
X	}
X
X	*out = '\0';
X
X	if (*s == '\0')
X		strcpy (s,"NULLDIGEST");
X}
X
Xdig_ulist (s)
Xchar *s;
X{
X	char *strtok();
X	for (s = strtok(s," "); s != NULL; s = strtok(NULL," "))
X		unlink (s);
X}
X
X/*
X	returns # lines in article, -1 for failure
X	scans past article, returns position of start.
X	also returns "extra" header lines encountered, WITH newlines.
X	and counts total header lines.
X*/
Xstatic dig_advance (fp,from,subj,date,extra,pos,hcount)
XFILE *fp;
Xchar *from,*subj,*date,*extra;
Xlong *pos;
Xint *hcount;
X{
X	char buf[RECLEN];
X	char *ptr, *index();
X	int len,state,lcount;
X
X	*hcount = lcount = state = 0;
X	*extra = '\0';
X
X	while (fgets(buf,RECLEN-1,fp) != NULL)
X	{
X		buf[(len = strlen(buf) - 1)] = '\0';
X		for (--len ; len >= 0 && buf[len] == ' ' || buf[len] == '\t'; --len)
X			buf[len] = '\0';
X		++len;
X
X		switch(state)
X		{
X		case 0:
X			/* skip blank lines before header */
X			if (len == 0)
X				break;
X			state = 1;	/* fall through */
X		case 1:
X			++(*hcount);
X			if (strncmp(buf,Fhead,FHDLEN) == 0)
X			{
X				strcpy (from,buf+FHDLEN);
X				break;
X			}
X			if (strncmp(buf,Thead,THDLEN) == 0)
X			{
X				strcpy (subj,buf+THDLEN);
X				break;
X			}
X			if (strncmp(buf,Dhead,DHDLEN) == 0)
X			{
X				strcpy (date,buf+DHDLEN);
X				break;
X			}
X			/* put wierd header lines in extra */
X			if ((ptr = index(buf,':')) != NULL)
X			{
X				*ptr = '\0';
X				if (index(buf, ' ') == NULL)
X				{
X					*ptr = ':';
X					sprintf(extra,"%s\n",buf);
X					extra += strlen(extra);
X					break;
X				}
X				*ptr = ':';
X			}
X			state = 2;
X			--(*hcount);
X
X			/* remember the newline we lopped off */
X			*pos = ftell(fp)-strlen(buf)-1;	/* fall through */
X		case 2:
X			++lcount;
X			if (strncmp("--------",buf,8) == 0)
X			{
X				--lcount;
X				return (lcount);
X			}
X			break;
X		}
X	}
X
X	return (-1);
X}
END_OF_FILE
if test 5727 -ne `wc -c <'digest.c'`; then
    echo shar: \"'digest.c'\" unpacked with wrong size!
fi
# end of 'digest.c'
fi
if test -f 'envir_set.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'envir_set.c'\"
else
echo shar: Extracting \"'envir_set.c'\" \(3569 characters\)
sed "s/^X//" >'envir_set.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** envir_set.c - routine to obtain pertinent environment variable settings
X**		and set up file / directory names
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include <pwd.h>
X
X#ifndef MINIX
X#ifndef MSDOS
X#ifndef amiga
X/* minix does not have this */
X#include <sys/param.h>
X#endif
X#endif
X#endif
X
X#include "tune.h"
X#include "config.h"
X#include "vn.h"
X
Xextern char *Editor, *Ps1, *Printer;
Xextern char *Orgdir, *Savedir, *Ccfile;	/* path names */
Xextern char Cxitop[], Cxitor[], Cxrtoi[], Cxptoi[];
Xextern char *Home;
Xextern int More;
X
X#ifdef SYSV
X#ifndef amiga
Xextern char *getcwd();
X#endif
X#define getwd(a) getcwd(a,sizeof(a))
X#define	MAXPATHLEN 240
X#else
Xextern char *getwd();
X#endif
X
Xstatic set_kxln ();
Xstatic char xln_str ();
X
X/*
X	environment variable, original directory string setup.
X*/
X
Xenvir_set ()
X{
X	char dbuf [MAXPATHLEN], *ccname, *keyxln;
X	char *vn_env(), *str_store();
X#ifndef amiga
X	char * *getcwd();
X#endif
X	struct passwd *ptr, *getpwuid();
X
X	vns_envir();
X	More = 0;
X
X	Ps1 = vn_env("PS1",DEF_PS1);
X	Editor = vn_env("EDITOR",DEF_ED);
X	Printer = vn_env("PRINTER",DEF_PRINT);
X	ccname = vn_env("CCFILE",DEF_CCFILE);
X	keyxln = vn_env("VNKEY",DEF_KEYXLN);
X	Savedir = vn_env("VNSAVE",NULL);
X	More = (strcmp(vn_env("MORE",""), "-c") == 0 ? TRUE : FALSE);
X
X	/*
X		set original directory strings.
X	*/
X
X	if ((ptr = getpwuid(getuid())) == NULL)
X		printex("Cannot obtain /etc/passwd entry");
X	Home = str_store(ptr->pw_dir);
X	if ((Orgdir = getwd(dbuf)) == NULL)
X		printex ("cannot stat pwd");
X	Orgdir = str_store (Orgdir);
X	if (Savedir == NULL)
X		Savedir = Orgdir;
X	if (*ccname != DIRSEP)
X	{
X#ifdef amiga
X		sprintf (dbuf, "%s%s",Home,ccname);
X#else
X		sprintf (dbuf, "%s%c%s",Home,DIRSEP,ccname);
X#endif
X		Ccfile = str_store (dbuf);
X	}
X	else
X		Ccfile = str_store (ccname);
X#ifdef amiga
X	sprintf (dbuf, "%s%s%s",Home,"vn","XXXXXX");
X#else
X	sprintf (dbuf, "%s%c%s%s",Home,DIRSEP,"vn","XXXXXX");
X#endif
X
X	if (*keyxln != DIRSEP)
X	{
X#ifdef amiga
X		sprintf(dbuf, "%s%s",Home,keyxln);
X#else
X		sprintf(dbuf, "%s%c%s",Home,DIRSEP,keyxln);
X#endif
X		set_kxln(dbuf);
X	}
X	else
X		set_kxln(keyxln);
X}
X
Xchar *
Xvn_env(var,def)
Xchar *var;
Xchar *def;
X{
X	char pfx[RECLEN];
X	char *res;
X	char *getenv();
X	char * GetConfig(char *field, char *def);
X
X	if (var[0] != 'V' || var[1] != 'N')
X	{
X		sprintf(pfx,"VN%s",var);
X#ifdef amiga
X		if ((res = GetConfig(pfx, NULL)) == NULL)
X			if ((res = getenv(pfx)) != NULL)
X				return(res);
X		return(res);
X#else
X		if ((res = getenv(pfx)) != NULL)
X			return(res);
X#endif
X	}
X
X#ifdef amiga
X	if ((res = GetConfig(var, NULL)) == NULL)
X		if ((res = getenv(var)) != NULL)
X				return(res);
X	return(res);
X#else
X	if ((res = getenv(var)) != NULL)
X		return(res);
X#endif
X	return(def);
X}
X
Xstatic
Xset_kxln(fname)
Xchar *fname;
X{
X	FILE *fp;
X	int i;
X	char bufr[80];
X	char in,out,*ptr;
X	char *index();
X
X	for (i=0; i < CHMASK+1; ++i)
X		Cxitop[i] = Cxitor[i] = Cxptoi[i] = Cxrtoi[i] = i;
X
X	if ((fp = fopen(fname,"r")) != NULL)
X	{
X		while(fgets(bufr,79,fp) != NULL)
X		{
X			if (strncmp(bufr+1,"==",2) == 0)
X				ptr = bufr+2;
X			else
X				ptr = index(bufr+1,'=');
X			if (ptr == NULL)
X				continue;
X			*ptr = '\0';
X			++ptr;
X			in = xln_str(bufr+1);
X			out = xln_str(ptr);
X			switch(bufr[0])
X			{
X			case 'r':
X			case 'R':
X				Cxrtoi[out] = in;
X				Cxitor[in] = out;
X				break;
X			case 'p':
X			case 'P':
X				Cxptoi[out] = in;
X				Cxitop[in] = out;
X			default:
X				break;
X			}
X		}
X		fclose(fp);
X	}
X}
X
Xstatic char
Xxln_str(s)
Xchar *s;
X{
X	if (*s < '0' || *s > '9')
X		return(*s & CHMASK);
X	return((char)(atoi(s) & CHMASK));
X}
END_OF_FILE
if test 3569 -ne `wc -c <'envir_set.c'`; then
    echo shar: \"'envir_set.c'\" unpacked with wrong size!
fi
# end of 'envir_set.c'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(5211 characters\)
sed "s/^X//" >'makefile' <<'END_OF_FILE'
X# CFLAGS:
X#	set -DJOBCONTROL if you have job control (BSD).
X#	set -DSYSV -Dindex=strchr -Drindex=strrchr on Sytem V systems
X#	set -Dregfree=free if you DON'T include reg.s (SYSV + some BSD)
X#
X# JOBCONTROL could be done as #ifndef SYSV, I suppose, but this clearly
X# marks that particular difference.
X#
X# LIBS:
X# should point to any extra libraries needed, such as termcap.  You
X# may want to change this to use the curses termcap cover.  If you need
X# to pull in another library to get regex / regcmp or strtok on non-SYSV
X# systems, you may want to put that here
X#
X# EXTRAOBJS:
X# may be used to include tmpnam.s, strtok.s, reg.s in the list.
X#
X# These objects implement SYSV utilities for BSD machines.
X#
X# strtok.s implements strtok() / strpbrk().  reg.s implements regex()/regcmp()
X# on top of the BSD regular expression library (regex() allows multiple
X# regular expressions).  tmpnam.s implements tmpnam() of course.
X#
X# If you have them, use your own regex/regcmp, because:
X#
X#	i) They should be faster than the reg.c code, which
X#	recompiles the "current" ucb string every time you
X#	switch regular expressions.
X#
X#	ii) I briefly checked out reg.c once, and it seemed to
X#	work.  Our system has the "real" calls available, so I
X#	run with those.  reg.c hasn't been used much by me, although
X#	I've had nobody tell me it doesn't work.
X#
X# if you DON'T include reg.s, be sure you set -Dregfree=free in CFLAGS.
X#
X# As with regex, if you have a system strtok(), it is likely more efficient -
X# string routines will often be done in assembler on a given machine.
X#
X# Even if you have it, you can use tmpnam.s anyhow.  This version will tailor
X# the temp file name to vnXXXXXX, instead of a generic tmpXXXXXX.
X#
X
X# AMIGA
XCC = dcc
XCFLAGS = -c -DSYSV -Damiga -Dindex=strchr -Drindex=strrchr -DDIRSEP='/'   \
X	 -Odh0:source/vn/
XLFLAGS = 
XLIBS=
XSERVEROBJS = std.o
XEXTRAOBJS = termcap.o regexp.o reg.o regcompat.o amiga.o stat2.o getenv.o \
X	    rand.o mktemp.o config.o
Xnow: vn
X# the vn define is necessary for the moment as I mean to make the amiga.c
X# routine general enougth for other projects and I put some code in amiga.c
X# to map the cursor keys to the UP,DOWN,FORWARD,BACK (j/k/BSP/RETURN)
X# in vn.
Xamiga.o: amiga.c
X	$(CC) $(CFLAGS) -Dvn $*.c
X	
X# MSDOS
X#CC = cl
X#CFLAGS = -Oint -Gs -DSYSV -Dindex=strchr -Drindex=strrchr -AL -DDIRSEP='\\' \
X#	-Dchdir=doschdir
X#LFLAGS = -link /NOI /ST:0x5000 /CP:0xffff
X#LIBS=
X#SERVEROBJS = std.obj
X#EXTRAOBJS = termcap.obj regexp.obj reg.obj regcompat.obj msdos.obj
X
X# "vanilla" BSD:
X#LIBS = -ltermcap
X#EXTRAOBJS = tmpnam.s strtok.s reg.s
X#CFLAGS = -O -DJOBCONTROL
X#
X# "vanilla" SYSV:
X#LIBS = -ltermcap
X#EXTRAOBJS = tmpnam.s
X#
X# BSD with strtok() / regex(), such as ULTRIX.  These are the rules
X# used for our installation (rtech is a microvax running ULTRIX):
X#LIBS = -ltermcap
X#EXTRAOBJS = tmpnam.s
X#CFLAGS = -O -DJOBCONTROL -Dregfree=free
X
X#
X# Minix!!!
X#	Regular expressions: Use reg.c to turn regcmp into re_comp
X#	and regex into re_exec. Use regcompat.c to turn re_comp into
X#	regcomp and re_exec into regexec. Wow! What a load of old
X#	cobblers.
X#LIBS =
X#EXTRAOBJS = tmpnam.s strtok.s reg.s
X#EXTRAOBJS = tmpnam.s reg.s regcompat.s
X#CFLAGS = -F -O -DMINIX -DSYSV
X
X# SERVEROBJS defines the object(s) for the vns_xxxx "server" interface.
X#
X#	std.s is the version for "standard" news, making use of the
X#	users .newsrc file, and  resident articles / active file.
X#
X#SERVEROBJS = std.obj
X#EXTRAOBJS = termcap.obj regexp.obj reg.obj regcompat.obj
X
X# normal vn objects
X#
XVNOBJS=	hash.o envir_set.o pagefile.o reader.o storage.o sig_set.o \
Xterm_set.o tty_set.o userlist.o vn.o vnglob.o digest.o strings.o \
Xsession.o printex.o getch.o help.o newdisp.o stat.o svart.o
X
X# This is to force you to read the makefile.  Once you have, comment this rule,
X# and uncomment the "real" rule.  At the minimum, you will also have to
X# uncomment one of the three sets of LIBS / EXTRAOBJS & CFLAGS definitions
X# above.
X#
X#vn:
X#	@echo "PLEASE READ THE MAKEFILE"
Xvn:	$(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS)
X#	cl -Fevn $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS) $(LIBS)
X#	cc -o vn *.o $(LFLAGS)
X	dlink @dfiles -o vn
X
Xdigest.o:	digest.c config.h head.h node.h page.h tune.h
Xenvir_set.o:	envir_set.c config.h tune.h vn.h
Xgetch.o:	getch.c config.h vn.h
Xhash.o:		hash.c config.h node.h tune.h
Xhelp.o:		help.c config.h node.h page.h reader.h tty.h tune.h vn.h
Xnewdisp.o:	newdisp.c config.h node.h tty.h
Xpagefile.o:	pagefile.c node.h page.h tune.h
Xprintex.o:	printex.c config.h tty.h
Xreader.o:	reader.c config.h brk.h head.h node.h page.h reader.h  \
X		tty.h tune.h vn.h
Xregcompat.o:	regcompat.c
Xsession.o:	session.c config.h brk.h head.h node.h page.h tty.h tune.h \
X		vn.h
Xsig_set.o:	sig_set.c config.h node.h page.h tty.h tune.h
Xstat.o:		stat.c config.h node.h
Xstd.o:		std.c config_std.h brk.h head.h server.h std.h
Xstorage.o:	storage.c node.h page.h tune.h
Xstrings.o:	strings.c node.h page.h tune.h
Xsvart.o:	svart.c config.h node.h page.h tty.h tune.h
Xterm_set.o:	term_set.c config.h node.h page.h tty.h tune.h
Xtty_set.o:	tty_set.c tty.h
Xtmpnam.o:	tmpnam.c config.h
Xuserlist.o:	userlist.c node.h page.h tune.h vn.h
Xvn.o:		vn.c node.h tty.h
Xvnglob.o:	vnglob.c config.h brk.h head.h node.h page.h tune.h
END_OF_FILE
if test 5211 -ne `wc -c <'makefile'`; then
    echo shar: \"'makefile'\" unpacked with wrong size!
fi
# end of 'makefile'
fi
if test -f 'pagefile.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pagefile.c'\"
else
echo shar: Extracting \"'pagefile.c'\" \(4756 characters\)
sed "s/^X//" >'pagefile.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** pagefile.c - routines to deal with page display tempfile
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include <ctype.h>
X
X#ifdef SYSV
X#include <sys/types.h>
X#include <fcntl.h>
X#endif
X
X#ifndef	MINIX
X#ifndef	MSDOS
X#ifndef	amiga
X#include <sys/file.h>
X#endif
X#endif
X#endif
X
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X
X#ifdef amiga
X#ifndef O_BINARY
X#define O_BINARY 0L
X#endif
X#endif
X
X
Xextern int Ncount,Lrec,L_allow,Cur_page,C_allow;
Xextern NODE **Newsorder;
Xextern PAGE Page;
Xextern int Digest;
X
Xextern char *Aformat;
X
Xextern char *T_head, *F_head, *L_head;
X
Xstatic int Tdes;	/* temp file descriptor */
Xstatic int Pgsize;	/* block size for seeking file */
X
Xstatic NODE *Curgp = NULL;	/* current newsgroup being written */
Xstatic int Order = 0;		/* order counter */
X
Xstatic fw_flush (), do_write (), ctl_xlt ();
X
X/*
X	routines which deal with the temp file containing
X	display pages.  Note the "invisible" file feature -
X	tempfile is unlinked from /usr/tmp immediately.  when
X	Tdes is closed by UNIX the disk space will be given back.
X*/
X
X#ifdef amiga
Xchar tmpname [L_tmpnam];
X
Xkill_tmp ()
X{
X	close (Tdes);
X	unlink (tmpname);
X}
X#endif
X
Xtemp_open ()
X{
X	char tmpart [L_tmpnam];
X	Lrec = -1;
X	tmpnam (tmpart);
X	Pgsize = sizeof (HEAD) + L_allow * sizeof(BODY);
X
X#ifdef	MINIX
X	/* Minix doesn'h have O_CREAT or 3-argument open */
X	if ((Tdes = open(tmpart,O_RDWR|OBINARY)) < 0) {
X		creat(tmpart,0644);
X		if ((Tdes = open(tmpart,O_RDWR|OBINARY)) < 0)
X			printex ("can't open %s",tmpart);
X	}
X#else
X	if ((Tdes = open(tmpart,O_RDWR|O_BINARY|O_CREAT,0600)) < 0)
X		printex ("can't open %s",tmpart);
X#endif
X
X#ifndef amiga
X	unlink (tmpart);
X#else
X	memcpy (tmpname, tmpart, L_tmpnam);
X#endif
X}
X
X/*
X** set newsgroup for tempfile write
X*/
Xfw_group(ng,new,sub,rd,look)
Xchar *ng;
Xint new;
Xint sub;
Xint rd;
Xint look;
X{
X	NODE *hashfind();
X
X	if (Curgp != NULL && Page.h.artnum > 0)
X		fw_flush();
X	
X	if ((Curgp = hashfind(ng)) == NULL)
X		printex("fw_group - non-existent newsgroup, \"%s\"",ng);
X	if (Curgp->order >= 0)
X		printex("fw_group - repeat call on newsgroup, \"%s\"",ng);
X	Curgp->order = Order;
X	++Order;
X	fw_chg(new,sub,rd,look);
X	Curgp->pages = 0;
X	Curgp->pnum = Lrec+1;
X	Page.h.name = Curgp->nd_name;
X	Page.h.group = Curgp;
X	Page.h.artnum = 0;
X}
X
Xfw_chg(new,sub,rd,look)
Xint new;
Xint sub;
Xint rd;
Xint look;
X{
X	Curgp->flags &= ~(FLG_NEW|FLG_SUB|FLG_SEARCH);
X	if (new)
X		Curgp->flags |= FLG_NEW;
X	if (sub)
X		Curgp->flags |= FLG_SUB;
X	if (look)
X		Curgp->flags |= FLG_SEARCH;
X	Curgp->rdnum = Curgp->orgrd = Curgp->pgrd = rd;
X}
X
X/*
X** write article to temp file.
X*/
Xfw_art(anum,subj,lines,author)
Xint anum;
Xchar *subj;
Xchar *lines;
Xchar *author;
X{
X	char tbuf[RECLEN];
X	int idx;
X
X	form_title(tbuf,subj,lines,author,anum);
X	idx = Page.h.artnum;
X	strcpy((Page.b)[idx].art_t, tbuf);
X	(Page.b)[idx].art_id = anum;
X	(Page.b)[idx].art_mark = ' ';
X
X	++(Page.h.artnum);
X	if (Page.h.artnum >= L_allow)
X		fw_flush();
X}
X
Xfw_done()
X{
X	if (Curgp != NULL && Page.h.artnum > 0)
X	{
X		/* correct if server was lying at fw_group() */
X		Curgp->flags |= FLG_SEARCH;
X		fw_flush();
X	}
X}
X
Xstatic
Xfw_flush()
X{
X	++(Curgp->pages);
X	++Lrec;
X	Curgp->flags |= FLG_PAGE;
X	do_write();
X	Page.h.artnum = 0;
X}
X
Xfind_page (n)
Xint n;
X{
X	long off;
X#ifndef amiga
X	long lseek();
X#endif
X	int i,last;
X	Cur_page = n;
X	off = Pgsize;
X	off *= (long) n;
X	lseek (Tdes, off, 0);
X	if (read(Tdes, (char *) &(Page.h), sizeof(HEAD)) < sizeof(HEAD))
X		printex("bad temp file read");
X	i = Pgsize - sizeof(HEAD);
X	if (read(Tdes, (char *) Page.b, i) < i)
X		printex("bad temp file read");
X	last = -1;
X	for (i=0; i < Ncount; ++i)
X	{
X		if ((Newsorder[i])->pages > 0)
X		{
X			if ((Newsorder[i])->pnum > n)
X				break;
X			last = i;
X		}
X	}
X	if (last < 0)
X		printex ("can't find page %d",n);
X	Page.h.group = Newsorder[last];
X	Page.h.name = (Page.h.group)->nd_name;
X	vns_gset(Page.h.name);
X}
X
Xwrite_page ()
X{
X	long off;
X#ifndef amiga
X	long lseek();
X#endif
X	if (!Digest)
X	{
X		off = Pgsize;
X		off *= (long) Cur_page;
X		lseek (Tdes, off, 0);
X		do_write();
X	}
X}
X
Xstatic do_write()
X{
X	int num;
X
X	if (write(Tdes, (char *) &(Page.h), sizeof(HEAD)) < sizeof(HEAD))
X		printex ("Bad temp file write");
X	num = L_allow * sizeof(BODY);
X	if (write(Tdes, (char *) Page.b, num) < num)
X		printex ("Bad temp file write");
X}
X
Xform_title (t,fn,fl,ff,n)
Xchar *t,*fn,*fl,*ff;
Xint n;
X{
X	char *ptr,*index();
X	int i;
X
X	if ((ptr = index(ff,'(')) != NULL && strlen(ptr) > 3)
X		ff = ptr;
X	sprintf (t,TFORMAT,fn,fl,ff);
X	sprintf(ff,Aformat,' ',' ',n);
X	i = C_allow - strlen(ff) + 1;	/* remember newline in Aformat */
X	t[i] = '\0';
X	ctl_xlt(t);
X	return (0);
X}
X
X/* replace control characters in titles */
Xstatic ctl_xlt(s)
Xchar *s;
X{
X	while (*s != '\0')
X	{
X		if (iscntrl(*s))
X			*s = '?';
X		++s;
X	}
X}
END_OF_FILE
if test 4756 -ne `wc -c <'pagefile.c'`; then
    echo shar: \"'pagefile.c'\" unpacked with wrong size!
fi
# end of 'pagefile.c'
fi
if test -f 'readme.amiga' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'readme.amiga'\"
else
echo shar: Extracting \"'readme.amiga'\" \(5067 characters\)
sed "s/^X//" >'readme.amiga' <<'END_OF_FILE'
XRELEASE NOTES FOR AMIGA VN (res1.1 8/88) 5/March/1991 RELEASE 2
X===============================================================
X
XIntroduction
X============
X
Xvn is a newsreader, similar to rn, vnews or nn and comes with full
Xsource (executable was created with DICE V2.05). All that is required
Xto run it is access to usenet messages (on a floppy from a friend is
Xhow I get usenet!).
X
XUpdates from Release 1 is the use of the AmigaUUCP Config file for most
Xoptions such as News directory, location and name of the .newsrc and
Xactive files. Also the user can set whether to use nested directories or
Xdirectories the same as the newsgroup name e.g.
XUUNEWS:comp/sys/amiga/misc or UUNEWS:comp.sys.amiga.misc.
X
XExample Config file (called UULIB:Config)
X
XNodeName      uucp
XUserName      root
XRealName      Foo The Bar
XDebug	      0
XNewsFeed      newsnode
XOrganization  Not an Organization
XFilter	      DMe
XRFilter       DMe
XMailEditor    DMe
XDomainName    .UUCP
XTimeZone      PST
XDefaultNode   overload.UUCP
XPALAMIGA      Y			N for NTSC amiga
XVNUSERDIR     UULIB:		where the .newsrc file is (the home dir)
XVNNEWSRC      .newsrc		
XVNPS1         "$ "		vn's prompt.
XVNEDITOR      emacs		
XVNPRINTER     print		command to print
XVNKEY         .vnkey
XVNCCFILE      author_copy
XVNSAVE        UUNEWS:		where to save articles
XVNMORE
XVNMAILER
XVNPOSTER
XVNTERM        amiga-p		termcap entry (amiga-n if NTSC amiga)
XVNACTFILE     uunews:active	the active file
XVNNEWSDIR     uunews:		where the news articles are (SPOOLDIR?)
XVNNESTED      Y			if AmigaUUCP dir structure set to "N"
X
Xas you can see the entries prefixed with VN are for vn.
X
XMichael Taylor 
XCanberra
X
X5th March 1991
X
X
X***Below are the release notes for release 1.***
X
X
X
X
XRELEASE NOTES FOR AMIGA VN (res1.1 8/88) 14/Nov/1990
X====================================================
X
X
X
XIntroduction
X============
X
Xvn is a newsreader, similar to rn, vnews or nn. It requires less memory
Xthan Arn 0.67 (Arn failed to run on my 1 meg amiga due to lack of
Xmemory) and comes with full source (executable was created with DICE
XV2.02). All that is required to run it is access to usenet messages (on
Xa floppy from a friend is how I get usenet!).
X
XSetting Up vn on the amiga
X==========================
X
X1. assign NEWS: <base directory of newsgrups>
X2. create a file called "active" in the directory NEWS: which contains 
X   the name of each news group you are interested in followed by the 
X   last message in the group
X   e.g.
X	comp.sys.amiga 30221
X	comp.sys.amiga.games 2011
X3. do the following SETENVs and copy
X	SETENV term amiga-p   (or amiga-n if using an NTSC machine)
X	SETENV PALAMIGA Y     (or N if using an NTSC machine)
X	copy termcap s: 
X
X4. (optional) create a file called s:.newsrc containing information
X   about the news groups you wish to read. If you don't create this file 
X   then vn will create it for you. (be prepared for a long wait while vn 
X   tries each file from 1 to the last message (as specified in the 
X   news:active file) for each newsgroup you specified in the news:active 
X   file).
X   FILE FORMAT:
X	groupname: <first message> <last message read>
X   e.g.
X	comp.sys.amiga: 1-30119
X	comp.sys.amiga.games: 1-1998
X5. set the stack (I know 20000 works) if it is not already set to some 
X   large value on your system. If the stack is not set large enough then
X   vn will crash probably resulting in a !GURU!
X   e.q. stack 20000
X6. type "vn" at the prompt.
X
XNotes on the directory structure required.
X==========================================
X
XIf the group name is comp.sys.amiga then the news files will reside in a 
Xdirectory called "NEWS:comp/sys/amiga". All the news files will have numeric
Xnames such as "30221" which correspond to the entries in the .newsrc and
Xactive files.
X
XAdditional Notes:
X=================
X
XSome of the internal commands require that the following programs or devices
Xare available, either mounted or in your command path:
X
Xprint		(a print spooler command)
Xnull:		(a device handler)
X
XAdditionally all the commands for replying to news etc still are the MINIX
Xor SYSV equivalents as I do not have access to a UUCP node (I don't even
Xown a modem).
X
XBUGS.
X=====
X
XThere are none in the parts I have tested. I have not tried the 
Xreply/sendmail parts and have not changed the source code for the
Xamiga. It should be a simple matter to adapt the source for these 
Xfunctions. 
X
X
XADVANTAGES OF vn OVER rn.
X=========================
X
Xvn presents you with a list of articles and allows you to select which ones 
Xto read based on the subject and from lines. This allows you to quickly
Xpass over news threads that are not of interest to you. Of course nn does 
Xthis and also organised the news in threads whereas vn presents the news
Xin chronological order (this means that sometimes the original message
Xappears after a reply - due to the order/direction the news filters through
Xto your site). This is a vast improvement over the way rn and vnews allow you
Xto read news. (NOTE: I do not know how Arn works as I could not run it on my
X1meg A500).
X
X
XMichael Taylor 
XCanberra
X
X14th November 1990
END_OF_FILE
if test 5067 -ne `wc -c <'readme.amiga'`; then
    echo shar: \"'readme.amiga'\" unpacked with wrong size!
fi
# end of 'readme.amiga'
fi
if test -f 'rnumbox.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rnumbox.c'\"
else
echo shar: Extracting \"'rnumbox.c'\" \(4787 characters\)
sed "s/^X//" >'rnumbox.c' <<'END_OF_FILE'
X/*--------------------------------------------------------------------- */
X/* umbox.c								*/
X/*	Break rn(1) mbox file into separate articles in a spool		*/
X/*	directory tree.							*/
X/*	A report is  sendt to stdout.					*/
X/*									*/
X/* Usage:								*/
X/*	umbox mboxfile							*/
X/*									*/
X/* Limitations:								*/
X/*	All directories MUST exist.					*/
X/*									*/
X/* History:								*/
X/*	6 Oct 1990	v1.0						*/
X/*									*/
X/* Author:								*/
X/*	Eyal Lebedinsky							*/
X/*	Canberra, AUSTRALIA						*/
X/*--------------------------------------------------------------------- */
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#ifndef	NEWSDIR
X#define	NEWSDIR	"dh0:news/"
X#endif
X
X#ifndef	DIRSEP
X#define	DIRSEP	"/"
X#endif
X
X/*typedef unsigned char	uchar;*/
X
Xstatic uchar	from[4096], line[4096];
Xstatic uchar	newsdir[1024] = NEWSDIR, dirsep[20] = DIRSEP,
X		groupname[1024], groupdir[1024], filename[1024];
Xstatic int	cc1 = 0, cc2 = 0;
X
Xstatic int
Xget_dir (group)
Xuchar	*group;
X{
X	uchar	*p, *q, *s;
X	struct stat	statbuff;
X
X	for (p = groupdir, q = newsdir; *q; *p++= *q++);
X	for (q = group; *q; ++q) {
X		if (*q == '.')
X			for (s = dirsep; *s; *p++ = *s++);
X		else
X			*p++ = *q;
X	}
X	*p = '\0';
X
X	if (stat (groupdir, &statbuff))
X		printf ("could not stat %s\n", groupdir);
X	else if (!(statbuff.st_mode & S_IFDIR))
X		printf ("%s not a directory\n", groupdir);
X	else
X		return (0);
X	return (1);
X}
X
XFILE *active = NULL;
X
Xstatic void
Xdo_one (file)
Xuchar	*file;
X{
X	FILE	*fin = NULL, *fout = NULL;
X	int	found, c1 = 0, c2 = 0, body;
X	uchar	artno[20], *p;
X#ifdef	VBUF
X	uchar	*vip, *voq;
X#endif
X
X	fin = fopen (file, "rt");
X	if (fin == NULL) {
X		fprintf (stderr, "could not open %s\n", file);
X		return;
X	}
X
X#ifdef	VBUF
X#define	BSIZE	20480
X	if ((vip = (uchar *)malloc (BSIZE)) == NULL ||
X	    setvbuf (fin, vip, _IOFBF, BSIZE) ||
X	    (voq = (uchar *)malloc (BSIZE)) == NULL ||
X	    setvbuf (fout, voq, _IOFBF, BSIZE)) {
X		fprintf (stderr, "Out of memory\n");
X		if (vip != NULL)
X			free (vip);
X		if (voq != NULL)
X			free (voq);
X		exit (1);
X	}
X#endif
X
X			/* find first header */
X	for (found = 0; fgets (line, sizeof (line), fin) != NULL;) {
X		if (memcmp (line, "From ", 5) == 0) {
X			found = 1;
X			break;
X		}
X		if (memcmp (line, "Article ", 8) == 0) {
X			found = 2;
X			break;
X		}
X	}
X
X	while (found) {
X		++c1;
X		if (found == 1) {
X			strcpy (from, line);
X			if (fgets (line, sizeof (line), fin) == NULL) {
X				fprintf (stderr, "broken mbox\n");
X				break;
X			}
X		} else
X			from[0] = '\0';
X		if (sscanf (line, "Article %s of %s",
X				artno, groupname) != 2) {
X			fprintf (stderr, "broken mbox\n");
X			break;
X		}
X		groupname[strlen (groupname) - 1] = '\0';
X		if (get_dir (groupname))
X			printf ("%s not a directory\n", groupdir);
X		else {
X			strcpy (filename, groupdir);
X			strcat (filename, dirsep);
X			strcat (filename, artno);
X			fout = fopen (filename, "w");
X			if (fout == NULL)
X				printf ("could not open %s\n",
X					filename);
X			else {
X				printf ("created %s\n", filename);
X				++c2;
X			}
X		}
X
X		fputs (line, stdout);
X
X		if (fout != NULL) {
X			if (found == 1 && (fputs (from, fout) == EOF) ||
X			    (fputs (line, fout) == EOF)) {
X			    	fprintf (stderr, "write error on %s\n",
X					filename);
X				fclose (fout);
X				fout = NULL;
X			}
X		}
X
X		for (body = found = 0;
X		     fgets (line, sizeof (line), fin) != NULL;) {
X			if (memcmp (line, "From ", 5) == 0) {
X				found = 1;
X				break;
X			}
X			if (memcmp (line, "Article ", 8) == 0) {
X				found = 2;
X				break;
X			}
X			if (fout != NULL) {
X				if (!memcmp (line, "Lines: ", 7))
X					body = 1;
X				else if (!body && !memcmp (line, ">From: ", 7))
X					for (p = line; p[0] = p[1]; ++p);
X				if (fputs (line, fout) == EOF) {
X				    	fprintf (stderr, "write error on %s\n",
X						filename);
X					fclose (fout);
X					fout = NULL;
X				}
X			}
X			if (!memcmp (line, "Subject: ", 9) ||
X			    !memcmp (line, "Lines: ", 7) ||
X			    !memcmp (line, "From: ", 6) ||
X			    !memcmp (line, "Date: ", 6) ||
X			    !memcmp (line, "Keywords: ", 10))
X				fputs (line, stdout);
X		}
X		fputs ("\n", stdout);
X		if (fout != NULL) {
X			fclose (fout);
X			fout = NULL;
X		}
X	}
X
X	if (fin != NULL)
X		fclose (fin);
X
X#ifdef	VBUF
X	free (vip);
X	free (voq);
X#endif
X
X	fprintf (stderr, "%s: %u articles found, %u saved.\n",
X		file, c1, c2);
X	fprintf (active, "%s %s\n", groupname, artno);
X	cc1 += c1;
X	cc2 += c2;
X}
X
Xmain (argc, argv)
Xint	argc;
Xuchar	*argv[];
X{
X	if (argc < 2) {
X		fprintf (stderr, "usage: umbox InputFiles\n");
X		exit (0);
X	}
X
X	active = fopen ("active", "w");
X	if (active == NULL) {
X		fprintf (stderr, "could not open 'active' file\n");
X		return;
X	}
X
X	while (argc-- > 1)
X		do_one (*++argv);
X
X	fprintf (stderr, "total %u articles found, %u saved.\n",
X		cc1, cc2);
X
X	fclose (active);
X	
X	exit (0);
X}
END_OF_FILE
if test 4787 -ne `wc -c <'rnumbox.c'`; then
    echo shar: \"'rnumbox.c'\" unpacked with wrong size!
fi
# end of 'rnumbox.c'
fi
if test -f 'sig_set.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'sig_set.c'\"
else
echo shar: Extracting \"'sig_set.c'\" \(5090 characters\)
sed "s/^X//" >'sig_set.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** sig_set.c - signal handler
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X
X#ifdef MINIX
X#include <signal.h>
X#else
X#ifdef MSDOS
X#include <signal.h>
X#else
X#ifdef amiga
X#include <signal.h>
X#else
X#include <sys/signal.h>
X#endif
X#endif
X#endif
X
X#ifndef	MSDOS
X#ifndef	amiga
X#include <sgtty.h>
X#endif
X#endif
X
X#include <setjmp.h>
X#include "tty.h"
X#include "config.h"
X#include "brk.h"
X#include "tune.h"
X#include "node.h"
X#include "page.h"
X
X#ifdef amiga
Xextern char pr_buf[];
Xextern ttputc ();
X#endif
X
Xextern int L_allow;
Xextern char *Version;
Xextern char *Brk_fmt;
Xextern char *Vns_version;
X
Xstatic int Sigflag=BRK_INIT;	/* phase of interaction */
Xstatic FILE **Fpseek;		/* article reading file pointer pointer */
Xstatic int Foreground;
Xstatic jmp_buf Jumploc;		/* for BRK_SESS phase */
Xstatic int Need_restart = 0;
X
X/*
X	interrupt handler - unusual termination (longjmp and printex aborts)
X	if not abort, remember to reset signal trap
X	CAUTION - the passing of a jump buffer is a little dicey - assumes
X	type jump_buf is an array.
X
X	sigcatch and sig_set control a lot of i/o on stderr also, since
X	it is so intimately related to signal interaction.  Note that the
X	SIGTSTP action causes a "stopped on tty output" if raw terminal
X	mode is restored by tty_set(RESTORE).  We don't get it if we were
X	already cooked since tty_set avoids calling ioctl if it doesn't
X	have to.
X*/
Xstatic
Xvoid sigcatch (sig)
Xint sig;
X{
X	char buf [MAX_C+1];
X	int pgrp;
X
X	/* disable signal while processing it */
X	signal (sig,SIG_IGN);
X
X	switch (sig)
X	{
X	case SIGINT:
X#ifdef	SIGQUIT
X	case SIGQUIT:
X#endif
X		break;
X
X#ifdef JOBCONTROL
X	case SIGTSTP:
X		/* ignore SIGTTOU so we don't get stopped if [kc]sh grabs the tty */
X		signal(SIGTTOU, SIG_IGN);
X		tty_set (SAVEMODE);
X		term_set (MOVE,0,L_allow+RECBIAS-1);
X#ifdef amiga
X		sprintf (pr_buf,"\n");
X		tputs(pr_buf,1,ttputc);
X#else
X		printf ("\n");
X#endif
X		Foreground = 0;
X#ifdef amiga
X		ttflush ();
X#else
X		fflush (stdout);
X#endif
X		fflush (stderr);
X		signal(SIGTTOU, SIG_DFL);
X
X		/* Send the TSTP signal to suspend our process group */
X		signal(SIGTSTP, SIG_DFL);
X		sigsetmask(0);
X		kill (0, SIGTSTP);
X
X		/* WE ARE NOW STOPPED */
X
X		/*
X				WELCOME BACK!
X				if terminals process group is ours, we are foregrounded again
X				and can turn newsgroup name printing back on
X			*/
X		tty_set (RESTORE);
X
X		/*
X		** Note concerning RESTART.  If in state BRK_IN, we simply
X		** set a flag to do it upon switch to state BRK_SESS - we
X		** don't want to send i/o to the terminal when we
X		** background during BRK_IN phase ("stopped on tty output")
X		*/
X		switch (Sigflag)
X		{
X		case BRK_SESS:
X			signal (SIGTSTP,sigcatch);
X			term_set (RESTART);
X			longjmp (Jumploc,1);
X		case BRK_IN:
X			Need_restart = 1;
X			ioctl (1,TIOCGPGRP,&pgrp);
X			if (pgrp == getpgrp(0))
X				Foreground = 1;
X			break;
X		default:
X			term_set (RESTART);
X			break;
X		}
X		signal (SIGTSTP,sigcatch);
X		return;
X#endif
X	default:
X		printex (Brk_fmt,sig);
X	}
X
X	/* QUIT and INTERRUPT signals */
X	switch (Sigflag)
X	{
X	case BRK_SESS:
X		/* if in session, ask if really a quit, do longjump if not */
X		term_set (ERASE);
X		tty_set (RAWMODE);
X		user_str (buf, BRK_PR, 1, "");
X		if (buf[0] == 'y')
X			printex (Brk_fmt,sig);
X		signal (sig,sigcatch);
X		longjmp (Jumploc,1);
X	case BRK_READ:
X		/* if reading seek file to end to abort page printing */
X#ifdef amiga
X		sprintf (pr_buf,"\n");
X		tputs(pr_buf,1,ttputc);
X#else
X		printf ("\n");
X#endif
X		if (*Fpseek == NULL || fseek(*Fpseek,0L,2) < 0)
X			putchar ('\07');
X		break;
X	default:
X		printex (Brk_fmt,sig);
X	}
X	signal (sig,sigcatch);
X}
X
X/*
X	sig_set controls what will be done with a signal when picked up by
X	sigcatch.  fgprintf is included here to keep knowledge
X	of TSTP state localized.
X*/
X/* VARARGS */
Xsig_set (flag,dat)
Xint flag, *dat;
X{
X	int i, *xfer, pgrp;
X	if (Sigflag == BRK_INIT)
X	{
X		signal (SIGINT,sigcatch);
X#ifdef	SIGQUIT
X		signal (SIGQUIT,sigcatch);
X#endif
X		signal (SIGTERM,sigcatch);
X#ifdef JOBCONTROL
X		signal (SIGTSTP,sigcatch);
X		ioctl (1,TIOCGPGRP,&pgrp);
X		if (pgrp == getpgrp(0))
X		{
X			Foreground = 1;
X			fgprintf ("Visual News, %s(%s), reading:\n",
X					Version, Vns_version);
X		}
X		else
X			Foreground = 0;
X#else
X		Foreground = NOJOB_FG;
X#endif
X	}
X	switch (flag)
X	{
X	case BRK_IN:
X	case BRK_OUT:
X		Sigflag = flag;
X		break;
X	case BRK_READ:
X		if (Sigflag != BRK_SESS)
X			printex ("unexpected read state, sig_set\n");
X		Fpseek = (FILE **) dat;
X		Sigflag = BRK_READ;
X		break;
X	case BRK_SESS:
X		if (Need_restart)
X			term_set(RESTART);
X		xfer = (int *) Jumploc;
X		for (i=0; i < sizeof(Jumploc) / sizeof(int); ++i)
X			xfer[i] = dat[i];
X		Sigflag = BRK_SESS;
X		break;
X	case BRK_RFIN:
X		if (Sigflag != BRK_READ)
X			printex ("unexpected finish state, sig_set\n");
X		Sigflag = BRK_SESS;
X		break;
X	default:
X		printex ("bad state %d, sig_set\n",flag);
X	}
X}
X
Xfgprintf (fs,a,b,c,d,e)
Xchar *fs;
Xint a,b,c,d,e;
X{
X	if (Foreground) {
X#ifdef amiga
X		sprintf (pr_buf,fs,a,b,c,d,e);
X		tputs (pr_buf,1,ttputc);
X		ttflush ();
X#else
X		fprintf (stderr,fs,a,b,c,d,e);
X#endif
X	}
X#ifndef amiga
X	fflush (stderr);
X#endif
X}
END_OF_FILE
if test 5090 -ne `wc -c <'sig_set.c'`; then
    echo shar: \"'sig_set.c'\" unpacked with wrong size!
fi
# end of 'sig_set.c'
fi
if test -f 'stat.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'stat.c'\"
else
echo shar: Extracting \"'stat.c'\" \(4343 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#ifndef	MSDOS
X#ifndef	amiga
X/* Minix doesn't have sys/file.h for some reason */
X#include <sys/file.h>
X#endif
X#endif
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[81];
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 4343 -ne `wc -c <'stat.c'`; then
    echo shar: \"'stat.c'\" unpacked with wrong size!
fi
# end of 'stat.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'\" \(5322 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
X#ifdef amiga
X#define system(a)	Execute(a, 0, 0)
X#endif
X
Xextern PAGE Page;
Xextern int Digest;
Xextern char *List_sep;
Xextern char *Home;
Xextern char *Savedir;
Xextern FILE *(*Saveopen)();
Xextern int (*Digsaver)();
X
Xextern char *index ();
X
Xstatic  noslash (), twiddle ();
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#ifdef amiga
X		sprintf(cmd,"copy %s %s",fn,dest);
X#else
X		sprintf(cmd,"cat %s %s",fn,dest);
X#endif
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#ifdef amiga
X	if ((colon = index(dest,';')) != NULL)
X	{
X		mode = dest;
X		*colon = '\0';
X		dest = colon+1;
X	}
X#else
X	if ((colon = index(dest,':')) != NULL)
X	{
X		mode = dest;
X		*colon = '\0';
X		dest = colon+1;
X	}
X#endif
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#ifdef amiga
X	if (*dest != DIRSEP)
X	{
X		strcpy (dest, "NEWS:");
X		strcat (dest, idest);
X	}
X#else
X	if (*dest != DIRSEP)
X	{
X		if (noslash(dest,msg) < 0)
X			return (-1);
X	}
X#endif
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#ifndef amiga
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#endif
X#ifdef amiga
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%c%s",dir,DIRSEP,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 != DIRSEP && *tail != '\0'; ++tail)
X		;
X
X	if (*name == '\0' || *name == DIRSEP)
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 5322 -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'\" \(5267 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
X#ifdef amiga
X#undef putchar
X#define putchar ttputc
X#endif
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	int rv;
X
X	tvar = vn_env("TERM",DEF_TERM);
X
X#ifdef amiga
X	ttopen ();	/* open a custom screen */
X#endif
X	c = optstr;
X	if ((rv = tgetent(tc_buf,tvar)) == -1)
X		printex ("termcap file not found");
X	if (rv != 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#ifdef amiga
X		tputs (tgoto(Cm,y,x), 1, outc);
X#else
X		tputs (tgoto(Cm,x,y), 1, outc);
X#endif
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		putchar ('\n');
X		tputs(Ke,1,outc);
X		tputs(Te,1,outc);
X#ifdef USEVS
X		tputs(Ve,1,outc);
X#endif
X#ifdef amiga
X		ttclose ();
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			putchar ('\010');
X			putchar (' ');
X			putchar ('\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 5267 -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 'tty_set.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tty_set.c'\"
else
echo shar: Extracting \"'tty_set.c'\" \(3855 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 MSDOS
Xtty_set(cmd)
Xint cmd;
X{
X	return;
X}
X#else
X
X#ifdef amiga
X
X#include "tty.h"
X
Xextern char Erasekey,Killkey;
X
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
Xtty_set(cmd)
Xint cmd;
X{
X	int rc;
X	unsigned mask;
X
X	rc = 0;
X	switch (cmd)
X	{
X	case BACKSTOP:
X		rc = 0;
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			Erasekey = 8;
X			Killkey = 12;
X		}
X		S_flag = IO_GOT|IO_RAW;
X		break;
X	case COOKED:
X		if ((S_flag & IO_RAW) != 0)
X		{
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			tty_set(COOKED);
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}
X#else
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}
X#endif	/* !MSDOS */
X#endif	/* !amiga */
X
END_OF_FILE
if test 3855 -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 'umbox.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'umbox.c'\"
else
echo shar: Extracting \"'umbox.c'\" \(4567 characters\)
sed "s/^X//" >'umbox.c' <<'END_OF_FILE'
X/*--------------------------------------------------------------------- */
X/* umbox.c								*/
X/*	Break nn(1) mbox file into separate articles in a spool		*/
X/*	directory tree.							*/
X/*	A report is  sent to stdout.					*/
X/*									*/
X/* Usage:								*/
X/*	umbox mboxfile							*/
X/*									*/
X/* Limitations:								*/
X/*	All directories MUST exist.					*/
X/*									*/
X/* History:								*/
X/*	1 Nov 1990	v2.0						*/
X/*									*/
X/* Author:								*/
X/*	Eyal Lebedinsky							*/
X/*	Canberra, AUSTRALIA						*/
X/*--------------------------------------------------------------------- */
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#ifndef	NEWSDIR
X#ifdef amiga
X#define NEWSDIR "dh0:news/"
X#else
X#define	NEWSDIR	"f:\\news\\"
X#endif
X#endif
X
X#ifndef	DIRSEP
X#ifdef amiga
X#define	DIRSEP	"/"
X#else
X#define	DIRSEP	"\\"
X#endif
X#endif
X
X#ifndef amiga
Xtypedef unsigned char	uchar;
X#endif
X
Xstatic uchar	line[4096];
Xstatic uchar	newsdir[1024] = NEWSDIR, dirsep[20] = DIRSEP,
X		groupname[1024], groupdir[1024], filename[1024];
Xstatic int	cc1 = 0, cc2 = 0;
X
Xstatic int
Xget_dir (group)
Xuchar	*group;
X{
X	uchar	*p, *q, *s;
X	struct stat	statbuff;
X
X	for (p = groupdir, q = newsdir; *q; *p++= *q++);
X	for (q = group; *q; ++q) {
X		if (*q == '.')
X			for (s = dirsep; *s; *p++ = *s++);
X		else
X			*p++ = *q;
X	}
X	*p = '\0';
X
X	if (stat (groupdir, &statbuff))
X		printf ("could not stat %s\n", groupdir);
X	else if (!(statbuff.st_mode & S_IFDIR))
X		printf ("%s not a directory\n", groupdir);
X	else
X		return (0);
X	return (1);
X}
X
XFILE *active = NULL;
X
Xstatic void
Xdo_one (file)
Xuchar	*file;
X{
X	FILE	*fin = NULL, *fout = NULL;
X	int	found, c1 = 0, c2 = 0, body;
X	uchar	artno[20], *p;
X#ifdef	VBUF
X	uchar	*vip, *voq;
X#endif
X
X	fin = fopen (file, "rt");
X	if (fin == NULL) {
X		fprintf (stderr, "could not open %s\n", file);
X		return;
X	}
X
X#ifdef	VBUF
X#define	BSIZE	20480
X	if ((vip = malloc (BSIZE)) == NULL ||
X	    setvbuf (fin, vip, _IOFBF, BSIZE) ||
X	    (voq = malloc (BSIZE)) == NULL ||
X	    setvbuf (fout, voq, _IOFBF, BSIZE)) {
X		fprintf (stderr, "Out of memory\n");
X		if (vip != NULL)
X			free (vip);
X		if (voq != NULL)
X			free (voq);
X		exit (1);
X	}
X#endif
X			/* find first header */
X	for (found = 0; fgets (line, sizeof (line), fin) != NULL;) {
X		if (memcmp (line, "Newsgroup: ", 11) == 0) {
X			found = 1;
X			break;
X		}
X	}
X
X	while (found) {
X		++c1;
X		if (sscanf (line,
X		   "Newsgroup: %[abcdefghijklmnopqrstuvwxyz0123456789.-]/%s",
X				groupname, artno) != 2) {
X			fprintf (stderr, "broken mbox\n");
X			break;
X		}
X		if (get_dir (groupname))
X			printf ("%s not a directory\n", groupdir);
X		else {
X			strcpy (filename, groupdir);
X			strcat (filename, dirsep);
X			strcat (filename, artno);
X			fout = fopen (filename, "wt");
X			if (fout == NULL)
X				printf ("could not open %s\n",
X					filename);
X			else {
X				printf ("created %s\n", filename);
X				++c2;
X			}
X		}
X
X		fputs (line, stdout);
X
X		if (fout != NULL) {
X			if (fputs (line, fout) == EOF) {
X			    	fprintf (stderr, "write error on %s\n",
X					filename);
X				fclose (fout);
X				fout = NULL;
X			}
X		}
X
X		for (body = found = 0;
X		     fgets (line, sizeof (line), fin) != NULL;) {
X			if (memcmp (line, "Newsgroup: ", 11) == 0) {
X				found = 1;
X				break;
X			}
X			if (fout != NULL) {
X				if (!memcmp (line, "Lines: ", 7))
X					body = 1;
X				else if (!body && !memcmp (line, ">From: ", 7))
X					for (p = line; p[0] = p[1]; ++p);
X				if (fputs (line, fout) == EOF) {
X				    	fprintf (stderr, "write error on %s\n",
X						filename);
X					fclose (fout);
X					fout = NULL;
X				}
X			}
X			if (!memcmp (line, "Subject: ", 9) ||
X			    !memcmp (line, "Lines: ", 7) ||
X			    !memcmp (line, "From: ", 6) ||
X			    !memcmp (line, "Date: ", 6) ||
X			    !memcmp (line, "Keywords: ", 10))
X				fputs (line, stdout);
X		}
X		fputs ("\n", stdout);
X		if (fout != NULL) {
X			fclose (fout);
X			fout = NULL;
X		}
X	}
X
X	if (fin != NULL)
X		fclose (fin);
X
X#ifdef	VBUF
X	free (vip);
X	free (voq);
X#endif
X
X	fprintf (stderr, "%s: %u articles found, %u saved.\n",
X		file, c1, c2);
X	cc1 += c1;
X	cc2 += c2;
X#ifdef amiga
X	fprintf (active, "%s %s\n", groupname, artno);
X#endif
X}
X
Xmain (argc, argv)
Xint	argc;
Xuchar	*argv[];
X{
X	if (argc < 2) {
X		fprintf (stderr, "usage: umbox InputFiles\n");
X		exit (0);
X	}
X
X#ifdef amiga
X	active = fopen ("active", "w");
X	if (active == NULL) {
X		fprintf (stderr, "could not open 'active' file\n");
X		return;
X	}
X#endif
X	while (argc-- > 1)
X		do_one (*++argv);
X
X	fprintf (stderr, "total %u articles found, %u saved.\n",
X		cc1, cc2);
X
X#ifdef amiga
X	fclose (active);
X#endif
X	exit (0);
X}
END_OF_FILE
if test 4567 -ne `wc -c <'umbox.c'`; then
    echo shar: \"'umbox.c'\" unpacked with wrong size!
fi
# end of 'umbox.c'
fi
echo shar: End of archive 2 \(of 6\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.