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

echo "This is rn kit 7 (of 10).  If kit 7 is complete, the line"
echo '"'"End of kit 7 (of 10)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting sw.c
cat >sw.c <<'!STUFFY!FUNK!'
/* $Id: sw.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $
 *
 * $Log: sw.c,v $
 * Revision 4.4  1991/09/09  20:27:37  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 "head.h"
#include "only.h"
#include "term.h"
#include "ng.h"
#include "intrp.h"
#include "INTERN.h"
#include "sw.h"

void
sw_init(argc,argv,tcbufptr)
int argc;
char *argv[];
char **tcbufptr;
{
    register int i;

    if (argc >= 2 && strEQ(argv[1],"-c"))
	checkflag=TRUE;			/* so we can optimize for -c */
    interp(*tcbufptr,1024,GLOBINIT);
    sw_file(tcbufptr,FALSE);
    safecpy(*tcbufptr,getenv("RNINIT"),1024);
    if (**tcbufptr) {
	if (**tcbufptr == '/') {
	    sw_file(tcbufptr,TRUE);
	}
	else
	    sw_list(*tcbufptr);
    }

    for (i = 1; i < argc; i++)
	decode_switch(argv[i]);
}

void
sw_file(tcbufptr,bleat)
char **tcbufptr;
bool bleat;
{
    int initfd = open(*tcbufptr,0);
	
    if (initfd >= 0) {
	fstat(initfd,&filestat);
	if (filestat.st_size > 1024)
	    *tcbufptr = saferealloc(*tcbufptr,(MEM_SIZE)filestat.st_size);
	if (filestat.st_size) {
	    read(initfd,*tcbufptr,(int)filestat.st_size);
	    (*tcbufptr)[filestat.st_size-1] = '\0';
				/* wipe out last newline */
	    sw_list(*tcbufptr);
	}
	else
	    **tcbufptr = '\0';
	close(initfd);
    }
    else {
	if (bleat)
	    printf(cantopen,*tcbufptr) FLUSH;
	**tcbufptr = '\0';
    }
}

/* decode a list of space separated switches */

void
sw_list(swlist)
char *swlist;
{
    char *tmplist = safemalloc((MEM_SIZE) strlen(swlist) + 2);
					/* semi-automatic string */
    register char *p, inquote = 0;

    strcpy(tmplist,swlist);
    for (p=tmplist; isspace(*p); p++) ;	/* skip any initial spaces */
    while (*p) {			/* "String, or nothing" */
	if (!inquote && isspace(*p)) {	/* word delimiter? */
	    *p++ = '\0';		/* chop here */
	    while (isspace(*p))		/* these will be ignored later */
		p++;
	}
	else if (inquote == *p) {
	    strcpy(p,p+1);		/* delete trailing quote */
	    inquote = 0;		/* no longer quoting */
	}
	else if (!inquote && *p == '"' || *p == '\'') {
					/* OK, I know when I am not wanted */
	    inquote = *p;		/* remember single or double */
	    strcpy(p,p+1);		/* delete the quote */
	}				/* (crude, but effective) */
	else if (*p == '\\') {		/* quoted something? */
	    if (p[1] == '\n')		/* newline? */
		strcpy(p,p+2);		/* "I didn't see anything" */
	    else {
		strcpy(p,p+1);		/* delete the backwhack */
		p++;			/* leave the whatever alone */
	    }
	}
	else
	    p++;			/* normal char, leave it alone */
    }
    *++p = '\0';			/* put an extra null on the end */
    if (inquote)
	printf("Unmatched %c in switch\n",inquote) FLUSH;
    for (p = tmplist; *p; /* p += strlen(p)+1 */ ) {
	decode_switch(p);
	while (*p++) ;			/* point at null + 1 */
    }
    free(tmplist);			/* this oughta be in Ada */
}

/* decode a single switch */

