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

echo "This is rn kit 4 (of 11).  If kit 4 is complete, the line"
echo '"'"End of kit 4 (of 11)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting ng.c
cat >ng.c <<'!STUFFY!FUNK!'
/* $Id: ng.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
 *
 * $Log: ng.c,v $
 * Revision 4.4.3.1  1992/02/01  03:09:32  sob
 * Release 4.4 Patchlevel 3
 *
 * Revision 4.4  1991/09/09  20: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 "rn.h"
#include "term.h"
#include "final.h"
#include "util.h"
#include "artsrch.h"
#include "cheat.h"
#include "help.h"
#include "kfile.h"
#include "rcstuff.h"
#include "head.h"
#include "bits.h"
#include "art.h"
#include "artio.h"
#include "ngstuff.h"
#include "intrp.h"
#include "respond.h"
#include "ngdata.h"
#include "backpage.h"
#include "rcln.h"
#include "last.h"
#include "search.h"
#ifdef SERVER
#include "server.h"
#endif
#include "uudecode.h"
#include "INTERN.h"
#include "ng.h"
#include "artstate.h"			/* somebody has to do it */

/* art_switch() return values */

#define AS_NORM 0
#define AS_INP 1
#define AS_ASK 2
#define AS_CLEAN 3

ART_NUM recent_art = -1;	/* previous article # for '-' command */
ART_NUM curr_art = -1;		/* current article # */
int exit_code = NG_NORM;

void
ng_init()
{

#ifdef KILLFILES
    open_kfile(KF_GLOBAL);
#endif
#ifdef CUSTOMLINES
    init_compex(&hide_compex);
    init_compex(&page_compex);
#endif
}

/* do newsgroup on line ng with name ngname */

/* assumes that we are chdir'ed to SPOOL, and assures that that is
 * still true upon return, but chdirs to SPOOL/ngname in between
 *
 * If you can understand this routine, you understand most of the program.
 * The basic structure is:
 *	for each desired article
 *		for each desired page
 *			for each line on page
 *				if we need another line from file
 *					get it
 *					if it's a header line
 *						do special things
 *				for each column on page
 *					put out a character
 *				end loop
 *			end loop
 *		end loop
 *	end loop
 *
 *	(Actually, the pager is in another routine.)
 *
 * The chief problem is deciding what is meant by "desired".  Most of
 * the messiness of this routine is due to the fact that people want
 * to do unstructured things all the time.  I have used a few judicious
 * goto's where I thought it improved readability.  The rest of the messiness
 * arises from trying to be both space and time efficient.  Have fun.
 */

