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

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

Submitted-by: eyal@echo.canberra.edu.au (Eyal Lebedinsky)
Posting-number: Volume 91, Issue 022
Archive-name: news/vn-res1.1/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 makefile pagefile.c readme.ami rnumbox.c
#   sig_set.c stat.c svart.c term_set.c termcap.c umbox.c
# Wrapped by tadguy@ab20 on Tue Feb 26 19:28:43 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'\" \(5705 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	long ftell();
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 5705 -ne `wc -c <'digest.c'`; then
    echo shar: \"'digest.c'\" unpacked with wrong size!
fi
# end of 'digest.c'
fi
if test -f 'makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'makefile'\"
else
echo shar: Extracting \"'makefile'\" \(5202 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
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 5202 -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'\" \(4700 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,lseek();
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,lseek();
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 4700 -ne `wc -c <'pagefile.c'`; then
    echo shar: \"'pagefile.c'\" unpacked with wrong size!
fi
# end of 'pagefile.c'
fi
if test -f 'readme.ami' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'readme.ami'\"
else
echo shar: Extracting \"'readme.ami'\" \(4156 characters\)
sed "s/^X//" >'readme.ami' <<'END_OF_FILE'
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
XAdditional utilities
X====================
X
Xupdact : reads the NEWS:active file and updates it with the latest news
X	article number. (attempts to find the last article by continuing
X	from the number in the active file and scanning ahead a file at a
X	time for a 1000 files, if none are found then it leaves the number
X	alone).
X
Xgettoc: prints the subject lines to stdout. takes as input the file
X	names of news articles.
X
Xumbox and rnumbox: the rn and nn newsreaders will package news articles
X	into a mailbox format. these can then be archived. these programs
X	extract the articles into the correct directories.
X
Xgetren: renames the article to the Vnn??? form as with comp.sources etc
X
XMichael Taylor 
XCanberra
X
X19th February 1990
X
X
END_OF_FILE
if test 4156 -ne `wc -c <'readme.ami'`; then
    echo shar: \"'readme.ami'\" unpacked with wrong size!