void
decode_switch(s)
register char *s;
{
    while (isspace(*s))			/* ignore leading spaces */
	s++;
#ifdef DEBUGGING
    if (debug)
	printf("Switch: %s\n",s) FLUSH;
#endif
    if (*s != '-' && *s != '+') {	/* newsgroup pattern */
	setngtodo(s);
    }
    else {				/* normal switch */
	bool upordown = *s == '-' ? TRUE : FALSE;
	char tmpbuf[LBUFLEN];

	s++;
	switch (*s) {
#ifdef TERMMOD
	case '=': {
	    char *beg = s+1;

	    while (*s && *s != '-' && *s != '+') s++;
	    cpytill(tmpbuf,beg,*s);
	    if (upordown ? strEQ(getenv("TERM"),tmpbuf)
	    		 : strNE(getenv("TERM"),tmpbuf) ) {
		decode_switch(s);
	    }
	    break;
	}
#endif
#ifdef BAUDMOD
	case '0': case '1': case '2': case '3': case '4':
	case '5': case '6': case '7': case '8': case '9':
	    if (upordown ? (just_a_sec*10 <= atoi(s))
	    		 : (just_a_sec*10 >= atoi(s)) ) {
		while (isdigit(*s)) s++;
		decode_switch(s);
	    }
	    break;
#endif
	case '/':
	    if (checkflag)
		break;
#ifdef SETENV
	    setenv("SAVEDIR",  upordown ? "%p/%c" : "%p" );
	    setenv("SAVENAME", upordown ? "%a"    : "%^C");
#else
	    notincl("-/");
#endif
	    break;
	case 'c':
	    checkflag = upordown;
	    break;
	case 'C':
	    s++;
	    if (*s == '=') s++;
	    docheckwhen = atoi(s);
	    break;
	case 'd': {
	    if (checkflag)
		break;
	    s++;
	    if (*s == '=') s++;
	    if (cwd) {
		chdir(cwd);
		free(cwd);
	    }
	    cwd = savestr(s);
	    break;
	}
#ifdef DEBUGGING
	case 'D':
	    s++;
	    if (*s == '=') s++;
	    if (*s)
		if (upordown)
		    debug |= atoi(s);
		else
		    debug &= ~atoi(s);
	    else
		if (upordown)
		    debug |= 1;
		else
		    debug = 0;
	    break;
#endif
	case 'e':
	    erase_screen = upordown;
	    break;
	case 'E':
#ifdef SETENV
	    s++;
	    if (*s == '=')
		s++;
	    strcpy(tmpbuf,s);
	    s = index(tmpbuf,'=');
	    if (s) {
		*s++ = '\0';
		setenv(tmpbuf,s);
	    }
	    else
		setenv(tmpbuf,nullstr);
#else
	    notincl("-E");
#endif
	    break;
	case 'F':
	    s++;
	    indstr = savestr(s);
	    break;
#ifdef INNERSEARCH
	case 'g':
	    gline = atoi(s+1)-1;
	    break;
#endif
	case 'H':
	case 'h': {
	    register int len, i;
	    char *t;
	    int flag = (*s == 'h' ? HT_HIDE : HT_MAGIC);
	    
	    if (checkflag)
		break;
	    s++;
	    len = strlen(s);
	    for (t=s; *t; t++)
		if (isupper(*t))
		   *t = tolower(*t);
	    for (i=HEAD_FIRST; i<HEAD_LAST; i++)
		if (!len || strnEQ(s,htype[i].ht_name,len))
		    if (upordown)
			htype[i].ht_flags |= flag;
		    else
			htype[i].ht_flags &= ~flag;
	    break;
	}
	case 'i':
	    s++;
	    if (*s == '=') s++;
	    initlines = atoi(s);
	    initlines_specified = TRUE;
	    break;
	case 'l':
	    muck_up_clear = upordown;
	    break;
	case 'L':
#ifdef CLEAREOL
	    can_home_clear = upordown;
#else
	    notincl("-L");
#endif
	    break;
	case 'M':
	    mbox_always = upordown;
	    break;
	case 'm':
	    s++;
	    if (*s == '=') s++;
	    if (!upordown)
		marking = NOMARKING;
	    else if (*s == 'u')
		marking = UNDERLINE;
	    else {
		marking = STANDOUT;
	    }
	    break;
	case 'N':
	    norm_always = upordown;
	    break;
#ifdef VERBOSE
	case 'n':
	    fputs("This isn't readnews.  Don't use -n.\n\n",stdout) FLUSH;
	    break;
#endif
	case 'r':
	    findlast = upordown;
	    break;
	case 's':
	    s++;
	    if (*s == '=') s++;
	    if (*s) {
		countdown = atoi(s);
		suppress_cn = FALSE;
	    }
	    else {
		if (!upordown)
		    countdown = 5;
		suppress_cn = upordown;
	    }
	    break;
	case 'S':
#ifdef ARTSEARCH
	    s++;
	    if (*s == '=') s++;
	    if (*s)
		scanon = atoi(s);
	    else
		scanon = upordown*3;
#else
	    notincl("-S");
#endif
	    break;
	case 't':
#ifdef VERBOSE
#ifdef TERSE
	    verbose = !upordown;
#else
	    notincl("+t");
#endif
#else
	    notincl("+t");
#endif
	    break;
	case 'T':
	    typeahead = upordown;
	    break;
	case 'v':
#ifdef VERIFY
	    verify = upordown;
#else
	    notincl("-v");
#endif
	    break;
	/*
	 * People want a way to avoid checking for new newsgroups on startup.
	 */
	case 'q':
		quickstart = upordown;
		break;
	default:
#ifdef VERBOSE
	    IF(verbose)
		printf("\nIgnoring unrecognized switch: -%c\n", *s) FLUSH;
	    ELSE
#endif
#ifdef TERSE
		printf("\nIgnoring -%c\n", *s) FLUSH;
#endif
	    break;
	}
    }
}

/* print current switch values */

void
pr_switches()
{
    static char mp[2] = {'+','-'};
    register int i;
    
    fputs("\nCurrent switch settings:\n",stdout);
    printf("%c/ ", mp[strEQ(getval("SAVEDIR",SAVEDIR),"%p/%c")]);
    printf("%cc ", mp[checkflag]);
    printf("-C%d ", docheckwhen);
    printf("-d%s ", cwd);
#ifdef DEBUGGING
    if (debug)
	printf("-D%d ", debug);
#endif
    printf("%ce ", mp[erase_screen]);
    printf("-F\"%s\" ", indstr);
#ifdef INNERSEARCH
    printf("-g%d", gline);
#endif
    putchar('\n');
#ifdef VERBOSE
    if (verbose) {
	for (i=HEAD_FIRST; i<HEAD_LAST; i++)
	    printf("%ch%s%c",
		mp[htype[i].ht_flags & HT_HIDE], htype[i].ht_name,
		(! (i % 5) ? '\n' : ' ') );
    }
#endif
    printf("-i%d ", initlines);
    printf("%cl ", mp[muck_up_clear]);
#ifdef CLEAREOL
    printf("%cL ", mp[can_home_clear]);
#endif /* CLEAREOL */
    if (marking)
	printf("-m%c ",marking==UNDERLINE?'u':'s');
    else
	printf("+m ");
    printf("%cM ", mp[mbox_always]);
    printf("%cN ", mp[norm_always]);
    printf("%cr ", mp[findlast]);
    if (countdown)
	printf("-s%d ", countdown);
    else
	printf("%cs ", mp[suppress_cn]);
#ifdef ARTSEARCH
    if (scanon)
	printf("-S%d ",scanon);
    else
	printf("+S ");
#endif
#ifdef VERBOSE
#ifdef TERSE
    printf("%ct ", mp[!verbose]);
#endif
#endif
    printf("%cT ", mp[typeahead]);
#ifdef VERIFY
    printf("%cv ", mp[verify]);
#endif
    fputs("\n\n",stdout) FLUSH;
#ifdef ONLY
    if (maxngtodo) {
#ifdef VERBOSE
	IF(verbose)
	    fputs("Current restriction:",stdout);
	ELSE
#endif
#ifdef TERSE
	    fputs("Only:",stdout);
#endif
	for (i=0; i<maxngtodo; i++)
	    printf(" %s",ngtodo[i]);
	fputs("\n\n",stdout) FLUSH;
    }
#ifdef VERBOSE
    else if (verbose)
	fputs("No restriction.\n\n",stdout) FLUSH;
#endif
#endif
}

