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

static char nullart[] = "\nNull article\n";

void
respond_init()
{
    ;
}

int
save_article()
{
    bool use_pref, cut_line();
    register char *s, *c;
    char altbuf[CBUFLEN];
    int iter;
    bool interactive = (buf[1] == FINISHCMD);
    char cmd = *buf;
    
    if (!finish_command(interactive))	/* get rest of command */
	return SAVE_ABORT;
    if ((use_pref = isupper(cmd)) != 0)
	cmd = tolower(cmd);
#ifdef ASYNC_PARSE
    parse_maybe(art);
#endif
    savefrom = (cmd == 'w' || cmd == 'e' ? htype[PAST_HEADER].ht_minpos : 0);
    if (artopen(art) == Nullfp) {
#ifdef VERBOSE
	IF(verbose)
	    fputs("\n\
Saving null articles is not very productive!  :-)\n\
",stdout) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    fputs(nullart,stdout) FLUSH;
#endif
	return SAVE_DONE;
    }
    if (chdir(cwd)) {
	printf(nocd,cwd) FLUSH;
	sig_catcher(0);
    }
    if (cmd == 'e') {		/* is this an extract command? */
	static bool custom_extract = FALSE;
	int cnt = 0;
	bool found_cut = FALSE;
	char art_buf[LBUFLEN], *cmdstr;

	s = buf+1;		/* skip e */
	while (*s == ' ') s++;	/* skip leading spaces */
	safecpy(altbuf,filexp(s),sizeof altbuf);
	s = altbuf;
	if (*s) {
	    cmdstr = cpytill(buf,s,'|');	/* check for | */
	    s = buf + strlen(buf)-1;
	    while (*s == ' ') s--;		/* trim trailing spaces */
	    *++s = '\0';
	    if (*cmdstr) {
		s = cmdstr+1;			/* skip | */
		while (*s == ' ') s++;
		if (*s)	{			/* if new command, use it */
		    if (extractprog)
			free(extractprog);
		    extractprog = savestr(s);	/* put extracter in %e */
		}
		else
		    cmdstr = extractprog;
	    }
	    else
		cmdstr = Nullch;
	    s = buf;
	}
	else {
	    if (savedest)
		strcpy(s, savedest);
	    if (custom_extract)
		cmdstr = extractprog;
	    else
		cmdstr = Nullch;
	}
	if (cmdstr) {
	    if (strEQ(extractprog,"-"))
		cmdstr = Nullch;
	    else if (uu_out != Nullfp)
		uud_end();
	}
	custom_extract = (cmdstr != 0);

	fseek(artfp,savefrom,0);
	if (*s != '/') {		/* relative path? */
	    c = (s==buf ? altbuf : buf);
	    interp(c, (sizeof buf), getval("SAVEDIR",SAVEDIR));
	    if (makedir(c,MD_DIR))	/* ensure directory exists */
		strcpy(c,cwd);
	    if (*s) {
		while (*c) c++;
		*c++ = '/';
		strcpy(c,s);		/* add filename */
	    }
	    s = (s==buf ? altbuf : buf);
	}
	if (*s != '/') {		/* path still relative? */
	    c = (s==buf ? altbuf : buf);
	    sprintf(c, "%s/%s", cwd, s);
	    s = c;			/* absolutize it */
	}
	if (uu_out != Nullfp) {
	    printf("Continuing %s:%s\n", uu_fname,
		cmd != '\0' && strNE(savedest,s) ?
		 " (Ignoring conflicting directory)" : nullstr ) FLUSH;
	    uudecode(artfp);
	}
	else {
	    if (savedest)
		free(savedest);
	    s = savedest = savestr(s);	/* make it handy for %b */
	    if (makedir(s, MD_DIR)) {	/* ensure directory exists */
		int_count++;
		return SAVE_DONE;
	    }
	    if (chdir(s)) {
		printf(nocd,s) FLUSH;
		sig_catcher(0);
	    }
	    s = getwd(buf);		/* simplify path for output */
	    while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
		if (*art_buf <= ' ')
		    continue;	/* Ignore empty or initially-whitespace lines */
		if (found_cut && custom_extract) {
		    printf("Extracting data into %s using %s:\n",
			s, extractprog) FLUSH;
		    goto extract_it;
		}
		if (((*art_buf == '#' || *art_buf == ':')
		  && (strnEQ(art_buf+1, "! /bin/sh", 9)
		   || strnEQ(art_buf+1, "!/bin/sh", 8)
		   || strnEQ(art_buf+2, "This is ", 8)))
		 || strnEQ(art_buf, "sed ", 4)
		 || strnEQ(art_buf, "cat ", 4)
		 || strnEQ(art_buf, "echo ", 5)) {
		    fseek(artfp,(long)-strlen(art_buf)-NL_SIZE+1,1);
		    savefrom = ftell(artfp);
		    if (custom_extract) {
			printf("Extracting shar into %s using %s:\n",
				s, extractprog) FLUSH;
			goto extract_it;
		    }
		    /* Check for special-case of shar'ed-uuencoded file */
		    while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
			if (*art_buf == '#' || *art_buf == ':'
			 || strnEQ(art_buf, "echo ", 5)
			 || strnEQ(art_buf, "sed ", 4))
			    continue;
			if (strnEQ(art_buf, "Xbegin ", 7))
			    goto uu_decode;
			break;
		    }
		    printf("Extracting shar into %s:\n", s) FLUSH;
		    if (extractprog)
			free(extractprog);
		    extractprog = savestr(filexp(getval("UNSHAR",UNSHAR)));
		  extract_it:
		    cnt = 0;
		    interp(cmd_buf,(sizeof cmd_buf),getval("EXSAVER",EXSAVER));
		    resetty();		/* restore tty state */
		    doshell(SH,cmd_buf);
		    noecho();		/* revert to cbreaking */
		    crmode();
		    break;
		}
		else
		if (!custom_extract
		 && (strnEQ(art_buf,"table\n", 6)
		  || strnEQ(art_buf,"begin ", 6))) {
		 uu_decode:
		    printf("Extracting uuencoded file into %s:\n", s) FLUSH;
		    if (extractprog)
			free(extractprog);
		    extractprog = savestr("-");
		    cnt = 0;
		    fseek(artfp,(long)-strlen(art_buf)-NL_SIZE+1,1);
		    savefrom = ftell(artfp);
		    uud_start(s);
		    uudecode(artfp);
		    break;
		}
		else {
		    if (cut_line(art_buf)) {
			savefrom = ftell(artfp);
			found_cut = TRUE;
		    }
		    else if (found_cut || ++cnt == 300) {
			break;
		    }
		}
	    }/* while */
	    if (cnt) {
		if (custom_extract)
		    printf("Didn't find cut line for extraction to '%s'.\n",
			extractprog) FLUSH;
		else
		    printf("Unable to determine type of file.\n") FLUSH;
	    }
	}/* if */
    }
    else if ((s = index(buf,'|')) != Nullch) {
				/* is it a pipe command? */
	s++;			/* skip the | */
	while (*s == ' ') s++;
	safecpy(altbuf,filexp(s),sizeof altbuf);
	if (savedest)
	    free(savedest);
	savedest = savestr(altbuf);
	interp(cmd_buf, (sizeof cmd_buf), getval("PIPESAVER",PIPESAVER));
				/* then set up for command */
	resetty();		/* restore tty state */
	if (use_pref)		/* use preferred shell? */
	    doshell(Nullch,cmd_buf);
				/* do command with it */
	else
	    doshell(sh,cmd_buf);	/* do command with sh */
	noecho();		/* and stop echoing */
	crmode();		/* and start cbreaking */
    }
    else {			/* normal save */
	bool there, mailbox;
	char *savename = getval("SAVENAME",SAVENAME);

	s = buf+1;		/* skip s or S */
	if (*s == '-') {	/* if they are confused, skip - also */
#ifdef VERBOSE
	    IF(verbose)
		fputs("Warning: '-' ignored.  This isn't readnews.\n",stdout)
		  FLUSH;
	    ELSE
#endif
#ifdef TERSE
		fputs("'-' ignored.\n",stdout) FLUSH;
#endif
	    s++;
	}
	for (; *s == ' '; s++);	/* skip spaces */
	safecpy(altbuf,filexp(s),sizeof altbuf);
	s = altbuf;
	if (! index(s,'/')) {
	    interp(buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
	    if (makedir(buf,MD_DIR))	/* ensure directory exists */
		strcpy(buf,cwd);
	    if (*s) {
		for (c = buf; *c; c++) ;
		*c++ = '/';
		strcpy(c,s);		/* add filename */
	    }
	    s = buf;
	}
	for (iter = 0;
	    (there = stat(s,&filestat) >= 0) &&
	    (filestat.st_mode & S_IFDIR);
	    iter++) {			/* is it a directory? */

	    c = (s+strlen(s));
	    *c++ = '/';			/* put a slash before filename */
	    interp(c, s==buf?(sizeof buf):(sizeof altbuf),
		iter ? "News" : savename );
				/* generate a default name somehow or other */
	}
	makedir(s,MD_FILE);
	if (*s != '/') {		/* relative path? */
	    c = (s==buf ? altbuf : buf);
	    sprintf(c, "%s/%s", cwd, s);
	    s = c;			/* absolutize it */
	}
	if (savedest)
	    free(savedest);
	s = savedest = savestr(s);	/* doesn't move any more */
					/* make it handy for %b */
	if (!there) {
	    if (mbox_always)
		mailbox = TRUE;
	    else if (norm_always)
		mailbox = FALSE;
	    else {
		char *dflt = (instr(savename,"%a", TRUE) ? "nyq" : "ynq");
		
		sprintf(cmd_buf,
		"\nFile %s doesn't exist--\n	use mailbox format? [%s] ",
		  s,dflt);
	      reask_save:
		in_char(cmd_buf, 'M');
		putchar('\n') FLUSH;
		setdef(buf,dflt);
#ifdef VERIFY
		printcmd();
#endif
		if (*buf == 'h') {
#ifdef VERBOSE
		    IF(verbose)
			printf("\n\
Type y to create %s as a mailbox.\n\
Type n to create it as a normal file.\n\
Type q to abort the save.\n\
",s) FLUSH;
		    ELSE
#endif
#ifdef TERSE
			fputs("\n\
y to create mailbox.\n\
n to create normal file.\n\
q to abort.\n\
",stdout) FLUSH;
#endif
		    goto reask_save;
		}
		else if (*buf == 'n') {
		    mailbox = FALSE;
		}
		else if (*buf == 'y') {
		    mailbox = TRUE;
		}
		else if (*buf == 'q') {
		    goto s_bomb;
		}
		else {
		    fputs(hforhelp,stdout) FLUSH;
		    settle_down();
		    goto reask_save;
		}
	    }
	}
	else if (filestat.st_mode & S_IFCHR)
	    mailbox = FALSE;
	else {
	    int tmpfd;
	    
	    tmpfd = open(s,0);
	    if (tmpfd == -1)
		mailbox = FALSE;
	    else {
		read(tmpfd,buf,LBUFLEN);
		c = buf;
		if (!isspace(MBOXCHAR))
		    while (isspace(*c))
			c++;
		mailbox = (*c == MBOXCHAR);
		close(tmpfd);
	    }
	}

	safecpy(cmd_buf, filexp(mailbox ?
	    getval("MBOXSAVER",MBOXSAVER) :
	    getval("NORMSAVER",NORMSAVER) ), sizeof cmd_buf);
				/* format the command */
	resetty();		/* make terminal behave */
	if (doshell(use_pref?Nullch:SH,cmd_buf))
	    fputs("Not saved",stdout);
	else
	    printf("%s to %s %s",
	      there?"Appended":"Saved",
	      mailbox?"mailbox":"file",
	      s);
	if (interactive)
	    putchar('\n') FLUSH;
	noecho();		/* make terminal do what we want */
	crmode();
    }
s_bomb:
#ifdef SERVER
    if (chdir(spool)) {
#else /* not SERVER */
    if (chdir(spool) || chdir(ngdir)) {
#endif /* SERVER */
	printf(nocd,ngdir) FLUSH;
	sig_catcher(0);
    }
    return SAVE_DONE;
}

int
cancel_article()
{
    char *artid_buf;
    char *ngs_buf;
    char *from_buf;
    char *reply_buf;
    int myuid = getuid();
    int r = -1;

    if (artopen(art) == Nullfp) {
#ifdef VERBOSE
	IF(verbose)
	    fputs("\n\
Cancelling null articles is your idea of fun?  :-)\n\
",stdout) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    fputs(nullart,stdout) FLUSH;
#endif
	return r;
    }
    reply_buf = fetchlines(art,REPLY_LINE);
    from_buf = fetchlines(art,FROM_LINE);
    artid_buf = fetchlines(art,ARTID_LINE);
    ngs_buf = fetchlines(art,NGS_LINE);
    if (!instr(from_buf,sitename,FALSE) ||
	(!instr(from_buf,logname,TRUE) &&
	 !instr(reply_buf,logname,TRUE) &&
#ifdef NEWSADMIN
	 myuid != newsuid &&
#endif
	 myuid != ROOTID ) ) {
	    if (debug)
		printf("\n%s@%s != %s\n",logname,sitename,from_buf) FLUSH;
#ifdef VERBOSE
	    IF(verbose)
		fputs("\nYou can't cancel someone else's article\n",stdout)
		  FLUSH;
	    ELSE
#endif
#ifdef TERSE
		fputs("\nNot your article\n",stdout) FLUSH;
#endif
    }
    else {
	tmpfp = fopen(headname,"w");	/* open header file */
	if (tmpfp == Nullfp) {
	    printf(cantcreate,headname) FLUSH;
	    goto no_cancel;
	}
	interp(buf, (sizeof buf), getval("CANCELHEADER",CANCELHEADER));
	fputs(buf,tmpfp);
	fclose(tmpfp);
	fputs("\nCanceling...\n",stdout) FLUSH;
	r = doshell(sh,filexp(getval("CANCEL",CANCEL)));
    }
no_cancel:
    free(artid_buf);
    free(ngs_buf);
    free(from_buf);
    free(reply_buf);
    return r;
}

int
supersede_article()		/* Supersedes: */
{
    char *artid_buf;
    char *ngs_buf;
    char *from_buf;
    char *reply_buf;
    int myuid = getuid();
    int r = -1;

    if (artopen(art) == Nullfp) {
#ifdef VERBOSE
	IF(verbose)
	    fputs("\n\
Superceding null articles is your idea of fun?  :-)\n\
",stdout) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    fputs(nullart,stdout) FLUSH;
#endif
	return r;
    }
    reply_buf = fetchlines(art,REPLY_LINE);
    from_buf = fetchlines(art,FROM_LINE);
    artid_buf = fetchlines(art,ARTID_LINE);
    ngs_buf = fetchlines(art,NGS_LINE);
    if (!instr(from_buf,sitename,FALSE) ||
	(!instr(from_buf,logname,TRUE) &&
	 !instr(reply_buf,logname,TRUE) &&
#ifdef NEWSADMIN
	 myuid != newsuid &&
#endif
	 myuid != ROOTID ) ) {
	    if (debug)
		printf("\n%s@%s != %s\n",logname,sitename,from_buf) FLUSH;
#ifdef VERBOSE
	    IF(verbose)
		fputs("\nYou can't supersede someone else's article\n",stdout)
		  FLUSH;
	    ELSE
#endif
#ifdef TERSE
		fputs("\nNot your article\n",stdout) FLUSH;
#endif
    }
    else {
	tmpfp = fopen(headname,"w");	/* open header file */
	if (tmpfp == Nullfp) {
	    printf(cantcreate,headname) FLUSH;
	    goto no_commute;
	}
	interp(buf, (sizeof buf), getval("SUPERSEDEHEADER",SUPERSEDEHEADER));
	fputs(buf,tmpfp);
	fclose(tmpfp);
    	safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),
		sizeof cmd_buf);
    	invoke(cmd_buf,origdir);
	r = 0;
    }