fi
# end of 'readme.ami'
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 'termcap.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'termcap.c'\"
else
echo shar: Extracting \"'termcap.c'\" \(7472 characters\)
sed "s/^X//" >'termcap.c' <<'END_OF_FILE'
X/*
X *	termcap.c	V1.1	20/7/87		agc	Joypace Ltd
X *
X *	Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
X *	This file may be freely distributed provided that this notice
X *	remains attached.
X *
X *	A public domain implementation of the termcap(3) routines.
X *
X *
X *
X *	 Klamer Schutte	      V1.2    Nov. 1988
X *
X *   - Can match multiple terminal names		 [tgetent]
X *   - Removal of **area assignments			 [tgetstr]
X *
X *	 Terrence W. Holm     V1.3    May, Sep, Oct.  1988
X *
X *   - Correct when TERM != name and TERMCAP is defined	 [tgetent]
X *   - Correct the comparison for the terminal name 	 [tgetent]
X *   - Correct the value of ^x escapes              	 [tgetstr]
X *   - Added %r to reverse row/column			 [tgoto]
X *   - Fixed end of definition test			 [tgetnum/flag/str]
X *
X *	 Terrence W. Holm     V1.4    Jan. 1989
X *
X *   - Incorporated Klamer's V1.2 fixes into V1.3
X *   - Added %d, (old %d is now %2)			 [tgoto]
X *   - Allow '#' comments in definition file		 [tgetent]
X */
X
X#include <lib.h>
X#include <termcap.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <ctype.h>
X#include <string.h>
X
Xchar *capab = (char *)NULL;		/* the capability itself */
X
X#if 0
X/*  The following are not yet used.  */
Xextern short ospeed;		/* output speed */
Xextern char PC;			/* padding character */
Xextern char *BC;		/* back cursor movement */
Xextern char *UP;		/* up cursor movement */
X#endif
X
X/*
X *	tgetent - get the termcap entry for terminal name, and put it
X *	in bp (which must be an array of 1024 chars). Returns 1 if
X *	termcap entry found, 0 if not found, and -1 if file not found.
X */
X
Xint tgetent(bp, name)
Xchar *bp;
Xchar *name;
X{
X  FILE *fp;
X  char *file;
X  char *term;
X  short len = strlen(name);
X  extern char *getenv ();
X
X  capab = bp;
X
X  /* If TERMCAP begins with a '/' then use TERMCAP as the path	 */
X  /* Name of the termcap definitions file. If TERMCAP is a	 */
X  /* Definition and TERM equals "name" then use TERMCAP as the	 */
X  /* Definition. Otherwise use "/etc/termcap" as the path name.	 */
X
X  if ((file = getenv("TERMCAP")) == (char *)NULL)
X#ifdef amiga
X	file = "s:termcap";
X#else
X	file = "/etc/termcap";
X#endif
X  else if (*file != DIRSEP) {
X	if ((term = getenv("TERM")) != (char *)NULL && strcmp(term, name) == 0) {
X		*bp = '\0';
X		strncat(bp, file, 1023);
X		return(1);
X	} else
X#ifdef amiga
X		file = "s:termcap";
X#else
X		file = "/etc/termcap";
X#endif
X  }
X
X  if ((fp = fopen(file, "r")) == (FILE *) NULL) {
X	capab = (char *)NULL;		/* no valid termcap  */
X	return(-1);
X  }
X  for (;;) {
X	/* Read in each definition */
X	int def_len = 0;
X	char *cp = bp;
X
X	do {
X		if (fgets(&bp[def_len], (unsigned int)(1024 - def_len), fp) == (char *)NULL) {
X			fclose(fp);
X			capab = (char *)NULL;	/* no valid termcap */
X			return(0);
X		}
X		def_len = strlen(bp) - 2;
X	} while (bp[def_len] == '\\');
X
X	while (isspace(*cp)) cp++;
X
X	/* Comment lines start with a '#'  */
X	if (*cp == '#') continue;
X
X	/* See if any of the terminal names in this definition */
X	/* Match "name".						 */
X
X	do {
X		if (strncmp(name, cp, len) == 0 &&
X		    (cp[len] == '|' || cp[len] == ':')) {
X			fclose(fp);
X			return(1);
X		}
X		while ((*cp) && (*cp != '|') && (*cp != ':')) cp++;
X	} while (*cp++ == '|');
X  }
X}
X
X
X/*
X *	tgetnum - get the numeric terminal capability corresponding
X *	to id. Returns the value, -1 if invalid.
X */
X
Xint tgetnum(id)
Xchar *id;
X{
X  register char *cp = capab;
X
X  if (cp == (char *)NULL || id == (char *)NULL) return(-1);
X
X  for (;;) {
X	while (*cp++ != ':')
X		if (cp[-1] == '\0') return(-1);
X
X	while (isspace(*cp)) cp++;
X
X	if (strncmp(cp, id, 2) == 0 && cp[2] == '#') return(atoi(cp + 3));
X  }
X}
X
X
X/*
X *	tgetflag - get the boolean flag corresponding to id. Returns -1
X *	if invalid, 0 if the flag is not in termcap entry, or 1 if it is
X *	present.
X */
X
Xint tgetflag(id)
Xchar *id;
X{
X  register char *cp = capab;
X
X  if (cp == (char *)NULL || id == (char *)NULL) return(-1);
X
X  for (;;) {
X	while (*cp++ != ':')
X		if (cp[-1] == '\0') return(0);
X
X	while (isspace(*cp)) cp++;
X
X	if (strncmp(cp, id, 2) == 0) return(1);
X  }
X}
X
X
X/*
X *	tgetstr - get the string capability corresponding to id and place
X *	it in area (advancing area at same time). Expand escape sequences
X *	etc. Returns the string, or NULL if it can't do it.
X */
X
Xchar *tgetstr(id, area)
Xchar *id;
Xchar **area;
X{
X  register char *cp = capab;
X  register char *wsp = *area;	/* workspace pointer  */
X
X  if (cp == (char *)NULL || id == (char *)NULL) return((char *)NULL);
X
X  for (;;) {
X	while (*cp++ != ':')
X		if (cp[-1] == '\0') return((char *)NULL);
X
X	while (isspace(*cp)) cp++;
X
X	if (strncmp(cp, id, 2) == 0 && cp[2] == '=') {
X		for (cp += 3; *cp && *cp != ':'; wsp++, cp++) switch (*cp) {
X			    case '^':
X				*wsp = *++cp - '@';
X				break;
X
X			    case '\\':
X				switch (*++cp) {
X				    case 'E':
X					*wsp = '\033';
X					break;
X				    case 'n':
X					*wsp = '\n';
X					break;
X				    case 'r':
X					*wsp = '\r';
X					break;
X				    case 't':
X					*wsp = '\t';
X					break;
X				    case 'b':
X					*wsp = '\b';
X					break;
X				    case 'f':
X					*wsp = '\f';
X					break;
X				    case '0':
X				    case '1':
X				    case '2':
X				    case '3':
X					{
X						int i;
X						int t = 0;
X						for (i = 0; i < 3 &&
X						     isdigit(*cp); ++i, ++cp)
X							t = t * 8 + *cp - '0';
X						*wsp = t;
X						cp--;
X						break;
X					}
X				    default:
X					*wsp = *cp;
X				}
X				break;
X
X			    default:	*wsp = *cp;
X  			}
X
X		*wsp++ = '\0';
X
X		{
X			char *ret = *area;
X			*area = wsp;
X			return(ret);
X		}
X	}
X  }				/* end for(;;) */
X}
X
X
X
X/*
X *	tgoto - given the cursor motion string cm, make up the string
X *	for the cursor to go to (destcol, destline), and return the string.
X *	Returns "OOPS" if something's gone wrong, or the string otherwise.
X */
X
Xchar *tgoto(cm, destcol, destline)
Xchar *cm;
Xint destcol;
Xint destline;
X{
X  PRIVATE char ret[24];
X  char *rp = ret;
X  int incr = 0;
X  int argno = 0;
X  int numval;
X
X  for (; *cm; cm++) {
X	if (*cm == '%') {
X		switch (*++cm) {
X		    case 'i':	incr = 1;	  			break;
X
X		    case 'r':	argno = 1;	  			break;
X
X		    case '+':
X#ifdef amiga
X			numval = (argno == 0 ? destcol : destline);
X#else
X			numval = (argno == 0 ? destline : destcol);
X#endif
X			*rp++ = numval + incr + *++cm;
X			argno = 1 - argno;
X			break;
X
X		    case '2':
X#ifdef amiga
X			numval = (argno == 0 ? destcol : destline);
X			numval = (numval + incr) % 100;
X#else
X			numval = (argno == 0 ? destline : destcol);
X			numval = (numval + incr) % 100;
X#endif
X			*rp++ = '0' + (numval / 10);
X			*rp++ = '0' + (numval % 10);
X			argno = 1 - argno;
X			break;
X
X		    case 'd':
X#ifdef amiga
X			numval = (argno == 0 ? destcol : destline);
X			numval = (numval + incr) % 1000;
X#else
X			numval = (argno == 0 ? destline : destcol);
X			numval = (numval + incr) % 1000;
X#endif
X			if (numval > 99) *rp++ = '0' + (numval / 100);
X			if (numval > 9) *rp++ = '0' + (numval / 10) % 10;
X			*rp++ = '0' + (numval % 10);
X			argno = 1 - argno;
X			break;
X
X		    case '%':	*rp++ = '%';	  			break;
X
X		    default:	return("OOPS");
X  		}
X
X	} else
X		*rp++ = *cm;
X  }
X
X  *rp = '\0';
X  return(ret);
X}
X
X
X
X/*
X *	tputs - put the string cp out onto the terminal, using the function
X *	outc. This should do padding for the terminal, but I can't find a
X *	terminal that needs padding at the moment...
X */
X
Xint tputs(cp, affcnt, outc)
Xregister char *cp;
Xint affcnt;
X_PROTOTYPE( void (*outc), (int ch));
X{
X  if (cp == (char *)NULL) return(1);
X  /* Do any padding interpretation - left null for MINIX just now */
X  while (*cp) (*outc) (*cp++);
X  return(1);
X}
END_OF_FILE
if test 7472 -ne `wc -c <'termcap.c'`; then
    echo shar: \"'termcap.c'\" unpacked with wrong size!
fi
# end of 'termcap.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.