void
cwd_check()
{
    char tmpbuf[LBUFLEN];

    if (!cwd)
	cwd = savestr(filexp("~/News"));
    strcpy(tmpbuf,cwd);
    if (chdir(cwd)) {
	safecpy(tmpbuf,filexp(cwd),sizeof tmpbuf);
	if (makedir(tmpbuf,MD_DIR) < 0 || chdir(tmpbuf) < 0) {
	    interp(cmd_buf, (sizeof cmd_buf), "%~/News");
	    if (makedir(cmd_buf,MD_DIR) < 0)
		strcpy(tmpbuf,homedir);
	    else
		strcpy(tmpbuf,cmd_buf);
	    chdir(tmpbuf);
#ifdef VERBOSE
	    IF(verbose)
		printf("\
Cannot make directory %s--\n\
	articles will be saved to %s\n\
\n\
",cwd,tmpbuf) FLUSH;
	    ELSE
#endif
#ifdef TERSE
		printf("\
Can't make %s--\n\
	using %s\n\
\n\
",cwd,tmpbuf) FLUSH;
#endif
	}
    }
    free(cwd);
    getwd(tmpbuf);
    if (eaccess(tmpbuf,2)) {
#ifdef VERBOSE
	IF(verbose)
	    printf("\
Current directory %s is not writeable--\n\
	articles will be saved to home directory\n\n\
",tmpbuf) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    printf("%s not writeable--using ~\n\n",tmpbuf) FLUSH;
#endif
	strcpy(tmpbuf,homedir);
    }
    cwd = savestr(tmpbuf);
}
!STUFFY!FUNK!
echo Extracting util.c
cat >util.c <<'!STUFFY!FUNK!'
/* $Id: util.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $
 *
 * $Log: util.c,v $
 * Revision 4.4  1991/09/09  20:27:37  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 "final.h"
#include "INTERN.h"
#include "util.h"

void
util_init()
{
    ;
}
    
/* fork and exec a shell command */

int
doshell(shl,s)
char *s, *shl;
{
    int status, pid, w;
    char *shell;

#ifdef SIGTSTP
    sigset(SIGTSTP,SIG_DFL);
    sigset(SIGTTOU,SIG_DFL);
    sigset(SIGTTIN,SIG_DFL);
#endif
    if (shl != Nullch)
	shell = shl;
    else if ((shell = getenv("SHELL")) == Nullch || !*shell)
	shell = PREFSHELL;
    if ((pid = vfork()) == 0) {
#ifdef SERVER
        int i;

	/* This is necessary to keep bourne shell from puking */

        for (i = 3; i < 10; ++i)
                close(i);
#endif /* SERVER */

	if (*s)
	    execl(shell, shell, "-c", s, Nullch);
	else
	    execl(shell, shell, Nullch, Nullch, Nullch);
	_exit(127);
    }
    signal(SIGINT, SIG_IGN);
#ifdef SIGQUIT
    signal(SIGQUIT, SIG_IGN);
#endif 
    waiting = TRUE;
    while ((w = wait(&status)) != pid)
	if (w == -1 && errno != EINTR)
	    break;
    if (w == -1)
	status = -1;
    waiting = FALSE;
    sigset(SIGINT, int_catcher);	/* always catch interrupts */
#ifdef SIGQUIT
    signal(SIGQUIT, SIG_DFL);
#endif 
#ifdef SIGTSTP
    sigset(SIGTSTP,stop_catcher);
    sigset(SIGTTOU,stop_catcher);
    sigset(SIGTTIN,stop_catcher);
#endif
    return status;
}

static char nomem[] = "rn: out of memory!\n";

/* paranoid version of malloc */

char *
safemalloc(size)
MEM_SIZE size;
{
    char *ptr;
    char *malloc();

    ptr = malloc(size ? size : (MEM_SIZE)1);
    if (ptr != Nullch)
	return ptr;
    else {
	fputs(nomem,stdout) FLUSH;
	sig_catcher(0);
    }
    /*NOTREACHED*/
}

/* paranoid version of realloc */

char *
saferealloc(where,size)
char *where;
MEM_SIZE size;
{
    char *ptr;
    char *realloc();

    ptr = realloc(where,size?size:1);	/* realloc(0) is NASTY on our system */
    if (ptr != Nullch)
	return ptr;
    else {
	fputs(nomem,stdout) FLUSH;
	sig_catcher(0);
    }
    /*NOTREACHED*/
}

/* safe version of string copy */

char *
safecpy(to,from,len)
char *to;
register char *from;
register int len;
{
    register char *dest = to;

    if (from != Nullch) 
	for (len--; len && (*dest++ = *from++); len--) ;
    *dest = '\0';
    return to;
}

/* safe version of string concatenate, with \n deletion and space padding */

char *
safecat(to,from,len)
char *to;
register char *from;
register int len;
{
    register char *dest = to;

    len--;				/* leave room for null */
    if (*dest) {
	while (len && *dest++) len--;
	if (len) {
	    len--;
	    *(dest-1) = ' ';
	}
    }
    if (from != Nullch)
	while (len && (*dest++ = *from++)) len--;
    if (len)
	dest--;
    if (*(dest-1) == '\n')
	dest--;
    *dest = '\0';
    return to;
}

/* copy a string up to some (non-backslashed) delimiter, if any */

char *
cpytill(to,from,delim)
register char *to, *from;
register int delim;
{
    for (; *from; from++,to++) {
	if (*from == '\\' && from[1] == delim)
	    from++;
	else if (*from == delim)
	    break;
	*to = *from;
    }
    *to = '\0';
    return from;
}

/* return ptr to little string in big string, NULL if not found */

char *
instr(big, little, case_matters)
char *big, *little;
int case_matters;
{
    register char *t, *s, *x;

    for (t = big; *t; t++) {
	for (x=t,s=little; *s; x++,s++) {
	    if (!*x)
		return Nullch;
	    if (case_matters == TRUE) {
		if(*s != *x)
			break;
	    } else {
		register char c,d;
		if (isupper(*s)) 
			c = tolower(*s);
		else
			c = *s;
		if (isupper(*x)) 
			d = tolower(*x);
		else
			d = *x;
		if ( c != d )
			break;
	   }
	}
	if (!*s)
	    return t;
    }
    return Nullch;
}

/* effective access */

#ifdef SETUIDGID
int
eaccess(filename, mod)
char *filename;
int mod;
{
    int protection, euid;
    
    mod &= 7;				/* remove extraneous garbage */
    if (stat(filename, &filestat) < 0)
	return -1;
    euid = geteuid();
    if (euid == ROOTID)
	return 0;
    protection = 7 & (filestat.st_mode >>
      (filestat.st_uid == euid ? 6 :
        (filestat.st_gid == getegid() ? 3 : 0)
      ));
    if ((mod & protection) == mod)
	return 0;
    errno = EACCES;
    return -1;
}
#endif