no_commute:
    free(artid_buf);
    free(ngs_buf);
    free(from_buf);
    free(reply_buf);
    return r;
}

void
reply()
{
    bool incl_body = (*buf == 'R');
    char *maildoer = savestr(filexp(getval("MAILPOSTER",MAILPOSTER)));

    artopen(art);
    tmpfp = fopen(headname,"w");	/* open header file */
    if (tmpfp == Nullfp) {
	printf(cantcreate,headname) FLUSH;
	goto no_reply;
    }
    interp(buf, (sizeof buf), getval("MAILHEADER",MAILHEADER));
    fputs(buf,tmpfp);
    if (!instr(maildoer,"%h",TRUE))
#ifdef VERBOSE
	IF(verbose)
	    printf("\n%s\n(Above lines saved in file %s)\n",buf,headname)
	      FLUSH;
	ELSE
#endif
#ifdef TERSE
	    printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH;
#endif
    if (incl_body && artfp != Nullfp) {
	interp(buf, (sizeof buf), getval("YOUSAID",YOUSAID));
	fprintf(tmpfp,"%s\n",buf);
#ifdef ASYNC_PARSE
	parse_maybe(art);
#endif
	fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
	while (fgets(buf,LBUFLEN,artfp) != Nullch) {
	    fprintf(tmpfp,"%s%s",indstr,buf);
	}
	fprintf(tmpfp,"\n");
    }
    fclose(tmpfp);
    interp(cmd_buf, (sizeof cmd_buf), maildoer);
    invoke(cmd_buf,origdir);
    UNLINK(headname);		/* kill the header file */
no_reply:
    free(maildoer);
}