int
do_newsgroup(start_command)
char *start_command;			/* command to fake up first */
{
#ifdef SERVER
    char artname[MAXFILENAME];
    char intrpwork[MAXFILENAME];
    static long our_pid=0;
#endif /* SERVER */
    char oldmode = mode;
    register long i;			/* scratch */
    int skipstate;			/* how many unavailable articles */
					/*   have we skipped already? */
    
    char *whatnext = "%sWhat next? [%s]";

#ifdef SERVER
    if (our_pid == 0)           /* Agreed, this is gross */
        our_pid = getpid();
#endif /* SERVER */

#ifdef ARTSEARCH
    srchahead = (scanon && ((ART_NUM)toread[ng]) >= scanon ? -1 : 0);
					/* did they say -S? */
#endif
    
    mode = 'a';
    recent_art = curr_art = -1;
    exit_code = NG_NORM;

    if (extractdest) {
	free(extractdest);
	extractdest = Nullch;
    }
    if (extractprog) {
	free(extractprog);
	extractprog = Nullch;
    }

#ifdef SERVER
    sprintf(ser_line, "GROUP %s", ngname);
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf(">%s\n", ser_line) FLUSH;
#endif
    put_server(ser_line);
    if (nntp_get(ser_line, sizeof(ser_line)) < 0) {
	fprintf(stderr, "\nrrn: Unexpected close of server socket.\n");
	finalize(1);
    }
#ifdef DEBUGGING
    if (debug & DEB_NNTP)
	printf("<%s\n", ser_line) FLUSH;
#endif
    if (*ser_line != CHAR_OK) {
	if (atoi(ser_line) != ERR_NOGROUP){
		fprintf(stderr, "\nrrn: server response to GROUP %s:\n%s\n",
			ngname, ser_line);
		finalize(1);
	}
	return (-1);
    }
    {
	long first, last;

	(void) sscanf(ser_line,"%*d%*d%ld%ld",&first,&last);
	ngmax[ng] = last;	/* ensure getngsize() knows the new maximum */
# ifdef CACHEFIRST
	abs1st[ng] = first;
# endif
    }
#else /* not SERVER */
    if (eaccess(ngdir,5)) {		/* directory read protected? */
	if (eaccess(ngdir,0)) {
#ifdef VERBOSE
	    IF(verbose)
		printf("\nNewsgroup %s does not have a spool directory!\n",
		    ngname) FLUSH;
	    ELSE
#endif
#ifdef TERSE
		printf("\nNo spool for %s!\n",ngname) FLUSH;
#endif
#ifdef CATCHUP
	    catch_up(ng);
#else
	    toread[ng] = TR_NONE;
#endif
	}
	else {
#ifdef VERBOSE
	    IF(verbose)
		printf("\nNewsgroup %s is not currently accessible.\n",
		    ngname) FLUSH;
	    ELSE
#endif
#ifdef TERSE
		printf("\n%s not readable.\n",ngname) FLUSH;
#endif
	    toread[ng] = TR_NONE;	/* make this newsgroup invisible */
					/* (temporarily) */
	}
	mode = oldmode;
	return -1;
    }

    /* chdir to newsgroup subdirectory */

    if (chdir(ngdir)) {
	printf(nocd,ngdir) FLUSH;
	mode = oldmode;
	return -1;
    }
#endif /* SERVER */

#ifdef CACHESUBJ
    subj_list = Null(char **);		/* no subject list till needed */
#endif
    
    /* initialize control bitmap */

    if (initctl()) {
	mode = oldmode;
	return -1;
    }

    /* FROM HERE ON, RETURN THRU CLEANUP OR WE ARE SCREWED */

    in_ng = TRUE;			/* tell the world we are here */
    forcelast = TRUE;			/* if 0 unread, do not bomb out */

    /* remember what newsgroup we were in for sake of posterity */

    writelast();

    /* see if there are any special searches to do */

#ifdef KILLFILES
    open_kfile(KF_LOCAL);
#ifdef VERBOSE
    IF(verbose)
	kill_unwanted(firstart,"Looking for articles to kill...\n\n",TRUE);
    ELSE
#endif
#ifdef TERSE
	kill_unwanted(firstart,"Killing...\n\n",TRUE);
#endif
#endif
    art=firstart;
    
    /* do they want a special top line? */

    firstline = getval("FIRSTLINE",Nullch);

    /* custom line suppression, custom page ending */

#ifdef CUSTOMLINES
    if (hideline = getval("HIDELINE",Nullch))
	compile(&hide_compex,hideline,TRUE,TRUE);
    if (pagestop = getval("PAGESTOP",Nullch))
	compile(&page_compex,pagestop,TRUE,TRUE);
#endif

    /* now read each unread article */

    rc_changed = doing_ng = TRUE;	/* enter the twilight zone */
    skipstate = 0;			/* we have not skipped anything (yet) */
    checkcount = 0;			/* do not checkpoint for a while */
    do_fseek = FALSE;			/* start 1st article at top */
    if (art > lastart)
	art=firstart;			/* init the for loop below */
    for (; art<=lastart+1; ) {		/* for each article */

	/* do we need to "grow" the newsgroup? */

	if (art > lastart || forcegrow)
	    grow_ctl(getngsize(ng));
	check_first(art);		/* make sure firstart is still 1st */
	if (start_command) {		/* fake up an initial command? */
	    prompt = whatnext;
	    strcpy(buf,start_command);
	    free(start_command);
	    start_command = Nullch;
	    art = lastart+1;
	    goto article_level;
	}
	if (art>lastart) {		/* are we off the end still? */
	    ART_NUM ucount = 0;		/* count of unread articles left */

	    for (i=firstart; i<=lastart; i++)
		if (!(ctl_read(i)))
		    ucount++;		/* count the unread articles */
#ifdef DEBUGGING
	    /*NOSTRICT*/
	    if (debug && ((ART_NUM)toread[ng]) != ucount)
		printf("(toread=%ld sb %ld)",(long)toread[ng],(long)ucount)
		  FLUSH;
#endif
	    /*NOSTRICT*/
	    toread[ng] = (ART_UNREAD)ucount;	/* this is perhaps pointless */
	    art = lastart + 1;		/* keep bitmap references sane */
	    if (art != curr_art) {
		recent_art = curr_art;
					/* remember last article # (for '-') */
		curr_art = art;      /* remember this article # */
	    }
	    if (erase_screen)
		clear();			/* clear the screen */
	    else
		fputs("\n\n",stdout) FLUSH;
#ifdef VERBOSE
	    IF(verbose)
		printf("End of newsgroup %s.",ngname);
					/* print pseudo-article */
	    ELSE
#endif
#ifdef TERSE
		printf("End of %s",ngname);
#endif
	    if (ucount) {
		    printf("  (%ld article%s still unread)",
			(long)ucount,ucount==1?nullstr:"s");
	    }
	    else {
		if (!forcelast)
		    goto cleanup;	/* actually exit newsgroup */
	    }
	    prompt = whatnext;
#ifdef ARTSEARCH
	    srchahead = 0;		/* no more subject search mode */
#endif
	    fputs("\n\n",stdout) FLUSH;
	    skipstate = 0;		/* back to none skipped */
	}
	else if (!reread && was_read(art)) {
					/* has this article been read? */
	    art++;			/* then skip it */
	    continue;
	}
	else if
	  (!reread && !was_read(art)
#ifdef SERVER
	    && nntpopen(art,GET_HEADER) == Nullfp) { 
#else
	    && artopen(art) == Nullfp) { /* never read it, & cannot find it? */
	    if (errno != ENOENT) {	/* has it not been deleted? */
#ifdef VERBOSE
		IF(verbose)
		    printf("\n(Article %ld exists but is unreadable.)\n",
			(long)art) FLUSH;
		ELSE
#endif /* VERBOSE */
#ifdef TERSE
		    printf("\n(%ld unreadable.)\n",(long)art) FLUSH;
#endif /* TERSE */
		skipstate = 0;
		sleep(2);
	    }
#endif /* SERVER */
	    switch(skipstate++) {
	    case 0:
		clear();
#ifdef VERBOSE
		IF(verbose)
		    fputs("Skipping unavailable article",stdout);
		ELSE
#endif /* VERBOSE */
#ifdef TERSE
		    fputs("Skipping",stdout);
#endif /* TERSE */
		pad(just_a_sec/3);
		sleep(1);
		break;
	    case 1:
		fputs("..",stdout);
		fflush(stdout);
		break;
	    default:
		putchar('.');
		fflush(stdout);
#ifndef SERVER
#define READDIR
#ifdef READDIR
		{			/* fast skip patch */
		    ART_NUM newart;
		    
		    if (! (newart=getngmin(".",art)))
			newart = lastart+1;
		    for (i=art; i<newart; i++)
			oneless(i);
		    art = newart - 1;
		}
#endif /* READDIR */
#else
		{
			char	ser_line[NNTP_STRLEN];
			ART_NUM	newart;

			if (isfirstart) {
				sprintf(ser_line, "STAT %d",absfirst);
				put_server(ser_line);
				if (nntp_get(ser_line, sizeof(ser_line)) < 0) {
					fprintf(stderr, 
					"\nrrn: Unexpected close of server socket.\n");
					finalize(1);
				}
				newart=absfirst;
				isfirstart=FALSE;
			} 
			else {
				put_server("NEXT");
				if  (nntp_get(ser_line, sizeof(ser_line)) < 0) {
					fprintf(stderr,
					"\nrrn: unexpected close of server socket.\n");
					finalize(1);
				}
				if (ser_line[0] != CHAR_OK) {
					newart = lastart + 1;
				}
				else
					newart = atoi(ser_line+4);
			}				
			for (i=art; i<newart; i++)
				oneless(i);
			art = newart - 1;
		}
#endif /* SERVER */
		break;
	    }
	    oneless(art);		/* mark deleted as read */
	    art++;			/* try next article */
	    continue;
	}
	else {				/* we have a real live article */
	    skipstate = 0;		/* back to none skipped */
	    if (art != curr_art) {
		recent_art = curr_art;
					/* remember last article # (for '-') */
		curr_art = art;      /* remember this article # */
	    }
	    if (!do_fseek) {		/* starting at top of article? */
		artline = 0;		/* start at the beginning */
		topline = -1;		/* and remember top line of screen */
					/*  (line # within article file) */
	    }
	    clear();			/* clear screen */
	    if (!artopen(art)) {	/* make sure article is found & open */
		printf("Article %ld of %s is not available.\n\n",
		    (long)art,ngname) FLUSH;
		prompt = whatnext;
#ifdef ARTSEARCH
		srchahead = 0;
#endif
	    }
	    else {			/* found it, so print it */
		switch (do_article()) {
		case DA_CLEAN:		/* quit newsgroup */
		    goto cleanup;
		case DA_TOEND:		/* do not mark as read */
		    goto reask_article; 
		case DA_RAISE:		/* reparse command at end of art */
		    goto article_level;
		case DA_NORM:		/* normal end of article */
		    break;
		}
	    }
	    if (art >= absfirst)	/* don't mark non-existant articles */
		mark_as_read();		/* mark current article as read */
	    do_hiding = TRUE;
#ifdef ROTATION
	    rotate = FALSE;
#endif
	}

/* if these gotos bother you, think of this as a little state machine */

reask_article:
#ifdef MAILCALL
	setmail();
#endif
	setdfltcmd();
#ifdef CLEAREOL
	if (erase_screen && can_home_clear)
	    clear_rest();
#endif /* CLEAREOL */
	unflush_output();		/* disable any ^O in effect */
	standout();			/* enter standout mode */
	printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */
	un_standout();			/* leave standout mode */
	putchar(' ');
	fflush(stdout);
reinp_article:
	reread = FALSE;
	forcelast = FALSE;
	eat_typeahead();
#ifdef PENDING
	look_ahead();			/* see what we can do in advance */
	if (!input_pending())
	    collect_subjects();		/* loads subject cache until */
					/* input is pending */
#endif
	getcmd(buf);
	if (errno || *buf == '\f') {
	    if (LINES < 100 && !int_count)
		*buf = '\f';		/* on CONT fake up refresh */
	    else {
		putchar('\n') FLUSH;		/* but only on a crt */
		goto reask_article;
	    }
	}
article_level:

	/* parse and process article level command */

	switch (art_switch()) {
	case AS_INP:			/* multichar command rubbed out */
	    goto reinp_article;
	case AS_ASK:			/* reprompt "End of article..." */
	    goto reask_article;
	case AS_CLEAN:			/* exit newsgroup */
	    goto cleanup;
	case AS_NORM:			/* display article art */
	    break;
	}
    }					/* end of article selection loop */
    
/* shut down newsgroup */

cleanup:
    uud_end();
#ifdef KILLFILES
    kill_unwanted(firstart,"\nCleaning up...\n\n",FALSE);
					/* do cleanup from KILL file, if any */
#endif
    in_ng = FALSE;			/* leave newsgroup state */
    if (artfp != Nullfp) {		/* article still open? */
	fclose(artfp);			/* close it */
	artfp = Nullfp;			/* and tell the world */
#ifdef SERVER
        interp(intrpwork,MAXFILENAME-1, "%P");
        sprintf(artname, "%s/rrn%ld.%ld", intrpwork,(long) openart, our_pid);
        UNLINK(artname);
#endif /* SERVER */
	openart = 0;
    }
    putchar('\n') FLUSH;
#ifdef DELAYMARK
    yankback();				/* do a Y command */
#endif
    restore_ng();			/* reconstitute .newsrc line */
    doing_ng = FALSE;			/* tell sig_catcher to cool it */
    free(ctlarea);			/* return the control area */
#ifdef CACHESUBJ
    if (subj_list) {
	for (i=OFFSET(lastart); i>=0; --i)
	    if (subj_list[i])
		free(subj_list[i]);
#ifndef lint
	free((char*)subj_list);
#endif /* lint */
    }
#endif
    write_rc();				/* and update .newsrc */
    rc_changed = FALSE;			/* tell sig_catcher it is ok */
    if (chdir(spool)) {
	printf(nocd,spool) FLUSH;
	sig_catcher(0);
    }
#ifdef KILLFILES
    if (localkfp) {
	fclose(localkfp);
	localkfp = Nullfp;
    }
#endif
    mode = oldmode;
    return exit_code;
}					/* Whew! */