/*
 * Get working directory
 */
#ifndef GETWD
#ifdef GETCWD
char *
getwd(np)
char *np;
{
    char * name;
	extern char * getcwd();
    name = getcwd(np,512);
    return(name);
}
#else
char *
getwd(np)			/* shorter but slower */
char *np;
{
    FILE *popen();
    FILE *pipefp = popen("/bin/pwd","r");

    if (pipefp == Nullfp) {
	printf("Can't run /bin/pwd\n") FLUSH;
	finalize(1);
    }
    fgets(np,512,pipefp);
    np[strlen(np)-1] = '\0';	/* wipe out newline */
    pclose(pipefp);
    return np;
}
#endif
#endif
/* just like fgets but will make bigger buffer as necessary */

char *
get_a_line(original_buffer,buffer_length,fp)
char *original_buffer;
register int buffer_length;
FILE *fp;
{
    register int bufix = 0;
    register int nextch;
    register char *some_buffer_or_other = original_buffer;

    do {
	if (bufix >= buffer_length) {
	    buffer_length *= 2;
	    if (some_buffer_or_other == original_buffer) {
					/* currently static? */
		some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1);
		strncpy(some_buffer_or_other,original_buffer,buffer_length/2);
					/* so we must copy it */
	    }
	    else {			/* just grow in place, if possible */
		some_buffer_or_other = saferealloc(some_buffer_or_other,
		    (MEM_SIZE)buffer_length+1);
	    }
	}
	if ((nextch = getc(fp)) == EOF)
	    return Nullch;
	some_buffer_or_other[bufix++] = (char) nextch;
    } while (nextch && nextch != '\n');
    some_buffer_or_other[bufix] = '\0';
    len_last_line_got = bufix;
    return some_buffer_or_other;
}

/* copy a string to a safe spot */

char *
savestr(str)
char *str;
{
    register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));

    strcpy(newaddr,str);
    return newaddr;
}

int
makedir(dirname,nametype)
register char *dirname;
int nametype;
{
#ifdef MAKEDIR
    register char *end;
    register char *s;
    char tmpbuf[1024];
    register char *tbptr = tmpbuf+5;

    for (end = dirname; *end; end++) ;	/* find the end */
    if (nametype == MD_FILE) {		/* not to create last component? */
	for (--end; end != dirname && *end != '/'; --end) ;
	if (*end != '/')
	    return 0;			/* nothing to make */
	*end = '\0';			/* isolate file name */
    }
    strcpy(tmpbuf,"mkdir");

    s = end;
    for (;;) {
	if (stat(dirname,&filestat) >= 0 && (filestat.st_mode & S_IFDIR)) {
					/* does this much exist as a dir? */
	    *s = '/';			/* mark this as existing */
	    break;
	}
	s = rindex(dirname,'/');	/* shorten name */
	if (!s)				/* relative path! */
	    break;			/* hope they know what they are doing */
	*s = '\0';			/* mark as not existing */
    }
    
    for (s=dirname; s <= end; s++) {	/* this is grody but efficient */
	if (!*s) {			/* something to make? */
	    sprintf(tbptr," %s",dirname);
	    tbptr += strlen(tbptr);	/* make it, sort of */
	    *s = '/';			/* mark it made */
	}
    }
    if (nametype == MD_DIR)		/* don't need final slash unless */
	*end = '\0';			/*  a filename follows the dir name */

    return (tbptr==tmpbuf+5 ? 0 : doshell(sh,tmpbuf));
					/* exercise our faith */
#else
    sprintf(cmd_buf,"%s %s %d", filexp(DIRMAKER), dirname, nametype);
    return doshell(sh,cmd_buf);
#endif
}

#ifdef SETENV
static bool firstsetenv = TRUE;
extern char **environ;

void
setenv(nam,val)
char *nam, *val;
{
    register int i=envix(nam);		/* where does it go? */

    if (!environ[i]) {			/* does not exist yet */
	if (firstsetenv) {		/* need we copy environment? */
	    int j;
#ifndef lint
	    char **tmpenv = (char**)	/* point our wand at memory */
		safemalloc((MEM_SIZE) (i+2) * sizeof(char*));
#else
	    char **tmpenv = Null(char **);
#endif /* lint */
    
	    firstsetenv = FALSE;
	    for (j=0; j<i; j++)		/* copy environment */
		tmpenv[j] = environ[j];
	    environ = tmpenv;		/* tell exec where it is now */
	}
#ifndef lint
	else
	    environ = (char**) saferealloc((char*) environ,
		(MEM_SIZE) (i+2) * sizeof(char*));
					/* just expand it a bit */
#endif /* lint */
	environ[i+1] = Nullch;	/* make sure it's null terminated */
    }
    environ[i] = safemalloc((MEM_SIZE) strlen(nam) + strlen(val) + 2);
					/* this may or may not be in */
					/* the old environ structure */
    sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
}

int
envix(nam)
char *nam;
{
    register int i, len = strlen(nam);

    for (i = 0; environ[i]; i++) {
	if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
	    break;			/* strnEQ must come first to avoid */
    }					/* potential SEGV's */
    return i;
}
#endif

void
notincl(feature)
char *feature;
{
    printf("\nNo room for feature \"%s\" on this machine.\n",feature) FLUSH;
}

char *
getval(nam,def)
char *nam,*def;
{
    char *val;

    if ((val = getenv(nam)) == Nullch || !*val)
	val = def;
    return val;
}

/* grow a static string to at least a certain length */

void
growstr(strptr,curlen,newlen)
char **strptr;
int *curlen;
int newlen;
{
    if (newlen > *curlen) {		/* need more room? */
	if (*curlen)
	    *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
	else
	    *strptr = safemalloc((MEM_SIZE)newlen);
	*curlen = newlen;
    }
}

void
setdef(buffer,dflt)
char *buffer,*dflt;
{
#ifdef STRICTCR
    if (*buffer == ' ')
#else
    if (*buffer == ' ' || *buffer == '\n')
#endif
    {
	if (*dflt == '^' && isupper(dflt[1]))
	    *buffer = Ctl(dflt[1]);
	else
	    *buffer = *dflt;
    }
}