void
followup()
{
    bool incl_body = (*buf == 'F');
    char hbuf[4*LBUFLEN];	/* four times the old size */

    artopen(art);
    tmpfp = fopen(headname,"w");
    if (tmpfp == Nullfp) {
	printf(cantcreate,headname) FLUSH;
	return;
    }
    interp(hbuf, (sizeof hbuf), getval("NEWSHEADER",NEWSHEADER));
    fprintf(tmpfp,"%s",hbuf);
    if (incl_body && artfp != Nullfp) {
#ifdef VERBOSE
	if (verbose)
	    fputs("\n\
(Be sure to double-check the attribution against the signature, and\n\
trim the quoted article down as much as possible.)\n\
",stdout) FLUSH;
#endif
	interp(buf, (sizeof buf), getval("ATTRIBUTION",ATTRIBUTION));
	fprintf(tmpfp,"%s\n",buf);
#ifdef ASYNC_PARSE
	parse_maybe(art);
#endif
	fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
	while (fgets(buf,LBUFLEN,artfp) != Nullch) {
	    fprintf(tmpfp,"%s%s",indstr,buf);
	}
	fprintf(tmpfp,"\n");
    }
    fclose(tmpfp);
    safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),sizeof cmd_buf);
    invoke(cmd_buf,origdir);
    UNLINK(headname);
}

void
invoke(cmd,dir)
char *cmd,*dir;
{
    if (chdir(dir)) {
	printf(nocd,dir) FLUSH;
	return;
    }
#ifdef VERBOSE
    IF(verbose)
	printf("\n(leaving cbreak mode; cwd=%s)\nInvoking command: %s\n\n",
	    dir,cmd) FLUSH;
    ELSE
#endif
#ifdef TERSE
	printf("\n(-cbreak; cwd=%s)\nInvoking: %s\n\n",dir,cmd) FLUSH;
#endif
    resetty();			/* make terminal well-behaved */
    doshell(sh,cmd);		/* do the command */
    noecho();			/* set no echo */
    crmode();			/* and cbreak mode */
#ifdef VERBOSE
    IF(verbose)
	fputs("\n(re-entering cbreak mode)\n",stdout) FLUSH;
    ELSE
#endif
#ifdef TERSE
	fputs("\n(+cbreak)\n",stdout) FLUSH;
#endif
#ifdef SERVER
    if (chdir(spool)) {
#else /* not SERVER */
    if (chdir(spool) || chdir(ngdir)) {
#endif /* SERVER */
	printf(nocd,ngdir) FLUSH;
	sig_catcher(0);
    }
}

/*
** cut_line() determines if a line is meant as a "cut here" marker.
** Some examples that we understand:
**
**  BEGIN--cut here--cut here
**
**  ------------------ tear at this line ------------------
**
**  #----cut here-----cut here-----cut here-----cut here----#
*/
bool
cut_line(str)
char *str;
{
    char *cp, got_flag;
    char word[80];
    int  dash_cnt, equal_cnt, other_cnt;

    /* Disallow any single-/double-quoted, parenthetical or c-commented
    ** string lines.  Make sure it has the cut-phrase and at least six
    ** '-'s or '='s.  If only four '-'s are present, check for a duplicate
    ** of the cut phrase.  If over 20 unknown characters are encountered,
    ** assume it isn't a cut line.  If we succeed, return TRUE.
    */
    for (cp = str, dash_cnt = equal_cnt = other_cnt = 0; *cp; cp++) {
	switch (*cp) {
	case '-':
	    dash_cnt++;
	    break;
	case '=':
	    equal_cnt++;
	    break;
	case '/':
	    if(*(cp+1) != '*') {
		break;
	    }
	case '"':
	case '\'':
	case '(':
	case ')':
	case '[':
	case ']':
	case '{':
	case '}':
	    return FALSE;
	default:
	    other_cnt++;
	    break;
	}
    }
    if (dash_cnt < 4 && equal_cnt < 6)
	return FALSE;

    got_flag = 0;

    for (*(cp = word) = '\0'; *str; str++) {
	if (islower(*str))
	    *cp++ = *str;
	else if (isupper(*str))
	    *cp++ = tolower(*str);
	else {
	    if (*word) {
		*cp = '\0';
		switch (got_flag) {
		case 2:
		    if (!strcmp(word, "line")
		     || !strcmp(word, "here"))
			if ((other_cnt -= 4) <= 20)
			    return TRUE;
		    break;
		case 1:
		    if (!strcmp(word, "this")) {
			got_flag = 2;
			other_cnt -= 4;
		    }
		    else if (!strcmp(word, "here")) {
			other_cnt -= 4;
			if ((dash_cnt >= 6 || equal_cnt >= 6)
			 && other_cnt <= 20)
			    return TRUE;
			dash_cnt = 6;
			got_flag = 0;
		    }
		    break;
		case 0:
		    if (!strcmp(word, "cut")
		     || !strcmp(word, "snip")
		     || !strcmp(word, "tear")) {
			got_flag = 1;
			other_cnt -= strlen(word);
		    }
		    break;
		}
		*(cp = word) = '\0';
	    }
	}
    } /* for *str */

    return FALSE;
}
!STUFFY!FUNK!
echo Extracting Pnews.SH
cat >Pnews.SH <<'!STUFFY!FUNK!'
case $CONFIG in
    '') . ./config.sh ;;
esac
echo "Extracting Pnews (with variable substitutions)"
$spitshell >Pnews <<!GROK!THIS!
$startsh
# $Id: Pnews.SH,v 4.4 1991/09/09 20:18:23 sob Exp sob $
#
# $Log: Pnews.SH,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. 
#
# syntax: Pnews -h headerfile			or
#	  Pnews -h headerfile oldarticle	or
#         Pnews newsgroup title			or just
#         Pnews

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

