#! /bin/sh
# Make a new directory for the rn sources, cd to it, and run kits 1 thru 11 
# through sh.  When all 11 kits have been run, read README.

echo "This is rn kit 8 (of 11).  If kit 8 is complete, the line"
echo '"'"End of kit 8 (of 11)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting ngdata.c
cat >ngdata.c <<'!STUFFY!FUNK!'
/* $Id: ngdata.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
 *
 * $Log: ngdata.c,v $
 * Revision 4.4.3.1  1992/02/01  03:09:32  sob
 * Release 4.4 Patchlevel 3
 *
 * Revision 4.4.2.1  1991/12/01  18:05:42  sob
 * Patchlevel 2 changes
 *
 * Revision 4.4.1.1  1991/09/25  19:38:08  sob
 * Some adaptions for CNEWS
 *
 * Revision 4.4  1991/09/09  20:23:31  sob
 * release 4.4
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "ndir.h"
#include "rcstuff.h"
#include "rn.h"
#include "ng.h"
#include "intrp.h"
#include "final.h"
#include "rcln.h"
#include "util.h"
#ifdef SERVER
#include "server.h"
#endif
#include "INTERN.h"
#include "ngdata.h"

void
ngdata_init()
{
    char *cp;

    /* open the active file */

#ifdef SERVER
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf(">LIST\n") FLUSH;
#endif
    put_server("LIST");		/* tell server we want the active file */
    nntp_get(ser_line, sizeof(ser_line));
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf("<%s\n", ser_line) FLUSH;
#endif
    if (*ser_line != CHAR_OK) {		/* and then see if that's ok */
	fprintf(stdout, "Can't get active file from server: \n%s\n", ser_line);
	finalize(1);
    }
    time(&lastactfetch);

    cp = filexp("%P/rrnact.%$");	/* make a temporary name */
    strcpy(active_name, cp);
    actfp = fopen(active_name, "w+");	/* and get ready */
    if (actfp == Nullfp) {
	printf(cantopen,active_name) FLUSH;
	finalize(1);
    }

    activeitems = 0;
    while (1) {
	if (nntp_get(ser_line, sizeof(ser_line)) < 0) {
	    printf("Can't get active file from server:\ntransfer failed after %d entries\n", activeitems);
	    finalize(1);
	}
	if (ser_line[0] == '.')		/* while there's another line */
		break;			/* get it and write it to */
	activeitems++;
	fputs(ser_line, actfp);
	putc('\n', actfp);
    }

    if (ferror(actfp)) {
	printf("Error writing to active file %s.\n", active_name) FLUSH;
	finalize(1);
    }
#else /* not SERVER */

    cp = filexp(ACTIVE);
    actfp = fopen(cp,"r");
    if (actfp == Nullfp) {
	printf(cantopen,cp) FLUSH;
	finalize(1);
    }
    activeitems = 0;
    /* count entries */
    while(fgets(buf,LBUFLEN,actfp) != NULL)
	activeitems++;
#endif
    if (fseek(actfp,0L,0) == -1) {	/* just get to the beginning */
	printf("Error seeking in active file.\n") FLUSH;
	finalize(1);
    }

    return;
}

/* find the maximum article number of a newsgroup */

ART_NUM
getngsize(num)
register NG_NUM num;
{
    register int len;
    register char *nam;
    char tmpbuf[80];
    ART_POS oldsoft;
    long last;

    nam = rcline[num];
    len = rcnums[num] - 1;
    softtries++;
#ifdef DEBUGGING
    if (debug & DEB_SOFT_POINTERS)
	printf("Softptr = %ld\n",(long)softptr[num]) FLUSH;
#endif
    oldsoft = softptr[num];
    if ((softptr[num] = findact(tmpbuf, nam, len, (long)oldsoft)) >= 0) {
	if (softptr[num] != oldsoft) {
	    softmisses++;
	    writesoft = TRUE;
	}
    }
    else {
	softptr[num] = 0;
	if (rcchar[num] == ':')		/* unsubscribe quietly */
	    rcchar[num] = NEGCHAR;
	return TR_BOGUS;		/* well, not so quietly, actually */
    }
	
#ifdef DEBUGGING
    if (debug & DEB_SOFT_POINTERS) {
	printf("Should be %ld\n",(long)softptr[num]) FLUSH;
    }
#endif
    {
	register char *s;
	ART_NUM tmp;

	for (s=tmpbuf+len+1; isdigit(*s); s++) ;
	if (tmp = atol(s))
#ifdef MININACT
#ifdef CACHEFIRST
	    abs1st[num] = tmp;
#else
	    abs1st = tmp;
#endif
#endif
	if (!in_ng) {
	    for (s++; isdigit(*s); s++) ;
	    while (isspace(*s)) s++;
	    switch (*s) {
	    case 'n': moderated = getval("NOPOSTRING"," (no posting)"); break;
	    case 'm': moderated = getval("MODSTRING", " (moderated)"); break;
	    /* This shouldn't even occur.  What are we doing in a non-existent
	       group?  Disallow it. */
	    case 'x': return TR_BOGUS;
	    /* what should be done about refiled groups?  rn shouldn't even
	       be in them (ie, if sci.aquaria is refiled to rec.aquaria, then
	       get the news there) */
	    case '=': return TR_BOGUS;
	    default: moderated = nullstr;
	    }
	}
    }
    last = atol(tmpbuf+len+1);
    if (last < ngmax[num]) {
#ifdef SERVER
	if (time(Null(time_t*)) - lastactfetch > MINFETCHTIME) {
	    fclose(actfp);
	    ngdata_init();	/* re-grab the active file */
	}
#endif
	return ngmax[num];
    }
    return (ART_NUM)last;
}

ACT_POS
findact(outbuf,nam,len,suggestion)
char *outbuf;
char *nam;
int len;
long suggestion;
{
    ACT_POS retval;

    fseek(actfp,100000L,1);	/* hopefully this forces a reread */
    if (suggestion == 0L || fseek(actfp,suggestion,0) < 0 ||
      fgets(outbuf,80,actfp) == Nullch ||
      outbuf[len] != ' ' ||
      strnNE(outbuf,nam,len)) {
#ifdef DEBUGGING
	if (debug & DEB_SOFT_POINTERS)
	    printf("Missed, looking for %s in %sLen = %d\n",nam,outbuf,len)
	      FLUSH;
#endif
	fseek(actfp,0L,0);
#ifndef lint
	retval = (ACT_POS)ftell(actfp);
#else
	retval = Null(ACT_POS);
#endif /* lint */
	while (fgets(outbuf,80,actfp) != Nullch) {
	    if (outbuf[len] == ' ' && strnEQ(outbuf,nam,len))
		return retval;
#ifndef lint
	    retval = (ACT_POS) ftell(actfp);
#endif /* lint */
	    if (ferror(actfp)) {
		perror("error on active file"); /* something is wrong */
		sig_catcher(0);
	    }
	}
	if(ferror(actfp)) {
	    perror("error on active file");
	    sig_catcher(0);
	}
	return (ACT_POS) -1;
    }
    else
#ifndef lint
	return (ACT_POS) suggestion;
#else
	return retval;
#endif /* lint */
    /*NOTREACHED*/
}

/* determine the absolutely first existing article number */
#ifdef SERVER
ART_NUM
getabsfirst(ngnum,ngsize)
register NG_NUM ngnum;
ART_NUM ngsize;
{
    long a1st, last;

#ifdef CACHEFIRST
    if (a1st = abs1st[ngnum])
	return (ART_NUM)a1st;
#endif
#ifdef MININACT
    getngsize(ngnum);
# ifdef CACHEFIRST
    return abs1st[ngnum];
# else
    return abs1st;
# endif
#else
    getngsize(ngnum); /* set moderated as side effect */
    sprintf(ser_line,"GROUP %s",rcline[ngnum]);
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf(">%s\n", ser_line) FLUSH;
#endif
    put_server(ser_line);
    if (nntp_get(ser_line, sizeof(ser_line)) < 0) {
	fprintf(stderr, "\nrrn: Unexpected close of server socket.\n");
	finalize(1);
    }
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf("<%s\n", ser_line) FLUSH;
#endif
    if (*ser_line == CHAR_FATAL){
	fprintf(stderr,"\nrrn: %s\n",ser_line);
	finalize(1);
    }
    if (*ser_line != CHAR_OK)		/* and then see if that's ok */
	a1st = ngsize+1;		/* nothing there */
    else {
	(void) sscanf(ser_line,"%*d%*d%ld%ld",&a1st,&last);
	ngmax[ngnum] = last;
    }
# ifdef CACHEFIRST
    abs1st[ngnum] = (ART_NUM)a1st;
# endif
    return (ART_NUM)a1st;
#endif
}
/* we already know the lowest article number with NNTP */
ART_NUM
getngmin(dirname,floor)
char *dirname;
ART_NUM floor;
{
    return(floor);		/* dirname not used */
}

#else /*SERVER*/

ART_NUM
getabsfirst(ngnum,ngsize)
register NG_NUM ngnum;
ART_NUM ngsize;
{
    register ART_NUM a1st;
#ifndef MININACT
    char dirname[MAXFILENAME];
#endif

#ifdef CACHEFIRST
    if (a1st = abs1st[ngnum])
	return a1st;
#endif
#ifdef MININACT
    getngsize(ngnum);
# ifdef CACHEFIRST
    return abs1st[ngnum];
# else
    return abs1st;
# endif
#else /* not MININACT */
    getngsize(ngnum); /* set moderate as side effect */
    sprintf(dirname,"%s/%s",spool,getngdir(rcline[ngnum]));
    a1st = getngmin(dirname,0L);
    if (!a1st)				/* nothing there at all? */
	a1st = ngsize+1;		/* aim them at end of newsgroup */
# ifdef CACHEFIRST
    abs1st[ngnum] = a1st;
# endif
    return a1st;
#endif /* MININACT */
}

