Path: tut!sunic!mcsun!uunet!munnari.oz.au!basser!ultima!nick From: nick@ultima.cs.uts.oz (Nick Andrew) Newsgroups: comp.os.minix Subject: Vn for Minix, part 1 of 4 Keywords: vn news usenet Message-ID: <16666@ultima.cs.uts.oz> Date: 26 Nov 89 11:27:59 GMT Organization: Comp Sci, NSWIT, Australia Lines: 1481 Since I've been using this Vn under Minix for over 6 months without problems, I thought it was time to post it to the net. This is the 4/88 version of Vn, as modified for Minix. Share and Enjoy ... Nick. "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) #! /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 'brk.h' <<'END_OF_FILE' X/* X** vn news reader. X** X** brk.h - codes for sig_set routine X** X** see copyright disclaimer / history in vn.c source file X*/ X X/* X state flags for handling breaks / values for sig_set calls. X BRK_IN, BRK_SESS, BRK_READ and BRK_OUT are the states. All X but BRK_INIT are used as calls to sig_set. BRK_RFIN indicates X a return from BRK_READ to BRK_SESS (no jump location passed), X*/ X#define BRK_INIT 0 /* initial value, indicating uncaught signals */ X#define BRK_IN 1 /* in NEWSRC / article scanning phase */ X#define BRK_SESS 2 /* in page interactive session */ X#define BRK_READ 3 /* reading articles */ X#define BRK_RFIN 4 /* finished reading, return to old mode */ X#define BRK_OUT 5 /* NEWSRC updating phase */ X X#define BRK_PR "really quit ? " END_OF_FILE if test 750 -ne `wc -c <'brk.h'`; then echo shar: \"'brk.h'\" unpacked with wrong size! fi # end of 'brk.h' fi if test -f 'config.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'config.h'\" else echo shar: Extracting \"'config.h'\" \(4479 characters\) sed "s/^X//" >'config.h' <<'END_OF_FILE' X/* X** vn news reader. X** X** config.h - system configuration parameters X** X** see copyright disclaimer / history in vn.c source file X*/ X X#define DEF_ED "/bin/mined" /* editor to use if no EDITOR variable */ X#define DEF_PS1 "$ " /* ! command prompt if no PS1 */ X#define DEF_SAVE "" /* save file */ X X#define DEF_PRINT "/usr/bin/lpr" /* print command */ X X#define DEF_CCFILE "author_copy" X#define DEF_KEYXLN ".vnkey" X X/* X** this is the "pre-typed" string the user will be presented with X** in answer to the "update" question following the QUIT command. X** Set to "" if you don't like it answering "yes" for you, or "y" X** if you only want to have to erase one character to say "no", etc. X*/ X#define QUIT_ANSWER "" X X/* X** default terminal assumed if TERM variable is unset. Since TERM has to X** be set for most UNIX tools, you probably want to make this something X** which will cause failure, unless EVERYBODY has the same kind of terminal X** or you don't really use a standard UNIX environment. X*/ X#define DEF_TERM "minix" X X/* X** foreground flag for messages. applies only if JOBCONTROL undefined X** (SYS V). set to 1 to see newsgroup messages, etc. during reading phase, X** 0 for "silent" operation - be warned that this may suppress some X** non-fatal diagnostic messages - find all references to fgprintf to X** see what is suppressed. X*/ X#define NOJOB_FG 1 X X/* X** bit mask for interpreting command characters. Set it to 0xff, and X** we should be able to handle 8 bit characters for control keys - X** leaving it 0x7f protects against possible parity bits in ascii X** characters. A lot of the general paranoia about character handling X** in raw mode comes from one of the earliest versions which was X** run on an amdahl using an IBM series 1 front end - it had a very X** brain damaged implementation of ioctl(). X*/ X#define CHMASK 0x7f X X/* X** arrow key treatment. If PAGEARROW is defined, right and left arrow X** keys will be synonyms for (next-page) and (previous). X** Otherwise, the right arrow will function as down, and the left as up. X** Made configurable because while there is no lateral motion on the screen X** to associate with the right and left arrows, you might not like them X** changing pages on you. X*/ X#define PAGEARROW X X/* X** if USEVS is defined, terminal initialization / exit for vn will include the X** "vs"/"ve" pair as well as "ti"/"te". This doesn't matter on a lot of X** terminals, but may make vn display behaviour closer to "vi" since vs/ve X** is vi's "visual mode" sequence. For instance, I believe the commonly X** used definitions for these strings on multi-page concepts allows the X** program to run in the first page of the terminal, preserving the more X** recent part of your session on exit X** X** #define USEVS X*/ X X/* X** temp file name template for mktemp(). Used in tmpnam.c, does not apply X** if you use a system library tmpnam(). BE CAREFUL - VNTEMPNAME MUST X** contain a string of 6 X's for mktemp() (actually, a place where 6 X's X** are intended to go). TMP_XOFFSET absolutely MUST point to the first of X** the X's. Yes, writing into a literal string is sloppy. To the best of X** my knowledge, tmpnam.c is the only place you'll find vn code doing it. X** We make this configurable in case you want temp files somewhere else. X*/ X#define VNTEMPNAME "/usr/tmp/vnXXXXXX" X#define TMP_XOFFSET 11 X X/* X** VNLOGFILE and VNSTATFILE. If these files EXIST, the corresponding data X** collection will be turned on. If they don't it will be turned off. X** To turn it back on again, create the files empty. Garbage in VNLOGFILE X** won't hurt collection but VNSTATFILE requires very strict syntax, so X** make sure its always an empty file or EXACTLY the right syntax. See stat.c X** X** VNLOGFILE logs user sessions. VNSTATFILE keeps a running breakdown X** of newsgroup activity. I add these with some hesitancy, as I find X** use of things like this for Gestapo-like purposes repugnant in the X** extreme. However, they can also be useful for system tuning purposes X** such as verifying what newsgroups are being read, and when load on X** the system due to newsreading is occurring. X** X** If VNLOGFILE and VNSTATFILE are NOT DEFINED, the code for doing logging X** and statistical collection will not be compiled in, saving some overhead, X** and avoiding calls to system functions like ctime() and time() which may X** have system dependent quirks. X** X*/ X#define VNLOGFILE "/usr/tmp/vn.log" X#define VNSTATFILE "/usr/tmp/vn.stat" END_OF_FILE if test 4479 -ne `wc -c <'config.h'`; then echo shar: \"'config.h'\" unpacked with wrong size! fi # end of 'config.h' fi if test -f 'config_std.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'config_std.h'\" else echo shar: Extracting \"'config_std.h'\" \(2802 characters\) sed "s/^X//" >'config_std.h' <<'END_OF_FILE' X/* X** default news poster X*/ X#define DEF_POST "/usr/lib/news/inews -h" X X/* X** default user .newsrc file X*/ X#define DEF_NEWSRC ".newsrc" X X/* X** If INLETTER is defined, the address line will be placed into the X** file editted by the user, and the mailer is assumed smart enough X** to understand about header lines in the file. Otherwise the X** address is part of the mailer's command line. X** X** if MAILSMART is defined, The From: line will be used for mail replies, X** or overridden by a "Reply-to:" line if present - "Path:" will be used X** as a last resort. If MAILSMART is not defined, "Path:" will simply be X** used. X** X** if MAILCHOOSE is defined, the user is prompted before edit with all X** of the address lines to choose from, or to input a new one. MAILCHOOSE X** makes MAILSMART irrelevant, but the two are independent of INLETTER. X** X*/ X#define MAILSMART X#define INLETTER X X/* X** default mail sender. If INLETTER, will be done as X** cat | DEF_MAIL, Otherwise, cat | DEF_MAIL
X** user's MAILER variable will have to conform, too. X*/ X#ifdef INLETTER X#define DEF_MAIL "/usr/lib/sendmail -t" X#else X#define DEF_MAIL "/bin/mail" X#endif X X/* OLDRC defined for an apparently earlier news version which took unnamed X** command line options as synonyms for -n, and did not take ranges in X** the .newsrc file. Probably useless, but kept in for historical reasons. X** X**#define OLDRC X*/ X X/* X** article spool directory X*/ X#define SPOOLDIR "/usr/spool/news" X X/* X** active file X*/ X#define ACTFILE "/usr/lib/news/active" X X/* X** maximum number of option lines in .newsrc X*/ X#define OPTLINES 20 X X/* X** maximum number of filter options X*/ X#define NUMFILTER 30 X X/* X** maximum number of file lines to search looking for header lines. X*/ X#define HDR_LINES 36 X X/* X** When a newsgroup is scanned, we ignore articles less than - X** MAXARTRANGE. This is intended to prevent ridiculous numbers of article X** opening attempts the first time a user reads a new newsgroup which has a X** huge difference between the high and low spool numbers, perhaps due to X** some articles not getting expired. X*/ X#define MAXARTRANGE 1600 /* about 2 weeks of soc.singles */ X X/* X** If we detect that the user has a higher number in .newsrc than the X** high article number, obviously the active file is out of synch with the X** .newsrc. We set the user's number back to the low article number in X** this case, on the theory that it's better to repeat stuff than miss X** articles. On such setbacks, we won't backdate the user by more than X** SYN_SETBACK articles, preventing floods of articles on large newsgroups X** if you don't define SYN_CHECK, the user's number won't be adjusted in X** this case, choosing to lose articles rather than show old ones. X*/ X#define SYN_CHECK X#define SYN_SETBACK 60 END_OF_FILE if test 2802 -ne `wc -c <'config_std.h'`; then echo shar: \"'config_std.h'\" unpacked with wrong size! fi # end of 'config_std.h' fi if test -f 'digest.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'digest.c'\" else echo shar: Extracting \"'digest.c'\" \(5681 characters\) sed "s/^X//" >'digest.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** digest.c - digest unpacking routines X** X** see copyright disclaimer / history in vn.c source file X*/ X X#include X#include "config.h" X#include "head.h" X#include "tune.h" X#include "node.h" X#include "page.h" X Xextern int Digest; Xextern int L_allow; Xextern int C_allow; Xextern PAGE Page; X Xextern FILE *vns_aopen(); X Xstatic char *Ext_pool = NULL; Xstatic char *Show[3]; X Xstatic char *Dhead = "Date: "; Xstatic char *Fhead = "From: "; Xstatic char *Lhead = "Lines: "; Xstatic char *Thead = "Subject: "; X X#define THDLEN 9 X#define LHDLEN 7 X#define FHDLEN 6 X#define DHDLEN 6 X Xdige_page (idx,skip) Xint idx; X{ X char name[24]; X FILE *fp; X int i,len,hl; X char subj[RECLEN],date[RECLEN],from[RECLEN],junk[RECLEN],*str_store(); X long pos; X ARTHEADER hdr; X X Digest = Page.b[idx].art_id; X X if ((fp = vns_aopen(Digest,&hdr)) == NULL) X return (-1); X X subj[0] = date[0] = from[0] = junk[0] = '\0'; X X /* skip over some articles if requested to */ X for (i=skip; i > 0; --i) X { X if (dig_advance(fp,from,subj,date,junk,&pos,&hl) < 0) X return (-1); X } X X for (i=0; i < L_allow && X (len = dig_advance(fp,from,subj,date,junk,&pos,&hl)) >= 0; ++i) X { X Page.b[i].art_id = i+1+skip; X Page.b[i].art_mark = ' '; X subj [C_allow] = '\0'; X from [C_allow] = '\0'; X sprintf (name,"%d",len); X form_title (date,subj,name,from,100); X strcpy (Page.b[i].art_t,date); X } X X vns_aclose (fp); X X if (i == 0) X return (-1); X X Page.h.artnum = i; X return (i); X} X X/* X returns name of file containing "article", NULL for failure X*/ Xchar * dige_extract (s,art,hdr,start) Xchar *s; Xint art; XARTHEADER *hdr; Xlong *start; X{ X FILE *fout,*fin; X long pos; X int lines,hl; X char subj[RECLEN],date[RECLEN],from[RECLEN],bufr[RECLEN]; X char extra[RECLEN]; X char *index(); X long ftell(); X char *str_tpool(), *str_tstore(); X X if (Ext_pool != NULL) X str_tfree(Ext_pool); X Ext_pool = str_tpool(3); X X if ((fin = vns_aopen(Digest,hdr)) == NULL) X return (NULL); X X for ( ; art > 0; --art) X { X from[0] = subj[0] = date[0] = '\0'; X if ((lines = dig_advance(fin,from,subj,date,extra,&pos,&hl)) < 0) X { X vns_aclose(fin); X return (NULL); X } X } X X tmpnam(s); X X if ((fout = fopen(s,"w")) == NULL) X { X vns_aclose(fin); X unlink (s); X return (NULL); X } X X fseek(fin,0L,0); X X hdr->show_num = 0; X hdr->show = Show; X hdr->lines = lines; X hdr->hlines = hl; X if (subj[0] != '\0') X { X sprintf (bufr,"%s%s",Thead,subj); X Show[hdr->show_num] = str_tstore(Ext_pool,bufr); X ++(hdr->show_num); X } X if (from[0] != '\0') X { X sprintf (bufr,"%s%s",Fhead,from); X Show[hdr->show_num] = str_tstore(Ext_pool,bufr); X ++(hdr->show_num); X } X if (date[0] != '\0') X { X sprintf (bufr,"%s%s",Dhead,date); X Show[hdr->show_num] = str_tstore(Ext_pool,bufr); X ++(hdr->show_num); X } X X while (fgets(bufr,RECLEN-1,fin) != NULL && bufr[0] != '\n') X { X if (strncmp(bufr,Fhead,FHDLEN) == 0) X { X fprintf (fout,"%s%s\n",Fhead,from); X continue; X } X if (strncmp(bufr,Thead,THDLEN) == 0) X { X fprintf (fout,"%s%s\n",Thead,subj); X continue; X } X if (strncmp(bufr,Dhead,DHDLEN) == 0) X { X fprintf (fout,"%s%s\n",Dhead,date); X continue; X } X /* defer line count header - it comes last */ X if (strncmp(bufr,Lhead,LHDLEN) == 0) X continue; X fprintf (fout,"%s",bufr); X } X X /* toss in extra header lines, line count header, extra newline */ X fprintf (fout,"%s%s%d\n\n",extra,Lhead,lines); X *start = ftell(fout); X X fseek (fin,pos,0); X X while (fgets(bufr,RECLEN-1,fin) != NULL && strncmp(bufr,"--------",8) != 0) X fprintf(fout,"%s",bufr); X X vns_aclose (fin); X fclose (fout); X return (s); X} X Xdig_list (s) Xchar *s; X{ X char *ptr,*out,*new,ns[L_tmpnam],tmp[RECLEN],*strtok(); X ARTHEADER hdr; X long pos; X int i; X X prinfo ("Extracting articles ....."); X strcpy (tmp,s); X out = s; X X for (ptr = strtok(tmp," "); ptr != NULL; ptr = strtok(NULL," ")) X { X i = atoi(ptr); X if ((new = dige_extract(ns,i,&hdr,&pos)) != NULL) X { X sprintf (out,"%s ",new); X out += strlen(new) + 1; X } X } X X *out = '\0'; X X if (*s == '\0') X strcpy (s,"NULLDIGEST"); X} X Xdig_ulist (s) Xchar *s; X{ X char *strtok(); X for (s = strtok(s," "); s != NULL; s = strtok(NULL," ")) X unlink (s); X} X X/* X returns # lines in article, -1 for failure X scans past article, returns position of start. X also returns "extra" header lines encountered, WITH newlines. X and counts total header lines. X*/ Xstatic dig_advance (fp,from,subj,date,extra,pos,hcount) XFILE *fp; Xchar *from,*subj,*date,*extra; Xlong *pos; Xint *hcount; X{ X char buf[RECLEN]; X char *ptr, *index(); X int len,state,lcount; X X *hcount = lcount = state = 0; X *extra = '\0'; X X while (fgets(buf,RECLEN-1,fp) != NULL) X { X buf[(len = strlen(buf) - 1)] = '\0'; X for (--len ; len >= 0 && buf[len] == ' ' || buf[len] == '\t'; --len) X buf[len] = '\0'; X ++len; X X switch(state) X { X case 0: X /* skip blank lines before header */ X if (len == 0) X break; X state = 1; /* fall through */ X case 1: X ++(*hcount); X if (strncmp(buf,Fhead,FHDLEN) == 0) X { X strcpy (from,buf+FHDLEN); X break; X } X if (strncmp(buf,Thead,THDLEN) == 0) X { X strcpy (subj,buf+THDLEN); X break; X } X if (strncmp(buf,Dhead,DHDLEN) == 0) X { X strcpy (date,buf+DHDLEN); X break; X } X /* put wierd header lines in extra */ X if ((ptr = index(buf,':')) != NULL) X { X *ptr = '\0'; X if (index(buf, ' ') == NULL) X { X *ptr = ':'; X sprintf(extra,"%s\n",buf); X extra += strlen(extra); X break; X } X *ptr = ':'; X } X state = 2; X --(*hcount); X X /* remember the newline we lopped off */ X *pos = ftell(fp)-strlen(buf)-1; /* fall through */ X case 2: X ++lcount; X if (strncmp("--------",buf,8) == 0) X { X --lcount; X return (lcount); X } X break; X } X } X X return (-1); X} END_OF_FILE if test 5681 -ne `wc -c <'digest.c'`; then echo shar: \"'digest.c'\" unpacked with wrong size! fi # end of 'digest.c' fi if test -f 'envir_set.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'envir_set.c'\" else echo shar: Extracting \"'envir_set.c'\" \(2900 characters\) sed "s/^X//" >'envir_set.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** envir_set.c - routine to obtain pertinent environment variable settings X** and set up file / directory names X** X** see copyright disclaimer / history in vn.c source file X*/ X X#include X#include X X#ifndef MINIX X/* minix does not have this */ X#include X#endif X X#include "tune.h" X#include "config.h" X#include "vn.h" X Xextern char *Editor, *Ps1, *Printer; Xextern char *Orgdir, *Savedir, *Ccfile; /* path names */ Xextern char Cxitop[], Cxitor[], Cxrtoi[], Cxptoi[]; Xextern char *Home; Xextern int More; X X#ifdef SYSV Xextern char *getcwd(); X#define getwd(a) getcwd(a,sizeof(a)) X#define MAXPATHLEN 240 X#else Xextern char *getwd(); X#endif X X/* X environment variable, original directory string setup. X*/ X Xenvir_set () X{ X char dbuf [MAXPATHLEN], *ccname, *keyxln; X char *vn_env(), *getcwd(), *str_store(); X struct passwd *ptr, *getpwuid(); X X vns_envir(); X More = 0; X X Ps1 = vn_env("PS1",DEF_PS1); X Editor = vn_env("EDITOR",DEF_ED); X Printer = vn_env("PRINTER",DEF_PRINT); X ccname = vn_env("CCFILE",DEF_CCFILE); X keyxln = vn_env("VNKEY",DEF_KEYXLN); X Savedir = vn_env("VNSAVE",NULL); X More = (strcmp(vn_env("MORE",""), "-c") == 0 ? TRUE : FALSE); X X /* X set original directory strings. X */ X X if ((ptr = getpwuid(getuid())) == NULL) X printex("Cannot obtain /etc/passwd entry"); X Home = str_store(ptr->pw_dir); X if ((Orgdir = getwd(dbuf)) == NULL) X printex ("cannot stat pwd"); X Orgdir = str_store (Orgdir); X if (Savedir == NULL) X Savedir = Orgdir; X if (*ccname != '/') X { X sprintf (dbuf, "%s/%s",Home,ccname); X Ccfile = str_store (dbuf); X } X else X Ccfile = str_store (ccname); X sprintf (dbuf, "%s/%s%s",Home,".vn","XXXXXX"); X X if (*keyxln != '/') X { X sprintf(dbuf, "%s/%s",Home,keyxln); X set_kxln(dbuf); X } X else X set_kxln(keyxln); X} X Xchar * Xvn_env(var,def) Xchar *var; Xchar *def; X{ X char pfx[RECLEN]; X char *res; X char *getenv(); X X if (var[0] != 'V' || var[1] != 'N') X { X sprintf(pfx,"VN%s",var); X if ((res = getenv(pfx)) != NULL) X return(res); X } X X if ((res = getenv(var)) != NULL) X return(res); X X return(def); X} X Xstatic Xset_kxln(fname) Xchar *fname; X{ X FILE *fp; X int i; X char bufr[80]; X char in,out,*ptr; X char *index(), xln_str(); X X for (i=0; i < CHMASK+1; ++i) X Cxitop[i] = Cxitor[i] = Cxptoi[i] = Cxrtoi[i] = i; X X if ((fp = fopen(fname,"r")) != NULL) X { X while(fgets(bufr,79,fp) != NULL) X { X if (strncmp(bufr+1,"==",2) == 0) X ptr = bufr+2; X else X ptr = index(bufr+1,'='); X if (ptr == NULL) X continue; X *ptr = '\0'; X ++ptr; X in = xln_str(bufr+1); X out = xln_str(ptr); X switch(bufr[0]) X { X case 'r': X case 'R': X Cxrtoi[out] = in; X Cxitor[in] = out; X break; X case 'p': X case 'P': X Cxptoi[out] = in; X Cxitop[in] = out; X default: X break; X } X } X fclose(fp); X } X} X Xstatic char Xxln_str(s) Xchar *s; X{ X if (*s < '0' || *s > '9') X return(*s & CHMASK); X return((char)(atoi(s) & CHMASK)); X} END_OF_FILE if test 2900 -ne `wc -c <'envir_set.c'`; then echo shar: \"'envir_set.c'\" unpacked with wrong size! fi # end of 'envir_set.c' fi if test -f 'getch.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'getch.c'\" else echo shar: Extracting \"'getch.c'\" \(2004 characters\) sed "s/^X//" >'getch.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** getch.c - character i/o routines X** X** see copyright disclaimer / history in vn.c source file X*/ X#include X#include X#include X#include "config.h" X#include "vn.h" X Xextern char Cxitop[]; Xextern char *Ku, *Kd, *Kr, *Kl; X X/* X getkey obtains user keystroke with count from leading X numerics, if any. Picks up arrow key sequences and maps X them to other keys. Also translates character through X Cxitop array since this routine is only used in session X loop. Saves untranslating arrow keys. X*/ Xgetkey (c) Xchar *c; X{ X int i, j; X static char ckseq[32]; X X#ifdef MINIX X fflush(stdout); X#endif X X /* Check for leading count */ X for (i = 0; isdigit(*c = getc(stdin) & CHMASK); i = i * 10 + *c - '0') X ; X X /* @#$!!! flakey front ends that won't map newlines in raw mode */ X if (*c == '\012' || *c == '\015') X *c = '\n'; X X /* @#$!!! flakey terminals which send control sequences for cursors! */ X if( *c == '\033' ) X { X /* X ** Check if part of cursor key input sequence X ** (pitch unknown escape sequences) X */ X j = 0; X ckseq[j] = *c; ckseq[j+1] = '\0'; X while(*c == Ku[j] || *c == Kd[j] || *c == Kl[j] || *c == Kr[j]) X { X if( strcmp(ckseq, Ku) == 0 ) { *c = UP; break; } X if( strcmp(ckseq, Kd) == 0 ) { *c = DOWN; break; } X#ifdef PAGEARROW X if( strcmp(ckseq, Kl) == 0 ) { *c = BACK; break; } X if( strcmp(ckseq, Kr) == 0 ) { *c = FORWARD; break; } X#else X if( strcmp(ckseq, Kl) == 0 ) { *c = UP; break; } X if( strcmp(ckseq, Kr) == 0 ) { *c = DOWN; break; } X#endif X *c = (getc(stdin) & CHMASK); X ckseq[++j] = *c; ckseq[j+1] = '\0'; X } X } X else X *c = Cxitop[*c]; X X if (i <= 0) X i = 1; X return (i); X} X X/* X get user key ignoring most controls. Used from reader and other X non-screen interactions. X*/ Xgetnoctl () X{ X char c; X X#ifdef MINIX X fflush(stdout); X#endif X while (iscntrl(c = getc(stdin) & CHMASK)) X { X if (c == '\015' || c == '\012') X c = '\n'; X if (c == '\n' || c == '\b' || c == '\t') X return (c); X } X return ((int) c); X} END_OF_FILE if test 2004 -ne `wc -c <'getch.c'`; then echo shar: \"'getch.c'\" unpacked with wrong size! fi # end of 'getch.c' fi if test -f 'hash.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'hash.c'\" else echo shar: Extracting \"'hash.c'\" \(1874 characters\) sed "s/^X//" >'hash.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** hash.c - hash table routines X** X** see copyright disclaimer / history in vn.c source file X*/ X X#include X#include "config.h" X#include "tune.h" X#include "node.h" X X/* X** hash table manipulation routines: X*/ X Xextern int Ncount; Xextern NODE **Newsorder; X Xstatic NODE *Tab [HASHSIZE]; /* hash Table */ X Xhashinit () X{ X int i; X for (i=0; i < HASHSIZE; ++i) X Tab[i] = NULL; X Ncount = 0; X} X X/* X enter new node (name s, articles n, low l) in hash Table, X initial flags = 0. Set order to -1. X*/ XNODE *hashenter(s,n,l) Xchar *s; Xint n; Xint l; X{ X char *str_store(); X NODE *ptr,*node_store(); X NODE *hashfind(); X int i; X X if ((ptr = hashfind(s)) != NULL) X { X fgprintf ("Warning: group %s encountered twice",s); X return (ptr); X } X X i=hash(s); X ptr = node_store(); X ptr->next = Tab[i]; X Tab[i] = ptr; X if (l > n) X l = n; X ++Ncount; X ptr->lownum = l; X ptr->state = 0; X ptr->data = NULL; X ptr->flags = 0; X ptr->highnum = n; X ptr->nd_name = str_store(s); X ptr->pgshwn = 0; X ptr->order = -1; X return (ptr); X} X XNODE *hashfind(s) Xchar *s; X{ X NODE *ptr; X X for (ptr = Tab[hash(s)]; ptr != NULL && strcmp(ptr->nd_name,s) != 0; X ptr = ptr->next) X ; X return (ptr); X} X Xmake_newsorder() X{ X char *malloc(); X int i; X NODE *ptr; X X if ((Newsorder = (NODE **) malloc(Ncount * sizeof(NODE *))) == NULL) X printex("Memory allocation failure - newsorder array"); X for (i=0; i < Ncount; ++i) X Newsorder[i] = NULL; X for (i=0; i < HASHSIZE; ++i) X { X for (ptr = Tab[i]; ptr != NULL; ptr = ptr->next) X { X if (ptr->order < 0 || ptr->order >= Ncount) X printex("News order range error"); X Newsorder[ptr->order] = ptr; X } X } X for (i=0; i < Ncount; ++i) X if (Newsorder[i] == NULL) X printex("News order duplication error"); X} X Xstatic hash (s) Xchar *s; X{ X unsigned rem; X for (rem=0; *s != '\0'; ++s) X rem = (rem*128 + (*s&0x7f)) % HASHSIZE; X return (rem); X} END_OF_FILE if test 1874 -ne `wc -c <'hash.c'`; then echo shar: \"'hash.c'\" unpacked with wrong size! fi # end of 'hash.c' fi if test -f 'head.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'head.h'\" else echo shar: Extracting \"'head.h'\" \(2530 characters\) sed "s/^X//" >'head.h' <<'END_OF_FILE' X/* X** vn news reader. X** X** head.h - header line structure X** X** see copyright disclaimer / history in vn.c source file X*/ X X/* X** How this thing works: X** X** this structure is filled in by vns_aopen when opening an article. X** lines & hlines items will be used in providing percentage read prompts X** X** show_num & show are the article information lines presented for the user X** when the "show headers" flag is turned off. X** X** from and artid are used for mail salutations, etc. X** X** The items used for mail replies, FOLLOWING the call to the mail massager X** if there is one, are mailcmd, mail_num, and mail. These are the items X** the massager should fill in. If no massager exists, vns_aopen will X** fill these in directly. If mail_err is non-null, the user won't be X** able to mail a reply to the article, and the item should be an error X** message explaining why. If there is a mailer function, the mailcmd X** item is not used. X** X** The priv and priv_num items are for sole use of the server layer in X** the mail massager, mailer and poster functions. X** X** The postcmd, post_num, and post arguments are used in treatment of X** followups. If post_err is non-null, followup won't be allowed, for X** the reason described therein. If there is a poster function, the X** postcmd item isn't used. X** X** The header lines for inclusion in mail / followup files will open X** the file, and will be followed by one blank line. The lines are literal - X** all appropriate headers should be prepended, etc. X** X** postcmd / mailcmd are used as format strings which are assumed to have a X** single %s in them some place for the placement of the users editted file. X** The result will be spawned as a command. X*/ X Xtypedef struct X{ X int lines; /* number of lines in article */ X int hlines; /* number of header lines in article */ X char *from; /* authors name */ X char *artid; /* article id */ X int show_num; /* number of extra lines for reader display */ X char **show; /* extra header lines */ X int priv_num; /* number of private arguments */ X char **priv; /* private server arguments */ X char *mail_err; /* mail reply error message */ X char *mailcmd; /* command line for mailer */ X int mail_num; /* number of header lines in mail reply file */ X char **mail; /* mail reply header lines */ X char *post_err; /* follow-up posting error message */ X char *postcmd; /* command line for followup poster */ X int post_num; /* number of header lines for followup file */ X char **post; /* followup header lines */ X} ARTHEADER; END_OF_FILE if test 2530 -ne `wc -c <'head.h'`; then echo shar: \"'head.h'\" unpacked with wrong size! fi # end of 'head.h' fi if test -f 'help.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'help.c'\" else echo shar: Extracting \"'help.c'\" \(6850 characters\) sed "s/^X//" >'help.c' <<'END_OF_FILE' X/* X** vn news reader. X** X** help.c - print help X** X** see copyright disclaimer / history in vn.c source file X*/ X#include X#include X#include "config.h" X#include "tty.h" X#include "tune.h" X#include "node.h" X#include "page.h" X#include "reader.h" X#include "vn.h" X Xextern int L_allow; Xextern int C_allow; Xextern int Digest; Xextern char *Contstr; Xextern char Cxptoi[], Cxrtoi[]; X Xextern int (*Hookfunc)(); Xextern char *(*Hookhelp)(); X X/* X Help message table. Character for command, plus its help X message. Table order is order of presentation to user. X*/ Xstatic struct HELPTAB X{ X char cmd, *msg; X int dig; X char *amsg; X} XHelptab [] = X{ X { QUIT, "quit", 1, NULL}, X { UP, "(or up arrow) move up [number of lines]", 1, NULL}, X { DOWN, "(or down arrow) move down [number of lines]", 1, NULL}, X#ifdef PAGEARROW X { BACK, "(or left arrow) previous page [number of pages]", 1, NULL}, X { FORWARD, "(or right arrow) next page [number of pages]", 1, NULL}, X#else X { BACK, "previous page [number of pages]", 1, NULL}, X { FORWARD, "next page [number of pages]", 1, NULL}, X#endif X { GRPBACK, "previous newsgroup [number of newsgroups]", 0, NULL }, X { GRPFORWARD, "next newsgroup [number of newsgroups]", 0, NULL }, X { TOPMOVE, "move to top of page", 1, NULL}, X { BOTMOVE, "move to bottom of page", 1, NULL}, X { ALTBOTTOM, "move to bottom of page (alternate L)", 1, NULL}, X { MIDMOVE, "move to middle of page", 1, NULL}, X { DIGEST, "unpack digest", 1, "exit digest"}, X { READ, "read article [number of articles]", 1, NULL}, X { ALTREAD, "read article (alternate 'r')", 1, NULL}, X { READALL, "read all articles on page", 1, NULL}, X { READSTRING, "specify articles to read", 1, NULL}, X { SAVE, "save or pipe article [number of articles]", 1, NULL}, X { SAVEALL, "save or pipe all articles on page", 1, NULL}, X { SAVESTRING, "specify articles to save", 1, NULL}, X { ALTSAVE, "specify articles to save (alternate ctl-s)", 1, NULL}, X { PRINT, "print article [number of articles]", 1, NULL}, X { PRINTALL, "print all article on page", 1, NULL}, X { PRINTSTRING, "specify articles to print", 1, NULL}, X { UPDATE, "update .newsrc status to cursor", 0, NULL}, X { UPALL, "update .newsrc status for whole newsgroup", 0, NULL}, X { UPSEEN, "update .newsrc status for all pages displayed", 0, NULL}, X { ORGGRP, "recover original .newsrc status for newsgroup", 0, NULL}, X { ORGSTAT, "recover all original .newsrc status", 0, NULL}, X { SSTAT, "display count of groups and pages - shown and total", 0, NULL}, X { GRPLIST, "list newsgroups with new article, updated counts", 0, NULL}, X { NEWGROUP, "specify newsgroup to display and/or resubscribe to", 1, NULL}, X { UNSUBSCRIBE, "unsubscribe from group", 0, NULL}, X { MARK, "mark/unmark article [number of articles]", 1, NULL}, X { ART_MARK, "mark/unmark article [number of articles]", 1, NULL}, X { UNMARK, "erase marks on articles", 1, NULL}, X { MARKSTRING, "specify articles to mark/unmark", 1, NULL}, X { HEADTOG, "toggle flag for display of headers when reading", 1, NULL}, X { SETROT, "toggle rotation for reading", 1, NULL}, X { REDRAW, "redraw screen", 1, NULL}, X { UNESC, "escape to UNIX to execute a command", 1, NULL}, X { PRTVERSION, "show vn version", 1, NULL}, X { HELP, "show this help menu", 1, NULL} X}; X X#define HTSIZE (sizeof(Helptab)/sizeof(struct HELPTAB)) X X X#define HHLINES 5 /* lines (CRs + 1) contained in HELP_HEAD */ X/* X help from main screen X*/ Xhelp () X{ X int i,lcount,lim; X char *hs; X char c; X X term_set (ERASE); X lim = L_allow + RECBIAS - 2; X printf("%s\n","[...] = effect of optional number preceding command\n"); X printf("%s\n","pipes are specified by filenames beginning with |\n"); X printf("%s\n","articles specified as a list of numbers, title search string, or\n"); X printf("%s\n"," * to specify marked articles. ! may be used to negate any\n"); X lcount = HHLINES; X for (i=0; i < HTSIZE; ++i) X { X if (Digest && !(Helptab[i].dig)) X continue; X if (Hookfunc != NULL && (*Hookfunc)(Helptab[i].cmd,0,0) >= 0) X continue; X ++lcount; X if (Digest && Helptab[i].amsg != NULL) X h_print (Cxptoi[Helptab[i].cmd],Helptab[i].amsg); X else X h_print (Cxptoi[Helptab[i].cmd],Helptab[i].msg); X if (lcount >= lim) X { X printf ("\n%s",Contstr); X getnoctl (); X term_set (MOVE,0,lim+1); X term_set (ZAP,0,strlen(Contstr)); X term_set (MOVE,0,lim-1); X putchar ('\n'); X lcount = 0; X } X } X if (Hookhelp != NULL) X { X for (hs=(*Hookhelp)(0,1,&c); X hs != NULL; hs = (*Hookhelp)(0,0,&c)) X { X ++lcount; X h_print (Cxptoi[c],hs); X if (lcount >= lim) X { X printf ("\n%s",Contstr); X getnoctl (); X term_set (MOVE,0,lim+1); X term_set (ZAP,0,strlen(Contstr)); X term_set (MOVE,0,lim-1); X putchar ('\n'); X lcount = 0; X } X } X } X if (lcount > 0) X { X printf ("\n%s",Contstr); X getnoctl (); X } X} X X/* X help from reader X*/ Xhelp_rd() X{ X char *hs; X char c; X X printf("\n"); /* "confused" tab expansion on first line */ X X hr_print (Cxrtoi[PG_NEXT],HPG_NEXT); X hr_print (Cxrtoi[PG_QUIT],HPG_QUIT); X hr_print (Cxrtoi[PG_FLIP],HPG_FLIP); X hr_print (Cxrtoi[PG_REWIND],HPG_REWIND); X hr_print (Cxrtoi[PG_WIND],HPG_WIND); X hr_print (Cxrtoi[PG_SEARCH],HPG_SEARCH); X hr_print (Cxrtoi[PG_STEP],HPG_STEP); X hr_print (Cxrtoi[PG_REPLY],HPG_REPLY); X hr_print (Cxrtoi[PG_FOLLOW],HPG_FOLLOW); X hr_print (Cxrtoi[SAVE],HPG_SAVE); X hr_print (Cxrtoi[PRINT],HPG_PRINT); X hr_print (Cxrtoi[SETROT],HPG_ROT); X hr_print (Cxrtoi[HEADTOG],HPG_HEAD); X hr_print (Cxrtoi[PG_HELP],HPG_HELP); X if (Hookhelp != NULL) X { X for (hs=(*Hookhelp)(1,1,&c); X hs != NULL; hs = (*Hookhelp)(1,0,&c)) X h_print (Cxrtoi[c],hs); X } X printf ("%s\n",HPG_DEF); X} X Xhr_print(c,msg) Xchar c; Xchar *msg; X{ X if (Hookfunc == NULL || (*Hookfunc)(c,1,0) < 0) X h_print(c,msg); X} X Xsrch_help(c,dig) Xchar c; Xint *dig; X{ X int i; X X for (i=0; i < HTSIZE; ++i) X if (Helptab[i].cmd == c) X break; X if (i < HTSIZE) X { X *dig = Helptab[i].dig; X return (0); X } X return(-1); X} X X/* X h_print prints a character and a legend for a help menu. X*/ Xstatic Xh_print(c,s) Xchar c,*s; X{ X if (strlen(s) > (C_allow - 14)) X s [C_allow - 14] = '\0'; X if (c > ' ' && c != '\177') X printf (" %c - %s\n",c,s); X else X { X switch (c) X { X case '\177': X printf (" - %s\n",s); X break; X case '\040': X printf (" - %s\n",s); X break; X case '\033': X printf (" - %s\n",s); X break; X case '\n': X printf (" - %s\n",s); X break; X case '\t': X printf (" - %s\n",s); X break; X case '\b': X printf (" - %s\n",s); X break; X case '\f': X printf (" - %s\n",s); X break; X case '\07': X printf (" - %s\n",s); X break; X case '\0': X printf (" - %s\n",s); X break; X default: X if (c < '\033') X { X c += 'a' - 1; X printf(" control-%c - %s\n",c,s); X } X else X printf(" %c0%o - %s\n",'\\',(int) c,s); X break; X } X } X} END_OF_FILE if test 6850 -ne `wc -c <'help.c'`; then echo shar: \"'help.c'\" unpacked with wrong size! fi # end of 'help.c' fi if test -f 'makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'makefile'\" else echo shar: Extracting \"'makefile'\" \(4377 characters\) sed "s/^X//" >'makefile' <<'END_OF_FILE' X# CFLAGS: X# set -DJOBCONTROL if you have job control (BSD). X# set -DSYSV -Dindex=strchr -Drindex=strrchr on Sytem V systems X# set -Dregfree=free if you DON'T include reg.s (SYSV + some BSD) X# X# JOBCONTROL could be done as #ifndef SYSV, I suppose, but this clearly X# marks that particular difference. X# X# LIBS: X# should point to any extra libraries needed, such as termcap. You X# may want to change this to use the curses termcap cover. If you need X# to pull in another library to get regex / regcmp or strtok on non-SYSV X# systems, you may want to put that here X# X# EXTRAOBJS: X# may be used to include tmpnam.s, strtok.s, reg.s in the list. X# X# These objects implement SYSV utilities for BSD machines. X# X# strtok.s implements strtok() / strpbrk(). reg.s implements regex()/regcmp() X# on top of the BSD regular expression library (regex() allows multiple X# regular expressions). tmpnam.s implements tmpnam() of course. X# X# If you have them, use your own regex/regcmp, because: X# X# i) They should be faster than the reg.c code, which X# recompiles the "current" ucb string every time you X# switch regular expressions. X# X# ii) I briefly checked out reg.c once, and it seemed to X# work. Our system has the "real" calls available, so I X# run with those. reg.c hasn't been used much by me, although X# I've had nobody tell me it doesn't work. X# X# if you DON'T include reg.s, be sure you set -Dregfree=free in CFLAGS. X# X# As with regex, if you have a system strtok(), it is likely more efficient - X# string routines will often be done in assembler on a given machine. X# X# Even if you have it, you can use tmpnam.s anyhow. This version will tailor X# the temp file name to vnXXXXXX, instead of a generic tmpXXXXXX. X# X# "vanilla" BSD: X#LIBS = -ltermcap X#EXTRAOBJS = tmpnam.s strtok.s reg.s X#CFLAGS = -O -DJOBCONTROL X# X# "vanilla" SYSV: X#LIBS = -ltermcap X#EXTRAOBJS = tmpnam.s X#CFLAGS = -O -DSYSV -Dregfree=free -Dindex=strchr -Drindex=strrchr X# X# BSD with strtok() / regex(), such as ULTRIX. These are the rules X# used for our installation (rtech is a microvax running ULTRIX): X#LIBS = -ltermcap X#EXTRAOBJS = tmpnam.s X#CFLAGS = -O -DJOBCONTROL -Dregfree=free X X# X# Minix!!! X# Regular expressions: Use reg.c to turn regcmp into re_comp X# and regex into re_exec. Use regcompat.c to turn re_comp into X# regcomp and re_exec into regexec. Wow! What a load of old X# cobblers. XLIBS = X#EXTRAOBJS = tmpnam.s strtok.s reg.s XEXTRAOBJS = tmpnam.s reg.s regcompat.s XCFLAGS = -F -O -DMINIX -DSYSV X X# SERVEROBJS defines the object(s) for the vns_xxxx "server" interface. X# X# std.s is the version for "standard" news, making use of the X# users .newsrc file, and resident articles / active file. X# XSERVEROBJS = std.s X X# normal vn objects X# XVNOBJS= hash.s envir_set.s pagefile.s reader.s storage.s sig_set.s \ Xterm_set.s tty_set.s userlist.s vn.s vnglob.s digest.s strings.s \ Xsession.s printex.s getch.s help.s newdisp.s stat.s svart.s X X# This is to force you to read the makefile. Once you have, comment this rule, X# and uncomment the "real" rule. At the minimum, you will also have to X# uncomment one of the three sets of LIBS / EXTRAOBJS & CFLAGS definitions X# above. X# X#vn: X# @echo "PLEASE READ THE MAKEFILE" Xvn: $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS) X cc -i -o vn $(VNOBJS) $(EXTRAOBJS) $(SERVEROBJS) $(LIBS) X Xdigest.s: digest.c config.h head.h node.h page.h tune.h Xenvir_set.s: envir_set.c config.h tune.h vn.h Xgetch.s: getch.c config.h vn.h Xhash.s: hash.c config.h node.h tune.h Xhelp.s: help.c config.h node.h page.h reader.h tty.h tune.h vn.h Xnewdisp.s: newdisp.c config.h node.h tty.h Xpagefile.s: pagefile.c node.h page.h tune.h Xprintex.s: printex.c config.h tty.h Xreader.s: reader.c config.h brk.h head.h node.h page.h reader.h \ X tty.h tune.h vn.h Xregcompat.s: regcompat.c Xsession.s: session.c config.h brk.h head.h node.h page.h tty.h tune.h \ X vn.h Xsig_set.s: sig_set.c config.h node.h page.h tty.h tune.h Xstat.s: stat.c config.h node.h Xstd.s: std.c config_std.h brk.h head.h server.h std.h Xstorage.s: storage.c node.h page.h tune.h Xstrings.s: strings.c node.h page.h tune.h Xsvart.s: svart.c config.h node.h page.h tty.h tune.h Xterm_set.s: term_set.c config.h node.h page.h tty.h tune.h Xtty_set.s: tty_set.c tty.h Xtmpnam.s: tmpnam.c config.h Xuserlist.s: userlist.c node.h page.h tune.h vn.h Xvn.s: vn.c node.h tty.h Xvnglob.s: vnglob.c config.h brk.h head.h node.h page.h tune.h END_OF_FILE if test 4377 -ne `wc -c <'makefile'`; then echo shar: \"'makefile'\" unpacked with wrong size! fi # end of 'makefile' fi echo shar: End of shell archive. exit 0 -- "Zeta Microcomputer Software" ACSnet: nick@nswitgould.cs.uts.oz nick@ultima.cs.uts.oz UUCP: ...!uunet!munnari!ultima.cs.uts.oz!nick Fidonet: Nick Andrew on 3:713/602 (Zeta)