v23i068: Complete reposting of TRN at patchlevel 1, Part09/14

Rich Salz rsalz at bbn.com
Sat Jan 5 08:05:53 AEST 1991


Submitted-by: Wayne Davison <0004475895 at mcimail.com>
Posting-number: Volume 23, Issue 68
Archive-name: trn/part09

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# Contents:  help.c rcln.c respond.c rn.c
# Wrapped by rsalz at litchi.bbn.com on Thu Dec 27 11:34:08 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 9 (of 14)."'
if test -f 'help.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'help.c'\"
else
  echo shar: Extracting \"'help.c'\" \(15622 characters\)
  sed "s/^X//" >'help.c' <<'END_OF_FILE'
X/* $Header: help.c,v 4.3.3.1 90/07/24 21:52:37 davison Trn $
X *
X * $Log:	help.c,v $
X * Revision 4.3.3.1  90/07/24  21:52:37  davison
X * Initial Trn Release
X * 
X * Revision 4.3.1.2  85/09/10  11:05:39  lwall
X * Improved %m in in_char().
X * 
X * Revision 4.3.1.1  85/05/10  11:33:10  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:38:59  lwall
X * Baseline for release with 4.3bsd.
X * 
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#ifdef USETHREADS
X    (cmd = print_lines("\
Xt	Display the entire article tree and all its subjects.\n\
X",NOMARKING)) ||
X#endif
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#ifdef USETHREADS
X    (cmd = print_lines("\
X<,>	Browse the previous/next selected thread.  If no threads are selected,\n\
X	all threads that had unread news upon entry to the group are considered\n\
X	selected for browsing.  Entering an empty group browses all threads.\n\
X[,],{,} Go to parent/child/root/leaf in thread.\n\
X\n\
X",NOMARKING)) ||
X#endif
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#ifdef USETHREADS
X    (cmd = print_lines("\
X	# $ & / = ? c C f F k K ^K J , m M number e r R ^R s S u 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#else
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#endif
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#ifdef USETHREADS
X    (cmd = print_lines("\n\
Xn,SP	Find next unread article (follows discussion-tree in threaded groups).\n\
X",NOMARKING)) ||
X#else
X    (cmd = print_lines("\n\
Xn,SP	Scan forward for next unread article.\n\
X",NOMARKING)) ||
X#endif
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#ifdef USETHREADS
X    (cmd = print_lines("\
X<,>	Browse the previous/next selected thread.  If no threads are selected,\n\
X	all threads that had unread news upon entry to the group are considered\n\
X	selected for browsing.  Entering an empty group browses all threads.\n\
X[,]	Go to article's parent/child.\n\
X{,}	Go to tree's root/leaf.\n\
Xt	Display the entire article tree and all its subjects.\n\
X",NOMARKING)) ||
X#endif
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#ifdef USETHREADS
X    (cmd = print_lines("\
X 	Valid commands are: e, j, m, M, s, S, t, T, |, +, and -.\n\
X:cmd	Perform a command on all the selected articles.\n\
X",NOMARKING)) ||
X#else
X    (cmd = print_lines("\
X 	Valid commands are: e, j, m, M, s, S, and |.\n\
X",NOMARKING)) ||
X#endif
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#ifdef USETHREADS
X    (cmd = print_lines("\
X,	Mark current article and its replies as read.\n\
XJ	Junk entire thread (mark all subjects as read in this thread).\n\
XT	Trash current thread (like 'J'), and save command in KILL file.\n\
X",NOMARKING)) ||
X#endif
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#ifdef USETHREADS
X    (cmd = print_lines("\
X+	Enter thread selection mode.\n\
XU	Unread some news -- prompts for thread, subthread, all, or select.\n\
X",NOMARKING)) ||
X#endif
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#ifdef USETHREADS
X    (cmd = print_lines("\
X+	Enter this newsgroup through the thread selector (like typing .+<CR>).\n\
X",NOMARKING)) ||
X#endif
X    (cmd = print_lines("\
X=	Start this newsgroup, but list subjects before reading articles.\n\
X",NOMARKING)) ||
X#ifdef USETHREADS
X    (cmd = print_lines("\
XU	Enter this newsgroup by way of the \"Set unread?\" prompt.\n\
X",NOMARKING)) ||
X#endif
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 trn.\n\
Xx	Quit, restoring .newsrc to its state at startup of trn.\n\
X^K	Edit the global KILL file.  Use commands like /pattern/j to suppress\n\
X	pattern in every newsgroup.\n\
Xv	Print version.\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X#ifdef PUSHBACK
X    if (cmd = get_anything())
X	return cmd;
X    show_macros();
X#endif
X    return 0;
X}
X
X#ifdef ESCSUBS
Xint
Xhelp_subs()
X{
X    int cmd;
X#ifdef SUBSHELP
X    doshell(sh,filexp(SUBSHELP));
X#else
X    page_init();
X    if ((cmd = print_lines("\
XValid substitutions are:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\
X\n\
Xa	Current article number\n\
XA	Full name of current article (%P/%c/%a)\n\
Xb	Destination of last save command, often a mailbox\n\
XB	Bytes to ignore at beginning of last saved article\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xc	Current newsgroup, directory form\n\
XC	Current newsgroup, dot form\n\
Xd	Full name of newsgroup directory (%P/%c)\n\
XD	Distribution line from current article\n\
Xe	The last command executed to extract data from an article\n\
XE	The number of extra (unselected) articles, not counting the current\n\
X	one if it is unselected\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xf	Who the current article is from\n\
XF	Newsgroups to followup to (from Newsgroups and Followup-To)\n\
Xh	(This help message)\n\
XH	Host name (yours)\n\
Xi	Message-I.D. line from current article, with <>\n\
XI	Reference indicator mark (see -F switch)\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xl	News administrator's login name, if any\n\
XL	Login name (yours)\n\
X",NOMARKING)) ||
X#ifdef USETHREADS
X    (cmd = print_lines("\
Xm	Current mode, first letter of (init,newsgroup,thread,article,pager,\n\
X		unread,Add,Catchup,Delete-bogus,Mailbox,Resubscribe)\n\
X",NOMARKING)) ||
X#else
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#endif
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 trn from)\n\
Xp	Your private news directory (from -d)\n\
XP	Public news spool directory\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xr	Last reference (parent article id)\n\
XR	References list for followup article\n\
Xs	Subject, with all Re's and (nf)'s stripped off\n\
XS	Subject, with one Re stripped off\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xt	New To line derived from From and Reply-To (Internet format)\n\
XT	New To line derived from Path\n\
Xu	Number of unread articles\n\
XU	Number of unread articles not counting the current article (when\n\
X	threads are selected, the count only reflects selected articles)\n\
Xx	News library directory\n\
XX	Trn library directory\n\
Xz	Length of current article in bytes\n\
XZ	Number of selected threads\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X~	Your home directory\n\
X.	Directory containing . files\n\
X#	A counter in multiple-article commands\n\
X$	Current process number\n\
X/	Last search string\n\
XESC	Run preceding command through % interpretation\n\
X",NOMARKING)) )
X	return cmd;
X#endif
X    return 0;
X}
X#endif
X
X#ifdef USETHREADS
Xint
Xhelp_select()
X{
X    int cmd;
X
X    page_init();
X    if ((cmd = print_lines("\
XThread selection commands:\n\
X",STANDOUT)) ||
X    (cmd = print_lines("\n\
Xa-z,0-9	Select/deselect the discussion thread by its letter or number.  By\n\
X	default the letters h, k, m, n, p, q and y are omitted.\n\
XSP	Perform the default command (usually > or Z).\n\
XCR	Start reading.  Selects the current thread if none are selected.\n\
XZ,TAB	Start reading.  If no articles are selected, read everything.\n\
Xy, '.'	Toggle the current thread's selection.\n\
Xk, ','	Mark the current thread as killed.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
Xm, \\	Unmark the current thread.\n\
X-	Set a range, as in 2 - 5.  Repeats the last marking action.\n\
X@	Toggle all visible thread selections.\n\
Xn, ]	Move down to the next thread.\n\
Xp, [	Move up to the previous thread.\n\
X<, >	Go to previous/next page.\n\
X^, $	Go to first/last page.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
XX	Mark all unselected articles as read and start reading.\n\
XD	Mark unselected articles on the current page as read.  Start\n\
X	reading if articles were selected, else go to next page.\n\
XJ	Junk all selected articles (mark them as read).\n\
X^K	Edit local KILL file (the one for this newsgroup).\n\
X:cmd	Perform a command on all the selected articles.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X/pattern/modifiers\n\
X	Scan all articles for a subject containing pattern.\n\
X	(Append h to scan headers, a to scan entire articles, c to make case\n\
X	sensitive, r to scan read articles (assumed when you are selecting\n\
X	read articles to set unread.)\n\
X/pattern/modifiers:command{:command}\n\
X	Apply one or more commands to the set of articles matching pattern.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
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: e, j, m, M, s, S, T, !, and the thread selection\n\
X	commands: + and -.\n\
XN	Leave this group as-is and go on to the next.\n\
XU	Switch between selecting read/unread articles.\n\
XL	Switch the current display mode between a terse mode without\n\
X	authors and a short and long mode with authors.\n\
X",NOMARKING)) ||
X    (cmd = print_lines("\
X&	View or set command line switches.\n\
X&&	View or set macro definitions.\n\
X!cmd	Escape to a subshell.\n\
Xq	Quit selection mode.\n\
XQ	Quit group and return to news group selection prompt for this group.\n\
X",NOMARKING)) )
X	return cmd;
X    return 0;
X}
X#endif
END_OF_FILE
  if test 15622 -ne `wc -c <'help.c'`; then
    echo shar: \"'help.c'\" unpacked with wrong size!
  fi
  # end of 'help.c'
fi
if test -f 'rcln.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rcln.c'\"
else
  echo shar: Extracting \"'rcln.c'\" \(13006 characters\)
  sed "s/^X//" >'rcln.c' <<'END_OF_FILE'
X/* $Header: rcln.c,v 4.3.3.2 90/08/20 16:46:05 davison Trn $
X *
X * $Log:	rcln.c,v $
X * Revision 4.3.3.2  90/08/20  16:46:05  davison
X * Removed extraneous xref boundary check.
X * 
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;
X    
X#ifdef VERBOSE
X    IF(verbose)
X	printf("\nMarking %s as all read.\n",rcline[ngx]) FLUSH;
X    ELSE
X#endif
X#ifdef TERSE
X	fputs("\nMarked read\n",stdout) FLUSH;
X#endif
X    sprintf(tmpbuf,"%s: 1-%ld", rcline[ngx],(long)getngsize(ngx));
X    free(rcline[ngx]);
X    rcline[ngx] = savestr(tmpbuf);
X    tmpp = rcline[ngx] + rcnums[ngx] - 1;
X    *tmpp = '\0';
X    write_rc();
X}
X#endif
X
X/* add an article number to a newsgroup, if it isn't already read */
X
Xint
Xaddartnum(artnum,ngnam)
XART_NUM artnum;
Xchar *ngnam;
X{
X    register NG_NUM ngnum = find_ng(ngnam);
X    register char *s, *t, *maxt = Nullch;
X    ART_NUM min = 0, max = -1, lastnum = 0;
X    char *mbuf;
X    bool morenum;
X
X    if (!artnum)
X	return 0;
X    if (ngnum == nextrcline || !rcnums[ngnum])
X					/* not found in newsrc? */
X	return 0;
X#ifdef CACHEFIRST
X    if (!abs1st[ngnum])
X#else
X    if (!toread[ngnum])
X#endif
X					/* now is a good time to trim down */
X	set_toread(ngnum);		/* the list due to expires if we */
X					/* have not yet. */
X#if defined(DEBUGGING) && !defined(USETHREADS)
X    if (artnum > ngmax[ngnum] + 10	/* allow for incoming articles */
X       ) {
X	printf("\nCorrupt Xref line!!!  %ld --> %s(1..%ld)\n",
X	    artnum,ngnam,
X	    ngmax[ngnum]) FLUSH;
X	paranoid = TRUE;		/* paranoia reigns supreme */
X	return -1;			/* hope this was the first newsgroup */
X    }
X#endif
X
X    if (toread[ngnum] == TR_BOGUS)
X	return 0;
X#ifdef DEBUGGING
X    if (debug & DEB_XREF_MARKER) {
X	printf("%ld->\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
X	  rcline[ngnum] + rcnums[ngnum]) FLUSH;
X    }
X#endif
X    s = rcline[ngnum] + rcnums[ngnum];
X    while (*s == ' ') s++;		/* skip spaces */
X    t = s;
X    while (isdigit(*s) && artnum >= (min = atol(s))) {
X					/* while it might have been read */
X	for (t = s; isdigit(*t); t++) ;	/* skip number */
X	if (*t == '-') {		/* is it a range? */
X	    t++;			/* skip to next number */
X	    if (artnum <= (max = atol(t)))
X		return 0;		/* it is in range => already read */
X	    lastnum = max;		/* remember it */
X	    maxt = t;			/* remember position in case we */
X					/* want to overwrite the max */
X	    while (isdigit(*t)) t++;	/* skip second number */
X	}
X	else {
X	    if (artnum == min)		/* explicitly a read article? */
X		return 0;
X	    lastnum = min;		/* remember what the number was */
X	    maxt = Nullch;		/* last one was not a range */
X	}
X	while (*t && !isdigit(*t)) t++;	/* skip comma and any spaces */
X	s = t;
X    }
X    
X    /* we have not read it, so insert the article number before s */
X    
X    morenum = isdigit(*s);		/* will it need a comma after? */
X    *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
X    mbuf = safemalloc((MEM_SIZE)(strlen(s) + (s-rcline[ngnum]) + 8));
X    strcpy(mbuf,rcline[ngnum]);		/* make new rc line */
X    if (maxt && lastnum && artnum == lastnum+1)
X    					/* can we just extend last range? */
X	t = mbuf + (maxt-rcline[ngnum]);/* then overwrite previous max */
X    else {
X	t = mbuf + (t-rcline[ngnum]);	/* point t into new line instead */
X	if (lastnum) {			/* have we parsed any line? */
X	    if (!morenum)		/* are we adding to the tail? */
X		*t++ = ',';		/* supply comma before */
X	    if (!maxt && artnum == lastnum+1 && *(t-1) == ',')
X					/* adjacent singletons? */
X		*(t-1) = '-';		/* turn them into a range */
X	}
X    }
X    if (morenum) {			/* is there more to life? */
X	if (min == artnum+1) {		/* can we consolidate further? */
X	    bool range_before = (*(t-1) == '-');
X	    bool range_after;
X	    char *nextmax;
X
X	    for (nextmax = s; isdigit(*nextmax); nextmax++) ;
X	    range_after = *nextmax++ == '-';
X	    
X	    if (range_before)
X		*t = '\0';		/* artnum is redundant */
X	    else
X		sprintf(t,"%ld-",(long)artnum);/* artnum will be new min */
X	    
X	    if (range_after)
X		s = nextmax;		/* *s is redundant */
X	/*  else
X		s = s */		/* *s is new max */
X	}
X	else
X	    sprintf(t,"%ld,",(long)artnum);	/* put the number and comma */
X    }
X    else
X	sprintf(t,"%ld",(long)artnum);	/* put the number there (wherever) */
X    strcat(t,s);			/* copy remainder of line */
X#ifdef DEBUGGING
X    if (debug & DEB_XREF_MARKER) {
X	printf("%s\n",mbuf) FLUSH;
X    }
X#endif
X    free(rcline[ngnum]);
X    rcline[ngnum] = mbuf;		/* pull the switcheroo */
X    *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
X					/* wipe out : or ! */
X    if (toread[ngnum] > TR_NONE)	/* lest we turn unsub into bogus */
X	--toread[ngnum];
X    return 0;
X}
X
X#ifdef MCHASE
X/* delete an article number from a newsgroup, if it is there */
X
Xvoid
Xsubartnum(artnum,ngnam)
Xregister ART_NUM artnum;
Xchar *ngnam;
X{
X    register NG_NUM ngnum = find_ng(ngnam);
X    register char *s, *t;
X    register ART_NUM min, max;
X    char *mbuf;
X    int curlen;
X
X    if (!artnum)
X	return;
X    if (ngnum == nextrcline || !rcnums[ngnum])
X	return;				/* not found in newsrc? */
X#ifdef DEBUGGING
X    if (debug & DEB_XREF_MARKER) {
X	printf("%ld<-\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
X	  rcline[ngnum] + rcnums[ngnum]) FLUSH;
X    }
X#endif
X    s = rcline[ngnum] + rcnums[ngnum];
X    while (*s == ' ') s++;		/* skip spaces */
X    
X    /* a little optimization, since it is almost always the last number */
X    
X    for (t=s; *t; t++) ;		/* find end of string */
X    curlen = t-rcline[ngnum];
X    for (t--; isdigit(*t); t--) ;	/* find previous delim */
X    if (*t == ',' && atol(t+1) == artnum) {
X	*t = '\0';
X	if (toread[ngnum] >= TR_NONE)
X	    ++toread[ngnum];
X#ifdef DEBUGGING
X	if (debug & DEB_XREF_MARKER)
X	    printf("%s%c %s\n",rcline[ngnum],rcchar[ngnum],s) FLUSH;
X#endif
X	return;
X    }
X
X    /* not the last number, oh well, we may need the length anyway */
X
X    while (isdigit(*s) && artnum >= (min = atol(s))) {
X					/* while it might have been read */
X	for (t = s; isdigit(*t); t++) ;	/* skip number */
X	if (*t == '-') {		/* is it a range? */
X	    t++;			/* skip to next number */
X	    max = atol(t);
X	    while (isdigit(*t)) t++;	/* skip second number */
X	    if (artnum <= max) {
X					/* it is in range => already read */
X		if (artnum == min) {
X		    min++;
X		    artnum = 0;
X		}
X		else if (artnum == max) {
X		    max--;
X		    artnum = 0;
X		}
X		*(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
X		mbuf = safemalloc((MEM_SIZE)(curlen + (artnum?15:2)));
X		*s = '\0';
X		strcpy(mbuf,rcline[ngnum]);	/* make new rc line */
X		s = mbuf + (s-rcline[ngnum]);
X					/* point s into mbuf now */
X		if (artnum) {		/* split into two ranges? */
X		    prange(s,min,artnum-1);
X		    s += strlen(s);
X		    *s++ = ',';
X		    prange(s,artnum+1,max);
X		}
X		else			/* only one range */
X		    prange(s,min,max);
X		s += strlen(s);
X		strcpy(s,t);		/* copy remainder over */
X#ifdef DEBUGGING
X		if (debug & DEB_XREF_MARKER) {
X		    printf("%s\n",mbuf) FLUSH;
X		}
X#endif
X		free(rcline[ngnum]);
X		rcline[ngnum] = mbuf;	/* pull the switcheroo */
X		*(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
X					/* wipe out : or ! */
X		if (toread[ngnum] >= TR_NONE)
X		    ++toread[ngnum];
X		return;
X	    }
X	}
X	else {
X	    if (artnum == min) {	/* explicitly a read article? */
X		if (*t == ',')		/* pick a comma, any comma */
X		    t++;
X		else if (s[-1] == ',')
X		    s--;
X		else if (s[-2] == ',')	/* (in case of space) */
X		    s -= 2;
X		strcpy(s,t);		/* no need to realloc */
X		if (toread[ngnum] >= TR_NONE)
X		    ++toread[ngnum];
X#ifdef DEBUGGING
X		if (debug & DEB_XREF_MARKER) {
X		    printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
X		      rcline[ngnum] + rcnums[ngnum]) FLUSH;
X		}
X#endif
X		return;
X	    }
X	}
X	while (*t && !isdigit(*t)) t++;	/* skip comma and any spaces */
X	s = t;
X    }
X}
X
Xvoid
Xprange(where,min,max)
Xchar *where;
XART_NUM min,max;
X{
X    if (min == max)
X	sprintf(where,"%ld",(long)min);
X    else
X	sprintf(where,"%ld-%ld",(long)min,(long)max);
X}
X#endif
X
X/* calculate the number of unread articles for a newsgroup */
X
Xvoid
Xset_toread(ngnum)
Xregister NG_NUM ngnum;
X{
X    register char *s, *c, *h;
X    char tmpbuf[64], *mybuf = tmpbuf;
X    char *nums;
X    int length;
X#ifdef CACHEFIRST
X    bool virgin_ng = (!abs1st[ngnum]);
X#endif
X    ART_NUM ngsize = getngsize(ngnum);
X    ART_NUM unread = ngsize;
X    ART_NUM newmax;
X
X#if defined(DEBUGGING) && !defined(USETHREADS)
X    ngmax[ngnum] = ngsize;		/* for checking out-of-range Xrefs */
X#endif
X    if (ngsize == TR_BOGUS) {
X	printf("Warning!  Bogus newsgroup: %s\n",rcline[ngnum]) FLUSH;
X	paranoid = TRUE;
X	toread[ngnum] = TR_BOGUS;
X	return;
X    }
X#ifdef CACHEFIRST
X    if (virgin_ng)
X#else
X    if (!toread[ngnum])
X#endif
X    {
X	sprintf(tmpbuf," 1-%ld",(long)ngsize);
X	if (strNE(tmpbuf,rcline[ngnum]+rcnums[ngnum]))
X	    checkexpired(ngnum,ngsize);	/* this might realloc rcline */
X    }
X    nums = rcline[ngnum]+rcnums[ngnum];
X    length = strlen(nums);
X    if (length >= 60)
X	mybuf = safemalloc((MEM_SIZE)(length+5));
X    strcpy(mybuf,nums);
X    mybuf[length++] = ',';
X    mybuf[length] = '\0';
X    for (s = mybuf; isspace(*s); s++)
X	    ;
X    for ( ; (c = index(s,',')) != Nullch ; s = ++c) {
X				    /* for each range */
X	*c = '\0';			/* keep index from running off */
X	if ((h = index(s,'-')) != Nullch)	/* find - in range, if any */
X	    unread -= (newmax = atol(h+1)) - atol(s) + 1;
X	else if (newmax = atol(s))
X	    unread--;		/* recalculate length */
X	if (newmax > ngsize) {	/* paranoia check */
X	    unread = -1;
X	    break;
X	}
X    }
X    if (unread >= 0)		/* reasonable number? */
X	toread[ngnum] = (ART_UNREAD)unread;
X					/* remember how many are left */
X#ifdef USETHREADS
X    else if (unread >= -100) {
X	/* If mthreads is in the process of updating the database, it's possible
X	** for the .thread file to be more up-to-date than the numbers in the
X	** active file (caused by buffering).  If so, it's also possible for the
X	** user to have read past the end of the group as we know it.  Assume
X	** 100 articles is enough of a buffer to distinguish reset newsgroups.
X	*/
X	toread[ngnum] = 0;
X    }
X#endif
X    else {				/* SOMEONE RESET THE NEWSGROUP!!! */
X	toread[ngnum] = (ART_UNREAD)ngsize;
X					/* assume nothing carried over */
X	printf("Warning!  Somebody reset %s--assuming nothing read.\n",
X	    rcline[ngnum]) FLUSH;
X	*(rcline[ngnum] + rcnums[ngnum]) = '\0';
X	paranoid = TRUE;		/* enough to make a guy paranoid */
X    }
X    if (mybuf != tmpbuf)
X	free(mybuf);
X    if (rcchar[ngnum] == NEGCHAR)
X	toread[ngnum] = TR_UNSUB;
X}
X
X/* make sure expired articles are marked as read */
X
Xvoid
Xcheckexpired(ngnum,ngsize)
Xregister NG_NUM ngnum;
XART_NUM ngsize;
X{
X    register ART_NUM a1st = getabsfirst(ngnum,ngsize);
X    register char *s, *t;
X    register ART_NUM num, lastnum = 0;
X    char *mbuf, *newnum;
X
X    if (a1st<=1)
X	return;
X#ifdef DEBUGGING
X    if (debug & DEB_XREF_MARKER) {
X	printf("1-%ld->\n%s%c%s\n",(long)(a1st-1),rcline[ngnum],rcchar[ngnum],
X	  rcline[ngnum] + rcnums[ngnum]) FLUSH;
X    }
X#endif
X    for (s = rcline[ngnum] + rcnums[ngnum]; isspace(*s); s++);
X    while (*s && (num = atol(s)) <= a1st) {
X	while (isdigit(*s)) s++;
X	while (*s && !isdigit(*s)) s++;
X	lastnum = num;
X    }
X    if (*s) {
X	if (s[-1] == '-') {			/* landed in a range? */
X	    if (lastnum != 1) {
X		if (3 + strlen(s) > strlen(rcline[ngnum]+rcnums[ngnum])) {
X		    mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + 3 +
X			strlen(s) + 1));
X		    strcpy(mbuf, rcline[ngnum]);
X		    sprintf(mbuf+rcnums[ngnum]," 1-%s",s);
X		    free(rcline[ngnum]);
X		    rcline[ngnum] = mbuf;
X		} else {
X		    sprintf(rcline[ngnum]+rcnums[ngnum]," 1-%s",s);
X		}
X	    }
X	    goto ret;
X	}
X    }
X    /* s now points to what should follow first range */
X    if (s - rcline[ngnum] > rcnums[ngnum] + 10) 
X	mbuf = rcline[ngnum];
X    else {
X	mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + strlen(s) + 10));
X	strcpy(mbuf,rcline[ngnum]);
X    }
X    newnum = t = mbuf+rcnums[ngnum];
X    sprintf(t," 1-%ld",(long)(a1st - (lastnum != a1st)));
X    if (*s) {
X	t += strlen(t);
X	*t++ = ',';
X	strcpy(t,s);
X    }
X    if (!checkflag && mbuf == rcline[ngnum]) {
X	rcline[ngnum] = saferealloc(rcline[ngnum],
X	    (MEM_SIZE)(rcnums[ngnum] + strlen(newnum) + 1));
X    }
X    else {
X	if (!checkflag)
X	    free(rcline[ngnum]);
X	rcline[ngnum] = mbuf;
X    }
X
Xret:;		/* semicolon in case DEBUGGING undefined */
X#ifdef DEBUGGING
X    if (debug & DEB_XREF_MARKER) {
X	printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
X	  rcline[ngnum] + rcnums[ngnum]) FLUSH;
X    }
X#endif
X}
X
END_OF_FILE
  if test 13006 -ne `wc -c <'rcln.c'`; then
    echo shar: \"'rcln.c'\" unpacked with wrong size!
  fi
  # end of 'rcln.c'