#ifdef SERVER
int nntp_get(buf, len)
char *buf;
int  len;
{
 	int n;
#ifdef HAVESIGHOLD
 	sighold(SIGINT);
#endif
 	n = get_server(buf, len);
#ifdef HAVESIGHOLD
 	sigrelse(SIGINT);
#endif
 	return n;
}
#endif
!STUFFY!FUNK!
echo Extracting uudecode.c
cat >uudecode.c <<'!STUFFY!FUNK!'
/* $Id: uudecode.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $
 *
 * $Log: uudecode.c,v $
 * Revision 4.4  1991/09/09  20:27:37  sob
 * release 4.4
 *
 * 
 * Decode one or more uuencoded articles back to binary form.
 * Adapted to rn 4.4 by Stan Barber
 * Trn version created by Wayne Davison.
 * Adapted from the nn version by Kim Storm.
 * From the Berkeley original, modified by MSD, RDR, JPHD & WLS.
 */
/*
 * 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 "INTERN.h"
#include "uudecode.h"

#define MAXCHAR 256
#define NORMLEN 60	/* allows for 80 encoded chars per line */

#define SEQMAX 'z'
#define SEQMIN 'a'

static char seqc;
static int first, secnd, check, numl;

static char *target;
static char dest[MAXFILENAME];
static char blank;
static int chtbl[MAXCHAR], cdlen[NORMLEN + 3];
static int state;
static bool Xflag;
static int expecting_part;

static decode_line(), inittbls(), gettable();

#define	NO_ADVANCE		0x10

#define	FIND_BEGIN		0x01
#define	AFTER_ERROR_FIND_BEGIN	0x02
#define	DECODE_TEXT		0x03
#define	SKIP_TRAILING	       (0x04 | NO_ADVANCE)
#define	SKIP_LEADING		0x05
#define	FOUND_END	       (0x06 | NO_ADVANCE)
#define DECODE_ERROR	       (0x07 | NO_ADVANCE)
#define OTHER_ERROR	       (0x08 | NO_ADVANCE)
#define NEW_BEGIN	       (0x09 | NO_ADVANCE)

uud_start(dir)
char *dir;
{
    target = dir;
    uu_out = Nullfp;
    Xflag = FALSE;
    expecting_part = 0;
    seqc = SEQMAX;
    check = 1;
    first = 1;
    secnd = 0;
    state = FIND_BEGIN;
}

uud_end()
{
    if (uu_out != Nullfp) {
	fclose(uu_out);
	uu_out = Nullfp;
	printf("\n%s INCOMPLETE -- removed\n", dest);
	unlink(dest);
    }
}


uudecode(in)
FILE *in;
{
    int mode, onedone, lens;
    char buff[LBUFLEN];

    numl = onedone = 0;

    if (state == FIND_BEGIN)
	inittbls();

    /*
     * search for header or translation table line.
     */

    while ((state & NO_ADVANCE) || fgets(buff, sizeof buff, in) != Nullch) {
	numl++;

	switch (state) {
	 case NEW_BEGIN:
	    if (uu_out != Nullfp) {
		if (expecting_part) {
		    register int got_part = 0;

		    if (strnEQ(buff + 6, "part ", 5)) {
			register char *bp;

			for (bp = buff + 11; islower(*bp); bp++)
			    got_part = got_part * 26 + *bp - 'a';
		    }
		    if (expecting_part == got_part) {
			state = DECODE_TEXT;
			break;
		    }
		    printf("Expecting part %d; got part %d.\n",
			 expecting_part + 1, got_part + 1);
		    if (got_part) {
			state = SKIP_LEADING;
			return -1;
		    }
		}
		printf("INCOMPLETE FILE: %s -- removed\n", dest);
		sleep(2);
		fclose(uu_out);
		uu_out = Nullfp;
		Xflag = FALSE;
		expecting_part = 0;
		unlink(dest);
	    }
	    state = FIND_BEGIN;
	    /* fall thru */

	 case FIND_BEGIN:
	 case AFTER_ERROR_FIND_BEGIN:
	    if (strnEQ(buff, "table", 5)) {
		gettable(in);
		continue;
	    }

	    if (strnEQ(buff, "begin ", 6)
	     || strnEQ(buff, "Xbegin ", 7)) {
		lens = strlen(buff)-1;
		if (buff[lens] == '\n')
		    buff[lens] = '\0';

		if(sscanf(buff+6,"%o%s", &mode, uu_fname) != 2) {
		    register char *bp = buff + 6;

		    if (*bp == ' ')
			bp++;
		    if (strnEQ(bp, "part ", 5)) {
			register int got_part = 0;

			for (bp = bp + 5; islower(*bp); bp++)
			    got_part = got_part * 26 + *bp - 'a';
			printf("Expecting part 1; got part %d.\n",
				got_part + 1);
			return -1;
		    }
		    continue;
		}

		Xflag = (*buff == 'X');

		if (target != Nullch)
		    sprintf(dest, "%s/%s", target, uu_fname);
		else
		    strcpy(dest, uu_fname);

		if ((uu_out = fopen(dest, FOPEN_WB)) == Nullfp) {
		    printf("Cannot create file: %s\n", dest);
		    goto err;
		}
		chmod(dest, mode);
		printf("Decoding: %s\n", uu_fname);
		state = DECODE_TEXT;
	    }
	    continue;

	 case SKIP_LEADING:
	    state = decode_line(buff);
	    continue;

	 case DECODE_TEXT:
	    state = decode_line(buff);
	    onedone = 1;
	    continue;

	 case FOUND_END:
	    fclose(uu_out);
	    uu_out = Nullfp;
	    Xflag = FALSE;
	    expecting_part = 0;
	    state = FIND_BEGIN;
	    printf("Done.\n");
	    continue;

	 case SKIP_TRAILING:
	    printf("(Continued)\n");
	    state = SKIP_LEADING;
	    return 0;

	 case DECODE_ERROR:
	    state = SKIP_TRAILING;
	    continue;

	 case OTHER_ERROR:
	    fclose(uu_out);
	    uu_out = Nullfp;
	    Xflag = FALSE;
	    expecting_part = 0;
	    state = AFTER_ERROR_FIND_BEGIN;
	    goto err;
	}
    }

    if (onedone) {
	if (state == DECODE_TEXT) {
	    printf("(Continued)\n");
	    state = SKIP_LEADING;
	}
	return 0;
    }

    if (state == AFTER_ERROR_FIND_BEGIN)
	return -1;
    printf("Couldn't find anything to decode.\n");

 err:
    sleep(2);
    return -1;
}

/*
 * decode one line, write on uu_out file
 */