/* decide what to do at the end of an article */

int
art_switch()
{
    register ART_NUM i;
      
    setdef(buf,dfltcmd);
#ifdef VERIFY
    printcmd();
#endif

    switch (*buf) {
    case 'p':			/* find previous unread article */
	do {
	    if (art <= firstart)
		break;
	    art--;
#ifdef SERVER
	} while (was_read(art) || nntpopen(art,GET_HEADER) == Nullfp);
#else
	} while (was_read(art) || artopen(art) == Nullfp);
#endif
#ifdef ARTSEARCH
	srchahead = 0;
#endif
	return AS_NORM;
    case 'P':		/* goto previous article */
	if (art > absfirst)
	    art--;
	else {
#ifdef VERBOSE
	    IF(verbose)
		fprintf(stdout,"\n\
There are no%s articles prior to this one.\n\
",*buf=='P'?nullstr:" unread") FLUSH;
	    ELSE
#endif
#ifdef TERSE
		fprintf(stdout,"\n\
No previous%s articles\n\
",*buf=='P'?nullstr:" unread") FLUSH;
#endif
	    art = curr_art;
	    return AS_ASK;
	}
	reread = TRUE;
#ifdef ARTSEARCH
	srchahead = 0;
#endif
	return AS_NORM;
    case '-':
	if (recent_art >= 0) {
	    art = recent_art;
	    reread = TRUE;
	    forcelast = TRUE;
#ifdef ARTSEARCH
	    srchahead = -(srchahead != 0);
#endif
	    return AS_NORM;
	}
	else {
	    exit_code = NG_MINUS;
	    return AS_CLEAN;
	}
    case 'n':		/* find next unread article? */
	if (art > lastart) {
	    if (!toread[ng])
		return AS_CLEAN;
	    art = firstart;
	}
#ifdef ARTSEARCH
	else if (scanon && srchahead) {
	    *buf = Ctl('n');
	    goto normal_search;
	}
#endif
	else
	    art++;

#ifdef ARTSEARCH
	srchahead = 0;
#endif
	return AS_NORM;
    case 'N':			/* goto next article */
	if (art > lastart)
	    art = absfirst;
	else
	    art++;
	if (art <= lastart)
	    reread = TRUE;
#ifdef ARTSEARCH
	srchahead = 0;
#endif
	return AS_NORM;
    case '$':
	art = lastart+1;
	forcelast = TRUE;
#ifdef ARTSEARCH
	srchahead = 0;
#endif
	return AS_NORM;
    case '1': case '2': case '3':	/* goto specified article */
    case '4': case '5': case '6':	/* or do something with a range */
    case '7': case '8': case '9': case '.':
	forcelast = TRUE;
	switch (numnum()) {
	case NN_INP:
	    return AS_INP;
	case NN_ASK:
	    return AS_ASK;
	case NN_REREAD:
	    reread = TRUE;
#ifdef ARTSEARCH
	    if (srchahead)
		srchahead = -1;
#endif
	    break;
	case NN_NORM:
	    if (was_read(art)) {
		art = firstart;
		pad(just_a_sec/3);
	    }
	    else {
		putchar('\n');
		return AS_ASK;
	    }
	    break;
	}
	return AS_NORM;
    case Ctl('k'):
	edit_kfile();
	return AS_ASK;
    case 'K':
    case 'k':
    case Ctl('n'):	/* search for next article with same subject */
    case Ctl('p'):	/* search for previous article with same subject */
    case '/': case '?':
normal_search:
#ifdef ARTSEARCH
    {		/* search for article by pattern */
	char cmd = *buf;
	
	reread = TRUE;		/* assume this */
	page_line = 1;
	switch (art_search(buf, (sizeof buf), TRUE)) {
	case SRCH_ERROR:
	    art = curr_art;
	    return AS_ASK;
	case SRCH_ABORT:
	    art = curr_art;
	    return AS_INP;
	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
	    art = curr_art;
			    /* restore to current article */
	    return AS_ASK;
	case SRCH_DONE:
	    fputs("done\n",stdout) FLUSH;
	    pad(just_a_sec/3);	/* 1/3 second */
	    if (!srchahead) {
		art = curr_art;
		return AS_ASK;
	    }
	    art = firstart;
	    reread = FALSE;
	    return AS_NORM;
	case SRCH_SUBJDONE:
#ifdef UNDEF
	    fputs("\n\n\n\nSubject not found.\n",stdout) FLUSH;
	    pad(just_a_sec/3);	/* 1/3 second */
#endif
	    art = firstart;
	    reread = FALSE;
	    return AS_NORM;
	case SRCH_NOTFOUND:
	    fputs("\n\n\n\nNot found.\n",stdout) FLUSH;
	    art = curr_art;  /* restore to current article */
	    return AS_ASK;
	case SRCH_FOUND:
	    if (cmd == Ctl('n') || cmd == Ctl('p'))
		oldsubject = TRUE;
	    break;
	}
	return AS_NORM;
    }
#else
    buf[1] = '\0';
    notincl(buf);
    return AS_ASK;
#endif
    case 'u':			/* unsubscribe from this newsgroup? */
	rcchar[ng] = NEGCHAR;
	return AS_CLEAN;
    case 'M':
#ifdef DELAYMARK
	if (art <= lastart) {
	    delay_unmark(art);
	    printf("\nArticle %ld will return.\n",(long)art) FLUSH;
	}
#else
	notincl("M");
#endif
	return AS_ASK;
    case 'm':
	if (art <= lastart) {
	    unmark_as_read();
	    printf("\nArticle %ld marked as still unread.\n",(long)art) FLUSH;
	}
	return AS_ASK;
    case 'c':			/* catch up */
      reask_catchup:
#ifdef VERBOSE
	IF(verbose)
	    in_char("\nDo you really want to mark everything as read? [yn] ",
		'C');
	ELSE
#endif
#ifdef TERSE
	    in_char("\nReally? [ynh] ", 'C');
#endif
	setdef(buf,"y");
#ifdef VERIFY
	printcmd();
#endif
	putchar('\n') FLUSH;
	if (*buf == 'h') {
#ifdef VERBOSE
	    IF(verbose)
		fputs("\
Type y or SP to mark all articles as read.\n\
Type n to leave articles marked as they are.\n\
Type u to mark everything read and unsubscribe.\n\
",stdout) FLUSH;
	    ELSE
#endif
#ifdef TERSE
		fputs("\
y or SP to mark all read.\n\
n to forget it.\n\
u to mark all and unsubscribe.\n\
",stdout) FLUSH;
#endif
	    goto reask_catchup;
	}
	else if (*buf == 'n' || *buf == 'q') {
	    return AS_ASK;
	}
	else if (*buf != 'y' && *buf != 'u') {
	    fputs(hforhelp,stdout) FLUSH;
	    settle_down();
	    goto reask_catchup;
	}
	for (i = firstart; i <= lastart; i++) {
	    oneless(i);		/* mark as read */
	}
#ifdef DELAYMARK
	if (dmfp)
	    yankback();
#endif
	if (*buf == 'u') {
	    rcchar[ng] = NEGCHAR;
	    return AS_CLEAN;
	}
	art = lastart+1;
	forcelast = FALSE;
	return AS_NORM;
    case 'Q':
	exit_code = NG_ASK;
	/* FALL THROUGH */
    case 'q':			/* go back up to newsgroup level? */
	return AS_CLEAN;
    case 'j':
	putchar('\n') FLUSH;
	if (art <= lastart)
	    mark_as_read();
	return AS_ASK;
    case 'h': {			/* help? */
	int cmd;

	if ((cmd = help_art()) > 0)
	    pushchar(cmd);
	return AS_ASK;
    }
    case '&':
	if (switcheroo()) /* get rest of command */
	    return AS_INP;	/* if rubbed out, try something else */
	return AS_ASK;
    case '#':
#ifdef VERBOSE
	IF(verbose)
	    printf("\nThe last article is %ld.\n",(long)lastart) FLUSH;
	ELSE
#endif
#ifdef TERSE
	    printf("\n%ld\n",(long)lastart) FLUSH;
#endif
	return AS_ASK;
    case '=': {			/* list subjects */
	char tmpbuf[256];
	ART_NUM oldart = art;
	int cmd;
	char *subjline = getval("SUBJLINE",Nullch);
#ifndef CACHESUBJ
	char *s;
#endif

	page_init();
#ifdef CACHESUBJ
	if (!subj_list)
	    fetchsubj(art,TRUE,FALSE);
#endif
	for (i=firstart; i<=lastart && !int_count; i++) {
#ifdef CACHESUBJ
	    if (!was_read(i) &&
	      (subj_list[OFFSET(i)] != Nullch || fetchsubj(i,FALSE,FALSE)) &&
	      *subj_list[OFFSET(i)] ) {
		sprintf(tmpbuf,"%5ld ", i);
		if (subjline) {
		    art = i;
		    interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
		}
		else
		    safecpy(tmpbuf + 6, subj_list[OFFSET(i)],
			(sizeof tmpbuf) - 6);
		if (cmd = print_lines(tmpbuf,NOMARKING)) {
		    if (cmd > 0)
			pushchar(cmd);
		    break;
		}
	    }
#else
	    if (!was_read(i) && (s = fetchsubj(i,FALSE,FALSE)) && *s) {
		sprintf(tmpbuf,"%5ld ", i);
		if (subjline) {	/* probably fetches it again! */
		    art = i;
		    interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
		}
		else
		    safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6);
		if (cmd = print_lines(tmpbuf,NOMARKING)) {
		    if (cmd > 0)
			pushchar(cmd);
		    break;
		}
	    }
#endif
	}
	int_count = 0;
	art = oldart;
	return AS_ASK;
    }
    case '^':
	art = firstart;