/* scan a directory for minimum article number greater than floor */

ART_NUM
getngmin(dirname,floor)
char *dirname;
ART_NUM floor;
{
    register DIR *dirp;
    register struct DIRTYPE *dp;
    register ART_NUM min = 1000000;
    register ART_NUM maybe;
    register char *p;
#ifdef notdef
    char tmpbuf[128];
#endif
    
    dirp = opendir(dirname);
    if (!dirp)
	return 0;
    while ((dp = readdir(dirp)) != Null(struct DIRTYPE *)) {
	if ((maybe = atol(dp->d_name)) < min && maybe > floor) {
	    for (p = dp->d_name; *p; p++)
		if (!isdigit(*p))
		    goto nope;
#ifdef notdef
	   /* 
	    * If newsgroup names ever go entirely numeric, then
	    * this code will have to be reinserted.
	    * For the time being, we assume that if a numeric name is
	    * found, it must be an article (and not a directory).
	    * This will avoid two stat(2) calls for those running
	    * rn.
	    */
	    if (*dirname == '.' && !dirname[1])
		stat(dp->d_name, &filestat);
	    else {
		sprintf(tmpbuf,"%s/%s",dirname,dp->d_name);
		stat(tmpbuf, &filestat);
	    }
	    if (! (filestat.st_mode & S_IFDIR))
#endif
		min = maybe;
	}
      nope:
	;
    }
    closedir(dirp);
    return min==1000000 ? 0 : min;
}
#endif
!STUFFY!FUNK!
echo Extracting head.c
cat >head.c <<'!STUFFY!FUNK!'
/* $Id: head.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
 *
 * $Log: head.c,v $
 * Revision 4.4.3.1  1992/02/01  03:09:32  sob
 * Release 4.4 Patchlevel 3
 *
 * Revision 4.4  1991/09/09  20:18:23  sob
 * release 4.4
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "artio.h"
#include "bits.h"
#ifdef SERVER
#include "server.h"
#endif
#include "util.h"
#include "INTERN.h"
#include "head.h"

bool first_one;		/* is this the 1st occurance of this header line? */

static char htypeix[26] =
    {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};

void
head_init()
{
    register int i;

    for (i=HEAD_FIRST+1; i<HEAD_LAST; i++)
	htypeix[*htype[i].ht_name - 'a'] = i;
}

#ifdef DEBUGGING
void
dumpheader(where)
char *where;
{
    register int i;

    printf("header: %d %s", parsed_art, where);

    for (i=0; i<HEAD_LAST; i++) {
	printf("%15s %4d %4d %03o\n",htype[i].ht_name,
	    htype[i].ht_minpos,
	    htype[i].ht_maxpos,
	    htype[i].ht_flags) FLUSH;
    }
}
#endif

int
set_line_type(bufptr,colon)
char *bufptr;
register char *colon;
{
    char lc[LONGKEY+3];
    register char *t, *f;
    register int i, len;

    if (colon-bufptr > LONGKEY+2)
	return SOME_LINE;

    for (t=lc,f=bufptr; f<colon; f++, t++) {
	if (isspace(*f))
	/* guard against space before : */
	    break;
	*t = isupper(*f) ? tolower(*f) : *f;
    }
    *t = '\0';
    f = lc;				/* get lc into register */
    len = t - f;

    /* now scan the headtype table, backwards so we don't have to supply an
     * extra terminating value, using first letter as index, and length as
     * optimization to avoid calling subroutine strEQ unnecessarily.  Hauls.
     */
    
    if (islower(*f)) {
	for (i = htypeix[*f - 'a']; *htype[i].ht_name == *f; --i) {
	    if (len == htype[i].ht_length && strEQ(f, htype[i].ht_name)) {
		return i;
	    }
	}
    }
    return SOME_LINE;
}

void
start_header(artnum)
ART_NUM artnum;
{
    register int i;

#ifdef DEBUGGING
    if (debug & 4)
	dumpheader("start_header\n");
#endif
    for (i=0; i<HEAD_LAST; i++) {
	htype[i].ht_minpos = -1;
	htype[i].ht_maxpos = 0;
    }
    in_header = SOME_LINE;
    first_one = FALSE;
#ifdef ASYNC_PARSE
    parsed_art = artnum;
#endif
}

bool
parseline(art_buf,newhide,oldhide)
char *art_buf;
int newhide, oldhide;
{
    if (*art_buf == ' ' || *art_buf == '\t')
					/* header continuation line? */
	return oldhide;
    else {				/* maybe another header line */
	char *s;

	if (first_one) {		/* did we just pass 1st occurance? */
	    first_one = FALSE;
	    htype[in_header].ht_maxpos = artpos;
					/* remember where line left off */
	}
	s = index(art_buf,':');
	if (s == Nullch) {
			    /* is it the end of the header? */
	    htype[PAST_HEADER].ht_minpos =
		(*art_buf == '\n') ? ftell(artfp) : artpos;
			    /* remember where body starts */
	    in_header = PAST_HEADER;
	}
	else {	/* it is a new header line */
	    in_header = set_line_type(art_buf,s);
	    first_one = (htype[in_header].ht_minpos < 0);
	    if (first_one)
		htype[in_header].ht_minpos = artpos;
#ifdef DEBUGGING
	    if (debug & 4)
		dumpheader(art_buf);
#endif
	    if (htype[in_header].ht_flags & HT_HIDE)
		return newhide;
	}
    }
    return FALSE;			/* don't hide this line */
}