static decode_line(buff)
char *buff;
{
    char outl[LBUFLEN];
    register char *bp, *ut;
    register int *trtbl = chtbl;
    register int n;
    register int blen;		/* binary length (from decoded file) */
    register int rlen;		/* calculated input line length */
    register int len;		/* actual input line length */

    if (Xflag) {
	if (*buff == 'X')
	    buff++;
	else
	    *buff = 'x';	/* force a mis-parse of a non-x'ed line */
    }
    len = strlen(buff);
    if (--len < 0)
	return state;

    buff[len] = '\0';

    /*
     * Get the binary line length.
     */
    if ((blen = trtbl[buff[0]]) < 0) {
	if (state == SKIP_LEADING) {
	    if (strnEQ(buff, "begin ", 6))
		return NEW_BEGIN;

	    return SKIP_LEADING;
	}
	/*
	 * end of uuencoded file ?
	 */
	if (strnEQ(buff, "end", 3))
	    return FOUND_END;

	/*
	 * end of current file ? : get next one.
	 */
	if (strnEQ(buff, "include ", 8)) {
	    for (bp = buff + 8; *bp; bp++) {
		if (bp[0] == '.' && bp[1] == 'u') {
		    expecting_part = (bp[2] - 'a') * 26 + bp[3] - 'a';
		    break;
		}
	    }
	}

	/*
	 * trailing garbage
	 */
	return SKIP_TRAILING;
    }

    rlen = cdlen[blen];
    if (state == SKIP_LEADING && len != rlen && len != rlen+1)
	return SKIP_LEADING;

    /*
     * Is it the empty line before the end line ?
     */
    if (blen == 0)
	return state;

    if (len > rlen + 5)
	return SKIP_TRAILING;

    /*
     * Pad with blanks.
     */
    for (bp = buff + len, n = rlen - len; --n >= 0; )
	*bp++ = blank;

    /*
     * Verify
     */
    for (n = rlen, bp = buff; --n >= 0; bp++)
	if (trtbl[*bp] < 0) {
	    if (state == SKIP_LEADING)
		return SKIP_LEADING;
	    return DECODE_ERROR;
	}

    /*
     * Check for uuencodes that append a 'z' to each line....
     */
    if (check)
	if (secnd) {
	    secnd = 0;
	    if (buff[rlen] == SEQMAX)
		check = 0;
	} else if (first) {
	    first = 0;
	    secnd = 1;
	    if (buff[rlen] != SEQMAX)
		check = 0;
	}

    /*
     * There we check.
     */
    if (check) {
	if (buff[rlen] != seqc) {
	    if (state == SKIP_LEADING)
		return SKIP_LEADING;
	    return DECODE_ERROR;
	}

	if (--seqc < SEQMIN)
	    seqc = SEQMAX;
    }

    /*
     * output a group of 3 bytes (4 input characters).
     * the input chars are pointed to by p, they are to
     * be output to file f. blen is used to tell us not to
     * output all of them at the end of the file.
     */
    ut = outl;
    n = blen;
    bp = &buff[1];
    while (--n >= 0) {
	*(ut++) = trtbl[*bp] << 2 | trtbl[bp[1]] >> 4;
	if (n > 0) {
	    *(ut++) = (trtbl[bp[1]] << 4) | (trtbl[bp[2]] >> 2);
	    n--;
	}
	if (n > 0) {
	    *(ut++) = trtbl[bp[2]] << 6 | trtbl[bp[3]];
	    n--;
	}
	bp += 4;
    }
    if (fwrite(outl, 1, blen, uu_out) <= 0) {
	printf("Error on writing decoded file\n");
	return OTHER_ERROR;
    }

    return DECODE_TEXT;
}



/*
 * Install the table in memory for later use.
 */
static inittbls()
{
    register int i, j;

    /*
     * Set up the default translation table.
     */
    for (i = 0; i < ' '; i++)
	chtbl[i] = -1;
    for (i = ' ', j = 0; i < ' ' + 64; i++, j++)
	chtbl[i] = j;
    for (i = ' ' + 64; i < MAXCHAR; i++)
	chtbl[i] = -1;
    chtbl['`'] = chtbl[' '];	/* common mutation */
    chtbl['~'] = chtbl['^'];	/* another common mutation */
    blank = ' ';
    /*
     * set up the line length table, to avoid computing lotsa * and / ...
     */
    cdlen[0] = 1;
    for (i = 1, j = 5; i <= NORMLEN; i += 3, j += 4)
	cdlen[i] = (cdlen[i + 1] = (cdlen[i + 2] = j));
}

static gettable(in)
FILE *in;
{
    char buff[LBUFLEN];
    register int c, n = 0;
    register char *cpt;

    for (c = 0; c <= MAXCHAR; c++)
	chtbl[c] = -1;

    for (;;) {
	if (fgets(buff, sizeof buff, in) == Nullch) {
	    printf("EOF while in translation table.\n");
	    return -1;
	}
	numl++;
	if (strnEQ(buff, "begin", 5)) {
	    printf("Incomplete translation table.\n");
	    return -1;
	}
	cpt = buff + strlen(buff) - 1;
	*cpt = ' ';
	while (*cpt == ' ') {
	    *cpt = 0;
	    cpt--;
	}
	cpt = buff;
	while (c = *cpt) {
	    if (chtbl[c] != -1) {
		printf("Duplicate char in translation table.\n");
		return -1;
	    }
	    if (n == 0)
		blank = c;
	    chtbl[c] = n++;
	    if (n >= 64)
		return 0;
	    cpt++;
	}
    }
}

!STUFFY!FUNK!
echo Extracting ngdata.c
cat >ngdata.c <<'!STUFFY!FUNK!'
/* $Id: ngdata.c,v 4.4 1991/09/09 20:23:31 sob Exp sob $
 *
 * $Log: ngdata.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 "ndir.h"
#include "rcstuff.h"
#include "rn.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;

/* The following is only for systems that do not zero globals properly */
#ifdef ZEROGLOB
# ifdef CACHEFIRST
  {
    int i;
    for (i=0; i<maxrcline; i++)
	abs1st[i] = 0;
  }
# endif
#endif	/* ZEROGLOB */

/* The following is only for systems that do not zero globals properly */
#ifdef ZEROGLOB
# ifdef CACHEFIRST
  {
    int i;
    for (i=0; i<MAXRCLINE; i++)
	abs1st[i] = 0;
  }