#ifdef ARTSEARCH
	srchahead = 0;
#endif
	return AS_NORM;
#if defined(CACHESUBJ) && defined(DEBUGGING)
    case 'D':
	printf("\nFirst article: %ld\n",(long)firstart) FLUSH;
	if (!subj_list)
	    fetchsubj(art,TRUE,FALSE);
	if (subj_list != Null(char **)) {
	    for (i=1; i<=lastart && !int_count; i++) {
		if (subj_list[OFFSET(i)])
		    printf("%5ld %c %s\n",
			i, (was_read(i)?'y':'n'), subj_list[OFFSET(i)]) FLUSH;
	    }
	}
	int_count = 0;
	return AS_ASK;
#endif
    case 'v':
	if (art <= lastart) {
	    reread = TRUE;
	    do_hiding = FALSE;
	}
	return AS_NORM;
#ifdef ROTATION
    case Ctl('x'):
#endif
    case Ctl('r'):
#ifdef ROTATION
	rotate = (*buf==Ctl('x'));
#endif
	if (art <= lastart)
	    reread = TRUE;
	else
	    forcelast = TRUE;
	return AS_NORM;
#ifdef ROTATION
    case 'X':
	rotate = !rotate;
	/* FALL THROUGH */
#else
    case Ctl('x'):
    case 'x':
    case 'X':
	notincl("x");
	return AS_ASK;
#endif
    case 'l': case Ctl('l'):		/* refresh screen */
	if (art <= lastart) {
	    reread = TRUE;
	    clear();
	    do_fseek = TRUE;
	    artline = topline;
	    if (artline < 0)
		artline = 0;
	}
	return AS_NORM;
    case 'b': case Ctl('b'):		/* back up a page */
	if (art <= lastart) {
	    ART_LINE target;

	    reread = TRUE;
	    clear();
	    do_fseek = TRUE;
	    target = topline - (LINES - 2);
	    artline = topline;
	    if (artline >= 0) do {
		artline--;
	    } while(artline >= 0 && artline > target && vrdary(artline-1) >= 0);
	    topline = artline;
	    if (artline < 0)
		artline = 0;
	}
	return AS_NORM;
    case '!':			/* shell escape */
	if (escapade())
	    return AS_INP;
	return AS_ASK;
    case 'C': {
	cancel_article();
	return AS_ASK;
    }
    case 'z': {
	supersede_article();	/* supersedes */
	return AS_ASK;
    }
    case 'R':
    case 'r': {			/* reply? */
	reply();
	return AS_ASK;
    }
    case 'F':
    case 'f': {			/* followup command */
	followup();
	forcegrow = TRUE;		/* recalculate lastart */
	return AS_ASK;
    }
    case '|':
    case 'w': case 'W':
    case 's': case 'S':		/* save command */
    case 'e':			/* extract command */
	if (save_article() == SAVE_ABORT)
	    return AS_INP;
	int_count = 0;
	return AS_ASK;
    case 'E':
	if (uu_out != Nullfp)
	    uud_end();
	else
	    putchar('\n') FLUSH;
	return AS_ASK;
#ifdef DELAYMARK
    case 'Y':				/* yank back M articles */
	yankback();
	art = firstart;			/* from the beginning */
	return AS_NORM;			/* pretend nothing happened */
#endif
#ifdef STRICTCR
    case '\n':
	fputs(badcr,stdout) FLUSH;
	return AS_ASK;
#endif
    default:
	printf("\n%s",hforhelp) FLUSH;
	settle_down();
	return AS_ASK;
    }
}

#ifdef MAILCALL
/* see if there is any mail */

void
setmail()
{
    if (! (mailcount++)) {
	char *mailfile = filexp(getval("MAILFILE",MAILFILE));
	
	if (stat(mailfile,&filestat) < 0 || !filestat.st_size
	    || filestat.st_atime > filestat.st_mtime)
	    mailcall = nullstr;
	else
	    mailcall = getval("MAILCALL","(Mail) ");
    }
    mailcount %= 10;			/* check every 10 articles */
}
#endif

void
setdfltcmd()
{
    if (!toread[ng]) {
	if (art > lastart)
	    dfltcmd = "qnp";
	else
	    dfltcmd = "npq";
    }
    else {
#ifdef ARTSEARCH
	if (srchahead)
	    dfltcmd = "^Nnpq";
	else
#endif
	    dfltcmd = "npq";
    }
}
!STUFFY!FUNK!
echo Extracting common.h
cat >common.h <<'!STUFFY!FUNK!'
/* $Id: common.h,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
 * 
 * $Log: common.h,v $
 * Revision 4.4.3.1  1992/02/01  03:09:32  sob
 * Release 4.4 Patchlevel 3
 *
 * Revision 4.4.2.1  1991/12/01  18:05:42  sob
 * Patchlevel 2 changes
 *
 * Revision 4.4  1991/09/09  20:18:23  sob
 * release 4.4
 *
 *
 *
 */
