rn version 4.1 distribution kit (part 3 of 8)
Larry Wall
lwall at sdcrdcf.UUCP
Tue Sep 25 09:49:59 AEST 1984
#! /bin/sh
# Make a new directory for the rn sources, cd to it, and run kits 1 thru 8
# through sh. When all 8 kits have been run, read README.
echo "This is rn kit 3 (of 8). If kit 3 is complete, the line"
echo '"'"End of kit 3 (of 8)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting art.c
cat >art.c <<'!STUFFY!FUNK!'
/* $Header: art.c,v 4.1 84/09/24 11:40:12 lwall Exp $
*
* $Log: art.c,v $
* Revision 4.1 84/09/24 11:40:12 lwall
* Real baseline.
*
* Revision 4.0.1.5 84/09/19 17:06:19 lwall
* Ifdef'ed some stuff that should have been.
*
* Revision 4.0.1.4 84/09/18 16:04:45 lwall
* Fixed INNERSEARCH commands.
*
* Revision 4.0.1.3 84/09/10 14:49:44 lwall
* Delinted.
*
* Revision 4.0.1.2 84/09/06 08:26:07 lwall
* Include util.h to define instr.
*
* Revision 4.0.1.1 84/09/05 17:07:19 lwall
* Treat restart correctly.
*
* Revision 4.0 84/09/04 09:49:21 lwall
* Baseline for netwide release
*
*/
#include "EXTERN.h"
#include "common.h"
#include "rn.h"
#include "ngstuff.h"
#include "head.h"
#include "cheat.h"
#include "help.h"
#include "search.h"
#include "artio.h"
#include "ng.h"
#include "bits.h"
#include "final.h"
#include "artstate.h"
#include "rcstuff.h"
#include "term.h"
#include "sw.h"
#include "util.h"
#include "backpage.h"
#include "intrp.h"
#include "INTERN.h"
#include "art.h"
/* page_switch() return values */
#define PS_NORM 0
#define PS_ASK 1
#define PS_RAISE 2
#define PS_TOEND 3
bool special = FALSE; /* is next page special length? */
int slines = 0; /* how long to make page when special */
ART_LINE highlight = -1; /* next line to be highlighted */
char *restart = Nullch; /* if nonzero, the place where last */
/* line left off on line split */
char *blinebeg; /* where in buffer current line began */
ART_POS alinebeg; /* where in file current line began */
#ifdef INNERSEARCH
ART_POS innersearch = 0; /* artpos of end of line we found */
/* for 'g' command */
ART_LINE isrchline = 0; /* last line to display */
bool hide_everything = FALSE;
/* if set, do not write page now, */
/* but refresh when done with page */
COMPEX gcompex; /* in article search pattern */
#endif
bool firstpage; /* is this the 1st page of article? */
void
art_init()
{
;
}
int
do_article()
{
register char *s;
ART_POS artsize; /* size in bytes of article */
char art_buf[LBUFLEN]; /* place for article lines */
bool hide_this_line = FALSE; /* hidden header line? */
ART_LINE linenum; /* line # on page, 1 origin */
#ifdef ULSMARTS
bool under_lining = FALSE;
/* are we underlining a word? */
#endif
register char *bufptr = art_buf;
/* pointer to input buffer */
register int outpos; /* column position of output */
static char prompt_buf[64]; /* place to hold prompt */
bool notesfiles = FALSE; /* might there be notesfiles junk? */
#ifdef INNERSEARCH
register int outputok;
#endif
if (fstat(artfp->_file,&filestat))
/* get article file stats */
return DA_CLEAN;
artsize = filestat.st_size;
/* from that get article size */
sprintf(prompt_buf,
"%%sEnd of article %ld (of %ld)--what next? [%%s]",
(long)art,(long)lastart); /* format prompt string */
prompt = prompt_buf;
int_count = 0; /* interrupt count is 0 */
firstpage = (topline < 0);
for (;;) { /* for each page */
assert(art == openart);
if (do_fseek) {
artpos = vrdary(artline);
if (artpos < 0)
artpos = -artpos; /* labs(), anyone? */
fseek(artfp,artpos,0);
if (artpos < htype[PAST_HEADER].ht_minpos)
in_header = SOME_LINE;
do_fseek = FALSE;
restart = Nullch;
}
if (firstpage) {
if (firstline) {
interp(art_buf,firstline);
fputs(art_buf,stdout);
}
else {
ART_NUM i;
printf("Article %ld",(long)art);
i = (((ART_NUM)toread[ng]) - 1 + was_read(art));
#ifdef DELAYMARK
if (i || dmcount) {
printf(" (%ld more",(long)i);
if (dmcount)
printf(" + %ld Marked to return)",(long)dmcount);
putchar(')');
}
#else
if (i)
printf(" (%ld more)",(long)i);
#endif
if (htype[NGS_LINE].ht_flags & HT_HIDE)
printf(" in %s", ngname);
fputs(":\n",stdout);
}
start_header(art);
forcelast = FALSE; /* we will have our day in court */
restart = Nullch;
artline = 0; /* start counting lines */
artpos = 0;
vwtary(artline,artpos); /* remember pos in file */
}
for (linenum=(firstpage?2:1);
in_header || (
#ifdef INNERSEARCH
innersearch ? innermore() :
#endif
linenum<(firstpage?initlines:(special?slines:LINES)) );
linenum++) { /* for each line on page */
if (int_count) { /* exit via interrupt? */
putchar('\n'); /* get to left margin */
int_count = 0; /* reset interrupt count */
return DA_NORM; /* skip out of loops */
}
if (restart) { /* did not finish last line? */
bufptr = restart; /* then start again here */
restart = Nullch; /* and reset the flag */
}
else { /* not a restart */
if (fgets(art_buf,LBUFLEN,artfp)==Nullch) {
/* if all done */
return DA_NORM; /* skip out of loops */
}
bufptr = art_buf; /* so start at beginning */
art_buf[LBUFLEN-1] = '\0';
/* make sure string ends */
}
blinebeg = bufptr; /* remember where we began */
alinebeg = artpos; /* both in buffer and file */
if (in_header && bufptr == art_buf)
hide_this_line =
parseline(art_buf,do_hiding,hide_this_line);
else if (notesfiles && do_hiding &&
bufptr == art_buf && *art_buf == '#' &&
isupper(art_buf[1]) && art_buf[2] == ':' ) {
fgets(art_buf,sizeof(art_buf),artfp);
if (index(art_buf,'!') != Nullch)
fgets(art_buf,sizeof(art_buf),artfp);
htype[PAST_HEADER].ht_minpos = ftell(artfp);
/* exclude notesfiles droppings */
hide_this_line = TRUE; /* and do not print either */
notesfiles = FALSE;
}
if (in_header && htype[in_header].ht_flags & HT_MAGIC) {
if (in_header == NGS_LINE) {
hide_this_line = (index(art_buf,',') == Nullch && do_hiding);
}
else if (in_header == EXPIR_LINE) {
if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE))
hide_this_line = (strlen(art_buf) < 10 && do_hiding);
}
}
if (in_header == SUBJ_LINE &&
htype[SUBJ_LINE].ht_flags & HT_MAGIC) {
/* is this the subject? */
int length;
length = strlen(art_buf)-1;
artline++;
art_buf[length] = '\0'; /* wipe out newline */
#ifdef NOFIREWORKS
no_ulfire();
#endif
notesfiles =
(instr(&art_buf[length-10]," - (nf") != Nullch);
if (oldsubject) {
length += 7;
fputs("(SAME) ",stdout);
oldsubject = FALSE;
}
if (length+UG > COLS) { /* rarely true */
linenum++;
vwtary(artline,vrdary(artline-1)+COLS);
artline++;
}
s = art_buf + 8;
*s++ = '\0'; /* make into 2 strings */
fputs(art_buf,stdout);
/* print up through : */
if (!UG)
putchar(' ');
underprint(s); /* print subject underlined */
putchar('\n'); /* and finish the line */
}
else if (hide_this_line) { /* do not print line? */
linenum--; /* compensate for linenum++ */
if (!in_header)
hide_this_line = FALSE;
}
else { /* just a normal line */
if (highlight==artline) { /* this line to be highlit? */
if (marking == STANDOUT) {
#ifdef NOFIREWORKS
if (erase_screen)
no_sofire();
#endif
standout();
}
else {
#ifdef NOFIREWORKS
if (erase_screen)
no_ulfire();
#endif
underline();
}
if (*bufptr == '\n')
putchar(' ');
}
#ifdef INNERSEARCH
outputok = !hide_everything;
/* get it into register, hopefully */
#endif
for (outpos = 0; outpos < COLS; ) {
/* while line has room */
if (*bufptr >= ' ') { /* normal char? */
#ifdef ULSMARTS
if (*bufptr == '_') {
if (bufptr[1] == '\b') {
if (!under_lining && highlight!=artline
#ifdef INNERSEARCH
&& outputok
#endif
) {
under_lining++;
if (UG) {
if (bufptr != buf &&
bufptr[-1] == ' ') {
outpos--;
backspace();
}
}
underline();
}
bufptr += 2;
}
}
else {
if (under_lining) {
under_lining = 0;
un_underline();
if (UG) {
if (*bufptr == ' ')
goto skip_put;
outpos++;
}
}
}
#endif
#ifdef INNERSEARCH
if (outputok)
#endif
{
#ifdef ROTATION
if (rotate && !in_header
&& isalpha(*bufptr)) {
if ((*bufptr & 31) <= 13)
putchar(*bufptr+13);
else
putchar(*bufptr-13);
}
else
#endif
putchar(*bufptr);
}
if (*UC && ((highlight==artline && marking == 1)
#ifdef ULSMARTS
|| under_lining
#endif
)) {
backspace();
underchar();
}
skip_put:
bufptr++;
outpos++;
}
else if (*bufptr == '\n' || !*bufptr) {
/* newline? */
#ifdef ULSMARTS
if (under_lining) {
under_lining = 0;
un_underline();
}
#endif
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH && outpos < COLS - 6) {
standout();
printf("%4d",artline);
un_standout();
}
#endif
#ifdef INNERSEARCH
if (outputok)
#endif
putchar('\n');
restart = 0;
outpos = 1000; /* signal normal \n */
}
else if (*bufptr == '\t') { /* tab? */
#ifdef INNERSEARCH
if (outputok)
#endif
putchar(*bufptr);
bufptr++;
outpos += 8 - outpos % 8;
}
else if (*bufptr == '\f') { /* form feed? */
#ifdef INNERSEARCH
if (outputok)
#endif
fputs("^L",stdout);
if (highlight != artline)
linenum = 32700;
/* how is that for a magic number? */
bufptr++;
outpos += 2;
}
else { /* other control char */
#ifdef INNERSEARCH
if (outputok)
#endif
{
putchar('^');
if (highlight == artline && *UC && marking == 1) {
backspace();
underchar();
putchar(*bufptr+64);
backspace();
underchar();
}
else
putchar(*bufptr+64);
}
bufptr++;
outpos += 2;
}
} /* end of column loop */
if (outpos < 1000) {/* did line overflow? */
restart = bufptr;
/* restart here next time */
if (AM) { /* automatic margins on tty? */
if (!XN && *bufptr == '\n')
/* need we simulate XN? */
restart = 0;
/* skip the newline */
}
else { /* cursor just hangs there */
#ifdef INNERSEARCH
if (outputok)
#endif
putchar('\n');
/* so move it down ourselves */
if (*bufptr == '\n')
restart = 0;
/* simulate XN if need be */
}
}
/* handle normal end of output line formalities */
if (highlight == artline) {
/* were we highlighting line? */
if (marking == STANDOUT)
un_standout();
else
un_underline();
highlight = -1; /* no more we are */
}
artline++; /* count the line just printed */
if (artline - LINES + 1 > topline)
/* did we just scroll top line off? */
topline = artline - LINES + 1;
/* then recompute top line # */
}
/* determine actual position in file */
if (restart) /* stranded somewhere in the buffer? */
artpos += restart - blinebeg;
/* just calculate position */
else /* no, ftell will do */
artpos = ftell(artfp);
/* so do ftell */
vwtary(artline,artpos); /* remember pos in file */
} /* end of line loop */
#ifdef INNERSEARCH
innersearch = 0;
if (hide_everything) {
hide_everything = FALSE;
*buf = Ctl('l');
goto fake_command;
}
#endif
if (linenum >= 32700)/* did last line have formfeed? */
vwtary(artline-1,-vrdary(artline-1));
/* remember by negating pos in file */
special = FALSE; /* end of page, so reset page length */
firstpage = FALSE; /* and say it is not 1st time thru */
/* extra loop bombout */
if (artpos == artsize) /* did we just now reach EOF? */
return DA_NORM; /* avoid --MORE--(100%) */
/* not done with this article, so pretend we are a pager */
reask_pager:
standout(); /* enter standout mode */
printf("--MORE--(%ld%%)",(long)(artpos*100/artsize));
un_standout(); /* leave standout mode */
fflush(stdout);
/* reinp_pager: /* unused, commented for lint */
eat_typeahead();
#ifdef DEBUGGING
if (debug & DEB_CHECKPOINTING) {
printf("(%d %d %d)",checkcount,linenum,artline);
fflush(stdout);
}
#endif
if (checkcount >= docheckwhen &&
linenum == LINES &&
(artline > 40 || checkcount >= docheckwhen+10) ) {
/* while he is reading a whole page */
/* in an article he is interested in */
checkcount = 0;
checkpoint_rc(); /* update .newsrc */
}
collect_subjects(); /* loads subject cache until */
/* input is pending */
getcmd(buf);
if (errno) {
if (LINES < 100 && !int_count)
*buf = '\f';/* on CONT fake up refresh */
else {
*buf = 'q'; /* on INTR or paper just quit */
}
}
putchar('\r'); /* put cursor at beginning of line */
erase_eol(); /* and erase the prompt */
fflush(stdout);
fake_command: /* used by innersearch */
/* parse and process pager command */
switch (page_switch()) {
case PS_ASK: /* reprompt "--MORE--..." */
goto reask_pager;
case PS_RAISE: /* reparse on article level */
return DA_RAISE;
case PS_TOEND: /* fast pager loop exit */
return DA_TOEND;
case PS_NORM: /* display more article */
break;
}
} /* end of page loop */
}
/* process pager commands */
int
page_switch()
{
register char *s;
switch (*buf) {
case 'd':
case Ctl('d'): /* half page */
special = TRUE;
slines = LINES / 2 + 1;
if (marking && *blinebeg != '\f') {
up_line();
highlight = --artline;
restart = blinebeg;
artpos = alinebeg;
}
return PS_NORM;
case '!': /* shell escape */
escapade();
return PS_ASK;
#ifdef INNERSEARCH
case Ctl('g'):
gline = 3;
compile(&gcompex,"^Subject:",TRUE,TRUE);
goto caseG;
case 'g': /* in-article search */
if (!finish_command(FALSE))/* get rest of command */
return PS_ASK;
s = buf+1;
if (isspace(*s))
s++;
if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) {
/* compile regular expression */
printf("\n%s\n",s);
return PS_ASK;
}
putchar('\r'); /* put cursor at beginning of line */
erase_eol(); /* and erase the prompt */
/* FALL THROUGH */
caseG:
case 'G': {
/* ART_LINE lines_to_skip = 0; */
ART_POS start_where;
if (gline < 0 || gline > LINES-2)
gline = LINES-2;
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("Start here? %d >=? %d\n",topline + gline + 1,artline);
#endif
if (topline+gline+1 >= artline)
start_where = artpos;
/* in case we had a line wrap */
else {
start_where = vrdary(topline+gline+1);
if (start_where < 0)
start_where = -start_where;
}
if (start_where < htype[PAST_HEADER].ht_minpos)
start_where = htype[PAST_HEADER].ht_minpos;
fseek(artfp,(long)start_where,0);
innersearch = 0; /* assume not found */
while (fgets(buf, sizeof buf, artfp) != Nullch) {
/* lines_to_skip++; NOT USED NOW */
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("Test %s",buf);
#endif
if (execute(&gcompex,buf) != Nullch) {
innersearch = ftell(artfp);
break;
}
}
if (!innersearch) {
fseek(artfp,artpos,0);
fputs("(Not found)",stdout);
return PS_ASK;
}
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos);
#endif
if (innersearch <= artpos) { /* already on page? */
if (innersearch < artpos) {
artline = topline+1;
while (vrdary(artline) < innersearch)
artline++;
}
highlight = artline - 1;
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("@ %d\n",highlight);
#endif
topline = highlight - gline;
if (topline < -1)
topline = -1;
*buf = '\f'; /* fake up a refresh */
innersearch = 0;
return page_switch();
}
else { /* who knows how many lines it is? */
do_fseek = TRUE;
hide_everything = TRUE;
}
return PS_NORM;
}
#else
case 'g': case 'G': case Ctl('g'):
notincl("g");
return PS_ASK;
#endif
case '\n': /* one line */
special = TRUE;
slines = 2;
return PS_NORM;
#ifdef ROTATION
case 'X':
rotate = !rotate;
/* FALL THROUGH */
#endif
case 'l':
case '\f': /* refresh screen */
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH) {
printf("Topline = %d",topline);
gets(buf);
}
#endif
clear();
do_fseek = TRUE;
artline = topline;
if (artline < 0)
artline = 0;
firstpage = (topline < 0);
return PS_NORM;
case 'b':
case Ctl('b'): { /* back up a page */
ART_LINE target;
clear();
do_fseek = TRUE; /* reposition article file */
target = topline - (LINES - 2);
artline = topline;
do {
artline--;
} while (artline >= 0 && artline > target &&
vrdary(artline-1) >= 0);
topline = artline;
/* remember top line of screen */
/* (line # within article file) */
if (artline < 0)
artline = 0;
firstpage = (topline < 0);
return PS_NORM;
}
case 'h': /* help */
help_page();
return PS_ASK;
case '\177':
case '\0': /* treat del,break as 'n' */
*buf = 'n';
/* FALL THROUGH */
case 'k': case 'K':
case 'n': case 'N': case Ctl('n'):
case 's': case 'S':
case 'u':
case 'w': case 'W':
case '|':
mark_as_read(art); /* mark article as read */
/* FALL THROUGH */
case '#':
case '$':
case '&':
case '-':
case '.':
case '/':
case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case '=':
case '?':
case 'c': case 'C':
case 'f': case 'F':
case 'j':
case Ctl('k'):
case 'm': case 'M':
case 'p': case 'P': case Ctl('p'):
case 'r': case 'R': case Ctl('r'):
case 'v':
case 'Y':
#ifndef ROTATION
case 'x': case 'X':
#endif
case Ctl('x'):
case '^':
#ifdef ROTATION
rotate = FALSE;
#endif
reread = FALSE;
do_hiding = TRUE;
if (index("nNpP",*buf) == Nullch &&
index("wWsS!&|/?123456789.",*buf) != Nullch) {
setdfltcmd();
standout(); /* enter standout mode */
printf(prompt,mailcall,dfltcmd);
/* print prompt, whatever it is */
un_standout(); /* leave standout mode */
putchar(' ');
fflush(stdout);
}
return PS_RAISE; /* and pretend we were at end */
#ifdef ROTATION
case 'x':
rotate = TRUE;
/* FALL THROUGH */
#endif
case 'y':
case ' ': /* continue current article */
if (erase_screen) { /* -e? */
clear(); /* clear screen */
if (*blinebeg != '\f') {
restart = blinebeg;
artline--; /* restart this line */
artpos = alinebeg;
if (marking) /* and mark repeated line */
highlight = artline;
}
topline = artline;
/* and remember top line of screen */
/* (line # within article file) */
}
else if (marking && *blinebeg != '\f') {
/* are we marking repeats? */
up_line(); /* go up one line */
highlight = --artline;/* and get ready to highlight */
restart = blinebeg; /* the old line */
artpos = alinebeg;
}
return PS_NORM;
case 'q': /* quit this article? */
do_hiding = TRUE;
return PS_TOEND;
default:
fputs(hforhelp,stdout);
return PS_ASK;
}
}
#ifdef INNERSEARCH
bool
innermore()
{
if (artpos < innersearch) { /* not even on page yet? */
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch);
#endif
return TRUE;
}
if (artpos == innersearch) { /* just got onto page? */
isrchline = artline; /* remember first line after */
highlight = artline - 1;
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,(long)innersearch,hide_everything,highlight);
#endif
if (hide_everything) { /* forced refresh? */
topline = highlight - gline;
if (topline < -1)
topline = -1;
return FALSE; /* let refresh do it all */
}
}
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline);
#endif
if (artline < isrchline + gline) {
return TRUE;
}
return FALSE;
}
#endif
!STUFFY!FUNK!
echo Extracting common.h
cat >common.h <<'!STUFFY!FUNK!'
/* $Header: common.h,v 4.1 84/09/24 11:44:27 lwall Exp $
*
* $Log: common.h,v $
* Revision 4.1 84/09/24 11:44:27 lwall
* Real baseline.
*
* Revision 4.0.1.6 84/09/22 16:51:29 lwall
* 2.10.2 inews moved.
*
* Revision 4.0.1.5 84/09/13 12:11:19 lwall
* UNLINK for Eunice.
*
* Revision 4.0.1.4 84/09/12 17:47:14 lwall
* Moved some includes here.
*
* Revision 4.0.1.3 84/09/10 15:09:09 lwall
* Delinted.
*
* Revision 4.0.1.2 84/09/05 13:48:13 lwall
* More LOCKART stuff.
*
* Revision 4.0.1.1 84/09/04 15:10:52 lwall
* LINKART option for poor Eunice sites.
*
* Revision 4.0 84/09/04 09:50:08 lwall
* Baseline for netwide release
*
*/
#include "config.h" /* generated by installation script */
#ifdef WHOAMI
# include <whoami.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#ifndef isalnum
# define isalnum(c) (isalpha(c) || isdigit(c))
#endif
#include <errno.h>
#include <signal.h>
#include <sys/ioctl.h>
#ifdef TERMIO
# include <termio.h>
#else
# include <sgtty.h>
#endif
#ifdef GETPWENT
# include <pwd.h>
#endif
#define BITSPERBYTE 8
#define TCSIZE 256 /* capacity for termcap strings */
#define LBUFLEN 512 /* line buffer length */
/* (don't worry, .newsrc lines can exceed this) */
#define CBUFLEN 256 /* command buffer length */
#ifdef pdp11
# define MAXFILENAME 128
#else
# define MAXFILENAME 512
#endif
#define LONGKEY 15 /* longest keyword: currently "posting-version" */
#define FINISHCMD 0177
/* some handy defs */
#define bool char
#define TRUE (1)
#define FALSE (0)
#define Null(t) ((t)0)
#define Nullch Null(char *)
#define Nullfp Null(FILE *)
#define Ctl(ch) (ch & 037)
#define strNE(s1,s2) (strcmp(s1,s2))
#define strEQ(s1,s2) (!strcmp(s1,s2))
#define strnNE(s1,s2,l) (strncmp(s1,s2,l))
#define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
/* Things we can figure out ourselves */
#ifdef SIGTSTP
# define BERKELEY /* include job control signals? */
#endif
#ifdef SIGPROF
# define BSD42 /* do we have Berkeley 4.2? */
#endif
#ifdef FIONREAD
# define PENDING
#else
# ifdef O_NDELAY
# define PENDING
# endif
#endif
#ifdef EUNICE
# define LINKART /* add 1 level of possible indirection */
# define UNLINK(victim) while (!unlink(victim))
#else
# define UNLINK(victim) unlink(victim)
#endif
/* Valid substitutions for strings marked with % comment are:
* %a Current article number
* %A Full name of current article (%P/%c/%a)
* (if LINKART defined, is the name of the real article)
* %b Destination of a save command, a mailbox or command
* %B The byte offset to the beginning of the article for saves
* with or without the header
* %c Current newsgroup, directory form
* %C Current newsgroup, dot form
* %d %P/%c
* %D Old Distribution: line
* %f Old From: line or Reply-To: line
* %F Newsgroups to followup to from Newsgroups: and Followup-To:
* %h Name of header file to pass to mail or news poster
* %H Host name (yours)
* %i Old Message-I.D.: line, with <>
* %l News administrator login name
* %L Login name (yours)
* %M Number of articles markd with M
* %n Newsgroups from source article
* %N Full name (yours)
* %o Organization (yours)
* %O Original working directory (where you ran rn from)
* %p Your private news directory (-d switch)
* %P Public news spool directory (SPOOLDIR)
* %r Last reference (parent article id)
* %R New references list
* %s Subject, with all Re's and (nf)'s stripped off
* %S Subject, with one Re stripped off
* %t New To: line derived from From: and Reply-To (Internet always)
* %T New To: line (Internet only if INTERNET is defined)
* %u Number of unread articles
* %U Number of unread articles disregarding current article
* %x News library directory, usually /usr/lib/news
* %X Rn library directory, usually %x/rn
* %~ Home directory
* %. Directory containing . files
* %$ current process number
* %{name} Environment variable "name". %{name-default} form allowed.
* %[name] Header line beginning with "Name: ", without "Name: "
* %(test_text=pattern?if_text:else_text)
* Substitute if_text if test_text matches pattern, otherwise
* substitute else_text. Use != for negated match.
* % substitutions are done on test_text, if_text, and else_text.
* (Note: %() only works if CONDSUB defined.)
* %digit Substitute the text matched by the nth bracket in the last
* pattern that had brackets. %0 matches the last bracket
* matched, in case you had alternatives.
*
* Put ^ in the middle to capitalize the first letter: %^C = Net.jokes
* Put ` in the middle to capitalize last component: %`c = net/Jokes
*
* ~ interpretation in filename expansion happens after % expansion, so
* you could put ~%{NEWSLOGNAME-news} and it will expand correctly.
*/
/* *** System Dependent Stuff *** */
/* NOTE: many of these are defined in the config.h file */
/* name of organization */
#ifndef ORGNAME
# define ORGNAME "ACME Widget Company, Widget Falls, Southern North Dakota"
#endif
#ifndef MBOXCHAR
# define MBOXCHAR 'F' /* how to recognize a mailbox by 1st char */
#endif
#ifndef ROOTID
# define ROOTID 0 /* uid of superuser */
#endif
#ifdef NORMSIG
# define sigset signal
# define sigignore(sig) signal(sig,SIG_IGN)
#endif
#ifndef LOGDIRFIELD
# define LOGDIRFIELD 6 /* Which field (origin 1) is the */
/* login directory in /etc/passwd? */
/* (If it is not kept in passwd, */
/* but getpwnam() returns it, */
/* define the symbol GETPWENT) */
#endif
#ifndef GCOSFIELD
# define GCOSFIELD 5
#endif
#ifndef NEGCHAR
# define NEGCHAR '!'
#endif
/* Space conservation section */
/* To save D space, cut down size of MAXRCLINE, NGMAX, VARYSIZE. */
#define MAXRCLINE 500 /* number of lines allowed in .newsrc */
/* several parallel arrays affected. */
/* (You can have more lines in the active file, */
/* just not in the .newsrc) */
#define HASHSIZ 547 /* should be prime, and at least MAXRCLINE + 10% */
#define NGMAX 100 /* number of newsgroups allowed on command line */
/* undefine ONLY symbol to disable "only" feature */
#define VARYSIZE 256 /* this makes a block 1024 bytes long in DECville */
/* (used by virtual array routines) */
/* Undefine any of the following features to save both I and D space */
/* In general, earlier ones are easier to get along without */
/* Pdp11's without split I and D may have to undefine them all */
#define DEBUGGING /* include debugging code */
#define SPEEDOVERMEM /* use more memory to run faster */
#define WORDERASE /* enable ^W to erase a word */
#define MAILCALL /* check periodically for mail */
#define NOFIREWORKS /* keep whole screen from flashing on certain */
/* terminals such as older Televideos */
#define VERIFY /* echo the command they just typed */
#define HASHNG /* hash newsgroup lines for fast lookup-- */
/* linear search used if not defined */
#define CONDSUB /* allow %(cond?text:text) */
#define ULSMARTS /* catch _^H in text and do underlining */
#define BAUDMOD /* allow baudrate modifier on switches */
#define GETLOGIN /* use getlogin() routine as backup to environment */
/* variables USER or LOGNAME */
#define ORGFILE /* if organization begins with /, look up in file */
#define TILDENAME /* allow ~logname expansion */
#define SETENV /* allow command line environment variable setting */
#define GETWD /* use our getwd() instead of piped in pwd */
#define SETUIDGID /* substitute eaccess() for access() so that rn */
/* can run setuid or setgid */
/* if not setuid or setgid, you don't need it */
#define MAKEDIR /* use our makedir() instead of shell script */
#define MEMHELP /* keep help messages in memory */
#define VERBOSE /* compile in more informative messages */
#define TERSE /* compile in shorter messages */
/* (Note: both VERBOSE and TERSE can be defined; -t
* sets terse mode. One or the other MUST be defined.
*/
#ifndef pdp11
# define CACHESUBJ /* cache subject lines in memory */
/* without this ^N still works but runs really slow */
/* but you save lots and lots of D space */
# define CACHEFIRST /* keep absolute first article numbers in memory */
/* cost: about 2k */
#endif
#define ROTATION /* enable x, X and ^X commands to work */
#define DELBOGUS /* ask if bogus newsgroups should be deleted */
#define RELOCATE /* allow newsgroup rearranging */
#define ESCSUBS /* escape substitutions in multi-character commands */
#define DELAYMARK /* allow articles to be temporarily marked as read */
/* until exit from current newsgroup or Y command */
#define MCHASE /* unmark xrefed articles on m or M */
#define MUNGHEADER /* allow alternate header formatting via */
/* environment variable ALTHEADER (not impl) */
#define ASYNC_PARSE /* allow parsing headers asyncronously to reading */
/* used by MCHASE and MUNGHEADER */
#define FINDNEWNG /* check for new newsgroups on startup */
#define FASTNEW /* do optimizations on FINDNEWNG for faster startup */
/* (this optimization can make occasional mistakes */
/* if a group is removed and another group of the */
/* same length is added, and if no softpointers are */
/* affected by said change.) */
#define INNERSEARCH /* search command 'g' with article */
#define CATCHUP /* catchup command at newsgroup level */
#define NGSEARCH /* newsgroup pattern matching */
#define ONLY /* newsgroup restrictions by pattern */
#define KILLFILES /* automatic article killer files */
#define ARTSEARCH /* pattern searches among articles */
/* /, ?, ^N, ^P, k, K */
/* some dependencies among options */
#ifndef ARTSEARCH
# undef KILLFILES
# undef INNERSEARCH
# undef CACHESUBJ
#endif
#ifndef DELAYMARK
# ifndef MCHASE
# ifndef MUNGHEADER
# undef ASYNC_PARSE
# endif
# endif
#endif
#ifndef SETUIDGID
# define eaccess access
#endif
#ifdef ONLY /* idiot lint doesn't grok #if */
# define NGSORONLY
#else
# ifdef NGSEARCH
# define NGSORONLY
# endif
#endif
#ifdef VERBOSE
# ifdef TERSE
# define IF(c) if (c)
# define ELSE else
# else !TERSE
# define IF(c)
# define ELSE
# endif
#else !VERBOSE
# ifndef TERSE
# define TERSE
# endif
# define IF(c) "IF" outside of VERBOSE???
# define ELSE "ELSE" outside of VERBOSE???
#endif
#ifndef DEBUGGING
# define NDEBUG
#endif
#include <assert.h>
#ifdef SPEEDOVERMEM
# define OFFSET(x) (x)
#else
# define OFFSET(x) ((x)-absfirst)
#endif
/* If you're strapped for space use the help messages in shell scripts */
/* if {NG,ART,PAGER,SUBS}HELP is undefined, help messages are in memory */
#ifdef MEMHELP /* undef MEMHELP above to get them all as sh scripts */
# undef NGHELP
# undef ARTHELP
# undef PAGERHELP
# undef SUBSHELP
#else
# ifndef NGHELP /* % and ~ */
# define NGHELP "%X/ng.help"
# endif
# ifndef ARTHELP /* % and ~ */
# define ARTHELP "%X/art.help"
# endif
# ifndef PAGERHELP /* % and ~ */
# define PAGERHELP "%X/pager.help"
# endif
# ifndef SUBSHELP /* % and ~ */
# define SUBSHELP "%X/subs.help"
# endif
#endif
/* Additional ideas:
* Make the do_newsgroup() routine a separate process.
* Keep .newsrc on disk instead of in memory.
* Overlays, if you have them.
* Get a bigger machine.
*/
/* End of Space Conservation Section */
/* More System Dependencies */
/* news library */
#ifndef LIB /* ~ and %l only ("~%l" is permissable) */
# define LIB "/usr/lib/news"
#endif
/* path to private executables */
#ifndef RNLIB /* ~, %x and %l only */
# define RNLIB "%x/rn"
#endif
/* where to find news files */
#ifndef SPOOL /* % and ~ */
# define SPOOL "/usr/spool/news"
#endif
/* file containing list of active newsgroups and max article numbers */
#ifndef ACTIVE /* % and ~ */
# define ACTIVE "%x/active"
#endif
/* command to setup a new .newsrc */
#ifndef NEWSETUP /* % and ~ */
# define NEWSETUP "newsetup"
#endif
/* command to display a list of un-subscribed-to newsgroups */
#ifndef NEWSGROUPS /* % and ~ */
# define NEWSGROUPS "newsgroups"
#endif
/* preferred shell for use in doshell routine */
/* ksh or sh would be okay here */
#ifndef PREFSHELL
# define PREFSHELL "/bin/csh"
#endif
/* path to fastest starting shell */
#ifndef SH
# define SH "/bin/sh"
#endif
/* path to default editor */
#ifndef DEFEDITOR
# define DEFEDITOR "/usr/ucb/vi"
#endif
/* location of full name */
#ifndef FULLNAMEFILE
# ifndef PASSNAMES
# define FULLNAMEFILE "%./fullname"
# endif
#endif
/* virtual array file name template */
#ifndef VARYNAME /* % and ~ */
# define VARYNAME "/tmp/rnvary.%$"
#endif
/* file to pass header to followup article poster */
#ifndef HEADNAME /* % and ~ */
# define HEADNAME "~/.rnhead"
/* or alternately #define HEADNAME "/tmp/rnhead.%$" */
#endif
#ifndef MAKEDIR
/* shell script to make n-deep subdirectories */
# ifndef DIRMAKER /* % and ~ */
# define DIRMAKER "%X/makedir"
# endif
#endif
/* location of newsrc file */
#ifndef RCNAME /* % and ~ */
# define RCNAME "%./.newsrc"
#endif
/* temporary newsrc file in case we crash while writing out */
#ifndef RCTNAME /* % and ~ */
# define RCTNAME "%./#.newsrc"
#endif
/* newsrc file at the beginning of this session */
#ifndef RCBNAME /* % and ~ */
# define RCBNAME "%./.oldnewsrc"
#endif
/* if existent, contains process number of current or crashed rn */
#ifndef LOCKNAME /* % and ~ */
# define LOCKNAME "%./.rnlock"
#endif
/* information from last invocation of rn */
#ifndef LASTNAME /* % and ~ */
# define LASTNAME "%./.rnlast"
#endif
/* file with soft pointers into the active file */
#ifndef SOFTNAME /* % and ~ */
# define SOFTNAME "%./.rnsoft"
#endif
/* list of article numbers to mark as unread later (see M and Y cmmands) */
#ifndef RNDELNAME /* % and ~ */
# define RNDELNAME "%./.rndelay"
#endif
/* a motd-like file for rn */
#ifndef NEWSNEWSNAME /* % and ~ */
# define NEWSNEWSNAME "%X/newsnews"
#endif
/* command to send a reply */
#ifndef MAILPOSTER /* % and ~ */
# define MAILPOSTER "Rnmail -h %h"
#endif
#ifndef MAILHEADER /* % */
# ifdef CONDSUB
# define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
# else
# define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
# endif
#endif
#ifndef YOUSAID /* % */
# define YOUSAID "In article %i you write:"
#endif
/* command to submit a followup article */
#ifndef NEWSPOSTER /* % and ~ */
# define NEWSPOSTER "Pnews -h %h"
#endif
#ifndef NEWSHEADER /* % */
# define NEWSHEADER "Newsgroups: %F\nSubject: Re: %S\nSummary: \nExpires: \nReferences: %R\nSender: \nReply-To: %L@%H.UUCP (%N)\nFollowup-To: \nDistribution: %D\nOrganization: %o\nKeywords: \n\n"
#endif
#ifndef ATTRIBUTION /* % */
# define ATTRIBUTION "In article %i %f writes:"
#endif
#ifndef PIPESAVER /* % */
# ifdef CONDSUB
# define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
# else
# define PIPESAVER "tail +%Bc %A | %b"
# endif
#endif
#ifndef NORMSAVER /* % and ~ */
# define NORMSAVER "%X/norm.saver %A %P %c %a %B %C \"%b\""
#endif
#ifndef MBOXSAVER /* % and ~ */
# ifdef CONDSUB
# define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From: %T %(%[posted]!=^$?%[posted]:%(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4))\""
/* header munging with a vengeance */
# else
# define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From: %T %[posted]\""
# endif
#endif
#ifdef MKDIRS
# ifndef SAVEDIR /* % and ~ */
# define SAVEDIR "%p/%c"
# endif
# ifndef SAVENAME /* % */
# define SAVENAME "%a"
# endif
#else
# ifndef SAVEDIR /* % and ~ */
# define SAVEDIR "%p"
# endif
# ifndef SAVENAME /* % */
# define SAVENAME "%^C"
# endif
#endif
#ifndef KILLGLOBAL /* % and ~ */
# define KILLGLOBAL "%p/KILL"
#endif
#ifndef KILLLOCAL /* % and ~ */
# define KILLLOCAL "%p/%c/KILL"
#endif
/* how to cancel an article */
#ifndef CANCEL
# ifdef MININACT /* 2.10.2 ? */
# define CANCEL "%x/inews -h < %h"
# else
# define CANCEL "inews -h < %h"
# endif
#endif
/* how to cancel an article, continued */
#ifndef CANCELHEADER
# define CANCELHEADER "Newsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nReply-To: %L@%H.UUCP (%N)\nDistribution: %D\nOrganization: %o\n\n%i cancelled from rn.\n"
#endif
/* where to find the mail file */
#ifndef MAILFILE
# define MAILFILE "/usr/spool/mail/%L"
#endif
/* some important types */
typedef int NG_NUM; /* newsgroup number */
typedef long ART_NUM; /* article number */
#ifdef pdp11
typedef short ART_UNREAD; /* ordinarily this should be long */
/* like ART_NUM, but assuming that */
/* we stay less than 32767 articles */
/* behind saves a lot of space. */
/* NOTE: do not make unsigned. */
#else
typedef long ART_UNREAD;
#endif
typedef long ART_POS; /* char position in article file */
typedef int ART_LINE; /* line position in article file */
typedef short ACT_POS; /* char position in active file */
typedef unsigned int MEM_SIZE; /* for passing to malloc */
/* *** end of the machine dependent stuff *** */
/* GLOBAL THINGS */
/* file statistics area */
EXT struct stat filestat;
/* various things of type char */
char *index();
char *rindex();
char *getenv();
char *strcat();
char *strcpy();
char *sprintf();
EXT char buf[LBUFLEN+1]; /* general purpose line buffer */
EXT char cmd_buf[CBUFLEN]; /* buffer for formatting system commands */
EXT char *indstr INIT(">"); /* indent for old article embedded in followup */
EXT char *cwd INIT(Nullch); /* current working directory */
EXT char *dfltcmd INIT(Nullch); /* 1st char is default command */
/* switches */
#ifdef DEBUGGING
EXT int debug INIT(0); /* -D */
# define DEB_INNERSRCH 32
# define DEB_FILEXP 64
# define DEB_HASH 128
# define DEB_XREF_MARKER 256
# define DEB_CTLAREA_BITMAP 512
# define DEB_SOFT_POINTERS 1024
# define DEB_NEWSRC_LINE 2048
# define DEB_SEARCH_AHEAD 4096
# define DEB_CHECKPOINTING 8192
# define DEB_FEED_XREF 16384
#endif
#ifdef ARTSEARCH
EXT int scanon INIT(0); /* -S */
#endif
EXT bool mbox_always INIT(FALSE); /* -M */
EXT bool norm_always INIT(FALSE); /* -N */
EXT bool checkflag INIT(FALSE); /* -c */
EXT bool suppress_cn INIT(FALSE); /* -s */
EXT int countdown INIT(5); /* how many lines to list before invoking -s */
EXT bool muck_up_clear INIT(FALSE); /* -loco */
EXT bool erase_screen INIT(FALSE); /* -e */
EXT bool findlast INIT(FALSE); /* -r */
EXT bool typeahead INIT(FALSE); /* -T */
#ifdef VERBOSE
# ifdef TERSE
EXT bool verbose INIT(TRUE); /* +t */
# endif
#endif
#ifdef VERIFY
EXT bool verify INIT(FALSE); /* -v */
#endif
#define NOMARKING 0
#define STANDOUT 1
#define UNDERLINE 2
EXT int marking INIT(NOMARKING); /* -m */
EXT ART_LINE initlines INIT(0); /* -i */
/* miscellania */
EXT bool in_ng INIT(FALSE); /* current state of rn */
EXT FILE *tmpfp INIT(Nullfp); /* scratch fp used for .rnlock, .rnlast, etc. */
EXT NG_NUM nextrcline INIT(0); /* 1st unused slot in rcline array */
/* startup to avoid checking twice in a row */
extern errno;
/* Factored strings */
EXT char nullstr[] INIT("");
EXT char sh[] INIT(SH);
EXT char defeditor[] INIT(DEFEDITOR);
EXT char hforhelp[] INIT("Type h for help.\n");
EXT char badcr[] INIT("\nUnnecessary CR ignored.\n");
EXT char readerr[] INIT("rn read error");
EXT char unsubto[] INIT("\n\nUnsubscribed to newsgroup %s\n");
#ifdef VERBOSE
EXT char nocd[] INIT("Can't chdir to directory %s\n");
#else
EXT char nocd[] INIT("Can't find %s\n");
#endif
!STUFFY!FUNK!
echo Extracting rcstuff.c
cat >rcstuff.c <<'!STUFFY!FUNK!'
/* $Header: rcstuff.c,v 4.1 84/09/24 12:05:08 lwall Exp $
*
* $Log: rcstuff.c,v $
* Revision 4.1 84/09/24 12:05:08 lwall
* Real baseline.
*
* Revision 4.0.1.7 84/09/22 17:01:33 lwall
* Suppressed soft pointer message on -c.
*
* Revision 4.0.1.6 84/09/18 16:39:18 lwall
* Instructed relocate_newsgroup() about ngmax[].
*
* Revision 4.0.1.5 84/09/13 12:05:28 lwall
* UNLINK for Eunice.
*
* Revision 4.0.1.4 84/09/10 15:24:22 lwall
* Delinted.
*
* Revision 4.0.1.3 84/09/10 08:30:24 lwall
* Newsgroup relocation now disables starthere optimization.
*
* Revision 4.0.1.2 84/09/06 13:13:51 lwall
* Turned = into L.
*
* Revision 4.0.1.1 84/09/05 09:31:26 lwall
* Made 'm' command force soft pointer writing.
*
* Revision 4.0 84/09/04 09:52:07 lwall
* Baseline for netwide release
*
*/
#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "ngdata.h"
#include "term.h"
#include "final.h"
#include "rn.h"
#include "intrp.h"
#include "only.h"
#include "rcln.h"
#include "INTERN.h"
#include "rcstuff.h"
char *rcname INIT(Nullch); /* path name of .newsrc file */
char *rctname INIT(Nullch); /* path name of temp .newsrc file */
char *rcbname INIT(Nullch); /* path name of backup .newsrc file */
char *softname INIT(Nullch); /* path name of .rnsoft file */
FILE *rcfp INIT(Nullfp); /* .newsrc file pointer */
#ifdef HASHNG
short hashtbl[HASHSIZ];
#endif
bool
rcstuff_init()
{
register NG_NUM newng;
register char *s;
register int i;
register bool foundany = FALSE;
char *some_buf;
long length;
#ifdef HASHNG
for (i=0; i<HASHSIZ; i++)
hashtbl[i] = -1;
#endif
/* make filenames */
rcname = savestr(filexp(RCNAME));
rctname = savestr(filexp(RCTNAME));
rcbname = savestr(filexp(RCBNAME));
softname = savestr(filexp(SOFTNAME));
/* make sure the .newsrc file exists */
newsrc_check();
/* open .rnsoft file containing soft ptrs to active file */
tmpfp = fopen(softname,"r");
if (tmpfp == Nullfp)
writesoft = TRUE;
/* read in the .newsrc file */
for (nextrcline = 0;
(some_buf = get_a_line(buf,LBUFLEN,rcfp)) != Nullch;
nextrcline++) {
/* for each line in .newsrc */
char tmpbuf[10];
newng = nextrcline; /* get it into a register */
length = len_last_line_got; /* side effect of get_a_line */
if (length <= 1) { /* only a newline??? */
nextrcline--; /* compensate for loop increment */
continue;
}
if (newng >= MAXRCLINE) { /* check for overflow */
fputs("Too many lines in .newsrc\n",stdout);
finalize(1);
}
if (tmpfp != Nullfp && fgets(tmpbuf,10,tmpfp) != Nullch)
softptr[newng] = atoi(tmpbuf);
else
softptr[newng] = 0;
some_buf[--length] = '\0'; /* wipe out newline */
if (some_buf == buf) {
rcline[newng] = savestr(some_buf);
/* make a semipermanent copy */
}
else {
/*NOSTRICT*/
some_buf = saferealloc(some_buf,(MEM_SIZE)(length+1));
rcline[newng] = some_buf;
}
#ifdef NOTDEF
if (strnEQ(some_buf,"to.",3)) { /* is this a non-newsgroup? */
nextrcline--; /* destroy this line */
continue;
}
#endif
if (*some_buf == ' ' ||
*some_buf == '\t' ||
strnEQ(some_buf,"options",7)) { /* non-useful line? */
toread[newng] = TR_JUNK;
rcchar[newng] = ' ';
rcnums[newng] = 0;
continue;
}
for (s = rcline[newng]; *s && *s != ':' && *s != NEGCHAR; s++) ;
if (!*s) {
rcline[newng] = saferealloc(rcline[newng],(MEM_SIZE)length+2);
s = rcline[newng] + length;
*s = ':';
*(s+1) = '\0';
}
rcchar[newng] = *s; /* salt away the : or ! */
rcnums[newng] = (char)(s - rcline[newng]);
rcnums[newng]++; /* remember where it was */
*s = '\0'; /* null terminate newsgroup name */
#ifdef HASHNG
if (!checkflag)
sethash(newng);
#endif
if (rcchar[newng] == NEGCHAR) {
toread[newng] = TR_UNSUB;
continue;
}
/* now find out how much there is to read */
if (!inlist(buf) || (suppress_cn && foundany && !paranoid))
toread[newng] = TR_NONE; /* no need to calculate now */
else
set_toread(newng);
#ifdef VERBOSE
if (!checkflag && softmisses == 1) {
softmisses++; /* lie a little */
fputs("(Revising soft pointers--be patient.)\n",stdout);
}
#endif
if (toread[newng] > TR_NONE) { /* anything unread? */
if (!foundany) {
starthere = newng;
foundany = TRUE; /* remember that fact*/
}
if (suppress_cn) { /* if no listing desired */
if (checkflag) { /* if that is all they wanted */
finalize(1); /* then bomb out */
}
}
else {
#ifdef VERBOSE
IF(verbose)
printf("Unread news in %-20s %5ld article%s\n",
rcline[newng],(long)toread[newng],
toread[newng]==TR_ONE ? nullstr : "s");
ELSE
#endif
#ifdef TERSE
printf("%s: %ld article%s\n",
rcline[newng],(long)toread[newng],
toread[newng]==TR_ONE ? nullstr : "s");
#endif
if (int_count) {
countdown = 1;
int_count = 0;
}
if (countdown) {
if (! --countdown) {
fputs("etc.\n",stdout);
if (checkflag)
finalize(1);
suppress_cn = TRUE;
}
}
}
}
}
fclose(rcfp); /* close .newsrc */
if (tmpfp != Nullfp)
fclose(tmpfp); /* close .rnsoft */
if (paranoid)
cleanup_rc();
if (checkflag) { /* were we just checking? */
finalize(foundany); /* tell them what we found */
}
#ifdef DEBUGGING
if (debug & DEB_HASH) {
page_line = 1;
for (i=0; i<HASHSIZ; i++) {
sprintf(buf,"%d %d",i,hashtbl[i]);
print_lines(buf,NOMARKING);
}
}
#endif
return foundany;
}
/* try to find or add an explicitly specified newsgroup */
/* returns TRUE if found or added, FALSE if not. */
/* assumes that we are chdir'ed to SPOOL */
bool
get_ng(what,do_reloc)
char *what;
bool do_reloc;
{
char *ntoforget;
char promptbuf[128];
#ifdef VERBOSE
IF(verbose)
ntoforget = "Type n to forget about this newsgroup.\n";
ELSE
#endif
#ifdef TERSE
ntoforget = "n to forget it.\n";
#endif
set_ngname(what);
ng = find_ng(ngname);
if (ng == nextrcline) { /* not in .newsrc? */
if (eaccess(ngdir,0)) {
#ifdef VERBOSE
IF(verbose)
printf("\n\007Newsgroup %s does not exist!\n",ngname);
ELSE
#endif
#ifdef TERSE
printf("\n\007No %s!\n",ngname);
#endif
sleep(2);
return FALSE;
}
#ifdef VERBOSE
IF(verbose)
sprintf(promptbuf,"\nNewsgroup %s not in .newsrc--add? [yn] ",ngname);
ELSE
#endif
#ifdef TERSE
sprintf(promptbuf,"\nAdd %s? [yn] ",ngname);
#endif
reask_add:
in_char(promptbuf);
putchar('\n');
setdef(buf,"y");
#ifdef VERIFY
printcmd();
#endif
if (*buf == 'h') {
#ifdef VERBOSE
IF(verbose)
printf("Type y or SP to add %s to your .newsrc.\n", ngname);
ELSE
#endif
#ifdef TERSE
fputs("y or SP to add\n",stdout);
#endif
fputs(ntoforget,stdout);
goto reask_add;
}
else if (*buf == 'n' || *buf == 'q') {
return FALSE;
}
else if (*buf == 'y') {
ng = add_newsgroup(ngname);
do_reloc = FALSE;
}
else {
fputs(hforhelp,stdout);
goto reask_add;
}
}
else if (rcchar[ng] == NEGCHAR) { /* unsubscribed? */
#ifdef VERBOSE
IF(verbose)
sprintf(promptbuf,
"\nNewsgroup %s is currently unsubscribed to--resubscribe? [yn] ",ngname);
ELSE
#endif
#ifdef TERSE
sprintf(promptbuf,"\n%s unsubscribed--resubscribe? [yn] ",ngname);
#endif
reask_unsub:
in_char(promptbuf);
putchar('\n');
setdef(buf,"y");
#ifdef VERIFY
printcmd();
#endif
if (*buf == 'h') {
#ifdef VERBOSE
IF(verbose)
printf("Type y or SP to resubscribe to %s.\n", ngname);
ELSE
#endif
#ifdef TERSE
fputs("y or SP to resubscribe.\n",stdout);
#endif
fputs(ntoforget,stdout);
goto reask_unsub;
}
else if (*buf == 'n' || *buf == 'q') {
return FALSE;
}
else if (*buf == 'y') {
rcchar[ng] = ':';
}
else {
fputs(hforhelp,stdout);
goto reask_unsub;
}
}
/* now calculate how many unread articles in newsgroup */
set_toread(ng);
#ifdef RELOCATE
if (do_reloc)
ng = relocate_newsgroup(ng,-1);
#endif
return toread[ng] >= TR_NONE;
}
/* add a newsgroup to the .newsrc file (eventually) */
NG_NUM
add_newsgroup(ngn)
char *ngn;
{
register NG_NUM newng = nextrcline++;
/* increment max rcline index */
rcnums[newng] = strlen(ngn) + 1;
rcline[newng] = safemalloc((MEM_SIZE)(rcnums[newng] + 1));
strcpy(rcline[newng],ngn); /* and copy over the name */
*(rcline[newng] + rcnums[newng]) = '\0';
rcchar[newng] = ':'; /* call it subscribed */
toread[newng] = TR_NONE; /* just for prettiness */
#ifdef HASHNG
sethash(newng); /* so we can find it again */
#endif
#ifdef RELOCATE
return relocate_newsgroup(newng,-1);
#else
return newng;
#endif
}
#ifdef RELOCATE
NG_NUM
relocate_newsgroup(ngx,newng)
NG_NUM ngx;
NG_NUM newng;
{
char *dflt = (ngx!=current_ng ? "$^.L" : "$^L");
char *tmprcline;
ART_UNREAD tmptoread;
char tmprcchar;
char tmprcnums;
ACT_POS tmpsoftptr;
register NG_NUM i;
#ifdef DEBUGGING
ART_NUM tmpngmax;
#endif
starthere = 0; /* Disable this optimization */
writesoft = TRUE; /* Update soft pointer file */
if (ngx < nextrcline-1) {
#ifdef HASHNG
for (i=0; i<HASHSIZ; i++) {
if (hashtbl[i] > ngx)
--hashtbl[i];
else if (hashtbl[i] == ngx)
hashtbl[i] = nextrcline-1;
}
#endif
tmprcline = rcline[ngx];
tmptoread = toread[ngx];
tmprcchar = rcchar[ngx];
tmprcnums = rcnums[ngx];
tmpsoftptr = softptr[ngx];
#ifdef DEBUGGING
tmpngmax = ngmax[ngx];
#endif
for (i=ngx+1; i<nextrcline; i++) {
rcline[i-1] = rcline[i];
toread[i-1] = toread[i];
rcchar[i-1] = rcchar[i];
rcnums[i-1] = rcnums[i];
softptr[i-1] = softptr[i];
#ifdef DEBUGGING
ngmax[i-1] = ngmax[i];
#endif
}
rcline[nextrcline-1] = tmprcline;
toread[nextrcline-1] = tmptoread;
rcchar[nextrcline-1] = tmprcchar;
rcnums[nextrcline-1] = tmprcnums;
softptr[nextrcline-1] = tmpsoftptr;
#ifdef DEBUGGING
ngmax[nextrcline-1] = tmpngmax;
#endif
}
if (current_ng > ngx)
current_ng--;
if (newng < 0) {
reask_reloc:
#ifdef VERBOSE
IF(verbose)
printf("\nPut newsgroup where? [%s] ", dflt);
ELSE
#endif
#ifdef TERSE
printf("\nPut where? [%s] ", dflt);
#endif
fflush(stdout);
reinp_reloc:
eat_typeahead();
getcmd(buf);
if (errno || *buf == '\f') {
/* if return from stop signal */
goto reask_reloc; /* give them a prompt again */
}
setdef(buf,dflt);
#ifdef VERIFY
printcmd();
#endif
if (*buf == 'h') {
#ifdef VERBOSE
IF(verbose) {
printf("\n\n\
Type ^ to put the newsgroup first (position 0).\n\
Type $ to put the newsgroup last (position %d).\n", nextrcline-1);
printf("\
Type . to put it before the current newsgroup (position %d).\n", current_ng);
printf("\
Type -newsgroup name to put it before that newsgroup.\n\
Type +newsgroup name to put it after that newsgroup.\n\
Type a number between 0 and %d to put it at that position.\n", nextrcline-1);
printf("\
Type L for a listing of newsgroups and their positions.\n");
}
ELSE
#endif
#ifdef TERSE
{
printf("\n\n\
^ to put newsgroup first (pos 0).\n\
$ to put last (pos %d).\n", nextrcline-1);
printf("\
. to put before current newsgroup (pos %d).\n", current_ng);
printf("\
-newsgroup to put before newsgroup.\n\
+newsgroup to put after.\n\
number in 0-%d to put at that pos.\n", nextrcline-1);
printf("\
L for list of .newsrc.\n");
}
#endif
goto reask_reloc;
}
else if (*buf == 'L') {
putchar('\n');
list_newsgroups();
goto reask_reloc;
}
else if (isdigit(*buf)) {
if (!finish_command(TRUE)) /* get rest of command */
goto reinp_reloc;
newng = atoi(buf);
if (newng < 0)
newng = 0;
if (newng >= nextrcline)
return nextrcline-1;
}
else if (*buf == '^') {
putchar('\n');
newng = 0;
}
else if (*buf == '$') {
putchar('\n');
return nextrcline-1;
}
else if (*buf == '.') {
putchar('\n');
newng = current_ng;
}
else if (*buf == '-' || *buf == '+') {
if (!finish_command(TRUE)) /* get rest of command */
goto reinp_reloc;
newng = find_ng(buf+1);
if (newng == nextrcline) {
fputs("Not found.",stdout);
goto reask_reloc;
}
if (*buf == '+')
newng++;
}
else {
printf("\n%s",hforhelp);
goto reask_reloc;
}
}
if (newng < nextrcline-1) {
#ifdef HASHNG
for (i=0; i<HASHSIZ; i++) {
if (hashtbl[i] == nextrcline-1)
hashtbl[i] = newng;
else if (hashtbl[i] >= newng)
++hashtbl[i];
}
#endif
tmprcline = rcline[nextrcline-1];
tmptoread = toread[nextrcline-1];
tmprcchar = rcchar[nextrcline-1];
tmprcnums = rcnums[nextrcline-1];
tmpsoftptr = softptr[nextrcline-1];
#ifdef DEBUGGING
tmpngmax = ngmax[nextrcline-1];
#endif
for (i=nextrcline-2; i>=newng; i--) {
rcline[i+1] = rcline[i];
toread[i+1] = toread[i];
rcchar[i+1] = rcchar[i];
rcnums[i+1] = rcnums[i];
softptr[i+1] = softptr[i];
#ifdef DEBUGGING
ngmax[i+1] = ngmax[i];
#endif
}
rcline[newng] = tmprcline;
toread[newng] = tmptoread;
rcchar[newng] = tmprcchar;
rcnums[newng] = tmprcnums;
softptr[newng] = tmpsoftptr;
#ifdef DEBUGGING
ngmax[newng] = tmpngmax;
#endif
}
if (current_ng >= newng)
current_ng++;
return newng;
}
#endif
/* List out the newsrc with annotations */
void
list_newsgroups()
{
register NG_NUM i;
char tmpbuf[2048];
static char *status[] = {"(READ)","(UNSUB)","(BOGUS)","(JUNK)"};
putchar('\n');
page_line = 1;
print_lines("\
# Status Newsgroup\n\
",STANDOUT);
for (i=0; i<nextrcline && !int_count; i++) {
if (toread[i] >= 0)
set_toread(i);
*(rcline[i] + rcnums[i] - 1) = rcchar[i];
if (toread[i] > 0)
sprintf(tmpbuf,"%3d %6d ",i,toread[i]);
else
sprintf(tmpbuf,"%3d %7s ",i,status[-toread[i]]);
safecpy(tmpbuf+13,rcline[i],2034);
*(rcline[i] + rcnums[i] - 1) = '\0';
if (print_lines(tmpbuf,NOMARKING))
break;
}
int_count = 0;
}
/* find a newsgroup in .newsrc */
NG_NUM
find_ng(ngnam)
char *ngnam;
{
register NG_NUM ngnum;
#ifdef HASHNG
register int hashix = hash(ngnam);
register int incr = 1;
while ((ngnum = hashtbl[hashix]) >= 0) {
if (strEQ(rcline[ngnum], ngnam) && toread[ngnum] >= TR_UNSUB)
return ngnum;
hashix = (hashix + incr) % HASHSIZ;
incr += 2; /* offsets from original are in n*2 */
}
return nextrcline; /* = notfound */
#else /* just do linear search */
for (ngnum = 0; ngnum < nextrcline; ngnum++) {
if (strEQ(rcline[ngnum],ngnam))
break;
}
return ngnum;
#endif
}
void
cleanup_rc()
{
register NG_NUM ngx;
register NG_NUM bogosity = 0;
#ifdef VERBOSE
IF(verbose)
fputs("Checking out your .newsrc--hang on a second...\n",stdout);
ELSE
#endif
#ifdef TERSE
fputs("Checking .newsrc--hang on...\n",stdout);
#endif
for (ngx = 0; ngx < nextrcline; ngx++) {
if (toread[ngx] >= TR_UNSUB) {
set_toread(ngx); /* this may reset newsgroup */
/* or declare it bogus */
}
if (toread[ngx] == TR_BOGUS)
bogosity++;
}
for (ngx = nextrcline-1; ngx >= 0 && toread[ngx] == TR_BOGUS; ngx--)
bogosity--; /* discount already moved ones */
if (nextrcline > 5 && bogosity > nextrcline / 2) {
fputs(
"It looks like the active file is messed up. Contact your news administrator,\n\
",stdout);
fputs(
"leave the \"bogus\" groups alone, and they may come back to normal. Maybe.\n\
",stdout);
}
#ifdef RELOCATE
else if (bogosity) {
#ifdef VERBOSE
IF(verbose)
fputs("Moving bogus newsgroups to the end of your .newsrc.\n",
stdout);
ELSE
#endif
#ifdef TERSE
fputs("Moving boguses to the end.\n",stdout);
#endif
for (; ngx >= 0; ngx--) {
if (toread[ngx] == TR_BOGUS)
relocate_newsgroup(ngx,nextrcline-1);
}
#ifdef DELBOGUS
reask_bogus:
in_char("Delete bogus newsgroups? [ny] ");
putchar('\n');
setdef(buf,"n");
#ifdef VERIFY
printcmd();
#endif
if (*buf == 'h') {
#ifdef VERBOSE
IF(verbose)
fputs("\
Type y to delete bogus newsgroups.\n\
Type n or SP to leave them at the end in case they return.\n\
",stdout);
ELSE
#endif
#ifdef TERSE
fputs("y to delete, n to keep\n",stdout);
#endif
goto reask_bogus;
}
else if (*buf == 'n' || *buf == 'q')
;
else if (*buf == 'y') {
while (toread[nextrcline-1] == TR_BOGUS && nextrcline > 0)
--nextrcline; /* real tough, huh? */
}
else {
fputs(hforhelp,stdout);
goto reask_bogus;
}
#endif
}
#else
#ifdef VERBOSE
IF(verbose)
fputs("You should edit bogus newsgroups out of your .newsrc.\n",
stdout);
ELSE
#endif
#ifdef TERSE
fputs("Edit boguses from .newsrc.\n",stdout);
#endif
#endif
paranoid = FALSE;
}
#ifdef HASHNG
/* make an entry in the hash table for the current newsgroup */
void
sethash(thisng)
NG_NUM thisng;
{
register int hashix = hash(rcline[thisng]);
register int incr = 1;
#ifdef DEBUGGING
static int hashhits = 0, hashtries = 0;
#endif
#ifdef DEBUGGING
hashtries++;
#endif
while (hashtbl[hashix] >= 0) {
#ifdef DEBUGGING
hashhits++;
if (debug & DEB_HASH) {
printf(" Hash hits: %d / %d\n",hashhits, hashtries);
}
hashtries++;
#endif
hashix = (hashix + incr) % HASHSIZ;
incr += 2; /* offsets from original are in n*2 */
}
hashtbl[hashix] = thisng;
}
short prime[] = {1,2,-3,-5,7,11,-13,-17,19,23,-29,-31,37,41,-43,-47,53,57,-59,
-61,67,71,-73,-79,83,89,-97,-101,1,1,1,1,1,1,1,1,1,1,1,1};
int
hash(ngnam)
register char *ngnam;
{
register int i = 0;
register int ch;
register int sum = 0;
#ifdef DEBUGGING
char *ngn = ngnam;
#endif
while (ch = *ngnam++) {
sum += (ch + i) * prime[i]; /* gives ~ 10% hits at 25% full */
i++;
}
#ifdef DEBUGGING
if (debug & DEB_HASH)
printf("hash(%s) => %d => %d\n",ngn, sum, (sum<0?-sum:sum)%HASHSIZ);
#endif
if (sum < 0)
sum = -sum;
return sum % HASHSIZ;
}
#endif
void
newsrc_check()
{
rcfp = fopen(rcname,"r"); /* open it */
if (rcfp == Nullfp) { /* not there? */
#ifdef VERBOSE
IF(verbose)
fputs("\
Trying to set up a .newsrc file--running newsetup...\n\n\
",stdout);
ELSE
#endif
#ifdef TERSE
fputs("Setting up .newsrc...\n",stdout);
#endif
if (doshell(sh,filexp(NEWSETUP)) ||
(rcfp = fopen(rcname,"r")) == Nullfp) {
#ifdef VERBOSE
IF(verbose)
fputs("\
Can't create a .newsrc--you must do it yourself.\n\
",stdout);
ELSE
#endif
#ifdef TERSE
fputs("(Fatal)\n",stdout);
#endif
finalize(1);
}
}
else {
UNLINK(rcbname); /* unlink backup file name */
link(rcname,rcbname); /* and backup current name */
}
}
/* write out the (presumably) revised .newsrc */
void
write_rc()
{
register NG_NUM tmpng;
register char *delim;
rcfp = fopen(rctname, "w"); /* open .newsrc */
/* write out each line*/
for (tmpng = 0; tmpng < nextrcline; tmpng++) {
if (rcnums[tmpng]) {
delim = rcline[tmpng] + rcnums[tmpng] - 1;
*delim = rcchar[tmpng];
}
else
delim = Nullch;
#ifdef DEBUGGING
if (debug & DEB_NEWSRC_LINE)
printf("%s\n",rcline[tmpng]);
#endif
fprintf(rcfp,"%s\n",rcline[tmpng]);
if (delim)
*delim = '\0'; /* might still need this line */
}
fclose(rcfp); /* close .newsrc */
UNLINK(rcname);
link(rctname,rcname);
UNLINK(rctname);
if (writesoft) {
tmpfp = fopen(filexp(softname), "w"); /* open .rnsoft */
for (tmpng = 0; tmpng < nextrcline; tmpng++) {
fprintf(tmpfp,"%ld\n",(long)softptr[tmpng]);
}
fclose(tmpfp);
}
}
!STUFFY!FUNK!
echo Extracting art.help.SH
cat >art.help.SH <<'!STUFFY!FUNK!'
case $CONFIG in
'') . config.sh ;;
esac
echo "Extracting art.help (with variable substitutions)"
$spitshell >art.help <<!GROK!THIS!
$startsh
# $Header: art.help.SH,v 4.1 84/09/24 11:41:43 lwall Exp $
#
# $Log: art.help.SH,v $
# Revision 4.1 84/09/24 11:41:43 lwall
# Real baseline.
#
# Revision 4.0.1.1 84/09/12 15:19:06 lwall
# Housekeeping.
#
# Revision 4.0 84/09/04 09:49:29 lwall
# Baseline for netwide release
#
#
$pager <<'EOT'
Article Selection commands:
n,SP Scan forward for next unread article.
N Go to next article.
^N Scan forward for next unread article with same subject.
p,P,^P Same as n,N,^N, only going backwards.
- Go to previously displayed article.
number Go to specified article.
range{,range} command{:command}
Apply one or more commands to one or more ranges of articles.
Ranges are of the form: number | number-number. You may use . for
the current article, and $ for the last article.
Valid commands are: j, m, M, s, S, and !.
/pattern/modifiers
Scan forward for article containing pattern in the subject line.
(Use ?pat? to scan backwards; append h to scan headers, a to scan
entire articles, r to scan read articles, c to make case sensitive.
/pattern/modifiers:command{:command}
Apply one or more commands to the set of articles matching pattern.
Use a K modifier to save entire command to the KILL file for this
newsgroup. Commands m and M, if first, imply an r modifier.
Valid commands are: j, m, M, s, S, and !.
f,F Submit a followup article (F = include this article).
r,R Reply through net mail (R = include this article).
s ... Save to file or pipe via sh.
S ... Save via preferred shell.
w,W Like s and S but save without the header.
| ... Same as s|...
C Cancel this article, if yours.
^R,v Restart article (v=verbose).
^X Restart article, rot13 mode.
c Catch up (mark all articles as read).
^B Back up one page.
^L Refresh the screen. You can get back to the pager with this.
X Refresh screen in rot13 mode.
^ Go to first unread article. Disables subject search mode.
$ Go to end of newsgroup. Disables subject search mode.
# Print last article number.
& Print current values of command-line switches.
&switch {switch}
Set or unset more switches.
j Junk this article (mark it read). Stays at end of article.
m Mark article as still unread.
M Mark article as still unread upon exiting newsgroup or Y command.
Y Yank back articles marked temporarily read via M.
k Mark current SUBJECT as read.
K Mark current SUBJECT as read, and save command in KILL file.
= List subjects of unread articles.
u Unsubscribe to this newsgroup.
^K Edit local KILL file (the one for this newsgroup).
q Quit this newsgroup for now.
EOT
!GROK!THIS!
$eunicefix art.help
chmod 755 art.help
!STUFFY!FUNK!
echo ""
echo "End of kit 3 (of 8)"
cat /dev/null >kit3isdone
config=true
for iskit in 1 2 3 4 5 6 7 8; do
if test -f kit${iskit}isdone; then
echo "You have run kit ${iskit}."
else
echo "You still need to run kit ${iskit}."
config=false
fi
done
case $config in
true)
echo "You have run all your kits. Please read README and then type Configure."
chmod 755 Configure
;;
esac
: I do not append .signature, but someone might mail this.
exit
More information about the Comp.sources.unix
mailing list