# endif
#endif	/* ZEROGLOB */

    /* open the active file */

#ifdef SERVER
    put_server("LIST");		/* tell server we want the active file */
    nntp_get(ser_line, sizeof(ser_line));
    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);
    }

    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;

    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
#ifdef MININACT
    {
	register char *s, ch;
	ART_NUM tmp;

	for (s=tmpbuf+len+1; isdigit(*s); s++) ;
	if (tmp = atol(s))
#ifdef CACHEFIRST
	    abs1st[num] = tmp;
#else
	    abs1st = tmp;
#endif
	if (!in_ng) {
	    for (s++; isdigit(*s); s++) ;
	    while (isspace(*s)) s++;
	    ch = *s;
	    switch (ch) {
	    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;
	    }
	}
    }
#endif
    return atol(tmpbuf+len+1);
}

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;		/* well, not so quietly, actually */
    }
    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;
{
    register ART_NUM a1st;
#ifndef MININACT
    ART_NUM x,y;
#endif

#ifdef CACHEFIRST
    if (a1st = abs1st[ngnum])
	return a1st;
#endif
#ifdef MININACT
    getngsize(ngnum);
# ifdef CACHEFIRST
    return abs1st[ngnum];
# else
    return abs1st;
# endif
#else
    sprintf(cp,"GROUP %s",rcline[ngnum]);
    put_server(cp);
    if (nntp_get(ser_line, sizeof(ser_line)) < 0) {
	fprintf(stderr, "\nrrn: Unexpected close of server socket.\n");
	finalize(1);
    }
    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 */
    }
    (void) sscanf(ser_line,"%d%d%d",&x,&y,&a1st);
# ifdef CACHEFIRST
    abs1st[ngnum] = a1st;
# endif
    return 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
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 */
    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;
    char tmpbuf[128];
    
    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 have numbers in them as the first
	    * character, 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 1991/09/09 20:18:23 sob Exp sob $
 *
 * $Log: head.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 "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
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 current_subject;			/* is it in a parsed header? */
bool 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);
		if (nntp_get(ser_line, sizeof (ser_line)) >= 0) {
			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) {
				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);
		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 term.h
cat >term.h <<'!STUFFY!FUNK!'
/* $Id: term.h,v 4.4 1991/09/09 20:27:37 sob Exp sob $
 *
 * $Log: term.h,v $
 * Revision 4.4  1991/09/09  20:27:37  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. 
 */

#ifdef PUSHBACK
EXT char circlebuf[PUSHSIZE];
EXT int nextin INIT(0);
EXT int nextout INIT(0);
#ifdef PENDING
#ifdef FIONREAD
EXT long iocount INIT(0);
#ifndef lint
#define input_pending() (nextin!=nextout || (ioctl(0, FIONREAD, &iocount),(int)iocount))
#else
#define input_pending() bizarre
#endif /* lint */
#else /* FIONREAD */
#ifdef RDCHK
#define input_pending() (rdchk(0) > 0)		/* boolean only */
#else /*  RDCHK */
int circfill();
EXT int devtty INIT(0);
#ifndef lint
#define input_pending() (nextin!=nextout || circfill())
#else
#define input_pending() bizarre
#endif /* lint */
#endif /* RDCHK */
#endif /* FIONREAD */
#else /* PENDING */
#ifndef lint
#define input_pending() (nextin!=nextout)
#else
#define input_pending() bizarre
#endif /* lint */
#endif /* PENDING */
#else /* PUSHBACK */
#ifdef PENDING
#ifdef FIONREAD	/* must have FIONREAD or O_NDELAY for input_pending() */
#define read_tty(addr,size) read(0,addr,size)
#ifndef lint
#define input_pending() (ioctl(0, FIONREAD, &iocount),(int)iocount)
#else
#define input_pending() bizarre
#endif /* lint */
EXT long iocount INIT(0);

#else /* FIONREAD */

#ifdef RDCHK
#define input_pending() (rdchk(0) > 0)		/* boolean only */
#else /*  RDCHK */

EXT int devtty INIT(0);
EXT bool is_input INIT(FALSE);
EXT char pending_ch INIT(0);
#ifndef lint
#define input_pending() (is_input || (is_input=read(devtty,&pending_ch,1)))
#else
#define input_pending() bizarre
#endif /* lint */
#endif /*  RDCHK */
#endif /* FIONREAD */
#else /* PENDING */
#define read_tty(addr,size) read(0,addr,size)
#define input_pending() (FALSE)
#endif /* PENDING */
#endif /* PUSHBACK */

/* stuff wanted by terminal mode diddling routines */

#ifdef TERMIO
EXT struct termio _tty, _oldtty;
#else
EXT struct sgttyb _tty;
EXT int _res_flg INIT(0);
#endif

EXT int _tty_ch INIT(2);
EXT bool bizarre INIT(FALSE);			/* do we need to restore terminal? */

/* terminal mode diddling routines */

#ifdef TERMIO

#define crmode() ((bizarre=1),_tty.c_lflag &=~ICANON,_tty.c_cc[VMIN] = 1,ioctl(_tty_ch,TCSETAF,&_tty))
#define nocrmode() ((bizarre=1),_tty.c_lflag |= ICANON,_tty.c_cc[VEOF] = CEOF,stty(_tty_ch,&_tty))
#define echo()	 ((bizarre=1),_tty.c_lflag |= ECHO, ioctl(_tty_ch, TCSETA, &_tty))
#define noecho() ((bizarre=1),_tty.c_lflag &=~ECHO, ioctl(_tty_ch, TCSETA, &_tty))
#define nl()	 ((bizarre=1),_tty.c_iflag |= ICRNL,_tty.c_oflag |= ONLCR,ioctl(_tty_ch, TCSETAW, &_tty))
#define nonl()	 ((bizarre=1),_tty.c_iflag &=~ICRNL,_tty.c_oflag &=~ONLCR,ioctl(_tty_ch, TCSETAW, &_tty))
#define	savetty() (ioctl(_tty_ch, TCGETA, &_oldtty),ioctl(_tty_ch, TCGETA, &_tty))
#define	resetty() ((bizarre=0),ioctl(_tty_ch, TCSETAF, &_oldtty))
#define unflush_output()

#else