/* This software is Copyright 1991 by Stan Barber. 
 *
 * Permission is hereby granted to copy, reproduce, redistribute or otherwise
 * use this software as long as: there is no monetary profit gained
 * specifically from the use or reproduction of this software, it is not
 * sold, rented, traded or otherwise marketed, and this copyright notice is
 * included prominently in any copy made. 
 *
 * The author make no claims as to the fitness or correctness of this software
 * for any use whatsoever, and it is provided as is. Any use of this software
 * is at the user's own risk. 
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include "config.h"	/* generated by installation script */
#ifdef WHOAMI
#    include <whoami.h>
#endif
#ifndef isalnum
#   define isalnum(c) (isalpha(c) || isdigit(c))
#endif

#include <errno.h>
#include <signal.h>
#ifdef IOCTL
#include <sys/ioctl.h>
#endif
#ifdef SUNOS4
# ifdef sparc		/* needed to support vfork call on sparc machines */
#  include <vfork.h>
# endif
#endif

#ifdef FCNTL
#   include <fcntl.h>
#endif

#ifdef TERMIO
#   include <termio.h>
#else
# ifdef TERMIOS
#   include <termios.h>
# else
#   include <sgtty.h>
# endif
#endif

#ifdef GETPWENT
#   include <pwd.h>
#endif

#ifdef PTEM
#include <sys/stream.h>
#include <sys/ptem.h>
#endif

#define BITSPERBYTE 8
#ifdef pdp11
#define LBUFLEN 512	/* line buffer length */
#else
#define LBUFLEN 1024	/* line buffer length */
#endif
			/* (don't worry, .newsrc lines can exceed this) */
#ifdef pdp11
#   define CBUFLEN 256	/* command buffer length */
#   define PUSHSIZE 128
#else
#   define CBUFLEN 512	/* command buffer length */
#   define PUSHSIZE 256
#endif
#ifdef pdp11
#   define MAXFILENAME 128
#else
#   define MAXFILENAME 512
#endif
#define LONGKEY 15	/* longest keyword: currently "posting-version" */
#define FINISHCMD 0177

/* some handy defs */

#define bool char
#define bool_int int
#define char_int int
#ifndef TRUE
#define TRUE (1)
#endif
#ifndef FALSE
#define FALSE (0)
#endif
#define Null(t) ((t)0)
#define Nullch Null(char *)
#define Nullfp Null(FILE *)

#define Ctl(ch) (ch & 037)

#define strNE(s1,s2) (strcmp(s1,s2))
#define strEQ(s1,s2) (!strcmp(s1,s2))
#define strnNE(s1,s2,l) (strncmp(s1,s2,l))
#define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))

/* Things we can figure out ourselves */

#ifdef SIGTSTP
#   define BERKELEY 	/* include job control signals? */
#endif

#ifdef FIONREAD
#   define PENDING
#else
#   ifdef O_NDELAY
#	define PENDING
#   endif
#endif

#ifdef EUNICE
#   define LINKART		/* add 1 level of possible indirection */
#   define UNLINK(victim) while (!unlink(victim))
#else
#   define UNLINK(victim) unlink(victim)
#endif

/* Valid substitutions for strings marked with % comment are:
 *	%a	Current article number
 *	%A	Full name of current article (%P/%c/%a)
 *		(if LINKART defined, is the name of the real article)
 *	%b	Destination of a save command, a mailbox or command
 *	%B	The byte offset to the beginning of the article for saves
 *		with or without the header
 *	%c	Current newsgroup, directory form
 *	%C	Current newsgroup, dot form
 *	%d	%P/%c
 *	%D	Old Distribution: line
 *	%e	Extract program
 *	%E	Extract destination directory
 *	%f	Old From: line or Reply-To: line
 *	%F	Newsgroups to followup to from Newsgroups: and Followup-To:
 *	%h	Name of header file to pass to mail or news poster
 *	%H	Host name (yours)
 *	%i	Old Message-I.D.: line, with <>
 *	%I	Inclusion indicator
 *	%l	News administrator login name
 *	%L	Login name (yours)
 *	%M	Number of articles marked with M
 *	%n	Newsgroups from source article
 *	%N	Full name (yours)
 *	%o	Organization (yours)
 *	%O	Original working directory (where you ran rn from)
 *	%p	Your private news directory (-d switch)
 *	%P	Public news spool directory (SPOOLDIR)
 *	%r	Last reference (parent article id)
 *	%R	New references list
 *	%s	Subject, with all Re's and (nf)'s stripped off
 *	%S	Subject, with one Re stripped off
 *	%t	New To: line derived from From: and Reply-To (Internet always)
 *	%T	New To: line derived from Path:
 *	%u	Number of unread articles
 *	%U	Number of unread articles disregarding current article
 *	%x	News library directory, usually /usr/lib/news
 *	%X	Rn library directory, usually %x/rn
 *	%z	Size of current article in bytes.
 *	%~	Home directory
 *	%.	Directory containing . files
 *	%#	count of articles saved in current command (from 1 to n)
 *	%$	current process number
 *	%{name} Environment variable "name".  %{name-default} form allowed.
 *	%[name]	Header line beginning with "Name: ", without "Name: " 
 *	%"prompt"
 *		Print prompt and insert what is typed.
 *	%`command`
 *		Insert output of command.
 *	%(test_text=pattern?if_text:else_text)
 *		Substitute if_text if test_text matches pattern, otherwise
 *		substitute else_text.  Use != for negated match.
 *		% substitutions are done on test_text, if_text, and else_text.
 *		(Note: %() only works if CONDSUB defined.)
 *	%digit	Substitute the text matched by the nth bracket in the last
 *		pattern that had brackets.  %0 matches the last bracket
 *		matched, in case you had alternatives.
 *
 *	Put ^ in the middle to capitalize the first letter: %^C = Net.jokes
 *	Put _ in the middle to capitalize last component: %_c = net/Jokes
 *
 *	~ interpretation in filename expansion happens after % expansion, so
 *	you could put ~%{NEWSLOGNAME-news} and it will expand correctly.
 */

/* *** System Dependent Stuff *** */

/* NOTE: many of these are defined in the config.h file */

/* name of organization */
#ifndef ORGNAME
#   define ORGNAME "ACME Widget Company, Widget Falls, Southern North Dakota"
#endif

#ifndef MBOXCHAR
#   define MBOXCHAR 'F'	/* how to recognize a mailbox by 1st char */
#endif

#ifndef ROOTID
#   define ROOTID 0        /* uid of superuser */
#endif

#ifdef NORMSIG
#   define sigset signal
#   define sigignore(sig) signal(sig,SIG_IGN)
#endif

#ifndef LOGDIRFIELD
#   define LOGDIRFIELD 6		/* Which field (origin 1) is the */
					/* login directory in /etc/passwd? */
					/* (If it is not kept in passwd, */
					/* but getpwnam() returns it, */
					/* define the symbol GETPWENT) */
#endif
#ifndef GCOSFIELD
#   define GCOSFIELD 5
#endif

#ifndef NEGCHAR
#   define NEGCHAR '!'
#endif

/* Space conservation section */

/* To save D space, cut down size of NGMAX and  VARYSIZE. */
#define NGMAX 100	/* number of newsgroups allowed on command line */
			/* undefine ONLY symbol to disable "only" feature */
#define VARYSIZE 256	/* this makes a block 1024 bytes long in DECville */
			/* (used by virtual array routines) */

/* Undefine any of the following features to save both I and D space */
/* In general, earlier ones are easier to get along without */
/* Pdp11's without split I and D may have to undefine them all */
#define DEBUGGING	/* include debugging code */
#define CUSTOMLINES	/* include code for HIDELINE and PAGESTOP */
#define PUSHBACK	/* macros and keymaps using pushback buffer */
#define SPEEDOVERMEM	/* use more memory to run faster */
#define WORDERASE	/* enable ^W to erase a word */
#define MAILCALL	/* check periodically for mail */
#define CLEAREOL	/* use clear to end-of-line instead of clear screen */
#define NOFIREWORKS	/* keep whole screen from flashing on certain */
			/* terminals such as older Televideos */
#define VERIFY		/* echo the command they just typed */
#define HASHNG		/* hash newsgroup lines for fast lookup-- */
			/* linear search used if not defined */
