home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Source Code 1992 March
/
Source_Code_CD-ROM_Walnut_Creek_March_1992.iso
/
usenet
/
altsrcs
/
1
/
1462
< prev
next >
Wrap
Internet Message Format
|
1990-12-28
|
63KB
From: sob@lib.tmc.edu (Stan Barber)
Newsgroups: alt.sources
Subject: rn/rrn combo kit part 5 of 9
Message-ID: <431@lib.tmc.edu>
Date: 14 Jun 90 03:28:04 GMT
#! /bin/sh
# Make a new directory for the rn sources, cd to it, and run kits 1 thru 9
# through sh. When all 9 kits have been run, read README.
echo "This is rn kit 5 (of 9). If kit 5 is complete, the line"
echo '"'"End of kit 5 (of 9)"'" 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.3.2.3 90/04/21 14:43:27 sob Exp $
*
* $Log: art.c,v $
* Revision 4.3.2.3 90/04/21 14:43:27 sob
* Revised previous patch insure that it does not decrement below zero.
*
* Revision 4.3.2.2 90/03/22 23:03:25 sob
* Fixes provided by Wayne Davison <drivax!davison>
*
* Revision 4.3.2.1 89/11/07 23:20:57 sob
* Bug fixes for NNTP
*
* Revision 4.3.1.5 85/09/10 11:07:18 lwall
* %m not restored on some returns.
*
* Revision 4.3.1.4 85/05/23 12:13:31 lwall
* shouldn't display article that's really a subdirectory.
*
* Revision 4.3.1.3 85/05/13 09:29:55 lwall
* Added CUSTOMLINES option.
*
* Revision 4.3.1.2 85/05/10 13:46:07 lwall
* Fixed header reparse bug on backpage.
*
* Revision 4.3.1.1 85/05/10 11:30:56 lwall
* Branch for patches.
*
* Revision 4.3 85/05/01 11:34:51 lwall
* Baseline for release with 4.3bsd.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "rn.h"
#include "ngstuff.h"
#include "ngdata.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? */
char art_buf[LBUFLEN]; /* place for article lines */
void
art_init()
{
;
}
int
do_article()
{
register char *s;
ART_POS artsize; /* size in bytes of article */
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? */
char oldmode = mode;
#ifdef INNERSEARCH
register int outputok;
#endif
if (fstat(artfp->_file,&filestat))
/* get article file stats */
return DA_CLEAN;
if ((filestat.st_mode & S_IFMT) != S_IFREG)
return DA_NORM;
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) {
#ifdef ASYNC_PARSE
parse_maybe(art); /* make sure header is ours */
#endif
artpos = vrdary(artline);
if (artpos < 0)
artpos = -artpos; /* labs(), anyone? */
if (firstpage)
artpos = (ART_POS)0;
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, (sizeof art_buf), firstline);
#ifdef CLEAREOL
maybe_eol();
#endif CLEAREOL
fputs(art_buf,stdout) FLUSH;
artopen(art); /* rewind article in case interp */
/* forced a header parse */
}
else {
ART_NUM i;
#ifdef CLEAREOL
maybe_eol();
#endif CLEAREOL
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(moderated,stdout);
fputs(":\n",stdout) FLUSH;
}
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') FLUSH; /* get to left margin */
int_count = 0; /* reset interrupt count */
mode = oldmode;
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 */
mode = oldmode;
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;
}
#ifdef CUSTOMLINES
if (hideline && bufptr == art_buf &&
execute(&hide_compex,art_buf) )
hide_this_line = TRUE;
#endif
if (in_header && htype[in_header].ht_flags & HT_MAGIC) {
if (in_header == NGS_LINE) {
hide_this_line = (index(art_buf,',') == Nullch);
}
else if (in_header == EXPIR_LINE) {
if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE))
hide_this_line = (strlen(art_buf) < 10);
}
}
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 */
#ifdef CLEAREOL
maybe_eol();
#endif CLEAREOL
fputs(art_buf,stdout) FLUSH;
/* print up through : */
if (!UG)
putchar(' ');
underprint(s); /* print subject underlined */
putchar('\n') FLUSH; /* and finish the line */
}
else if (hide_this_line && do_hiding) {
/* 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
#ifdef CLEAREOL
#ifdef INNERSEARCH
if (outputok)
#endif
maybe_eol();
#endif CLEAREOL
#ifdef CUSTOMLINES
if (pagestop && bufptr == art_buf &&
execute(&page_compex,art_buf) )
linenum = 32700;
#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') FLUSH;
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 (bufptr == blinebeg && 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') FLUSH;
/* so move it down ourselves */
if (*bufptr == '\n')
restart = 0;
/* simulate XN if need be */
}
#ifdef CLEAREOL
/* #ifdef INNERSEARCH
if (outputok)
#endif
maybe_eol(); */ /* comment this out for now
until I am sure it is
needed*/
#endif CLEAREOL
}
/* 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? */
mode = oldmode;
return DA_NORM; /* avoid --MORE--(100%) */
}
/* not done with this article, so pretend we are a pager */
reask_pager:
unflush_output(); /* disable any ^O in effect */
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 */
mode = 'p';
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 */
}
}
carriage_return();
#ifndef CLEAREOL
erase_eol(); /* and erase the prompt */
#else
if (erase_screen && can_home_clear)
clear_rest();
else
erase_eol(); /* and erase the prompt */
#endif CLEAREOL
carriage_return(); /* Resets kernels tab coloumn counter to 0 */ 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 */
mode = oldmode;
return DA_RAISE;
case PS_TOEND: /* fast pager loop exit */
mode = oldmode;
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'
#ifdef CUSTOMLINES
&& (!pagestop || blinebeg != art_buf ||
!execute(&page_compex,blinebeg))
#endif
) {
up_line();
highlight = --artline;
restart = blinebeg;
artpos = alinebeg;
}
return PS_NORM;
case '!': /* shell escape */
escapade();
return PS_ASK;
#ifdef INNERSEARCH
case Ctl('i'):
gline = 3;
sprintf(cmd_buf,"^[^%c]",*blinebeg);
compile(&gcompex,cmd_buf,TRUE,TRUE);
goto caseG;
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) FLUSH;
return PS_ASK;
}
carriage_return();
erase_eol(); /* erase the prompt */
carriage_return(); /* Resets kernels tab coloumn counter to 0 */
/* 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)
FLUSH;
#endif
if (*buf == Ctl('i') || 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) FLUSH;
#endif
if (execute(&gcompex,buf) != Nullch) {
innersearch = ftell(artfp);
break;
}
}
if (!innersearch) {
fseek(artfp,artpos,0);
fputs("(Not found)",stdout) FLUSH;
return PS_ASK;
}
#ifdef DEBUGGING
if (debug & DEB_INNERSRCH)
printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos)
FLUSH;
#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) FLUSH;
#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) FLUSH;
gets(buf);
}
#endif
clear();
carriage_return(); /* Resets kernels tab coloumn counter to 0 */
do_fseek = TRUE;
artline = topline;
if (artline < 0)
artline = 0;
firstpage = (topline < 0);
return PS_NORM;
case 'b':
case '\b':
case Ctl('b'): { /* back up a page */
ART_LINE target;
#ifndef CLEAREOL
clear();
#else
if (can_home_clear) /* if we can home do it */
home_cursor();
else
clear();
#endif CLEAREOL
carriage_return(); /* Resets kernels tab coloumn counter to 0 */
do_fseek = TRUE; /* reposition article file */
target = topline - (LINES - 2);
artline = topline;
if (artline > 0) 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 */
int cmd;
if ((cmd = help_page()) > 0)
pushchar(cmd);
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 'Q':
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 Ctl('v'):
/* Leaving it undocumented in case */
/* I want to steal the key--LAW */
case ' ': /* continue current article */
if (erase_screen) { /* -e? */
#ifndef CLEAREOL
clear(); /* clear screen */
#else
if (can_home_clear) /* if we can home do it */
home_cursor();
else
clear(); /* else clear screen */
#endif CLEAREOL
if (*blinebeg != '\f'
#ifdef CUSTOMLINES
&& (!pagestop || blinebeg != art_buf ||
!execute(&page_compex,blinebeg))
#endif
) {
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'
#ifdef CUSTOMLINES
&& (!pagestop || blinebeg != art_buf ||
!execute(&page_compex,blinebeg))
#endif
) {
/* 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) FLUSH;
settle_down();
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)
FLUSH;
#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) FLUSH;
#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)
FLUSH;
#endif
if (artline < isrchline + gline) {
return TRUE;
}
return FALSE;
}
#endif
!STUFFY!FUNK!
echo Extracting rcstuff.c
cat >rcstuff.c <<'!STUFFY!FUNK!'
/* $Header: rcstuff.c,v 4.3.2.5 90/05/04 00:44:07 sob Exp $
*
* $Log: rcstuff.c,v $
* Revision 4.3.2.5 90/05/04 00:44:07 sob
* Fixes to add_newsgroup() from lar@usl.edu.
*
* Revision 4.3.2.4 90/04/23 00:25:45 sob
* Changed atoi to atol.
*
* Revision 4.3.2.3 89/12/20 23:25:04 sob
* Changed the maximum lenght of a newsgroup name from 20 to 40 characters.
*
* Revision 4.3.2.2 89/11/26 18:22:26 sob
* Added changes to addnewgroup() to cause rn to ask once and only once
* to add a new group to .newsrc.
* Fix provided by Fletcher Mattox <fletcher@cs.utexas.edu>
*
* Revision 4.3.2.1 89/11/06 00:58:29 sob
* Added RRN support from NNTP 1.5
*
* Revision 4.3.1.5 86/07/24 14:09:10 lwall
* Removed check for spool directory existence in get_ng.
*
* Revision 4.3.1.4 85/09/10 11:04:44 lwall
* Improved %m in in_char().
*
* Revision 4.3.1.3 85/05/29 09:13:25 lwall
* %d that should be %ld.
*
* Revision 4.3.1.2 85/05/17 11:40:08 lwall
* Sped up "rn -c" by not mallocing unnecessarily.
*
* Revision 4.3.1.1 85/05/10 11:37:18 lwall
* Branch for patches.
*
* Revision 4.3 85/05/01 11:45:56 lwall
* Baseline for release with 4.3bsd.
*
*/
#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"
#ifdef SERVER
#include "server.h"
#endif
#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 SERVER
char *cp;
#endif SERVER
#ifdef HASHNG
for (i=0; i<HASHSIZ; i++)
hashtbl[i] = -1;
#endif
/* make filenames */
#ifdef SERVER
if (cp = getenv("NEWSRC"))
rcname = savestr(filexp(cp));
else
rcname = savestr(filexp(RCNAME));
#else not SERVER
rcname = savestr(filexp(RCNAME));
#endif SERVER
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) FLUSH;
finalize(1);
}
if (tmpfp != Nullfp && fgets(tmpbuf,10,tmpfp) != Nullch)
softptr[newng] = atol(tmpbuf);
else
softptr[newng] = 0;
some_buf[--length] = '\0'; /* wipe out newline */
if (checkflag) /* no extra mallocs for -c */
rcline[newng] = some_buf;
else if (some_buf == buf) {
rcline[newng] = savestr(some_buf);
/* make a semipermanent copy */
}
else {
/*NOSTRICT*/
#ifndef lint
some_buf = saferealloc(some_buf,(MEM_SIZE)(length+1));
#endif lint
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 && !checkflag) {
#ifndef lint
rcline[newng] = saferealloc(rcline[newng],(MEM_SIZE)length+2);
#endif lint
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) FLUSH;
}
#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 %-40s %5ld article%s\n",
rcline[newng],(long)toread[newng],
toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
ELSE
#endif
#ifdef TERSE
printf("%s: %ld article%s\n",
rcline[newng],(long)toread[newng],
toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
#endif
if (int_count) {
countdown = 1;
int_count = 0;
}
if (countdown) {
if (! --countdown) {
fputs("etc.\n",stdout) FLUSH;
if (checkflag)
finalize(1);
suppress_cn = TRUE;
}
}
}
}
}
fclose(rcfp); /* close .newsrc */
if (tmpfp != Nullfp)
fclose(tmpfp); /* close .rnsoft */
if (checkflag) { /* were we just checking? */
finalize(foundany); /* tell them what we found */
}
if (paranoid)
cleanup_rc();
#ifdef DEBUGGING
if (debug & DEB_HASH) {
page_init();
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 */
#ifdef SERVER
static int addnewbydefault = 0;
#endif SERVER
bool
get_ng(what,do_reloc)
char *what;
bool do_reloc;
{
char *ntoforget;
char promptbuf[128];
#ifdef SERVER
char ser_line[256];
#endif SERVER
#ifdef VERBOSE
IF(verbose)
ntoforget = "Type n to forget about this newsgroup.\n";
ELSE
#endif
#ifdef TERSE
ntoforget = "n to forget it.\n";
#endif
if (index(what,'/')) {
dingaling();
printf("\nBad newsgroup name.\n") FLUSH;
return FALSE;
}
set_ngname(what);
ng = find_ng(ngname);
if (ng == nextrcline) { /* not in .newsrc? */
#ifdef SERVER
sprintf(ser_line, "GROUP %s", ngname);
put_server(ser_line);
if (get_server(ser_line, sizeof(ser_line)) < 0) {
fprintf(stderr, "rrn: Unexpected close of server socket.\n");
finalize(1);
}
if (*ser_line != CHAR_OK) {
if (atoi(ser_line) != ERR_NOGROUP) {
fprintf(stderr, "Server response to GROUP %s:\n%s\n",
ngname, ser_line);
}
#else not SERVER
if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
#endif SERVER
dingaling();
#ifdef VERBOSE
IF(verbose)
printf("\nNewsgroup %s does not exist!\n",ngname) FLUSH;
ELSE
#endif
#ifdef TERSE
printf("\nNo %s!\n",ngname) FLUSH;
#endif
sleep(2);
return FALSE;
}
#ifdef SERVER
if (addnewbydefault) {
printf("(Adding %s to end of your .newsrc)\n", ngname);
ng = add_newsgroup(ngname, ':');
do_reloc = FALSE;
} else {
#endif SERVER
#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,'A');
putchar('\n') FLUSH;
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)
FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("y or SP to add\n",stdout) FLUSH;
#endif
fputs(ntoforget,stdout) FLUSH;
goto reask_add;
}
else if (*buf == 'n' || *buf == 'q') {
ng = add_newsgroup(ngname, '!');
return FALSE;
}
else if (*buf == 'y') {
ng = add_newsgroup(ngname, ':');
do_reloc = FALSE;
}
#ifdef SERVER
else if (*buf == 'Y') {
fputs(
"(I'll add all new newsgroups to the end of your .newsrc.)\n", stdout);
addnewbydefault = 1;
printf("(Adding %s to end of your .newsrc)\n", ngname);
ng = add_newsgroup(ngname, ':');
do_reloc = FALSE;
}
#endif SERVER
else {
fputs(hforhelp,stdout) FLUSH;
settle_down();
goto reask_add;
}
#ifdef SERVER
}
#endif SERVER
}
else if (rcchar[ng] == NEGCHAR) { /* unsubscribed? */
#ifdef VERBOSE
IF(verbose)
sprintf(promptbuf,
"\nNewsgroup %s is currently unsubscribed to--resubscribe? [yn] ",ngname)
FLUSH;
ELSE
#endif
#ifdef TERSE
sprintf(promptbuf,"\n%s unsubscribed--resubscribe? [yn] ",ngname)
FLUSH;
#endif
reask_unsub:
in_char(promptbuf,'R');
putchar('\n') FLUSH;
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) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("y or SP to resubscribe.\n",stdout) FLUSH;
#endif
fputs(ntoforget,stdout) FLUSH;
goto reask_unsub;
}
else if (*buf == 'n' || *buf == 'q') {
return FALSE;
}
else if (*buf == 'y') {
rcchar[ng] = ':';
}
else {
fputs(hforhelp,stdout) FLUSH;
settle_down();
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, c)
char *ngn, c;
{
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] = c; /* subscribe or unsubscribe */
toread[newng] = TR_NONE; /* just for prettiness */
#ifdef HASHNG
sethash(newng); /* so we can find it again */
#endif
#ifdef RELOCATE
return c=='!' ? newng : 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
#ifdef CACHEFIRST
ART_NUM tmpabs1st;
#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
#ifdef CACHEFIRST
tmpabs1st = abs1st[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
#ifdef CACHEFIRST
abs1st[i-1] = abs1st[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
#ifdef CACHEFIRST
abs1st[nextrcline-1] = tmpabs1st;
#endif
}
if (current_ng > ngx)
current_ng--;
if (newng < 0) {
reask_reloc:
unflush_output(); /* disable any ^O in effect */
#ifdef SERVER
if (addnewbydefault) {
buf[0] = '$';
buf[1] = '\0';
} else {
#endif SERVER
#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);
#ifdef SERVER
}
#endif SERVER
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") FLUSH;
}
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") FLUSH;
}
#endif
goto reask_reloc;
}
else if (*buf == 'L') {
putchar('\n') FLUSH;
list_newsgroups();
goto reask_reloc;
}
else if (isdigit(*buf)) {
if (!finish_command(TRUE)) /* get rest of command */
goto reinp_reloc;
newng = atol(buf);
if (newng < 0)
newng = 0;
if (newng >= nextrcline)
return nextrcline-1;
}
else if (*buf == '^') {
putchar('\n') FLUSH;
newng = 0;
}
else if (*buf == '$') {
putchar('\n') FLUSH;
return nextrcline-1;
}
else if (*buf == '.') {
putchar('\n') FLUSH;
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) FLUSH;
goto reask_reloc;
}
if (*buf == '+')
newng++;
}
else {
printf("\n%s",hforhelp) FLUSH;
settle_down();
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
#ifdef CACHEFIRST
tmpabs1st = abs1st[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
#ifdef CACHEFIRST
abs1st[i+1] = abs1st[i];
#endif
}
rcline[newng] = tmprcline;
toread[newng] = tmptoread;
rcchar[newng] = tmprcchar;
rcnums[newng] = tmprcnums;
softptr[newng] = tmpsoftptr;
#ifdef DEBUGGING
ngmax[newng] = tmpngmax;
#endif
#ifdef CACHEFIRST
abs1st[newng] = tmpabs1st;
#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)"};
int cmd;
page_init();
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 %6ld ",i,(long)toread[i]);
else
sprintf(tmpbuf,"%3d %7s ",i,status[-toread[i]]);
safecpy(tmpbuf+13,rcline[i],2034);
*(rcline[i] + rcnums[i] - 1) = '\0';
if (cmd = print_lines(tmpbuf,NOMARKING)) {
if (cmd > 0)
pushchar(cmd);
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)
FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("Checking .newsrc--hang on...\n",stdout) FLUSH;
#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) FLUSH;
}
#ifdef RELOCATE
else if (bogosity) {
#ifdef VERBOSE
IF(verbose)
fputs("Moving bogus newsgroups to the end of your .newsrc.\n",
stdout) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("Moving boguses to the end.\n",stdout) FLUSH;
#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] ", 'D');
putchar('\n') FLUSH;
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) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("y to delete, n to keep\n",stdout) FLUSH;
#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) FLUSH;
settle_down();
goto reask_bogus;
}
#endif
}
#else
#ifdef VERBOSE
IF(verbose)
fputs("You should edit bogus newsgroups out of your .newsrc.\n",
stdout) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("Edit boguses from .newsrc.\n",stdout) FLUSH;
#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) FLUSH;
}
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)
FLUSH;
#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) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("Setting up .newsrc...\n",stdout) FLUSH;
#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) FLUSH;
ELSE
#endif
#ifdef TERSE
fputs("(Fatal)\n",stdout) FLUSH;
#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 */
if (rcfp == Nullfp) {
printf("Can't recreate .newsrc\n") FLUSH;
finalize(1);
}
/* 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]) FLUSH;
#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 */
if (tmpfp == Nullfp) {
printf(cantcreate,filexp(softname)) FLUSH;
return;
}
for (tmpng = 0; tmpng < nextrcline; tmpng++) {
fprintf(tmpfp,"%ld\n",(long)softptr[tmpng]);
}
fclose(tmpfp);
}
}
void
get_old_rc()
{
UNLINK(rctname);
link(rcname,rctname);
UNLINK(rcname);
link(rcbname,rcname);
UNLINK(rcbname);
}
!STUFFY!FUNK!
echo Extracting bits.c
cat >bits.c <<'!STUFFY!FUNK!'
/* $Header: bits.c,v 4.3.2.3 89/11/28 01:52:02 sob Locked $
*
* $Log: bits.c,v $
* Revision 4.3.2.3 89/11/28 01:52:02 sob
* Removed some lint.
*
* Revision 4.3.2.2 89/11/27 01:30:04 sob
* Altered NNTP code per ideas suggested by Bela Lubkin
* <filbo@gorn.santa-cruz.ca.us>
*
* Revision 4.3.1.4 86/10/31 15:23:53 lwall
* Separated firstart into two variables so KILL on new articles won't
* accidentally mark articles read.
*
* Revision 4.3.1.3 86/09/09 16:01:43 lwall
* Fixed 'n more articles' bug.
*
* Revision 4.3.1.2 86/07/24 14:40:23 lwall
* Gets host name from path instead of relay-version for news 2.10.3.
*
* Revision 4.3.1.1 85/05/10 11:31:41 lwall
* Branch for patches.
*
* Revision 4.3 85/05/01 11:36:15 lwall
* Baseline for release with 4.3bsd.
*
*/
#include "EXTERN.h"
#include "common.h"
#include "rcstuff.h"
#include "head.h"
#include "util.h"
#include "final.h"
#include "rn.h"
#include "cheat.h"
#include "ng.h"
#include "artio.h"
#include "intrp.h"
#include "ngdata.h"
#include "rcln.h"
#include "kfile.h"
#include "INTERN.h"
#include "bits.h"
#ifdef DBM
# ifdef NULL
# undef NULL
# endif NULL
# include <dbm.h>
#endif DBM
MEM_SIZE ctlsize; /* size of bitmap in bytes */
void
bits_init()
{
#ifdef DELAYMARK
dmname = savestr(filexp(RNDELNAME));
#else
;
#endif
}
/* checkpoint the .newsrc */
void
checkpoint_rc()
{
#ifdef DEBUGGING
if (debug & DEB_CHECKPOINTING) {
fputs("(ckpt)",stdout);
fflush(stdout);
}
#endif
if (doing_ng)
restore_ng(); /* do not restore M articles */
if (rc_changed)
write_rc();
#ifdef DEBUGGING
if (debug & DEB_CHECKPOINTING) {
fputs("(done)",stdout);
fflush(stdout);
}
#endif
}
/* reconstruct the .newsrc line in a human readable form */
void
restore_ng()
{
register char *s, *mybuf = buf;
register ART_NUM i;
ART_NUM count=0;
int safelen = LBUFLEN - 16;
strcpy(buf,rcline[ng]); /* start with the newsgroup name */
s = buf + rcnums[ng] - 1; /* use s for buffer pointer */
*s++ = rcchar[ng]; /* put the requisite : or !*/
*s++ = ' '; /* put the not-so-requisite space */
for (i=1; i<=lastart; i++) { /* for each article in newsgroup */
if (s-mybuf > safelen) { /* running out of room? */
safelen *= 2;
if (mybuf == buf) { /* currently static? */
*s = '\0';
mybuf = safemalloc((MEM_SIZE)safelen + 16);
strcpy(mybuf,buf); /* so we must copy it */
s = mybuf + (s-buf);
/* fix the pointer, too */
}
else { /* just grow in place, if possible */
char *newbuf;
newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
s = newbuf + (s-mybuf);
mybuf = newbuf;
}
}
if (!was_read(i)) /* still unread? */
count++; /* then count it */
else { /* article was read */
ART_NUM oldi;
sprintf(s,"%ld",(long)i); /* put out the min of the range */
s += strlen(s); /* keeping house */
oldi = i; /* remember this spot */
do i++; while (i <= lastart && was_read(i));
/* find 1st unread article or end */
i--; /* backup to last read article */
if (i > oldi) { /* range of more than 1? */
sprintf(s,"-%ld,",(long)i);
/* then it out as a range */
s += strlen(s); /* and housekeep */
}
else
*s++ = ','; /* otherwise, just a comma will do */
}
}
if (*(s-1) == ',') /* is there a final ','? */
s--; /* take it back */
*s++ = '\0'; /* and terminate string */
#ifdef DEBUGGING
if (debug & DEB_NEWSRC_LINE && !panic) {
printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
printf("%s\n",mybuf) FLUSH;
}
#endif
free(rcline[ng]); /* return old rc line */
if (mybuf == buf) {
rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
/* grab a new rc line */
strcpy(rcline[ng], buf); /* and load it */
}
else {
mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
/* be nice to the heap */
rcline[ng] = mybuf;
}
*(rcline[ng] + rcnums[ng] - 1) = '\0';
if (rcchar[ng] == NEGCHAR) { /* did they unsubscribe? */
printf(unsubto,ngname) FLUSH;
toread[ng] = TR_UNSUB; /* make line invisible */
}
else
/*NOSTRICT*/
toread[ng] = (ART_UNREAD)count; /* remember how many unread there are */
}
/* mark an article unread, keeping track of toread[] */
void
onemore(artnum)
ART_NUM artnum;
{
#ifdef DEBUGGING
if (debug && artnum < firstbit) {
printf("onemore: %d < %d\n",artnum,firstbit) FLUSH;
return;
}
#endif
if (ctl_read(artnum)) {
ctl_clear(artnum);
++toread[ng];
}
}
/* mark an article read, keeping track of toread[] */
void
oneless(artnum)
ART_NUM artnum;
{
#ifdef DEBUGGING
if (debug && artnum < firstbit) {
printf("oneless: %d < %d\n",artnum,firstbit) FLUSH;
return;
}
#endif
if (!ctl_read(artnum)) {
ctl_set(artnum);
if (toread[ng] > TR_NONE)
--toread[ng];
}
}
/* mark an article as unread, making sure that firstbit is properly handled */
/* cross-references are left as read in the other newsgroups */
void
unmark_as_read(artnum)
ART_NUM artnum;
{
check_first(artnum);
onemore(artnum);
#ifdef MCHASE
if (!parse_maybe(artnum))
chase_xrefs(artnum,FALSE);
#endif
}
#ifdef DELAYMARK
/* temporarily mark article as read. When newsgroup is exited, articles */
/* will be marked as unread. Called via M command */
void
delay_unmark(artnum)
ART_NUM artnum;
{
if (dmfp == Nullfp) {
dmfp = fopen(dmname,"w");
if (dmfp == Nullfp) {
printf(cantcreate,dmname) FLUSH;
sig_catcher(0);
}
}
oneless(artnum); /* set the correct bit */
dmcount++;
fprintf(dmfp,"%ld\n",(long)artnum);
}
#endif
/* mark article as read. If article is cross referenced to other */
/* newsgroups, mark them read there also. */
void
mark_as_read(artnum)
ART_NUM artnum;
{
oneless(artnum); /* set the correct bit */
checkcount++; /* get more worried about crashes */
chase_xrefs(artnum,TRUE);
}
/* make sure we have bits set correctly down to firstbit */
void
check_first(min)
ART_NUM min;
{
register ART_NUM i = firstbit;
if (min < absfirst)
min = absfirst;
if (min < i) {
for (i--; i>=min; i--)
ctl_set(i); /* mark as read */
firstart = firstbit = min;
}
}
/* bring back articles marked with M */
#ifdef DELAYMARK
void
yankback()
{
register ART_NUM anum;
if (dmfp) { /* delayed unmarks pending? */
#ifdef VERBOSE
printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
dmcount == 1 ? nullstr : "s") FLUSH;
#endif
fclose(dmfp);
if (dmfp = fopen(dmname,"r")) {
while (fgets(buf,sizeof buf,dmfp) != Nullch) {
anum = (ART_NUM)atol(buf);
/*NOSTRICT*/
onemore(anum); /* then unmark them */
#ifdef MCHASE
chase_xrefs(anum,FALSE);
#endif
}
fclose(dmfp);
dmfp = Nullfp;
UNLINK(dmname); /* and be tidy */
}
else {
printf(cantopen,dmname) FLUSH;
sig_catcher(0);
}
}
dmcount = 0;
}
#endif
/* run down xref list and mark as read or unread */
int
chase_xrefs(artnum,markread)
ART_NUM artnum;
int markread;
{
#ifdef ASYNC_PARSE
if (parse_maybe(artnum)) /* make sure we have right header */
return -1;
#endif
#ifdef DBM
{
datum lhs, rhs;
datum fetch();
register char *idp;
char *ident_buf;
static FILE * hist_file = Nullfp;
#else
if (
#ifdef DEBUGGING
debug & DEB_FEED_XREF ||
#endif
htype[XREF_LINE].ht_minpos >= 0) {
/* are there article# xrefs? */
#endif DBM
char *xref_buf, *curxref;
register char *xartnum;
char *rver_buf = Nullch;
static char *inews_site = Nullch;
register ART_NUM x;
char tmpbuf[128];
#ifdef DBM
rver_buf = fetchlines(artnum,NGS_LINE);
/* get Newsgroups */
if (!index(rver_buf,',')) /* if no comma, no Xref! */
return 0;
if (hist_file == Nullfp) { /* Init. file accesses */
#ifdef DEBUGGING
if (debug)
printf ("chase_xref: opening files\n");
#endif
dbminit(filexp(ARTFILE));
if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
return 0;
}
xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
ident_buf = fetchlines(artnum,MESSID_LINE);
/* get Message-ID */
#ifdef DEBUGGING
if (debug)
printf ("chase_xref: Message-ID: %s\n", ident_buf);
#endif
idp = ident_buf;
while (*++idp) /* make message-id case insensitive */
if (isupper(*idp))
*idp = tolower (*idp);
lhs.dptr = ident_buf; /* look up article by id */
lhs.dsize = strlen(lhs.dptr) + 1;
rhs = fetch(lhs); /* fetch the record */
if (rhs.dptr == NULL) /* if null, nothing there */
goto wild_goose;
fseek (hist_file, *((long *)rhs.dptr), 0);
/* datum returned is position in hist file */
fgets (xref_buf, BUFSIZ, hist_file);
#ifdef DEBUGGING
if (debug)
printf ("Xref from history: %s\n", xref_buf);
#endif
curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
curxref = cpytill(tmpbuf, curxref, '\t') + 1;
#ifdef DEBUGGING
if (debug)
printf ("chase_xref: curxref: %s\n", curxref);
#endif
#else !DBM
#ifdef DEBUGGING
if (htype[XREF_LINE].ht_minpos >= 0)
#endif
xref_buf = fetchlines(artnum,XREF_LINE);
/* get xrefs list */
#ifdef DEBUGGING
else {
xref_buf = safemalloc((MEM_SIZE)100);
printf("Give Xref: ") FLUSH;
gets(xref_buf);
}
#endif
#ifdef DEBUGGING
if (debug & DEB_XREF_MARKER)
printf("Xref: %s\n",xref_buf) FLUSH;
#endif
curxref = cpytill(tmpbuf,xref_buf,' ') + 1;
/* Make sure site name on Xref matches what inews thinks site is.
* Check first against last inews_site. If it matches, fine.
* If not, fetch inews_site from current Relay-Version line and
* check again. This is so that if the new administrator decides
* to change the system name as known to inews, rn will still do
* Xrefs correctly--each article need only match itself to be valid.
*/
if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
#ifndef NORELAY
char *t;
#endif
if (inews_site != Nullch)
free(inews_site);
#ifndef NORELAY
rver_buf = fetchlines(artnum,RVER_LINE);
if ((t = instr(rver_buf,"; site ")) == Nullch)
#else NORELAY
/* In version 2.10.3 of news or afterwards, the Relay-Version
* and Posting-Version header lines have been removed. For
* the code below to work as intended, I have modified it to
* extract the first component of the Path header line. This
* should give the same effect as did the old code with respect
* to the use of the Relay-Version site name.
*/
rver_buf = fetchlines(artnum,PATH_LINE);
if (instr(rver_buf,"!") == Nullch)
#endif NORELAY
inews_site = savestr(nullstr);
else {
char new_site[128];
#ifndef NORELAY
cpytill(new_site,t + 7,'.');
#else NORELAY
cpytill(new_site,rver_buf,'!');
#endif NORELAY
inews_site = savestr(new_site);
}
if (strNE(tmpbuf,inews_site)) {
#ifdef DEBUGGING
if (debug)
printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
#endif
goto wild_goose;
}
}
#endif DBM
while (*curxref) {
/* for each newsgroup */
curxref = cpytill(tmpbuf,curxref,' ');
#ifdef DBM
xartnum = index(tmpbuf,'/');
#else
xartnum = index(tmpbuf,':');
#endif DBM
if (!xartnum) /* probably an old-style Xref */
break;
*xartnum++ = '\0';
if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
x = atol(xartnum);
if (x)
if (markread) {
if (addartnum(x,tmpbuf))
goto wild_goose;
}
#ifdef MCHASE
else
subartnum(x,tmpbuf);
#endif
}
while (*curxref && isspace(*curxref))
curxref++;
}
wild_goose:
free(xref_buf);
#ifdef DBM
free(ident_buf);
#endif DBM
if (rver_buf != Nullch)
free(rver_buf);
}
return 0;
}
int
initctl()
{
char *mybuf = buf; /* place to decode rc line */
register char *s, *c, *h;
register long i;
register ART_NUM unread;
#ifdef DELAYMARK
dmcount = 0;
#endif
if ((lastart = getngsize(ng)) < 0) /* this cannot happen (laugh here) */
return -1;
absfirst = getabsfirst(ng,lastart); /* remember first existing article */
if (!absfirst) /* no articles at all? */
absfirst = 1; /* pretend there is one */
#ifndef lint
ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
#endif lint
ctlarea = safemalloc(ctlsize); /* allocate control area */
/* now modify ctlarea to reflect what has already been read */
for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
/* find numbers in rc line */
i = strlen(s);
#ifndef lint
if (i >= LBUFLEN-2) /* bigger than buf? */
mybuf = safemalloc((MEM_SIZE)(i+2));
#endif lint
strcpy(mybuf,s); /* make scratch copy of line */
mybuf[i++] = ','; /* put extra comma on the end */
mybuf[i] = '\0';
s = mybuf; /* initialize the for loop below */
if (strnEQ(s,"1-",2)) { /* can we save some time here? */
firstbit = atol(s+2)+1; /* ignore first range thusly */
s=index(s,',') + 1;
}
else
firstbit = 1; /* all the bits are valid for now */
if (absfirst > firstbit) { /* do we know already? */
firstbit = absfirst; /* no point calling getngmin again */
}
else if (artopen(firstbit) == Nullfp) {
/* first unread article missing? */
i = getngmin(".",firstbit); /* see if expire has been busy */
if (i) { /* avoid a bunch of extra opens */
firstbit = i;
}
}
firstart = firstbit; /* firstart > firstbit in KILL */
#ifdef PENDING
# ifdef CACHESUBJ
subj_to_get = firstbit;
# endif
#endif
unread = lastart - firstbit + 1; /* assume this range unread */
for (i=OFFSET(firstbit)/BITSPERBYTE; i<ctlsize; i++)
ctlarea[i] = 0; /* assume unread */
#ifdef DEBUGGING
if (debug & DEB_CTLAREA_BITMAP) {
printf("\n%s\n",mybuf) FLUSH;
for (i=1; i <= lastart; i++)
if (! was_read(i))
printf("%ld ",(long)i) FLUSH;
}
#endif
for ( ; (c = index(s,',')) != Nullch; s = ++c) {
/* for each range */
ART_NUM min, max;
*c = '\0'; /* do not let index see past comma */
if ((h = index(s,'-')) != Nullch) { /* is there a -? */
min = atol(s);
max = atol(h+1);
if (min < firstbit) /* make sure range is in range */
min = firstbit;
if (max > lastart)
max = lastart;
if (min <= max) /* non-null range? */
unread -= max - min + 1;/* adjust unread count */
for (i=min; i<=max; i++) /* for all articles in range */
ctl_set(i); /* mark them read */
}
else if ((i = atol(s)) >= firstbit && i <= lastart) {
/* is single number reasonable? */
ctl_set(i); /* mark it read */
unread--; /* decrement articles to read */
}
#ifdef DEBUGGING
if (debug & DEB_CTLAREA_BITMAP) {
printf("\n%s\n",s) FLUSH;
for (i=1; i <= lastart; i++)
if (! was_read(i))
printf("%ld ",(long)i) FLUSH;
}
#endif
}
#ifdef DEBUGGING
if (debug & DEB_CTLAREA_BITMAP) {
fputs("\n(hit CR)",stdout) FLUSH;
gets(cmd_buf);
}
#endif
if (mybuf != buf)
free(mybuf);
toread[ng] = unread;
return 0;
}
void
grow_ctl()
{
ART_NUM newlast;
ART_NUM tmpfirst;
MEM_SIZE newsize;
register ART_NUM i;
forcegrow = FALSE;
newlast = getngsize(ng);
if (newlast > lastart) {
ART_NUM tmpart = art;
#ifndef lint
newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
#else
newsize = Null(MEM_SIZE);
#endif lint
if (newsize > ctlsize) {
newsize += 20;
ctlarea = saferealloc(ctlarea,newsize);
ctlsize = newsize;
}
toread[ng] += (ART_UNREAD)(newlast-lastart);
for (i=lastart+1; i<=newlast; i++)
ctl_clear(i); /* these articles are unread */
#ifdef CACHESUBJ
if (subj_list != Null(char**)) {
#ifndef lint
subj_list = (char**)saferealloc((char*)subj_list,
(MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
#endif lint
for (i=lastart+1; i<=newlast; i++)
subj_list[OFFSET(i)] = Nullch;
}
#endif
tmpfirst = lastart+1;
lastart = newlast;
#ifdef KILLFILES
#ifdef VERBOSE
IF(verbose)
sprintf(buf,
"%ld more article%s arrived--looking for more to kill...\n\n",
(long)(lastart - tmpfirst + 1),
(lastart > tmpfirst ? "s have" : " has" ) );
ELSE /* my, my, how clever we are */
#endif
#ifdef TERSE
strcpy(buf, "More news--killing...\n\n");
#endif
kill_unwanted(tmpfirst,buf,TRUE);
#endif
art = tmpart;
}
}
!STUFFY!FUNK!
echo Extracting INIT
cat >INIT <<'!STUFFY!FUNK!'
-ESAMPLE="sample"
!STUFFY!FUNK!
echo ""
echo "End of kit 5 (of 9)"
cat /dev/null >kit5isdone
config=true
for iskit in 1 2 3 4 5 6 7 8 9 ; 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