nick@ultima.cs.uts.oz (Nick Andrew) (11/26/89)
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: newdisp.c node.h page.h pagefile.c printex.c reader.c
# reader.h reg.c regcompat.c
# Wrapped by nick@ultima on Sun Nov 26 22:15:46 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'newdisp.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'newdisp.c'\"
else
echo shar: Extracting \"'newdisp.c'\" \(920 characters\)
sed "s/^X//" >'newdisp.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** newgroups.c - display list of new groups since user's last ession.
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include "config.h"
X#include "tty.h"
X#include "node.h"
X
Xextern NODE **Newsorder;
Xextern int Ncount, Lrec, C_allow;
X
Xnew_groups ()
X{
X int i,wrem,w;
X int max;
X char fs[24],c_end;
X
X max = 0;
X for (i=0; i < Ncount; ++i)
X if (((Newsorder[i])->flags & FLG_NEW) != 0 &&
X (w = strlen((Newsorder[i])->nd_name)) > max)
X max = w;
X sprintf (fs,"%%-%ds%%c",max);
X
X if (max <= 0)
X return (0);
X
X term_set (ERASE);
X printf ("New newsgroups:\n");
X
X wrem = C_allow;
X for (i=0; i < Ncount; ++i)
X {
X if (((Newsorder[i])->flags & FLG_NEW) == 0)
X continue;
X if ((wrem -= max) < max)
X {
X wrem = C_allow;
X c_end = '\n';
X }
X else
X c_end = ' ';
X printf (fs,(Newsorder[i])->nd_name,c_end);
X }
X if (c_end != '\n')
X putchar ('\n');
X
X return (1);
X}
END_OF_FILE
if test 920 -ne `wc -c <'newdisp.c'`; then
echo shar: \"'newdisp.c'\" unpacked with wrong size!
fi
# end of 'newdisp.c'
fi
if test -f 'node.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'node.h'\"
else
echo shar: Extracting \"'node.h'\" \(1580 characters\)
sed "s/^X//" >'node.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** node.h - NODE structure
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X/* newsgroup status flags */
X#define FLG_SUB 1 /* user subscribed to newsgroup */
X#define FLG_PAGE 2 /* a page exists to display */
X#define FLG_NEW 4 /* new newsgroup */
X#define FLG_ECHG 8 /* edit change by user */
X#define FLG_SEARCH 16 /* newsgroup was searched */
X#define FLG_ACC 32 /* newsgroup had articles accessed */
X#define FLG_STAT 64 /* stat's written */
X
X/*
X newsgroup information (hash table node)
X
X items unaccessed by server interface:
X next - hashtable link
X pnum - page number
X pages - number of pages for news display
X pgshwn - pages shown mask
X pgrd - article number on highest conecutively shown page
X order - order of appearance in Newsorder array.
X orgrd - original articles read number
X
X may be read following hashfind by server interface, but not written:
X nd_name - name of newsgroup (key to reach node by)
X this will be a permanent copy of the name.
X highnum - high article number in group
X lownum - low article number in group
X
X legal for vns_write to read, but not written by server interface:
X flags - bit mask of FLG_xxxx flags.
X rdnum - articles read.
X
X unused by vn user interface, intended for use by server interface:
X state - state variable. initted 0.
X data - arbitrary data pointer. initted NULL.
X*/
Xtypedef struct _node
X{
X struct _node *next;
X char *nd_name;
X int highnum, lownum;
X int pnum, pages, rdnum, orgrd, pgrd;
X unsigned long pgshwn;
X unsigned flags;
X int order;
X unsigned state;
X char *data;
X} NODE;
END_OF_FILE
if test 1580 -ne `wc -c <'node.h'`; then
echo shar: \"'node.h'\" unpacked with wrong size!
fi
# end of 'node.h'
fi
if test -f 'page.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'page.h'\"
else
echo shar: Extracting \"'page.h'\" \(1152 characters\)
sed "s/^X//" >'page.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** page.h - display page structure
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X/*
X page display format and dependent parameters
X*/
X#define HFORMAT "\n%s (page %d of %d):"
X#define DHFORMAT "\n%s (DIGEST EXTRACTION):"
X#define TFORMAT "%s ~ %s %s"
X#define AFORMAT "\n%c%c%d) " /* begin with newline - see show routine */
X#define AFLEN 5 /* min. char. in article id - depends on AFORMAT */
X#define CFORMAT "page %d of %d (%d shown), newsgroup %d of %d"
X#define RECBIAS 2 /* lines before articles - depends on HFORMAT */
X#define WRCOL 1 /* column of written mark. depends on AFORMAT */
X#define INFOLINE 0 /* HFORMAT TFORMAT leaves for use */
X#define REQLINES 7 /* required terminal lines for display, incl. help */
X
X/*
X newsgroup information for page display
X name - of group
X group - pointer to table entry
X artnum - number of articles
X*/
Xtypedef struct
X{
X char *name;
X NODE *group;
X int artnum;
X} HEAD;
X
X/*
X article information - id (spool) number, title string, mark, written.
X*/
Xtypedef struct
X{
X int art_id;
X char art_mark;
X char art_t[MAX_C-AFLEN];
X} BODY;
X
Xtypedef struct
X{
X HEAD h;
X BODY *b;
X} PAGE;
END_OF_FILE
if test 1152 -ne `wc -c <'page.h'`; then
echo shar: \"'page.h'\" unpacked with wrong size!
fi
# end of 'page.h'
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'\" \(4360 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#include <sys/file.h>
X#endif
X
X#include "tune.h"
X#include "node.h"
X#include "page.h"
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
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
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)) < 0) {
X creat(tmpart,0644);
X if ((Tdes = open(tmpart,O_RDWR)) < 0)
X printex ("can't open %s",tmpart);
X }
X#else
X if ((Tdes = open(tmpart,O_RDWR|O_CREAT,0600)) < 0)
X printex ("can't open %s",tmpart);
X#endif
X
X unlink (tmpart);
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 4360 -ne `wc -c <'pagefile.c'`; then
echo shar: \"'pagefile.c'\" unpacked with wrong size!
fi
# end of 'pagefile.c'
fi
if test -f 'printex.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'printex.c'\"
else
echo shar: Extracting \"'printex.c'\" \(760 characters\)
sed "s/^X//" >'printex.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** printex.c - print fatal error message and exit.
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X#include <stdio.h>
X#include <setjmp.h>
X#include "config.h"
X#include "tty.h"
X
Xextern int errno; /* unix error number */
X
X/*
X error/abnormal condition cleanup and abort routine
X pass stack to printf
X*/
Xprintex (s,a,b,c,d,e,f)
Xchar *s;
Xlong a,b,c,d,e,f;
X{
X static int topflag=0;
X if (topflag == 0)
X {
X ++topflag;
X term_set (STOP);
X#ifndef MINIX
X tty_set (COOKED);
X#else
X/* COOKED is defined in Minix! */
X tty_set (XCOOKED);
X#endif
X fflush (stdout);
X fprintf (stderr,s,a,b,c,d,e,f);
X fprintf (stderr," (error code %d)\n",errno);
X vns_exit(1);
X stat_end(-1);
X exit (1);
X }
X else
X fprintf (stderr,s,a,b,c,d,e,f);
X}
END_OF_FILE
if test 760 -ne `wc -c <'printex.c'`; then
echo shar: \"'printex.c'\" unpacked with wrong size!
fi
# end of 'printex.c'
fi
if test -f 'reader.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'reader.c'\"
else
echo shar: Extracting \"'reader.c'\" \(16175 characters\)
sed "s/^X//" >'reader.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** reader.c - article reading interface - "more" like.
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <ctype.h>
X#include "tty.h"
X#include "config.h"
X#include "tune.h"
X#include "head.h"
X#include "reader.h"
X#include "brk.h"
X#include "node.h"
X#include "page.h"
X#include "vn.h"
X
X#define PERTAB 8 /* tab expansion factor */
X#define BACKTRACK 24
X
Xextern char *Printer,*Editor,*Mailer,*Poster,*Orgdir,*Savefile,*Savedir,*Ccfile;
Xextern int L_allow;
Xextern int C_allow;
Xextern int Rot;
Xextern int Headflag;
Xextern int Digest;
Xextern int More;
Xextern char *No_msg;
Xextern char *Roton_msg;
Xextern char *Rotoff_msg;
Xextern char *Hdon_msg;
Xextern char *Hdoff_msg;
Xextern char *Def_smode;
X
Xextern PAGE Page;
X
Xextern int (*Massage)();
Xextern int (*Postfunc)();
Xextern int (*Mailfunc)();
Xextern int (*Savemode)();
Xextern int (*Hookfunc)();
X
Xextern char Cxrtoi[], Cxitor[];
X
Xstatic FILE *Fpread;
Xstatic char *Fname;
Xstatic char *Lookahead;
Xstatic int Rlines;
Xstatic int Hlines;
Xstatic long Rew_pos;
X
X/*
X readfile presents article:
X fn = name of article.
X sn - name of next article, NULL if last.
X pages - pages to advance on return, if applicable
X returns 0 for "continue", <0 for "quit"
X
X calls sig_set(BRK_READ / BRK_RFIN) around reading article.
X*/
Xreadfile (fn,sn,pages)
Xchar *fn;
Xchar *sn;
Xint *pages;
X{
X ARTHEADER hdr;
X FILE *fopen();
X int lines,percent;
X int i;
X int top, bottom;
X int step;
X char c, buf[RECLEN];
X char lasave[RECLEN];
X char pstr[24], dgname[48];
X char getpgch(), *index(), *dige_extract(), *tgetstr();
X char *any;
X FILE *vns_aopen();
X long ftell();
X
X Fname = fn;
X *pages = 0;
X step = FALSE; /* Boolean; to indicate user input a <RET> (PG_STEP) */
X
X term_set(ERASE);
X sig_set(BRK_READ,&Fpread);
X
X any = "any key to continue .... ";
X
X if (Digest)
X {
X lines = atoi(Fname);
X if ((Fname = dige_extract(dgname,lines,&hdr,&Rew_pos)) == NULL)
X {
X rerrmsg("couldn't extract article %d from digest",lines);
X printf(any);
X getnoctl();
X sig_set(BRK_RFIN);
X return (0);
X }
X if ((Fpread = fopen(Fname,"r")) == NULL)
X {
X rerrmsg("couldn't open %s",Fname);
X printf(any);
X getnoctl();
X sig_set(BRK_RFIN);
X return (0);
X }
X fseek(Fpread,Rew_pos,0);
X }
X else
X {
X if ((Fpread = vns_aopen(atoi(Fname),&hdr)) == NULL)
X {
X rerrmsg("couldn't open article %s",Fname);
X printf(any);
X getnoctl();
X sig_set(BRK_RFIN);
X return (0);
X }
X Rew_pos = ftell(Fpread);
X }
X
X Hlines = hdr.hlines;
X printf (ANFORM,Fname,Cxrtoi[PG_HELP]);
X
X lines = 0;
X
X if (Headflag)
X {
X rewind(Fpread);
X Rlines = 0;
X }
X else
X {
X /* use do_out to guard against control sequences */
X Rlines = Hlines;
X for (i=0; i < hdr.show_num; ++i)
X lines += do_out((hdr.show)[i],L_allow-lines);
X lines += do_out("",L_allow-lines);
X }
X
X /* will return out of outer while loop */
X Lookahead = NULL;
X while (1)
X {
X /*
X ** lines counts folded lines from do_out.
X ** globals Hlines and Rlines refer to records.
X ** If Lookahead is null after this loop, we've
X ** hit EOF.
X */
X if (Lookahead != NULL && More && !step)
X {
X char *looktmp;
X
X /*
X ** Save Lookahead because `do_out' nukes it.
X ** Perhaps we could just use `printf' here
X ** but for now we'll play it safe. - GKE 12/26/87
X */
X looktmp = Lookahead;
X term_set(ERASE);
X /*
X ** The following presents the last line of the
X ** previous page in reversed video, as the first line
X ** of the current page, `rn'-stylee. Since `rn'
X ** uses an option to enable/disable this, remove the
X ** two `term_set's if not to your liking.
X */
X term_set(ONREVERSE);
X do_out(lasave,1);
X term_set(OFFREVERSE);
X Lookahead = looktmp;
X }
X lines += do_out(Lookahead,L_allow-lines);
X while (1)
X {
X if (Lookahead == NULL)
X {
X if (fgets(buf,RECLEN-1,Fpread) == NULL)
X break;
X Lookahead = buf;
X if (Rot != 0 && Rlines >= Hlines)
X rot_line(buf);
X ++Rlines;
X }
X if (lines >= L_allow)
X break;
X if (More)
X strcpy(lasave,Lookahead);
X lines += do_out(Lookahead,L_allow-lines);
X }
X
X if (Lookahead != NULL)
X {
X /*
X ** calculation is truncated rather than rounded,
X ** so we shouldn't get "100%". Subtract 2 for
X ** 1 line lookahead and empty line at beginning
X ** of article.
X */
X if (Headflag)
X {
X top = (Rlines-2);
X bottom = hdr.lines + Hlines;
X }
X else
X {
X top = (Rlines-Hlines-2);
X bottom = hdr.lines;
X }
X /*
X ** protect against division by zero -
X ** shouldn't actually come up zero at this
X ** point if vns_aopen is sane. 999 will let user
X ** know the percentage is obviously wrong.
X */
X if (bottom != 0)
X percent = (top*100L)/bottom;
X else
X percent = 999;
X sprintf (pstr,PAGE_MID,percent);
X }
X else
X {
X if (sn == NULL)
X strcpy (pstr,PAGE_END);
X else
X strcpy (pstr,PAGE_NEXT);
X }
X c = getpgch(pstr,&hdr);
X
X /*
X handle user input:
X CAUTION!! return cases must close Fpread.
X */
X step = FALSE;
X switch (c)
X {
X case PG_NEXT:
X if (Digest)
X {
X fclose (Fpread);
X unlink (Fname);
X }
X else
X vns_aclose (Fpread);
X sig_set(BRK_RFIN);
X return (0);
X case PG_FLIP:
X *pages = 1; /* fall through */
X case PG_QUIT:
X if (Digest)
X {
X fclose (Fpread);
X unlink (Fname);
X }
X else
X vns_aclose (Fpread);
X sig_set(BRK_RFIN);
X return (-1);
X case PG_REWIND:
X if (Headflag)
X {
X Rlines = 0;
X rewind (Fpread);
X }
X else
X {
X fseek (Fpread,Rew_pos,0);
X Rlines = Hlines;
X }
X Lookahead = NULL;
X lines = 2 - RECBIAS;
X break;
X case PG_SEARCH:
X searcher(buf);
X lines = 2 - RECBIAS;
X lines += do_out(buf,L_allow-lines);
X break;
X case PG_WIND:
X fseek (Fpread,0L,2);
X lines = 2 - RECBIAS;
X Lookahead = NULL;
X break;
X case PG_STEP:
X if (Lookahead == NULL)
X {
X if (Digest)
X {
X fclose (Fpread);
X unlink (Fname);
X }
X else
X vns_aclose (Fpread);
X sig_set(BRK_RFIN);
X return (0);
X }
X lines = L_allow - 1;
X step = TRUE; /* Temporarily disable paging */
X break;
X default:
X if (Lookahead == NULL)
X {
X if (Digest)
X {
X fclose (Fpread);
X unlink (Fname);
X }
X else
X vns_aclose (Fpread);
X sig_set(BRK_RFIN);
X return (0);
X }
X lines = 2 - RECBIAS;
X break;
X }
X }
X}
X
X/*
X getpgch prints prompt and gets command from user
X handles "mail", "save" and "followup" internally
X as well as flag resets.
X*/
Xstatic char
Xgetpgch(prompt,hdr)
Xchar *prompt;
XARTHEADER *hdr;
X{
X char c;
X int ic;
X int i;
X char mbuf[RECLEN];
X
X term_set (ONREVERSE);
X printf("%s\015",prompt);
X term_set (OFFREVERSE);
X while ((ic=getnoctl()) != EOF)
X {
X c = Cxitor[ic];
X if (Hookfunc != NULL && (i = (*Hookfunc)(c,1,1,mbuf)) >= 0)
X {
X if (i == 0)
X {
X term_set (ZAP,0,PPR_MAX);
X printf("%s\n",mbuf);
X }
X term_set (ONREVERSE);
X printf("%s\015",prompt);
X term_set (OFFREVERSE);
X continue;
X }
X switch (c)
X {
X case SETROT:
X term_set (ZAP,0,PPR_MAX);
X if (Rot == 0)
X {
X Rot = 13;
X printf ("%s\n",Roton_msg);
X }
X else
X {
X Rot = 0;
X printf ("%s\n",Rotoff_msg);
X }
X if (Lookahead != NULL && Rlines > Hlines)
X rot_line(Lookahead);
X break;
X case HEADTOG:
X term_set (ZAP,0,PPR_MAX);
X if (Headflag)
X {
X Headflag = FALSE;
X printf ("%s\n",Hdoff_msg);
X }
X else
X {
X Headflag = TRUE;
X printf ("%s\n",Hdon_msg);
X }
X break;
X case PG_HELP:
X term_set (ZAP,0,PPR_MAX);
X help_rd ();
X break;
X case PG_REPLY:
X mail (hdr);
X break;
X case PG_FOLLOW:
X followup (hdr);
X break;
X case SAVE:
X saver ();
X break;
X case PRINT:
X printr ();
X break;
X default:
X term_set (ZAP,0,PPR_MAX);
X return (c);
X }
X
X term_set (ONREVERSE);
X printf("%s\015",prompt);
X term_set (OFFREVERSE);
X }
X term_set (ZAP,0,PPR_MAX);
X return (c);
X}
X
X/*
X save article. Like its "session" counterpart, this loses storage
X if the user specifies a new file, but it should not be significant
X*/
Xstatic
Xsaver ()
X{
X char buf[RECLEN],msg[RECLEN],*str_store();
X
X user_str (buf,"save file ? ",0,Savefile);
X if (buf[0] != '\0' && buf[0] != '|')
X Savefile = str_store(buf);
X if (save_art(Fname,buf,msg) != 0)
X rerrmsg(msg);
X else
X printf("%s\n",msg);
X}
X
X/*
X invoke editor on new temp file, mail using reply line,
X possibly first allowing user to overide the reply (not INLETTER)
X*/
Xstatic
Xmail (hdr)
XARTHEADER *hdr;
X{
X char *new, fn[L_tmpnam], cmd [RECLEN+60], *rprompt ();
X int i;
X FILE *fp, *fopen();
X
X if (Massage != NULL)
X (*Massage)(hdr);
X
X if (hdr->mail_err != NULL)
X {
X rerrmsg(hdr->mail_err);
X return;
X }
X
X tmpnam (fn);
X if ((fp = fopen(fn,"w")) == NULL)
X {
X rerrmsg("can't open temp file, %s",fn);
X return;
X }
X
X for (i = 0; i < hdr->mail_num; ++i)
X fprintf(fp,"%s\n",(hdr->mail)[i]);
X fprintf(fp,"\n");
X
X fprintf(fp,"%s:\n",hdr->from);
X edcopy (fp);
X fclose (fp);
X
X tty_set (SAVEMODE);
X
X sprintf (cmd,"%s %s", Editor, fn);
X chdir (Orgdir);
X system (cmd);
X vns_gset (Page.h.name);
X
X new = rprompt ("still want to mail it ? ",cmd);
X if (new != NULL && (*new == 'y' || *new == 'Y'))
X {
X if (Mailfunc == NULL)
X {
X sprintf (cmd, hdr->mailcmd, fn);
X system (cmd);
X printf ("given to mailer\n");
X }
X else
X (*Mailfunc)(hdr,fn);
X }
X else
X printf ("not mailed\n");
X
X unlink (fn);
X
X tty_set (RESTORE);
X term_set (RESTART);
X}
X
X/*
X post a followup article, invoking editor for user after creating
X new temp file. remove after posting.
X*/
Xstatic
Xfollowup (hdr)
XARTHEADER *hdr;
X{
X char fn[L_tmpnam], *new, cmd [RECLEN], *rprompt();
X int i;
X FILE *f, *fopen();
X char *rindex();
X
X if (hdr->post_err != NULL)
X {
X rerrmsg(hdr->post_err);
X return;
X }
X
X tmpnam (fn);
X if ((f = fopen(fn,"w")) == NULL)
X {
X rerrmsg("can't open temp file, %s",fn);
X return;
X }
X
X for (i=0; i < hdr->post_num; ++i)
X fprintf(f,"%s\n",(hdr->post)[i]);
X fprintf(f,"\n");
X
X fprintf(f,"From article %s, by %s:\n", hdr->artid, hdr->from);
X
X edcopy (f);
X fclose (f);
X tty_set (SAVEMODE);
X sprintf (cmd,"%s %s", Editor, fn);
X chdir (Orgdir);
X system (cmd);
X vns_gset (Page.h.name);
X
X new = rprompt("still want to post it ? ",cmd);
X if (new != NULL && (*new == 'y' || *new == 'Y'))
X {
X if (Postfunc == NULL)
X {
X sprintf (cmd, hdr->postcmd, fn);
X system (cmd);
X printf ("given to posting program\n");
X }
X else
X (*Postfunc)(hdr,fn);
X save2_article (fn);
X }
X else
X printf ("not posted\n");
X unlink (fn);
X tty_set (RESTORE);
X term_set (RESTART);
X}
X
X/*
X get user buffer, return whitespace delimited token
X buffer is allowed to overwrite prompt string. This routine
X should only be used when the terminal is in cooked mode.
X In raw, use user_str().
X*/
Xstatic char *
Xrprompt(s,buf)
Xchar *s,*buf;
X{
X char *strtok();
X
X printf("%s",s);
X fgets (buf,RECLEN-1,stdin);
X return (strtok(buf," \t\n"));
X}
X
X/*
X edcopy copies article to file which user is editting for
X a reply or followup, so it may be referenced. It places
X ED_MARK in the left hand margin.
X*/
Xstatic
Xedcopy(fp)
XFILE *fp;
X{
X long current;
X char buf[RECLEN];
X
X /* save position, and seek to top of article */
X current = ftell(Fpread);
X fseek (Fpread,Rew_pos,0);
X
X /* if line already begins with ED_MARK, forget about the space */
X while (fgets(buf,RECLEN-1,Fpread) != NULL)
X {
X if (buf[0] == ED_MARK)
X fprintf(fp,"%c%s",ED_MARK,buf);
X else
X fprintf(fp,"%c %s",ED_MARK,buf);
X }
X
X /* restore position */
X fseek(Fpread,current,0);
X}
X
Xstatic
Xrot_line (s)
Xunsigned char *s;
X{
X for ( ; *s != '\0'; ++s)
X {
X if (isupper(*s))
X {
X *s += Rot;
X if (!isupper(*s))
X *s -= 26;
X continue;
X }
X if (islower(*s))
X {
X *s += Rot;
X if (!islower(*s))
X *s -= 26;
X }
X }
X}
X
X/*
X** output record. folds record to terminal width on word boundaries,
X** returning number of lines output. If limit is reached, remainder
X** of buffer waiting to be output is returned. Processes several
X** special characters:
X** form-feed - return "lim" lines so we stop on that line
X** tabs - counts "expanded" width
X** backspace - assumes they work, -1 width unless in first col.
X** bell - pass through with zero width
X** newline - end of record.
X** del - turns into '_'
X** other control - turned into '?'
X** (prevents "letter bombs" containing inappropriate control
X** sequences for the terminal).
X**
X** Sets Lookahead pointer to remainder of line or NULL.
X*/
Xstatic
Xdo_out(s,lim)
Xchar *s;
Xint lim;
X{
X int len,i;
X char cs,*word,*start;
X
X Lookahead = NULL;
X if (s == NULL)
X return(0);
X len = 0;
X start = word = s;
X
X /*
X ** NOTE: "normal" return is buried inside switch, at newline
X ** ending record
X */
X for (i=0; i < lim; ++i)
X {
X for ( ; len < C_allow; ++s)
X {
X switch (*s)
X {
X case '\n':
X *s = '\0'; /* fall through */
X case '\0':
X printf("%s\n",start);
X return(i+1);
X case '\t':
X len = ((len/PERTAB)+1)*PERTAB;
X word = s;
X break;
X case '\b':
X if (len > 0)
X --len;
X break;
X case '\014':
X *s = ' ';
X i = lim-1; /* fall through */
X case ' ':
X word = s+1;
X ++len;
X break;
X case '\177':
X *s = '_';
X ++len;
X break;
X default:
X if (iscntrl(*s))
X *s = '?';
X ++len; /* fall through */
X case '\07':
X break;
X }
X }
X cs = *s;
X *s = '\0';
X if ((len = strlen(word)) < BACKTRACK)
X {
X *s = cs;
X s = word;
X cs = *s;
X *s = '\0';
X }
X else
X len = 0;
X printf("%s\n",start);
X start = s;
X *s = cs;
X }
X Lookahead = start;
X return(lim);
X}
X
Xstatic
Xsave2_article(tempfname)
Xchar *tempfname;
X{
X FILE *in, *out;
X int c;
X time_t timenow, time();
X char *today, *ctime();
X
X if ((in = fopen(tempfname, "r")) == NULL)
X return;
X if ((out = fopen(Ccfile, "a")) == NULL)
X {
X fclose(in);
X return;
X }
X timenow = time((time_t)0);
X today = ctime(&timenow);
X fprintf(out,"From vn %s",today);
X while ((c=getc(in)) != EOF)
X putc(c, out);
X putc('\n', out);
X fclose(in);
X fclose(out);
X printf ("a copy has been saved in %s\n", Ccfile);
X}
X
X/*
X send article to printer
X*/
Xstatic
Xprintr ()
X{
X char cmd[RECLEN];
X char fn[L_tmpnam];
X long savepos;
X FILE *f;
X
X tmpnam (fn);
X if ((f = fopen(fn,"w")) == NULL)
X {
X rerrmsg("can't open temp file, %s",fn);
X return;
X }
X
X savepos = ftell(Fpread);
X rewind(Fpread);
X while (fgets(cmd,RECLEN-1,Fpread) != NULL)
X fputs(cmd,f);
X fclose(f);
X fseek(Fpread,savepos,0);
X
X tty_set (SAVEMODE);
X printf("Sent to printer\n");
X sprintf (cmd,"%s %s 2>/dev/null",Printer,fn);
X system (cmd);
X tty_set (RESTORE);
X unlink (fn);
X}
X
X/*
X search article for specified search pattern, returning the line on which
X it is found in buf, a null buffer otherwise. The input file will
X be positioned either after the line on which the pattern is
X found, or unaaltered if match fails.
X*/
Xstatic
Xsearcher (buf)
Xchar *buf;
X{
X static char searchstr[RECLEN] = "";
X char lasave[RECLEN];
X char *reg, *regcmp(), *regex();
X long current;
X int orlines;
X
X /* save position, then request search pattern */
X current = ftell(Fpread);
X orlines = Rlines;
X
X sprintf (lasave,SEARCHFORM,searchstr);
X user_str (searchstr,lasave,0,searchstr);
X
X /* Now compile the search string */
X if(( reg = regcmp(searchstr, (char *)0)) == NULL) {
X rerrmsg("Invalid search string \"%s\"", searchstr);
X *buf = '\0';
X return;
X }
X
X /* try lookahead buffer first */
X if (Lookahead != NULL && regex(reg,Lookahead) != NULL)
X {
X strcpy(buf,Lookahead);
X regfree(reg);
X return;
X }
X
X /* Lookahead can point into buf */
X if (Lookahead != NULL)
X strcpy(lasave,Lookahead);
X
X /* now start reading lines, rotating if necessary and do search */
X while (fgets(buf,RECLEN-1,Fpread) != NULL)
X {
X if (Rot != 0 && Rlines >= Hlines)
X rot_line(buf);
X ++Rlines;
X if( regex(reg, buf) != NULL ){ /* Got it */
X#ifdef MINIX
X/* inverse video mucks up this line somehow */
X rerrmsg("\tSkipping ...\n\n");
X#else
X rerrmsg("\n\tSkipping ....\n\n");
X#endif
X regfree(reg);
X return;
X }
X }
X
X /* no dice, so restore position */
X regfree(reg);
X rerrmsg("Cannot find string \"%s\" in remainder of article", searchstr);
X fseek(Fpread,current,0);
X Rlines = orlines;
X if (Lookahead != NULL)
X strcpy(buf,lasave);
X else
X *buf = '\0';
X}
X
X/*
X** print a reverse video error message while reading an article.
X*/
Xstatic
Xrerrmsg(s,a,b,c,d,e)
Xchar *s;
Xlong a,b,c,d,e;
X{
X term_set (ONREVERSE);
X printf("\n ");
X printf(s,a,b,c,d,e);
X printf(" \07\n");
X term_set (OFFREVERSE);
X}
END_OF_FILE
if test 16175 -ne `wc -c <'reader.c'`; then
echo shar: \"'reader.c'\" unpacked with wrong size!
fi
# end of 'reader.c'
fi
if test -f 'reader.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'reader.h'\"
else
echo shar: Extracting \"'reader.h'\" \(1537 characters\)
sed "s/^X//" >'reader.h' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** reader.h - article reading interface definitions
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#define PAGE_MID ":more (%2d%%):"
X#define PAGE_NEXT ":next article:"
X#define PAGE_END ":end:"
X#define PAGE_NO ":?:"
X#define PPR_MAX 18 /* maximum length of PAGE prompts */
X
X/*
X reading commands: no control chars, add help message to helppg
X SAVE, PRINT, HEADTOG and SETROT are also recognized
X*/
X#define HPG_HEAD "toggle header print flag"
X#define HPG_ROT "toggle rotation"
X#define HPG_SAVE "save article in a file"
X#define HPG_PRINT "print article"
X#define PG_NEXT 'n'
X#define HPG_NEXT "next article, if any"
X#define PG_QUIT 'q'
X#define HPG_QUIT "quit reading articles, if any more to read"
X#define PG_FLIP 'Q'
X#define HPG_FLIP "quit reading, and turn to next page of articles"
X#define PG_FOLLOW 'f'
X#define HPG_FOLLOW "post followup to article"
X#define PG_REPLY 'm'
X#define HPG_REPLY "send mail to author of article"
X#define PG_HELP '?'
X#define HPG_HELP "see this help menu"
X#define PG_REWIND 'r'
X#define HPG_REWIND "rewind article to beginning"
X#define PG_WIND 'e'
X#define HPG_WIND "seek to end of article (to next/end prompt)"
X#define PG_STEP '\n'
X#define HPG_STEP "next line"
X#define PG_SEARCH '/'
X#define HPG_SEARCH "search for regular expression in remainder of article"
X#define SEARCHFORM "search pattern (%s) ? "
X#define HPG_DEF "\n anything else to continue normal reading"
X#define HPG_EDEF "\n anything else to try reading next article, if any"
X
X#define ANFORM ":%s - %c for help:\n"
END_OF_FILE
if test 1537 -ne `wc -c <'reader.h'`; then
echo shar: \"'reader.h'\" unpacked with wrong size!
fi
# end of 'reader.h'
fi
if test -f 'reg.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'reg.c'\"
else
echo shar: Extracting \"'reg.c'\" \(1656 characters\)
sed "s/^X//" >'reg.c' <<'END_OF_FILE'
X/*
X** vn news reader.
X**
X** reg.c - implementation of regex / regcmp on top of UCB library
X**
X** see copyright disclaimer / history in vn.c source file
X*/
X
X#include <stdio.h>
X
X#define RGBLKSIZE 20
X
Xstruct _regtab
X{
X struct _regtab *link;
X char *regstr;
X};
X
Xtypedef struct _regtab REGTAB;
X
Xstatic REGTAB *Chain = NULL;
Xstatic REGTAB *Free = NULL;
Xstatic REGTAB *Compiled = NULL;
X
Xregfree(s)
Xchar *s;
X{
X REGTAB *ptr,*cmp,*old;
X
X cmp = (REGTAB *) s;
X old = NULL;
X
X for (ptr = Chain; ptr != NULL; ptr = (old = ptr)->link)
X {
X if (ptr == cmp)
X {
X if (old == NULL)
X Chain = Chain->link;
X else
X old->link = ptr->link;
X ptr->link = Free;
X Free = ptr;
X break;
X }
X }
X}
X
Xchar *regcmp(str)
Xchar *str;
X{
X int i;
X char *str_store();
X char *re_comp();
X
X if (re_comp(str) != NULL)
X {
X Compiled = NULL; /* make sure we're OK */
X return(NULL);
X }
X
X if (Free == NULL)
X {
X Free = (REGTAB *) malloc(RGBLKSIZE * sizeof(REGTAB));
X if (Free == NULL)
X printex ("regcmp: memory allocation failure");
X for (i = 0; i < RGBLKSIZE - 1; ++i)
X Free[i].link = Free + i + 1;
X Free[i].link = NULL;
X }
X
X Compiled = Free;
X Free = Free->link;
X
X Compiled->link = Chain;
X Chain = Compiled;
X Compiled->regstr = str_store(str);
X
X return ((char *) Compiled);
X}
X
Xchar *regex(reg,str)
Xchar *reg,*str;
X{
X REGTAB *cmp;
X
X cmp = (REGTAB *) reg;
X
X if (cmp == Compiled)
X {
X if (re_exec(str))
X return(str);
X return (NULL);
X }
X
X for (Compiled = Chain; Compiled != NULL; Compiled = Compiled->link)
X {
X if (Compiled == cmp)
X break;
X }
X
X if (Compiled == NULL)
X printex ("regex: bad pointer");
X
X re_comp(Compiled->regstr);
X
X if (re_exec(str))
X return(str);
X
X return(NULL);
X}
END_OF_FILE
if test 1656 -ne `wc -c <'reg.c'`; then
echo shar: \"'reg.c'\" unpacked with wrong size!
fi
# end of 'reg.c'
fi
if test -f 'regcompat.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'regcompat.c'\"
else
echo shar: Extracting \"'regcompat.c'\" \(1093 characters\)
sed "s/^X//" >'regcompat.c' <<'END_OF_FILE'
X/* regcompat.c */
X/* file: regcompat.c
X** author: Peter S. Housel 11/21/88
X** Compatibility routines for regular expressions. more.c uses the
X** re_comp() and re_exec() routines, while Minix only has regcomp() and
X** regexec() (from Henry Spencer's freely redistributable regexp package).
X** Note that the third argument to regexec() is a beginning-of-line flag
X** and was probably added by Andrew Tannenbaum. It will probably be ignored
X** if your copy of the regexp routines only expects two args.
X**/
X
X#include <regexp.h>
X/* following just for debugging #define NULL 0 */
X#include <stdio.h>
X
Xstatic regexp *re_exp = NULL; /* currently compiled regular expression */
Xstatic char *re_err = NULL; /* current regexp error */
X
Xchar *re_comp(str)
Xchar *str;
X{
X if(str == NULL)
X return NULL;
X
X if(re_exp != NULL)
X free(re_exp);
X
X if((re_exp = regcomp(str)) != NULL)
X return NULL;
X
X return re_err != NULL ? re_err : "string didn't compile";
X}
X
Xint re_exec(str)
Xchar *str;
X{
X if(re_exp == NULL)
X return -1;
X return regexec(re_exp, str, 1);
X}
X
Xregerror(str)
Xchar *str;
X{
X re_err = str;
X}
END_OF_FILE
if test 1093 -ne `wc -c <'regcompat.c'`; then
echo shar: \"'regcompat.c'\" unpacked with wrong size!
fi
# end of 'regcompat.c'
fi
echo shar: End of shell archive.
exit 0
--
"Zeta Microcomputer Software"
ACSnet: nick@nswitgould.cs.uts.oz nick@ultima.cs.uts.oz
UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick
Fidonet: Nick Andrew on 3:713/602 (Zeta)