#define raw()	 ((bizarre=1),_tty.sg_flags|=RAW, stty(_tty_ch,&_tty))
#define noraw()	 ((bizarre=1),_tty.sg_flags&=~RAW,stty(_tty_ch,&_tty))
#define crmode() ((bizarre=1),_tty.sg_flags |= CBREAK, stty(_tty_ch,&_tty))
#define nocrmode() ((bizarre=1),_tty.sg_flags &= ~CBREAK,stty(_tty_ch,&_tty))
#define echo()	 ((bizarre=1),_tty.sg_flags |= ECHO, stty(_tty_ch, &_tty))
#define noecho() ((bizarre=1),_tty.sg_flags &= ~ECHO, stty(_tty_ch, &_tty))
#define nl()	 ((bizarre=1),_tty.sg_flags |= CRMOD,stty(_tty_ch, &_tty))
#define nonl()	 ((bizarre=1),_tty.sg_flags &= ~CRMOD, stty(_tty_ch, &_tty))
#define	savetty() (gtty(_tty_ch, &_tty), _res_flg = _tty.sg_flags)
#define	resetty() ((bizarre=0),_tty.sg_flags = _res_flg, stty(_tty_ch, &_tty))
#ifdef LFLUSHO
#ifndef lint
EXT int lflusho INIT(LFLUSHO);
#else
EXT long lflusho INIT(LFLUSHO);
#endif /* lint */
#define unflush_output() (ioctl(_tty_ch,TIOCLBIC,&lflusho))
#else
#define unflush_output()
#endif /* LFLUSHO */
#endif /* TERMIO */

#ifdef TIOCSTI
#ifdef lint
#define forceme(c) ioctl(_tty_ch,TIOCSTI,Null(long*))	/* ghad! */
#else
#define forceme(c) ioctl(_tty_ch,TIOCSTI,c) /* pass character in " " */
#endif /* lint */
#else
#define forceme(c)
#endif

/* termcap stuff */

/*
 * NOTE: if you don't have termlib you'll either have to define these strings
 *    and the tputs routine, or you'll have to redefine the macros below
 */

#ifdef HAVETERMLIB
EXT int GT;				/* hardware tabs */
EXT char *BC INIT(Nullch);		/* backspace character */
EXT char *UP INIT(Nullch);		/* move cursor up one line */
EXT char *CR INIT(Nullch);		/* get to left margin, somehow */
EXT char *VB INIT(Nullch);		/* visible bell */
EXT char *CL INIT(Nullch);		/* home and clear screen */
EXT char *CE INIT(Nullch);		/* clear to end of line */
EXT char *TI INIT(Nullch);		/* initialize terminal */
EXT char *TE INIT(Nullch);		/* reset terminal */
#ifdef CLEAREOL
EXT char *CM INIT(Nullch);		/* cursor motion */
EXT char *HO INIT(Nullch);		/* home cursor */
EXT char *CD INIT(Nullch);		/* clear to end of display */
#endif /* CLEAREOL */
EXT char *SO INIT(Nullch);		/* begin standout mode */
EXT char *SE INIT(Nullch);		/* end standout mode */
EXT int SG INIT(0);			/* blanks left by SO and SE */
EXT char *US INIT(Nullch);		/* start underline mode */
EXT char *UE INIT(Nullch);		/* end underline mode */
EXT char *UC INIT(Nullch);		/* underline a character,
						 if that's how it's done */
EXT int UG INIT(0);			/* blanks left by US and UE */
EXT bool AM INIT(FALSE);		/* does terminal have automatic
								 margins? */
EXT bool XN INIT(FALSE);		/* does it eat 1st newline after
							 automatic wrap? */
EXT char PC INIT(0);			/* pad character for use by tputs() */
EXT long ospeed INIT(0);		/* terminal output speed, 
							for use by tputs() */
EXT int LINES INIT(0), COLS INIT(0);	/* size of screen */
EXT int just_a_sec INIT(960);		/* 1 sec at current baud rate */
					/* (number of nulls) */

/* define a few handy macros */

#define backspace() tputs(BC,0,putchr) FLUSH
#define clear() tputs(CL,LINES,putchr) FLUSH
#define erase_eol() tputs(CE,1,putchr) FLUSH
#ifdef CLEAREOL
#define clear_rest() tputs(CD,LINES,putchr) FLUSH
#define maybe_eol() if(erase_screen&&can_home_clear)tputs(CE,1,putchr) FLUSH
#endif /* CLEAREOL */
#define underline() tputs(US,1,putchr) FLUSH
#define un_underline() tputs(UE,1,putchr) FLUSH
#define underchar() tputs(UC,0,putchr) FLUSH
#define standout() tputs(SO,1,putchr) FLUSH
#define un_standout() tputs(SE,1,putchr) FLUSH
#define up_line() tputs(UP,1,putchr) FLUSH
#define carriage_return() tputs(CR,1,putchr) FLUSH
#define dingaling() tputs(VB,1,putchr) FLUSH
#else
  ????????		/* up to you */
#endif

EXT int page_line INIT(1);	/* line number for paging in
						 print_line (origin 1) */

void	term_init ANSI((void));
void	term_set ANSI((char *));
#ifdef PUSHBACK
void	pushchar ANSI((char));
void	mac_init ANSI((char *));
void	mac_line ANSI((char *,char *,int));
void	show_macros ANSI((void));
#endif
char	putchr ANSI((char));	/* routine for tputs to call */
bool	finish_command ANSI((int));
void	eat_typeahead ANSI((void));
void	settle_down ANSI((void));
#ifdef HAVETERMLIB
void	termlib_init ANSI((void));
void	termlib_reset ANSI((void));
#endif
#ifndef read_tty
    int		read_tty ANSI((char *,int));
#endif
void	underprint ANSI((char *));
#ifdef NOFIREWORKS
    void	no_sofire ANSI((void));
    void	no_ulfire ANSI((void));
#endif
void	getcmd ANSI((char *));
int	get_anything ANSI((void));
void	in_char ANSI((char *,char));
int	print_lines ANSI((char *,int));
void	page_init ANSI((void));
void	pad ANSI((int));
void	printcmd ANSI((void));
void	rubout ANSI((void));
void	reprint ANSI((void));
#ifdef CLEAREOL
void	home_cursor ANSI((void));
#endif
#ifdef SIGWINCH
SIGRET	winch_catcher ANSI((void));
#endif /* SIGWINCH */
!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 ""
echo "End of kit 7 (of 10)"
cat /dev/null >kit7isdone
config=true
for iskit in 1 2 3 4 5 6 7 8 9 10 ; 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