case $portable in
define)
# your site name
case "$hostcmd" in
'') sitename="$sitename" ;;
*)  sitename=\`$hostcmd\` ;;
esac
case \$sitename in
	*.*)
		;;
	*)
		sitename=\${sitename}.$domain
		;;
esac
# where recordings, distributions and moderators are kept
lib=\`$filexp $lib\`
# where important rn things are kept
rnlib=\`$filexp $rnlib\`
;;
undef)
# your site name
sitename="$sitename"
# where recordings, distributions and moderators are kept
lib="$lib"
# where important rn things are kept
rnlib="$rnlib"
;;
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"
# how not to echo with newline
n="$n"
c="$c"

# You should also look at the distribution warnings below marked !DIST!
# to make sure any distribution regions you are a member of are included.
# The following are some prototypical distribution groups.  If you do not
# use them all set the unused ones to a non-null string such as 'none'.
loc="$locpref"
org="$orgpref"
city="$citypref"
state="$statepref"
cntry="$cntrypref"
cont="$contpref"

test=${test-test}
sed=${sed-sed}
echo=${echo-echo}
cat=${cat-cat}
egrep=${egrep-egrep}
grep=${grep-grep}
rm=${rm-rm}
tr=${tr-tr}
inews=${inews-inews}
nidump=${nidump}
ypmatch=${ypmatch}

!GROK!THIS!
$spitshell >>Pnews <<'!NO!SUBS!'
dotdir=${DOTDIR-${HOME-$LOGDIR}}
tmpart=$dotdir/.article

if $test -f $dotdir/.pnewsexpert; then
    expertise=expert
else
    $cat <<'EOM'
I see you've never used this version of Pnews before.  I will give you extra
help this first time through, but then you must remember what you learned.
If you don't understand any question, type h and a CR (carriage return) for
help.

If you've never posted an article to the net before, it is HIGHLY recommended
that you read the netiquette document found in news.announce.newusers so
that you'll know to avoid the commonest blunders.  To do that, interrupt
Pnews, and get to the top-level prompt of rn.  Type "g news.announce.newusers"
and you are on your way.

EOM
    expertise=beginner
fi

case $cntry in
  can) stpr=Province ;;
  *)   stpr=State ;;
esac

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

case $headerfile in
'')
    . $rnlib/Pnews.header
    ;;
*)
    $cat < $headerfile  > $tmpart
    ;;
esac
    rescue="sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.article ; $echo Article appended to ${HOME-$LOGDIR}/dead.article ; exit"
    trap "$rescue" 1
    trap "$rescue" 2

$echo ""

# extract the newsgroups list and distribution
hdr_newsgroups=`$sed -n -e '/^Newsgroups:/{' -e 's///' -e 's/,/ /g' -e p -e q -e '}' $tmpart`
hdr_distribution=`$sed -n -e '/^Distribution:/{' -e 's///' -e p -e q -e '}' $tmpart`

# check for "poster" magic cookie
flag=0
for ng in $hdr_newsgroups ; do
    case "$ng" in
	poster)	flag=1 ;;
	*)	;;
    esac
done
case $flag in
1)
    $echo " "
    $echo "The original author has requested that messages be sent back via"
    $echo "mail rather than posting to news.  Do you want to jump out of this"
    $echo $n "and mail your reply instead? [yn] $c"
    read ans
    case $ans in
	n*) ;;
	*)  exit ;;
    esac
    $echo " "
    $echo "OK, but you will have to edit the 'Newsgroups:' line in the message."
    ;;
esac
  
# play recorded message
if $test -s ${lib}/recording ; then
     for ng in $hdr_newsgroups ; do
	_rec1=${lib}/`$sed -n "/^$ng/s/^.*	//p" ${lib}/recording`
	_tmp=`$echo $ng |$sed "s/\..*//"`
	_rec2=${lib}/`$cat -s ${lib}/recording|$grep ${_tmp}.all|$sed "s/^.*	//"`
	if $test -f ${_rec1} ; then
	    $cat -s ${_rec1}
	fi
	if $test -f ${_rec2} ; then
	    $cat -s ${_rec2}
	fi
    done
fi

# determine the distribution of this message
set X $hdr_distribution
shift
if $test $# -gt 0 ; then
    dist=$1.whatever
else
    set X $hdr_newsgroups
    shift
    if $test $# -gt 0 ; then
	dist=$1.whatever
    else
	dist=misc.whatever
    fi
fi
case $dist in
*.*)
    ;;
*)
    dist=$dist.whatever
    ;;
esac

# tell them what we think they are doing... !DIST!
case $dist in
world.*|comp.*|news.*|sci.*|rec.*|misc.*|soc.*|talk.*|alt.*)
    $cat <<'EOM'
This program posts news to thousands of machines throughout the entire
civilized world.  Your message will cost the net hundreds if not thousands of
dollars to send everywhere.  Please be sure you know what you are doing.

EOM
    ;;
vmsnet.*)
    $echo 'This program posts news to many machines.'
    ;;
bit.*)
    $echo 'This program posts news to many machines on BITNET.'
    ;;
ddn.*)
    $echo 'This program posts news to many machines throughout the internet.'
    ;;
$cont.*)
    $echo 'This program posts news to many machines throughout the continent.'
    ;;
$cntry.*)
    $echo 'This program posts news to many machines throughout the country.'
    ;;
$state.*)
    $echo 'This program posts news to many machines throughout the state.'
    ;;
$city.*)
    $echo 'This program posts news to many machines throughout the city.'
    ;;
$org.*)
    $echo 'This program posts news to machines throughout the organization.'
    ;;
$loc.*)
    $echo 'This program posts news to machines throughout the local organization.'
    ;;
*.*)
    $echo 'This program may post news to many machines.'
    ;;
to.*)
    $echo 'This program may post news to a particular machine.'
    ;;
*)
    $echo 'This program posts news to everyone on the machine.'
    ;;
esac
ans=""
while $test "$ans" = "" ; do
    $echo $n "Are you absolutely sure that you want to do this? [ny] $c"
    read ans
    case $ans in
    y*) ;;
    f*) ;;
    h*) $cat <<'EOH'

Type n or CR to exit, y to post.

EOH
	ans="" ;;
    *) exit ;;
    esac
done

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 article, 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 article.
EOH
	;;
    '')
	$echo "" >> $tmpart
	state=edit
	;;
    *)
	$cat $file >>$tmpart
	state=ask
	;;
    esac
done

$echo ""

while true ; do
    case $state in
    edit)
	case $expertise in
	beginner)
	    $cat </dev/null >$dotdir/.pnewsexpert
	    $cat <<'EOMessage'
A temporary file has been created for you to edit.  Be sure to leave at
least one blank line between the header and the body of your message.
(And until a certain bug is fixed all over the net, don't start the body of
your message with any indentation, or it may get eaten.)

Within the header may be fields that you don't understand.  If you don't
understand a field (or even if you do), you can simply leave it blank, and
it will go away when the article is posted.

Type return to get the default editor, or type the name of your favorite
editor.

EOMessage
	    ;;
	esac
	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
	trap : 2
	${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 article, a to abort and append the article to dead.article,
e to edit the article again, or l to list the article.

To invoke an alternate editor, type 'e editor'.
EOH
	esac
	;;
    
    send)
	set X `$sed < $tmpart -n -e '/^Newsgroups: /{' -e p -e q -e '}'`
	shift
	case $# in
	2)
	    state=cleanup
	    if $test -f $lib/moderators; then
		tryinews=no
		shift
		case "$1" in
		*,*) set `$echo $1 | tr ',' ' '`;;
		esac
		for newsgroup in $*; do
# the following screwy sed should prevent Eunice from hanging on no match
		    moderator=`$sed <$lib/moderators \
		    -e "/^$newsgroup[ 	]/!s/.*//" \
		    -e "s/^$newsgroup[ 	]//"`
		    case ${moderator}X in
		    X)  tryinews=yes
			;;
		    *)
			$echo Mailing to moderator $moderator
			case "$sign" in
			n*) ;;
			*)
			    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
			    sign=no
			    ;;
			esac
			case "$mailer" in
			*recmail)
			    $echo To: $moderator | $cat - $tmpart | $mailer
			    ;;
			*)
			    $mailer $moderator < $tmpart
			    ;;
			esac
			case $? in
			0) ;;
			*)
			    $echo Unable to mail to moderator $moderator
			    state=rescue
			    ;;
			esac
			;;
		    esac
		done
	    else
		tryinews=yes
	    fi
	    case "$tryinews" in
	    yes)
		if $sed '1,/^[	 ]*$/{/^[A-Z][-A-Za-z0-9]*:[	 ]*$/d;}' $tmpart |
			$inews -h ; then
		    : null
		else
		    state=rescue
		fi
		;;
	    esac
	    ;;
	*)
	    $echo ""
	    $echo "Malformed Newsgroups line."
	    $echo ""
	    sleep 1
	    state=edit
	    ;;
	esac
	;;
    rescue)
	if $test -s $tmpart; then
		$cat $tmpart >> ${HOME-$LOGDIR}/dead.article
		$echo "Article appended to ${HOME-$LOGDIR}/dead.article"
		$echo "A copy may be temporarily found in $tmpart"
	else
		$echo "Null article discarded."
	fi
	exit
	;;
    cleanup)
	case "${AUTHORCOPY-none}" in
	none)
	    ;;
	*)
	    set X ${USER-${LOGNAME-`who am i`}} unknown
	    shift
	    $rnlib/mbox.saver $tmpart "." "." 0 0 Pnews $AUTHORCOPY "From $1 `date`"
	    if $test $? -eq 0 ; then
		$echo "Article appended to $AUTHORCOPY"
	    else
		$echo "Cannot append to $AUTHORCOPY"
	    fi
	    ;;
	esac
	exit
	;;
    esac
done
!NO!SUBS!
$eunicefix Pnews
chmod 755 Pnews
$spitshell >Pnews.header <<'!NO!SUBS!'
case $# in
0)
    ng=h
    while $test "$ng" = h ; do
	$echo ""
	$echo $n "Newsgroup(s): $c"
	read ng
	case $ng in
	h)
	    $cat <<'EOH'

Type the name of one or more newsgroups to which you wish to post an article.
If you want to post to multiple newsgroups, it is better to do them all at
once than to post to each newsgroup individually, which defeats the news
reading programs' strategies of eliminating duplicates.

Separate multiple newsgroup names with commas.
EOH
	    ;;
	esac
    done
    ;;
*)
    ng=$1
    shift
    ;;
esac
case $ng in
*\ *)
    ng=`$echo "$ng" | $sed 's/[, ] */,/g'`
    ;;
esac
case $ng in
bit.*|pubnet.*|bionet.*|vmsnet.*|comp.*|news.*|sci.*|rec.*|misc.*|soc.*|talk.*|alt.*)
    defdist=world
    dist=h
    ;;
ddn.*)
    defdist=inet
    dist=h
    ;;
to.*)
    defdist=''
    dist=''
    ;;
*.*)
    defdist=`expr "X$ng" : 'X\([a-z0-9]*\)'`
    dist=h
    ;;
*)
    defdist=''
    dist=''
    ;;
esac

while $test "$dist" = h ; do
    if $test -f $lib/distributions; then
	$echo " "
	$echo "Your local distribution prefixes are:"
	$cat $lib/distributions
	$echo " "
    else
	$egrep -v '[	 ]none$' <<EOM

Your local distribution prefixes are:
    Local organization:	$loc
    Organization:	$org
    City:		$city
    $stpr:  		$state
    Country:		$cntry
    Continent:		$cont
    Everywhere:		world

EOM
    fi
    $echo $n "Distribution ($defdist): $c"
    read dist
    case $dist in
    '') dist=$defdist ;;
    esac
    case $dist in
    h)
	$cat <<'EOH'

The Distribution line may be used to limit the distribution of an article
to some subset of the systems that would receive the article based only on
the Newsgroups line.  For example, if you want to sell your car in talk.auto,
and you live in New Jersey, you might want to put "nj" on the Distribution
line to avoid advertising in California, which has enough problems of its own.
The actual area designators to use depend on where you are, of course.
EOH
	;;
    ''|$loc*|$org*|$city*|$state*|$cntry*|$cont*|$defdist)
	;;
    world*|comp*|news*|sci*|rec*|misc*|soc*|talk*|alt*)
	dist=''
	;;
    *)  
	if $test -f $lib/distributions && \
	  $egrep "^$dist[ 	]" $lib/distributions >$tmpart && \
	  $test -s $tmpart; then
	    : null
	else
	    $echo "Unrecognized distribution prefix--type h for help, CR to use anyway."
	    defdist=$dist
	    dist=h
	fi
	;;
    esac
done

follow=""

case $# in
0)
    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 article.  Please make it as informative as possible
(within reason) so that people who aren't interested won't have to read the
article to find out they aren't interested.  This includes marking movie
spoilers as (spoiler), and rotated jokes as (rot 13).
EOH
	;;
	esac
    done
    ;;
*)
    title="$*"
    ;;
esac

# now build a file with a header for them to edit

set X ${USER-${LOGNAME-`who am i`}}
shift
logname=$1
case $logname in
*!*) logname=`expr "$logname" : '!\(.*\)$'` ;;
esac
case ${NAME-$nametype} in
bsd)
	if $test "$ypmatch" != ""; then
		fullname=`$ypmatch $logname passwd 2>/dev/null | $sed -e "s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/"`
	elif $test "$nidump" != ""; then
		fullname=`$nidump passwd / | $sed -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
	fi
     if $test "$fullname" = ""; then
		fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
	fi
    case $fullname in
    *'&'*) : GACK
	lname=`$echo $logname | $tr 'a-z' 'A-Z'`
	lname=`$echo $lname $logname | $sed 's/^\(.\)[^ ]* ./\1/'`
	fullname=`$echo "$fullname" | $sed "s/&/${lname}/"`
	;;
    esac
    ;;