#ifdef ASYNC_PARSE
int
parse_maybe(artnum)
ART_NUM artnum;
{
    char tmpbuf[LBUFLEN];

    if (parsed_art == artnum)
	return 0;
    /* no maybe about it now */
#ifdef SERVER
    if (nntpopen(artnum,GET_HEADER) == Nullfp) {
#else
    if (artopen(artnum) == Nullfp) {
#endif
	return -1;
    }
    start_header(artnum);
    while (in_header) {
	artpos = ftell(artfp);
	if (fgets(tmpbuf,LBUFLEN,artfp) == Nullch)
	    break;
	parseline(tmpbuf,FALSE,FALSE);
    }
    in_header = PAST_HEADER;
    return 0;
}
#endif

/* get the subject line for an article */

char *
fetchsubj(artnum,current_subject,copy)
ART_NUM artnum;				/* article to get subject from */
bool_int current_subject;		/* is it in a parsed header? */
bool_int copy;				/* do you want it savestr()ed? */
{
    char *s = Nullch, *t;
#ifdef SERVER
    static int xhdr = 1;		/* Can we use xhdr command? */
    int eoo;				/* End of server output */
#endif /* SERVER */

#ifdef CACHESUBJ
    if (!subj_list) {
	register ART_NUM i;
	

#ifndef lint
	subj_list =
	  (char**)safemalloc((MEM_SIZE)((OFFSET(lastart)+2)*sizeof(char *)));
#endif /* lint */
	for (i=0; i<=OFFSET(lastart); i++)
	    subj_list[i] = Nullch;
    }
    if (!artnum || artnum > lastart)
	s = nullstr;
    else
	s = subj_list[OFFSET(artnum)];
#endif
    if (s == Nullch) {
	if (current_subject) {
	    s = fetchlines(artnum,SUBJ_LINE);
#ifdef CACHESUBJ
	    subj_list[OFFSET(artnum)] = s;
#endif
	}
	else {
	    s = safemalloc((MEM_SIZE)LBUFLEN);
	    *s = '\0';
#ifdef SERVER
	    if (xhdr) {
	    	sprintf(ser_line, "XHDR subject %ld", artnum);
	    	put_server(ser_line);
#ifdef DEBUGGING
		if (debug & DEB_NNTP)
		    printf(">%s\n", ser_line) FLUSH;
#endif
		if (nntp_get(ser_line, sizeof (ser_line)) >= 0) {
#ifdef DEBUGGING
			if (debug & DEB_NNTP)
			    printf("<%s\n", ser_line) FLUSH;
#endif
			if (ser_line[0] == CHAR_FATAL) {
				fprintf(stderr,"\nrrn: %s\n",ser_line);
				finalize(1);
/*			    xhdr = 0; */
			} else {
			    while (nntp_get(ser_line, sizeof (ser_line)) >= 0) {
#ifdef DEBUGGING
				if (debug & DEB_NNTP)
				    printf("<%s\n", ser_line) FLUSH;
#endif
				if (ser_line[0] == '.')
				    break;
				else {
				    t = index(ser_line, ' ');
				    if (t++) {
					strcpy(s, t);
					if (t = index(s, '\r'))
						*t = '\0';
				    }
				}
			    }
			}
		} else {
		    fprintf(stderr,
			"\nrrn: Unexpected close of server socket.\n");
		    finalize(1);
		}
	    }

	    if (!xhdr) {
		sprintf(ser_line, "HEAD %ld", artnum);
		put_server(ser_line);
#ifdef DEBUGGING
		if (debug & DEB_NNTP)
		    printf(">%s\n", ser_line) FLUSH;
#endif
		eoo = 0;
		if (nntp_get(ser_line, sizeof (ser_line)) >= 0 && 
			ser_line[0] == CHAR_OK) {
		    do {
			if (nntp_get(s, LBUFLEN) < 0 || (*s == '.')) {
			strcpy(s, "Title: \n");
			eoo = 1;
		        }
		    } while (strnNE(s,"Title:",6) && strnNE(s,"Subject:",8));

		    if (!eoo)
			while (nntp_get(ser_line, sizeof (ser_line)) >= 0 &&
				ser_line[0] != '.');
		    t = index(s,':')+1;
		    while (*t == ' ') t++;
		    strcpy(s, t);
	        }
	    }
#else /* not SERVER */
	    if (artopen(artnum) != Nullfp) {
		do {
		    if (fgets(s,LBUFLEN,artfp) == Nullch)
			strcpy(s, "Title: \n");
		} while (strnNE(s,"Title:",6) && strnNE(s,"Subject:",8));

		s[strlen(s)-1] = '\0';
		t = index(s,':')+1;
		while (*t == ' ') t++;
		strcpy(s, t);
	    }
#endif
	    s = saferealloc(s, (MEM_SIZE)strlen(s)+1);
#ifdef CACHESUBJ
	    subj_list[OFFSET(artnum)] = s;
#endif 
	}
    }
#ifdef CACHESUBJ
    if (copy) {
	t = savestr(s);
	return t;
    }
    else
	return s;
#else
    if (copy)
	return s;
    else {
	safecpy(cmd_buf,s,CBUFLEN);	/* hope this is okay--we're */
	free(s);
	return cmd_buf;			/* really scraping for space here */
    }
#endif
}

/* get header lines from an article */

char *
fetchlines(artnum,which_line)
ART_NUM artnum;				/* article to get line from */
int which_line;				/* type of line desired */
{
    char *newbuf, *t, tmp_buf[LBUFLEN];
    register ART_POS curpos;
    int size;
    register ART_POS firstpos;
    register ART_POS lastpos;
    
#ifdef ASYNC_PARSE
    if (parse_maybe(artnum))
	artnum = 0;
#endif
    firstpos = htype[which_line].ht_minpos;
    lastpos = htype[which_line].ht_maxpos;
#ifdef SERVER
    if (!artnum || firstpos < 0 || nntpopen(artnum,GET_HEADER) == Nullfp) {
#else
    if (!artnum || firstpos < 0 || artopen(artnum) == Nullfp) {
#endif
	newbuf = safemalloc((unsigned int)1);
	*newbuf = '\0';
	return newbuf;
    }
#ifndef lint
    size = lastpos - firstpos + 1;
#else
    size = Null(int);
#endif /* lint */
#ifdef DEBUGGING
    if (debug && (size < 1 || size > 1000)) {
	printf("Firstpos = %ld, lastpos = %ld\n",(long)firstpos,(long)lastpos);
	gets(tmp_buf);
    }
#endif
    newbuf = safemalloc((unsigned int)size);
    *newbuf = '\0';
    fseek(artfp,firstpos,0);
    for (curpos = firstpos; curpos < lastpos; curpos = ftell(artfp)) {
	if (fgets(tmp_buf,LBUFLEN,artfp) == Nullch)
	    break;
	if (*tmp_buf == ' ' || *tmp_buf == '\t')
	    t = tmp_buf;
	else {
	    t = index(tmp_buf,':');
	    if (t == Nullch)
		break;
	    t++;
	}
	while (*t == ' ' || *t == '\t') t++;
	safecat(newbuf,t,size);
    }
    return newbuf;
}

!STUFFY!FUNK!
echo Extracting addng.c
cat >addng.c <<'!STUFFY!FUNK!'
/* $Id: addng.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
 *
 * $Log: addng.c,v $
 * Revision 4.4.3.1  1992/02/01  03:09:32  sob
 * Release 4.4 Patchlevel 3
 *
 * Revision 4.4.2.1  1991/12/01  18:05:42  sob
 * Patchlevel 2 changes
 *
 * Revision 4.4  1991/09/09  20:18:23  sob
 * release 4.4
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "rn.h"
#include "ngdata.h"
#include "last.h"
#include "util.h"
#include "intrp.h"
#include "only.h"
#include "rcstuff.h"
#ifdef SERVER
#include "server.h"
#endif
#include "final.h"
#include "INTERN.h"
#include "addng.h"
#include <time.h>

void
addng_init()
{
    ;
}

#ifdef FINDNEWNG
/* generate a list of new newsgroups from active file */

bool
newlist(munged,checkinlist)
bool_int munged;			/* are we scanning the whole file? */
bool_int checkinlist;
{
    char *tmpname;
    register char *s, *status;
    register NG_NUM ngnum;
#ifndef ACTIVE_TIMES
    long birthof();
#endif

    tmpname = filexp(RNEWNAME);
    tmpfp = fopen(tmpname,"w+");
    if (tmpfp == Nullfp) {
	printf(cantcreate,tmpname) FLUSH;
	return FALSE;
    }
    UNLINK(tmpname);			/* be nice to the world */

    while (fgets(buf,LBUFLEN,actfp) != Nullch) {
	/* Check if they want to break out of the new newsgroups search */
	if (int_count) {
	    int_count = 0;
	    fclose(tmpfp);
	    return FALSE;
	}
	if (s = index(buf,' ')) {
	    status=s;
	    while (isdigit(*status) || isspace(*status)) status++;
	    *s++ = '\0';
	    if (strnEQ(buf,"to.",3) || *status == 'x' || *status == '=')
	        /* since = groups are refiling to another group, just
		   ignore their existence */
		continue;
#ifdef ACTIVE_TIMES
	    if (inlist(buf) && ((ngnum = find_ng(buf)) == nextrcline
				|| toread[ngnum] == TR_UNSUB)
#else
	    if (checkinlist ?
		(inlist(buf) && ((ngnum = find_ng(buf)) == nextrcline
				 || toread[ngnum] == TR_UNSUB))
	      : (find_ng(buf) == nextrcline
		 && birthof(buf,(ART_NUM)atol(s)) > lasttime)
#endif
	    ) {
					/* if not in .newsrc and younger */
					/* than the last time we checked */
		fprintf(tmpfp,"%s\n",buf);
					/* then remember said newsgroup */
	    }
#ifdef FASTNEW
	    else {			/* not really a new group */
		if (!munged) {		/* did we assume not munged? */
		    fclose(tmpfp);	/* then go back, knowing that */
		    return TRUE;	/* active file was indeed munged */
		}
	    }
#endif
	}
#ifdef DEBUGGING
	else
	    printf("Bad active record: %s\n",buf) FLUSH;
#endif
    }

    /* we have successfully generated the list */

    fseek(tmpfp,0L,0);			/* rewind back to the beginning */
    while (fgets(buf,LBUFLEN,tmpfp) != Nullch) {
	buf[strlen(buf)-1] = '\0';
	get_ng(buf,TRUE);		/* add newsgroup, maybe */
    }
    fclose(tmpfp);			/* be nice to ourselves */
    return FALSE;			/* do not call us again */
}

#ifdef ACTIVE_TIMES
#ifdef SERVER

bool
find_new_groups()
{
    char *tmpname;
    register char *s;
    struct tm *ts;
    long now;
    NG_NUM oldnext = nextrcline;	/* remember # lines in newsrc */

    tmpname = filexp(RNEWNAME);
    tmpfp = fopen(tmpname,"w+");
    if (tmpfp == Nullfp) {
	printf(cantcreate,tmpname) FLUSH;
	return FALSE;
    }
    UNLINK(tmpname);			/* be nice to the world */

    time(&now);
    ts = gmtime(&lastnewtime);
    sprintf(ser_line, "NEWGROUPS %02d%02d%02d %02d%02d%02d GMT",
	ts->tm_year % 100, ts->tm_mon+1, ts->tm_mday,
	ts->tm_hour, ts->tm_min, ts->tm_sec);
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf(">%s\n", ser_line) FLUSH;
#endif
    put_server(ser_line);
    nntp_get(ser_line, sizeof(ser_line));
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf("<%s\n", ser_line) FLUSH;
#endif
    if (*ser_line != CHAR_OK) {		/* and then see if that's ok */
  error_exit:
	fclose(tmpfp);
	printf("Can't get new groups from server:\n%s\n", ser_line);
	return FALSE;
    }

    while (1) {
	if (nntp_get(ser_line, sizeof(ser_line)) < 0)
	    goto error_exit;
#ifdef DEBUGGING
	if (debug & DEB_NNTP)
	    printf("<%s\n", ser_line) FLUSH;
#endif
	if (ser_line[0] == '.')
	    break;
	if ((s = index(ser_line, ' ')) != Nullch)
	    *s = '\0';
	fprintf(tmpfp,"%s\n",ser_line);
    }

    /* we have successfully generated the list */

    if (ftell(tmpfp)) {
	fputs("\nFinding new newsgroups:\n",stdout) FLUSH;

	fseek(tmpfp,0L,0);		/* rewind back to the beginning */
	while (fgets(buf,LBUFLEN,tmpfp) != Nullch) {
	    buf[strlen(buf)-1] = '\0';
	    get_ng(buf,FALSE);		/* add newsgroup, maybe */
	}
	lastnewtime = now;		/* remember when we found new groups */
    }					/* (ends up back in .rnlast) */
    fclose(tmpfp);			/* be nice to ourselves */

    return oldnext != nextrcline;
}
#else /* not SERVER */

bool
find_new_groups()
{
    register char *s;
    long lastone;
    NG_NUM oldnext = nextrcline;	/* remember # lines in newsrc */

    fstat(fileno(actfp),&filestat);	/* find active file size */
    lastactsiz = filestat.st_size;	/* just to save it in .rnlast */

    stat(ACTIVE_TIMES,&filestat);	/* did active.times file grow? */
    if (filestat.st_size == lastnewsize)
	return FALSE;
    lastnewsize = filestat.st_size;

    fputs("\nChecking for new newsgroups...\n",stdout) FLUSH;

    s = filexp(ACTIVE_TIMES);
    tmpfp = fopen(s,"r");
    if (tmpfp == Nullfp) {
	printf(cantopen,s) FLUSH;
	return FALSE;
    }
    lastone = time(Null(time_t*)) - 24L * 60 * 60 - 1;
    while (fgets(buf,LBUFLEN,tmpfp) != Nullch) {
	if ((s = index(buf, ' ')) != Nullch)
	    if ((lastone = atol(s+1)) >= lastnewtime) {
		char tmpbuf[80];
		*s = '\0';
		if (findact(tmpbuf, buf, s - buf, 0L) >= 0)
		    get_ng(buf,FALSE);	/* add newsgroup, maybe */
	    }
    }
    fclose(tmpfp);
    lastnewtime = lastone+1;		/* remember time of last new group */
					/* (ends up back in .rnlast) */
    return oldnext != nextrcline;
}
#endif /* SERVER */
#else /* not ACTIVE_TIMES */

bool
find_new_groups()
{
    long oldactsiz = lastactsiz;
    NG_NUM oldnext = nextrcline;	/* remember # lines in newsrc */

    fstat(fileno(actfp),&filestat);	/* did active file grow? */

    if (filestat.st_size == lastactsiz)
	return FALSE;
    lastactsiz = filestat.st_size;	/* remember new size */

#ifdef VERBOSE
    IF(verbose)
	fputs("\nChecking active file for new newsgroups...\n",stdout) FLUSH;
    ELSE
#endif
#ifdef TERSE
	fputs("\nNew newsgroups:\n",stdout) FLUSH;
#endif

#ifdef FASTNEW				/* bad soft ptrs -> edited active */
    if (!writesoft && oldactsiz) {	/* maybe just do tail of file? */
	fseek(actfp,oldactsiz-NL_SIZE,0);
	fgets(buf,LBUFLEN,actfp);
	if (*buf == '\n' && !newlist(FALSE,FALSE))
	    goto bugout;
    }
#endif
    fseek(actfp,0L,0);		/* rewind active file */
    newlist(TRUE,FALSE);		/* sure hope they use hashing... */
bugout:
    return oldnext != nextrcline;
}

/* return creation time of newsgroup */

long
birthof(ngnam,ngsize)
char *ngnam;
ART_NUM ngsize;
{
    char tst[128];
    long time();
 
#ifdef SERVER		/* ngsize not used */
    long tot;
    sprintf(tst,"GROUP %s",ngnam);
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf(">%s\n", tst) FLUSH;
#endif
    put_server(tst);
    (void) nntp_get(tst, sizeof(tst));
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf("<%s\n", tst) FLUSH;
#endif
    if (*tst != CHAR_OK) return(0); /* not a real group */
    (void) sscanf(tst,"%*d%ld",&tot);
    if (tot > 0) return(time(Null(long *)));
    else return(0);
#else /* not SERVER */

    sprintf(tst, ngsize ? "%s/%s/1" : "%s/%s" ,spool,getngdir(ngnam));
    if (stat(tst,&filestat) < 0)
	return (ngsize ? 0L : time(Null(long *)));
	/* not there, assume something good */
    else
	return filestat.st_mtime;

#endif
}
#endif /* ACTIVE_TIMES */

bool
scanactive()
{
    NG_NUM oldnext = nextrcline;	/* remember # lines in newsrc */

    fseek(actfp,0L,0);
    newlist(TRUE,TRUE);
    if (nextrcline != oldnext) {	/* did we add any new groups? */
	return TRUE;
    }
    return FALSE;
}

#endif

!STUFFY!FUNK!
echo Extracting artsrch.c
cat >artsrch.c <<'!STUFFY!FUNK!'
/* $Id: artsrch.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
 *
 * $Log: artsrch.c,v $
 * Revision 4.4.3.1  1992/02/01  03:09:32  sob
 * Release 4.4 Patchlevel 3
 *
 * Revision 4.4.2.1  1991/12/01  18:05:42  sob
 * Patchlevel 2 changes
 *
 * Revision 4.4  1991/09/09  20:18:23  sob
 * release 4.4
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "search.h"
#include "term.h"
#include "util.h"
#include "intrp.h"
#include "bits.h"
#include "kfile.h"
#include "head.h"
#include "final.h"
#include "cheat.h"
#ifdef SERVER
#include "server.h"
#endif
#include "ng.h"
#include "artio.h"
#include "INTERN.h"
#include "artsrch.h"

void
artsrch_init()
{
#ifdef ARTSEARCH
#ifdef ZEROGLOB
    init_compex(&sub_compex);
    init_compex(&art_compex);
#endif
#endif
}

/* search for an article containing some pattern */

#ifdef ARTSEARCH
int
art_search(patbuf,patbufsiz,get_cmd)
char *patbuf;				/* if patbuf != buf, get_cmd must */
int patbufsiz;
int get_cmd;				/*   be set to FALSE!!! */
{
    char *pattern;			/* unparsed pattern */
    register char cmdchr = *patbuf;	/* what kind of search? */
    register char *s;
    bool backward = cmdchr == '?' || cmdchr == Ctl('p');
					/* direction of search */
    COMPEX *compex;			/* which compiled expression */
    char *cmdlst = Nullch;		/* list of commands to do */
    int normal_return = SRCH_NOTFOUND;	/* assume no commands */
    bool saltaway = FALSE;		/* store in KILL file? */
    char howmuch;			/* search just the subjects */
    bool doread;			/* search read articles? */
    bool foldcase = TRUE;		/* fold upper and lower case? */

    int_count = 0;
    if (cmdchr == '/' || cmdchr == '?') {	/* normal search? */
	if (get_cmd && buf == patbuf)
	    if (!finish_command(FALSE))	/* get rest of command */
		return SRCH_ABORT;
	compex = &art_compex;
	if (patbuf[1]) {
	    howmuch = 0;
	    doread = FALSE;
	}
	else {
	    howmuch = art_howmuch;
	    doread = art_doread;
	}
	s = cpytill(buf,patbuf+1,cmdchr);/* ok to cpy buf+1 to buf */
	pattern = buf;
	if (*pattern) {
	    if (*lastpat)
		free(lastpat);
	    lastpat = savestr(pattern);
	}
	if (*s) {			/* modifiers or commands? */
	    for (s++; *s && index("Kharc",*s); s++) {
		if (*s == 'h')		/* scan header */
		    howmuch = 1;
		else if (*s == 'a')	/* scan article */
		    howmuch = 2;
		else if (*s == 'r')	/* scan read articles */
		    doread = TRUE;
		else if (*s == 'K')	/* put into KILL file */
		    saltaway = TRUE;
		else if (*s == 'c')	/* make search case sensitive */
		    foldcase = FALSE;
	    }
	}
	while (isspace(*s) || *s == ':')
	    s++;
	if (*s) {
	    if (*s == 'm' || *s == 'M')
		doread = TRUE;
	    if (*s == 'k')		/* grandfather clause */
		*s = 'j';
	    cmdlst = savestr(s);
	    normal_return = SRCH_DONE;
	}
	art_howmuch = howmuch;
	art_doread = doread;
	if (srchahead)
	    srchahead = -1;
    }
    else {
	register char *h;

	howmuch = 0;			/* just search subjects */
	doread = (cmdchr == Ctl('p'));
	if (cmdchr == Ctl('n'))
	    normal_return = SRCH_SUBJDONE;
	compex = &sub_compex;
	pattern = patbuf+1;
	strcpy(pattern,": *");
	h = pattern + strlen(pattern);
	interp(h,patbufsiz - (h-patbuf),"%\\s");  /* fetch current subject */
	if (cmdchr == 'K') {
	    saltaway = TRUE;
	    cmdchr = 'k';
	}
	if (cmdchr == 'k') {
	    normal_return = SRCH_DONE;
	    cmdlst = savestr("j");
	    mark_as_read();		/* this article has this subject */
	    if (!*h) {
#ifdef VERBOSE
		IF(verbose)
		    fputs("\nCannot delete null subject.\n",stdout) FLUSH;
		ELSE
#endif
#ifdef TERSE
		    fputs("\nNull subject.\n",stdout) FLUSH;
#endif
		return SRCH_ABORT;
	    }
#ifdef VERBOSE
	    else if (verbose)
		printf("\nMarking subject \"%s\" as read.\n",h) FLUSH;
#endif
	}
	else if (!srchahead)
	    srchahead = -1;
	{			/* compensate for notesfiles */
	    register int i;
	    for (i = 24; *h && i--; h++)
		if (*h == '\\')
		    h++;
	    *h = '\0';
	}
#ifdef DEBUGGING
	if (debug) {
	    printf("\npattern = %s\n",pattern) FLUSH;
	}
#endif
    }
    if ((s = compile(compex,pattern,TRUE,foldcase)) != Nullch) {
					/* compile regular expression */
	printf("\n%s\n",s) FLUSH;
	return SRCH_ABORT;
    }
#ifdef KILLFILES
    if (saltaway) {
	char saltbuf[LBUFLEN];

	s = saltbuf;
	sprintf(s,"/%s/",pattern);
	s += strlen(s);
	if (doread)
	    *s++ = 'r';
	if (howmuch==1)
	    *s++ = 'h';
	else if (howmuch==2)
	    *s++ = 'a';
	*s++ = ':';
	if (!cmdlst)
	    cmdlst = savestr("j");
	safecpy(s,cmdlst,LBUFLEN-(s-saltbuf));
	kf_append(saltbuf);
    }
#endif
    if (cmdlst && index(cmdlst,'='))
	normal_return = SRCH_ERROR;	/* listing subjects is an error? */
    if (get_cmd) {
	fputs("\nSearching...\n",stdout) FLUSH;
					/* give them something to read */
    }
    if (backward) {
	if (cmdlst && art <= lastart)
	    art++;			/* include current article */
	if (doread)
	    check_first(absfirst);
    }
    else {
	if (art > lastart) {
	    art = (doread ? absfirst : firstart);
	    check_first(art--);
	}
	else if (cmdlst && art >= absfirst)
	    art--;			/* include current article */
    }
    if (srchahead > 0) {
	if (!backward)
	    art = srchahead - 1;
	srchahead = -1;
    }
    assert(!cmdlst || *cmdlst);
    perform_cnt = 0;
    for (;;) {
	if (backward ?
		(--art < absfirst || (!doread && art < firstart)) :
		(++art > lastart)
	  ) {			/* out of articles? */
	    if (cmdlst)
		free(cmdlst);
	    return normal_return;
	}
	if (int_count) {
	    int_count = 0;
	    if (cmdlst)
		free(cmdlst);
	    return SRCH_INTR;
	}
	/*NOSTRICT*/
	if (doread || !was_read(art)) {
	    if (wanted(compex,art,howmuch)) {
				    /* does the shoe fit? */
		if (cmdlst) {
		    if (perform(cmdlst,TRUE)) {
			if (cmdlst)
			    free(cmdlst);
			return SRCH_INTR;
		    }
		}
		else {
		    if (cmdlst)
			free(cmdlst);
		    return SRCH_FOUND;
		}
	    }
	    else if (!cmdlst && ! (art%50)) {
		printf("...%ld",(long)art);
		fflush(stdout);
	    }
	}
    }
}

/* determine if article fits pattern */
/* returns TRUE if it exists and fits pattern, FALSE otherwise */

bool
wanted(compex, artnum, scope)
COMPEX *compex;
ART_NUM artnum;
char_int scope;
{
    if (!scope) {
	char subj_buf[266];
	{
	    strcpy(subj_buf, "Subject: ");
	    strncpy(subj_buf+9,fetchsubj(artnum,FALSE,FALSE),256);
	}
#ifdef DEBUGGING
	if (debug & DEB_SEARCH_AHEAD)
	    printf("%s\n",subj_buf) FLUSH;
#endif
	return execute(compex,subj_buf) != Nullch;
    }
#ifdef CACHESUBJ
    else
	fetchsubj(artnum,FALSE,FALSE);/* might as well get subject handy */
#endif
    
#ifdef SERVER
    if (scope == 1){
	if (nntpopen(artnum,GET_HEADER) == Nullfp) /* we only need the header */
	    return FALSE;
    }
    else
#endif
    if (artopen(artnum) == Nullfp)	/* ensure that article is open */

	return FALSE;			/* if not, return NO MATCH */
    scope--;
    while (fgets(buf,LBUFLEN,artfp) != Nullch) {
					/* for each line of article */
	if (!scope && index(buf,':') == Nullch && *buf != ' ' && *buf != '\t')
					/* if headers only and out of header */
	    return FALSE;		/* say no go */
	if (execute(compex,buf) != Nullch) {
					/* does pattern matcher match? */
	    return TRUE;		/* say Eureka */
	}
    }
    return FALSE;			/* out of article, so no match */
}
#endif

!STUFFY!FUNK!
echo Extracting ngstuff.c
cat >ngstuff.c <<'!STUFFY!FUNK!'
/* $Id: ngstuff.c,v 4.4 1991/09/09 20:23:31 sob Exp sob $
 *
 * $Log: ngstuff.c,v $
 * Revision 4.4  1991/09/09  20:23:31  sob
 * release 4.4
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "term.h"
#include "util.h"
#include "ng.h"
#include "bits.h"
#include "intrp.h"
#include "cheat.h"
#include "head.h"
#include "final.h"
#include "sw.h"
#include "uudecode.h"
#include "INTERN.h"
#include "ngstuff.h"

void
ngstuff_init()
{
    ;
}

/* do a shell escape */

int
escapade()
{
    register char *s;
    bool interactive = (buf[1] == FINISHCMD);
    bool docd;
    char whereiam[512];

    if (!finish_command(interactive))	/* get remainder of command */
	return -1;
    s = buf+1;
    docd = *s != '!';
    if (!docd) {
	s++;
    }
    else {
	getwd(whereiam);
	if (chdir(cwd)) {
	    printf(nocd,cwd) FLUSH;
	    sig_catcher(0);
	}
    }
    while (*s == ' ') s++;
					/* skip leading spaces */
    interp(cmd_buf, (sizeof cmd_buf), s);/* interpret any % escapes */
    resetty();				/* make sure tty is friendly */
    doshell(Nullch,cmd_buf);	/* invoke the shell */
    noecho();				/* and make terminal */
    crmode();				/*   unfriendly again */
    if (docd) {
	if (chdir(whereiam)) {
	    printf(nocd,whereiam) FLUSH;
	    sig_catcher(0);
	}
    }
#ifdef MAILCALL
    mailcount = 0;			/* force recheck */
#endif
    return 0;
}

/* process & command */

int
switcheroo()
{
    if (!finish_command(TRUE)) /* get rest of command */
	return -1;	/* if rubbed out, try something else */
    if (!buf[1])
	pr_switches();
#ifdef PUSHBACK
    else if (buf[1] == '&') {
	if (!buf[2]) {
	    page_init();
	    show_macros();
	}
	else {
	    char tmpbuf[LBUFLEN];
	    register char *s;

	    for (s=buf+2; isspace(*s); s++);
	    mac_line(s,tmpbuf,(sizeof tmpbuf));
	}
    }
#endif
    else {
	bool docd = (instr(buf,"-d", TRUE) != Nullch);
 	char whereami[512];
 
	if (docd)
	    getwd(whereami);
	sw_list(buf+1);
	if (docd) {
	    cwd_check();
	    if (chdir(whereami)) {		/* -d does chdirs */
		printf(nocd,whereami) FLUSH;
		sig_catcher(0);
	    }
	}
    }
    return 0;
}

/* process range commands */

int
numnum()
{
    ART_NUM min, max;
    char *cmdlst = Nullch;
    register char *s, *c;
    ART_NUM oldart = art;
    char tmpbuf[LBUFLEN];
    bool justone = TRUE;		/* assume only one article */

    perform_cnt = 0;
    if (!finish_command(TRUE))	/* get rest of command */
	return NN_INP;
	if (lastart < 1) {
	    fputs("\nNo articles\n",stdout) FLUSH;
	    return NN_ASK;
	}
#ifdef ARTSRCH
    if (srchahead)
	srchahead = -1;
#endif
    for (s=buf; *s && (isdigit(*s) || index(" ,-.$",*s)); s++)
	if (!isdigit(*s))
	    justone = FALSE;
    if (*s) {
	cmdlst = savestr(s);
	justone = FALSE;
    }
    else if (!justone)
	cmdlst = savestr("m");
    *s++ = ',';
    *s = '\0';
    safecpy(tmpbuf,buf,LBUFLEN);
    for (s = tmpbuf; c = index(s,','); s = ++c) {
	*c = '\0';
	if (*s == '.')
	    min = oldart;
	else
	    min = atol(s);
	if (min<absfirst) {		/* make sure it is reasonable */
	    min = absfirst;
	    printf("(First article is %ld)\n",(long)absfirst) FLUSH;
	    pad(just_a_sec/3);
	}
	if ((s=index(s,'-')) != Nullch) {
	    s++;
	    if (*s == '$')
		max = lastart;
	    else if (*s == '.')
		max = oldart;
	    else
		max = atol(s);
	}
	else
	    max = min;
	if (max>lastart) {
	    max = lastart;
	    if (min > max)
		min = max;
	    printf("(Last article is %ld)\n",(long)lastart) FLUSH;
	    pad(just_a_sec/3);
	}
	if (max < min) {
	    fputs("\nBad range\n",stdout) FLUSH;
	    if (cmdlst)
		free(cmdlst);
	    return NN_ASK;
	}
	if (justone) {
	    art = min;
	    return NN_REREAD;
	}
	check_first(min);
	for (art=min; art<=max; art++) {
	    if (perform(cmdlst,TRUE)) {
#ifdef VERBOSE
		IF(verbose)
		    printf("\n(Interrupted at article %ld)\n",(long)art)
		      FLUSH;
		ELSE
#endif
#ifdef TERSE
		    printf("\n(Intr at %ld)\n",(long)art) FLUSH;
#endif
		if (cmdlst)
		    free(cmdlst);
		return NN_ASK;
	    }
	}
    }
    art = oldart;
    if (cmdlst)
	free(cmdlst);
    return NN_NORM;
}

int
perform(cmdlst,toplevel)
register char *cmdlst;
int toplevel;
{
    register int ch;
    
    if (toplevel) {
	printf("%-6ld ",art);
	fflush(stdout);
    }
    perform_cnt++;
    for (; ch = *cmdlst; cmdlst++) {
	if (isspace(ch) || ch == ':')
	    continue;
	if (ch == 'j') {
	    if (!was_read(art)) {
		mark_as_read();
#ifdef VERBOSE
		IF(verbose)
		    fputs("\tJunked",stdout);
#endif
	    }
	}
	else if (ch == 'm') {
	    if (was_read(art)) {
		unmark_as_read();
#ifdef VERBOSE
		IF(verbose)
		    fputs("\tMarked unread",stdout);
#endif
	    }
	}
	else if (ch == 'M') {
#ifdef DELAYMARK
	    delay_unmark(art);
#ifdef VERBOSE
	    IF(verbose)
		fputs("\tWill return",stdout);
#endif
#else
	    notincl("M");
	    return -1;
#endif
	}
	else if (ch == '=') {
	    printf("\t%s",fetchsubj(art,FALSE,FALSE));
#ifdef VERBOSE
	    IF(verbose)
		;
	    ELSE
#endif
		putchar('\n') FLUSH;		/* ghad! */
	}
	else if (ch == 'C') {
#ifdef ASYNC_PARSE
	    printf("\t%sancelled",(cancel_article() ? "Not c" : "C"));
#else
	    notincl("C");
	    return -1;
#endif
	}
	else if (ch == '%') {
#ifdef ASYNC_PARSE
	    char tmpbuf[512];

	    if (one_command)
		interp(tmpbuf, (sizeof tmpbuf), cmdlst);
	    else
		cmdlst = dointerp(tmpbuf, (sizeof tmpbuf), cmdlst, ":") - 1;
	    perform_cnt--;
	    if (perform(tmpbuf,FALSE))
		return -1;
#else
	    notincl("%");
	    return -1;
#endif
	}
	else if (index("!&sSwWe|",ch)) {
	    if (one_command)
		strcpy(buf,cmdlst);
	    else
		cmdlst = cpytill(buf,cmdlst,':') - 1;
	    /* we now have the command in buf */
	    if (ch == '!') {
		escapade();
#ifdef VERBOSE
		IF(verbose)
		    fputs("\tShell escaped",stdout);
#endif
	    }
	    else if (ch == '&') {
		switcheroo();
#ifdef VERBOSE
		IF(verbose)
		    if (buf[1] && buf[1] != '&')
			fputs("\tSwitched",stdout);
#endif
	    }
	    else {
		putchar('\t');
		save_article();
#ifdef VERBOSE
		IF(verbose)
		    ;
		ELSE
#endif
		    putchar('\n') FLUSH;
	    }
	}
	else {
	    printf("\t???%s\n",cmdlst);
	    return -1;
	}
#ifdef VERBOSE
	fflush(stdout);
#endif
	if (one_command)
	    break;
    }
    if (toplevel) {
#ifdef VERBOSE
	IF(verbose)
	    putchar('\n') FLUSH;
#endif
    }
    if( int_count ) {
	int_count = 0;
	return -1;
    }
    return 0;
}
!STUFFY!FUNK!
echo Extracting init.c
cat >init.c <<'!STUFFY!FUNK!'
/* $Id: init.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
 *
 * $Log: init.c,v $
 * Revision 4.4.3.1  1992/02/01  03:09:32  sob
 * Release 4.4 Patchlevel 3
 *
 * Revision 4.4  1991/09/09  20:18:23  sob
 * release 4.4
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "util.h"
#include "final.h"
#include "term.h"
#include "last.h"
#include "rn.h"
#include "rcstuff.h"
#include "ngdata.h"
#include "only.h"
#include "intrp.h"
#include "addng.h"
#include "sw.h"
#include "art.h"
#include "artsrch.h"
#include "artio.h"
#include "backpage.h"
#include "bits.h"
#include "cheat.h"
#include "head.h"
#include "help.h"
#include "kfile.h"
#include "ngsrch.h"
#include "ngstuff.h"
#include "rcln.h"
#include "respond.h"
#ifdef SERVER
#include "server.h"
#endif
#include "ng.h"
#include "INTERN.h"
#include "init.h"

bool
initialize(argc,argv)
int argc;
char *argv[];
{
    char *tcbuf;
    register bool foundany = FALSE;
    long time();
#ifdef SERVER
    char *server;
    int response;
#endif
#ifdef NOLINEBUF
    static char std_out_buf[BUFSIZ];	/* must be static or malloced */

    setbuf(stdout, std_out_buf);
#endif

    tcbuf = safemalloc(1024);		/* make temp buffer for termcap and */
					/* other initialization stuff */
    
    /* init terminal */
    
    term_init();			/* must precede sw_init() so that */
					/* ospeed is set for baud-rate */
					/* switches.  Actually terminal */
					/* mode setting is in term_set() */

    /* we have to know rnlib to look up global switches in %X/INIT */

    lib = savestr(filexp(LIB));
    rnlib = savestr(filexp(RNLIB));

    /* decode switches */

    sw_init(argc,argv,&tcbuf);          /* must not do % interps! */
					/* (but may mung environment) */

    /* init signals, status flags */

    final_init();
    
    /* start up file expansion and the % interpreter */

    intrp_init(tcbuf);
    
    /* now make sure we have a current working directory */

    if (!checkflag)
	cwd_check();
    
    /* now that we know where to save things, cd to news directory */

    if (chdir(spool)) {
	printf(nocd,spool) FLUSH;
	finalize(1);
    }

    /* if we aren't just checking, turn off echo */

    if (!checkflag)
	term_set(tcbuf);

    /* get info on last rn run, if any */

    if (!checkflag)
	last_init(tcbuf);

    free(tcbuf);			/* recover 1024 bytes */

    /* make sure we are the sole possessors of .newsrc */

    if (!checkflag)
	lock_check();

    /* check for news news */

    if (!checkflag)
	newsnews_check();

#ifdef SERVER

    /* open connection to server if appropriate */

    server = getserverbyfile(SERVER_FILE);
    if (server == NULL) {
	fprintf(stderr, "Can't get the name of the news server from %s\n",
		SERVER_FILE);
	fprintf(stderr,
	  "Either fix this file, or put NNTPSERVER in your environment.\n");
	finalize(1);
    }

    response = server_init(server);
    if (response < 0) {
	fprintf(stderr,
	    "Couldn't connect to %s news server, try again later.\n",
		server);
	finalize(1);
    }

    if (handle_server_response(response, server) < 0)
	finalize(1);

#endif

    /* open active file, etc. */

    ngdata_init();

    /* now read in the .newsrc file */

    foundany = rcstuff_init();

    /* it looks like we will actually read something, so init everything */

    addng_init();
    art_init();
    artio_init();
    artsrch_init();
    backpage_init();
    bits_init();
    cheat_init();
    head_init();
    help_init();
    kfile_init();
    ng_init();
    ngsrch_init();
    ngstuff_init();
    only_init();
    rcln_init();
    respond_init();
    rn_init();
    search_init();
    util_init();

#ifdef FINDNEWNG
	/*
	 * Skip this check if the -q flag was given.
	 */
    if (!quickstart) {
	if (find_new_groups()) {	/* did we add any new groups? */
	    foundany = TRUE;		/* let main() know */
	    starthere = 0;		/* start ng scan from the top */
	}
    }
#endif
    time(&lasttime);			/* remember when we inited-- */
					/* ends up back in .rnlast */
    writelast();			/* in fact, put it there now */

#ifdef FINDNEWNG
# ifdef ONLY
    if (maxngtodo)			/* patterns on command line? */
	foundany |= scanactive();
# endif
#endif

    return foundany;
}

/* make sure there is no rn out there already */

void
lock_check()
{
    lockname = savestr(filexp(LOCKNAME));
    if (!checkflag) {
	tmpfp = fopen(lockname,"r");
	if (tmpfp != Nullfp) {
	    int processnum;
    
	    fgets(buf,LBUFLEN,tmpfp);
	    fclose(tmpfp);
	    processnum = atoi(buf);
#ifdef VERBOSE
	    IF(verbose)
		printf("You seem to have left a rn running, process %d.\n",
		    processnum) FLUSH;
	    ELSE
#endif
#ifdef TERSE
		printf("Rn left running, #%d.\n", processnum) FLUSH;
#endif
	    if (kill(processnum, SIGEMT)) {
				    /* does process not exist? */
				    /* (rn ignores SIGEMT) */
		sleep(2);
#ifdef VERBOSE
		IF(verbose)
		    fputs("\n\
That process does not seem to exist anymore.  The count of read articles\n\
may be incorrect in the last newsgroup accessed by that other (defunct)\n\
process.\n\n",stdout) FLUSH;
		ELSE
#endif
#ifdef TERSE
		    fputs("\nProcess crashed.\n",stdout) FLUSH;
#endif
		if (*lastngname) {
#ifdef VERBOSE
		    IF(verbose)
			printf("(The last newsgroup accessed was %s.)\n\n",
			lastngname) FLUSH;
		    ELSE
#endif
#ifdef TERSE
			printf("(In %s.)\n\n",lastngname) FLUSH;
#endif
		}
		get_anything();
		putchar('\n') FLUSH;
	    }
	    else {
#ifdef VERBOSE
		IF(verbose)
		    fputs("\n\
You may not have two copies of rn running simultaneously.  Goodbye.\n\
",stdout) FLUSH;
		ELSE
#endif
#ifdef TERSE
		    fputs("\nCan't start another.\n",stdout) FLUSH;
#endif
               if (bizarre)
                 resetty();
		exit(0);
	    }
	}
	tmpfp = fopen(lockname,"w");
	if (tmpfp == Nullfp) {
	    printf(cantcreate,lockname) FLUSH;
	    sig_catcher(0);
	}
	fprintf(tmpfp,"%d\n",getpid());
	fclose(tmpfp);
    }
}

void
newsnews_check()
{
    char *newsnewsname = filexp(NEWSNEWSNAME);

    if ((tmpfp = fopen(newsnewsname,"r")) != Nullfp) {
	fstat(fileno(tmpfp),&filestat);
	if (filestat.st_mtime > lasttime) {
	    while (fgets(buf,sizeof(buf),tmpfp) != Nullch)
		fputs(buf,stdout) FLUSH;
	    get_anything();
	    putchar('\n') FLUSH;
	}
	fclose(tmpfp);
    }
}
!STUFFY!FUNK!
echo Extracting Rnmail.SH
cat >Rnmail.SH <<'!STUFFY!FUNK!'
case $CONFIG in
    '') . ./config.sh ;;
esac
echo "Extracting Rnmail (with variable substitutions)"
$spitshell >Rnmail <<!GROK!THIS!
$startsh
# $Id: Rnmail.SH,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
# 
# $Log: Rnmail.SH,v $
# Revision 4.4.3.1  1992/02/01  03:09:32  sob
# Release 4.4 Patchlevel 3
#
# Revision 4.4  1991/09/09  20:18:23  sob
# release 4.4
#
#
# 
# This software is Copyright 1991 by Stan Barber. 
#
# Permission is hereby granted to copy, reproduce, redistribute or otherwise
# use this software as long as: there is no monetary profit gained
# specifically from the use or reproduction of this software, it is not
# sold, rented, traded or otherwise marketed, and this copyright notice is
# included prominently in any copy made. 
#
# The author make no claims as to the fitness or correctness of this software
# for any use whatsoever, and it is provided as is. Any use of this software
# is at the user's own risk. 
#
#
# syntax: Rnmail -h headerfile [oldart]		or
#         Rnmail destination-list 		or just
#         Rnmail

export PATH || (echo "OOPS, this isn't sh.  Desperation time.  I will feed myself to sh."; sh \$0; kill \$\$)

# System dependencies

mailer="${mailer-/bin/mail}"
# if you change this to something that does signatures, take out signature code

# your site name
case $portable in
define)
	case "$hostcmd" in
	'') sitename="$sitename" ;;
	*)  sitename=\`$hostcmd\` ;;
	esac
	case \$sitename in
		*.*)
			;;
		*)
			sitename=\${sitename}.$domain
			;;
	esac
	;;
undef) sitename="$sitename" ;;
esac

# your organization name
orgname="$orgname"
# what pager you use--if you have kernal paging use cat
pager="\${PAGER-$pager}"
# how you derive full names, bsd, usg, or other
nametype="$nametype"
# default editor
defeditor="$defeditor"
# where the non-publics are
rnlib=$rnlib
# how not to do a newline with echo
n="$n"
c="$c"

test=${test-test}
sed=${sed-sed}
echo=${echo-echo}
cat=${cat-cat}
grep=${grep-grep}
rm=${rm-rm}

!GROK!THIS!
case "$ignoreorg" in
define) $spitshell >>Rnmail <<'!NO!SUBS!'
orgname=${NEWSORG-$orgname}
!NO!SUBS!
	;;
*)	$spitshell >>Rnmail <<'!NO!SUBS!'
orgname=${NEWSORG-${ORGANIZATION-$orgname}}
!NO!SUBS!
	;;
esac
$spitshell >>Rnmail <<'!NO!SUBS!'
dotdir=${DOTDIR-${HOME-$LOGDIR}}
tmpart=$dotdir/.letter

headerfile=""
case $# in
0) ;;
*)  case $1 in
    -h)
	headerfile="$2"
	case $# in
	3) oldart=$3 ;;
	esac
	;;
    esac
    ;;
esac

case $headerfile in
'')
    case $# in
    0)
	to=h
	while $test "$to" = h ; do
	    $echo ""
	    $echo $n "To: $c"
	    read to
	    case $to in
	    h)
		$cat <<'EOH'

Type the net address of those people that you wish the message sent to.
Additional recipients may be added on the Cc: line when you edit.

Separate multiple addresses with spaces.

EOH
		;;
	    esac
	done
	;;
    *)
	to="$*"
	;;
    esac
    to=`$echo "$to" | $sed 's/  */ /g'`

    title=h
    while $test "$title" = h ; do
	$echo ""
	$echo $n "Title/Subject: $c"
	read title
	case $title in
	h)
	    $cat <<'EOH'

Type the title for your message.  
EOH
	    ;;
	esac
    done

# now build a file with a header for them to edit
    
    case $orgname in
    /*) orgname=`$cat $orgname` ;;
    esac

    $sed -e '/^Reply-To: $/d' > $tmpart <<EOHeader
To: $to
Subject: $title
Organization: $orgname
Reply-To: $REPLYTO
Cc:
Bcc:

EOHeader

    ;;
*)
    $cat < $headerfile  > $tmpart
    ;;
esac


file=h
while $test "$file" = h ; do
    $echo ""
    $echo $n "Prepared file to include [none]: $c"
    read file
    case $file in
    h)
	$cat <<'EOH'

If you have already produced the body of your message, type the filename
for it here.  If you just want to proceed directly to the editor, type a
RETURN.  In any event, you will be allowed to edit as many times as you
want before you send off the message.
EOH
	;;
    '')
	$echo "" >> $tmpart
	state=edit
	;;
    *)
	$cat $file >>$tmpart
	state=ask
	;;
    esac
done

$echo ""

while true ; do
    case $state in
    edit)
	rescue="sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.letter ; $echo Message appended to ${HOME-$LOGDIR}/dead.letter ; exit"
	trap "$rescue" 1
	trap : 2
	case "${VISUAL-${EDITOR-}}" in
	'')
	    tmp=h
	    ;;
	*)
	    tmp=''
	    ;;
	esac
	while $test "$tmp" = h ; do
	    $echo $n "Editor [${VISUAL-${EDITOR-$defeditor}}]: $c"
	    read tmp
	    case $tmp in
	    h)
		$cat <<'EOH'

Type a return to get the default editor, or type the name of the editor you
prefer.  The default editor depends on the VISUAL and EDITOR environment
variables.

EOH
		;;
	    '')
		;;
	    *)
		VISUAL=$tmp
		export VISUAL
		;;
	    esac
	done
	${VISUAL-${EDITOR-$defeditor}} $tmpart $oldart
	trap "$rescue" 2
	state=ask
	;;
	
    ask)
	$echo ""
	$echo $n "Send, abort, edit, or list? $c"
	read ans
	
	case $ans in
	a*)
	    state=rescue
	    ;;
	e*)
	    set $ans
	    case $# in
	    2)  VISUAL="$2" ;;
	    esac
	    state=edit
	    ;;
	l*)
	    $pager $tmpart
	    state=ask
	    ;;
	s*)
	    state=send
	    ;;
	h*)
	    $cat <<'EOH'

Type s to send the message, a to abort and append the message to dead.letter,
e to edit the message again, or l to list the message.

To invoke an alternate editor, type 'e editor'.
EOH
	esac
	;;
    
    send)
	if $test -f $dotdir/.signature; then
	    $echo $n "Append .signature file? [y] $c"
	    read ans
	    case $ans in
	    ''|y*)
		$echo "-- " >> $tmpart
		cat $dotdir/.signature >> $tmpart
		;;
	    esac
	fi
	case $mailer in
	*sendmail)
	    $mailer -t <$tmpart
	    ;;
# but recmail does not know about Bcc, alas
	*recmail)
	    $mailer <$tmpart
	    ;;
	*)
	    set X `$sed <$tmpart -n -e '/^To:/{' -e 's/To: *//p' -e q -e '}'`
	    shift
	    set X "$@" `$sed <$tmpart -n -e '/^Cc:/{' -e 's/Cc: *//p' -e q -e '}'`
	    shift
	    set X "$@" `$sed <$tmpart -n -e '/^Bcc:/{' -e 's/Bcc: *//p' -e q -e '}'`
	    shift
	    $grep -v "^Bcc:"  <$tmpart | $mailer "$@"
	    ;;
	esac
	case $? in
	0)
	    state=cleanup
	    ;;
	*)
	    state=rescue
	    ;;
	esac
	;;
    rescue)
	$cat $tmpart >> ${HOME-$LOGDIR}/dead.letter
	$echo "Message appended to ${HOME-$LOGDIR}/dead.letter"
	$echo "A copy may be temporarily found in $tmpart"
	exit
	;;
    cleanup)
	case "${MAILRECORD-none}" in
	none)
	    ;;
	*)
	    set X ${USER-${LOGNAME-`who am i`}} unknown
	    shift
	    $rnlib/mbox.saver $tmpart "." "." 0 0 Pnews $MAILRECORD "From $1 `date`"
	    if $test $? -eq 0 ; then
		$echo "Message appended to $MAILRECORD"
	    else
		$echo "Cannot append to $MAILRECORD"
	    fi
	    ;;
	esac
	exit
	;;
    esac
done
!NO!SUBS!
$eunicefix Rnmail
chmod 755 Rnmail
!STUFFY!FUNK!
echo Extracting kfile.c
cat >kfile.c <<'!STUFFY!FUNK!'
/* $Id: kfile.c,v 4.4 1991/09/09 20:18:23 sob Exp sob $
 *
 * $Log: kfile.c,v $
 * Revision 4.4  1991/09/09  20:18:23  sob
 * release 4.4
 *
 *
 * 
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */

#include "EXTERN.h"
#include "common.h"
#include "term.h"
#include "util.h"
#include "artsrch.h"
#include "ng.h"
#include "bits.h"
#include "intrp.h"
#include "ngstuff.h"
#include "rcstuff.h"
#include "rn.h"
#include "INTERN.h"
#include "kfile.h"

static bool exitcmds = FALSE;

void
kfile_init()
{
    ;
}

#ifndef KILLFILES
int
edit_kfile()
{
    notincl("^K");
    return -1;
}

#else /* KILLFILES */

char killglobal[] = KILLGLOBAL;
char killlocal[] = KILLLOCAL;

void
mention(str)
char *str;
{
#ifdef VERBOSE
    IF(verbose) {
#ifdef NOFIREWORKS
	no_sofire();
#endif
	standout();
	fputs(str,stdout);
	un_standout();
	putchar('\n');
    }
    ELSE
#endif
#ifdef TERSE
	putchar('.');
#endif
    fflush(stdout);
}

bool kill_mentioned;

int
do_kfile(kfp,entering)
FILE *kfp;
int entering;
{

    art = lastart+1;
    fseek(kfp,0L,0);			/* rewind file */
    while (fgets(buf,LBUFLEN,kfp) != Nullch) {
	buf[strlen(buf)-1] = '\0';
	if (strnEQ(buf,"THRU",4)) {
	    ART_NUM tmpart;

	    tmpart = atol(buf+4)+1;
	    if (tmpart < absfirst)
		tmpart = absfirst;
	    check_first(tmpart);
	    firstart = tmpart;
	    continue;
	}
	if (*buf == 'X') {		/* exit command? */
	    if (entering) {
		exitcmds = TRUE;
		continue;
	    }
	    strcpy(buf,buf+1);
	}
	else {
	    if (!entering)
		continue;
	}
	if (*buf == '&') {
	    mention(buf);
	    switcheroo();
	}
	else if (*buf == '/' && firstart <= lastart) {
	    mention(buf);
	    kill_mentioned = TRUE;
	    switch (art_search(buf, (sizeof buf), FALSE)) {
	    case SRCH_ABORT:
		continue;
	    case SRCH_INTR:
#ifdef VERBOSE
		IF(verbose)
		    printf("\n(Interrupted at article %ld)\n",(long)art)
		      FLUSH;
		ELSE
#endif
#ifdef TERSE
		    printf("\n(Intr at %ld)\n",(long)art) FLUSH;
#endif
		return -1;
	    case SRCH_DONE:
		break;
	    case SRCH_SUBJDONE:
		fputs("\tsubject not found (???)\n",stdout) FLUSH;
		break;
	    case SRCH_NOTFOUND:
		fputs("\tnot found\n",stdout) FLUSH;
		break;
	    case SRCH_FOUND:
		fputs("\tfound\n",stdout) FLUSH;
	    }
	}
    }

    return 0;
}

void
kill_unwanted(starting,message,entering)
ART_NUM starting;
char *message;
int entering;
{
    bool intr = FALSE;			/* did we get an interrupt? */
    ART_NUM oldfirst;
    bool anytokill = (toread[ng] > 0);

    if (localkfp || globkfp) {
	if (!entering && !exitcmds)
	    return;
	exitcmds = FALSE;
	oldfirst = firstart;
	firstart = starting;
	clear();
#ifdef VERBOSE
# ifdef TERSE
	if (message && (verbose || entering))
# else
	if (message)
# endif
#else
	if (message && entering)
#endif
	    fputs(message,stdout) FLUSH;

	kill_mentioned = FALSE;
	if (localkfp)
	    intr = do_kfile(localkfp,entering);
	if (globkfp && !intr)
	    intr = do_kfile(globkfp,entering);
	if (entering && localkfp && !intr)
	    setthru(lastart);
	putchar('\n') FLUSH;
	if (entering && kill_mentioned)
#ifdef VERBOSE
	    IF(verbose)
		get_anything();
	    ELSE
#endif
#ifdef TERSE
		pad(just_a_sec);
#endif
	if (anytokill)			/* if there was anything to kill */
	    forcelast = FALSE;		/* allow for having killed it all */
	firstart = oldfirst;
    }
}

void
setthru(thru)
ART_NUM thru;
{
    FILE *newkfp;
    bool no_kills = 0;

    fseek(localkfp,0L,0);		/* rewind current file */
    if (fgets(buf,LBUFLEN,localkfp) != Nullch
     && (strnNE(buf,"THRU",4) || fgets(buf,LBUFLEN,localkfp) != Nullch))
	fseek(localkfp,0L,0);
    else
	no_kills = 1;
    strcpy(buf,filexp(getval("KILLLOCAL",killlocal)));
    UNLINK(buf);			/* to prevent file reuse */
    if (no_kills)
	open_kfile(KF_LOCAL);		/* close file and reset open flag */
    else if (newkfp = fopen(buf,"w")) {
	fprintf(newkfp,"THRU %ld\n",(long)thru);
	while (fgets(buf,LBUFLEN,localkfp) != Nullch) {
	    if (strnEQ(buf,"THRU",4))
		continue;
	    fputs(buf,newkfp);
	}
	fclose(newkfp);
	open_kfile(KF_LOCAL);		/* and reopen local file */
    }
    else
	printf(cantcreate,buf) FLUSH;
}

/* edit KILL file for newsgroup */

int
edit_kfile()
{
    int r = -1;

    if (in_ng)
	strcpy(buf,filexp(getval("KILLLOCAL",killlocal)));
    else
	strcpy(buf,filexp(getval("KILLGLOBAL",killglobal)));
    if ((r = makedir(buf,MD_FILE)) >= 0) {
	sprintf(cmd_buf,"%s %s",
	    filexp(getval("VISUAL",getval("EDITOR",defeditor))),buf);
	printf("\nEditing %s KILL file:\n%s\n",
	    (in_ng?"local":"global"),cmd_buf) FLUSH;
	resetty();			/* make sure tty is friendly */
	r = doshell(sh,cmd_buf);/* invoke the shell */
	noecho();			/* and make terminal */
	crmode();			/*   unfriendly again */
	open_kfile(in_ng);
    }
    else
	printf("Can't make %s\n",buf) FLUSH;
    return r;
}

void
open_kfile(local)
int local;
{
    char *kname = filexp(local ?
	getval("KILLLOCAL",killlocal) :
	getval("KILLGLOBAL",killglobal)
	);
    
    stat(kname,&filestat);
    if (!filestat.st_size)		/* nothing in the file? */
	UNLINK(kname);			/* delete the file */
    if (local) {
	if (localkfp)
	    fclose(localkfp);
	localkfp = fopen(kname,"r");
    }
    else {
	if (globkfp)
	    fclose(globkfp);
	globkfp = fopen(kname,"r");
    }
}

void
kf_append(cmd)
char *cmd;
{
    strcpy(cmd_buf,filexp(getval("KILLLOCAL",killlocal)));
    if (makedir(cmd_buf,MD_FILE) >= 0) {
#ifdef VERBOSE
	IF(verbose)
	    printf("\nDepositing command in %s...",cmd_buf);
	ELSE
#endif
#ifdef TERSE
	    printf("\n--> %s...",cmd_buf);
#endif
	fflush(stdout);
	sleep(2);
	if ((tmpfp = fopen(cmd_buf,"a")) != Nullfp) {
	    fseek(tmpfp,0L,2);		/* get to EOF for sure */
	    fprintf(tmpfp,"%s\n",cmd);
	    fclose(tmpfp);
	    fputs("done\n",stdout) FLUSH;
	}
	else
	    printf(cantopen,cmd_buf) FLUSH;
    }
}
#endif /* KILLFILES */
!STUFFY!FUNK!
echo Extracting range.c
cat >range.c <<'!STUFFY!FUNK!'
#ifndef lint
static char * rcsid ="$Id: range.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $";
#endif
/*
***************************************************************************
This work in its current form is Copyright 1989 Stan Barber
This software may be distributed freely as long as no profit is made from
such distribution and this notice is reproducted in whole.
***************************************************************************
This software is provided on an "as is" basis with no guarantee of 
usefulness or correctness of operation for any purpose, intended or
otherwise. The author is in no way liable for this software's performance
or any damage it may cause to any data of any kind anywhere.
***************************************************************************
*/
/*
 * $Log: range.c,v $
 * Revision 4.4  1991/09/09  20:27:37  sob
 * release 4.4
 *
 *
 *
 */

#include <stdio.h>
#ifdef USG
#include <strings.h>
#define rindex strrchr
#else
extern char *rindex(); 
#endif
char * progname;

main(argc,argv)
char *argv[];
int argc;
{
    int x,y,i;


    if ((progname = rindex(argv[0],'/'))== NULL)
	    progname = argv[0];
    else progname++;
    

    if (argc != 3) usage();
    x = atoi(argv[1]);
    y = atoi(argv[2]);
    if (y < x) usage();
    y++;

    for (i=x;i < y;i++)
	printf("%d ",i);
    printf("\n");

    exit(0);
}

usage(){
    fprintf(stderr,"Usage: %s startnumber endnumber\n",progname);
    exit(-1);
}
!STUFFY!FUNK!
echo ""
echo "End of kit 8 (of 11)"
cat /dev/null >kit8isdone
config=true
for iskit in 1 2 3 4 5 6 7 8 9 10 11 ; 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
