Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!lll-lcc!ptsfa!amdahl!rtech!bobm From: bobm@rtech.UUCP (Bob Mcqueer) Newsgroups: net.sources Subject: vn 12/86 (part 4 of 4) - remaining source files Message-ID: <572@rtech.UUCP> Date: Thu, 1-Jan-87 14:50:14 EST Article-I.D.: rtech.572 Posted: Thu Jan 1 14:50:14 1987 Date-Received: Fri, 2-Jan-87 20:45:29 EST Organization: Relational Technology, Alameda CA Lines: 2036 Bob McQueer {amdahl, sun, mtxinu, hoptoad, cpsc6a}!rtech!bobm cut here ----------------------------------- #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # digest.c # envir_set.c # groupdir.c # hash.c # pagefile.c # reg.c # sig_set.c # storage.c # strings.c # strtok.c # term_set.c # tmpnam.c # tty_set.c # userlist.c # vnglob.c # This archive created: Thu Jan 1 11:15:28 1987 export PATH; PATH=/bin:$PATH echo shar: extracting "'digest.c'" '(5027 characters)' if test -f 'digest.c' then echo shar: will not over-write existing file "'digest.c'" else cat << \SHAR_EOF > 'digest.c' /* ** vn news reader. ** ** digest.c - digest unpacking routines ** ** see copyright disclaimer / history in vn.c source file */ #include#include "config.h" #include "vn.h" #include "head.h" extern int Digest; extern int L_allow; extern int C_allow; extern PAGE Page; extern char *F_head, *T_head, *L_head, *D_head; digest_page (idx,skip) int idx; { char *ptr,name[24],*title,*index(); FILE *fp; int i,len; char subj[RECLEN],date[RECLEN],from[RECLEN],junk[RECLEN],*str_store(); long pos; Digest = Page.b[idx].art_id; sprintf (name,"%d", Digest); if ((fp = fopen(name,"r")) == NULL) return (-1); subj[0] = date[0] = from[0] = junk[0] = '\0'; skip_header (fp); /* skip over some articles if requested to */ for (i=skip; i > 0; --i) { if (dig_advance(fp,from,subj,date,junk,&pos) < 0) return (-1); } /* every new call to a digest Page "loses" a small amount of storage */ title = str_store(Page.b[idx].art_t); if ((ptr = index(title,'~')) != 0) *ptr = '\0'; title [C_allow - 20] = '\0'; for (i=0; i < L_allow && (len = dig_advance(fp,from,subj,date,junk,&pos)) >= 0; ++i) { Page.b[i].art_id = i+1+skip; Page.b[i].art_mark = ' '; subj [C_allow] = '\0'; from [C_allow] = '\0'; sprintf (name,"%d",len); form_title (date,subj,name,from,100); strcpy (Page.b[i].art_t,date); } fclose (fp); if (i == 0) return (-1); Page.h.name = title; Page.h.artnum = i; return (i); } /* returns name of file containing "article", NULL for failure */ char * digest_extract (s,art) char *s; int art; { char name[24]; FILE *fout,*fin; char subj[RECLEN],date[RECLEN],from[RECLEN],bufr[RECLEN]; char extra[RECLEN]; char *index(); long pos; int lines; sprintf (name,"%d", Digest); if ((fin = fopen(name,"r")) == NULL) return (NULL); for (skip_header (fin); art > 0; --art) if ((lines = dig_advance(fin,from,subj,date,extra,&pos)) < 0) { fclose (fin); return (NULL); } tmpnam(s); if ((fout = fopen(s,"w")) == NULL) { fclose (fin); unlink (s); return (NULL); } fseek(fin,0L,0); while (fgets(bufr,RECLEN-1,fin) != NULL && index(bufr,':') != NULL) { if (strncmp(bufr,F_head,FHDLEN) == 0) { fprintf (fout,"%s%s\n",F_head,from); continue; } if (strncmp(bufr,T_head,THDLEN) == 0) { fprintf (fout,"%s%s\n",T_head,subj); continue; } if (strncmp(bufr,D_head,DHDLEN) == 0) { fprintf (fout,"%s%s\n",D_head,date); continue; } /* defer line count header - it comes last */ if (strncmp(bufr,L_head,LHDLEN) == 0) continue; fprintf (fout,"%s",bufr); } /* toss in extra header lines, line count header, extra newline */ fprintf (fout,"%s%s%d\n\n",extra,L_head,lines); fseek (fin,pos,0); while (fgets(bufr,RECLEN-1,fin) != NULL && strncmp(bufr,"--------",8) != 0) fprintf(fout,"%s",bufr); fclose (fin); fclose (fout); return (s); } dig_list (s) char *s; { char *ptr,*out,*new,ns[L_tmpnam],tmp[RECLEN],*strtok(); int i; prinfo ("Extracting articles ....."); strcpy (tmp,s); out = s; for (ptr = strtok(tmp," "); ptr != NULL; ptr = strtok(NULL," ")) { i = atoi(ptr); if ((new = digest_extract(ns,i)) != NULL) { sprintf (out,"%s ",new); out += strlen(new) + 1; } } *out = '\0'; if (*s == '\0') strcpy (s,"NULLDIGEST"); } dig_ulist (s) char *s; { char *strtok(); for (s = strtok(s," "); s != NULL; s = strtok(NULL," ")) unlink (s); } /* returns # lines in article, -1 for failure scans past article, returns position of start. also returns "extra" header lines encountered, WITH newlines. */ static dig_advance (fp,from,subj,date,extra,pos) FILE *fp; char *from,*subj,*date,*extra; long *pos; { char buf[RECLEN]; char *ptr, *index(); int len,state,lcount; lcount = state = 0; *extra = '\0'; while (fgets(buf,RECLEN-1,fp) != NULL) { buf[(len = strlen(buf) - 1)] = '\0'; for (--len ; len >= 0 && buf[len] == ' ' || buf[len] == '\t'; --len) buf[len] = '\0'; ++len; switch(state) { case 0: /* skip blank lines before header */ if (len == 0) break; state = 1; /* fall through */ case 1: if (strncmp(buf,F_head,FHDLEN) == 0) { strcpy (from,buf+FHDLEN); break; } if (strncmp(buf,T_head,THDLEN) == 0) { strcpy (subj,buf+THDLEN); break; } if (strncmp(buf,D_head,DHDLEN) == 0) { strcpy (date,buf+DHDLEN); break; } /* put wierd header lines in extra */ if ((ptr = index(buf,':')) != NULL) { *ptr = '\0'; if (index(buf, ' ') == NULL) { *ptr = ':'; sprintf(extra,"%s\n",buf); extra += strlen(extra); break; } *ptr = ':'; } state = 2; /* remember the newline we lopped off */ *pos = ftell(fp)-strlen(buf)-1; /* fall through */ case 2: ++lcount; if (strncmp("--------",buf,8) == 0) { --lcount; return (lcount); } break; } } return (-1); } static skip_header (fp) FILE *fp; { char buf[RECLEN]; while (fgets(buf,RECLEN-1,fp) != NULL) if (strncmp("--------",buf,8) == 0) break; } SHAR_EOF fi # end of overwriting check echo shar: extracting "'envir_set.c'" '(2931 characters)' if test -f 'envir_set.c' then echo shar: will not over-write existing file "'envir_set.c'" else cat << \SHAR_EOF > 'envir_set.c' /* ** vn news reader. ** ** envir_set.c - routine to obtain pertinent environment variable settings ** and set up file / directory names ** ** see copyright disclaimer / history in vn.c source file */ #include #include #include #include "config.h" extern char *Editor,*Ps1,*Mailer,*Printer,*Poster; extern char *Onews, *Newsrc, *Orgdir, *Savedir, *Ccfile; /* path names */ extern char Cxitop[], Cxitor[], Cxrtoi[], Cxptoi[]; #ifdef SYSV extern char *getcwd(); #define getwd(a) getcwd(a,sizeof(a)) #define MAXPATHLEN 240 #else extern char *getwd(); #endif /* environment variable, original directory string setup. */ envir_set () { char dbuf [MAXPATHLEN], *rcname, *ccname, *keyxln; char *getenv(), *getcwd(), *str_store(); struct passwd *ptr, *getpwuid(); if ((Ps1 = getenv("PS1")) == NULL) Ps1 = DEF_PS1; if ((Editor = getenv("EDITOR")) == NULL) Editor=DEF_ED; if ((Mailer = getenv("MAILER")) == NULL) Mailer=DEF_MAIL; if ((Poster = getenv("POSTER")) == NULL) Poster=DEF_POST; if ((Printer = getenv("PRINTER")) == NULL) Printer=DEF_PRINT; if ((rcname = getenv("NEWSRC")) == NULL) rcname=DEF_NEWSRC; if ((ccname = getenv("CCFILE")) == NULL) ccname=DEF_CCFILE; if ((keyxln = getenv("VNKEY")) == NULL) keyxln=DEF_KEYXLN; Savedir = getenv("VNSAVE"); /* set original directory strings. create empty Newsrc if it doesn't exist */ ptr = getpwuid (getuid()); if ((Orgdir = getwd(dbuf)) == NULL) printex ("cannot stat pwd"); Orgdir = str_store (Orgdir); if (Savedir == NULL) Savedir = Orgdir; if (*rcname != '/') { sprintf (dbuf, "%s/%s",ptr->pw_dir,rcname); Newsrc = str_store (dbuf); } else Newsrc = str_store (rcname); if (*ccname != '/') { sprintf (dbuf, "%s/%s",ptr->pw_dir,ccname); Ccfile = str_store (dbuf); } else Ccfile = str_store (ccname); sprintf (dbuf, "%s/%s%s",ptr->pw_dir,".vn","XXXXXX"); Onews = str_store (mktemp(dbuf)); if (access (Newsrc,0) != 0) creat (Newsrc,0666); if (*keyxln != '/') { sprintf(dbuf, "%s/%s",ptr->pw_dir,keyxln); set_kxln(dbuf); } else set_kxln(keyxln); } static set_kxln(fname) char *fname; { FILE *fp; int i; char bufr[80]; char in,out,*ptr; char *index(), xln_str(); for (i=0; i < 128; ++i) Cxitop[i] = Cxitor[i] = Cxptoi[i] = Cxrtoi[i] = i; if ((fp = fopen(fname,"r")) != NULL) { while(fgets(bufr,79,fp) != NULL) { if (strncmp(bufr+1,"==",2) == 0) ptr = bufr+2; else ptr = index(bufr+1,'='); if (ptr == NULL) continue; *ptr = '\0'; ++ptr; in = xln_str(bufr+1); out = xln_str(ptr); switch(bufr[0]) { case 'r': case 'R': Cxrtoi[out] = in; Cxitor[in] = out; break; case 'p': case 'P': Cxptoi[out] = in; Cxitop[in] = out; default: break; } } fclose(fp); } } static char xln_str(s) char *s; { if (*s < '0' || *s > '9') return(*s & 0x7f); return((char)(atoi(s) & 0x7f)); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'groupdir.c'" '(686 characters)' if test -f 'groupdir.c' then echo shar: will not over-write existing file "'groupdir.c'" else cat << \SHAR_EOF > 'groupdir.c' /* ** vn news reader. ** ** groupdir.c - translation between newsgroup name and directory ** ** see copyright disclaimer / history in vn.c source file */ #include #include "config.h" #include "vn.h" extern PAGE Page; /* g_dir converts newsgroup name to directory string */ g_dir(s,t) char *s,*t; { char *ptr, *index(); sprintf (t,"%s/%s",SPOOLDIR,s); for (ptr=t+strlen(SPOOLDIR)+1; (ptr = index(ptr,'.')) != NULL; *ptr = '/') ; } /* change directory to group */ cd_group () { char dbuf [RECLEN]; g_dir ((Page.h.group)->nd_name,dbuf); if (chdir(dbuf) < 0) { Page.h.artnum = 1; Page.b[0].art_id = 0; strcpy (Page.b[0].art_t, "CANNOT FIND NEWSGROUP"); } } SHAR_EOF fi # end of overwriting check echo shar: extracting "'hash.c'" '(1842 characters)' if test -f 'hash.c' then echo shar: will not over-write existing file "'hash.c'" else cat << \SHAR_EOF > 'hash.c' /* ** vn news reader. ** ** hash.c - hash table routines ** ** see copyright disclaimer / history in vn.c source file */ #include #include "config.h" #include "tune.h" #include "vn.h" /* ** hash table manipulation routines: ** also sets Ncount, allocates Newsorsder array, and sets Newsorder ** initially to order newsgroups were entered in (active file order) */ extern int Ncount; extern NODE **Newsorder; static NODE *Tab [HASHSIZE]; /* hash Table */ hashinit () { int i; for (i=0; i < HASHSIZE; ++i) Tab[i] = NULL; Ncount = 0; } /* enter new node (name s, articles n, low l) in hash Table, initial flags = 0. As nodes are entered, pnum item is temporarily used to indiacte entry order for initial construction of Newsorder array via entry_order(); */ NODE *hashenter(s,n,l) char *s; int n; int l; { char *str_store(); NODE *ptr,*node_store(); int i; i=hash(s); ptr = node_store(); ptr->next = Tab[i]; Tab[i] = ptr; if (l > n) l = n; ptr->pnum = Ncount; ++Ncount; ptr->rdnum = l; ptr->state = 0; ptr->art = n; ptr->nd_name = str_store(s); return (ptr); } NODE *hashfind(s) char *s; { NODE *ptr; for (ptr = Tab[hash(s)]; ptr != NULL && strcmp(ptr->nd_name,s) != 0; ptr = ptr->next) ; return (ptr); } /* ** entry order is called after all hash_enter's have been done, PRIOR ** to the use of pnum item for anything else. It constructs the initial ** Newsorder array. */ entry_order() { int i; NODE *ptr; if ((Newsorder = (NODE **) malloc(Ncount*sizeof(NODE *))) == NULL) printex("Cannot allocate memory for Newsorder array"); for (i=0; i < HASHSIZE; ++i) { for (ptr = Tab[i]; ptr != NULL; ptr = ptr->next) Newsorder[ptr->pnum] = ptr; } } static hash (s) char *s; { int rem; for (rem=0; *s != '\0'; ++s) rem = (rem*128 + (*s&0x7f)) % HASHSIZE; return (rem); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'pagefile.c'" '(5053 characters)' if test -f 'pagefile.c' then echo shar: will not over-write existing file "'pagefile.c'" else cat << \SHAR_EOF > 'pagefile.c' /* ** vn news reader. ** ** pagefile.c - routines to deal with page display tempfile ** ** see copyright disclaimer / history in vn.c source file */ #include #ifdef SYSV #include #include #endif #include #include "vn.h" #include "head.h" extern int Ncount,Lrec,L_allow,Cur_page,C_allow; extern int Nwopt, Nnwopt, Ntopt, Nntopt; extern char *Wopt[], *Topt[], *Negtopt[], *Negwopt[]; extern NODE **Newsorder; extern PAGE Page; extern int Digest; extern char *Aformat; extern char *T_head, *F_head, *L_head; static int Tdes; /* temp file descriptor */ static int Pgsize; /* block size for seeking file */ /* routines which deal with the temp file containing display pages. Note the "invisible" file feature - tempfile is unlinked from /usr/tmp immediately. when Tdes is closed by UNIX the disk space will be given back. */ temp_open () { char tmpart [L_tmpnam]; Lrec = -1; tmpnam (tmpart); Pgsize = sizeof (HEAD) + L_allow * sizeof(BODY); if ((Tdes = open(tmpart,O_RDWR|O_CREAT)) < 0) printex ("can't open %s",tmpart); unlink (tmpart); } /* create page records for newsgroup s all articles between low and hi are to be included. */ outgroup (s,low,hi) char *s; int low,hi; { int i,aid; char title[RECLEN],gd[RECLEN]; g_dir(s,gd); if (chdir(gd) < 0) { grp_indic(s,0); return; } grp_indic(s,1); aid = 0; for (i=low+1; i <= hi; ++i) { if (digname (i,title) >= 0) { Page.b[aid].art_id = i; Page.b[aid].art_mark = ' '; strcpy (Page.b[aid].art_t, title); if ((++aid) >= L_allow) { /* start next page */ Page.h.artnum = L_allow; do_write (); ++Lrec; aid = 0; } } } /* last page (partial) */ if (aid != 0) { Page.h.artnum = aid; do_write (); ++Lrec; } } /* set current page to n. use Pgsize and lseek to find it in temp file (descriptor Tdes). */ find_page (n) int n; { long off,lseek(); int i,last; Cur_page = n; off = Pgsize; off *= (long) n; lseek (Tdes, off, 0); if (read(Tdes, (char *) &(Page.h), sizeof(HEAD)) < sizeof(HEAD)) printex("bad temp file read"); i = Pgsize - sizeof(HEAD); if (read(Tdes, (char *) Page.b, i) < i) printex("bad temp file read"); last = -1; for (i=0; i < Ncount; ++i) { if ((Newsorder[i])->pages > 0) { if ((Newsorder[i])->pnum > n) break; last = i; } } if (last < 0) printex ("can't find page %d",n); Page.h.group = Newsorder[last]; Page.h.name = (Page.h.group)->nd_name; cd_group (); } write_page () { long off,lseek(); if (!Digest) { off = Pgsize; off *= (long) Cur_page; lseek (Tdes, off, 0); do_write(); } } static do_write() { int num; if (write(Tdes, (char *) &(Page.h), sizeof(HEAD)) < sizeof(HEAD)) printex ("Bad temp file write"); num = L_allow * sizeof(BODY); if (write(Tdes, (char *) Page.b, num) < num) printex ("Bad temp file write"); } /* find article title: n - articles id t - returned title - must have storage for RECLEN, assumed to be > 3 * max title length also. */ static digname (n, t) int n; char *t; { int i,j; FILE *fp,*fopen(); char ff [MAX_C+1],fn [MAX_C+1],fl [MAX_C+1],*index(); /* open article */ sprintf (t,"%d", n); if ((fp = fopen(t,"r")) == NULL) return (-1); /* get subject, from and lines by reading article */ ff[0] = fn[0] = fl[0] = '?'; ff[1] = fn[1] = fl[1] = '\0'; ff[C_allow] = fn[C_allow] = fl[C_allow] = '\0'; for (i = 0; i < HDR_LINES && fgets(t,RECLEN-1,fp) != NULL; ++i) { if (index(CHFIRST,t[0]) == NULL) continue; t[strlen(t) - 1] = '\0'; if (strncmp(T_head,t,THDLEN) == 0) { for (j=0; j < Nntopt; ++j) { if (regex(Negtopt[j],t+THDLEN) != NULL) { fclose(fp); return(-1); } } if (Ntopt > 0) { for (j=0; j < Ntopt; ++j) { if (regex(Topt[j],t+THDLEN) != NULL) break; } if (j >= Ntopt) { fclose(fp); return(-1); } } strncpy(fn,t+THDLEN,C_allow); continue; } if (strncmp(F_head,t,FHDLEN) == 0) { for (j=0; j < Nnwopt; ++j) { if (regex(Negwopt[j],t+FHDLEN) != NULL) { fclose(fp); return(-1); } } if (Nwopt > 0) { for (j=0; j < Nwopt; ++j) { if (regex(Wopt[j],t+FHDLEN) != NULL) break; } if (j >= Nwopt) { fclose(fp); return(-1); } } strncpy(ff,t+FHDLEN,C_allow); continue; } if (strncmp(L_head,t,LHDLEN) == 0) { strncpy(fl,t+LHDLEN,C_allow); break; } } fclose (fp); /* reject empty or 1 line files */ if (i < 2) return (-1); form_title (t,fn,fl,ff,n); return (0); } form_title (t,fn,fl,ff,n) char *t,*fn,*fl,*ff; int n; { char *ptr,*index(); int i; if ((ptr = index(ff,'(')) != NULL && strlen(ptr) > 3) ff = ptr; sprintf (t,TFORMAT,fn,fl,ff); sprintf(ff,Aformat,' ',' ',n); i = C_allow - strlen(ff) + 1; /* remember newline in Aformat */ t[i] = '\0'; ctl_xlt(t); return (0); } /* replace control characters in titles */ static ctl_xlt(s) char *s; { while (*s != '\0') { if (*s < ' ') *s += 'A' - 1; ++s; } } SHAR_EOF fi # end of overwriting check echo shar: extracting "'reg.c'" '(1656 characters)' if test -f 'reg.c' then echo shar: will not over-write existing file "'reg.c'" else cat << \SHAR_EOF > 'reg.c' /* ** vn news reader. ** ** reg.c - implementation of regex / regcmp on top of UCB library ** ** see copyright disclaimer / history in vn.c source file */ #include #define RGBLKSIZE 20 struct _regtab { struct _regtab *link; char *regstr; }; typedef struct _regtab REGTAB; static REGTAB *Chain = NULL; static REGTAB *Free = NULL; static REGTAB *Compiled = NULL; regfree(s) char *s; { REGTAB *ptr,*cmp,*old; cmp = (REGTAB *) s; old = NULL; for (ptr = Chain; ptr != NULL; ptr = (old = ptr)->link) { if (ptr == cmp) { if (old == NULL) Chain = Chain->link; else old->link = ptr->link; ptr->link = Free; Free = ptr; break; } } } char *regcmp(str) char *str; { int i; char *str_store(); char *re_comp(); if (re_comp(str) != NULL) { Compiled = NULL; /* make sure we're OK */ return(NULL); } if (Free == NULL) { Free = (REGTAB *) malloc(RGBLKSIZE * sizeof(REGTAB)); if (Free == NULL) printex ("regcmp: memory allocation failure"); for (i = 0; i < RGBLKSIZE - 1; ++i) Free[i].link = Free + i + 1; Free[i].link = NULL; } Compiled = Free; Free = Free->link; Compiled->link = Chain; Chain = Compiled; Compiled->regstr = str_store(str); return ((char *) Compiled); } char *regex(reg,str) char *reg,*str; { REGTAB *cmp; cmp = (REGTAB *) reg; if (cmp == Compiled) { if (re_exec(str)) return(str); return (NULL); } for (Compiled = Chain; Compiled != NULL; Compiled = Compiled->link) { if (Compiled == cmp) break; } if (Compiled == NULL) printex ("regex: bad pointer"); re_comp(Compiled->regstr); if (re_exec(str)) return(str); return(NULL); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'sig_set.c'" '(4501 characters)' if test -f 'sig_set.c' then echo shar: will not over-write existing file "'sig_set.c'" else cat << \SHAR_EOF > 'sig_set.c' /* ** vn news reader. ** ** sig_set.c - signal handler ** ** see copyright disclaimer / history in vn.c source file */ #include #include #include #include #include "tty.h" #include "vn.h" #include "config.h" extern int L_allow; extern char *Version; static int Sigflag=BRK_INIT; /* phase of interaction */ static FILE **Fpseek; /* article reading file pointer pointer */ static int Foreground; static jmp_buf Jumploc; /* for BRK_SESS phase */ static char *Cur_scn; /* current group name being scanned */ /* interrupt handler - unusual termination (longjmp and printex aborts) if not abort, remember to reset signal trap CAUTION - the passing of a jump buffer is a little dicey - assumes type jump_buf is an array. sigcatch and sig_set control a lot of i/o on stderr also, since it is so intimately related to signal interaction. Note that the SIGTSTP action causes a "stopped on tty output" if raw terminal mode is restored by tty_set(RESTORE). We don't get it if we were already cooked since tty_set avoids calling ioctl if it doesn't have to. */ static sigcatch (sig) int sig; { char buf [MAX_C+1]; int pgrp; /* disable signal while processing it */ signal (sig,SIG_IGN); switch (sig) { case SIGINT: case SIGQUIT: break; #ifdef JOBCONTROL case SIGTSTP: /* ignore SIGTTOU so we don't get stopped if [kc]sh grabs the tty */ signal(SIGTTOU, SIG_IGN); tty_set (SAVEMODE); term_set (MOVE,0,L_allow+RECBIAS-1); printf ("\n"); Foreground = 0; fflush (stdout); fflush (stderr); signal(SIGTTOU, SIG_DFL); /* Send the TSTP signal to suspend our process group */ signal(SIGTSTP, SIG_DFL); sigsetmask(0); kill (0, SIGTSTP); /* WE ARE NOW STOPPED */ /* WELCOME BACK! if terminals process group is ours, we are foregrounded again and can turn newsgroup name printing back on */ tty_set (RESTORE); switch (Sigflag) { case BRK_SESS: signal (SIGTSTP,sigcatch); longjmp (Jumploc,1); case BRK_IN: ioctl (1,TIOCGPGRP,&pgrp); if (pgrp == getpgrp(0)) { Foreground = 1; if (Cur_scn != NULL) fgprintf (" %s\n",Cur_scn); } break; default: break; } signal (SIGTSTP,sigcatch); return; #endif default: printex (BRK_MSG,sig); } /* QUIT and INTERRUPT signals */ switch (Sigflag) { case BRK_SESS: /* if in session, ask if really a quit, do longjump if not */ term_set (ERASE); tty_set (RAWMODE); user_str (buf, BRK_PR, 1); if (buf[0] == 'y') printex (BRK_MSG,sig); signal (sig,sigcatch); longjmp (Jumploc,1); case BRK_READ: /* if reading seek file to end to abort page printing */ printf ("\n"); if (*Fpseek == NULL || fseek(*Fpseek,0L,2) < 0) putchar ('\07'); break; default: printex (BRK_MSG,sig); } signal (sig,sigcatch); } /* sig_set controls what will be done with a signal when picked up by sigcatch. grp_indic / fgprintf is included here to keep knowledge of TSTP state localized. */ /* VARARGS */ sig_set (flag,dat) int flag, *dat; { int i, *xfer, pgrp; if (Sigflag == BRK_INIT) { Cur_scn = NULL; signal (SIGINT,sigcatch); signal (SIGQUIT,sigcatch); signal (SIGHUP,sigcatch); signal (SIGTERM,sigcatch); #ifdef JOBCONTROL signal (SIGTSTP,sigcatch); ioctl (1,TIOCGPGRP,&pgrp); if (pgrp == getpgrp(0)) { Foreground = 1; fgprintf ("Visual News, Release %s, reading:\n",Version); } else Foreground = 0; #else Foreground = NOJOB_FG; #endif } switch (flag) { case BRK_IN: case BRK_OUT: Sigflag = flag; break; case BRK_READ: if (Sigflag != BRK_SESS) printex ("unexpected read state, sig_set\n"); Fpseek = (FILE **) dat; Sigflag = BRK_READ; break; case BRK_SESS: xfer = (int *) Jumploc; for (i=0; i < sizeof(Jumploc) / sizeof(int); ++i) xfer[i] = dat[i]; Sigflag = BRK_SESS; break; case BRK_RFIN: if (Sigflag != BRK_READ) printex ("unexpected finish state, sig_set\n"); Sigflag = BRK_SESS; break; default: printex ("bad state %d, sig_set\n",flag); } } grp_indic (s,ok) char *s; int ok; { NODE *ptr,*hashfind(); /* we go to hash table because s might be a temporary buffer */ if ((ptr = hashfind(s)) != NULL) { Cur_scn = ptr->nd_name; if (Foreground) { if (ok) fgprintf(" %s\n",Cur_scn); else fgprintf(" %s - Can't access spool directory\n",Cur_scn); } } } fgprintf (fs,a,b,c,d,e) char *fs; int a,b,c,d,e; { if (Foreground) fprintf (stderr,fs,a,b,c,d,e); fflush (stderr); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'storage.c'" '(1309 characters)' if test -f 'storage.c' then echo shar: will not over-write existing file "'storage.c'" else cat << \SHAR_EOF > 'storage.c' /* ** vn news reader. ** ** storage.c - storage allocation routines ** ** see copyright disclaimer / history in vn.c source file */ #include #include "vn.h" extern char *malloc(); extern int L_allow; extern PAGE Page; /* Storage allocaters. One more call to malloc in entry_order routine. */ char *str_store (s) char *s; { static unsigned av_len = 0; /* current storage available */ static char *avail; int len; if (s == NULL) s = ""; if ((len = strlen(s)+1) > av_len) { if (len > STRBLKSIZE) av_len = len; else av_len = STRBLKSIZE; if ((avail = malloc(av_len)) == NULL) printex ("can't allocate memory for string storage"); } strcpy (avail,s); s = avail; avail += len; av_len -= len; return (s); } /* ** called after number of terminal lines (L_allow) is known, to set ** up storage for Page. */ page_alloc () { char *body; if ((body = malloc(L_allow*sizeof(BODY))) == NULL) printex ("can't allocate memory for display storage"); Page.b = (BODY *) body; } NODE *node_store() { static int nd_avail = 0; static NODE *nd; NODE *ret; if (nd_avail <= 0) { if ((nd = (NODE *) malloc(sizeof(NODE)*NDBLKSIZE)) == NULL) printex ("can't allocate memory for newsgroup table"); nd_avail = NDBLKSIZE; } --nd_avail; ret = nd; ++nd; return(ret); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'strings.c'" '(720 characters)' if test -f 'strings.c' then echo shar: will not over-write existing file "'strings.c'" else cat << \SHAR_EOF > 'strings.c' /* ** vn news reader. ** ** strings.c - character strings ** ** see copyright disclaimer / history in vn.c source file */ #include "vn.h" #include "head.h" char *Version = "12/86"; char *No_msg = "No articles"; char *Hdon_msg = "Headers being printed"; char *Hdoff_msg = "Headers being suppressed"; char *Roton_msg = "ROT 13"; char *Rotoff_msg = "NO ROT"; char *Aformat = AFORMAT; char *Contstr = " ******** any key to continue ********"; char *R_head = RHEAD; char *M_head = MHEAD; char *P_head = PHEAD; char *D_head = DHEAD; char *F_head = FHEAD; char *FT_head = FTHEAD; char *T_head = THEAD; char *L_head = LHEAD; char *N_head = NHEAD; char *RT_head = RTHEAD; char *TO_head = TOHEAD; char *DIS_head = DISHEAD; SHAR_EOF fi # end of overwriting check echo shar: extracting "'strtok.c'" '(1082 characters)' if test -f 'strtok.c' then echo shar: will not over-write existing file "'strtok.c'" else cat << \SHAR_EOF > 'strtok.c' /* ** vn news reader. ** ** strtok.c - strtok() and strpbrk() string routines using UCB index(). ** ** see copyright disclaimer / history in vn.c source file */ #include char *strpbrk (s,del) char *s, *del; { char *ptr,*index(); if (s == NULL) return (NULL); for (; *del != '\0'; ++del) if ((ptr = index(s,*del)) != NULL) return (ptr); return (NULL); } char *strtok(str,delim) char *str, *delim; { char *tokstart, *tokend, *first_ch (), *last_ch(); static char *save=NULL; if (str != NULL) save = str; if (save == NULL) return (NULL); tokstart = first_ch (save, delim); tokend = last_ch (tokstart, delim); save = first_ch (tokend, delim); *tokend = '\0'; if (*tokstart == '\0') return (NULL); return (tokstart); } static char *first_ch (str,delim) char *str,*delim; { char *index (); char *f; for (f = str; *f != '\0' && index(delim,*f) != NULL; ++f) ; return (f); } static char *last_ch (str,delim) char *str,*delim; { char *index (); char *f; for (f = str; *f != '\0' && index(delim,*f) == NULL; ++f) ; return (f); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'term_set.c'" '(4914 characters)' if test -f 'term_set.c' then echo shar: will not over-write existing file "'term_set.c'" else cat << \SHAR_EOF > 'term_set.c' /* ** vn news reader. ** ** term_set.c - terminal control, hides termcap interface ** ** see copyright disclaimer / history in vn.c source file */ #include #include "tty.h" #include "vn.h" extern int L_allow, C_allow; extern char *Ku, *Kd, *Kl, *Kr; static outc (c) char c; { putchar (c); } /* term_set controls terminal through termcap START sets global parameters related to terminal also, as well as allocating display buffer which depends on terminal lines, and allocating escape strings. RESTART simply re-issues the initialization - used following system calls that could have goofed up the terminal state. */ /* ** Escape strings. */ static char *Cm,*Cl,*So,*Se,*Te,*Bc,*Ce,*Ti,*Ks,*Ke; #ifdef USEVS static char *Vs,*Ve; #endif static int Backspace; /* backspace works */ static int Overstrike; /* terminal overstrikes */ static t_setup() { int i; char *tgetstr(), *getenv(), *str_store(); char *c, tc_buf[2048],optstr[2048]; c = optstr; if (tgetent(tc_buf,getenv("TERM")) != 1) printex ("%s - unknown terminal",getenv("TERM")); /* get needed capabilities */ Cm = str_store(tgetstr("cm",&c)); Cl = str_store(tgetstr("cl",&c)); So = str_store(tgetstr("so",&c)); Se = str_store(tgetstr("se",&c)); Te = str_store(tgetstr("te",&c)); Ti = str_store(tgetstr("ti",&c)); Bc = str_store(tgetstr("bc",&c)); Ce = str_store(tgetstr("ce",&c)); Kd = str_store(tgetstr("kd",&c)); Ke = str_store(tgetstr("ke",&c)); Kl = str_store(tgetstr("kl",&c)); Kr = str_store(tgetstr("kr",&c)); Ks = str_store(tgetstr("ks",&c)); Ku = str_store(tgetstr("ku",&c)); #ifdef USEVS Vs = str_store(tgetstr("vs",&c)); Ve = str_store(tgetstr("ve",&c)); #endif Backspace = tgetflag("bs"); Overstrike = tgetflag("os"); if ( *Cm == '\0' || *Cl == '\0') { printex ("cursor control and erase capability needed"); } /* ** Checks for arrow keys which don't issue something beginning ** with . This is more paranoid than we need to be, strictly ** speaking - we could get away with any string which didn't ** conflict with controls used for commands. However, that would ** be a maintenance headache - we will simply reserve as the ** only char not to be used for commands, and punt on terminals ** which don't send reasonable arrow keys. It would be confusing ** to have keys work partially, also. I know of no terminal with ** one arrow key beginning with an escape, and another beginning ** with something else, but let's be safe. This also insists on ** definitions for all 4 arrows, which seems reasonable. */ if ((*Ku != '\0' && *Ku != '\033') || *Kl != *Ku || *Kr != *Ku || *Kd != *Ku) { fgprintf("WARNING: arrow keys will not work for this terminal"); Ku = Kd = Kl = Kr = Kd = Ke = ""; } if (Overstrike) fgprintf ("WARNING: terminal overstrikes - can't update display without erase\n"); i = RECBIAS+1 < HHLINES+2 ? HHLINES+2 : RECBIAS+1; if ((L_allow = tgetnum("li")) < i) { if (L_allow < 0) printex ("can't determine number of lines on terminal"); printex ("too few lines for display - %d needed", i); } /* ** C_allow set so as to not use extreme right column. ** Avoids "bad wraparound" problems - we're deciding it's best ** to ALWAYS assume no automargin, and take care of it ourselves */ if((C_allow = tgetnum("co")) > MAX_C) C_allow = MAX_C; else --C_allow; if (C_allow < MIN_C) { if (C_allow < 0) printex("can't determine number of columns on terminal."); printex ("too few columns for display - %d needed",MIN_C); } L_allow -= RECBIAS; page_alloc(); tputs(Ti,1,outc); tputs(Ks,1,outc); #ifdef USEVS tputs(Vs,1,outc); #endif } /* VARARGS */ term_set(cmd,x,y) int cmd,x,y; { char *tgoto(); int i; switch (cmd) { case MOVE: tputs (tgoto(Cm,x,y),1,outc); break; case ERASE: tputs(Cl,1,outc); break; case ONREVERSE: tputs(So,1,outc); break; case OFFREVERSE: tputs(Se,1,outc); break; case START: t_setup(); break; case RESTART: tputs(Ti,1,outc); tputs(Ks,1,outc); #ifdef USEVS tputs(Vs,1,outc); #endif break; case STOP: term_set (MOVE,0,L_allow+RECBIAS-1); printf ("\n"); tputs(Ke,1,outc); tputs(Te,1,outc); #ifdef USEVS tputs(Ve,1,outc); #endif break; case RUBSEQ: if (Overstrike) { /* space overprint is futile */ if (Backspace) putchar('\010'); else tputs(Bc,1,outc); break; } if (Backspace) printf("%c %c",'\010','\010'); else { tputs(Bc,1,outc); putchar(' '); tputs(Bc,1,outc); } break; case ZAP: if (Ce != NULL && *Ce != '\0') tputs(Ce,1,outc); else { if (Overstrike) break; /* punt */ for (i=x; i < y; ++i) putchar(' '); if (Backspace) { for (i=x; i < y; ++i) putchar('\010'); } else { for (i=x; i < y; ++i) tputs(Bc,1,outc); } } break; default: printex ("term_set unknown code (%d)",cmd); break; } return (0); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'tmpnam.c'" '(420 characters)' if test -f 'tmpnam.c' then echo shar: will not over-write existing file "'tmpnam.c'" else cat << \SHAR_EOF > 'tmpnam.c' /* ** vn news reader. ** ** tmpnam.c - tmpnam() replacement for UCB, also uses non-generic name. ** ** see copyright disclaimer / history in vn.c source file */ #include #include "config.h" char *tmpnam (buf) char *buf; { static char *ptr = VNTEMPNAME; /* depends on string initialized above */ sprintf (ptr+TMP_XOFFSET,"XXXXXX"); mktemp (ptr); if (buf != NULL) strcpy (buf,ptr); return (ptr); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'tty_set.c'" '(2552 characters)' if test -f 'tty_set.c' then echo shar: will not over-write existing file "'tty_set.c'" else cat << \SHAR_EOF > 'tty_set.c' /* ** vn news reader. ** ** tty_set.c - interface to ioctl (system tty interface) ** ** see copyright disclaimer / history in vn.c source file */ #ifdef SYSV #include #else #include #endif #include "tty.h" extern char Erasekey,Killkey; #ifdef SYSV static struct termio C_tp, O_tp; #else static struct sgttyb C_tp; static unsigned short O_lflag; #endif static unsigned S_flag=0; static int R_ignore=0; /* up/down counter of reset calls to ignore */ #define IO_GOT 1 /* have polled for original terminal mode */ #define IO_RAW 2 /* in RAW (CBREAK actually) mode */ /* tty_set handles ioctl calls. SAVEMODE, RESTORE are used around system calls and interrupts to assure cooked mode, and restore raw if raw on SAVEMODE. The pair results in no calls to ioctl if we are cooked already when SAVEMODE is called, and may be nested, provided we desire no "restore" of cooked mode after restoring raw. When we get the original terminal mode, we also save erase and kill. sig_set makes an ioctl call to get process group leader. Otherwise ioctl calls should come through here. */ tty_set(cmd) int cmd; { int rc; unsigned mask; switch (cmd) { case BACKSTOP: #ifdef JOBCONTROL if ((rc = ioctl(1,TIOCLGET,&mask)) != 0) break; mask |= LTOSTOP; rc = ioctl(1,TIOCLSET,&mask); #else rc = 0; #endif break; case RAWMODE: if ((S_flag & IO_RAW) != 0) { rc = 0; break; } if ((S_flag & IO_GOT) == 0) { /* Save original modes, get erase / kill */ #ifdef SYSV rc = ioctl(0,TCGETA,&C_tp); O_tp = C_tp; Erasekey = C_tp.c_cc[VERASE]; Killkey = C_tp.c_cc[VKILL]; #else rc = ioctl(0,TIOCGETP,&C_tp); O_lflag = C_tp.sg_flags; Erasekey = C_tp.sg_erase; Killkey = C_tp.sg_kill; #endif } #ifdef SYSV C_tp.c_lflag &= ~(ECHO | ICANON); C_tp.c_cc[VMIN] = 1; rc = ioctl(0,TCSETAW,&C_tp); #else C_tp.sg_flags |= CBREAK; C_tp.sg_flags &= ~ECHO; rc = ioctl(0,TIOCSETP,&C_tp); #endif S_flag = IO_GOT|IO_RAW; break; case COOKED: if ((S_flag & IO_RAW) != 0) { #ifdef SYSV C_tp = O_tp; rc = ioctl(0,TCSETAW,&C_tp); #else C_tp.sg_flags = O_lflag; rc = ioctl(0,TIOCSETP,&C_tp); #endif S_flag &= ~IO_RAW; } else rc = 0; break; case SAVEMODE: if ((S_flag & IO_RAW) != 0) { tty_set(COOKED); R_ignore = 0; } else ++R_ignore; rc = 0; break; case RESTORE: if (R_ignore <= 0) { tty_set(RAWMODE); } else --R_ignore; rc = 0; break; default: rc = -1; } if (rc < 0) printex ("ioctl failure, tty_set: %d",cmd); } SHAR_EOF fi # end of overwriting check echo shar: extracting "'userlist.c'" '(1923 characters)' if test -f 'userlist.c' then echo shar: will not over-write existing file "'userlist.c'" else cat << \SHAR_EOF > 'userlist.c' /* ** vn news reader. ** ** userlist.c - generate user's list of articles ** ** see copyright disclaimer / history in vn.c source file */ #include #include "vn.h" extern PAGE Page; /* generate user list of articles - either article numbers are input directly (numeric list), or input is a search string - invoke regular expression library and examine titles search string "*" reserved for marked articles. Strings may be prefixed with '!' for negation. */ userlist (list) char *list; { int i,j,anum[RECLEN/2],acount; char neg, *s, sbuf[MAX_C+1], *reg, *regex(), *regcmp(), *index(), *strtok(); user_str (sbuf,"Articles or title search string : ",1); if (sbuf[0] == '!') { neg = '!'; s = sbuf+1; } else { neg = '\0'; s = sbuf; } for (i=0; s[i] != '\0'; ++i) { if (index(LIST_SEP,s[i]) == NULL) { if (s[i] < '0' || s[i] > '9') break; } } acount = 0; if (s[i] == '\0') { for (s = strtok(s,LIST_SEP); s != NULL; s = strtok(NULL,LIST_SEP)) { anum[acount] = atoi(s); ++acount; } } else { if (s[0] == ART_MARK) { for (i=0; i < Page.h.artnum; ++i) { if (Page.b[i].art_mark == ART_MARK) { anum[acount] = Page.b[i].art_id; ++acount; } } } else { reg = regcmp(s,(char *) 0); if (reg != NULL) { for (i=0; i < Page.h.artnum; ++i) { if (regex(reg,Page.b[i].art_t) != NULL) { anum[acount] = Page.b[i].art_id; ++acount; } } regfree (reg); } else preinfo ("bad regular expression syntax"); } } /* algorithm is inefficient, but we're only handling a few numbers */ *list = '\0'; for (i=0; i < Page.h.artnum; ++i) { for (j=0; j < acount && anum[j] != Page.b[i].art_id; ++j) ; if (neg == '!') { if (j < acount) continue; } else { if (j >= acount) continue; } sprintf (list,"%d ",Page.b[i].art_id); list += strlen(list); } } SHAR_EOF fi # end of overwriting check echo shar: extracting "'vnglob.c'" '(1613 characters)' if test -f 'vnglob.c' then echo shar: will not over-write existing file "'vnglob.c'" else cat << \SHAR_EOF > 'vnglob.c' /* ** vn news reader. ** ** vnglob.c - global variables - see string.c also ** ** see copyright disclaimer / history in vn.c source file */ #include #include "config.h" #include "vn.h" #include "head.h" /* global data structure */ NODE **Newsorder; /* .newsrc file order */ char *Editor,*Ps1,*Mailer,*Printer,*Poster; char Erasekey, Killkey; /* user keys from stty */ char *Newsrc, *Orgdir; /* .newsrc file, and original pwd */ char *Onews; /* temp. file for backing up .newsrc */ char *Savefile = DEF_SAVE; /* file in which to save articles */ char *Savedir; /* default directory for saved articles */ char *Ccfile; /* author_copy file, stored /bin/mail fmt */ int Rot; /* rotation */ int Headflag; /* header printing flag */ int Digest; /* if non-zero, digest article */ char *Ku, *Kd, *Kl, *Kr; /* Cursor movement capabilities */ /* character translation arrays for commands */ char Cxitop[128], Cxitor[128], Cxrtoi[128], Cxptoi[128]; /* cur_page - current page displayed; lrec - last record l_allow - lines allowed for article display c_allow - columns allowed ncount = newsorder index nfltr - number of filters */ int Cur_page, Lrec, L_allow, C_allow, Ncount, Nfltr; /* article filtration options. */ char *Wopt[NUMFILTER]; /* regular expressions for -w options */ char *Topt[NUMFILTER]; /* regular expressions for -t options */ char *Negwopt[NUMFILTER]; /* regular expressions for negated -w options */ char *Negtopt[NUMFILTER]; /* regular expressions for negated -t options */ int Nwopt, Ntopt, Nnwopt, Nntopt; int Nounsub, Listfirst; /* current page */ PAGE Page; SHAR_EOF fi # end of overwriting check # End of shell archive exit 0