usg)
	if $test "$ypmatch" != ""; then
		fullname=`$ypmatch $logname passwd 2>/dev/null | $sed -e "s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q"`
	fi
     if $test "$fullname" = ""; then
    fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q" -e "}" -e "d"`
	fi
    ;;
*)
    fullname=${NAME-`$cat $dotdir/.fullname`}
    ;;
esac

orgname=${NEWSORG-${ORGANIZATION-$orgname}}
case $orgname in
/*) orgname=`$cat $orgname` ;;
esac

$sed -e '/^Reply-To: $/d' > $tmpart <<EOHeader
Newsgroups: $ng
Subject: $title
Summary: 
Reply-To: $REPLYTO
Followup-To: $follow
Distribution: $dist
Organization: $orgname
Keywords: 

EOHeader

!NO!SUBS!
case "$isrrn" in
define) sed < Pnews.header -e '/^#NORMAL/d' > Pnews.h.new ;;
*)  sed < Pnews.header -e '/^#NORMAL/s/^#NORMAL//' > Pnews.h.new ;;
esac
mv Pnews.h.new Pnews.header
$eunicefix Pnews.header
!STUFFY!FUNK!
echo Extracting bits.c
cat >bits.c <<'!STUFFY!FUNK!'
/* $Id: bits.c,v 4.4 1991/09/09 20:18:23 sob Exp sob $
 *
 * $Log: bits.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 "rcstuff.h"
#include "head.h"
#include "util.h"
#include "final.h"
#include "rn.h"
#include "cheat.h"
#include "ng.h"
#include "artio.h"
#include "intrp.h"
#include "ngdata.h"
#include "rcln.h"
#include "kfile.h"
#include "INTERN.h"
#include "bits.h"

#ifdef DBM
#    ifdef NULL
#	undef NULL
#    endif
#    include <dbm.h>
#endif
MEM_SIZE ctlsize;			/* size of bitmap in bytes */

void
bits_init()
{
#ifdef DELAYMARK
    dmname = savestr(filexp(RNDELNAME));
#else
    ;
#endif
}

/* checkpoint the .newsrc */

void
checkpoint_rc()
{
#ifdef DEBUGGING
    if (debug & DEB_CHECKPOINTING) {
	fputs("(ckpt)",stdout);
	fflush(stdout);
    }
#endif
    if (doing_ng)
	restore_ng();			/* do not restore M articles */
    if (rc_changed)
	write_rc();
#ifdef DEBUGGING
    if (debug & DEB_CHECKPOINTING) {
	fputs("(done)",stdout);
	fflush(stdout);
    }
#endif
}

/* reconstruct the .newsrc line in a human readable form */

void
restore_ng()
{
    register char *s, *mybuf = buf;
    register ART_NUM i;
    ART_NUM count=0;
    int safelen = LBUFLEN - 16;

    strcpy(buf,rcline[ng]);		/* start with the newsgroup name */
    s = buf + rcnums[ng] - 1;		/* use s for buffer pointer */
    *s++ = rcchar[ng];			/* put the requisite : or !*/
    *s++ = ' ';				/* put the not-so-requisite space */
    for (i=1; i<=lastart; i++) {	/* for each article in newsgroup */
	if (s-mybuf > safelen) {	/* running out of room? */
	    safelen *= 2;
	    if (mybuf == buf) {		/* currently static? */
		*s = '\0';
		mybuf = safemalloc((MEM_SIZE)safelen + 16);
		strcpy(mybuf,buf);	/* so we must copy it */
		s = mybuf + (s-buf);
					/* fix the pointer, too */
	    }
	    else {			/* just grow in place, if possible */
		char *newbuf;

		newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
		s = newbuf + (s-mybuf);
		mybuf = newbuf;
	    }
	}
	if (!was_read(i))		/* still unread? */
	    count++;			/* then count it */
	else {				/* article was read */
	    ART_NUM oldi;

	    sprintf(s,"%ld",(long)i);	/* put out the min of the range */
	    s += strlen(s);		/* keeping house */
	    oldi = i;			/* remember this spot */
	    do i++; while (i <= lastart && was_read(i));
					/* find 1st unread article or end */
	    i--;			/* backup to last read article */
	    if (i > oldi) {		/* range of more than 1? */
		sprintf(s,"-%ld,",(long)i);
					/* then it out as a range */
		s += strlen(s);		/* and housekeep */
	    }
	    else
		*s++ = ',';		/* otherwise, just a comma will do */
	}
    }
    if (*(s-1) == ',')			/* is there a final ','? */
	s--;				/* take it back */
    *s++ = '\0';			/* and terminate string */
#ifdef DEBUGGING
    if (debug & DEB_NEWSRC_LINE && !panic) {
	printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]) FLUSH;
	printf("%s\n",mybuf) FLUSH;
    }
#endif
    free(rcline[ng]);			/* return old rc line */
    if (mybuf == buf) {
	rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
					/* grab a new rc line */
	strcpy(rcline[ng], buf);	/* and load it */
    }
    else {
	mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
					/* be nice to the heap */
	rcline[ng] = mybuf;
    }
    *(rcline[ng] + rcnums[ng] - 1) = '\0';
    if (rcchar[ng] == NEGCHAR) {	/* did they unsubscribe? */
	printf(unsubto,ngname) FLUSH;
	toread[ng] = TR_UNSUB;		/* make line invisible */
    }
    else
	/*NOSTRICT*/
	toread[ng] = (ART_UNREAD)count;		/* remember how many unread there are */
}

/* mark an article unread, keeping track of toread[] */

void
onemore(artnum)
ART_NUM artnum;
{
#ifdef DEBUGGING
    if (debug && artnum < firstbit) {
	printf("onemore: %d < %d\n",artnum,firstbit) FLUSH;
	return;
    }
#endif
    if (ctl_read(artnum)) {
	ctl_clear(artnum);
	++toread[ng];
    }
}