fi
if test -f 'respond.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'respond.c'\"
else
  echo shar: Extracting \"'respond.c'\" \(15981 characters\)
  sed "s/^X//" >'respond.c' <<'END_OF_FILE'
X/* $Header: respond.c,v 4.3.3.1 90/07/21 20:30:18 davison Trn $
X *
X * $Log:	respond.c,v $
X * Revision 4.3.3.1  90/07/21  20:30:18  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.3  90/03/22  23:05:19  sob
X * Fixes provided by Wayne Davison <drivax!davison>
X * 
X * Revision 4.3.2.2  89/11/26  18:25:10  sob
X * Enlarged the size of the header buffer to accomodate long references lines.
X * Fix provided by Joe Buck.
X * 
X * Revision 4.3.2.1  89/11/06  01:00:26  sob
X * Added RRN support from NNTP 1.5
X * 
X * Revision 4.3.1.5  85/09/10  11:05:00  lwall
X * Improved %m in in_char().
X * 
X * Revision 4.3.1.4  85/05/23  17:24:49  lwall
X * Now allows 'r' and 'f' on null articles.
X * 
X * Revision 4.3.1.3  85/05/15  14:42:32  lwall
X * Removed duplicate include of intrp.h.
X * 
X * Revision 4.3.1.2  85/05/14  08:55:15  lwall
X * Default for normal/mailbox question was applied to wrong buffer.
X * 
X * Revision 4.3.1.1  85/05/10  11:37:33  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:47:04  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "EXTERN.h"
X#include "common.h"
X#include "intrp.h"
X#include "head.h"
X#include "term.h"
X#include "ng.h"
X#include "util.h"
X#include "rn.h"
X#include "artio.h"
X#include "final.h"
X#include "uudecode.h"
X#include "INTERN.h"
X#include "respond.h"
X
Xstatic char nullart[] = "\nNull article\n";
X
Xvoid
Xrespond_init()
X{
X    ;
X}
X
Xint
Xsave_article()
X{
X    bool use_pref, cut_line();
X    register char *s, *c;
X    char altbuf[CBUFLEN];
X    int iter;
X    bool interactive = (buf[1] == FINISHCMD);
X    char cmd = *buf;
X    
X    if (!finish_command(interactive))	/* get rest of command */
X	return SAVE_ABORT;
X    if ((use_pref = isupper(cmd)) != 0)
X	cmd = tolower(cmd);
X#ifdef ASYNC_PARSE
X    parse_maybe(art);
X#endif
X    savefrom = (cmd == 'w' || cmd == 'e' ? htype[PAST_HEADER].ht_minpos : 0);
X    if (artopen(art) == Nullfp) {
X#ifdef VERBOSE
X	IF(verbose)
X	    fputs("\n\
XSaving null articles is not very productive!  :-)\n\
X",stdout) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    fputs(nullart,stdout) FLUSH;
X#endif
X	return SAVE_DONE;
X    }
X    if (chdir(cwd)) {
X	printf(nocd,cwd) FLUSH;
X	sig_catcher(0);
X    }
X    if (cmd == 'e') {		/* is this an extract command? */
X	int cnt = 0;
X	bool found_cut = FALSE;
X	char art_buf[LBUFLEN], *cmdstr;
X
X	s = buf+1;		/* skip e */
X	while (*s == ' ') s++;	/* skip leading spaces */
X	safecpy(altbuf,filexp(s),sizeof altbuf);
X	s = altbuf;
X	if (extractprog)
X	    free(extractprog);
X	if (*s) {
X	    cmdstr = cpytill(buf,s,'|');	/* check for | */
X	    s = buf + strlen(buf)-1;
X	    while (*s == ' ') s--;		/* trim trailing spaces */
X	    *++s = '\0';
X	    if (*cmdstr) {
X		s = cmdstr+1;			/* skip | */
X		while (*s == ' ') s++;
X		if (strEQ(s,"-"))
X		    cmdstr = Nullch;
X		else {
X		    extractprog = savestr(s);	/* put extracter in %e */
X		    if (uu_out != Nullfp)
X			uud_end();
X		}
X	    } else
X		cmdstr = Nullch;
X	    s = buf;
X	} else
X	    cmdstr = Nullch;
X
X	fseek(artfp,savefrom,0);
X	if ((cmd = *s) == '\0')
X	    interp(s = buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
X	if (*s != '/') {		/* relative path? */
X	    c = (s==buf ? altbuf : buf);
X	    sprintf(c, "%s/%s", cwd, s);
X	    s = c;			/* absolutize it */
X	}
X	if (uu_out != Nullfp) {
X	    printf("Continuing %s:%s\n", uu_fname,
X		cmd != '\0' && strNE(savedest,s) ?
X		 " (Ignoring conflicting directory)" : nullstr );
X	    uudecode(artfp);
X	}
X	else {
X	    if (savedest)
X		free(savedest);
X	    s = savedest = savestr(s);	/* make it handy for %b */
X	    if (makedir(s, MD_DIR)) {	/* ensure directory exists */
X		int_count++;
X		return SAVE_DONE;
X	    }
X	    if (chdir(s)) {
X		printf(nocd,s) FLUSH;
X		sig_catcher(0);
X	    }
X	    s = getwd(buf);		/* simplify path for output */
X	    while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
X		if (*art_buf <= ' ')
X		    continue;	/* Ignore empty or initially-whitespace lines */
X		if (found_cut && cmdstr) {
X		    printf("Extracting data into %s using %s:\n",
X			s, extractprog);
X		    goto extract_it;
X		}
X		if (((*art_buf == '#' || *art_buf == ':')
X		  && (strnEQ(art_buf+1, "! /bin/sh", 9)
X		   || strnEQ(art_buf+1, "!/bin/sh", 8)
X		   || strnEQ(art_buf+2, "This is ", 8)))
X		 || strnEQ(art_buf, "sed ", 4)
X		 || strnEQ(art_buf, "cat ", 4)
X		 || strnEQ(art_buf, "echo ", 5)) {
X		    fseek(artfp,(long)-strlen(art_buf),1);
X		    savefrom = ftell(artfp);
X		    if (cmdstr) {
X			printf("Extracting shar into %s using %s:\n",
X				s, extractprog);
X			goto extract_it;
X		    }
X		    /* Check for special-case of shar'ed-uuencoded file */
X		    while(fgets(art_buf,LBUFLEN,artfp) != Nullch) {
X			if (*art_buf == '#' || *art_buf == ':'
X			 || strnEQ(art_buf, "echo ", 5)
X			 || strnEQ(art_buf, "sed ", 4))
X			    continue;
X			if (strnEQ(art_buf, "Xbegin ", 7))
X			    goto uu_decode;
X			break;
X		    }
X		    printf("Extracting shar into %s:\n", s);
X		    extractprog = savestr(filexp(getval("UNSHAR",UNSHAR)));
X		  extract_it:
X		    cnt = 0;
X		    interp(cmd_buf,(sizeof cmd_buf),getval("EXSAVER",EXSAVER));
X		    resetty();		/* restore tty state */
X		    doshell(SH,cmd_buf);
X		    noecho();		/* revert to cbreaking */
X		    crmode();
X		    break;
X		}
X		else
X		if (!cmdstr
X		 && (strnEQ(art_buf,"table ", 6)
X		  || strnEQ(art_buf,"begin ", 6))) {
X		 uu_decode:
X		    printf("Extracting uuencoded file into %s:\n", s);
X		    extractprog = savestr("-");
X		    cnt = 0;
X		    fseek(artfp,(long)-strlen(art_buf),1);
X		    savefrom = ftell(artfp);
X		    uud_start(s);
X		    uudecode(artfp);
X		    break;
X		}
X		else {
X		    if (cut_line(art_buf)) {
X			savefrom = ftell(artfp);
X			found_cut = TRUE;
X		    }
X		    else if (found_cut || ++cnt == 200) {
X			break;
X		    }
X		}
X	    }/* while */
X	    if (cnt) {
X		if (!cmdstr)
X		    extractprog = savestr("-");
X		printf("Unable to determine type of file.\n");
X	    }
X	}/* if */
X    }
X    else if ((s = index(buf,'|')) != Nullch) {
X				/* is it a pipe command? */
X	s++;			/* skip the | */
X	while (*s == ' ') s++;
X	safecpy(altbuf,filexp(s),sizeof altbuf);
X	if (savedest)
X	    free(savedest);
X	savedest = savestr(altbuf);
X	interp(cmd_buf, (sizeof cmd_buf), getval("PIPESAVER",PIPESAVER));
X				/* then set up for command */
X	resetty();		/* restore tty state */
X	if (use_pref)		/* use preferred shell? */
X	    doshell(Nullch,cmd_buf);
X				/* do command with it */
X	else
X	    doshell(sh,cmd_buf);	/* do command with sh */
X	noecho();		/* and stop echoing */
X	crmode();		/* and start cbreaking */
X    }
X    else {			/* normal save */
X	bool there, mailbox;
X	char *savename = getval("SAVENAME",SAVENAME);
X
X	s = buf+1;		/* skip s or S */
X	if (*s == '-') {	/* if they are confused, skip - also */
X#ifdef VERBOSE
X	    IF(verbose)
X		fputs("Warning: '-' ignored.  This isn't readnews.\n",stdout)
X		  FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("'-' ignored.\n",stdout) FLUSH;
X#endif
X	    s++;
X	}
X	for (; *s == ' '; s++);	/* skip spaces */
X	safecpy(altbuf,filexp(s),sizeof altbuf);
X	s = altbuf;
X	if (! index(s,'/')) {
X	    interp(buf, (sizeof buf), getval("SAVEDIR",SAVEDIR));
X	    if (makedir(buf,MD_DIR))	/* ensure directory exists */
X		strcpy(buf,cwd);
X	    if (*s) {
X		for (c = buf; *c; c++) ;
X		*c++ = '/';
X		strcpy(c,s);		/* add filename */
X	    }
X	    s = buf;
X	}
X	for (iter = 0;
X	    (there = stat(s,&filestat) >= 0) &&
X	    (filestat.st_mode & S_IFDIR);
X	    iter++) {			/* is it a directory? */
X
X	    c = (s+strlen(s));
X	    *c++ = '/';			/* put a slash before filename */
X	    interp(c, s==buf?(sizeof buf):(sizeof altbuf),
X		iter ? "News" : savename );
X				/* generate a default name somehow or other */
X	    if (index(c,'/')) {		/* yikes, a '/' in the filename */
X		makedir(s,MD_FILE);
X	    }
X	}
X	if (*s != '/') {		/* relative path? */
X	    c = (s==buf ? altbuf : buf);
X	    sprintf(c, "%s/%s", cwd, s);
X	    s = c;			/* absolutize it */
X	}
X	if (savedest)
X	    free(savedest);
X	s = savedest = savestr(s);	/* doesn't move any more */
X					/* make it handy for %b */
X	if (!there) {
X	    if (mbox_always)
X		mailbox = TRUE;
X	    else if (norm_always)
X		mailbox = FALSE;
X	    else {
X		char *dflt = (instr(savename,"%a") ? "nyq" : "ynq");
X		
X		sprintf(cmd_buf,
X		"\nFile %s doesn't exist--\n	use mailbox format? [%s] ",
X		  s,dflt);
X	      reask_save:
X		in_char(cmd_buf, 'M');
X		putchar('\n') FLUSH;
X		setdef(buf,dflt);
X#ifdef VERIFY
X		printcmd();
X#endif
X		if (*buf == 'h') {
X#ifdef VERBOSE
X		    IF(verbose)
X			printf("\n\
XType y to create %s as a mailbox.\n\
XType n to create it as a normal file.\n\
XType q to abort the save.\n\
X",s) FLUSH;
X		    ELSE
X#endif
X#ifdef TERSE
X			fputs("\n\
Xy to create mailbox.\n\
Xn to create normal file.\n\
Xq to abort.\n\
X",stdout) FLUSH;
X#endif
X		    goto reask_save;
X		}
X		else if (*buf == 'n') {
X		    mailbox = FALSE;
X		}
X		else if (*buf == 'y') {
X		    mailbox = TRUE;
X		}
X		else if (*buf == 'q') {
X		    goto s_bomb;
X		}
X		else {
X		    fputs(hforhelp,stdout) FLUSH;
X		    settle_down();
X		    goto reask_save;
X		}
X	    }
X	}
X	else if (filestat.st_mode & S_IFCHR)
X	    mailbox = FALSE;
X	else {
X	    int tmpfd;
X	    
X	    tmpfd = open(s,0);
X	    if (tmpfd == -1)
X		mailbox = FALSE;
X	    else {
X		read(tmpfd,buf,LBUFLEN);
X		c = buf;
X		if (!isspace(MBOXCHAR))
X		    while (isspace(*c))
X			c++;
X		mailbox = (*c == MBOXCHAR);
X		close(tmpfd);
X	    }
X	}
X
X	safecpy(cmd_buf, filexp(mailbox ?
X	    getval("MBOXSAVER",MBOXSAVER) :
X	    getval("NORMSAVER",NORMSAVER) ), sizeof cmd_buf);
X				/* format the command */
X	resetty();		/* make terminal behave */
X	if (doshell(use_pref?Nullch:SH,cmd_buf))
X	    fputs("Not saved",stdout);
X	else
X	    printf("%s to %s %s",
X	      there?"Appended":"Saved",
X	      mailbox?"mailbox":"file",
X	      s);
X	if (interactive)
X	    putchar('\n') FLUSH;
X	noecho();		/* make terminal do what we want */
X	crmode();
X    }
Xs_bomb:
X#ifdef SERVER
X    if (chdir(spool)) {
X#else /* not SERVER */
X    if (chdir(spool) || chdir(ngdir)) {
X#endif /* SERVER */
X	printf(nocd,ngdir) FLUSH;
X	sig_catcher(0);
X    }
X    return SAVE_DONE;
X}
X
Xint
Xcancel_article()
X{
X    char *artid_buf;
X    char *ngs_buf;
X    char *from_buf;
X    char *reply_buf;
X    int myuid = getuid();
X    int r = -1;
X
X    if (artopen(art) == Nullfp) {
X#ifdef VERBOSE
X	IF(verbose)
X	    fputs("\n\
XCancelling null articles is your idea of fun?  :-)\n\
X",stdout) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    fputs(nullart,stdout) FLUSH;
X#endif
X	return r;
X    }
X    reply_buf = fetchlines(art,REPLY_LINE);
X    from_buf = fetchlines(art,FROM_LINE);
X    artid_buf = fetchlines(art,ARTID_LINE);
X    ngs_buf = fetchlines(art,NGS_LINE);
X    if (!instr(from_buf,sitename) ||
X	(!instr(from_buf,logname) &&
X	 !instr(reply_buf,logname) &&
X#ifdef NEWSADMIN
X	 myuid != newsuid &&
X#endif
X	 myuid != ROOTID ) )
X#ifdef VERBOSE
X	    IF(verbose)
X		fputs("\nYou can't cancel someone else's article\n",stdout)
X		  FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("\nNot your article\n",stdout) FLUSH;
X#endif
X    else {
X	tmpfp = fopen(headname,"w");	/* open header file */
X	if (tmpfp == Nullfp) {
X	    printf(cantcreate,headname) FLUSH;
X	    goto no_cancel;
X	}
X	interp(buf, (sizeof buf), getval("CANCELHEADER",CANCELHEADER));
X	fputs(buf,tmpfp);
X	fclose(tmpfp);
X	fputs("\nCanceling...\n",stdout) FLUSH;
X	r = doshell(sh,filexp(getval("CANCEL",CANCEL)));
X    }
Xno_cancel:
X    free(artid_buf);
X    free(ngs_buf);
X    free(from_buf);
X    free(reply_buf);
X    return r;
X}
X
Xvoid
Xreply()
X{
X    bool incl_body = (*buf == 'R');
X    char *maildoer = savestr(filexp(getval("MAILPOSTER",MAILPOSTER)));
X
X    artopen(art);
X    tmpfp = fopen(headname,"w");	/* open header file */
X    if (tmpfp == Nullfp) {
X	printf(cantcreate,headname) FLUSH;
X	goto no_reply;
X    }
X    interp(buf, (sizeof buf), getval("MAILHEADER",MAILHEADER));
X    fputs(buf,tmpfp);
X    if (!instr(maildoer,"%h"))
X#ifdef VERBOSE
X	IF(verbose)
X	    printf("\n%s\n(Above lines saved in file %s)\n",buf,headname)
X	      FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    printf("\n%s\n(Header in %s)\n",buf,headname) FLUSH;
X#endif
X    if (incl_body && artfp != Nullfp) {
X	interp(buf, (sizeof buf), getval("YOUSAID",YOUSAID));
X	fprintf(tmpfp,"%s\n",buf);
X#ifdef ASYNC_PARSE
X	parse_maybe(art);
X#endif
X	fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
X	while (fgets(buf,LBUFLEN,artfp) != Nullch) {
X	    fprintf(tmpfp,"%s%s",indstr,buf);
X	}
X	fprintf(tmpfp,"\n");
X    }
X    fclose(tmpfp);
X    interp(cmd_buf, (sizeof cmd_buf), maildoer);
X    invoke(cmd_buf,origdir);
X    UNLINK(headname);		/* kill the header file */
Xno_reply:
X    free(maildoer);
X}
X
Xvoid
Xfollowup()
X{
X    bool incl_body = (*buf == 'F');
X    char hbuf[4*LBUFLEN];	/* four times the old size */
X
X    artopen(art);
X    tmpfp = fopen(headname,"w");
X    if (tmpfp == Nullfp) {
X	printf(cantcreate,headname) FLUSH;
X	return;
X    }
X    interp(hbuf, (sizeof hbuf), getval("NEWSHEADER",NEWSHEADER));
X    fprintf(tmpfp,"%s",hbuf);
X    if (incl_body && artfp != Nullfp) {
X#ifdef VERBOSE
X	if (verbose)
X	    fputs("\n\
X(Be sure to double-check the attribution against the signature, and\n\
Xtrim the quoted article down as much as possible.)\n\
X",stdout) FLUSH;
X#endif
X	interp(buf, (sizeof buf), getval("ATTRIBUTION",ATTRIBUTION));
X	fprintf(tmpfp,"%s\n",buf);
X#ifdef ASYNC_PARSE
X	parse_maybe(art);
X#endif
X	fseek(artfp,(long)htype[PAST_HEADER].ht_minpos,0);
X	while (fgets(buf,LBUFLEN,artfp) != Nullch) {
X	    fprintf(tmpfp,"%s%s",indstr,buf);
X	}
X	fprintf(tmpfp,"\n");
X    }
X    fclose(tmpfp);
X    safecpy(cmd_buf,filexp(getval("NEWSPOSTER",NEWSPOSTER)),sizeof cmd_buf);
X    invoke(cmd_buf,origdir);
X    UNLINK(headname);
X}
X
Xvoid
Xinvoke(cmd,dir)
Xchar *cmd,*dir;
X{
X    if (chdir(dir)) {
X	printf(nocd,dir) FLUSH;
X	return;
X    }
X#ifdef VERBOSE
X    IF(verbose)
X	printf("\n(leaving cbreak mode; cwd=%s)\nInvoking command: %s\n\n",
X	    dir,cmd) FLUSH;
X    ELSE
X#endif
X#ifdef TERSE
X	printf("\n(-cbreak; cwd=%s)\nInvoking: %s\n\n",dir,cmd) FLUSH;
X#endif
X    resetty();			/* make terminal well-behaved */
X    doshell(sh,cmd);		/* do the command */
X    noecho();			/* set no echo */
X    crmode();			/* and cbreak mode */
X#ifdef VERBOSE
X    IF(verbose)
X	fputs("\n(re-entering cbreak mode)\n",stdout) FLUSH;
X    ELSE
X#endif
X#ifdef TERSE
X	fputs("\n(+cbreak)\n",stdout) FLUSH;
X#endif
X#ifdef SERVER
X    if (chdir(spool)) {
X#else /* not SERVER */
X    if (chdir(spool) || chdir(ngdir)) {
X#endif /* SERVER */
X	printf(nocd,ngdir) FLUSH;
X	sig_catcher(0);
X    }
X}
X
X/*
X** cut_line() determines if a line is meant as a "cut here" marker.
X** Some examples that we understand:
X**
X**  BEGIN--cut here--cut here
X**
X**  ------------------ tear at this line ------------------
X**
X**  #----cut here-----cut here-----cut here-----cut here----#
X*/
Xbool
Xcut_line(str)
Xchar *str;
X{
X    char *cp, got_flag;
X    char word[80];
X    int  dash_cnt, equal_cnt;
X
X    /* Disallow any single-/double-quoted, parenthetical or c-commented
X    ** string lines.  Make sure it has the cut-phrase and at least 20
X    ** '-'s or '='s.  If only four '-'s are present, check for a duplicate
X    ** of the cut phrase.  If we succeed, return TRUE.
X    */
X    for (cp = str, dash_cnt = equal_cnt = 0; *cp; cp++) {
X	switch (*cp) {
X	case '-':
X	    dash_cnt++;
X	    break;
X	case '=':
X	    equal_cnt++;
X	    break;
X	case '/':
X	    if( *(cp+1) != '*' ) {
X		break;
X	    }
X	case '"':
X	case '\'':
X	case '(':
X	case ')':
X	case '[':
X	case ']':
X	case '{':
X	case '}':
X	    return FALSE;
X	}
X    }
X    if (dash_cnt < 4 && equal_cnt < 20)
X	return FALSE;
X
X    got_flag = 0;
X
X    for (*(cp = word) = '\0'; *str; str++) {
X	if (islower(*str))
X	    *cp++ = *str;
X	else if (isupper(*str))
X	    *cp++ = tolower(*str);
X	else {
X	    if (*word) {
X		*cp = '\0';
X		switch (got_flag) {
X		case 2:
X		    if (!strcmp(word, "line")
X		     || !strcmp(word, "here"))
X			return TRUE;
X		    break;
X		case 1:
X		    if (!strcmp(word, "this"))
X			got_flag = 2;
X		    if (!strcmp(word, "here")) {
X			if (dash_cnt >= 20 || equal_cnt >= 20)
X			    return TRUE;
X			dash_cnt = 20;
X			got_flag = 0;
X		    }
X		    break;
X		case 0:
X		    if (!strcmp( word, "cut")
X		     || !strcmp( word, "snip")
X		     || !strcmp( word, "tear"))
X			got_flag = 1;
X		    break;
X		}
X		*(cp = word) = '\0';
X	    }
X	}
X    } /* for *str */
X
X    return FALSE;
X}
END_OF_FILE
  if test 15981 -ne `wc -c <'respond.c'`; then
    echo shar: \"'respond.c'\" unpacked with wrong size!
  fi
  # end of 'respond.c'
fi
if test -f 'rn.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rn.c'\"
else
  echo shar: Extracting \"'rn.c'\" \(14023 characters\)
  sed "s/^X//" >'rn.c' <<'END_OF_FILE'
X/*  rn -- new readnews program
X *
X *  Original Author: lwall at sdcrdcf.UUCP (Larry Wall)
X *  Organization: System Development Corporation, Santa Monica
X *
X *  begun:   01/14/83
X *	1.0: 04/08/83
X *      2.0: 09/01/83
X *      RRN/RN: 11/01/89
X*/
X
Xstatic char rnid[] = "@(#)$Header: rn.c,v 4.3.3.2 90/08/20 16:48:19 davison Trn $";
Xstatic char patchlevel[] = "Trn v1.0.1 based on Rn patchlevel 47";
X
X/* $Log:	rn.c,v $
X * Revision 4.3.3.2  90/08/20  16:48:19  davison
X * Changed unthreaded group's default action, version #, email address.
X * 
X * Revision 4.3.3.1  90/07/21  20:31:38  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.4  90/04/03  23:11:33  sob
X * Added more information to the version command.
X * 
X * Revision 4.3.2.3  90/03/22  23:05:23  sob
X * Fixes provided by Wayne Davison <drivax!davison>
X * 
X * Revision 4.3.2.2  89/11/28  01:51:25  sob
X * Removed redundant #include directive.
X * 
X * Revision 4.3.2.1  89/11/08  02:27:38  sob
X * Release of RN 4.3 with RRN that can be compiled from the same
X * sources as either version of the program.
X * 
X * Revision 4.3.1.4  85/09/10  11:05:13  lwall
X * Improved %m in in_char().
X * 
X * Revision 4.3.1.3  85/05/16  16:47:10  lwall
X * Catchup confirmation didn't grok -t.
X * 
X * Revision 4.3.1.2  85/05/13  09:34:53  lwall
X * Fixed default after do_newsgroup() returns from Q command.
X * 
X * Revision 4.3.1.1  85/05/10  11:38:08  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:47:56  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#include "INTERN.h"
X#include "common.h"
X#include "rn.h"
X#include "EXTERN.h"
X#include "rcstuff.h"
X#include "term.h"
X#include "final.h"
X#include "ngdata.h"
X#include "util.h"
X#include "only.h"
X#include "ngsrch.h"
X#include "help.h"
X#include "last.h"
X#include "init.h"
X#include "intrp.h"
X#include "rcln.h"
X#include "sw.h"
X#include "addng.h"
X#include "ng.h"
X
Xvoid
Xrn_init()
X{
X    ;
X}
X
Xvoid
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X    bool foundany;
X    register char *s;
X    bool oh_for_the_good_old_days = FALSE;
X
X#if defined(USETHREADS) && !THREAD_INIT
X    /* Default to threaded operation if our name starts with a 't' */
X    if ((s = rindex(argv[0],'/')) == Nullch)
X	s = argv[0];
X    else
X	s++;
X    if (*s == 't')
X	use_threads = TRUE;
X#endif
X    foundany = initialize(argc,argv);
X
X    if (maxngtodo)
X	starthere = 0;
X    else if (!foundany) {		/* nothing to do? */
X#ifdef VERBOSE
X	if (verbose)
X	    fputs("\
XNo unread news in subscribed-to newsgroups.  To subscribe to a new\n\
Xnewsgroup use the g<newsgroup> command.\n\
X",stdout) FLUSH;
X#endif
X	starthere = nextrcline;
X    }
X
X    /* loop through all unread news */
X
X    {
X	char promptbuf[80];
X	bool special = FALSE;		/* temporarily allow newsgroup */
X					/*   with no unread news? */
X	bool retry;			/* cycle back to top of list? */
X	NG_NUM recent_ng = 0;
X	
X	current_ng = 0;
X	do {
X	    retry = FALSE;
X	    if (findlast) {
X		findlast = FALSE;
X		starthere = 0;
X		if (*lastngname) {
X		    if ((ng = find_ng(lastngname)) == nextrcline)
X			ng = 0;
X		    else {
X			set_ngname(lastngname);
X		    	set_toread(ng);
X			if (toread[ng] <= TR_NONE)
X			    ng = 0;
X		    }
X		}
X	    }
X	    else {
X		ng = starthere;
X		starthere = 0;
X	    }
X	    while (ng <= nextrcline) {	/* for each newsgroup */
X		mode = 'n';
X		if (ng >= nextrcline) {	/* after the last newsgroup? */
X		    ng = nextrcline;	/* force it to 1 after */
X#ifdef ONLY
X		    if (maxngtodo) {
X			if (retry)
X#ifdef VERBOSE
X			    IF(verbose)
X				printf("\nRestriction %s%s still in effect.\n",
X				    ngtodo[0],
X				    maxngtodo > 1 ? ", etc." : nullstr) FLUSH;
X			    ELSE
X#endif
X#ifdef TERSE
X				fputs("\n(\"Only\" mode.)\n",stdout) FLUSH;
X#endif
X			else {
X#ifdef VERBOSE
X			    IF(verbose)
X				fputs("\nNo articles under restriction.",
X				  stdout) FLUSH;
X			    ELSE
X#endif
X#ifdef TERSE
X				fputs("\nNo \"only\" articles.",stdout) FLUSH;
X#endif
X			    end_only();	/* release the restriction */
X			    retry = TRUE;
X			}
X		    }
X#endif
X		    dfltcmd = (retry ? "npq" : "qnp");
X#ifdef VERBOSE
X		    IF(verbose)
X			sprintf(promptbuf,
X			    "\n******** End of newsgroups--what next? [%s] ",
X			    dfltcmd);
X		    ELSE
X#endif
X#ifdef TERSE
X			sprintf(promptbuf,
X			    "\n**** End--next? [%s] ", dfltcmd);
X#endif
X		}
X		else {
X		    bool shoe_fits;	/* newsgroup matches restriction? */
X
X		    if (toread[ng] >= TR_NONE) {	/* recalc toread? */
X			set_ngname(rcline[ng]);
X			if (shoe_fits = (special || inlist(ngname)))
X			    set_toread(ng);
X			if (paranoid) {
X			    recent_ng = current_ng;
X			    current_ng = ng;
X			    cleanup_rc();
X					/* this may move newsgroups around */
X			    ng = current_ng;
X			    set_ngname(rcline[ng]);
X			}
X		    }
X		    if (toread[ng] < (maxngtodo||special ? TR_NONE : TR_ONE) || !shoe_fits) {
X					/* unwanted newsgroup? */
X			ng++;		/* then skip it */
X			continue;
X		    }
X    reprompt_newsgroup:
X#ifdef USETHREADS
X		    dfltcmd = (ThreadedGroup && select_on
X			&& (ART_NUM)toread[ng] >= select_on ? "+ynq" : "ynq");
X#else
X		    dfltcmd = "ynq";
X#endif
X#ifdef VERBOSE
X		    IF(verbose)
X			sprintf(promptbuf,
X			    "\n******** %3ld unread article%c in %s--read now? [%s] ",
X			    (long)toread[ng], (toread[ng]==TR_ONE ? ' ' : 's'),
X			    ngname, dfltcmd);	/* format prompt string */
X		    ELSE
X#endif
X#ifdef TERSE
X			sprintf(promptbuf,
X			    "\n**** %3ld in %s--read? [%s] ",
X			    (long)toread[ng],
X			    ngname,dfltcmd);	/* format prompt string */
X#endif
X		}
X		special = FALSE;	/* go back to normal mode */
X		if (ng != current_ng) {
X		    recent_ng = current_ng;
X					/* remember previous newsgroup */
X		    current_ng = ng;	/* remember current newsgroup */
X		}
X    reask_newsgroup:
X		unflush_output();	/* disable any ^O in effect */
X		fputs(promptbuf,stdout) FLUSH;/* print prompt */
X		fflush(stdout);
X    reinp_newsgroup:
X		eat_typeahead();
X		getcmd(buf);
X		if (errno || *buf == '\f') {
X		    putchar('\n') FLUSH; /* if return from stop signal */
X		    goto reask_newsgroup;	/* give them a prompt again */
X		}
X		setdef(buf,dfltcmd);
X#ifdef VERIFY
X		printcmd();
X#endif
X		switch (*buf) {
X		case 'p':		/* find previous unread newsgroup */
X		    do {
X			if (ng <= 0)
X			    break;
X			ng--;
X			if (toread[ng] == TR_NONE)
X			    set_toread(ng);
X		    } while (toread[ng] <= TR_NONE);
X		    break;
X		case 'P':		/* goto previous newsgroup */
X		    do {
X			if (ng <= 0)
X			    break;
X			ng--;
X		    } while (toread[ng] < TR_NONE);
X		    special = TRUE;	/* don't skip it if toread==0 */
X		    break;
X		case '-':
X		    ng = recent_ng;	/* recall previous newsgroup */
X		    special = TRUE;	/* don't skip it if toread==0 */
X		    break;
X		case 'q': case 'Q': case 'x':	/* quit? */
X		    oh_for_the_good_old_days = (*buf == 'x');
X		    putchar('\n') FLUSH;
X		    ng = nextrcline+1;	/* satisfy */
X		    retry = FALSE;	/*   loop conditions */
X		    break;
X		case '^':
X		    putchar('\n') FLUSH;
X		    ng = 0;
X		    break;
X		case 'n':		/* find next unread newsgroup */
X		    if (ng == nextrcline) {
X			putchar('\n') FLUSH;
X			retry = TRUE;
X		    }
X		    else if (toread[ng] > TR_NONE)
X			retry = TRUE;
X		    ng++;
X		    break;
X		case 'N':		/* goto next newsgroup */
X		    ng++;
X		    special = TRUE;	/* and don't skip it if toread==0 */
X		    break;
X		case '1':		/* goto 1st newsgroup */
X		    ng = 0;
X		    special = TRUE;	/* and don't skip it if toread==0 */
X		    break;
X		case '$':
X		    ng = nextrcline;	/* goto last newsgroup */
X		    retry = TRUE;
X		    break;
X		case 'L':
X		    list_newsgroups();
X		    goto reask_newsgroup;
X		case '/': case '?':	/* scan for newsgroup pattern */
X#ifdef NGSEARCH
X		    switch (ng_search(buf,TRUE)) {
X		    case NGS_ABORT:
X			goto reinp_newsgroup;
X		    case NGS_INTR:
X#ifdef VERBOSE
X			IF(verbose)
X			    fputs("\n(Interrupted)\n",stdout) FLUSH;
X			ELSE
X#endif
X#ifdef TERSE
X			    fputs("\n(Intr)\n",stdout) FLUSH;
X#endif
X			ng = current_ng;
X			goto reask_newsgroup;
X		    case NGS_FOUND:
X			special = TRUE;	/* don't skip it if toread==0 */
X			break;
X		    case NGS_NOTFOUND:
X#ifdef VERBOSE
X			IF(verbose)
X			    fputs("\n\nNot found--use g to add newsgroups\n",
X				stdout) FLUSH;
X			ELSE
X#endif
X#ifdef TERSE
X			    fputs("\n\nNot found\n",stdout) FLUSH;
X#endif
X			goto reask_newsgroup;
X		    }
X#else
X		    notincl("/");
X#endif
X		    break;
X		case 'm':
X#ifndef RELOCATE
X		    notincl("m");
X		    break;
X#endif		    
X		case 'g':	/* goto named newsgroup */
X		    if (!finish_command(FALSE))
X					/* if they didn't finish command */
X			goto reinp_newsgroup;	/* go try something else */
X		    for (s = buf+1; *s == ' '; s++);
X					/* skip leading spaces */
X		    if (!*s)
X			strcpy(s,ngname);
X#ifdef RELOCATE
X		    if (!get_ng(s,*buf=='m'))	/* try to find newsgroup */
X#else
X		    if (!get_ng(s,FALSE))	/* try to find newsgroup */
X#endif
X			ng = current_ng;/* if not found, go nowhere */
X		    special = TRUE;	/* don't skip it if toread==0 */
X		    break;
X#ifdef DEBUGGING
X		case 'D':
X		    printf("\nTries: %d Hits: %d\n",
X			softtries,softtries-softmisses) FLUSH;
X		    goto reask_newsgroup;
X#endif
X		case '!':		/* shell escape */
X		    if (escapade())	 /* do command */
X			goto reinp_newsgroup;
X					/* if rubbed out, re input */
X		    goto reask_newsgroup;
X		case Ctl('k'):		/* edit global KILL file */
X		    edit_kfile();
X		    goto reask_newsgroup;
X		case 'c':		/* catch up */
X#ifdef CATCHUP
Xreask_catchup:
X#ifdef VERBOSE
X		IF(verbose)
X		    in_char("\nDo you really want to mark everything as read? [yn] ", '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		    if (*buf == 'h') {
X#ifdef VERBOSE
X		    printf("Type y or SP to mark all articles as read.\n");
X		    printf("Type n to leave articles marked as they are.\n");
X#else
X		    printf("y or SP to mark all read.\n");
X		    printf("n to forget it.\n");
X#endif
X			goto reask_catchup;
X		    }
X		    else if (*buf!=' ' && *buf!='y' && *buf!='n' && *buf!='q') {
X			printf(hforhelp);
X			settle_down();
X			goto reask_catchup;
X		    } else if ( (*buf == ' ' || *buf == 'y') && ng<nextrcline )
X			catch_up(ng);
X		    else
X			retry = TRUE;
X		    ng++;
X#else
X		    notincl("c");
X#endif
X		    break;
X		case 'u':		/* unsubscribe */
X		    if (ng < nextrcline && toread[ng] >= TR_NONE) {
X					/* unsubscribable? */
X			printf(unsubto,rcline[ng]) FLUSH;
X			rcchar[ng] = NEGCHAR;
X					/* unsubscribe to (from?) it */
X			toread[ng] = TR_UNSUB;
X					/* and make line invisible */
X			ng++;		/* do an automatic 'n' */
X		    }
X		    break;
X		case 'h': {		/* help */
X		    int cmd;
X
X		    if ((cmd = help_ng()) > 0)
X			pushchar(cmd);
X		    goto reask_newsgroup;
X		}
X		case 'a':
X#ifndef FINDNEWNG
X		    notincl("a");
X		    goto reask_newsgroup;
X#else
X		    /* FALL THROUGH */
X#endif
X		case 'o':
X#ifdef ONLY
X		{
X#ifdef FINDNEWNG
X		    bool doscan = (*buf == 'a');
X#endif
X
X		    if (!finish_command(TRUE)) /* get rest of command */
X			goto reinp_newsgroup;	/* if rubbed out, try something else */
X		    end_only();
X		    if (buf[1]) {
X			bool minusd = instr(buf+1,"-d") != Nullch;
X
X			sw_list(buf+1);
X			if (minusd)
X			    cwd_check();
X			putchar('\n') FLUSH;
X#ifdef FINDNEWNG
X			if (doscan && maxngtodo)
X			    scanactive();
X#endif
X		    }
X		    ng = 0;		/* simulate ^ */
X		    retry = FALSE;
X		    break;
X		}
X#else
X		    notincl("o");
X		    goto reask_newsgroup;
X#endif
X		case '&':
X		    if (switcheroo()) /* get rest of command */
X			goto reinp_newsgroup;	/* if rubbed out, try something else */
X		    goto reask_newsgroup;
X		case 'l': {		/* list other newsgroups */
X		    if (!finish_command(TRUE)) /* get rest of command */
X			goto reinp_newsgroup;	/* if rubbed out, try something else */
X		    for (s = buf+1; *s == ' '; s++);
X		    			/* skip leading spaces */
X		    sprintf(cmd_buf,"%s '%s'",filexp(NEWSGROUPS),s);
X		    resetty();
X		    if (doshell(sh,cmd_buf))
X#ifdef VERBOSE
X			IF(verbose)
X			    fputs("    (Error from newsgroups program)\n",
X				stdout) FLUSH;
X			ELSE
X#endif
X#ifdef TERSE
X			    fputs("(Error)\n",stdout) FLUSH;
X#endif
X		    noecho();
X		    crmode();
X		    goto reask_newsgroup;
X		}
X#ifdef USETHREADS
X		case 'U': case '+':
X#endif
X		case '.': case '=':
X		case 'y': case 'Y': /* do normal thing */
X		    if (ng >= nextrcline) {
X			fputs("\nNot on a newsgroup.",stdout) FLUSH;
X			goto reask_newsgroup;
X		    }
X#ifdef USETHREADS
X		    else if (*buf == '+' || *buf == 'U' || *buf == '=') {
X			buf[1] = '\0';
X			s = savestr(buf);
X		    }
X#else
X		    if (*buf == '=')
X			s = savestr("=");
X#endif
X		    else if (*buf == '.') {	/* start command? */
X			if (!finish_command(FALSE)) /* get rest of command */
X			    goto reinp_newsgroup;
X			s = savestr(buf+1);
X					/* do_newsgroup will free it */
X		    }
X		    else
X			s = Nullch;
X		    if (toread[ng])
X			retry = TRUE;
X		    switch (do_newsgroup(s)) {
X		    case NG_ERROR:
X		    case NG_NORM:
X			ng++;
X			break;
X		    case NG_ASK:
X			goto reprompt_newsgroup;
X		    case NG_MINUS:
X			ng = recent_ng;	/* recall previous newsgroup */
X			special = TRUE;	/* don't skip it if toread==0 */
X			break;
X		    }
X		    break;
X#ifdef STRICTCR
X		case '\n':
X		    fputs(badcr,stdout) FLUSH;
X		    goto reask_newsgroup;
X#endif
X		case 'v':
X		    printf("\n%s",rnid);
X		    printf("\n%s",patchlevel);
X		    printf("\nSend bugs to davison at dri.com (...!uunet!drivax!davison)\n") FLUSH;
X		    goto reask_newsgroup;
X		default:
X		    printf("\n%s",hforhelp) FLUSH;
X		    settle_down();
X		    goto reask_newsgroup;
X		}
X	    }
X	} while (retry);
X    }
X
X    /* now write .newsrc back out */
X
X    write_rc();
X
X    if (oh_for_the_good_old_days)
X	get_old_rc();
X
X    finalize(0);			/* and exit */
X}
X
X/* set current newsgroup */
X
Xvoid
Xset_ngname(what)
Xchar *what;
X{
X    int len = strlen(what)+1;
X
X    growstr(&ngname,&ngnlen,len);
X    strcpy(ngname,what);
X    growstr(&ngdir,&ngdlen,len);
X    strcpy(ngdir,getngdir(ngname));
X}
X
Xstatic char *myngdir;
Xstatic int ngdirlen = 0;
X
Xchar *
Xgetngdir(ngnam)
Xchar *ngnam;
X{
X    register char *s;
X
X    growstr(&myngdir,&ngdirlen,strlen(ngnam)+1);
X    strcpy(myngdir,ngnam);
X    for (s = myngdir; *s; s++)
X	if (*s == '.')
X	    *s = '/';
X    return myngdir;
X}
X
END_OF_FILE
  if test 14023 -ne `wc -c <'rn.c'`; then
    echo shar: \"'rn.c'\" unpacked with wrong size!
  fi
  # end of 'rn.c'
fi
echo shar: End of archive 9 \(of 14\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 14 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
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