#define CONDSUB		/* allow %(cond?text:text) */
#define BACKTICK	/* allow %`command` */
#define PROMPTTTY	/* allow %"prompt" */
#define ULSMARTS	/* catch _^H in text and do underlining */
#define TERMMOD		/* allow terminal type modifier on switches */
#define BAUDMOD		/* allow baudrate modifier on switches */
#define GETLOGIN	/* use getlogin() routine as backup to environment */
			/* variables USER or LOGNAME */
#define ORGFILE		/* if organization begins with /, look up in file */
#define TILDENAME	/* allow ~logname expansion */
#define SETENV		/* allow command line environment variable setting */
#define MAKEDIR		/* use our makedir() instead of shell script */
#define MEMHELP		/* keep help messages in memory */
#define VERBOSE		/* compile in more informative messages */
#define TERSE		/* compile in shorter messages */
			/* (Note: both VERBOSE and TERSE can be defined; -t
			 * sets terse mode.  One or the other MUST be defined.
			 */
#ifndef pdp11
#   define CACHESUBJ	/* cache subject lines in memory */
			/* without this ^N still works but runs really slow */
			/* but you save lots and lots of D space */
#   define CACHEFIRST	/* keep absolute first article numbers in memory */
			/* cost: about 2k */
#endif
#define ROTATION	/* enable x, X and ^X commands to work */
#define DELBOGUS	/* ask if bogus newsgroups should be deleted */
#define RELOCATE	/* allow newsgroup rearranging */
#define ESCSUBS		/* escape substitutions in multi-character commands */
#define DELAYMARK	/* allow articles to be temporarily marked as read */
			/* until exit from current newsgroup or Y command */
#define MCHASE		/* unmark xrefed articles on m or M */
#define MUNGHEADER	/* allow alternate header formatting via */
			/* environment variable ALTHEADER (not impl) */
#define ASYNC_PARSE	/* allow parsing headers asyncronously to reading */
			/* used by MCHASE and MUNGHEADER */
#define FINDNEWNG	/* check for new newsgroups on startup */
#define FASTNEW		/* do optimizations on FINDNEWNG for faster startup */
			/* (this optimization can make occasional mistakes */
			/* if a group is removed and another group of the */
			/* same length is added, and if no softpointers are */
			/* affected by said change.) */
#define INNERSEARCH	/* search command 'g' with article */
#define CATCHUP		/* catchup command at newsgroup level */
#define NGSEARCH	/* newsgroup pattern matching */
#define ONLY		/* newsgroup restrictions by pattern */
#define KILLFILES	/* automatic article killer files */
#define ARTSEARCH	/* pattern searches among articles */
			/* /, ?, ^N, ^P, k, K */

/* some dependencies among options */

#ifndef ARTSEARCH
#   undef KILLFILES
#   undef INNERSEARCH
#   undef CACHESUBJ
#endif

#ifndef DELAYMARK
#   ifndef MCHASE
#	ifndef MUNGHEADER
#	    undef ASYNC_PARSE
#	endif
#   endif
#endif

#ifndef SETUIDGID
#   define eaccess access
#endif

#ifdef ONLY				/* idiot lint doesn't grok #if */
#   define NGSORONLY
#else
#   ifdef NGSEARCH
#	define NGSORONLY
#   endif
#endif

#ifdef VERBOSE
#   ifdef TERSE
#	define IF(c) if (c)
#	define ELSE else
#   else
#	define IF(c)
#	define ELSE
#   endif
#else /* !VERBOSE */
#   ifndef TERSE
#	define TERSE
#   endif
#   define IF(c) "IF" outside of VERBOSE???
#   define ELSE "ELSE" outside of VERBOSE???
#endif

#ifdef DEBUGGING
#   define assert(ex) {if (!(ex)){fprintf(stderr,"Assertion failed: file %s, line %d\n", __FILE__, __LINE__);sig_catcher(0);}}
#else
#   define assert(ex) ;
#endif

#ifdef SPEEDOVERMEM
#   define OFFSET(x) (x)
#else
#   define OFFSET(x) ((x)-absfirst)
#endif

/* If you're strapped for space use the help messages in shell scripts */
/* if {NG,ART,PAGER,SUBS}HELP is undefined, help messages are in memory */
#ifdef MEMHELP  /* undef MEMHELP above to get them all as sh scripts */
#   undef NGHELP
#   undef ARTHELP
#   undef PAGERHELP
#   undef SUBSHELP
#else
#   ifndef NGHELP			/* % and ~ */
#	define NGHELP "%X/ng.help"
#   endif
#   ifndef ARTHELP			/* % and ~ */
#	define ARTHELP "%X/art.help"
#   endif
#   ifndef PAGERHELP		/* % and ~ */
#	define PAGERHELP "%X/pager.help"
#   endif
#   ifndef SUBSHELP		/* % and ~ */
#	define SUBSHELP "%X/subs.help"
#   endif
#endif

#ifdef CLEAREOL
#   define TCSIZE 512	/* capacity for termcap strings */
#else
#   ifdef pdp11
#	define TCSIZE 256	/* capacity for termcap strings */
#   else
#	define TCSIZE 512	/* capacity for termcap srings */
#   endif
#endif

/* Additional ideas:
 *	Make the do_newsgroup() routine a separate process.
 *	Keep .newsrc on disk instead of in memory.
 *	Overlays, if you have them.
 *	Get a bigger machine.
 */

/* End of Space Conservation Section */

/* More System Dependencies */

/* news library */
#ifndef LIB		/* ~ and %l only ("~%l" is permissable) */
#   define LIB "/usr/lib/news"
#endif

/* path to private executables */
#ifndef RNLIB		/* ~, %x and %l only */
#   define RNLIB "%x/rn"
#endif

/* system-wide RNINIT switches */
#ifndef GLOBINIT
#   define GLOBINIT "%X/INIT"
#endif

/* where to find news files */
#ifndef SPOOL			/* % and ~ */
#   define SPOOL "/usr/spool/news"
#endif

/* file containing list of active newsgroups and max article numbers */
#ifndef ACTIVE			/* % and ~ */
#   define ACTIVE "%x/active"
#endif

/* location of history file */
#ifndef ARTFILE			/* % and ~ */
#    define ARTFILE "%x/history"
#endif

/* command to setup a new .newsrc */
#ifndef NEWSETUP		/* % and ~ */
#   define NEWSETUP "newsetup"
#endif

/* command to display a list of un-subscribed-to newsgroups */
#ifndef NEWSGROUPS		/* % and ~ */
#   define NEWSGROUPS "newsgroups"
#endif

/* preferred shell for use in doshell routine */
/*  ksh or sh would be okay here */
#ifndef PREFSHELL
#   define PREFSHELL "/bin/csh"
#endif

/* path to fastest starting shell */
#ifndef SH
#   define SH "/bin/sh"
#endif

/* default unshar'ing program */
#ifndef UNSHAR
#   define UNSHAR "/bin/sh"
#endif

/* path to default editor */
#ifndef DEFEDITOR
#   define DEFEDITOR "/usr/ucb/vi"
#endif

/* location of macro file */
#ifndef RNMACRO
#   ifdef PUSHBACK
#	define RNMACRO "%./.rnmac"
#   endif
#endif

/* location of full name */
#ifndef FULLNAMEFILE
#   ifndef PASSNAMES
#	define FULLNAMEFILE "%./.fullname"
#   endif
#endif

/* virtual array file name template */
#ifndef VARYNAME		/* % and ~ */
#   define VARYNAME "/tmp/rnvary.%$"
#endif

/* where to compile a new newsgroup list */
#ifndef RNEWNAME
#   define RNEWNAME "/tmp/rnew.%$"
#endif

/* file to pass header to followup article poster */
#ifndef HEADNAME		/* % and ~ */
#   define HEADNAME "%./.rnhead"
/* or alternately #define HEADNAME "/tmp/rnhead.%$" */
#endif

#ifndef MAKEDIR
/* shell script to make n-deep subdirectories */
#   ifndef DIRMAKER		/* % and ~ */
#	define DIRMAKER "%X/makedir"
#   endif
#endif