/* mark an article read, keeping track of toread[] */

void
oneless(artnum)
ART_NUM artnum;
{
#ifdef DEBUGGING
    if (debug && artnum < firstbit) {
	printf("oneless: %d < %d\n",artnum,firstbit) FLUSH;
	return;
    }
#endif
    if (!ctl_read(artnum)) {
	ctl_set(artnum);
	if (toread[ng] > TR_NONE)
	    --toread[ng];
    }
}

/* mark an article as unread, making sure that firstbit is properly handled */
/* cross-references are left as read in the other newsgroups */

void
unmark_as_read()
{
    check_first(art);
    onemore(art);
#ifdef MCHASE
    if (!parse_maybe(art))
	chase_xrefs(art,FALSE);
#endif
}

#ifdef DELAYMARK
/* temporarily mark article as read.  When newsgroup is exited, articles */
/* will be marked as unread.  Called via M command */

void
delay_unmark(artnum)
ART_NUM artnum;
{
    if (dmfp == Nullfp) {
	dmfp = fopen(dmname,"w+");
	if (dmfp == Nullfp) {
	    printf(cantcreate,dmname) FLUSH;
	    sig_catcher(0);
	}
    }
    oneless(artnum);			/* set the correct bit */
    dmcount++;
    fprintf(dmfp,"%ld\n",(long)artnum);
}
#endif

/* mark article as read.  If article is cross referenced to other */
/* newsgroups, mark them read there also. */

void
mark_as_read()
{
    oneless(art);			/* set the correct bit */
    checkcount++;			/* get more worried about crashes */
    chase_xrefs(art,TRUE);
}

/* make sure we have bits set correctly down to firstbit */

void
check_first(min)
ART_NUM min;
{
    register ART_NUM i = firstbit;

    if (min < absfirst)
	min = absfirst;
    if (min < i) {
	for (i--; i>=min; i--)
	    ctl_set(i);		/* mark as read */
	firstart = firstbit = min;
    }
}

/* bring back articles marked with M */

#ifdef DELAYMARK
void
yankback()
{
    if (dmfp) {			/* delayed unmarks pending? */
#ifdef VERBOSE
	printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
	    dmcount == 1 ? nullstr : "s") FLUSH;
#endif
	rewind(dmfp);
	while (fgets(buf,sizeof buf,dmfp) != Nullch) {
	    art = (ART_NUM)atol(buf);
	    unmark_as_read();
	}
	fclose(dmfp);
	dmfp = Nullfp;
	UNLINK(dmname);		/* and be tidy */
    }
    dmcount = 0;
}
#endif
    
/* run down xref list and mark as read or unread */

int
chase_xrefs(artnum,markread)
ART_NUM artnum;
int markread;
{
#ifdef ASYNC_PARSE
    if (parse_maybe(artnum))		/* make sure we have right header */
	return -1;
#endif
#ifdef DBM
    {
	datum lhs, rhs;
	datum fetch();
	register char *idp;
	char *ident_buf;
	static FILE * hist_file = Nullfp;
#else
    if (
#ifdef DEBUGGING
	debug & DEB_FEED_XREF ||
#endif
	htype[XREF_LINE].ht_minpos >= 0) {
					/* are there article# xrefs? */
#endif /* DBM */
	char *xref_buf, *curxref;
	register char *xartnum;
	char *rver_buf = Nullch;
	static char *inews_site = Nullch;
	register ART_NUM x;
	char tmpbuf[128];
#ifdef DBM
	long pos;
	rver_buf = fetchlines(artnum,NGS_LINE);
					/* get Newsgroups */
#ifdef XREF_WITH_COMMAS
	if (!index(rver_buf,','))	/* if no comma, no Xref! */
	    return 0;
#endif
	if (hist_file == Nullfp) {	/* Init. file accesses */
#ifdef DEBUGGING
	    if (debug)
		printf ("chase_xref: opening files\n");
#endif
	    dbminit(filexp(ARTFILE));
	    if ((hist_file = fopen (filexp(ARTFILE), "r")) == Nullfp)
		return 0;
	}
	xref_buf = safemalloc((MEM_SIZE)BUFSIZ);
	ident_buf = fetchlines(artnum,MESSID_LINE);
					/* get Message-ID */
#ifdef DEBUGGING
	if (debug)
	    printf ("chase_xref: Message-ID: %s\n", ident_buf);
#endif
	idp = ident_buf;
	while (*++idp)			/* make message-id case insensitive */
	    if (isupper(*idp))
	        *idp = tolower (*idp);
	lhs.dptr = ident_buf;		/* look up article by id */
	lhs.dsize = strlen(lhs.dptr) + 1;
	rhs = fetch(lhs);		/* fetch the record */
	if (rhs.dptr == NULL)		/* if null, nothing there */
	    goto wild_goose;
	bcopy((void *)rhs.dptr,(void *)&pos, 4);
	fseek (hist_file, pos, 0);
				/* datum returned is position in hist file */
	fgets (xref_buf, BUFSIZ, hist_file);
#ifdef DEBUGGING
	if (debug)
	    printf ("Xref from history: %s\n", xref_buf);
#endif
	curxref = cpytill(tmpbuf, xref_buf, '\t') + 1;
	curxref = cpytill(tmpbuf, curxref, '\t') + 1;
#ifdef DEBUGGING
	if (debug)
	    printf ("chase_xref: curxref: %s\n", curxref);
#endif
#else /* !DBM */
#ifdef DEBUGGING
	if (htype[XREF_LINE].ht_minpos >= 0)
#endif
	    xref_buf = fetchlines(artnum,XREF_LINE);
					/* get xrefs list */
#ifdef DEBUGGING
	else {
	    xref_buf = safemalloc((MEM_SIZE)100);
	    printf("Give Xref: ") FLUSH;
	    gets(xref_buf);
	}
#endif
#ifdef DEBUGGING
	if (debug & DEB_XREF_MARKER)
	    printf("Xref: %s\n",xref_buf) FLUSH;
#endif
	curxref = cpytill(tmpbuf,xref_buf,' ') + 1;

	/* Make sure site name on Xref matches what inews thinks site is.
	 * Check first against last inews_site.  If it matches, fine.
	 * If not, fetch inews_site from current Relay-Version line and
	 * check again.  This is so that if the new administrator decides
	 * to change the system name as known to inews, rn will still do
	 * Xrefs correctly--each article need only match itself to be valid.
	 */ 
	if (inews_site == Nullch || strNE(tmpbuf,inews_site)) {
#ifndef NORELAY
	    char *t;
#endif
	    if (inews_site != Nullch)
		free(inews_site);
#ifndef NORELAY
	    rver_buf = fetchlines(artnum,RVER_LINE);
	    if ((t = instr(rver_buf,"; site "), TRUE) == Nullch)
#else /* NORELAY */
          /* In version 2.10.3 of news or afterwards, the Relay-Version
           * and Posting-Version header lines have been removed.  For
           * the code below to work as intended, I have modified it to
           * extract the first component of the Path header line.  This
           * should give the same effect as did the old code with respect
           * to the use of the Relay-Version site name.
           */
          rver_buf = fetchlines(artnum,PATH_LINE);
          if (instr(rver_buf,"!", TRUE) == Nullch)
#endif /* NORELAY */
		inews_site = savestr(nullstr);
	    else {
		char new_site[128];

#ifndef NORELAY
		cpytill(new_site,t + 7,'.');
#else /* NORELAY */
              cpytill(new_site,rver_buf,'!');
#endif /* NORELAY */
		inews_site = savestr(new_site);
	    }
	    if (strNE(tmpbuf,inews_site)) {
#ifdef DEBUGGING
		if (debug)
		    printf("Xref not from %s--ignoring\n",inews_site) FLUSH;
#endif
		goto wild_goose;
	    }
	}
#endif /* DBM */
	while (*curxref) {
					/* for each newsgroup */
	    curxref = cpytill(tmpbuf,curxref,' ');
#ifdef DBM
	    xartnum = index(tmpbuf,'/');
#else
	    xartnum = index(tmpbuf,':');
#endif /* DBM */
	    if (!xartnum)		/* probably an old-style Xref */
		break;
	    *xartnum++ = '\0';
	    if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
		x = atol(xartnum);
		if (x)
		    if (markread) {
			if (addartnum(x,tmpbuf))
			    goto wild_goose;
		    }
#ifdef MCHASE
		    else
			subartnum(x,tmpbuf);
#endif
	    }
	    while (*curxref && isspace(*curxref))
		curxref++;
	}
      wild_goose:
	free(xref_buf);
#ifdef DBM
	free(ident_buf);
#endif /* DBM */
	if (rver_buf != Nullch)
	    free(rver_buf);
    }
    return 0;
}

