v23i069: TRN, version of RN that follows conversation threads, Part10/14

Rich Salz rsalz at bbn.com
Tue Dec 4 07:28:05 AEST 1990


Submitted-by: Wayne Davison <davison at dri.com>
Posting-number: Volume 23, Issue 69
Archive-name: trn/part10

---- Cut Here and unpack ----
#!/bin/sh
# this is part 10 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file ng.c continued
#
CurArch=10
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
     exit 1; fi
( read Scheck
  if test "$Scheck" != $CurArch
  then echo "Please unpack part $Scheck next!"
       exit 1;
  else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file ng.c"
sed 's/^X//' << 'SHAR_EOF' >> ng.c
X#endif
X	    /*NOSTRICT*/
X	    toread[ng] = (ART_UNREAD)ucount;	/* this is perhaps pointless */
X	    art = lastart + 1;		/* keep bitmap references sane */
X	    if (art != curr_art) {
X#ifdef USETHREADS
X		recent_p_art = curr_p_art;
X		find_article(art);
X		curr_p_art = p_art;
X#endif
X		recent_art = curr_art;
X					/* remember last article # (for '-') */
X		curr_art = art;      /* remember this article # */
X	    }
X	    if (erase_screen)
X		clear();			/* clear the screen */
X	    else
X		fputs("\n\n",stdout) FLUSH;
X#ifdef VERBOSE
X	    IF(verbose)
X		printf("End of newsgroup %s.",ngname);
X					/* print pseudo-article */
X	    ELSE
X#endif
X#ifdef TERSE
X		printf("End of %s",ngname);
X#endif
X	    if (ucount) {
X#ifdef USETHREADS
X		if (selected_root_cnt)
X		    printf("  (%ld + %ld articles still unread)",
X			(long)selected_count,(long)ucount-selected_count);
X		else
X#endif
X		    printf("  (%ld article%s still unread)",
X			(long)ucount,ucount==1?nullstr:"s");
X	    }
X	    else {
X		if (!forcelast)
X		    goto cleanup;	/* actually exit newsgroup */
X	    }
X	    prompt = whatnext;
X#ifdef ARTSEARCH
X	    srchahead = 0;		/* no more subject search mode */
X#endif
X	    fputs("\n\n",stdout) FLUSH;
X	    skipstate = 0;		/* back to none skipped */
X	}
X	else if (!reread && was_read(art)) {
X					/* has this article been read? */
X#ifdef USETHREADS
X	    follow_thread('n');
X#else
X	    art++;			/* then skip it */
X#endif
X	    continue;
X	}
X	else if
X	  (!reread && !was_read(art)
X#ifdef SERVER
X	    && nntpopen(art,GET_HEADER) == Nullfp) { 
X#else
X	    && artopen(art) == Nullfp) { /* never read it, & cannot find it? */
X	    if (errno != ENOENT) {	/* has it not been deleted? */
X#ifdef VERBOSE
X		IF(verbose)
X		    printf("\n(Article %ld exists but is unreadable.)\n",
X			(long)art) FLUSH;
X		ELSE
X#endif
X#ifdef TERSE
X		    printf("\n(%ld unreadable.)\n",(long)art) FLUSH;
X#endif
X		skipstate = 0;
X		sleep(2);
X	    }
X#endif
X	    switch(skipstate++) {
X	    case 0:
X		clear();
X#ifdef VERBOSE
X		IF(verbose)
X		    fputs("Skipping unavailable article",stdout);
X		ELSE
X#endif
X#ifdef TERSE
X		    fputs("Skipping",stdout);
X#endif
X		for (i = just_a_sec/3; i; --i)
X		    putchar(PC);
X		fflush(stdout);
X		sleep(1);
X		break;
X	    case 1:
X		fputs("..",stdout);
X		fflush(stdout);
X		break;
X	    default:
X		putchar('.');
X		fflush(stdout);
X#ifndef SERVER
X#define READDIR
X#ifdef READDIR
X		{			/* fast skip patch */
X		    ART_NUM newart;
X		    
X		    if (! (newart=getngmin(".",art)))
X			newart = lastart+1;
X		    for (i=art; i<newart; i++)
X			oneless(i);
X		    art = newart - 1;
X		}
X#endif
X#else
X		{
X			char	ser_line[256];
X			ART_NUM	newart;
X
X			put_server("NEXT");
X			if (get_server(ser_line, sizeof (ser_line)) < 0) {
X				fprintf(stderr,
X			"rrn: unexpected close of server socket.\n");
X				finalize(1);
X			}
X			if (ser_line[0] != CHAR_OK)
X				newart = lastart + 1;
X			else
X				newart = atoi(ser_line+4);
X		        for (i=art; i<newart; i++)
X				oneless(i);
X		        art = newart - 1;
X		}
X#endif /* SERVER */
X		break;
X	    }
X	    oneless(art);		/* mark deleted as read */
X#ifdef USETHREADS
X	    count_roots(FALSE);		/* Keep selected_count accurate */
X	    find_article(art);
X	    follow_thread('n');
X#else
X	    art++;			/* try next article */
X#endif
X	    continue;
X	}
X	else {				/* we have a real live article */
X	    skipstate = 0;		/* back to none skipped */
X	    if (art != curr_art) {
X#ifdef USETHREADS
X		recent_p_art = curr_p_art;
X		find_article(art);
X		curr_p_art = p_art;
X#endif
X		recent_art = curr_art;
X					/* remember last article # (for '-') */
X		curr_art = art;      /* remember this article # */
X	    }
X	    if (!do_fseek) {		/* starting at top of article? */
X		artline = 0;		/* start at the beginning */
X		topline = -1;		/* and remember top line of screen */
X					/*  (line # within article file) */
X	    }
X	    clear();			/* clear screen */
X	    if (!artopen(art)) {	/* make sure article is found & open */
X#ifdef USETHREADS
X		char tmpbuf[256];
X		/* see if we have tree data for this article anyway */
X		init_tree();
X		sprintf(tmpbuf,"%s #%ld is not available.",ngname,(long)art);
X		tree_puts(tmpbuf,0,0);
X		vwtary((ART_LINE)0,(ART_POS)0);
X		finish_tree(1);
X		prompt = whatnext;
X#else
X		printf("Article %ld of %s is not available.\n\n",
X		    (long)art,ngname) FLUSH;
X		prompt = whatnext;
X#endif
X#ifdef ARTSEARCH
X		srchahead = 0;
X#endif
X	    }
X	    else {			/* found it, so print it */
X		switch (do_article()) {
X		case DA_CLEAN:		/* quit newsgroup */
X		    goto cleanup;
X		case DA_TOEND:		/* do not mark as read */
X		    goto reask_article; 
X		case DA_RAISE:		/* reparse command at end of art */
X		    goto article_level;
X		case DA_NORM:		/* normal end of article */
X		    break;
X		}
X	    }
X	    if (art >= absfirst)	/* don't mark non-existant articles */
X		mark_as_read();		/* mark current article as read */
X	    reread = FALSE;
X	    do_hiding = TRUE;
X#ifdef ROTATION
X	    rotate = FALSE;
X#endif
X	}
X
X/* if these gotos bother you, think of this as a little state machine */
X
Xreask_article:
X#ifdef MAILCALL
X	setmail();
X#endif
X	setdfltcmd();
X#ifdef CLEAREOL
X	if (erase_screen && can_home_clear)
X	    clear_rest();
X#endif /* CLEAREOL */
X	unflush_output();		/* disable any ^O in effect */
X	standout();			/* enter standout mode */
X	printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */
X	un_standout();			/* leave standout mode */
X	putchar(' ');
X	fflush(stdout);
Xreinp_article:
X	eat_typeahead();
X#ifdef PENDING
X	look_ahead();			/* see what we can do in advance */
X	if (!input_pending())
X	    collect_subjects();		/* loads subject cache until */
X					/* input is pending */
X#endif
X	getcmd(buf);
X	if (errno || *buf == '\f') {
X	    if (LINES < 100 && !int_count)
X		*buf = '\f';		/* on CONT fake up refresh */
X	    else {
X		putchar('\n') FLUSH;		/* but only on a crt */
X		goto reask_article;
X	    }
X	}
Xarticle_level:
X
X	/* parse and process article level command */
X
X	switch (art_switch()) {
X	case AS_INP:			/* multichar command rubbed out */
X	    goto reinp_article;
X	case AS_ASK:			/* reprompt "End of article..." */
X	    goto reask_article;
X	case AS_CLEAN:			/* exit newsgroup */
X	    goto cleanup;
X	case AS_NORM:			/* display article art */
X	    break;
X	}
X    }					/* end of article selection loop */
X    
X/* shut down newsgroup */
X
Xcleanup:
X    uud_end();
X#ifdef KILLFILES
X    kill_unwanted(firstart,"\nCleaning up...\n\n",FALSE);
X					/* do cleanup from KILL file, if any */
X#endif
X#ifdef USETHREADS
X    if (ThreadedGroup)
X	unuse_data(0);			/* free article thread data */
X#endif
X    in_ng = FALSE;			/* leave newsgroup state */
X    if (artfp != Nullfp) {		/* article still open? */
X	fclose(artfp);			/* close it */
X	artfp = Nullfp;			/* and tell the world */
X#ifdef SERVER
X        sprintf(artname, "/tmp/rrn%ld.%ld", (long) openart, our_pid);
X        UNLINK(artname);
X#endif /* SERVER */
X	openart = 0;
X    }
X    putchar('\n') FLUSH;
X    yankback();				/* do a Y command */
X    restore_ng();			/* reconstitute .newsrc line */
X    doing_ng = FALSE;			/* tell sig_catcher to cool it */
X    free(ctlarea);			/* return the control area */
X#ifdef CACHESUBJ
X    if (subj_list) {
X	for (i=OFFSET(lastart); i>=0; --i)
X	    if (subj_list[i])
X		free(subj_list[i]);
X#ifndef lint
X	free((char*)subj_list);
X#endif /* lint */
X    }
X#endif
X    write_rc();				/* and update .newsrc */
X    rc_changed = FALSE;			/* tell sig_catcher it is ok */
X    if (chdir(spool)) {
X	printf(nocd,spool) FLUSH;
X	sig_catcher(0);
X    }
X#ifdef KILLFILES
X    if (localkfp) {
X	fclose(localkfp);
X	localkfp = Nullfp;
X    }
X#endif
X    mode = oldmode;
X    return exit_code;
X}					/* Whew! */
X
X/* decide what to do at the end of an article */
X
Xint
Xart_switch()
X{
X    register ART_NUM i;
X      
X    setdef(buf,dfltcmd);
X#ifdef VERIFY
X    printcmd();
X#endif
X
X    switch (*buf) {
X#ifdef USETHREADS
X    case '<':			/* goto previous thread */
X	if (!ThreadedGroup) {
X	    goto group_unthreaded;
X	}
X	prev_root();
X	return AS_NORM;
X    case '>':			/* goto next thread */
X	if (!ThreadedGroup) {
X	    goto group_unthreaded;
X	}
X	next_root();
X	return AS_NORM;
X    case 'U': {			/* unread some articles */
X	char *u_prompt, *u_help_thread;
X
X	if (!ThreadedGroup) {
X	    dfltcmd = "a";
X	    u_help_thread = nullstr;
X#ifdef VERBOSE
X	    IF(verbose)
X		u_prompt = "\nSet unread: all articles? [an] ";
X	    ELSE
X#endif
X#ifdef TERSE
X		u_prompt = "\nUnread? [an] ";
X#endif
X	}
X	else if (!p_art || art > lastart) {
X	    dfltcmd = "+";
X	    u_help_thread = nullstr;
X#ifdef VERBOSE
X	    IF(verbose)
X		u_prompt = "\nSet unread: +select or all? [+an] ";
X	    ELSE
X#endif
X#ifdef TERSE
X		u_prompt = "\nUnread? [+an] ";
X#endif
X	}
X	else {
X	    dfltcmd = "t";
X#ifdef VERBOSE
X	    IF(verbose) {
X		u_prompt = "\n\
XSet unread: thread, subthread, +select, or all? [ts+an] ";
X		u_help_thread = "\
XType t or SP to mark this thread's articles as unread.\n\
XType s to mark the current article and its descendants as unread.\n";
X	    }
X	    ELSE
X#endif
X#ifdef TERSE
X	    {
X		u_prompt = "\nUnread? [ts+an] ";
X		u_help_thread = "\
Xt or SP to mark thread unread.\n\
Xs to mark subthread unread.\n";
X	    }
X#endif
X	}
X      reask_unread:
X	in_char(u_prompt,'u');
X	putchar('\n') FLUSH;
X	setdef(buf,dfltcmd);
X#ifdef VERIFY
X	printcmd();
X#endif
X	if (*buf == 'h') {
X	    fputs(u_help_thread,stdout);
X#ifdef VERBOSE
X	    IF(verbose)
X	    {
X		if (ThreadedGroup)
X		    fputs("\
XType + to enter select thread mode using all the unread articles.\n\
X(The selected threads will be marked as unread and displayed as usual.)\n\
X",stdout) FLUSH;
X		fputs("\
XType a to mark all articles in this group as unread.\n\
XType n to change nothing.\n\
X",stdout) FLUSH;
X	    }
X	    ELSE
X#endif
X#ifdef TERSE
X	    {
X		if (ThreadedGroup)
X		    fputs("\
X+ to select threads from the unread.\n\
X",stdout) FLUSH;
X		fputs("\
Xa to mark all articles unread.\n\
Xn to change nothing.\n\
X",stdout) FLUSH;
X	    }
X#endif
X	    goto reask_unread;
X	}
X	else if (*buf == 'n' || *buf == 'q') {
X	    return AS_ASK;
X	}
X	else if (*buf == 't' && *dfltcmd == 't')
X	    follow_thread('u');
X	else if (*buf == 's' && *dfltcmd == 't') {
X	    follow_thread('U');
X	}
X	else if (*buf == 'a') {
X	    check_first(absfirst);
X	    for (i = absfirst; i <= lastart; i++) {
X		onemore(i);		/* mark as unread */
X	    }
X	    scan_all_roots = FALSE;
X	    count_roots(FALSE);
X	    if (art > lastart) {
X		first_art();
X	    }
X	}
X	else if (ThreadedGroup && *buf == '+') {
X	    *buf = 'U';
X	    goto select_threads;
X	}
X	else {
X	    fputs(hforhelp,stdout) FLUSH;
X	    settle_down();
X	    goto reask_unread;
X	}
X	return AS_NORM;
X    }
X    case '[':			/* goto parent article */
X    case '{':			/* goto thread's root article */
X	if (p_art) {
X	    if (!p_art->parent) {
X		if (p_art == p_articles + p_roots[p_art->root].articles) {
X		    register char *cp = (*buf=='['?"parent":"root");
X#ifdef VERBOSE
X		    IF(verbose)
X			fprintf(stdout,"\n\
XThere is no %s article prior to this one.\n",cp) FLUSH;
X		    ELSE
X#endif
X#ifdef TERSE
X			fprintf(stdout,"\nNo prior %s.\n",cp) FLUSH;
X#endif
X		    return AS_ASK;
X		}
X		*buf = '{';
X		p_art--;
X	    }
X	    else
X		p_art += p_art->parent;
X
X	    if (*buf == '{')
X		while (p_art->parent)
X		    p_art += p_art->parent;
X
X	    art = p_art->num;
X	    reread = TRUE;
X	    return AS_NORM;
X	}
Xnot_threaded:
X	if (ThreadedGroup) {
X#ifdef VERBOSE
X	    IF(verbose)
X		fputs("\nThis article is not threaded.\n",stdout) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("\nUnthreaded article.\n",stdout) FLUSH;
X#endif
X	    return AS_ASK;
X	}
Xgroup_unthreaded:
X#ifdef VERBOSE
X	IF(verbose)
X	    fputs("\nThis group is not threaded.\n",stdout) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    fputs("\nUnthreaded group.\n",stdout) FLUSH;
X#endif
X	return AS_ASK;
X    case ']':			/* goto child article */
X    case '}':			/* goto thread's leaf article */
X	if (p_art) {
X	    if (!(p_art++)->child_cnt) {
X		PACKED_ARTICLE *root_limit = upper_limit(p_art-1,FALSE);
X
X		if (p_art == root_limit) {
X#ifdef VERBOSE
X		    IF(verbose)
X			fputs("\n\
XThis is the last leaf in this tree.\n",stdout) FLUSH;
X		    ELSE
X#endif
X#ifdef TERSE
X			fputs("\nLast leaf.\n",stdout) FLUSH;
X#endif
X		    p_art--;
X		    return AS_ASK;
X		}
X		if (*buf == ']')
X		    *buf = '}';
X		else {
X		    while (++p_art != root_limit && p_art->parent)
X			;
X		    p_art--;
X		    *buf = ' ';
X		}
X	    }
X	    if( *buf == '}' )
X		while (p_art->child_cnt)
X		    p_art++;
X
X	    art = p_art->num;
X	    reread = TRUE;
X	    return AS_NORM;
X	}
X	goto not_threaded;
X    case 'T':
X	if (p_art) {
X	    sprintf(buf,"T%ld\t# %s",(long)p_roots[p_art->root].root_num,
X		subject_ptrs[p_art->subject]);
X	    fputs(buf,stdout);
X	    kf_append(buf);
X	    *buf = 'J';
X	    goto follow_threads;
X	}
X	goto not_threaded;
X    case 'K':
X	if (p_art) {
X	    /* first, write kill-subject command */
X	    (void)art_search(buf, (sizeof buf), TRUE);
X	    art = curr_art;
X	    p_art = curr_p_art;
X	    *buf = 'k';			/* then take care of any prior subjs */
X	    goto follow_threads;
X	}
X	goto normal_search;
X    case ',':		/* kill this node and all descendants */
X	mark_as_read();
X	*buf = 'K';
X    case 'k':		/* kill current subject # (e.g. [1]) */
X    case 'J':		/* Junk all nodes in this thread */
X	if (!ThreadedGroup) {
X	    *buf = 'k';
X	    goto normal_search;
X	}
Xfollow_threads:
X	follow_thread(*buf);
X	if (!reread && !toread[ng])
X	    return AS_CLEAN;
X	if (!reread && selected_root_cnt && !selected_count)
X	    goto select_threads;
X	return AS_NORM;
X    case 't':
X	carriage_return();
X#ifndef CLEAREOL
X	erase_eol();		/* erase the prompt */
X#else
X	if (erase_screen && can_home_clear)
X	    clear_rest();
X	else
X	    erase_eol();	/* erase the prompt */
X#endif /* CLEAREOL */
X	fflush(stdout);
X	page_line = 1;
X	p_art = curr_p_art;
X	entire_tree();
X	return AS_ASK;
X    case ':':			/* execute command on selected articles */
X	if (!ThreadedGroup) {
X	    goto group_unthreaded;
X	}
X	page_line = 1;
X	if (!use_selected())
X	    return AS_INP;
X	putchar('\n');
X	art = curr_art;
X	p_art = curr_p_art;
X	return AS_ASK;
X#endif /* USETHREADS */
X    case 'p':			/* find previous unread article */
X#ifdef USETHREADS
X	if (ThreadedGroup) {
X	    goto backtrack_threads;
X	}
X#endif
X	do {
X	    if (art <= firstart)
X		break;
X	    art--;
X#ifdef SERVER
X	} while (was_read(art) || nntpopen(art,GET_HEADER) == Nullfp);
X#else
X	} while (was_read(art) || artopen(art) == Nullfp);
X#endif
X#ifdef ARTSEARCH
X	srchahead = 0;
X#endif
X	return AS_NORM;
X    case 'P':		/* goto previous article */
X#ifdef USETHREADS
X	if (ThreadedGroup) {
Xbacktrack_threads:
X	    backtrack_thread( *buf );
X	    art++;		/* prepare for art-- below */
X	}
X#endif
X	if (art > absfirst)
X	    art--;
X	else {
X#ifdef VERBOSE
X	    IF(verbose)
X		fprintf(stdout,"\n\
XThere are no%s articles prior to this one.\n\
X",*buf=='P'?nullstr:" unread") FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fprintf(stdout,"\n\
XNo previous%s articles\n\
X",*buf=='P'?nullstr:" unread") FLUSH;
X#endif
X	    art = curr_art;
X#ifdef USETHREADS
X	    p_art = curr_p_art;
X#endif
X	    return AS_ASK;
X	}
X	reread = TRUE;
X#ifdef ARTSEARCH
X	srchahead = 0;
X#endif
X	return AS_NORM;
X    case '-':
X	if (recent_art >= 0) {
X#ifdef USETHREADS
X	    p_art = recent_p_art;
X#endif
X	    art = recent_art;
X	    reread = TRUE;
X#ifdef ARTSEARCH
X	    srchahead = -(srchahead != 0);
X#endif
X	    return AS_NORM;
X	}
X	else {
X	    exit_code = NG_MINUS;
X	    return AS_CLEAN;
X	}
X    case 'n':		/* find next unread article? */
X#ifdef USETHREADS
X	if (ThreadedGroup) {
X	    goto follow_threads;
X	}
X#endif
X	if (art > lastart) {
X	    if (!toread[ng])
X		return AS_CLEAN;
X	    art = firstart;
X	}
X#ifdef ARTSEARCH
X	else if (scanon && srchahead) {
X	    *buf = Ctl('n');
X	    goto normal_search;
X	}
X#endif
X	else
X	    art++;
X
X#ifdef ARTSEARCH
X	srchahead = 0;
X#endif
X	return AS_NORM;
X    case 'N':			/* goto next article */
X#ifdef USETHREADS
X	if (ThreadedGroup) {
X	    goto follow_threads;
X	}
X#endif
X	if (art > lastart)
X	    art = absfirst;
X	else
X	    art++;
X	if (art <= lastart)
X	    reread = TRUE;
X#ifdef ARTSEARCH
X	srchahead = 0;
X#endif
X	return AS_NORM;
X    case '$':
X	art = lastart+1;
X	forcelast = TRUE;
X#ifdef USETHREADS
X	p_art = Nullart;
X#endif
X#ifdef ARTSEARCH
X	srchahead = 0;
X#endif
X	return AS_NORM;
X    case '1': case '2': case '3':	/* goto specified article */
X    case '4': case '5': case '6':	/* or do something with a range */
X    case '7': case '8': case '9': case '.':
X	forcelast = TRUE;
X	switch (numnum()) {
X	case NN_INP:
X	    return AS_INP;
X	case NN_ASK:
X	    return AS_ASK;
X	case NN_REREAD:
X	    reread = TRUE;
X#ifdef ARTSEARCH
X	    if (srchahead)
X		srchahead = -1;
X#endif
X	    break;
X	case NN_NORM:
X	    if (was_read(art)) {
X#ifdef USETHREADS
X		first_art();
X#else
X		art = firstart;
X#endif
X		pad(just_a_sec/3);
X	    }
X	    else {
X		putchar('\n');
X		return AS_ASK;
X	    }
X	    break;
X	}
X	return AS_NORM;
X    case Ctl('k'):
X	edit_kfile();
X	return AS_ASK;
X#ifndef USETHREADS
X    case 'K':
X    case 'k':
X#endif
X    case Ctl('n'):	/* search for next article with same subject */
X#ifdef USETHREADS
X	if (ThreadedGroup) {
X	    goto follow_threads;
X	}
X#endif
X    case Ctl('p'):	/* search for previous article with same subject */
X#ifdef USETHREADS
X	if (ThreadedGroup) {
X	    goto backtrack_threads;
X	}
X#endif
X    case '/': case '?':
Xnormal_search:
X#ifdef ARTSEARCH
X    {		/* search for article by pattern */
X	char cmd = *buf;
X	
X	reread = TRUE;		/* assume this */
X	page_line = 1;
X	switch (art_search(buf, (sizeof buf), TRUE)) {
X	case SRCH_ERROR:
X	    art = curr_art;
X	    return AS_ASK;
X	case SRCH_ABORT:
X	    art = curr_art;
X	    return AS_INP;
X	case SRCH_INTR:
X#ifdef VERBOSE
X	    IF(verbose)
X		printf("\n(Interrupted at article %ld)\n",(long)art) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		printf("\n(Intr at %ld)\n",(long)art) FLUSH;
X#endif
X	    art = curr_art;
X			    /* restore to current article */
X	    return AS_ASK;
X	case SRCH_DONE:
X	    fputs("done\n",stdout) FLUSH;
X	    pad(just_a_sec/3);	/* 1/3 second */
X	    if (!srchahead) {
X		art = curr_art;
X		return AS_ASK;
X	    }
X#ifdef USETHREADS
X	    first_art();
X#else
X	    art = firstart;
X#endif
X	    reread = FALSE;
X	    return AS_NORM;
X	case SRCH_SUBJDONE:
X#ifdef UNDEF
X	    fputs("\n\n\n\nSubject not found.\n",stdout) FLUSH;
X	    pad(just_a_sec/3);	/* 1/3 second */
X#endif
X#ifdef USETHREADS
X	    first_art();
X#else
X	    art = firstart;
X#endif
X	    reread = FALSE;
X	    return AS_NORM;
X	case SRCH_NOTFOUND:
X	    fputs("\n\n\n\nNot found.\n",stdout) FLUSH;
X	    art = curr_art;  /* restore to current article */
X	    return AS_ASK;
X	case SRCH_FOUND:
X	    if (cmd == Ctl('n') || cmd == Ctl('p'))
X		oldsubject = TRUE;
X	    break;
X	}
X	return AS_NORM;
X    }
X#else
X    buf[1] = '\0';
X    notincl(buf);
X    return AS_ASK;
X#endif
X    case 'u':			/* unsubscribe from this newsgroup? */
X	rcchar[ng] = NEGCHAR;
X	return AS_CLEAN;
X    case 'M':
X#ifdef DELAYMARK
X	if (art <= lastart) {
X	    delay_unmark(art);
X	    printf("\nArticle %ld will return.\n",(long)art) FLUSH;
X	}
X#else
X	notincl("M");
X#endif
X	return AS_ASK;
X    case 'm':
X	if (art <= lastart) {
X	    unmark_as_read();
X	    printf("\nArticle %ld marked as still unread.\n",(long)art) FLUSH;
X	}
X	return AS_ASK;
X    case 'c':			/* catch up */
X      reask_catchup:
X#ifdef VERBOSE
X	IF(verbose)
X	    in_char("\nDo you really want to mark everything as read? [yn] ",
X		'C');
X	ELSE
X#endif
X#ifdef TERSE
X	    in_char("\nReally? [ynh] ", 'C');
X#endif
X	putchar('\n') FLUSH;
X	setdef(buf,"y");
X#ifdef VERIFY
X	printcmd();
X#endif
X	if (*buf == 'h') {
X#ifdef VERBOSE
X	    IF(verbose)
X		fputs("\
XType y or SP to mark all articles as read.\n\
XType n to leave articles marked as they are.\n\
XType u to mark everything read and unsubscribe.\n\
X",stdout) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("\
Xy or SP to mark all read.\n\
Xn to forget it.\n\
Xu to mark all and unsubscribe.\n\
X",stdout) FLUSH;
X#endif
X	    goto reask_catchup;
X	}
X	else if (*buf == 'n' || *buf == 'q') {
X	    return AS_ASK;
X	}
X	else if (*buf != 'y' && *buf != 'u') {
X	    fputs(hforhelp,stdout) FLUSH;
X	    settle_down();
X	    goto reask_catchup;
X	}
X	for (i = firstart; i <= lastart; i++) {
X	    oneless(i);		/* mark as read */
X	}
X#ifdef USETHREADS
X	selected_root_cnt = selected_count = 0;
X#endif
X#ifdef DELAYMARK
X	if (dmfp)
X	    yankback();
X#endif
X	if (*buf == 'u') {
X	    rcchar[ng] = NEGCHAR;
X	    return AS_CLEAN;
X	}
X#ifdef USETHREADS
X	p_art = Nullart;
X	selected_count = 0;
X#endif
X	art = lastart+1;
X	forcelast = FALSE;
X	return AS_NORM;
X    case 'Q':
X	exit_code = NG_ASK;
X	/* FALL THROUGH */
X    case 'q':			/* go back up to newsgroup level? */
X	return AS_CLEAN;
X    case 'j':
X	putchar('\n') FLUSH;
X	if (art <= lastart)
X	    mark_as_read();
X	return AS_ASK;
X    case 'h': {			/* help? */
X	int cmd;
X
X	if ((cmd = help_art()) > 0)
X	    pushchar(cmd);
X	return AS_ASK;
X    }
X    case '&':
X	if (switcheroo()) /* get rest of command */
X	    return AS_INP;	/* if rubbed out, try something else */
X	return AS_ASK;
X    case '#':
X#ifdef VERBOSE
X	IF(verbose)
X	    printf("\nThe last article is %ld.\n",(long)lastart) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    printf("\n%ld\n",(long)lastart) FLUSH;
X#endif
X	return AS_ASK;
X#ifdef USETHREADS
X    case '+':			/* enter thread selection mode */
X	if (ThreadedGroup) {
Xselect_threads:
X	    *buf = select_thread(*buf);
X	    if (*buf == 'q') {
X		putchar( '\n' ) FLUSH;
X		return AS_ASK;
X	    }
X	    if (*buf == 'Q') {
X		exit_code = NG_ASK;
X		return AS_CLEAN;
X	    }
X	    if (*buf == 'N' || !toread[ng])
X		return AS_CLEAN;
X	    return AS_NORM;
X	}
X	/* FALLTHROUGH */
X#endif
X    case '=': {			/* list subjects */
X	char tmpbuf[256];
X	ART_NUM oldart = art;
X	int cmd;
X	char *subjline = getval("SUBJLINE",Nullch);
X#ifndef CACHESUBJ
X	char *s;
X#endif
X
X	page_init();
X#ifdef CACHESUBJ
X	if (!subj_list)
X	    fetchsubj(art,TRUE,FALSE);
X#endif
X	for (i=firstart; i<=lastart && !int_count; i++) {
X#ifdef CACHESUBJ
X	    if (!was_read(i) &&
X	      (subj_list[OFFSET(i)] != Nullch || fetchsubj(i,FALSE,FALSE)) &&
X	      *subj_list[OFFSET(i)] ) {
X		sprintf(tmpbuf,"%5ld ", i);
X		if (subjline) {
X		    art = i;
X		    interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
X		}
X		else
X		    safecpy(tmpbuf + 6, subj_list[OFFSET(i)],
X			(sizeof tmpbuf) - 6);
X		if (cmd = print_lines(tmpbuf,NOMARKING)) {
X		    if (cmd > 0)
X			pushchar(cmd);
X		    break;
X		}
X	    }
X#else
X	    if (!was_read(i) && (s = fetchsubj(i,FALSE,FALSE)) && *s) {
X		sprintf(tmpbuf,"%5ld ", i);
X		if (subjline) {	/* probably fetches it again! */
X		    art = i;
X		    interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
X		}
X		else
X		    safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6);
X		if (cmd = print_lines(tmpbuf,NOMARKING)) {
X		    if (cmd > 0)
X			pushchar(cmd);
X		    break;
X		}
X	    }
X#endif
X	}
X	int_count = 0;
X	art = oldart;
X	return AS_ASK;
X    }
X    case '^':
X#ifdef USETHREADS
X	first_art();
X#else
X	art = firstart;
X#endif
X#ifdef ARTSEARCH
X	srchahead = 0;
X#endif
X	return AS_NORM;
X#if defined(CACHESUBJ) && defined(DEBUGGING)
X    case 'D':
X	printf("\nFirst article: %ld\n",(long)firstart) FLUSH;
X	if (!subj_list)
X	    fetchsubj(art,TRUE,FALSE);
X	if (subj_list != Null(char **)) {
X	    for (i=1; i<=lastart && !int_count; i++) {
X		if (subj_list[OFFSET(i)])
X		    printf("%5ld %c %s\n",
X			i, (was_read(i)?'y':'n'), subj_list[OFFSET(i)]) FLUSH;
X	    }
X	}
X	int_count = 0;
X	return AS_ASK;
X#endif
X    case 'v':
X	if (art <= lastart) {
X	    reread = TRUE;
X	    do_hiding = FALSE;
X	}
X	return AS_NORM;
X#ifdef ROTATION
X    case Ctl('x'):
X#endif
X    case Ctl('r'):
X#ifdef ROTATION
X	rotate = (*buf==Ctl('x'));
X#endif
X	if (art <= lastart)
X	    reread = TRUE;
X	return AS_NORM;
X#ifdef ROTATION
X    case 'X':
X	rotate = !rotate;
X	/* FALL THROUGH */
X#else
X    case Ctl('x'):
X    case 'x':
X    case 'X':
X	notincl("x");
X	return AS_ASK;
X#endif
X    case 'l': case Ctl('l'):		/* refresh screen */
X	if (art <= lastart) {
X	    reread = TRUE;
X	    clear();
X	    do_fseek = TRUE;
X	    artline = topline;
X	    if (artline < 0)
X		artline = 0;
X	}
X	return AS_NORM;
X    case 'b': case Ctl('b'):		/* back up a page */
X	if (art <= lastart) {
X	    ART_LINE target;
X
X	    reread = TRUE;
X	    clear();
X	    do_fseek = TRUE;
X	    target = topline - (LINES - 2);
X	    artline = topline;
X	    while (artline >= 0 && artline > target && vrdary(artline-1) >= 0)
X		artline--;
X	    topline = artline;
X	    if (artline < 0)
X		artline = 0;
X	}
X	return AS_NORM;
X    case '!':			/* shell escape */
X	if (escapade())
X	    return AS_INP;
X	return AS_ASK;
X    case 'C': {
X	cancel_article();
X	return AS_ASK;
X    }
X    case 'R':
X    case 'r': {			/* reply? */
X	reply();
X	return AS_ASK;
X    }
X    case 'F':
X    case 'f': {			/* followup command */
X	followup();
X	forcegrow = TRUE;		/* recalculate lastart */
X	return AS_ASK;
X    }
X    case '|':
X    case 'w': case 'W':
X    case 's': case 'S':		/* save command */
X    case 'e':			/* extract command */
X	if (save_article() == SAVE_ABORT)
X	    return AS_INP;
X	int_count = 0;
X	return AS_ASK;
X    case 'E':
X	if (uu_out != Nullfp) {
X	    uud_end();
X	}
X	return AS_ASK;
X#ifdef DELAYMARK
X    case 'Y':				/* yank back M articles */
X	yankback();
X#ifdef USETHREADS
X	first_art();
X#else
X	art = firstart;			/* from the beginning */
X#endif
X	return AS_NORM;			/* pretend nothing happened */
X#endif
X#ifdef STRICTCR
X    case '\n':
X	fputs(badcr,stdout) FLUSH;
X	return AS_ASK;
X#endif
X    default:
X	printf("\n%s",hforhelp) FLUSH;
X	settle_down();
X	return AS_ASK;
X    }
X}
X
X#ifdef MAILCALL
X/* see if there is any mail */
X
Xvoid
Xsetmail()
X{
X    if (! (mailcount++)) {
X	char *mailfile = filexp(getval("MAILFILE",MAILFILE));
X	
X	if (stat(mailfile,&filestat) < 0 || !filestat.st_size
X	    || filestat.st_atime > filestat.st_mtime)
X	    mailcall = nullstr;
X	else
X	    mailcall = getval("MAILCALL","(Mail) ");
X    }
X    mailcount %= 10;			/* check every 10 articles */
X}
X#endif
X
Xvoid
Xsetdfltcmd()
X{
X#ifdef USETHREADS
X    if (toread[ng] == unthreaded) {
X#else
X    if (!toread[ng]) {
X#endif
X	if (art > lastart)
X	    dfltcmd = "qnp";
X	else
X	    dfltcmd = "npq";
X    }
X    else {
X#ifdef USETHREADS
X	if (selected_root_cnt && !selected_count)
X	    dfltcmd = "+npq";
X	else
X# ifdef ARTSEARCH
X	if (!ThreadedGroup && srchahead)
X	    dfltcmd = "^Nnpq";
X	else
X# endif
X#else
X# ifdef ARTSEARCH
X	if (srchahead)
X	    dfltcmd = "^Nnpq";
X	else
X# endif
X#endif
X	    dfltcmd = "npq";
X	}
X}
SHAR_EOF
echo "File ng.c is complete"
chmod 0660 ng.c || echo "restore of ng.c fails"
echo "x - extracting ng.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > ng.h &&
X/* $Header: ng.h,v 4.3 85/05/01 11:44:29 lwall Exp $
X *
X * $Log:	ng.h,v $
X * Revision 4.3  85/05/01  11:44:29  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
XEXT ART_NUM art INIT(0);	/* current or prospective article # */
X
XEXT int checkcount INIT(0);	/* how many articles have we read */
X			/*   in the current newsgroup since */
X			/*   the last checkpoint? */
XEXT int docheckwhen INIT(20);	/* how often to do checkpoint */
X
X#ifdef MAILCALL
XEXT int mailcount INIT(0);			/* check for mail when 0 mod 10 */
X#endif
XEXT char *mailcall INIT(nullstr);
X
XEXT bool forcelast INIT(FALSE);			/* ought we show "End of newsgroup"? */
XEXT bool forcegrow INIT(FALSE);		/* do we want to recalculate size */
X				    /* of newsgroup, e.g. after posting? */
X
X#define NG_ERROR -1
X#define NG_NORM 0
X#define NG_ASK 1
X#define NG_MINUS 2
X
Xvoid    ng_init();
Xint	do_newsgroup();
Xint	art_switch();
X#ifdef MAILCALL
X    void	setmail();
X#endif
Xvoid	setdfltcmd();
SHAR_EOF
chmod 0660 ng.h || echo "restore of ng.h fails"
echo "x - extracting ngdata.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > ngdata.c &&
X/* $Header: ngdata.c,v 4.3.3.1 90/07/21 20:28:27 davison Trn $
X *
X * $Log:	ngdata.c,v $
X * Revision 4.3.3.1  90/07/21  20:28:27  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.10  90/04/14  22:05:15  sob
X * Removed redundant declaration of active_name
X * 
X * Revision 4.3.2.9  90/03/22  23:04:55  sob
X * Fixes provided by Wayne Davison <drivax!davison>
X * 
X * Revision 4.3.2.8  90/03/17  20:50:51  sob
X * Fixes provided by stewart at netxcom.iad-nxe.global-mis.dhl.com to handle
X * flaky transfers of the active file from the server.
X * 
X * Revision 4.3.2.7  90/03/17  17:11:08  sob
X * Added support for CNEWS active file flags.
X *
X * Revision 4.3.2.6  89/12/08  22:42:04  sob
X * Corrected typo in an #ifdef statement pointed out by
X * jik at pit-manager.mit.edu
X * 
X * Revision 4.3.2.5  89/11/28  01:51:14  sob
X * Removed redundant #include directive.
X * 
X * Revision 4.3.2.4  89/11/27  01:31:07  sob
X * Altered NNTP code per ideas suggested by Bela Lubkin
X * <filbo at gorn.santa-cruz.ca.us>
X * 
X * Revision 4.3.2.3  89/11/08  02:41:40  sob
X * Removed unneeded subroutine.
X * 
X * Revision 4.3.2.2  89/11/08  02:24:31  sob
X * Integrated modifications from other RRN patches colleceted from USENET
X * 
X * Revision 4.3.2.1  89/11/06  00:42:43  sob
X * Added RRN support from NNTP 1.5
X * 
X * Revision 4.3  85/05/01  11:44:38  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "ndir.h"
X#include "rcstuff.h"
X#include "rn.h"
X#include "intrp.h"
X#include "final.h"
X#include "rcln.h"
X#include "util.h"
X#ifdef SERVER
X#include "server.h"
X#endif
X#include "INTERN.h"
X#include "ngdata.h"
X
Xvoid
Xngdata_init()
X{
X#ifdef SERVER
X    char ser_line[256];
X    int entries;
X#endif
X    char *cp;
X
X/* The following is only for systems that do not zero globals properly */
X#ifdef ZEROGLOB
X# ifdef CACHEFIRST
X    for (i=0; i<MAXRCLINE; i++)
X	abs1st[i] = 0;
X# endif
X#endif	/* ZEROGLOB */
X
X    /* open the active file */
X
X#ifdef SERVER
X
X#ifdef USETHREADS
X    if (use_threads) {
X	cp = filexp(ACTIVE2);
X	actfp = fopen(cp,"r");
X	if (actfp == Nullfp) {
X	    printf(cantopen,cp) FLUSH;
X	    finalize(1);
X	}
X	return;
X    }
X#endif
X
X    put_server("LIST");		/* tell server we want the active file */
X    get_server(ser_line, sizeof(ser_line));
X    if (*ser_line != CHAR_OK) {		/* and then see if that's ok */
X	fprintf(stdout, "Can't get active file from server: \n%s\n", ser_line);
X	finalize(1);
X    }
X
X    cp = filexp("/tmp/rrnact.%$");	/* make a temporary name */
X    strcpy(active_name, cp);
X    actfp = fopen(active_name, "w+");	/* and get ready */
X    if (actfp == Nullfp) {
X	printf(cantopen,active_name) FLUSH;
X	finalize(1);
X    }
X
X    entries = 0;
X    while (1) {
X	if (get_server(ser_line, sizeof(ser_line)) < 0) {
X	    printf("Can't get active file from server:\ntransfer failed after %d entries\n", entries);
X	    finalize(1);
X	}
X	if (ser_line[0] == '.')		/* while there's another line */
X		break;			/* get it and write it to */
X	entries++;
X	fputs(ser_line, actfp);
X	putc('\n', actfp);
X    }
X
X    fseek(actfp,0L,0);		/* just get to the beginning */
X
X#else /* not SERVER */
X
X#ifdef USETHREADS
X    if (use_threads)
X	cp = filexp(ACTIVE2);
X    else
X#endif
X	cp = filexp(ACTIVE);
X    actfp = fopen(cp,"r");
X    if (actfp == Nullfp) {
X	printf(cantopen,cp) FLUSH;
X	finalize(1);
X    }
X#endif
X}
X
X/* find the maximum article number of a newsgroup */
X
XART_NUM
Xgetngsize(num)
Xregister NG_NUM num;
X{
X    register int len;
X    register char *nam;
X    char tmpbuf[80];
X    ART_POS oldsoft;
X
X    nam = rcline[num];
X    len = rcnums[num] - 1;
X    softtries++;
X#ifdef DEBUGGING
X    if (debug & DEB_SOFT_POINTERS)
X	printf("Softptr = %ld\n",(long)softptr[num]) FLUSH;
X#endif
X    oldsoft = softptr[num];
X    if ((softptr[num] = findact(tmpbuf, nam, len, (long)oldsoft)) >= 0) {
X	if (softptr[num] != oldsoft) {
X	    softmisses++;
X	    writesoft = TRUE;
X	}
X    }
X    else {
X	softptr[num] = 0;
X	if (rcchar[num] == ':')		/* unsubscribe quietly */
X	    rcchar[num] = NEGCHAR;
X	return TR_BOGUS;		/* well, not so quietly, actually */
X    }
X	
X#ifdef DEBUGGING
X    if (debug & DEB_SOFT_POINTERS) {
X	printf("Should be %ld\n",(long)softptr[num]) FLUSH;
X    }
X#endif
X#ifdef MININACT
X    {
X	register char *s, ch;
X	ART_NUM tmp;
X
X	for (s=tmpbuf+len+1; isdigit(*s); s++) ;
X	if (tmp = atol(s))
X#ifdef CACHEFIRST
X	    abs1st[num] = tmp;
X#else
X	    abs1st = tmp;
X#endif
X	if (!in_ng) {
X	    for (s++; isdigit(*s); s++) ;
X	    while (isspace(*s)) s++;
X	    ch = *s;
X#ifdef USETHREADS
X	    if (isupper(ch)) {
X		ch = tolower(ch);
X		ThreadedGroup = FALSE;
X	    } else
X		ThreadedGroup = use_threads;
X#endif
X	    switch (ch) {
X	    case 'n': moderated = getval("NOPOSTRING"," (no posting)"); break;
X	    case 'm': moderated = getval("MODSTRING", " (moderated)"); break;
X	    /* This shouldn't even occur.  What are we doing in a non-existent
X	       group?  Disallow it. */
X	    case 'x': return TR_BOGUS;
X	    /* what should be done about refiled groups?  rn shouldn't even
X	       be in them (ie, if sci.aquaria is refiled to rec.aquaria, then
X	       get the news there) */
X	    case '=': return TR_BOGUS;
X	    default: moderated = nullstr;
X	    }
X	}
X    }
X#endif
X    return atol(tmpbuf+len+1);
X}
X
XACT_POS
Xfindact(outbuf,nam,len,suggestion)
Xchar *outbuf;
Xchar *nam;
Xint len;
Xlong suggestion;
X{
X    ACT_POS retval;
X
X    fseek(actfp,100000L,1);	/* hopefully this forces a reread */
X    if (suggestion == 0L || fseek(actfp,suggestion,0) < 0 ||
X      fgets(outbuf,80,actfp) == Nullch ||
X      outbuf[len] != ' ' ||
X      strnNE(outbuf,nam,len)) {
X#ifdef DEBUGGING
X	if (debug & DEB_SOFT_POINTERS)
X	    printf("Missed, looking for %s in %sLen = %d\n",nam,outbuf,len)
X	      FLUSH;
X#endif
X	fseek(actfp,0L,0);
X#ifndef lint
X	retval = (ACT_POS)ftell(actfp);
X#else
X	retval = Null(ACT_POS);
X#endif /* lint */
X	while (fgets(outbuf,80,actfp) != Nullch) {
X	    if (outbuf[len] == ' ' && strnEQ(outbuf,nam,len))
X		return retval;
X#ifndef lint
X	    retval = (ACT_POS) ftell(actfp);
X#endif /* lint */
X	}
X	return (ACT_POS) -1;		/* well, not so quietly, actually */
X    }
X    else
X#ifndef lint
X	return (ACT_POS) suggestion;
X#else
X	return retval;
X#endif /* lint */
X    /*NOTREACHED*/
X}
X
X/* determine the absolutely first existing article number */
X#ifdef SERVER
XART_NUM
Xgetabsfirst(ngnum,ngsize)
Xregister NG_NUM ngnum;
XART_NUM ngsize;
X{
X    register ART_NUM a1st;
X#ifndef MININACT
X    char ser_line[256];
X    ART_NUM x,y;
X#endif
X
X#ifdef CACHEFIRST
X    if (a1st = abs1st[ngnum])
X	return a1st;
X#endif
X#ifdef MININACT
X    getngsize(ngnum);
X# ifdef CACHEFIRST
X    return abs1st[ngnum];
X# else
X    return abs1st;
X# endif
X#else
X    sprintf(cp,"GROUP %s",rcline[ngnum]);
X    put_server(cp);
X    if (get_server(ser_line, sizeof(ser_line)) < 0) {
X	fprintf(stderr, "rrn: Unexpected close of server socket.\n");
X	finalize(1);
X    }
X    if (*ser_line != CHAR_OK) {		/* and then see if that's ok */
X	a1st = ngsize+1;		/* nothing there */
X    }
X    (void) sscanf(ser_line,"%d%d%d",&x,&y,&a1st);
X# ifdef CACHEFIRST
X    abs1st[ngnum] = a1st;
X# endif
X    return a1st;
X#endif
X}
X/* we already know the lowest article number with NNTP */
XART_NUM
Xgetngmin(dirname,floor)
Xchar *dirname;
XART_NUM floor;
X{
X    return(floor);
X}
X#else
XART_NUM
Xgetabsfirst(ngnum,ngsize)
Xregister NG_NUM ngnum;
XART_NUM ngsize;
X{
X    register ART_NUM a1st;
X#ifndef MININACT
X    char dirname[MAXFILENAME];
X#endif
X
X#ifdef CACHEFIRST
X    if (a1st = abs1st[ngnum])
X	return a1st;
X#endif
X#ifdef MININACT
X    getngsize(ngnum);
X# ifdef CACHEFIRST
X    return abs1st[ngnum];
X# else
X    return abs1st;
X# endif
X#else /* not MININACT */
X    sprintf(dirname,"%s/%s",spool,getngdir(rcline[ngnum]));
X    a1st = getngmin(dirname,0L);
X    if (!a1st)				/* nothing there at all? */
X	a1st = ngsize+1;		/* aim them at end of newsgroup */
X# ifdef CACHEFIRST
X    abs1st[ngnum] = a1st;
X# endif
X    return a1st;
X#endif /* MININACT */
X}
X
X/* scan a directory for minimum article number greater than floor */
X
XART_NUM
Xgetngmin(dirname,floor)
Xchar *dirname;
XART_NUM floor;
X{
X    register DIR *dirp;
X    register struct DIRTYPE *dp;
X    register ART_NUM min = 1000000;
X    register ART_NUM maybe;
X    register char *p;
X    char tmpbuf[128];
X    
X    dirp = opendir(dirname);
X    if (!dirp)
X	return 0;
X    while ((dp = readdir(dirp)) != Null(struct DIRTYPE *)) {
X	if ((maybe = atol(dp->d_name)) < min && maybe > floor) {
X	    for (p = dp->d_name; *p; p++)
X		if (!isdigit(*p))
X		    goto nope;
X	    if (*dirname == '.' && !dirname[1])
X		stat(dp->d_name, &filestat);
X	    else {
X		sprintf(tmpbuf,"%s/%s",dirname,dp->d_name);
X		stat(tmpbuf, &filestat);
X	    }
X	    if (! (filestat.st_mode & S_IFDIR))
X		min = maybe;
X	}
X      nope:
X	;
X    }
X    closedir(dirp);
X    return min==1000000 ? 0 : min;
X}
X#endif
SHAR_EOF
chmod 0660 ngdata.c || echo "restore of ngdata.c fails"
echo "x - extracting ngdata.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > ngdata.h &&
X/* $Header: ngdata.h,v 4.3.3.1 90/06/20 22:38:50 davison Trn $
X *
X * $Log:	ngdata.h,v $
X * Revision 4.3.3.1  90/06/20  22:38:50  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.1  89/11/06  00:41:21  sob
X * Added RRN support from NNTP 1.5
X * 
X * Revision 4.3  85/05/01  11:44:48  lwall
X * added to local RCS
X * 
X * Revision 4.3  85/05/01  11:44:48  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
XEXT FILE *actfp INIT(Nullfp);	/* the active file */
XEXT bool writesoft INIT(FALSE);	/* rewrite the soft pointer file? */
XEXT int softtries INIT(0), softmisses INIT(0);
X
X#ifdef SERVER
X    EXT char active_name[256];
X#endif
X
X#ifdef CACHEFIRST
X    EXT ART_NUM abs1st[MAXRCLINE];	/* 1st real article in newsgroup */
X#else
X# ifdef MININACT
X    EXT ART_NUM abs1st INIT(0);
X# endif
X#endif
X
XEXT char *moderated;
X#ifdef USETHREADS
XEXT bool ThreadedGroup;
X#endif
X
Xvoid	ngdata_init();
XART_NUM	getngsize();
XACT_POS findact();
XART_NUM	getabsfirst();
XART_NUM	getngmin();
SHAR_EOF
chmod 0660 ngdata.h || echo "restore of ngdata.h fails"
echo "x - extracting ngsrch.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > ngsrch.c &&
X/* $Header: ngsrch.c,v 4.3 85/05/01 11:44:51 lwall Exp $
X *
X * $Log:	ngsrch.c,v $
X * Revision 4.3  85/05/01  11:44:51  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "rcstuff.h"
X#include "final.h"
X#include "search.h"
X#include "rn.h"
X#include "util.h"
X#include "term.h"
X#include "rcln.h"
X#include "INTERN.h"
X#include "ngsrch.h"
X
X#ifdef NGSORONLY
X    COMPEX ngcompex;
X#endif
X
Xvoid
Xngsrch_init()
X{
X#ifdef ZEROGLOB
X    init_compex(&ngcompex);
X#endif	/* ZEROGLOB */
X    ;
X}
X
X#ifdef NGSEARCH
Xint
Xng_search(patbuf,get_cmd)
Xchar *patbuf;				/* if patbuf != buf, get_cmd must */
Xint get_cmd;				/*   be set to FALSE!!! */
X{
X    char *pattern;			/* unparsed pattern */
X    register char cmdchr = *patbuf;	/* what kind of search? */
X    register char *s;
X    bool backward = cmdchr == '?';	/* direction of search */
X
X    int_count = 0;
X    if (get_cmd && buf == patbuf)
X	if (!finish_command(FALSE))		/* get rest of command */
X	    return NGS_ABORT;
X    for (pattern = patbuf+1; *pattern == ' '; pattern++) ;
X    if (*pattern) {
X	ng_doread = FALSE;
X    }
X    s = rindex(pattern,cmdchr);
X    if (s != Nullch && *(s-1) != '\\') {
X	*s++ = '\0';
X	if (index(s,'r') != Nullch)
X	    ng_doread = TRUE;
X    }
X    if ((s = ng_comp(&ngcompex,pattern,TRUE,TRUE)) != Nullch) {
X					/* compile regular expression */
X	printf("\n%s\n",s) FLUSH;
X	return NGS_ABORT;
X    }
X    fputs("\nSearching...",stdout) FLUSH;	/* give them something to read */
X    fflush(stdout);
X    for (;;) {
X	if (int_count) {
X	    int_count = 0;
X	    return NGS_INTR;
X	}
X	if (backward) {
X	    if (ng > 0)
X		--ng;
X	    else
X		ng = nextrcline;
X	}
X	else {
X	    if (ng >= nextrcline)
X		ng = 0;
X	    else
X		++ng;
X	}
X	if (ng == current_ng)
X	    return NGS_NOTFOUND;
X	if (ng == nextrcline || toread[ng] < TR_NONE || !ng_wanted())
X	    continue;
X	if (toread[ng] == TR_NONE)
X	    set_toread(ng);
X	
X	if (toread[ng] > TR_NONE)
X	    return NGS_FOUND;
X	else if (toread[ng] == TR_NONE)
X	    if (ng_doread)
X		return NGS_FOUND;
X	    else
X		printf("\n[0 unread in %s--skipping]",rcline[ng]) FLUSH;
X    }
X}
X
Xbool
Xng_wanted()
X{
X    return execute(&ngcompex,rcline[ng]) != Nullch;
X}
X#endif
X
X#ifdef NGSORONLY
Xchar *
Xng_comp(compex,pattern,RE,fold)
XCOMPEX *compex;
Xchar *pattern;
Xbool RE;
Xbool fold;
X{
X    char ng_pattern[128];
X    register char *s = pattern, *d = ng_pattern;
X
X    if (!*s)
X	return Nullch;			/* reuse old pattern */
X    for (; *s; s++) {
X	if (*s == '.') {
X	    *d++ = '\\';
X	    *d++ = *s;
X	}
X	else if (*s == '?') {
X	    *d++ = '.';
X	}
X	else if (*s == '*') {
X	    *d++ = '.';
X	    *d++ = *s;
X	}
X	else if (strnEQ(s,"all",3)) {
X	    *d++ = '.';
X	    *d++ = '*';
X	    s += 2;
X	}
X	else
X	    *d++ = *s;
X    }
X    *d = '\0';
X    return compile(compex,ng_pattern,RE,fold);
X}
X#endif
X
SHAR_EOF
chmod 0660 ngsrch.c || echo "restore of ngsrch.c fails"
echo "x - extracting ngsrch.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > ngsrch.h &&
X/* $Header: ngsrch.h,v 4.3 85/05/01 11:44:56 lwall Exp $
X *
X * $Log:	ngsrch.h,v $
X * Revision 4.3  85/05/01  11:44:56  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#ifdef NGSEARCH
X#define NGS_ABORT 0
X#define NGS_FOUND 1
X#define NGS_INTR 2
X#define NGS_NOTFOUND 3
X
XEXT bool ng_doread INIT(FALSE);		/* search read newsgroups? */
X#endif
X
Xvoid	ngsrch_init();
X#ifdef NGSEARCH 
X    int		ng_search();
X    bool	ng_wanted();
X#endif
X#ifdef NGSORONLY
X    char	*ng_comp();
X#endif
SHAR_EOF
chmod 0660 ngsrch.h || echo "restore of ngsrch.h fails"
echo "x - extracting ngstuff.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > ngstuff.c &&
X/* $Header: ngstuff.c,v 4.3.3.1 90/07/21 20:29:12 davison Trn $
X *
X * $Log:	ngstuff.c,v $
X * Revision 4.3.3.1  90/07/21  20:29:12  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.2  90/04/14  19:40:02  sob
X * Fixed small syntax problem that generates errors with particular C
X * preprocessors.
X *
X * Revision 4.3.1.2  85/05/10  14:31:52  lwall
X * Prevented "Junked" or "Marked unread" when no state change.
X * 
X * Revision 4.3.1.1  85/05/10  11:36:45  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:45:03  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "term.h"
X#include "util.h"
X#include "ng.h"
X#include "bits.h"
X#include "intrp.h"
X#include "cheat.h"
X#include "head.h"
X#include "final.h"
X#include "sw.h"
X#ifdef USETHREADS
X#include "rthreads.h"
X#include "rn.h"
X#include "rcstuff.h"
X#endif
X#include "uudecode.h"
X#include "INTERN.h"
X#include "ngstuff.h"
X
Xvoid
Xngstuff_init()
X{
X    ;
X}
X
X/* do a shell escape */
X
Xint
Xescapade()
X{
X    register char *s;
X    bool interactive = (buf[1] == FINISHCMD);
X    bool docd;
X    char whereiam[256];
X
X    if (!finish_command(interactive))	/* get remainder of command */
X	return -1;
X    s = buf+1;
X    docd = *s != '!';
X    if (!docd) {
X	s++;
X    }
X    else {
X	getwd(whereiam);
X	if (chdir(cwd)) {
X	    printf(nocd,cwd) FLUSH;
X	    sig_catcher(0);
X	}
X    }
X    while (*s == ' ') s++;
X					/* skip leading spaces */
X    interp(cmd_buf, (sizeof cmd_buf), s);/* interpret any % escapes */
X    resetty();				/* make sure tty is friendly */
X    doshell(Nullch,cmd_buf);	/* invoke the shell */
X    noecho();				/* and make terminal */
X    crmode();				/*   unfriendly again */
X    if (docd) {
X	if (chdir(whereiam)) {
X	    printf(nocd,whereiam) FLUSH;
X	    sig_catcher(0);
X	}
X    }
X#ifdef MAILCALL
X    mailcount = 0;			/* force recheck */
X#endif
X    return 0;
X}
X
X/* process & command */
X
Xint
Xswitcheroo()
X{
X    if (!finish_command(TRUE)) /* get rest of command */
X	return -1;	/* if rubbed out, try something else */
X    if (!buf[1])
X	pr_switches();
X#ifdef PUSHBACK
X    else if (buf[1] == '&') {
X	if (!buf[2]) {
X	    page_init();
X	    show_macros();
X	}
X	else {
X	    char tmpbuf[LBUFLEN];
X	    register char *s;
X
X	    for (s=buf+2; isspace(*s); s++);
X	    mac_line(s,tmpbuf,(sizeof tmpbuf));
X	}
X    }
X#endif
X    else {
X	bool docd = (instr(buf,"-d") != Nullch);
X 	char whereami[256];
X 
X	if (docd)
X	    getwd(whereami);
X	sw_list(buf+1);
X	if (docd) {
X	    cwd_check();
X	    if (chdir(whereami)) {		/* -d does chdirs */
X		printf(nocd,whereami) FLUSH;
X		sig_catcher(0);
X	    }
X	}
X    }
X    return 0;
X}
X
X/* process range commands */
X
Xint
Xnumnum()
X{
X    ART_NUM min, max;
X    char *cmdlst = Nullch;
X    register char *s, *c;
X    ART_NUM oldart = art;
X    char tmpbuf[LBUFLEN];
X    bool justone = TRUE;		/* assume only one article */
X
X    perform_cnt = 0;
X    if (!finish_command(TRUE))	/* get rest of command */
X	return NN_INP;
X	if (lastart < 1) {
X	    fputs("\nNo articles\n",stdout) FLUSH;
X	    return NN_ASK;
X	}
X#ifdef ARTSRCH
X    if (srchahead)
X	srchahead = -1;
X#endif
X    for (s=buf; *s && (isdigit(*s) || index(" ,-.$",*s)); s++)
X	if (!isdigit(*s))
X	    justone = FALSE;
X    if (*s) {
X	cmdlst = savestr(s);
X	justone = FALSE;
X    }
X    else if (!justone)
X	cmdlst = savestr("m");
X    *s++ = ',';
X    *s = '\0';
X    safecpy(tmpbuf,buf,LBUFLEN);
X    for (s = tmpbuf; c = index(s,','); s = ++c) {
X	*c = '\0';
X	if (*s == '.')
X	    min = oldart;
X	else
X	    min = atol(s);
X#ifdef USETHREADS
X	if (min<absfirst && justone) {
X	    int r;
X
X	    /* Check if this is a root number */
X	    for (r = 0; r < total.root; r++) {
X		if (p_roots[r].root_num == min) {
X		    p_art = p_articles + p_roots[r].articles;
X		    art = p_art->num;
X		    if (p_art->subject == -1) {
X			follow_thread('N');
X		    }
X		    return NN_REREAD;
X		}
X	    }
X	}
X#endif
X	if (min<absfirst) {		/* make sure it is reasonable */
X	    min = absfirst;
X	    printf("(First article is %ld)\n",(long)absfirst) FLUSH;
X	    pad(just_a_sec/3);
X	}
X	if ((s=index(s,'-')) != Nullch) {
X	    s++;
X	    if (*s == '$')
X		max = lastart;
X	    else if (*s == '.')
X		max = oldart;
X	    else
X		max = atol(s);
X	}
X	else
X	    max = min;
X	if (max>lastart) {
X	    max = lastart;
X	    if (min > max)
X		min = max;
X	    printf("(Last article is %ld)\n",(long)lastart) FLUSH;
X	    pad(just_a_sec/3);
X	}
X	if (max < min) {
X	    fputs("\nBad range\n",stdout) FLUSH;
X	    if (cmdlst)
X		free(cmdlst);
X	    return NN_ASK;
X	}
X	if (justone) {
X	    art = min;
X	    return NN_REREAD;
X	}
X	check_first(min);
X	for (art=min; art<=max; art++) {
X	    if (perform(cmdlst,TRUE)) {
X#ifdef VERBOSE
X		IF(verbose)
X		    printf("\n(Interrupted at article %ld)\n",(long)art)
X		      FLUSH;
X		ELSE
X#endif
X#ifdef TERSE
X		    printf("\n(Intr at %ld)\n",(long)art) FLUSH;
X#endif
X		if (cmdlst)
X		    free(cmdlst);
X		return NN_ASK;
X	    }
X	}
X    }
X    art = oldart;
X    if (cmdlst)
X	free(cmdlst);
X    return NN_NORM;
X}
X
X#ifdef USETHREADS
Xint
Xuse_selected()
X{
X    PACKED_ARTICLE *root_limit;
X    register char *s, ch;
X    register int r;
X    char *cmdstr;
X    int ret = 1, orig_root_cnt = selected_root_cnt;
X
X    if (!finish_command(TRUE))	/* get rest of command */
X	return 0;
X    if (!(ch = buf[1]))
X	return -1;
X    cmdstr = savestr(buf+1);
X
X    perform_cnt = 0;
X    page_line = 1;
X
X    /* Multiple commands and commands that operate on individual articles
X    ** use the article loop.
X    */
X    if (strlen(cmdstr) > 1 || index("ejmMsSwW|=", ch)) {
X	bool want_unread = (unread_selector || ch == 'm');
X
X	for (r = 0; r < total.root; r++) {
X	    if (scan_all_roots
X	     || (!orig_root_cnt&&root_article_cnts[r]&&!(selected_roots[r]&4))
X	     || (selected_roots[r] & (unread_selector+1))) {
X		p_art = p_articles + p_roots[r].articles;
X		root_limit = upper_limit( p_art, 0 );
X		for (; p_art < root_limit; p_art++) {
X		    art = p_art->num;
X		    if (p_art->subject != -1
X		     && (!was_read(art) ^ want_unread)) {
X			if (perform(cmdstr, TRUE)) {
X			    fputs("\nInterrupted\n", stdout) FLUSH;
X			    goto break_out;
X			}
X		    }
X		    if (p_art == Nullart)
X			break;
X		}/* for all articles */
X	    }/* if selected */
X	}/* for all threads */
X    }				/* other commands get the root loop */
X    else if (ch == '+' || ch == '-' || ch == 'J' || ch == 'T' || ch == 't') {
X	for (r = 0; r < total.root; r++) {
X	    if (scan_all_roots
X	     || (!orig_root_cnt&&root_article_cnts[r]&&!(selected_roots[r]&4))
X	     || (selected_roots[r] & (unread_selector+1))) {
X		if (mode != 't' && ch != 't') {
X		    printf("T%-5ld ", (long)p_roots[r].root_num);
X		}
X		p_art = p_articles + p_roots[r].articles;
X		art = p_art->num;
X		if (perform(cmdstr, FALSE)) {
X		    fputs("\nInterrupted\n", stdout) FLUSH;
X		    goto break_out;
X		}
X#ifdef VERBOSE
X		IF(verbose)
X		    if (mode != 't' && ch != 't' && ch != 'T')
X			putchar('\n') FLUSH;
X#endif
X	    }
X	}
X    }
X    else if (ch == 'E') {	/* one command needs no looping at all */
X	if (uu_out != Nullfp) {
X	    uud_end();
X	} else {
X	    ret = 2;
X	}
X    }
X    else {
X	printf("???%s\n",cmdstr);
X	ret = -1;
X    }
X  break_out:
X    free(cmdstr);
X    return ret;
X}
X#endif
X
Xint
Xperform(cmdlst,toplevel)
Xregister char *cmdlst;
Xint toplevel;
X{
X    register int ch;
X    
X    if (toplevel) {
X	printf("%-6ld ",art);
X	fflush(stdout);
X    }
X    perform_cnt++;
X    for (; ch = *cmdlst; cmdlst++) {
X	if (isspace(ch) || ch == ':')
X	    continue;
X	if (ch == 'j') {
X	    if (!was_read(art)) {
X		mark_as_read();
X#ifdef VERBOSE
X		IF(verbose)
X		    fputs("\tJunked",stdout);
X#endif
X	    }
X	}
X#ifdef USETHREADS
X	else if (ch == '+') {
X	    find_article(art);
X	    if (p_art && !(selected_roots[p_art->root] & (unread_selector+1))) {
X		selected_roots[p_art->root] |= (unread_selector+1);
X		selected_root_cnt++;
X		if (mode == 't') {
X		    selected_count += root_article_cnts[p_art->root];
X		} else {
X		    selected_count += count_one_root(p_art->root);
X#ifdef VERBOSE
X		    IF(verbose)
X			fputs("\tSelected",stdout);
X#endif
X		}
X	    }
X	}
X	else if (ch == '-') {
X	    find_article(art);
X	    if (p_art && selected_root_cnt
X	     && (selected_roots[p_art->root] & (unread_selector+1))) {
X		selected_roots[p_art->root] &= ~(unread_selector+1);
X		selected_root_cnt--;
X		if (mode == 't') {
X		    selected_count -= root_article_cnts[p_art->root];
X		} else {
X		    selected_count -= count_one_root(p_art->root);
X#ifdef VERBOSE
X		    IF(verbose)
X			fputs("\tDeselected",stdout);
X#endif
X		}
X	    }
X	}
X	else if (ch == 't') {
X	    find_article(art);
X	    entire_tree();
X	}
X	else if (ch == 'J' || ch == 'T') {
X	    char tmpbuf[128];
X	    ART_NUM oldart = art;
X
X	    find_article(art);
X	    if (p_art) {
X		if (ch == 'T') {
X		    sprintf(tmpbuf,"T%ld\t# %s",
X			(long)p_roots[p_art->root].root_num,
X			subject_ptrs[p_art->subject]);
X		    fputs(tmpbuf,stdout);
X		    kf_append(tmpbuf);
X		}
X		follow_thread('J');
X		art = oldart;
X	    }
X	}
X#endif
X	else if (ch == 'm') {
X	    if (was_read(art)) {
X		unmark_as_read();
X#ifdef VERBOSE
X		IF(verbose)
X		    fputs("\tMarked unread",stdout);
X#endif
X	    }
X	}
X	else if (ch == 'M') {
X#ifdef DELAYMARK
X	    delay_unmark(art);
X#ifdef VERBOSE
X	    IF(verbose)
X		fputs("\tWill return",stdout);
X#endif
X#else
X	    notincl("M");
X	    return -1;
X#endif
X	}
X	else if (ch == '=') {
X	    printf("\t%s",fetchsubj(art,FALSE,FALSE));
X#ifdef VERBOSE
X	    IF(verbose)
X		;
X	    ELSE
X#endif
X		putchar('\n') FLUSH;		/* ghad! */
X	}
X	else if (ch == 'C') {
X#ifdef ASYNC_PARSE
X	    printf("\t%sancelled",(cancel_article() ? "Not c" : "C"));
X#else
X	    notincl("C");
X	    return -1;
X#endif
X	}
X	else if (ch == '%') {
X#ifdef ASYNC_PARSE
X	    char tmpbuf[512];
X
X	    if (one_command)
X		interp(tmpbuf, (sizeof tmpbuf), cmdlst);
X	    else
X		cmdlst = dointerp(tmpbuf, (sizeof tmpbuf), cmdlst, ":") - 1;
X	    perform_cnt--;
X	    if (perform(tmpbuf,FALSE))
X		return -1;
X#else
X	    notincl("%");
X	    return -1;
X#endif
X	}
X	else if (index("!&sSwWe|",ch)) {
X	    if (one_command)
X		strcpy(buf,cmdlst);
X	    else
X		cmdlst = cpytill(buf,cmdlst,':') - 1;
X	    /* we now have the command in buf */
X	    if (ch == '!') {
X		escapade();
X#ifdef VERBOSE
X		IF(verbose)
X		    fputs("\tShell escaped",stdout);
X#endif
X	    }
X	    else if (ch == '&') {
X		switcheroo();
X#ifdef VERBOSE
X		IF(verbose)
X		    if (buf[1] && buf[1] != '&')
X			fputs("\tSwitched",stdout);
X#endif
X	    }
X	    else {
X		putchar('\t');
X		save_article();
X#ifdef VERBOSE
X		IF(verbose)
X		    ;
X		ELSE
X#endif
X		    putchar('\n') FLUSH;
X	    }
X	}
X	else {
X	    printf("\t???%s\n",cmdlst);
X	    return -1;
X	}
X#ifdef VERBOSE
X	fflush(stdout);
X#endif
X	if (one_command)
X	    break;
X    }
X    if (toplevel) {
X#ifdef VERBOSE
X	IF(verbose)
X	    putchar('\n') FLUSH;
X#endif
X    }
X    if( int_count ) {
X	int_count = 0;
X	return -1;
X    }
X    return 0;
X}
SHAR_EOF
chmod 0660 ngstuff.c || echo "restore of ngstuff.c fails"
echo "x - extracting ngstuff.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > ngstuff.h &&
X/* $Header: ngstuff.h,v 4.3.3.1 90/06/20 22:39:07 davison Trn $
X *
X * $Log:	ngstuff.h,v $
X * Revision 4.3.3.1  90/06/20  22:39:07  davison
X * Initial Trn Release
X * 
X * Revision 4.3  85/05/01  11:45:12  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#define NN_NORM 0
X#define NN_INP 1
X#define NN_REREAD 2
X#define NN_ASK 3
X
XEXT bool one_command INIT(FALSE);	/* no ':' processing in perform() */
X
Xvoid	ngstuff_init();
Xint	escapade();
Xint	switcheroo();
Xint	numnum();
Xint	perform();
SHAR_EOF
chmod 0660 ngstuff.h || echo "restore of ngstuff.h fails"
echo "x - extracting norm.saver.SH (Text)"
sed 's/^X//' << 'SHAR_EOF' > norm.saver.SH &&
Xcase $CONFIG in
X    '') . ./config.sh ;;
Xesac
Xecho "Extracting norm.saver (with variable substitutions)"
X$spitshell >norm.saver <<!GROK!THIS!
X$startsh
X# $Header: norm.saver.SH,v 4.3.2.1 89/11/28 00:08:01 sob Locked $
X# 
X# $Log:	norm.saver.SH,v $
X# Revision 4.3.2.1  89/11/28  00:08:01  sob
X# Branch for RN/RRN combo.
X# 
X# Revision 4.3.1.2  85/05/20  15:56:24  lwall
X# Turned $5 into \$5.
X# 
X# Revision 4.3.1.1  85/05/10  11:36:52  lwall
X# Branch for patches.
X# 
X# Revision 4.3  85/05/01  11:45:16  lwall
X# Baseline for release with 4.3bsd.
X# 
X# 
X#	Arguments:
X#	1 Full name of article (%A)
X#	2 Public news spool directory (%P)
X#	3 Directory of current newsgroup (%c)
X#	4 Article number (%a)
X#	5 Where in article to start (%B)
X#	6 Newsgroup name (%C)
X#	7 Save destination (%b)
X#
Xexport PATH || (echo "OOPS, this isn't sh.  Desperation time.  I will feed myself to sh."; sh \$0; kill \$\$)
X
X( case "\$5" in
X  0) $echo "Article \$4 of \$6:" ;;
X  esac
X  $tail +\$5c \$1
X  $echo ""
X  $echo "" ) >> \$7
X!GROK!THIS!
X$eunicefix norm.saver
Xchmod 755 norm.saver
SHAR_EOF
chmod 0770 norm.saver.SH || echo "restore of norm.saver.SH fails"
echo "x - extracting only.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > only.c &&
X/* $Header: only.c,v 4.3.3.1 90/06/20 22:39:13 davison Trn $
X *
X * $Log:	only.c,v $
X * Revision 4.3.3.1  90/06/20  22:39:13  davison
X * Initial Trn Release
X * 
X * Revision 4.3  85/05/01  11:45:21  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "search.h"
X#include "util.h"
X#include "final.h"
X#include "ngsrch.h"
X#include "INTERN.h"
X#include "only.h"
X
Xvoid
Xonly_init()
X{
X    ;
X}
X
Xvoid
Xsetngtodo(pat)
Xchar *pat;
X{
X    char *s;
X
X#ifdef ONLY
X    if (!*pat)
X	return;
X    if (maxngtodo < NGMAX) {
X	ngtodo[maxngtodo] = savestr(pat);
X#ifdef SPEEDOVERMEM
X#ifndef lint
X	compextodo[maxngtodo] = (COMPEX*)safemalloc(sizeof(COMPEX));
X#endif /* lint */
X	init_compex(compextodo[maxngtodo]);
X	compile(compextodo[maxngtodo],pat,TRUE,TRUE);
X	if ((s = ng_comp(compextodo[maxngtodo],pat,TRUE,TRUE)) != Nullch) {
X					    /* compile regular expression */
X	    printf("\n%s\n",s) FLUSH;
X	    finalize(1);
X	}
X#endif
X	maxngtodo++;
X    }
X#else
X    notincl("o");
X#endif
X}
X
X/* if command line list is non-null, is this newsgroup wanted? */
X
Xbool
Xinlist(ngnam)
Xchar *ngnam;
X{
X#ifdef ONLY
X    register int i;
X#ifdef SPEEDOVERMEM
X
X    if (maxngtodo == 0)
X	return TRUE;
X    for (i=0; i<maxngtodo; i++) {
X	if (execute(compextodo[i],ngnam))
X	    return TRUE;
X    }
X    return FALSE;
X#else
X    COMPEX ilcompex;
X    char *s;
X
X    if (maxngtodo == 0)
X	return TRUE;
X    init_compex(&ilcompex);
X    for (i=0; i<maxngtodo; i++) {
X	if ((s = ng_comp(&ilcompex,ngtodo[i],TRUE,TRUE)) != Nullch) {
X					    /* compile regular expression */
X	    printf("\n%s\n",s) FLUSH;
X	    finalize(1);
X	}
X	
X	if (execute(&ilcompex,ngnam) != Nullch) {
X	    free_compex(&ilcompex);
X	    return TRUE;
X	}
X    }
X    free_compex(&ilcompex);
X    return FALSE;
X#endif
X#else
X    return TRUE;
X#endif
X}
X
X#ifdef ONLY
Xvoid
Xend_only()
X{
X    if (maxngtodo) {			/* did they specify newsgroup(s) */
X	int whicharg;
X
X#ifdef VERBOSE
X	IF(verbose)
X	    printf("\nRestriction %s%s removed.\n",ngtodo[0],
X		maxngtodo > 1 ? ", etc." : nullstr) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    fputs("\nExiting \"only\".\n",stdout) FLUSH;
X#endif
X	for (whicharg = 0; whicharg < maxngtodo; whicharg++) {
X	    free(ngtodo[whicharg]);
X#ifdef SPEEDOVERMEM
X	    free_compex(compextodo[whicharg]);
X#ifndef lint
X	    free((char*)compextodo[whicharg]);
X#endif /* lint */
X#endif
X	}
X	maxngtodo = 0;
X    }
X}
X#endif
SHAR_EOF
chmod 0660 only.c || echo "restore of only.c fails"
echo "x - extracting only.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > only.h &&
X/* $Header: only.h,v 4.3 85/05/01 11:45:27 lwall Exp $
X *
X * $Log:	only.h,v $
X * Revision 4.3  85/05/01  11:45:27  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#ifndef NBRA
X#include "search.h"
X#endif
X
X#ifdef ONLY
X    EXT char *ngtodo[NGMAX];		/* restrictions in effect */
X#   ifdef SPEEDOVERMEM
X	EXT COMPEX *compextodo[NGMAX];	/* restrictions in compiled form */
X#   endif
X#endif
X
XEXT int maxngtodo INIT(0);			/*  0 => no restrictions */
X					/* >0 => # of entries in ngtodo */
X
Xvoid	only_init();
Xbool	inlist();	/* return TRUE if ngname is in command line list */
X			/* or if there was no list */
Xvoid	setngtodo();
X#ifdef ONLY
X    void	end_only();
X#endif
SHAR_EOF
chmod 0660 only.h || echo "restore of only.h fails"
echo "x - extracting rcln.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > rcln.c &&
X/* $Header: rcln.c,v 4.3.3.1 90/06/20 22:39:19 davison Trn $
X *
X * $Log:	rcln.c,v $
X * Revision 4.3.3.1  90/06/20  22:39:19  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.1  90/04/23  00:22:22  sob
X * Changed atoi to atol and fixed RCS information.
X * 
X * Revision 4.3.1.2  85/07/23  17:39:08  lwall
X * Oops, was freeing a static buf on -c in checkexpired.
X * 
X * Revision 4.3.1.1  85/05/10  11:37:08  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:45:36  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "util.h"
X#include "rcstuff.h"
X#include "ngdata.h"
X#include "INTERN.h"
X#include "rcln.h"
X
Xvoid
Xrcln_init()
X{
X    ;
X}
X
X#ifdef CATCHUP
Xvoid
Xcatch_up(ngx)
XNG_NUM ngx;
X{
X    char tmpbuf[128];
X    char *tmpp;
SHAR_EOF
echo "End of part 10"
echo "File rcln.c is continued in part 11"
echo "11" > s2_seq_.tmp
exit 0

exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.



More information about the Comp.sources.unix mailing list