nick@ultima.cs.uts.oz (Nick Andrew) (11/28/89)
Geez I'm stupid ... neatly segregate the files into appropriately sized shars, then forget to create and post one! Here is the remaining sharfile. Sorry, Nick. #! /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: stat.c std.c std.h storage.c strings.c strtok.c svart.c # term_set.c tmpnam.c tty.h tty_set.c tune.h # Wrapped by nick@nswitgould on Tue Nov 28 07:59:57 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'stat.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'stat.c'\" else echo shar: Extracting \"'stat.c'\" \(4301 characters\) sed "s/^X//" >'stat.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** stat.c - stat and log file collection X** X** see copyright disclaimer / history in vn.c source file X*/ X#include <stdio.h> X#include <sys/types.h> X#ifdef SYSV X#include <fcntl.h> X#endif X X#ifndef MINIX X/* Minix doesn't have sys/file.h for some reason */ X#include <sys/file.h> X#endif X X#include <sys/stat.h> X#include <pwd.h> X#include "config.h" X#include "node.h" X Xextern NODE *hashfind(); Xextern char *strtok(); Xextern int Ncount; Xextern NODE **Newsorder; X X#ifdef VNLOGFILE Xstatic char Start[80]; X#endif X Xstat_start() X{ X#ifdef VNLOGFILE X char *ctime(); X long now; X X time(&now); X strcpy(Start,ctime(&now)); X#endif X} X X/* X** flag = 0, "NO NEWS" type session. X** = 1, regular session. X** = -1, aborted session X** X** CAUTION: routine CALLED from within printex() - do NOT X** call printex(). Simply do message to stderr on fail. X*/ Xstat_end(flag) Xint flag; X{ X NODE *nd; X char *nl,*index(); X char *how; X struct passwd *ptr, *getpwuid(); X struct stat buf; X long now; X char bufr[80]; X char name[60]; X FILE *fp; X int fd; X long chk, rd, pg; X int i; X X#ifdef VNLOGFILE X if (stat(VNLOGFILE,&buf) == 0 && (fp = fopen(VNLOGFILE,"a")) != NULL) X { X time(&now); X strcpy(bufr,ctime(&now)); X if ((nl = index(bufr,'\n')) != NULL) X *nl = '\0'; X if ((nl = index(Start,'\n')) != NULL) X *nl = '\0'; X if (flag == 0) X how = "NO NEWS"; X else X { X if (flag > 0) X how = "OK"; X else X how = "ABORTED"; X } X ptr = getpwuid (getuid()); X fprintf(fp, "%s\t%s - %s %s\n", ptr->pw_name, Start, bufr, how); X fclose (fp); X } X#endif X X#ifdef VNSTATFILE X /* X ** Stat file is done with a fixed record size, and maintaining the X ** existing record order exactly so that concurrent users will do X ** the least damage. If two users actually read & update a single X ** record simultaneously, we should just lose one user's counts. X ** Short of implementing a locking scheme, we probably won't do X ** much better. Disadvantages are that deleted newsgroups never X ** get cleaned out, order is set by the first user whose X ** statistics are collected, it will break if anyone modifies it, X ** and the file is a bit larger than it needs to be. X ** X ** record format: X ** X ** CCCCCC PPPPPP RRRRRR newsgroup name .... \n X ** ^ ^ ^ ^ ^ X ** 0 7 14 21 char 79 X ** X ** CCCCCC - count of sessions searching group X ** PPPPPP - count of sessions actually finding pages for group X ** RRRRRR - count of sessions actually accessing articles in group X */ X if ((fd = open(VNSTATFILE,O_RDWR)) > 0) X { X bufr[80] = '\0'; X X /* X ** read a record, find the newsgroup, update counts. X ** If changed, seek back & overwrite. By using fixed X ** length records, we should only lose something on X ** concurrent writes of the same record, and by writing X ** the ENTIRE record, we keep it consistent X */ X while ((i = read(fd,bufr,80)) == 80 && bufr[79] == '\n') X { X chk = atoi(bufr); X pg = atoi(bufr+7); X rd = atoi(bufr+14); X strcpy(name,bufr+21); X nl = strtok(name," \n"); X if (nl == NULL || (nd = hashfind(nl)) == NULL) X continue; X nd->flags |= FLG_STAT; X if ((nd->flags & (FLG_SEARCH|FLG_ACC|FLG_PAGE)) == 0) X continue; X if ((nd->flags & FLG_SEARCH) != 0) X ++chk; X if ((nd->flags & FLG_PAGE) != 0) X ++pg; X if ((nd->flags & FLG_ACC) != 0) X ++rd; X if (chk > 999999L) X chk = 999999L; X if (pg > 999999L) X pg = 999999L; X if (rd > 999999L) X rd = 999999L; X sprintf(bufr,"%6ld",chk); X bufr[6] = ' '; X sprintf(bufr+7,"%6ld",pg); X bufr[13] = ' '; X sprintf(bufr+14,"%6ld",rd); X bufr[20] = ' '; X lseek(fd,-80L,1); X write(fd,bufr,80); X } X X /* format screwed up ? */ X if (i != 0) X { X lseek(fd,(long) -i,1); X fprintf(stderr,"bad data in %s\n",VNSTATFILE); X } X X /* may have aborted during vns_news() */ X if (Newsorder == NULL) X Ncount = 0; X X /* now append any groups not in file yet */ X for (i = 0; i < Ncount; ++i) X { X nd = Newsorder[i]; X if ((nd->flags & FLG_STAT) != 0) X continue; X chk = rd = pg = 0; X if ((nd->flags & FLG_SEARCH) != 0) X chk = 1; X if ((nd->flags & FLG_PAGE) != 0) X pg = 1; X if ((nd->flags & FLG_ACC) != 0) X rd = 1; X sprintf(bufr,"%6ld %6ld %6ld %-58s\n", X chk, pg, rd, nd->nd_name); X write(fd,bufr,80); X } X close(fd); X } X#endif X} END_OF_FILE if test 4301 -ne `wc -c <'stat.c'`; then echo shar: \"'stat.c'\" unpacked with wrong size! fi # end of 'stat.c' fi if test -f 'std.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'std.c'\" else echo shar: Extracting \"'std.c'\" \(24307 characters\) sed "s/^X//" >'std.c' <<'END_OF_FILE' X#include <stdio.h> X#include <pwd.h> X#include <ctype.h> X X#ifndef MINIX X/* Minix is missing it */ X#include <sys/param.h> X#endif X X#include "server.h" X#include "config_std.h" X#include "std.h" X X#ifdef MINIX X#define clearerr(p) (((p)->_flags) &= ~_ERR) X#endif X X#ifndef MAXPATHLEN X#define MAXPATHLEN 240 X#endif X Xextern NODE *hashfind(); Xextern FILE *fopen(); Xextern char *index(), *rindex(); Xextern char *malloc(); Xextern char *str_tstore(), *str_tpool(), *str_store(); Xextern char *strtok(), *strpbrk(); Xextern char *regex(), *regcmp(); X X#ifdef MAILCHOOSE Xextern int (*Massage)(); X#endif X X/* X global flags signifying options set X*/ X#define GF_ALL 1 /* -x option - scan everything */ X#define GF_SPEC 2 /* -n option(s) - user specified groups */ X#define GF_OVER 4 /* command line specification - overide marks */ X Xchar *Vns_version = "res1.1"; X Xstatic char *Onews, *Newsrc; Xstatic int Ntopt, Nntopt, Nwopt, Nnwopt; X Xstatic char *Wopt[NUMFILTER]; /* regular expressions for -w options */ Xstatic char *Topt[NUMFILTER]; /* for -t options */ Xstatic char *Negwopt[NUMFILTER]; /* for negated -w options */ Xstatic char *Negtopt[NUMFILTER]; /* for negated -t options */ X Xstatic char *Options[OPTLINES]; Xstatic int Max_name, Optlines; Xstatic unsigned Gflags = 0; Xstatic char **Active; Xstatic int Actnum; Xstatic char *Mailer, *Poster; X Xstatic char *RT_head = RTHEAD; Xstatic char *P_head = PHEAD; Xstatic char *M_head = MHEAD; Xstatic char *R_head = RHEAD; Xstatic char *TO_head = TOHEAD; Xstatic char *F_head = FHEAD; Xstatic char *FT_head = FTHEAD; Xstatic char *T_head = THEAD; Xstatic char *DIS_head = DISHEAD; Xstatic char *L_head = LHEAD; Xstatic char *N_head = NHEAD; X Xstatic char *Fpfix = FPFIX; X X/* X** environment setup. X*/ Xvns_envir() X{ X char dbuf[MAXPATHLEN], *rcname; X char *vn_env(); X struct passwd *ptr, *getpwuid(); X#ifdef MAILCHOOSE X int mail_prompt(); X X Massage = mail_prompt; X#endif X X ptr = getpwuid (getuid()); X X rcname = vn_env("MAILER",DEF_MAIL); X#ifdef INLETTER X sprintf(dbuf,"cat %%s | %s",rcname); X#else X /* used as a format string TWICE (%%%% -> %% -> %) */ X sprintf(dbuf,"cat %%%%s | %s %%s",rcname); X#endif X Mailer = str_store(dbuf); X rcname = vn_env("VNPOSTER",DEF_POST); X sprintf(dbuf,"%s %%s",rcname); X Poster = str_store(dbuf); X rcname = vn_env("NEWSRC",DEF_NEWSRC); X if (*rcname != '/') X { X sprintf (dbuf, "%s/%s",ptr->pw_dir,rcname); X Newsrc = str_store (dbuf); X } X else X Newsrc = str_store (rcname); X X /* above logic guarantees that Newsrc contains a '/' */ X strcpy(dbuf,Newsrc); X strcpy(rindex(dbuf,'/')+1,".vnXXXXXX"); X mktemp(dbuf); X Onews = str_store (dbuf); X X if (access (Newsrc,0) != 0) X creat (Newsrc,0666); X} X X/* X change directory to group X*/ Xvns_gset(grp) Xchar *grp; X{ X char dbuf [RECLEN]; X g_dir (grp,dbuf); X if (chdir(dbuf) < 0) X printex("can't change to newsgroup directory"); X} X X/* X g_dir converts newsgroup name to directory string X*/ Xstatic Xg_dir(s,t) Xchar *s,*t; X{ X char *ptr; X sprintf (t,"%s/%s",SPOOLDIR,s); X for (ptr=t+strlen(SPOOLDIR)+1; (ptr = index(ptr,'.')) != NULL; *ptr = '/') X ; X} X X/* X** myfind is used for hashfind() calls which aren't supposed to fail. X*/ Xstatic NODE * Xmyfind(name) Xchar *name; X{ X NODE *n; X X n = hashfind(name); X if (n == NULL) X printex("Unexpected table lookup failure"); X return (n); X} X Xvns_news(argc,argv,lfirst,nun) Xint argc; Xchar **argv; Xint *lfirst, *nun; X{ X FILE *fp; X static char marks[] = X { X NEWS_ON, NEWS_OFF, '\0' X }; X int line, len, num; X char buf [RECLEN], trail, optpflag, submark, *fret, *ptr; X X ++argv; X --argc; X X /* fill table with active newsgroups */ X fill_active (); X X if (argc > 0) X { X Gflags |= GF_OVER; X arg_opt(argc,argv,lfirst,nun); X optpflag = 'y'; X } X else X optpflag = 'n'; X X if ((fp = fopen (Newsrc,"r")) == NULL) X printex ("can't open %s for reading",Newsrc); X X Optlines = 0; X X for (line = 1; (fret = fgets(buf,RECLEN-1,fp)) != NULL && emptyline(buf) == 1; ++line) X ; X if (fret != NULL && strncmp (buf,"options",7) == 0) X { X Options[0] = str_store(buf); X Optlines = 1; X trail = buf [strlen(buf)-2]; X for ( ; (fret = fgets(buf,RECLEN-1,fp)) != NULL; ++line) X { X if (trail != '\\' && buf[0] != ' ' && buf[0] != '\t') X break; X if (Optlines >= OPTLINES) X printex ("%s - too many option lines (%d allowed)",Newsrc,OPTLINES); X Options[Optlines] = str_store(buf); X ++Optlines; X if ((len = strlen(buf)) >= 2 && buf[len-2] != '\\') X trail = buf[len-2]; X else X trail = '\0'; X } X } X X /* do the options from the newsrc file if there weren't command line args */ X if (Optlines > 0 && optpflag == 'n') X newsrc_opt (lfirst,nun); X X for ( ; fret != NULL; ++line, fret = fgets(buf,RECLEN-1,fp)) X { X if (emptyline(buf) == 1) X continue; X if ((ptr = strpbrk(buf,marks)) == NULL) X { X fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n", X line,Newsrc,buf); X continue; X } X submark = *ptr; X *ptr = '\0'; X ++ptr; X num = 0; X for (ptr = strtok(ptr," ,-\n"); ptr != NULL; ptr = strtok(NULL," ,-\n")) X { X len = atoi (ptr); X for ( ; *ptr >= '0' && *ptr <= '9'; ++ptr) X ; X if (*ptr != '\0' || len < num) X { X num = -1; X fprintf (stderr,"\nwarning: line %d of %s (%s) - bad syntax\n", X line,Newsrc,buf); X break; X } X num = len; X } X if (num < 0) X continue; X chkgroup (buf,submark,num,0); X } X fclose (fp); X X /* now take care of groups not specified in .newsrc */ X art_active(); X X /* free up the option string storage */ X for (num=0; num < Ntopt; ++num) X regfree (Topt[num]); X for (num=0; num < Nwopt; ++num) X regfree (Wopt[num]); X for (num=0; num < Nntopt; ++num) X regfree (Negtopt[num]); X for (num=0; num < Nnwopt; ++num) X regfree (Negwopt[num]); X Ntopt = Nwopt = Nntopt = Nnwopt = 0; X X /* free the active list */ X free ((char *) Active); X} X Xstatic Xemptyline(s) Xchar *s; X{ X while (isspace(*s)) X ++s; X if (*s == '\0') X return (1); X return (0); X} X X/* X fill hash table from active news group list X This is needed to be able to process options X before scanning user order. Constructs an array X of active newsgroup names for the rest of vns_nws(). X*/ Xstatic Xfill_active () X{ X FILE *f; X char *nread, act_rec[RECLEN]; X int num,lownum,rcount; X X Max_name = 0; X if ((f = fopen (ACTFILE,"r")) == NULL) X printex ("couldn't open %s\n",ACTFILE); X X /* X ** we do things this way so that we only examine active records X ** once, minimizing the window where changes could screw us up X ** at the cost of possibly alloc'ing a few extra bytes. We start X ** with a count of one to have a positive rcount for alloc. X */ X for(rcount=1; fgets(act_rec, RECLEN-1, f) != NULL; ++rcount) X ; X if ((Active = (char **) malloc(rcount*sizeof(char *))) == NULL) X printex("Memory allocation failure"); X X rewind(f); X X Actnum = 0; X while (Actnum < rcount && fgets(act_rec, RECLEN-1, f) != NULL) X { X if (strtok (act_rec," \n") == NULL) X continue; X nread = strtok (NULL, " \n"); X if (nread != NULL) X num = atoi(nread); X else X num = 0; X nread = strtok (NULL, " \n"); X if (nread != NULL) X lownum = atoi(nread); X else X lownum = 0; X if (lownum > 0) X --lownum; X if (strlen(act_rec) > Max_name) X Max_name = strlen(act_rec); X X /* enter newsgroup, point to permanent copy of name */ X hashenter (act_rec, num, lownum); X Active[Actnum] = (myfind(act_rec))->nd_name; X ++Actnum; X } X X fclose (f); X} X X/* X check active newsgroups not mentioned in NEWSRC file X (SFLG_SCAN not set) X*/ Xstatic Xart_active () X{ X int i; X NODE *ptr; X X for( i=0; i < Actnum; ++i) X { X ptr = myfind(Active[i]); X if ((ptr->state & SFLG_SCAN) == 0) X chkgroup (ptr->nd_name, NEWS_ON, 0, 1); X } X} X X/* X check group for new articles: X s - group X c - subscription indicator from NEWSRC X n - number read X new - new newsgroup flag X*/ Xstatic Xchkgroup (s,c,n,new) Xchar *s,c; Xint n; Xint new; X{ X NODE *ptr; X char sub; X int nrd; X int lowart; X int st; X X if ((ptr = hashfind(s)) != NULL && (ptr->state & SFLG_SCAN) == 0) X { X ptr->state |= SFLG_SCAN; X X#ifdef SYN_CHECK X /* if "read" more than exist, reset */ X if (n > ptr->highnum) X { X n = ptr->highnum - SYN_SETBACK; X fgprintf("%s: .newsrc out of synch, resetting\n",s); X } X#endif X lowart = ptr->lownum; X if (n < ptr->lownum) X n = ptr->lownum; X X nrd = n; X sub = c; X X /* X ** scan decision is rather complex, since GF_ALL setting X ** overides "n" value, GF_SPEC indicates SFLG_SPEC flag used. X ** if GF_OVER set, SFLG_SPEC overides subscription mark, else X ** SFLG_SPEC AND subscribed is neccesary. X */ X if ((Gflags & GF_SPEC) != 0) X { X if ((ptr->state & SFLG_SPEC) == 0) X c = NEWS_OFF; X else X { X if ((Gflags & GF_OVER) != 0) X c = NEWS_ON; X } X } X if ((Gflags & GF_ALL) != 0) X n = lowart; X fw_group(s, new, sub == NEWS_ON, nrd, c == NEWS_ON); X if (c == NEWS_ON && ptr->highnum > n) X { X st = outgroup (s,n,ptr->highnum); X if (st > nrd) X fw_chg(new, sub == NEWS_ON, st, c == NEWS_ON); X } X } X} X X/* X vns_write writes the .newsrc file X*/ Xvns_write(news,ncount) XNODE **news; Xint ncount; X{ X FILE *fp; X NODE *p; X char c; X int i,rc; X X if (link(Newsrc,Onews) < 0) X printex ("can't backup %s to %s before writing",Newsrc,Onews); X X if (unlink(Newsrc) < 0 || (fp = fopen(Newsrc,"w")) == NULL) X printex ("can't open %s for writing (backed up in %s)",Newsrc,Onews); X else X { X clearerr(fp); X for (i=0; (rc = ferror(fp)) == 0 && i < Optlines; ++i) X fprintf (fp,"%s",Options[i]); X for (i=0; rc == 0 && i < ncount; ++i) X { X p = news[i]; X if ((p->flags & FLG_SUB) == 0) X c = NEWS_OFF; X else X c = NEWS_ON; X#ifdef OLDRC X fprintf (fp,"%s%c %d\n",p->nd_name,c,p->rdnum); X#else X if (p->rdnum > 0) X fprintf(fp,"%s%c 1-%d\n",p->nd_name,c,p->rdnum); X else X fprintf(fp,"%s%c 0\n",p->nd_name,c); X#endif X rc = ferror(fp); X } X fclose (fp); X if (rc != 0) X printex ("write of %s failed, old copy stored in %s",Newsrc,Onews); X else X unlink (Onews); X } X} X X/* X arg_opt must be called prior to option scanning, since X it uses the options array. This is a bit of a kludge, X but it saves a bunch of work. NOTE - no command name argument X*/ Xstatic Xarg_opt (argc,argv,lfirst,nun) Xint argc; Xchar **argv; Xint *lfirst, *nun; X{ X if (argc > OPTLINES) X printex ("too many command line options (%d allowed)\n",OPTLINES); X for (Optlines=0; Optlines < argc; ++Optlines) X { X Options[Optlines] = *argv; X ++argv; X } X newsrc_opt(lfirst,nun); X} X X/* X option setting routine: X sets global flags: GF_ALL for -x option GF_SPEC for -n. X sets up filter array for article scanning X*/ Xstatic Xnewsrc_opt(lfirst,nun) Xint *lfirst, *nun; X{ X int i; X char curopt,tmp[RECLEN],*tok; X X *nun = *lfirst = 0; X Ntopt = Nwopt = Nnwopt = Nntopt = 0; X curopt = '\0'; X for (i=0; i < Optlines; ++i) X { X strcpy(tmp,Options[i]); X for (tok = strtok(tmp,",\\ \t\n"); tok != NULL; tok = strtok(NULL,",\\ \t\n")) X { X if (*tok != '-') X do_opt (curopt,tok); X else X { X for (++tok; index("nwt",*tok) == NULL; ++tok) X { X /* options with no strings */ X switch(*tok) X { X case 'S': X Gflags &= ~GF_OVER; X break; X case '%': X *lfirst = 1; X break; X case 'U': X *nun = 1; X break; X#ifdef OLDRC X case 'i': X /* Treat "-i" as synonym for "-x" */ X#endif X case 'x': X Gflags |= GF_ALL; X default: X break; X } X } X curopt = *tok; X if (*(++tok) != '\0') X do_opt (curopt,tok); X } X } X } X} X X/* do_opt is for options with strings attached */ Xstatic Xdo_opt (opt,str) Xchar opt, *str; X{ X switch (opt) X { X case 'n': X Gflags |= GF_SPEC; X specmark(str); X break; X case 'w': X specfilter (FIL_AUTHOR,str); X break; X case 't': X specfilter (FIL_TITLE,str); X break; X default: X#ifdef OLDRC X Gflags |= GF_SPEC; /* Assume anything else is newsgroup */ X specmark(str); X#endif X break; X } X} X Xstatic Xspecfilter (comp,str) Xchar comp,*str; X{ X int *count; X char **rex; X X /* X ** we may set rex one past end of array. we will error before X ** referencing it if that's the case, however. X */ X if (*str == '!') X { X if (comp == FIL_TITLE) X { X count = &Nntopt; X rex = Negtopt + *count; X } X else X { X count = &Nnwopt; X rex = Negwopt + *count; X } X ++str; X } X else X { X if (comp == FIL_TITLE) X { X count = &Ntopt; X rex = Topt + *count; X } X else X { X count = &Nwopt; X rex = Wopt + *count; X } X } X if (*count >= NUMFILTER) X printex ("too many %c options, %d allowed",comp,NUMFILTER); X if ((*rex = regcmp(str,(char *) 0)) == NULL) X printex ("%c option regular expression syntax: %s",comp,str); X ++(*count); X} X X/* X handle the newsgroup specification string. X ("all" convention - braack!!!) X*/ Xstatic Xspecmark (s) Xchar *s; X{ X unsigned ormask,andmask; X int i,len; X char *ptr,*re,pattern[RECLEN]; X NODE *nptr; X X if (*s == '!') X { X ++s; X ormask = 0; X andmask = ~SFLG_SPEC; X if (*s == '\0') X return; X } X else X { X ormask = SFLG_SPEC; X andmask = 0xffff; X } X X /* convert "all" not bounded by alphanumerics to ".*". ".all" becomes ".*" */ X for (ptr = s; (len = findall(ptr)) >= 0; ptr += len+1) X { X if (len > 0 && isalnum (s[len-1])) X continue; X if (isalnum (s[len+3])) X continue; X if (len > 0 && s[len-1] == '.') X { X --len; X strcpy (s+len,s+len+1); X } X s[len] = '.'; X s[len+1] = '*'; X strcpy (s+len+2,s+len+3); X } X X /* now use regular expressions */ X sprintf (pattern,"^%s$",s); X if ((re = regcmp(pattern,(char *) 0)) == NULL) X printex ("n option regular expression syntax: %s",s); X for (i=0; i < Actnum; ++i) X { X nptr = myfind(Active[i]); X if (regex(re,nptr->nd_name) != NULL) X { X nptr->state |= ormask; X nptr->state &= andmask; X } X } X regfree (re); X} X Xstatic Xfindall (s) Xchar *s; X{ X int len; X for (len=0; *s != '\0'; ++s,++len) X { X if (*s == 'a' && strncmp(s,"all",3) == 0) X return (len); X } X return (-1); X} X Xstatic Xgrp_indic (s,ok) Xchar *s; Xint ok; X{ X if (ok) X fgprintf(" %s\n",s); X else X fgprintf(" %s - Can't access spool directory\n",s); X} X X/* X enter newsgroup articles. X all articles between low and hi are to be included. X X Returns the highest number less than an OPENED (not neccesarily X accepted) article to allow caller to revise "articles read" X number beyond non-existent articles. X*/ Xoutgroup (s,low,hi) Xchar *s; Xint low,hi; X{ X int i; X char subj[RECLEN], lines[RECLEN], auth[RECLEN], gd[RECLEN]; X int ret,op; X X if ((hi-low) > MAXARTRANGE) X low = hi - MAXARTRANGE; X X ret = low; X op = 1; X X g_dir(s,gd); X if (chdir(gd) < 0) X { X grp_indic(s,0); X return (ret); X } X grp_indic(s,1); X for (i=low+1; i <= hi; ++i) X { X if (digname(i,subj,lines,auth,&op) >= 0) X { X fw_art(i,subj,lines,auth); X } X else X { X if (op) X ret = i; X } X } X X return(ret); X} X X/* X** open article and interpret options, if any. The op parameter is set X** to ZERO if and only if an article is opened. Used above as a flag to X** indicate no articles opened yet. X*/ Xstatic digname (n, subj, lines, auth, op) Xint n; Xchar *subj, *lines, *auth; Xint *op; X{ X int i,j; X FILE *fp; X char t[RECLEN]; X char *nfgets(); X X /* open article */ X sprintf (t,"%d", n); X if ((fp = fopen(t,"r")) == NULL) X return (-1); X *op = 0; X X /* get subject, from and lines by reading article */ X subj[0] = lines[0] = auth[0] = '?'; X subj[1] = lines[1] = auth[1] = '\0'; X for (i = 0; i < HDR_LINES && nfgets(t,RECLEN-1,fp) != NULL; ++i) X { X if (index(CHFIRST,t[0]) == NULL) X continue; X t[strlen(t) - 1] = '\0'; X if (strncmp(T_head,t,THDLEN) == 0) X { X for (j=0; j < Nntopt; ++j) X { X if (regex(Negtopt[j],t+THDLEN) != NULL) X { X fclose(fp); X return(-1); X } X } X if (Ntopt > 0) X { X for (j=0; j < Ntopt; ++j) X { X if (regex(Topt[j],t+THDLEN) != NULL) X break; X } X if (j >= Ntopt) X { X fclose(fp); X return(-1); X } X } X strcpy(subj,t+THDLEN); X continue; X } X if (strncmp(F_head,t,FHDLEN) == 0) X { X for (j=0; j < Nnwopt; ++j) X { X if (regex(Negwopt[j],t+FHDLEN) != NULL) X { X fclose(fp); X return(-1); X } X } X if (Nwopt > 0) X { X for (j=0; j < Nwopt; ++j) X { X if (regex(Wopt[j],t+FHDLEN) != NULL) X break; X } X if (j >= Nwopt) X { X fclose(fp); X return(-1); X } X } X strcpy(auth,t+FHDLEN); X continue; X } X if (strncmp(L_head,t,LHDLEN) == 0) X { X strcpy(lines,t+LHDLEN); X break; X } X } X X fclose (fp); X X /* reject empty or 1 line files */ X if (i < 2) X return (-1); X X return (0); X} X X/* X** special fgets for reading header lines, which unfolds continued lines X** and throws away trailing stuff on buffer overflow. X*/ Xstatic char * Xnfgets(buf, size, fp) Xchar *buf; Xint size; XFILE *fp; X{ X register int c; X X while (!feof(fp)) X { X if ((c = getc(fp)) == '\n') X { X if ((c = getc(fp)) == '\t' || c == ' ') X continue; X ungetc(c, fp); X *buf = '\n'; X ++buf; X *buf = '\0'; X ++buf; X return (buf); X } X X /* prevent "terminal bombs" */ X if (c < ' ' || c == '\177') X { X switch(c) X { X case '\r': X case '\010': X case '\07': X break; X case '\177': X c = '~'; X break; X case '\t': X c = ' '; X break; X default: X if (size > 1) X { X *buf = '^'; X ++buf; X --size; X } X c += 'A' - 1; X break; X } X } X X if (size > 0) X { X *buf = c; X ++buf; X --size; X } X if (c == '\r') X { X if ((c = getc(fp)) != '\n') X { X ungetc(c, fp); X continue; X } X if ((c = getc(fp)) != ' ' && c != '\t') X { X *buf = '\0'; X ++buf; X ungetc(c, fp); X return (buf); X } X --buf; X ++size; X continue; X } X } X X *buf = '\0'; X ++buf; X return (NULL); X} X Xstatic char *Mail[2], *Show[6], *Post[4]; Xstatic char *Priv[8]; Xstatic char *Pool = NULL; X XFILE * Xvns_aopen(art,hdr) Xint art; XARTHEADER *hdr; X{ X char buf[RECLEN]; X char *dist, *reply, *from, *ngrp, *flto, *path, *resubj; X FILE *fp; X int n; X char *mail_trim(); X X dist = resubj = path = reply = from = ngrp = flto = NULL; X X sprintf(buf,"%d",art); X if ((fp = fopen(buf,"r")) == NULL) X return(NULL); X X /* X ** we only really need a lot extra if MAILCHOOSE, but allocating X ** a temporary array of pointers isn't that much. Similarly, a X ** few assignments, and the "Priv" declaration are only needed X ** with some define settings. Not worth ifdef'ing. X */ X Pool = str_tpool(100); X X hdr->artid = "<some article>"; X hdr->from = "<somebody>"; X hdr->priv = Priv; X hdr->postcmd = Poster; X hdr->mail = Mail; X hdr->show = Show; X hdr->post = Post; X hdr->priv_num = hdr->show_num = hdr->post_num = hdr->mail_num = 0; X X /* for conditional is abnormal - expected exit is break */ X for (n=0; n < HDR_LINES && fgets(buf,RECLEN-1,fp) != NULL; ++n) X { X /* bail out at first non-header line */ X if (buf[0] == '\n') X break; X if (strncmp(buf,RT_head,RTHDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X reply = str_tstore(Pool,buf+RTHDLEN); X continue; X } X if (strncmp(buf,P_head,PHDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X path = str_tstore(Pool,buf+PHDLEN); X continue; X } X if (strncmp(buf,DIS_head,DISHDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X dist = str_tstore(Pool,buf); X continue; X } X if (strncmp(buf,M_head,MHDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X hdr->artid = str_tstore(Pool,buf+MHDLEN); X continue; X } X if (strncmp(buf,F_head,FHDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X (hdr->show)[hdr->show_num] = str_tstore(Pool,buf); X from = hdr->from = (hdr->show)[hdr->show_num]+FHDLEN; X ++(hdr->show_num); X continue; X } X if (strncmp(buf,T_head,THDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X (hdr->show)[hdr->show_num] = str_tstore(Pool,buf); X if (strncmp(buf+THDLEN,Fpfix,FPFLEN) != 0) X { X sprintf(buf,"%s%s%s",T_head,Fpfix, X ((hdr->show)[hdr->show_num])+THDLEN); X resubj = str_tstore(Pool,buf); X } X else X resubj = (hdr->show)[hdr->show_num]; X ++(hdr->show_num); X continue; X } X if (strncmp(buf,N_head,NHDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X X /* if multiple newsgroups, include in "show" */ X if (index(buf,',') != NULL) X { X (hdr->show)[hdr->show_num] = str_tstore(Pool,buf); X ngrp = (hdr->show)[hdr->show_num] + NHDLEN; X ++(hdr->show_num); X } X else X ngrp = str_tstore(Pool,buf+NHDLEN); X continue; X } X if (strncmp(buf,FT_head,FTHDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X (hdr->show)[hdr->show_num] = str_tstore(Pool,buf); X flto = (hdr->show)[hdr->show_num] + FTHDLEN; X ++(hdr->show_num); X continue; X } X if (strncmp(buf,L_head,LHDLEN) == 0) X { X buf [strlen(buf)-1] = '\0'; X hdr->lines = atoi(buf+LHDLEN); X (hdr->show)[hdr->show_num] = str_tstore(Pool,buf); X ++(hdr->show_num); X continue; X } X } X X hdr->hlines = n; X X#ifdef MAILCHOOSE X (hdr->priv)[hdr->priv_num] = resubj; X ++(hdr->priv_num); X if (reply != NULL) X { X (hdr->priv)[hdr->priv_num] = mail_trim(reply); X ++(hdr->priv_num); X } X if (from != NULL) X { X (hdr->priv)[hdr->priv_num] = mail_trim(from); X ++(hdr->priv_num); X } X if (path != NULL) X { X (hdr->priv)[hdr->priv_num] = mail_trim(path); X ++(hdr->priv_num); X } X#else X#ifdef MAILSMART X if (reply == NULL) X if (from != NULL) X reply = from; X else X { X if (path != NULL) X reply = path; X } X#else X if (path != NULL) X reply = path; X#endif X if (reply != NULL) X reply = mail_trim(reply); X mail_cmd(hdr,reply,resubj); X#endif /* MAILCHOOSE */ X X if (flto == NULL) X { X if ((flto = ngrp) == NULL) X flto = "group.unknown"; X } X ngrp = rindex(flto,'.'); X X if (strncmp("mod.",flto,4) == 0 || X (ngrp != NULL && strcmp(".announce",ngrp) == 0)) X { X sprintf(buf,"Cannot post a follow-up to \"%s\", reply with mail to moderator",flto); X hdr->post_err = str_tstore(Pool,buf); X return (fp); X } X X if (ngrp != NULL && strcmp(ngrp,".general") == 0) X { X *ngrp = '\0'; X sprintf(buf,"%s%s.followup",N_head,flto); X } X else X sprintf(buf,"%s%s",N_head,flto); X flto = str_tstore(Pool,buf); X X hdr->post_err = NULL; X X if (resubj != NULL) X { X (hdr->post)[hdr->post_num] = resubj; X ++(hdr->post_num); X } X X (hdr->post)[hdr->post_num] = flto; X ++(hdr->post_num); X X sprintf(buf,"%s%s",R_head,hdr->artid); X (hdr->post)[hdr->post_num] = str_tstore(Pool,buf); X ++(hdr->post_num); X X if (dist != NULL) X { X (hdr->post)[hdr->post_num] = dist; X ++(hdr->post_num); X } X X return (fp); X} X X#ifdef MAILCHOOSE X/* X** routine to prompt user for mail path approval X*/ Xstatic Xmail_prompt(hdr) XARTHEADER *hdr; X{ X int i; X char buf[RECLEN],*ptr; X X tty_set(SAVEMODE); X for (i=1; i < hdr->priv_num; ++i) X { X printf("%d - %s\n",i,(hdr->priv)[i]); X } X printf("\nType number to choose one of the above, or input address: "); X fgets(buf,RECLEN-1,stdin); X tty_set(RESTORE); X X ptr = strtok(buf," \t\n"); X if (ptr == NULL) X ptr = ""; X X i = strlen(ptr); X if (i == 1) X { X i = atoi(ptr); X if (i > 0 && i <= hdr->priv_num) X ptr = (hdr->priv)[i]; X i = 1; X } X X /* X ** If the user keeps cycling through here on the same article, X ** we will eventually run out of strings. We made Pool large X ** enough to make it unlikely (user will have to retry about 80 X ** times without switching articles). Hardly elegant, but should X ** be sufficient. X */ X if (i > 1 && hdr->priv_num < 8) X { X (hdr->priv)[hdr->priv_num] = str_tstore(Pool,ptr); X ++(hdr->priv_num); X } X mail_cmd(hdr,ptr,(hdr->priv)[0]); X} X#endif X X/* X** trim () off potential mail address, and make copy if needed. X** addr must be allocated string. X*/ Xstatic char * Xmail_trim(addr) Xchar *addr; X{ X char buf[RECLEN]; X char *ptr; X X if (index(addr,'(') == NULL) X return(addr); X X strcpy(buf,addr); X ptr = index(buf,'('); X for (--ptr; *ptr == ' ' || *ptr == '\t'; --ptr) X ; X ++ptr; X *ptr = '\0'; X return (str_tstore(Pool,buf)); X} X X/* X** format mail command. Subj must point to allocated string. X*/ Xstatic Xmail_cmd(hdr,addr,subj) XARTHEADER *hdr; Xchar *addr, *subj; X{ X char buf[RECLEN]; X X if (addr == NULL || *addr == '\0') X { X hdr->mail_err = "No address"; X return; X } X X hdr->mail_err = NULL; X ; X X#ifdef INLETTER X hdr->mailcmd = Mailer; X sprintf(buf,"%s%s",TO_head,addr); X (hdr->mail)[0] = str_tstore(Pool,buf); X hdr->mail_num = 1; X#else X sprintf(buf,Mailer,addr); X hdr->mailcmd = str_tstore(Pool,buf); X hdr->mail_num = 0; X#endif X if (subj != NULL) X { X (hdr->mail)[hdr->mail_num] = subj; X ++(hdr->mail_num); X } X} X Xvns_aclose(fp) XFILE *fp; X{ X if (Pool != NULL) X str_tfree(Pool); X Pool = NULL; X fclose(fp); X} X X/* X** we don't use the count / name / mode arguments because this doesn't X** implement any fancy article massaging X*/ Xvns_asave(art,fp) Xint art; XFILE *fp; X{ X char buf[RECLEN]; X FILE *fin; X X sprintf(buf,"%d",art); X if ((fin = fopen(buf,"r")) == NULL) X return; X X while (fgets(buf,RECLEN-1,fin) != NULL) X fputs(buf,fp); X fclose(fin); X} X Xvns_exit() X{ X} END_OF_FILE if test 24307 -ne `wc -c <'std.c'`; then echo shar: \"'std.c'\" unpacked with wrong size! fi # end of 'std.c' fi if test -f 'std.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'std.h'\" else echo shar: Extracting \"'std.h'\" \(886 characters\) sed "s/^X//" >'std.h' <<'END_OF_FILE' X/* X newsrc states X*/ X#define NEWS_ON ':' X#define NEWS_OFF '!' X X#define SFLG_SCAN 1 X#define SFLG_SPEC 2 X X#define FPFIX "Re: " X#define FPFLEN 4 X X#define FIL_AUTHOR 'w' X#define FIL_TITLE 't' X X/* X header lines and associated lengths. Strings should X actually be used only once. X*/ X#define RHEAD "References: " X#define RHDLEN 12 X#define MHEAD "Message-ID: " X#define MHDLEN 12 X#define PHEAD "Path: " X#define PHDLEN 6 X#define DHEAD "Date: " X#define DHDLEN 6 X#define RTHEAD "Reply-To: " X#define RTHDLEN 10 X#define TOHEAD "To: " X#define TOHDLEN 4 X#define FHEAD "From: " X#define FHDLEN 6 X#define FTHEAD "Followup-To: " X#define FTHDLEN 13 X#define DISHEAD "Distribution: " X#define DISHDLEN 14 X#define THEAD "Subject: " X#define THDLEN 9 X#define LHEAD "Lines: " X#define LHDLEN 7 X#define NHEAD "Newsgroups: " X#define NHDLEN 12 X X#define CHFIRST "FSL" /* first char's of those used in page display */ END_OF_FILE if test 886 -ne `wc -c <'std.h'`; then echo shar: \"'std.h'\" unpacked with wrong size! fi # end of 'std.h' fi if test -f 'storage.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'storage.c'\" else echo shar: Extracting \"'storage.c'\" \(2261 characters\) sed "s/^X//" >'storage.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** storage.c - storage allocation routines X** X** see copyright disclaimer / history in vn.c source file X*/ X X#include <stdio.h> X#include "tune.h" X#include "node.h" X#include "page.h" X Xextern char *malloc(); X Xextern int L_allow; X Xextern PAGE Page; X/* X Storage allocaters. X*/ X Xchar *str_store (s) Xchar *s; X{ X static unsigned av_len = 0; /* current storage available */ X static char *avail; X int len; X X if (s == NULL) X s = ""; X X if ((len = strlen(s)+1) > av_len) X { X if (len > STRBLKSIZE) X av_len = len; X else X av_len = STRBLKSIZE; X if ((avail = malloc(av_len)) == NULL) X printex ("can't allocate memory for string storage"); X } X strcpy (avail,s); X s = avail; X avail += len; X av_len -= len; X return (s); X} X X/* X** called after number of terminal lines (L_allow) is known, to set X** up storage for Page. X*/ Xpage_alloc () X{ X char *body; X X if ((body = malloc(L_allow*sizeof(BODY))) == NULL) X printex ("can't allocate memory for display storage"); X X Page.b = (BODY *) body; X} X XNODE X*node_store() X{ X static int nd_avail = 0; X static NODE *nd; X NODE *ret; X X if (nd_avail <= 0) X { X if ((nd = (NODE *) malloc(sizeof(NODE)*NDBLKSIZE)) == NULL) X printex ("can't allocate memory for newsgroup table"); X nd_avail = NDBLKSIZE; X } X --nd_avail; X ret = nd; X ++nd; X return(ret); X} X X/* X** temp string storage X*/ X Xtypedef struct X{ X int len; X int idx; X char **ptr; X} STRINGPOOL; X Xchar * Xstr_tpool(n) Xint n; X{ X int size; X STRINGPOOL *p; X X size = sizeof(STRINGPOOL) + n * sizeof(char **); X X if ((p = (STRINGPOOL *) malloc(size)) == NULL) X printex("Cannot allocate temporary string storage"); X X p->ptr = (char **)(p+1); X p->len = n; X p->idx = 0; X X return((char *) p); X} X Xchar * Xstr_tstore(cp,s) Xchar *cp; Xchar *s; X{ X STRINGPOOL *p; X int len; X X p = (STRINGPOOL *) cp; X if (p->idx >= p->len) X printex("Temporary string storage overflow"); X len = strlen(s)+1; X if ((cp = malloc(len)) == NULL) X printex("Cannot allocate copy of string"); X strcpy(cp,s); X (p->ptr)[p->idx] = cp; X ++(p->idx); X X return(cp); X} X Xchar ** Xstr_taptr(cp) Xchar *cp; X{ X STRINGPOOL *p; X X p = (STRINGPOOL *) cp; X X return (p->ptr + p->idx); X} X Xstr_tfree(cp) Xchar *cp; X{ X STRINGPOOL *p; X int i; X X p = (STRINGPOOL *) cp; X for (i=0; i < p->idx; ++i) X free((p->ptr)[i]); X free (cp); X} END_OF_FILE if test 2261 -ne `wc -c <'storage.c'`; then echo shar: \"'storage.c'\" unpacked with wrong size! fi # end of 'storage.c' fi if test -f 'strings.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'strings.c'\" else echo shar: Extracting \"'strings.c'\" \(537 characters\) sed "s/^X//" >'strings.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** strings.c - read only character strings X** X** see copyright disclaimer / history in vn.c source file X*/ X X#include "tune.h" X#include "node.h" X#include "page.h" X Xchar *Version = "4/88"; X Xchar *No_msg = "No articles"; Xchar *Hdon_msg = "Headers being printed"; Xchar *Hdoff_msg = "Headers being suppressed"; Xchar *Roton_msg = "ROT 13"; Xchar *Rotoff_msg = "NO ROT"; X Xchar *Aformat = AFORMAT; X Xchar *Contstr = " ******** any key to continue ********"; X Xchar *Brk_fmt = "QUIT (signal %d)"; X Xchar *List_sep = " \t,"; END_OF_FILE if test 537 -ne `wc -c <'strings.c'`; then echo shar: \"'strings.c'\" unpacked with wrong size! fi # end of 'strings.c' fi if test -f 'strtok.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'strtok.c'\" else echo shar: Extracting \"'strtok.c'\" \(1082 characters\) sed "s/^X//" >'strtok.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** strtok.c - strtok() and strpbrk() string routines using UCB index(). X** X** see copyright disclaimer / history in vn.c source file X*/ X X#include <stdio.h> X Xchar *strpbrk (s,del) Xchar *s, *del; X{ X char *ptr,*index(); X if (s == NULL) X return (NULL); X for (; *del != '\0'; ++del) X if ((ptr = index(s,*del)) != NULL) X return (ptr); X return (NULL); X} X Xchar *strtok(str,delim) Xchar *str, *delim; X{ X char *tokstart, *tokend, *first_ch (), *last_ch(); X static char *save=NULL; X X if (str != NULL) X save = str; X X if (save == NULL) X return (NULL); X X tokstart = first_ch (save, delim); X tokend = last_ch (tokstart, delim); X save = first_ch (tokend, delim); X *tokend = '\0'; X X if (*tokstart == '\0') X return (NULL); X X return (tokstart); X} X Xstatic char *first_ch (str,delim) Xchar *str,*delim; X{ X char *index (); X char *f; X X for (f = str; *f != '\0' && index(delim,*f) != NULL; ++f) X ; X X return (f); X} X Xstatic char *last_ch (str,delim) Xchar *str,*delim; X{ X char *index (); X char *f; X X for (f = str; *f != '\0' && index(delim,*f) == NULL; ++f) X ; X X return (f); X} END_OF_FILE if test 1082 -ne `wc -c <'strtok.c'`; then echo shar: \"'strtok.c'\" unpacked with wrong size! fi # end of 'strtok.c' fi if test -f 'svart.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'svart.c'\" else echo shar: Extracting \"'svart.c'\" \(4834 characters\) sed "s/^X//" >'svart.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** svart.c - article save routine X** X** see copyright disclaimer / history in vn.c source file X*/ X#include <stdio.h> X#include <pwd.h> X#include <sys/types.h> X#include <sys/stat.h> X#include "config.h" X#include "tty.h" X#include "tune.h" X#include "node.h" X#include "page.h" X Xextern PAGE Page; Xextern int Digest; Xextern char *List_sep; Xextern char *Home; Xextern char *Savedir; Xextern FILE *(*Saveopen)(); Xextern int (*Digsaver)(); X X/* X** save article in file. Called from reader and session both. X** handles "|" pipe convention. Caller passes in return message buffer. X*/ Xsave_art(art,idest,msg) Xchar *art; Xchar *idest; Xchar *msg; X{ X char fn[L_tmpnam+1]; X char cmd[RECLEN]; X char *mode; X char *dest, dstore[RECLEN]; X struct stat sbuf; X int rstat; X char *colon; X char *pcnt; X char *index(); X X /* temporary copy so we don't overwrite saved string */ X strcpy((dest = dstore),idest); X X if (*dest == '|') X { X tmpnam(fn); X if (art_xfer(fn,art,"w",NULL) != 0) X { X strcpy(msg,"Can't open temporary file"); X return (-1); X } X sprintf(cmd,"cat %s %s",fn,dest); X tty_set (SAVEMODE); X rstat = system (cmd); X tty_set (RESTORE); X sprintf(msg,"Command returns %d",rstat); X return (rstat); X } X X if (Saveopen != NULL) X return (art_xfer(dest,art,"a",msg)); X X if ((colon = index(dest,':')) != NULL) X { X mode = dest; X *colon = '\0'; X dest = colon+1; X } X else X mode = "a"; X X if (*dest == '~') X { X if (twiddle(dest,msg) < 0) X return (-1); X } X X if (*dest == '\0') X strcpy(dest,"%d"); X X if (*dest != '/') X { X if (noslash(dest,msg) < 0) X return (-1); X } X X if ((pcnt = index(dest,'%')) != NULL && pcnt[1] == 'd') X { X if (Digest) X sprintf(cmd,dest,Digest); X else X sprintf(cmd,dest,atoi(art)); X dest = cmd; X } X X rstat = stat(dest,&sbuf); X X if (art_xfer(dest,art,mode,msg) != 0) X { X sprintf(msg,"Can't open %s with mode %s",dest,mode); X return(-1); X } X X if (rstat != 0) X { X sprintf(msg,"Created %s",dest); X return(0); X } X X if (strcmp(mode,"a") == 0) X { X sprintf(msg,"Appended %s",dest); X return(0); X } X X sprintf(msg,"Wrote (mode %s) %s",mode,dest); X return(0); X} X Xstatic Xnoslash(dest,msg) Xchar *dest; Xchar *msg; X{ X char *pcnt; X char buf[RECLEN]; X char dir[RECLEN]; X struct stat sbuf; X X strcpy(buf,Page.h.name); X#ifdef SYSV X buf[14] = '\0'; X#endif X if ((pcnt = index(Savedir,'%')) != NULL && pcnt[1] == 's') X sprintf(dir,Savedir,buf); X else X strcpy(dir,Savedir); X if (dir[0] == '~') X { X if (twiddle(dir,msg) < 0) X return (-1); X } X if (stat(dir,&sbuf) != 0) X { X#ifdef SYSV X /* X ** late enough releases of SYSV may have a mkdir() call, but X ** this is an obscure feature anyway. We'll accept the fork. X */ X sprintf(buf,"mkdir %s",dir); X if (system(buf) != 0) X#else X if (mkdir(dir,0755) != 0) X#endif X { X sprintf(msg,"Cannot make directory %s",dir); X return (-1); X } X } X sprintf(buf,"%s/%s",dir,dest); X strcpy(dest,buf); X return (0); X} X Xstatic Xtwiddle(dest,msg) Xchar *dest, *msg; X{ X char *tail; X char *name; X char tmp; X char buf[RECLEN]; X struct passwd *ptr, *getpwnam(); X X for (tail=name=dest+1; *tail != '/' && *tail != '\0'; ++tail) X ; X X if (*name == '\0' || *name == '/') X sprintf(buf,"%s%s",Home,tail); X else X { X tmp = *tail; X *tail = '\0'; X ptr = getpwnam(name); X *tail = tmp; X if (ptr == NULL) X { X sprintf(msg,"Can't interpret ~%s",name); X return(-1); X } X sprintf(buf,"%s%s",ptr->pw_dir,tail); X } X X strcpy(dest,buf); X return (0); X} X X/* X** transfer contents of a list of articles to a file. If Digest, this X** is simply a list of files. If not, it is a list of articles to be X** saved with vns_asave. Parses list destructively with X** strtok(). Return 0 for success, -1 for failure to open file. X** X** Called directly to copy a list of articles to a temp. file to X** direct to printer. X** X** NOTE: X** The msg argument only matters if Saveopen is not NULL. If so, it X** is non-NULL if *Saveopen is to be called, and points to the message X** buffer. Will be called with msg = NULL to fill temp. files rather X** than user named files. If *Saveopen is called, mode argument is X** actually returned by it, and only matters for vns_asave call. X*/ Xart_xfer(fn,list,mode,msg) Xchar *fn, *list, *mode, *msg; X{ X char *p; X FILE *fout, *fin; X int count; X char buf[RECLEN]; X char *strtok(); X X if (Saveopen != NULL && msg != NULL) X fout = (*Saveopen)(fn,msg,&mode); X else X fout = fopen(fn,mode); X if (fout == NULL) X return (-1); X X count = 0; X for (p = strtok(list,List_sep); p != NULL; p = strtok(NULL,List_sep)) X { X if (Digest) X { X if (Digsaver != NULL) X { X (*Digsaver)(p,fout,count,fn,mode); X ++count; X continue; X } X fin = fopen(p,"r"); X if (fin == NULL) X continue; X while (fgets(buf,RECLEN-1,fin) != NULL) X fputs(buf,fout); X fclose(fin); X continue; X } X vns_asave(atoi(p),fout,count,fn,mode); X ++count; X } X fclose(fout); X return(0); X} END_OF_FILE if test 4834 -ne `wc -c <'svart.c'`; then echo shar: \"'svart.c'\" unpacked with wrong size! fi # end of 'svart.c' fi if test -f 'term_set.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'term_set.c'\" else echo shar: Extracting \"'term_set.c'\" \(4953 characters\) sed "s/^X//" >'term_set.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** term_set.c - terminal control, hides termcap interface X** X** see copyright disclaimer / history in vn.c source file X*/ X X#include <stdio.h> X#include "tty.h" X#include "config.h" X#include "tune.h" X#include "node.h" X#include "page.h" X Xextern int L_allow, C_allow; Xextern char *Ku, *Kd, *Kl, *Kr; X Xstatic outc (c) Xchar c; X{ X putchar (c); X} X X/* X term_set controls terminal through termcap X START sets global parameters related to terminal also, X as well as allocating display buffer which depends on X terminal lines, and allocating escape strings. RESTART X simply re-issues the initialization - used following system X calls that could have goofed up the terminal state. X*/ X X/* X** Escape strings. X*/ X Xstatic char *Cm,*Cl,*So,*Se,*Te,*Bc,*Ce,*Ti,*Ks,*Ke; X#ifdef USEVS Xstatic char *Vs,*Ve; X#endif X Xstatic int Backspace; /* backspace works */ Xstatic int Overstrike; /* terminal overstrikes */ X Xstatic t_setup() X{ X char *tgetstr(), *vn_env(), *str_store(); X char *c, tc_buf[2048],optstr[2048]; X char *tvar; X X tvar = vn_env("TERM",DEF_TERM); X X c = optstr; X if (tgetent(tc_buf,tvar) != 1) X printex ("%s - unknown terminal",tvar); X X /* get needed capabilities */ X Cm = str_store(tgetstr("cm",&c)); X Cl = str_store(tgetstr("cl",&c)); X So = str_store(tgetstr("so",&c)); X Se = str_store(tgetstr("se",&c)); X Te = str_store(tgetstr("te",&c)); X Ti = str_store(tgetstr("ti",&c)); X Bc = str_store(tgetstr("bc",&c)); X Ce = str_store(tgetstr("ce",&c)); X Kd = str_store(tgetstr("kd",&c)); X Ke = str_store(tgetstr("ke",&c)); X Kl = str_store(tgetstr("kl",&c)); X Kr = str_store(tgetstr("kr",&c)); X Ks = str_store(tgetstr("ks",&c)); X Ku = str_store(tgetstr("ku",&c)); X#ifdef USEVS X Vs = str_store(tgetstr("vs",&c)); X Ve = str_store(tgetstr("ve",&c)); X#endif X Backspace = tgetflag("bs"); X Overstrike = tgetflag("os"); X X if ( *Cm == '\0' || *Cl == '\0') X { X printex ("cursor control and erase capability needed"); X } X X /* X ** Checks for arrow keys which don't issue something beginning X ** with <ESC>. This is more paranoid than we need to be, strictly X ** speaking - we could get away with any string which didn't X ** conflict with controls used for commands. However, that would X ** be a maintenance headache - we will simply reserve <ESC> as the X ** only char not to be used for commands, and punt on terminals X ** which don't send reasonable arrow keys. It would be confusing X ** to have keys work partially, also. I know of no terminal with X ** one arrow key beginning with an escape, and another beginning X ** with something else, but let's be safe. This also insists on X ** definitions for all 4 arrows, which seems reasonable. X */ X X if ((*Ku != '\0' && *Ku != '\033') || *Kl != *Ku || *Kr != *Ku || *Kd != *Ku) X { X fgprintf("WARNING: arrow keys will not work for this terminal"); X Ku = Kd = Kl = Kr = Kd = Ke = ""; X } X X if (Overstrike) X fgprintf ("WARNING: terminal overstrikes - can't update display without erase\n"); X X if ((L_allow = tgetnum("li")) < REQLINES) X { X if (L_allow < 0) X printex ("can't determine number of lines on terminal"); X printex ("too few lines for display - %d needed", REQLINES); X } X X /* X ** C_allow set so as to not use extreme right column. X ** Avoids "bad wraparound" problems - we're deciding it's best X ** to ALWAYS assume no automargin, and take care of it ourselves X */ X if((C_allow = tgetnum("co")) > MAX_C) X C_allow = MAX_C; X else X --C_allow; X if (C_allow < MIN_C) X { X if (C_allow < 0) X printex("can't determine number of columns on terminal."); X printex ("too few columns for display - %d needed",MIN_C); X } X X L_allow -= RECBIAS; X page_alloc(); X tputs(Ti,1,outc); X tputs(Ks,1,outc); X#ifdef USEVS X tputs(Vs,1,outc); X#endif X} X X/* VARARGS */ Xterm_set(cmd,x,y) Xint cmd,x,y; X{ X char *tgoto(); X int i; X switch (cmd) X { X case MOVE: X tputs (tgoto(Cm,x,y),1,outc); X break; X case ERASE: X tputs(Cl,1,outc); X break; X case ONREVERSE: X tputs(So,1,outc); X break; X case OFFREVERSE: X tputs(Se,1,outc); X break; X case START: X t_setup(); X break; X case RESTART: X tputs(Ti,1,outc); X tputs(Ks,1,outc); X#ifdef USEVS X tputs(Vs,1,outc); X#endif X break; X case STOP: X term_set (MOVE,0,L_allow+RECBIAS-1); X printf ("\n"); X tputs(Ke,1,outc); X tputs(Te,1,outc); X#ifdef USEVS X tputs(Ve,1,outc); X#endif X break; X case RUBSEQ: X if (Overstrike) X { X /* space overprint is futile */ X if (Backspace) X putchar('\010'); X else X tputs(Bc,1,outc); X break; X } X if (Backspace) X printf("%c %c",'\010','\010'); X else X { X tputs(Bc,1,outc); X putchar(' '); X tputs(Bc,1,outc); X } X break; X case ZAP: X if (Ce != NULL && *Ce != '\0') X tputs(Ce,1,outc); X else X { X if (Overstrike) X break; /* punt */ X for (i=x; i < y; ++i) X putchar(' '); X if (Backspace) X { X for (i=x; i < y; ++i) X putchar('\010'); X } X else X { X for (i=x; i < y; ++i) X tputs(Bc,1,outc); X } X } X break; X default: X printex ("term_set unknown code (%d)",cmd); X break; X } X return (0); X} END_OF_FILE if test 4953 -ne `wc -c <'term_set.c'`; then echo shar: \"'term_set.c'\" unpacked with wrong size! fi # end of 'term_set.c' fi if test -f 'tmpnam.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tmpnam.c'\" else echo shar: Extracting \"'tmpnam.c'\" \(420 characters\) sed "s/^X//" >'tmpnam.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** tmpnam.c - tmpnam() replacement for UCB, also uses non-generic name. X** X** see copyright disclaimer / history in vn.c source file X*/ X X#include <stdio.h> X#include "config.h" X Xchar *tmpnam (buf) Xchar *buf; X{ X static char *ptr = VNTEMPNAME; X X /* depends on string initialized above */ X sprintf (ptr+TMP_XOFFSET,"XXXXXX"); X X mktemp (ptr); X X if (buf != NULL) X strcpy (buf,ptr); X X return (ptr); X} END_OF_FILE if test 420 -ne `wc -c <'tmpnam.c'`; then echo shar: \"'tmpnam.c'\" unpacked with wrong size! fi # end of 'tmpnam.c' fi if test -f 'tty.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tty.h'\" else echo shar: Extracting \"'tty.h'\" \(451 characters\) sed "s/^X//" >'tty.h' <<'END_OF_FILE' X/* X** vn news reader. X** X** tty.h - codes for tty_set and term_set X** X** see copyright disclaimer / history in vn.c source file X*/ X X#define MOVE 100 X#define ERASE 101 X#define START 102 X#define STOP 103 X#define RUBSEQ 104 X#define ZAP 105 X#define ONREVERSE 106 X#define OFFREVERSE 107 X#define RESTART 108 X X#define RAWMODE 200 X#ifndef MINIX X#define COOKED 201 X#else X#define XCOOKED 201 X#endif X#define SAVEMODE 202 X#define RESTORE 203 X#define BACKSTOP 204 END_OF_FILE if test 451 -ne `wc -c <'tty.h'`; then echo shar: \"'tty.h'\" unpacked with wrong size! fi # end of 'tty.h' fi if test -f 'tty_set.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tty_set.c'\" else echo shar: Extracting \"'tty_set.c'\" \(2713 characters\) sed "s/^X//" >'tty_set.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** tty_set.c - interface to ioctl (system tty interface) X** X** see copyright disclaimer / history in vn.c source file X*/ X X#ifdef MINIX X/* Minix uses non-SysV type ioctls */ X#undef SYSV X#endif X X#ifdef SYSV X#include <termio.h> X#else X#include <sgtty.h> X#endif X X#include "tty.h" X Xextern char Erasekey,Killkey; X X#ifdef SYSV Xstatic struct termio C_tp, O_tp; X#else Xstatic struct sgttyb C_tp; Xstatic unsigned short O_lflag; X#endif X Xstatic unsigned S_flag=0; Xstatic int R_ignore=0; /* up/down counter of reset calls to ignore */ X X#define IO_GOT 1 /* have polled for original terminal mode */ X#define IO_RAW 2 /* in RAW (CBREAK actually) mode */ X X/* X tty_set handles ioctl calls. SAVEMODE, RESTORE are used around X system calls and interrupts to assure cooked mode, and restore X raw if raw on SAVEMODE. The pair results in no calls to ioctl X if we are cooked already when SAVEMODE is called, and may be nested, X provided we desire no "restore" of cooked mode after restoring raw. X X When we get the original terminal mode, we also save erase and kill. X X sig_set makes an ioctl call to get process group leader. Otherwise X ioctl calls should come through here. X*/ Xtty_set(cmd) Xint cmd; X{ X int rc; X unsigned mask; X X switch (cmd) X { X case BACKSTOP: X#ifdef JOBCONTROL X if ((rc = ioctl(1,TIOCLGET,&mask)) != 0) X break; X mask |= LTOSTOP; X rc = ioctl(1,TIOCLSET,&mask); X#else X rc = 0; X#endif X break; X case RAWMODE: X if ((S_flag & IO_RAW) != 0) X { X rc = 0; X break; X } X if ((S_flag & IO_GOT) == 0) X { X /* Save original modes, get erase / kill */ X#ifdef SYSV X rc = ioctl(0,TCGETA,&C_tp); X O_tp = C_tp; X Erasekey = C_tp.c_cc[VERASE]; X Killkey = C_tp.c_cc[VKILL]; X#else X rc = ioctl(0,TIOCGETP,&C_tp); X O_lflag = C_tp.sg_flags; X Erasekey = C_tp.sg_erase; X Killkey = C_tp.sg_kill; X#endif X } X#ifdef SYSV X C_tp.c_lflag &= ~(ECHO | ICANON); X C_tp.c_cc[VMIN] = 1; X rc = ioctl(0,TCSETAW,&C_tp); X#else X C_tp.sg_flags |= CBREAK; X C_tp.sg_flags &= ~ECHO; X rc = ioctl(0,TIOCSETP,&C_tp); X#endif X S_flag = IO_GOT|IO_RAW; X break; X#ifndef MINIX X case COOKED: X#else X case XCOOKED: X#endif X if ((S_flag & IO_RAW) != 0) X { X#ifdef SYSV X C_tp = O_tp; X rc = ioctl(0,TCSETAW,&C_tp); X#else X C_tp.sg_flags = O_lflag; X rc = ioctl(0,TIOCSETP,&C_tp); X#endif X S_flag &= ~IO_RAW; X } X else X rc = 0; X break; X case SAVEMODE: X if ((S_flag & IO_RAW) != 0) X { X#ifndef MINIX X tty_set(COOKED); X#else X tty_set(XCOOKED); X#endif X R_ignore = 0; X } X else X ++R_ignore; X rc = 0; X break; X case RESTORE: X if (R_ignore <= 0) X { X tty_set(RAWMODE); X } X else X --R_ignore; X rc = 0; X break; X default: X rc = -1; X } X if (rc < 0) X printex ("ioctl failure, tty_set: %d",cmd); X} END_OF_FILE if test 2713 -ne `wc -c <'tty_set.c'`; then echo shar: \"'tty_set.c'\" unpacked with wrong size! fi # end of 'tty_set.c' fi if test -f 'tune.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'tune.h'\" else echo shar: Extracting \"'tune.h'\" \(2198 characters\) sed "s/^X//" >'tune.h' <<'END_OF_FILE' X/* X** vn news reader. X** X** tune.h - system tuning parameters X** X** see copyright disclaimer / history in vn.c source file X*/ X X/* X** buffer size needed for tmpnam() X*/ X#ifndef L_tmpnam X#define L_tmpnam 48 X#endif X X/* X** hash table size. linked list type of table which can expand to X** arbitrary density, including densities > 100%. Number of entries X** will be number of newsgroups in active list. This should be a prime X** number ("long division" of string modulo table size hash function). X*/ X#define HASHSIZE 809 X X/* X** maximum number of columns on terminal. If made smaller, there X** will be a savings in the size of the temporary file used X** for holding displays, at the penalty of not being able to use X** the entire screen width on terminals actually possessing more X** columns than this. A block roughly on the order of this value X** times the number of lines the terminal has is maintained per page in X** the temp file, and read / written as displays are interacted X** with. MIN_C put here because MAX_C > MIN_C. MIN_C is the minumum X** number of columns for which a "reasonable" display can be produced. X** before making it smaller, look at all uses of C_allow and variable X** to see that a setting that small won't screw up array bounds. X*/ X#define MAX_C 132 X#define MIN_C 36 X X/* X** large size for general purpose local buffers. only used in automatic X** variable declarations. Used with fgets for buffer size when reading X** file records, to hold pathnames, commands, etc. Reduce if you blow X** out stack storage. If reduced too far, may eventually show up X** as syntax errors on interacting with vns_ routines, or command line X** botches. X*/ X#define RECLEN 1200 X X/* block sizes for allocation routines */ X#define STRBLKSIZE 1800 /* string storage allocation block */ X#define NDBLKSIZE 50 /* NODE structures to allocate at a time */ X X/* X** maximum number of articles to allow for processing in a single user X** list. Used only to declare an array of pointers on the stack, so it X** can be fair sized without much problem. In practicality, there is X** no use for it being larger than the greatest line length available X** on the CRT's being used. X*/ X#define MAXARTLIST 200 END_OF_FILE if test 2198 -ne `wc -c <'tune.h'`; then echo shar: \"'tune.h'\" unpacked with wrong size! fi # end of 'tune.h' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)