int
initctl()
{
    char *mybuf = buf;			/* place to decode rc line */
    register char *s, *c, *h;
    register long i;
    register ART_NUM unread;
    
#ifdef DELAYMARK
    dmcount = 0;
#endif
    if ((lastart = getngsize(ng)) < 0)	/* this cannot happen (laugh here) */
	return -1;

    absfirst = getabsfirst(ng,lastart);	/* remember first existing article */
    if (!absfirst)			/* no articles at all? */
	absfirst = 1;			/* pretend there is one */
#ifndef lint
    ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
#endif /* lint */
    ctlarea = safemalloc(ctlsize);	/* allocate control area */

    /* now modify ctlarea to reflect what has already been read */

    for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
					/* find numbers in rc line */
    i = strlen(s);
#ifndef lint
    if (i >= LBUFLEN-2)			/* bigger than buf? */
	mybuf = safemalloc((MEM_SIZE)(i+2));
#endif /* lint */
    strcpy(mybuf,s);			/* make scratch copy of line */
    mybuf[i++] = ',';			/* put extra comma on the end */
    mybuf[i] = '\0';
    s = mybuf;				/* initialize the for loop below */
    if (strnEQ(s,"1-",2)) {		/* can we save some time here? */
	firstbit = atol(s+2)+1;		/* ignore first range thusly */
	s=index(s,',') + 1;
    }
    else
	firstbit = 1;			/* all the bits are valid for now */
    if (absfirst > firstbit) {		/* do we know already? */
	firstbit = absfirst;		/* no point calling getngmin again */
    }
    else if (artopen(firstbit) == Nullfp) {
					/* first unread article missing? */
	i = getngmin(".",firstbit);	/* see if expire has been busy */
	if (i) {			/* avoid a bunch of extra opens */
	    firstbit = i;
	}
    }
    firstart = firstbit;		/* firstart > firstbit in KILL */
#ifdef PENDING
#   ifdef CACHESUBJ
	subj_to_get = firstbit;
#   endif
#endif
    unread = lastart - firstbit + 1;	/* assume this range unread */
    for (i=OFFSET(firstbit)/BITSPERBYTE; i<ctlsize; i++)
	ctlarea[i] = 0;			/* assume unread */
#ifdef DEBUGGING
    if (debug & DEB_CTLAREA_BITMAP) {
	printf("\n%s\n",mybuf) FLUSH;
	for (i=1; i <= lastart; i++)
	    if (! was_read(i))
		printf("%ld ",(long)i) FLUSH;
    }
#endif
    for ( ; (c = index(s,',')) != Nullch; s = ++c) {
					/* for each range */
	ART_NUM min, max;

	*c = '\0';			/* do not let index see past comma */
	if ((h = index(s,'-')) != Nullch) {	/* is there a -? */
	    min = atol(s);
	    max = atol(h+1);
	    if (min < firstbit)		/* make sure range is in range */
		min = firstbit;
	    if (max > lastart)
		max = lastart;
	    if (min <= max)		/* non-null range? */
		unread -= max - min + 1;/* adjust unread count */
	    for (i=min; i<=max; i++)	/* for all articles in range */
		ctl_set(i);		/* mark them read */
	}
	else if ((i = atol(s)) >= firstbit && i <= lastart) {
					/* is single number reasonable? */
	    ctl_set(i);			/* mark it read */
	    unread--;			/* decrement articles to read */
	}
#ifdef DEBUGGING
	if (debug & DEB_CTLAREA_BITMAP) {
	    printf("\n%s\n",s) FLUSH;
	    for (i=1; i <= lastart; i++)
		if (! was_read(i))
		    printf("%ld ",(long)i) FLUSH;
	}
#endif
    }
#ifdef DEBUGGING
    if (debug & DEB_CTLAREA_BITMAP) {
	fputs("\n(hit CR)",stdout) FLUSH;
	gets(cmd_buf);
    }
#endif
    if (mybuf != buf)
	free(mybuf);
    toread[ng] = unread;
    return 0;
}

