2673 lines
56 KiB
Groff
2673 lines
56 KiB
Groff
Path: tut!sunic!mcsun!uunet!cs.utexas.edu!samsung!munnari.oz.au!basser!ultima!nick
|
||
From: nick@ultima.cs.uts.oz (Nick Andrew)
|
||
Newsgroups: comp.os.minix
|
||
Subject: Vn for Minix, part 5 of 5 (sorry)
|
||
Keywords: vn news usenet
|
||
Message-ID: <16672@ultima.cs.uts.oz>
|
||
Date: 27 Nov 89 21:27:37 GMT
|
||
Organization: Comp Sci, NSWIT, Australia
|
||
Lines: 2662
|
||
|
||
|
||
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)
|