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)