void
grow_ctl(newlast)
ART_NUM newlast;
{
    ART_NUM tmpfirst;
    MEM_SIZE newsize;
    register ART_NUM i;

    forcegrow = FALSE;
    if (newlast > lastart) {
	ART_NUM tmpart = art;
#ifndef lint
	newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
#else
	newsize = Null(MEM_SIZE);
#endif /* lint */
	if (newsize > ctlsize) {
	    newsize += 20;
	    ctlarea = saferealloc(ctlarea,newsize);
	    ctlsize = newsize;
	}
	toread[ng] += (ART_UNREAD)(newlast-lastart);
	for (i=lastart+1; i<=newlast; i++)
	    ctl_clear(i);	/* these articles are unread */
#ifdef CACHESUBJ
	if (subj_list != Null(char**)) {
#ifndef lint
	    subj_list = (char**)saferealloc((char*)subj_list,
		  (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
#endif /* lint */
	    for (i=lastart+1; i<=newlast; i++)
		subj_list[OFFSET(i)] = Nullch;
	}
#endif
	tmpfirst = lastart+1;
	lastart = newlast;
#ifdef KILLFILES
#ifdef VERBOSE
	IF(verbose)
	    sprintf(buf,
		"%ld more article%s arrived--looking for more to kill...\n\n",
		(long)(lastart - tmpfirst + 1),
		(lastart > tmpfirst ? "s have" : " has" ) );
	ELSE			/* my, my, how clever we are */
#endif
#ifdef TERSE
	    strcpy(buf, "More news--killing...\n\n");
#endif
	kill_unwanted(tmpfirst,buf,TRUE);
#endif
	art = tmpart;
    }
}

!STUFFY!FUNK!
echo Extracting help.c
sed >help.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Id: help.c,v 4.4 1991/09/09 20:18:23 sob Exp sob $
X *
X * $Log: help.c,v $
X * Revision 4.4  1991/09/09  20:18:23  sob
X * release 4.4
X *
X *
X * 
X */
X/* This software is Copyright 1991 by Stan Barber. 
X *
X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
X * use this software as long as: there is no monetary profit gained
X * specifically from the use or reproduction of this software, it is not
X * sold, rented, traded or otherwise marketed, and this copyright notice is
X * included prominently in any copy made. 
X *
X * The author make no claims as to the fitness or correctness of this software
X * for any use whatsoever, and it is provided as is. Any use of this software
X * is at the user's own risk. 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "rn.h"
X#include "term.h"
X#include "INTERN.h"
X#include "help.h"
X
Xvoid
Xhelp_init()
X{
X    ;
X}
X
Xint
Xhelp_page()
X{
X    int cmd;
X
X#ifdef PAGERHELP
X    doshell(sh,filexp(PAGERHELP));
X#else
X    page_init();
X    if ((cmd = print_lines("\
XPaging commands:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\n\
XSP	Display the next page.\n\
Xx	Display the next page decrypted (rot13).\n\
Xd	Display half a page more.\n\
XCR	Display one more line.\n\
X^R,v,^X	Restart the current article (v=verbose header, ^X=rot13).\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xb	Back up one page.\n\
X^L,X	Refresh the screen (X=rot13).\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xg pat	Go to (search forward within article for) pattern.\n\
XG	Search again for current pattern within article.\n\
X^G	Search for next line beginning with \"Subject:\".\n\
XTAB	Search for next line beginning with a different character.\n\
Xq	Quit the pager, go to end of article.  Leave article read or unread.\n\
Xj	Junk this article (mark it read).  Goes to end of article.\n\
X\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XThe following commands skip the rest of the current article, then behave\n\
Xjust as if typed to the 'What next?' prompt at the end of the article:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\n\
Xn	Scan forward for next unread article.\n\
XN	Go to next article.\n\
X^N	Scan forward for next unread article with same title.\n\
Xp,P,^P	Same as n,N,^N, only going backwards.\n\
X-	Go to previously displayed article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XThe following commands also take you to the end of the article.\n\
XType h at end of article for a description of these commands:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\
X	# $ & / = ? c C f F k K ^K m M number e r R ^R s S u v w W Y ^ |\n\
X\n\
X(To return to the middle of the article after one of these commands, type ^L.)\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X    return 0;
X}
X
Xint
Xhelp_art()
X{
X    int cmd;
X#ifdef ARTHELP
X    doshell(sh,filexp(ARTHELP));
X#else
X    page_init();
X    if ((cmd = print_lines("\
XArticle Selection commands:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\n\
Xn,SP	Scan forward for next unread article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XN	Go to next article.\n\
X^N	Scan forward for next unread article with same subject.\n\
Xp,P,^P	Same as n,N,^N, only going backwards.\n\
X-	Go to previously displayed article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xnumber	Go to specified article.\n\
Xrange{,range}:command{:command}\n\
X	Apply one or more commands to one or more ranges of articles.\n\
X	Ranges are of the form: number | number-number.  You may use . for\n\
X	the current article, and $ for the last article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X 	Valid commands are: e, j, m, M, s, S, and |.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X/pattern/modifiers\n\
X	Scan forward for article containing pattern in the subject line.\n\
X	(Use ?pat? to scan backwards; append h to scan headers, a to scan\n\
X	entire articles, r to scan read articles, c to make case sensitive.)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X/pattern/modifiers:command{:command}\n\
X	Apply one or more commands to the set of articles matching pattern.\n\
X	Use a K modifier to save entire command to the KILL file for this\n\
X	newsgroup.  Commands m and M, if first, imply an r modifier.\n\
X 	Valid commands are the same as for the range command.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xf,F	Submit a followup article (F = include this article).\n\
Xr,R	Reply through net mail (R = include this article).\n\
Xe dir{|command}\n\
X	Extract to directory using /bin/sh, uudecode, or specified command.\n\
Xs ...	Save to file or pipe via sh.\n\
XS ...	Save via preferred shell.\n\
Xw,W	Like s and S but save without the header.\n\
X| ...	Same as s|...\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XC	Cancel this article, if yours.\n\
X^R,v	Restart article (v=verbose).\n\
X^X	Restart article, rot13 mode.\n\
Xc	Catch up (mark all articles as read).\n\
Xb	Back up one page.\n\
X^L	Refresh the screen.  You can get back to the pager with this.\n\
XX	Refresh screen in rot13 mode.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X^	Go to first unread article.  Disables subject search mode.\n\
X$	Go to end of newsgroup.  Disables subject search mode.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("#       Print last article number.\n\
X&	Print current values of command-line switches.\n\
X&switch {switch}\n\
X	Set or unset more switches.\n\
X&&	Print current macro definitions.\n\
X&&def	Define a new macro.\n\
Xj	Junk this article (mark it read).  Stays at end of article.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xm	Mark article as still unread.\n\
XM	Mark article as still unread upon exiting newsgroup or Y command.\n\
XY	Yank back articles marked temporarily read via M.\n\
Xk	Kill current subject (mark articles as read).\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XK	Mark current subject as read, and save command in KILL file.\n\
X^K	Edit local KILL file (the one for this newsgroup).\n\
X=	List subjects of unread articles.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xu	Unsubscribe from this newsgroup.\n\
Xq	Quit this newsgroup for now.\n\
XQ	Quit newsgroup, staying at current newsgroup.\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X    return 0;
X}
X
Xint
Xhelp_ng()
X{
X    int cmd;
X#ifdef NGHELP
X    doshell(sh,filexp(NGHELP));
X#else
X    page_init();
X    if (cmd = print_lines("\
XNewsgroup Selection commands:\n\
X",STANDOUT) )
X	return cmd;
X    if (ng != nextrcline) {
X	if ((cmd = print_lines("\
X\n\
Xy,SP	Do this newsgroup now.\n\
X.cmd	Do this newsgroup, executing cmd as first command.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X=	Start this newsgroup, but list subjects before reading articles.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xu	Unsubscribe from this newsgroup.\n\
X",NOMARKING)) )
X	    return cmd;
X    }
X    if ((cmd = print_lines("\
Xc	Catch up (mark this newsgroup all read).\n\
X\n\
Xn	Go to the next newsgroup with unread news.\n\
XN	Go to the next newsgroup.\n\
Xp	Go to the previous newsgroup with unread news.\n\
XP	Go to the previous newsgroup.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X-	Go to the previously displayed newsgroup.\n\
X1	Go to the first newsgroup.\n\
X^	Go to the first newsgroup with unread news.\n\
X$	Go to the last newsgroup.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xg name	Go to the named newsgroup.  Subscribe to new newsgroups this way too.\n\
X/pat	Search forward for newsgroup matching pattern.\n\
X?pat	Search backward for newsgroup matching pattern.\n\
X	(Use * and ? style patterns.  Append r to include read newsgroups.)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xl pat	List unsubscribed newsgroups containing pattern.\n\
Xm name	Move named newsgroup elsewhere (no name moves current newsgroup).\n\
Xo pat	Only display newsgroups matching pattern.  Omit pat to unrestrict.\n\
Xa pat	Like o, but also scans for unsubscribed newsgroups matching pattern.\n\
XL	List current .newsrc.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X&	Print current command-line switch settings.\n\
X&switch {switch}\n\
X	Set (or unset) more command-line switches.\n\
X&&	Print current macro definitions.\n\
X&&def	Define a new macro.\n\
X!cmd	Shell escape.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xq	Quit rn.\n\
Xx	Quit, restoring .newsrc to its state at startup of rn.\n\
X^K	Edit the global KILL file.  Use commands like /pattern/j to suppress\n\
X	pattern in every newsgroup.\n\
Xv	Print version.\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X#ifdef PUSHBACK
X    if (cmd = get_anything())
X	return cmd;
X    show_macros();
X#endif
X    return 0;
X}
X
X#ifdef ESCSUBS
Xint
Xhelp_subs()
X{
X    int cmd;
X#ifdef SUBSHELP
X    doshell(sh,filexp(SUBSHELP));
X#else
X    page_init();
X    if ((cmd = print_lines("\
XValid substitutions are:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\
X\n\
Xa	Current article number\n\
XA	Full name of current article (%P/%c/%a)\n\
Xb	Destination of last save command, often a mailbox\n\
XB	Bytes to ignore at beginning of last saved article\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xc	Current newsgroup, directory form\n\
XC	Current newsgroup, dot form\n\
Xd	Full name of newsgroup directory (%P/%c)\n\
XD	Distribution line from current article\n\
Xe	The last command executed to extract data from an article\n\
XE	The number of extra (unselected) articles, not counting the current\n\
X	one if it is unselected\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xf	Who the current article is from\n\
XF	Newsgroups to followup to (from Newsgroups and Followup-To)\n\
Xh	(This help message)\n\
XH	Host name (yours)\n\
Xi	Message-I.D. line from current article, with <>\n\
XI	Reference indicator mark (see -F switch)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xl	News administrator's login name, if any\n\
XL	Login name (yours)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xm	Current mode, first letter of (init, newsgroup, article, pager,\n\
X		Add, Catchup, Delete bogus, Mailbox, Resubscribe)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XM	Number of article marked with M\n\
Xn	Newsgroups from current article\n\
XN	Full name (yours)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xo	Organization (yours)\n\
XO	Original working directory (where you ran rn from)\n\
Xp	Your private news directory (from -d)\n\
XP	Public news spool directory\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xr	Last reference (parent article id)\n\
XR	References list for followup article\n\
Xs	Subject, with all Re's and (nf)'s stripped off\n\
XS	Subject, with one Re stripped off\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xt	New To line derived from From and Reply-To (Internet format)\n\
XT	New To line derived from Path\n\
Xu	Number of unread articles\n\
XU	Number of unread articles not counting the current article (when\n\
X	threads are selected, the count only reflects selected articles)\n\
Xx	News library directory\n\
XX	Rn library directory\n\
Xz	Length of current article in bytes\n\
XZ	Number of selected threads\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X~	Your home directory\n\
X.	Directory containing . files\n\
X#	A counter in multiple-article commands\n\
X$	Current process number\n\
X/	Last search string\n\
XESC	Run preceding command through % interpretation\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X    return 0;
X}
X#endif
X
!STUFFY!FUNK!
echo Extracting only.h
cat >only.h <<'!STUFFY!FUNK!'
/* $Id: only.h,v 4.4 1991/09/09 20:23:31 sob Exp sob $
 *
 * $Log: only.h,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. 
 */

#ifndef NBRA
#include "search.h"
#endif

#ifdef ONLY
    EXT char *ngtodo[NGMAX];		/* restrictions in effect */
#   ifdef SPEEDOVERMEM
	EXT COMPEX *compextodo[NGMAX];	/* restrictions in compiled form */
#   endif
#endif

EXT int maxngtodo INIT(0);			/*  0 => no restrictions */
					/* >0 => # of entries in ngtodo */

void	only_init ANSI((void));
bool	inlist ANSI((char *));	/* return TRUE if ngname is in command line list */
			/* or if there was no list */
void	setngtodo ANSI((char *));
#ifdef ONLY
    void	end_only ANSI((void));
#endif
!STUFFY!FUNK!
echo ""
echo "End of kit 6 (of 10)"
cat /dev/null >kit6isdone
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