/* location of newsrc file */
#ifndef RCNAME		/* % and ~ */
#   define RCNAME "%./.newsrc"
#endif

/* temporary newsrc file in case we crash while writing out */
#ifndef RCTNAME		/* % and ~ */
#   define RCTNAME "%./.newnewsrc"
#endif

/* newsrc file at the beginning of this session */
#ifndef RCBNAME		/* % and ~ */
#   define RCBNAME "%./.oldnewsrc"
#endif

/* if existent, contains process number of current or crashed rn */
#ifndef LOCKNAME		/* % and ~ */
#   define LOCKNAME "%./.rnlock"
#endif

/* information from last invocation of rn */
#ifndef LASTNAME		/* % and ~ */
#   define LASTNAME "%./.rnlast"
#endif

/* file with soft pointers into the active file */
#ifndef SOFTNAME		/* % and ~ */
#   define SOFTNAME "%./.rnsoft"
#endif

/* list of article numbers to mark as unread later (see M and Y cmmands) */
#ifndef RNDELNAME		/* % and ~ */
#   define RNDELNAME "%./.rndelay"
#endif

/* a motd-like file for rn */
#ifndef NEWSNEWSNAME		/* % and ~ */
#   define NEWSNEWSNAME "%X/newsnews"
#endif

/* command to send a reply */
#ifndef MAILPOSTER		/* % and ~ */
#   define MAILPOSTER "Rnmail -h %h"
#endif

#ifdef INTERNET
#   ifndef MAILHEADER		/* % */
#	ifdef CONDSUB
#	    define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
#	else
#	    define MAILHEADER "To: %t\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
#	endif
#   endif
#else
#   ifndef MAILHEADER		/* % */
#	ifdef CONDSUB
#	    define MAILHEADER "To: %T\nSubject: %(%i=^$?:Re: %S\nNewsgroups: %n\nIn-Reply-To: %i)\n%(%[references]!=^$?References\\: %[references]\n)Organization: %o\nCc: \nBcc: \n\n"
#	else
#	    define MAILHEADER "To: %T\nSubject: Re: %S\nNewsgroups: %n\nIn-Reply-To: %i\nReferences: %[references]\nCc: \nBcc: \n\n"
#	endif
#   endif
#endif

#ifndef YOUSAID			/* % */
#   define YOUSAID "In article %i you write:"
#endif

/* command to submit a followup article */
#ifndef NEWSPOSTER		/* % and ~ */
#   define NEWSPOSTER "Pnews -h %h"
#endif

#ifndef NEWSHEADER		/* % */
#   ifdef CONDSUB
#ifdef INTERNET
#	define NEWSHEADER "Newsgroups: %(%F=^$?%C:%F)\nSubject: %(%S=^$?%\"\n\nSubject: \":Re: %S)\nSummary: \nExpires: \n%(%R=^$?:References: %R\n)Sender: \nFollowup-To: \nDistribution: %(%i=^$?%\"Distribution: \":%D)\nOrganization: %o\nKeywords: %[keywords]\n\n"
#else
#	define NEWSHEADER "Newsgroups: %(%F=^$?%C:%F)\nSubject: %(%S=^$?%\"\n\nSubject: \":Re: %S)\nSummary: \nExpires: \n%(%R=^$?:References: %R\n)Sender: \nFollowup-To: \nDistribution: %(%i=^$?%\"Distribution: \":%D)\nOrganization: %o\nKeywords: %[keywords]\n\n"
#endif
#   else
#	ifdef INTERNET
#	    define NEWSHEADER "Newsgroups: %F\nSubject: Re: %S\nSummary: \nExpires: \nReferences: %R\nSender: \nFollowup-To: \nDistribution: %D\nOrganization: %o\nKeywords: %[keywords]\n\n"
#	else
#	    define NEWSHEADER "Newsgroups: %F\nSubject: Re: %S\nSummary: \nExpires: \nReferences: %R\nSender: \nFollowup-To: \nDistribution: %D\nOrganization: %o\nKeywords: %[keywords]\n\n"
#	endif
#   endif
#endif

#ifndef ATTRIBUTION		/* % */
#   define ATTRIBUTION "In article %i %f writes:"
#endif

#ifndef PIPESAVER		/* % */
#   ifdef CONDSUB
#       ifdef SERVER
#               define PIPESAVER "%(%B=^0$?<%P/rrn%a.%$:tail +%Bc %P/rrn%a.%$ |) %b"
#       else
#		define PIPESAVER "%(%B=^0$?<%A:tail +%Bc %A |) %b"
#	endif
#   else
#       ifdef SERVER
#               define PIPESAVER "tail +%Bc %P/rrn%a.%$ | %b"
#       else
#		define PIPESAVER "tail +%Bc %A | %b"
#	endif
#   endif
#endif

#ifndef EXSAVER
#    ifdef SERVER
#	define EXSAVER "tail +%Bc %P/rrn%a.%$ | %e"
#    else
#	define EXSAVER "tail +%Bc %A | %e"
#    endif
#endif

#ifndef NORMSAVER		/* % and ~ */
#    ifdef SERVER
#	define NORMSAVER "%X/norm.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\""
#    else
#   	define NORMSAVER "%X/norm.saver %A %P %c %a %B %C \"%b\""
#    endif
#endif

#ifndef MBOXSAVER		/* % and ~ */
#   ifdef MININACT		/* 2.10.2 site? */
#       ifdef SERVER
#           define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %`date`\""
#       else
#	    define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %`date`\""
#	endif
#   else
#	ifdef CONDSUB
#           ifdef SERVER
#               define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
#           else
#	        define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %(%[date]=^\\(\\w*\\), \\(\\w*\\)-\\(\\w*\\)-\\(\\w*\\) \\([^ ]*\\)?%1 %3 %(%2=..?%2: %2) %5 19%4)\""
#	    endif
					/* header munging with a vengeance */
#	else
#           ifdef SERVER
#               define MBOXSAVER "%X/mbox.saver %P/rrn%a.%$ %P %c %a %B %C \"%b\" \"From %T %[posted]\""
#           else
#	        define MBOXSAVER "%X/mbox.saver %A %P %c %a %B %C \"%b\" \"From %T %[posted]\""
#	    endif
#	endif
#   endif
#endif

#ifdef MKDIRS

#   ifndef SAVEDIR			/* % and ~ */
#	define SAVEDIR "%p/%c"
#   endif
#   ifndef SAVENAME		/* % */
#	define SAVENAME "%a"
#   endif

#else

#   ifndef SAVEDIR			/* % and ~ */
#	define SAVEDIR "%p"
#   endif
#   ifndef SAVENAME		/* % */
#	define SAVENAME "%^C"
#   endif

#endif

#ifndef KILLGLOBAL		/* % and ~ */
#   define KILLGLOBAL "%p/KILL"
#endif

#ifndef KILLLOCAL		/* % and ~ */
#   define KILLLOCAL "%p/%c/KILL"
#endif

/* how to cancel an article */
#ifndef CANCEL
#   ifdef MININACT			/* 2.10.2 ? */
#	define CANCEL "%x/inews -h < %h"
#   else
#	define CANCEL "inews -h < %h"
#   endif
#endif

/* how to cancel an article, continued */
#ifndef CANCELHEADER
#ifdef INTERNET
#   define CANCELHEADER "From: %L@%H (%N)\nNewsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nDistribution: %D\nOrganization: %o\n\n%i was cancelled from within rn.\n"
#else
#   define CANCELHEADER "From:%L@%H.UUCP (%N)\nNewsgroups: %n\nSubject: cmsg cancel %i\nReferences: %R\nDistribution: %D\nOrganization: %o\n\n%i was cancelled from within rn.\n"
#endif
#endif

/* how to supersede an article */
#ifndef SUPERSEDEHEADER
#ifdef INTERNET
#   define SUPERSEDEHEADER "From: %L@%H (%N)\nNewsgroups: %n\nSupersedes: %i\nSubject: %S\nDistribution: %D\nOrganization: %o\n"
#else
#   define SUPERSEDEHEADER "From:%L@%H.UUCP (%N)\nNewsgroups: %n\nSupersedes: %i\nSubject: %S\nDistribution: %D\nOrganization: %o\n"
#endif
#endif

/* where to find the mail file */
#ifndef MAILFILE
#   define MAILFILE "/usr/spool/mail/%L"
#endif

/* how to open binary format files */
#ifndef FOPEN_RB
#   define FOPEN_RB "r"
#endif
#ifndef FOPEN_WB
#   define FOPEN_WB "w"
#endif

/* what to do with ansi prototypes -- '()' == ignore, 'x' == use */
#ifndef ANSI
#   ifdef __STDC__
#	define ANSI(x) x
#   else
#	define ANSI(x) ()
#   endif
#endif

/* how many characters is a newline in a text file? */
#ifndef NL_SIZE
#   define NL_SIZE 1
#endif

/* some important types */

typedef int		NG_NUM;		/* newsgroup number */
typedef long		ART_NUM;	/* article number */
#ifdef pdp11
    typedef short	ART_UNREAD;	/* ordinarily this should be long */
					/* like ART_NUM, but assuming that */
					/* we stay less than 32767 articles */
					/* behind saves a lot of space. */
					/* NOTE: do not make unsigned. */
#else
    typedef long	ART_UNREAD;
#endif
#ifdef SERVER
typedef int		ART_PART;	/* for passing to nntpopen() */
#endif
typedef long		ART_POS;	/* char position in article file */
typedef int		ART_LINE;	/* line position in article file */
typedef long		ACT_POS;	/* char position in active file */
typedef unsigned int	MEM_SIZE;	/* for passing to malloc */


/* *** end of the machine dependent stuff *** */

/* GLOBAL THINGS */

/* file statistics area */

EXT struct stat filestat;

/* various things of type char */

char	*index();
char	*rindex();
char	*getenv();
char	*strcat();
char	*strcpy();

EXT char buf[LBUFLEN+1];	/* general purpose line buffer */
EXT char cmd_buf[CBUFLEN];	/* buffer for formatting system commands */
EXT char *indstr INIT(">");	/* indent for old article embedded in followup */

EXT char *cwd INIT(Nullch);		/* current working directory */
EXT char *dfltcmd INIT(Nullch);	/* 1st char is default command */

/* switches */

#ifdef DEBUGGING
    EXT int debug INIT(0);				/* -D */
#   define DEB_NNTP 16 
#   define DEB_INNERSRCH 32 
#   define DEB_FILEXP 64 
#   define DEB_HASH 128
#   define DEB_XREF_MARKER 256
#   define DEB_CTLAREA_BITMAP 512
#   define DEB_SOFT_POINTERS 1024
#   define DEB_NEWSRC_LINE 2048
#   define DEB_SEARCH_AHEAD 4096
#   define DEB_CHECKPOINTING 8192
#   define DEB_FEED_XREF 16384
#endif

#ifdef ARTSEARCH
    EXT int scanon INIT(0);				/* -S */
#endif

EXT bool mbox_always INIT(FALSE);			/* -M */
EXT bool norm_always INIT(FALSE);			/* -N */
EXT bool checkflag INIT(FALSE);			/* -c */
EXT bool suppress_cn INIT(FALSE);			/* -s */
EXT int countdown INIT(5);	/* how many lines to list before invoking -s */
EXT bool muck_up_clear INIT(FALSE);			/* -loco */
EXT bool erase_screen INIT(FALSE);			/* -e */
#ifdef CLEAREOL
EXT bool can_home INIT(FALSE);
#endif
#ifdef CLEAREOL
EXT bool can_home_clear INIT(FALSE);		/* fancy -e */
#endif
EXT bool findlast INIT(FALSE);			/* -r */
EXT bool typeahead INIT(FALSE);			/* -T */
#ifdef VERBOSE
#   ifdef TERSE
	EXT bool verbose INIT(TRUE);			/* +t */
#   endif
#endif
#ifdef VERIFY
    EXT bool verify INIT(FALSE);			/* -v */
#endif
    EXT bool quickstart INIT(FALSE);			/* -q */

#define NOMARKING 0
#define STANDOUT 1
#define UNDERLINE 2
EXT int marking INIT(NOMARKING);			/* -m */

EXT ART_LINE initlines INIT(0);		/* -i */
EXT bool initlines_specified INIT(FALSE);

/* miscellania */

int fseek();
long atol(), ftell();
EXT bool in_ng INIT(FALSE);		/* current state of rn */
EXT char mode INIT('i');		/* current state of rn */

EXT FILE *tmpfp INIT(Nullfp);	/* scratch fp used for .rnlock, .rnlast, etc. */

EXT NG_NUM nextrcline INIT(0);	/* 1st unused slot in rcline array */
			/* startup to avoid checking twice in a row */

extern errno;
/* Factored strings */

EXT char nullstr[1] INIT("");
EXT char sh[] INIT(SH);
EXT char defeditor[] INIT(DEFEDITOR);
EXT char hforhelp[] INIT("Type h for help.\n");
#ifdef STRICTCR
EXT char badcr[] INIT("\nUnnecessary CR ignored.\n");
#endif
EXT char readerr[] INIT("rn read error");
EXT char unsubto[] INIT("\n\nUnsubscribed to newsgroup %s\n");
EXT char cantopen[] INIT("Can't open %s\n");
EXT char cantcreate[] INIT("Can't create %s\n");
EXT char cantrecreate[] INIT("Can't recreate %s -- restoring older version.\n");

#ifdef VERBOSE
    EXT char nocd[] INIT("Can't chdir to directory %s\n");
#else
    EXT char nocd[] INIT("Can't find %s\n");
#endif

#ifdef NOLINEBUF
#define FLUSH ,fflush(stdout)
#else
#define FLUSH
#endif

#ifdef lint
#undef FLUSH
#define FLUSH
#undef putchar
#define putchar(c)
#endif
!STUFFY!FUNK!
echo Extracting help.c
sed >help.c <<'!STUFFY!FUNK!' -e 's/X//'
X/* $Id: help.c,v 4.4.3.1 1992/02/01 03:09:32 sob PATCH_3 sob $
X *
X * $Log: help.c,v $
X * Revision 4.4.3.1  1992/02/01  03:09:32  sob
X * Release 4.4 Patchlevel 3
X *
X * Revision 4.4.2.1  1991/12/01  18:05:42  sob
X * Patchlevel 2 changes
X *
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 last extraction directory\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\n\
Xx	News library directory\n\
XX	Rn library directory\n\
Xz	Length of current article in bytes\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X~	Your home directory\n\
X.	Directory containing . files\n\
X#	A counter in multi-article saves\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 backpage.h
cat >backpage.h <<'!STUFFY!FUNK!'
/* $Id: backpage.h,v 4.4 1991/09/09 20:18:23 sob Exp sob $
 *
 * $Log: backpage.h,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. 
 */

/* things for doing the 'back page' command */

EXT int varyfd INIT(0);			/* virtual array file for storing  */
					/* file offsets */
EXT ART_POS varybuf[VARYSIZE];		/* current window onto virtual array */

EXT long oldoffset INIT(-1);		/* offset to block currently in window */

void	backpage_init ANSI((void));
ART_POS	vrdary ANSI((ART_LINE));
void	vwtary ANSI((ART_LINE,ART_POS));
!STUFFY!FUNK!
echo ""
echo "End of kit 4 (of 11)"
cat /dev/null >kit4isdone
config=true
for iskit in 1 2 3 4 5 6 7 8 9 10 11 ; do
    if test -f kit${iskit}isdone; then
	echo "You have run kit ${iskit}."
    else
	echo "You still need to run kit ${iskit}."
	config=false
    fi
done
case $config in
    true)
	echo "You have run all your kits.  Please read README and then type Configure."
	chmod 755 Configure
	;;
esac
: I do not append .signature, but someone might mail this.
exit
