v23i070: TRN, version of RN that follows conversation threads, Part11/14

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


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

---- Cut Here and unpack ----
#!/bin/sh
# this is part 11 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file rcln.c continued
#
CurArch=11
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 rcln.c"
sed 's/^X//' << 'SHAR_EOF' >> rcln.c
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#ifdef DEBUGGING
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#ifdef DEBUGGING
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
SHAR_EOF
echo "File rcln.c is complete"
chmod 0660 rcln.c || echo "restore of rcln.c fails"
echo "x - extracting rcln.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > rcln.h &&
X/* $Header: rcln.h,v 4.3 85/05/01 11:45:52 lwall Exp $
X *
X * $Log:	rcln.h,v $
X * Revision 4.3  85/05/01  11:45:52  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
X#ifdef DEBUGGING
XEXT ART_NUM ngmax[MAXRCLINE];
X#endif
X
Xvoid    rcln_init();
X#ifdef CATCHUP
X    void	catch_up();
X#endif
Xint	addartnum();
X#ifdef MCHASE
X    void	subartnum();
X#endif
Xvoid	prange();
Xvoid	set_toread();
Xvoid	checkexpired();
SHAR_EOF
chmod 0660 rcln.h || echo "restore of rcln.h fails"
echo "x - extracting rcstuff.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > rcstuff.c &&
X/* $Header: rcstuff.c,v 4.3.3.1 90/06/20 22:39:28 davison Trn $
X *
X * $Log:	rcstuff.c,v $
X * Revision 4.3.3.1  90/06/20  22:39:28  davison
X * Initial Trn Release
X * 
X * Revision 4.3.2.5  90/05/04  00:44:07  sob
X * Fixes to add_newsgroup() from lar at usl.edu.
X * 
X * Revision 4.3.2.4  90/04/23  00:25:45  sob
X * Changed atoi to atol.
X * 
X * Revision 4.3.2.3  89/12/20  23:25:04  sob
X * Changed the maximum lenght of a newsgroup name from 20 to 40 characters.
X * 
X * Revision 4.3.2.2  89/11/26  18:22:26  sob
X * Added changes to addnewgroup() to cause rn to ask once and only once
X * to add a new group to .newsrc. 
X * Fix provided by Fletcher Mattox <fletcher at cs.utexas.edu>
X * 
X * Revision 4.3.2.1  89/11/06  00:58:29  sob
X * Added RRN support from NNTP 1.5
X * 
X * Revision 4.3.1.5  86/07/24  14:09:10  lwall
X * Removed check for spool directory existence in get_ng.
X * 
X * Revision 4.3.1.4  85/09/10  11:04:44  lwall
X * Improved %m in in_char().
X * 
X * Revision 4.3.1.3  85/05/29  09:13:25  lwall
X * %d that should be %ld.
X * 
X * Revision 4.3.1.2  85/05/17  11:40:08  lwall
X * Sped up "rn -c" by not mallocing unnecessarily.
X * 
X * Revision 4.3.1.1  85/05/10  11:37:18  lwall
X * Branch for patches.
X * 
X * Revision 4.3  85/05/01  11:45:56  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 "ngdata.h"
X#include "term.h"
X#include "final.h"
X#include "rn.h"
X#include "intrp.h"
X#include "only.h"
X#include "rcln.h"
X#ifdef SERVER
X#include "server.h"
X#endif
X#include "INTERN.h"
X#include "rcstuff.h"
X
Xchar *rcname INIT(Nullch);		/* path name of .newsrc file */
Xchar *rctname INIT(Nullch);		/* path name of temp .newsrc file */
Xchar *rcbname INIT(Nullch);		/* path name of backup .newsrc file */
Xchar *softname INIT(Nullch);		/* path name of .rnsoft file */
XFILE *rcfp INIT(Nullfp);			/* .newsrc file pointer */
X
X#ifdef HASHNG
X    short hashtbl[HASHSIZ];
X#endif
X
Xbool
Xrcstuff_init()
X{
X    register NG_NUM newng;
X    register char *s;
X    register int i;
X    register bool foundany = FALSE;
X    char *some_buf;
X    long length;
X#ifdef SERVER
X    char *cp;
X#endif /* SERVER */
X
X#ifdef HASHNG
X    for (i=0; i<HASHSIZ; i++)
X	hashtbl[i] = -1;
X#endif
X
X    /* make filenames */
X
X#ifdef SERVER
X
X    if (cp = getenv("NEWSRC"))
X	rcname = savestr(filexp(cp));
X    else
X	rcname = savestr(filexp(RCNAME));
X
X#else /* not SERVER */
X
X    rcname = savestr(filexp(RCNAME));
X
X#endif /* SERVER */
X
X    rctname = savestr(filexp(RCTNAME));
X    rcbname = savestr(filexp(RCBNAME));
X    softname = savestr(filexp(SOFTNAME));
X    
X    /* make sure the .newsrc file exists */
X
X    newsrc_check();
X
X    /* open .rnsoft file containing soft ptrs to active file */
X
X    tmpfp = fopen(softname,"r");
X    if (tmpfp == Nullfp)
X	writesoft = TRUE;
X
X    /* read in the .newsrc file */
X
X    for (nextrcline = 0;
X	(some_buf = get_a_line(buf,LBUFLEN,rcfp)) != Nullch;
X	nextrcline++) {
X					/* for each line in .newsrc */
X	char tmpbuf[10];
X
X	newng = nextrcline;		/* get it into a register */
X	length = len_last_line_got;	/* side effect of get_a_line */
X	if (length <= 1) {		/* only a newline??? */
X	    nextrcline--;		/* compensate for loop increment */
X	    continue;
X	}
X	if (newng >= MAXRCLINE) {	/* check for overflow */
X	    fputs("Too many lines in .newsrc\n",stdout) FLUSH;
X	    finalize(1);
X	}
X	if (tmpfp != Nullfp && fgets(tmpbuf,10,tmpfp) != Nullch)
X	    softptr[newng] = atol(tmpbuf);
X	else
X	    softptr[newng] = 0;
X	some_buf[--length] = '\0';	/* wipe out newline */
X	if (checkflag)			/* no extra mallocs for -c */
X	    rcline[newng] = some_buf;
X	else if (some_buf == buf) {
X	    rcline[newng] = savestr(some_buf);
X					/* make a semipermanent copy */
X	}
X	else {
X	    /*NOSTRICT*/
X#ifndef lint
X	    some_buf = saferealloc(some_buf,(MEM_SIZE)(length+1));
X#endif /* lint */
X	    rcline[newng] = some_buf;
X	}
X#ifdef NOTDEF
X	if (strnEQ(some_buf,"to.",3)) {	/* is this a non-newsgroup? */
X	    nextrcline--;		/* destroy this line */
X	    continue;
X	}
X#endif
X	if (*some_buf == ' ' ||
X	  *some_buf == '\t' ||
X	  strnEQ(some_buf,"options",7)) {		/* non-useful line? */
X	    toread[newng] = TR_JUNK;
X	    rcchar[newng] = ' ';
X	    rcnums[newng] = 0;
X	    continue;
X	}
X	for (s = rcline[newng]; *s && *s != ':' && *s != NEGCHAR; s++) ;
X	if (!*s && !checkflag) {
X#ifndef lint
X	    rcline[newng] = saferealloc(rcline[newng],(MEM_SIZE)length+2);
X#endif /* lint */
X	    s = rcline[newng] + length;
X	    *s = ':';
X	    *(s+1) = '\0';
X	}
X	rcchar[newng] = *s;		/* salt away the : or ! */
X	rcnums[newng] = (char)(s - rcline[newng]); 
X	rcnums[newng]++;		/* remember where it was */
X	*s = '\0';			/* null terminate newsgroup name */
X#ifdef HASHNG
X	if (!checkflag)
X	    sethash(newng);
X#endif
X	if (rcchar[newng] == NEGCHAR) {
X	    toread[newng] = TR_UNSUB;
X	    continue;
X	}
X
X	/* now find out how much there is to read */
X
X	if (!inlist(buf) || (suppress_cn && foundany && !paranoid))
X	    toread[newng] = TR_NONE;	/* no need to calculate now */
X	else
X	    set_toread(newng);
X#ifdef VERBOSE
X	if (!checkflag && softmisses == 1) {
X	    softmisses++;		/* lie a little */
X	    fputs("(Revising soft pointers--be patient.)\n",stdout) FLUSH;
X	}
X#endif
X	if (toread[newng] > TR_NONE) {	/* anything unread? */
X	    if (!foundany) {
X		starthere = newng;
X		foundany = TRUE;	/* remember that fact*/
X	    }
X	    if (suppress_cn) {		/* if no listing desired */
X		if (checkflag) {	/* if that is all they wanted */
X		    finalize(1);	/* then bomb out */
X		}
X	    }
X	    else {
X#ifdef VERBOSE
X		IF(verbose)
X		    printf("Unread news in %-40s %5ld article%s\n",
X			rcline[newng],(long)toread[newng],
X			toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
X		ELSE
X#endif
X#ifdef TERSE
X		    printf("%s: %ld article%s\n",
X			rcline[newng],(long)toread[newng],
X			toread[newng]==TR_ONE ? nullstr : "s") FLUSH;
X#endif
X		if (int_count) {
X		    countdown = 1;
X		    int_count = 0;
X		}
X		if (countdown) {
X		    if (! --countdown) {
X			fputs("etc.\n",stdout) FLUSH;
X			if (checkflag)
X			    finalize(1);
X			suppress_cn = TRUE;
X		    }
X		}
X	    }
X	}
X    }
X    fclose(rcfp);			/* close .newsrc */
X    if (tmpfp != Nullfp)
X	fclose(tmpfp);			/* close .rnsoft */
X    if (checkflag) {			/* were we just checking? */
X	finalize(foundany);		/* tell them what we found */
X    }
X    if (paranoid)
X	cleanup_rc();
X
X#ifdef DEBUGGING
X    if (debug & DEB_HASH) {
X	page_init();
X	for (i=0; i<HASHSIZ; i++) {
X	    sprintf(buf,"%d	%d",i,hashtbl[i]);
X	    print_lines(buf,NOMARKING);
X	}
X    }
X#endif
X
X    return foundany;
X}
X
X/* try to find or add an explicitly specified newsgroup */
X/* returns TRUE if found or added, FALSE if not. */
X/* assumes that we are chdir'ed to SPOOL */
X
X#ifdef SERVER
Xstatic int addnewbydefault = 0;
X#endif /* SERVER */
X
Xbool
Xget_ng(what,do_reloc)
Xchar *what;
Xbool do_reloc;
X{
X    char *ntoforget;
X    char promptbuf[128];
X#ifdef SERVER
X    char ser_line[256];
X#endif /* SERVER */
X
X#ifdef VERBOSE
X    IF(verbose)
X	ntoforget = "Type n to forget about this newsgroup.\n";
X    ELSE
X#endif
X#ifdef TERSE
X	ntoforget = "n to forget it.\n";
X#endif
X    if (index(what,'/')) {
X	dingaling();
X	printf("\nBad newsgroup name.\n") FLUSH;
X	return FALSE;
X    }
X    set_ngname(what);
X    ng = find_ng(ngname);
X    if (ng == nextrcline) {		/* not in .newsrc? */
X
X#ifdef SERVER
X	sprintf(ser_line, "GROUP %s", ngname);
X	put_server(ser_line);
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) {
X	    if (atoi(ser_line) != ERR_NOGROUP) {
X		fprintf(stderr, "Server response to GROUP %s:\n%s\n",
X		    ngname, ser_line);
X	    }
X#else /* not SERVER */
X
X	if ((softptr[ng] = findact(buf,ngname,strlen(ngname),0L)) < 0 ) {
X
X#endif /* SERVER */
X
X	    dingaling();
X#ifdef VERBOSE
X	    IF(verbose)
X		printf("\nNewsgroup %s does not exist!\n",ngname) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		printf("\nNo %s!\n",ngname) FLUSH;
X#endif
X	    sleep(2);
X	    return FALSE;
X	}
X#ifdef SERVER
X	if (addnewbydefault) {
X		printf("(Adding %s to end of your .newsrc)\n", ngname);
X	        ng = add_newsgroup(ngname, ':');
X	        do_reloc = FALSE;
X	} else {
X#endif /* SERVER */
X#ifdef VERBOSE
X	IF(verbose)
X	    sprintf(promptbuf,"\nNewsgroup %s not in .newsrc--add? [yn] ",ngname);
X	ELSE
X#endif
X#ifdef TERSE
X	    sprintf(promptbuf,"\nAdd %s? [yn] ",ngname);
X#endif
Xreask_add:
X	in_char(promptbuf,'A');
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		printf("Type y or SP to add %s to your .newsrc.\n", ngname)
X		  FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("y or SP to add\n",stdout) FLUSH;
X#endif
X	    fputs(ntoforget,stdout) FLUSH;
X	    goto reask_add;
X	}
X	else if (*buf == 'n' || *buf == 'q') {
X	    ng = add_newsgroup(ngname, '!');
X	    return FALSE;
X	}
X	else if (*buf == 'y') {
X	    ng = add_newsgroup(ngname, ':');
X	    do_reloc = FALSE;
X	}
X#ifdef SERVER
X	else if (*buf == 'Y') {
X	    fputs(
X	"(I'll add all new newsgroups to the end of your .newsrc.)\n", stdout);
X	    addnewbydefault = 1;
X	    printf("(Adding %s to end of your .newsrc)\n", ngname);
X	    ng = add_newsgroup(ngname, ':');
X	    do_reloc = FALSE;
X	}
X#endif /* SERVER */
X	else {
X	    fputs(hforhelp,stdout) FLUSH;
X	    settle_down();
X	    goto reask_add;
X	}
X#ifdef SERVER
X      }
X#endif /* SERVER */
X    }
X    else if (rcchar[ng] == NEGCHAR) {	/* unsubscribed? */
X#ifdef VERBOSE
X	IF(verbose)
X	    sprintf(promptbuf,
X"\nNewsgroup %s is currently unsubscribed to--resubscribe? [yn] ",ngname)
X  FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    sprintf(promptbuf,"\n%s unsubscribed--resubscribe? [yn] ",ngname)
X	      FLUSH;
X#endif
Xreask_unsub:
X	in_char(promptbuf,'R');
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		printf("Type y or SP to resubscribe to %s.\n", ngname) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("y or SP to resubscribe.\n",stdout) FLUSH;
X#endif
X	    fputs(ntoforget,stdout) FLUSH;
X	    goto reask_unsub;
X	}
X	else if (*buf == 'n' || *buf == 'q') {
X	    return FALSE;
X	}
X	else if (*buf == 'y') {
X	    rcchar[ng] = ':';
X	}
X	else {
X	    fputs(hforhelp,stdout) FLUSH;
X	    settle_down();
X	    goto reask_unsub;
X	}
X    }
X
X    /* now calculate how many unread articles in newsgroup */
X
X    set_toread(ng);
X#ifdef RELOCATE
X    if (do_reloc)
X	ng = relocate_newsgroup(ng,-1);
X#endif
X    return toread[ng] >= TR_NONE;
X}
X
X/* add a newsgroup to the .newsrc file (eventually) */
X
XNG_NUM
Xadd_newsgroup(ngn, c)
Xchar *ngn, c;
X{
X    register NG_NUM newng = nextrcline++;
X					/* increment max rcline index */
X    
X    rcnums[newng] = strlen(ngn) + 1;
X    rcline[newng] = safemalloc((MEM_SIZE)(rcnums[newng] + 1));
X    strcpy(rcline[newng],ngn);		/* and copy over the name */
X    *(rcline[newng] + rcnums[newng]) = '\0';
X    rcchar[newng] = c;			/* subscribe or unsubscribe */
X    toread[newng] = TR_NONE;	/* just for prettiness */
X#ifdef HASHNG
X    sethash(newng);			/* so we can find it again */
X#endif
X#ifdef RELOCATE
X    return c=='!' ? newng : relocate_newsgroup(newng,-1);
X#else
X    return newng;
X#endif
X}
X
X#ifdef RELOCATE
XNG_NUM
Xrelocate_newsgroup(ngx,newng)
XNG_NUM ngx;
XNG_NUM newng;
X{
X    char *dflt = (ngx!=current_ng ? "$^.L" : "$^L");
X    char *tmprcline;
X    ART_UNREAD tmptoread;
X    char tmprcchar;
X    char tmprcnums;
X    ACT_POS tmpsoftptr;
X    register NG_NUM i;
X#ifdef DEBUGGING
X    ART_NUM tmpngmax;
X#endif
X#ifdef CACHEFIRST
X    ART_NUM tmpabs1st;
X#endif
X    
X    starthere = 0;                      /* Disable this optimization */
X    writesoft = TRUE;			/* Update soft pointer file */
X    if (ngx < nextrcline-1) {
X#ifdef HASHNG
X	for (i=0; i<HASHSIZ; i++) {
X	    if (hashtbl[i] > ngx)
X		--hashtbl[i];
X	    else if (hashtbl[i] == ngx)
X		hashtbl[i] = nextrcline-1;
X	}
X#endif
X	tmprcline = rcline[ngx];
X	tmptoread = toread[ngx];
X	tmprcchar = rcchar[ngx];
X	tmprcnums = rcnums[ngx];
X	tmpsoftptr = softptr[ngx];
X#ifdef DEBUGGING
X	tmpngmax = ngmax[ngx];
X#endif
X#ifdef CACHEFIRST
X	tmpabs1st = abs1st[ngx];
X#endif
X	for (i=ngx+1; i<nextrcline; i++) {
X	    rcline[i-1] = rcline[i];
X	    toread[i-1] = toread[i];
X	    rcchar[i-1] = rcchar[i];
X	    rcnums[i-1] = rcnums[i];
X	    softptr[i-1] = softptr[i];
X#ifdef DEBUGGING
X	    ngmax[i-1] = ngmax[i];
X#endif
X#ifdef CACHEFIRST
X	    abs1st[i-1] = abs1st[i];
X#endif
X	}
X	rcline[nextrcline-1] = tmprcline;
X	toread[nextrcline-1] = tmptoread;
X	rcchar[nextrcline-1] = tmprcchar;
X	rcnums[nextrcline-1] = tmprcnums;
X	softptr[nextrcline-1] = tmpsoftptr;
X#ifdef DEBUGGING
X	ngmax[nextrcline-1] = tmpngmax;
X#endif
X#ifdef CACHEFIRST
X	abs1st[nextrcline-1] = tmpabs1st;
X#endif
X    }
X    if (current_ng > ngx)
X	current_ng--;
X    if (newng < 0) {
X      reask_reloc:
X	unflush_output();		/* disable any ^O in effect */
X#ifdef SERVER
X	if (addnewbydefault) {
X	    buf[0] = '$';
X	    buf[1] = '\0';
X	} else {
X#endif /* SERVER */
X#ifdef VERBOSE
X	IF(verbose)
X	    printf("\nPut newsgroup where? [%s] ", dflt);
X	ELSE
X#endif
X#ifdef TERSE
X	    printf("\nPut where? [%s] ", dflt);
X#endif
X	fflush(stdout);
X      reinp_reloc:
X	eat_typeahead();
X	getcmd(buf);
X#ifdef SERVER
X	}
X#endif /* SERVER */
X	if (errno || *buf == '\f') {
X			    /* if return from stop signal */
X	    goto reask_reloc;	/* give them a prompt again */
X	}
X	setdef(buf,dflt);
X#ifdef VERIFY
X	printcmd();
X#endif
X	if (*buf == 'h') {
X#ifdef VERBOSE
X	    IF(verbose) {
X		printf("\n\n\
XType ^ to put the newsgroup first (position 0).\n\
XType $ to put the newsgroup last (position %d).\n", nextrcline-1);
X		printf("\
XType . to put it before the current newsgroup (position %d).\n", current_ng);
X		printf("\
XType -newsgroup name to put it before that newsgroup.\n\
XType +newsgroup name to put it after that newsgroup.\n\
XType a number between 0 and %d to put it at that position.\n", nextrcline-1);
X		printf("\
XType L for a listing of newsgroups and their positions.\n") FLUSH;
X	    }
X	    ELSE
X#endif
X#ifdef TERSE
X	    {
X		printf("\n\n\
X^ to put newsgroup first (pos 0).\n\
X$ to put last (pos %d).\n", nextrcline-1);
X		printf("\
X. to put before current newsgroup (pos %d).\n", current_ng);
X		printf("\
X-newsgroup to put before newsgroup.\n\
X+newsgroup to put after.\n\
Xnumber in 0-%d to put at that pos.\n", nextrcline-1);
X		printf("\
XL for list of .newsrc.\n") FLUSH;
X	    }
X#endif
X	    goto reask_reloc;
X	}
X	else if (*buf == 'L') {
X	    putchar('\n') FLUSH;
X	    list_newsgroups();
X	    goto reask_reloc;
X	}
X	else if (isdigit(*buf)) {
X	    if (!finish_command(TRUE))	/* get rest of command */
X		goto reinp_reloc;
X	    newng = atol(buf);
X	    if (newng < 0)
X		newng = 0;
X	    if (newng >= nextrcline)
X		return nextrcline-1;
X	}
X	else if (*buf == '^') {
X	    putchar('\n') FLUSH;
X	    newng = 0;
X	}
X	else if (*buf == '$') {
X	    putchar('\n') FLUSH;
X	    return nextrcline-1;
X	}
X	else if (*buf == '.') {
X	    putchar('\n') FLUSH;
X	    newng = current_ng;
X	}
X	else if (*buf == '-' || *buf == '+') {
X	    if (!finish_command(TRUE))	/* get rest of command */
X		goto reinp_reloc;
X	    newng = find_ng(buf+1);
X	    if (newng == nextrcline) {
X		fputs("Not found.",stdout) FLUSH;
X		goto reask_reloc;
X	    }
X	    if (*buf == '+')
X		newng++;
X	}
X	else {
X	    printf("\n%s",hforhelp) FLUSH;
X	    settle_down();
X	    goto reask_reloc;
X	}
X    }
X    if (newng < nextrcline-1) {
X#ifdef HASHNG
X	for (i=0; i<HASHSIZ; i++) {
X	    if (hashtbl[i] == nextrcline-1)
X		hashtbl[i] = newng;
X	    else if (hashtbl[i] >= newng)
X		++hashtbl[i];
X	}
X#endif
X	tmprcline = rcline[nextrcline-1];
X	tmptoread = toread[nextrcline-1];
X	tmprcchar = rcchar[nextrcline-1];
X	tmprcnums = rcnums[nextrcline-1];
X	tmpsoftptr = softptr[nextrcline-1];
X#ifdef DEBUGGING
X	tmpngmax = ngmax[nextrcline-1];
X#endif
X#ifdef CACHEFIRST
X	tmpabs1st = abs1st[nextrcline-1];
X#endif
X	for (i=nextrcline-2; i>=newng; i--) {
X	    rcline[i+1] = rcline[i];
X	    toread[i+1] = toread[i];
X	    rcchar[i+1] = rcchar[i];
X	    rcnums[i+1] = rcnums[i];
X	    softptr[i+1] = softptr[i];
X#ifdef DEBUGGING
X	    ngmax[i+1] = ngmax[i];
X#endif
X#ifdef CACHEFIRST
X	    abs1st[i+1] = abs1st[i];
X#endif
X	}
X	rcline[newng] = tmprcline;
X	toread[newng] = tmptoread;
X	rcchar[newng] = tmprcchar;
X	rcnums[newng] = tmprcnums;
X	softptr[newng] = tmpsoftptr;
X#ifdef DEBUGGING
X	ngmax[newng] = tmpngmax;
X#endif
X#ifdef CACHEFIRST
X	abs1st[newng] = tmpabs1st;
X#endif
X    }
X    if (current_ng >= newng)
X	current_ng++;
X    return newng;
X}
X#endif
X
X/* List out the newsrc with annotations */
X
Xvoid
Xlist_newsgroups()
X{
X    register NG_NUM i;
X    char tmpbuf[2048];
X    static char *status[] = {"(READ)","(UNSUB)","(BOGUS)","(JUNK)"};
X    int cmd;
X
X    page_init();
X    print_lines("\
X  #  Status  Newsgroup\n\
X",STANDOUT);
X    for (i=0; i<nextrcline && !int_count; i++) {
X	if (toread[i] >= 0)
X	    set_toread(i);
X	*(rcline[i] + rcnums[i] - 1) = rcchar[i];
X	if (toread[i] > 0)
X	    sprintf(tmpbuf,"%3d %6ld   ",i,(long)toread[i]);
X	else
X	    sprintf(tmpbuf,"%3d %7s  ",i,status[-toread[i]]);
X	safecpy(tmpbuf+13,rcline[i],2034);
X	*(rcline[i] + rcnums[i] - 1) = '\0';
X	if (cmd = print_lines(tmpbuf,NOMARKING)) {
X	    if (cmd > 0)
X		pushchar(cmd);
X	    break;
X	}
X    }
X    int_count = 0;
X}
X
X/* find a newsgroup in .newsrc */
X
XNG_NUM
Xfind_ng(ngnam)
Xchar *ngnam;
X{
X    register NG_NUM ngnum;
X#ifdef HASHNG
X    register int hashix = hash(ngnam);
X    register int incr = 1;
X
X    while ((ngnum = hashtbl[hashix]) >= 0) {
X	if (strEQ(rcline[ngnum], ngnam) && toread[ngnum] >= TR_UNSUB)
X	    return ngnum;
X	hashix = (hashix + incr) % HASHSIZ;
X	incr += 2;			/* offsets from original are in n*2 */
X    }
X    return nextrcline;			/* = notfound */
X
X#else /* just do linear search */
X
X    for (ngnum = 0; ngnum < nextrcline; ngnum++) {
X	if (strEQ(rcline[ngnum],ngnam))
X	    break;
X    }
X    return ngnum;
X#endif
X}
X
Xvoid
Xcleanup_rc()
X{
X    register NG_NUM ngx;
X    register NG_NUM bogosity = 0;
X
X#ifdef VERBOSE
X    IF(verbose)
X	fputs("Checking out your .newsrc--hang on a second...\n",stdout)
X	  FLUSH;
X    ELSE
X#endif
X#ifdef TERSE
X	fputs("Checking .newsrc--hang on...\n",stdout) FLUSH;
X#endif
X    for (ngx = 0; ngx < nextrcline; ngx++) {
X	if (toread[ngx] >= TR_UNSUB) {
X	    set_toread(ngx);		/* this may reset newsgroup */
X					/* or declare it bogus */
X	}
X	if (toread[ngx] == TR_BOGUS)
X	    bogosity++;
X    }
X    for (ngx = nextrcline-1; ngx >= 0 && toread[ngx] == TR_BOGUS; ngx--)
X	bogosity--;			/* discount already moved ones */
X    if (nextrcline > 5 && bogosity > nextrcline / 2) {
X	fputs(
X"It looks like the active file is messed up.  Contact your news administrator,\n\
X",stdout);
X	fputs(
X"leave the \"bogus\" groups alone, and they may come back to normal.  Maybe.\n\
X",stdout) FLUSH;
X    }
X#ifdef RELOCATE
X    else if (bogosity) {
X#ifdef VERBOSE
X	IF(verbose)
X	    fputs("Moving bogus newsgroups to the end of your .newsrc.\n",
X		stdout) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    fputs("Moving boguses to the end.\n",stdout) FLUSH;
X#endif
X	for (; ngx >= 0; ngx--) {
X	    if (toread[ngx] == TR_BOGUS)
X		relocate_newsgroup(ngx,nextrcline-1);
X	}
X#ifdef DELBOGUS
Xreask_bogus:
X	in_char("Delete bogus newsgroups? [ny] ", 'D');
X	putchar('\n') FLUSH;
X	setdef(buf,"n");
X#ifdef VERIFY
X	printcmd();
X#endif
X	if (*buf == 'h') {
X#ifdef VERBOSE
X	    IF(verbose)
X		fputs("\
XType y to delete bogus newsgroups.\n\
XType n or SP to leave them at the end in case they return.\n\
X",stdout) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("y to delete, n to keep\n",stdout) FLUSH;
X#endif
X	    goto reask_bogus;
X	}
X	else if (*buf == 'n' || *buf == 'q')
X	    ;
X	else if (*buf == 'y') {
X	    while (toread[nextrcline-1] == TR_BOGUS && nextrcline > 0)
X		--nextrcline;		/* real tough, huh? */
X	}
X	else {
X	    fputs(hforhelp,stdout) FLUSH;
X	    settle_down();
X	    goto reask_bogus;
X	}
X#endif
X    }
X#else
X#ifdef VERBOSE
X    IF(verbose)
X	fputs("You should edit bogus newsgroups out of your .newsrc.\n",
X	    stdout) FLUSH;
X    ELSE
X#endif
X#ifdef TERSE
X	fputs("Edit boguses from .newsrc.\n",stdout) FLUSH;
X#endif
X#endif
X    paranoid = FALSE;
X}
X
X#ifdef HASHNG
X/* make an entry in the hash table for the current newsgroup */
X
Xvoid
Xsethash(thisng)
XNG_NUM thisng;
X{
X    register int hashix = hash(rcline[thisng]);
X    register int incr = 1;
X#ifdef DEBUGGING
X    static int hashhits = 0, hashtries = 0;
X#endif
X
X#ifdef DEBUGGING
X    hashtries++;
X#endif
X    while (hashtbl[hashix] >= 0) {
X#ifdef DEBUGGING
X	hashhits++;
X	if (debug & DEB_HASH) {
X	    printf("  Hash hits: %d / %d\n",hashhits, hashtries) FLUSH;
X	}
X	hashtries++;
X#endif
X	hashix = (hashix + incr) % HASHSIZ;
X	incr += 2;			/* offsets from original are in n*2 */
X    }
X    hashtbl[hashix] = thisng;
X}
X
Xshort prime[] = {1,2,-3,-5,7,11,-13,-17,19,23,-29,-31,37,41,-43,-47,53,57,-59,
X    -61,67,71,-73,-79,83,89,-97,-101,1,1,1,1,1,1,1,1,1,1,1,1};
X
Xint
Xhash(ngnam)
Xregister char *ngnam;
X{
X    register int i = 0;
X    register int ch;
X    register int sum = 0;
X#ifdef DEBUGGING
X    char *ngn = ngnam;
X#endif
X
X    while (ch = *ngnam++) {
X	sum += (ch + i) * prime[i];   /* gives ~ 10% hits at 25% full */
X	i++;
X    }
X#ifdef DEBUGGING
X    if (debug & DEB_HASH)
X	printf("hash(%s) => %d => %d\n",ngn, sum, (sum<0?-sum:sum)%HASHSIZ)
X	  FLUSH;
X#endif
X    if (sum < 0)
X	sum = -sum;
X    return sum % HASHSIZ;
X}
X
X#endif
X
Xvoid
Xnewsrc_check()
X{
X    rcfp = fopen(rcname,"r");		/* open it */
X    if (rcfp == Nullfp) {			/* not there? */
X#ifdef VERBOSE
X	IF(verbose)
X	    fputs("\
XTrying to set up a .newsrc file--running newsetup...\n\n\
X",stdout) FLUSH;
X	ELSE
X#endif
X#ifdef TERSE
X	    fputs("Setting up .newsrc...\n",stdout) FLUSH;
X#endif
X	if (doshell(sh,filexp(NEWSETUP)) ||
X	    (rcfp = fopen(rcname,"r")) == Nullfp) {
X#ifdef VERBOSE
X	    IF(verbose)
X		fputs("\
XCan't create a .newsrc--you must do it yourself.\n\
X",stdout) FLUSH;
X	    ELSE
X#endif
X#ifdef TERSE
X		fputs("(Fatal)\n",stdout) FLUSH;
X#endif
X	    finalize(1);
X	}
X    }
X    else {
X	UNLINK(rcbname);		/* unlink backup file name */
X	link(rcname,rcbname);		/* and backup current name */
X    }
X}
X
X/* write out the (presumably) revised .newsrc */
X
Xvoid
Xwrite_rc()
X{
X    register NG_NUM tmpng;
X    register char *delim;
X
X    rcfp = fopen(rctname, "w");		/* open .newsrc */
X    if (rcfp == Nullfp) {
X	printf("Can't recreate .newsrc\n") FLUSH;
X	finalize(1);
X    }
X
X    /* write out each line*/
X
X    for (tmpng = 0; tmpng < nextrcline; tmpng++) {
X	if (rcnums[tmpng]) {
X	    delim = rcline[tmpng] + rcnums[tmpng] - 1;
X	    *delim = rcchar[tmpng];
X	}
X	else
X	    delim = Nullch;
X#ifdef DEBUGGING
X	if (debug & DEB_NEWSRC_LINE)
X	    printf("%s\n",rcline[tmpng]) FLUSH;
X#endif
X	fprintf(rcfp,"%s\n",rcline[tmpng]);
X	if (delim)
X	    *delim = '\0';		/* might still need this line */
X    }
X
X    fclose(rcfp);			/* close .newsrc */
X    UNLINK(rcname);
X    link(rctname,rcname);
X    UNLINK(rctname);
X
X    if (writesoft) {
X	tmpfp = fopen(filexp(softname), "w");	/* open .rnsoft */
X	if (tmpfp == Nullfp) {
X	    printf(cantcreate,filexp(softname)) FLUSH;
X	    return;
X	}
X	for (tmpng = 0; tmpng < nextrcline; tmpng++) {
X	    fprintf(tmpfp,"%ld\n",(long)softptr[tmpng]);
X	}
X	fclose(tmpfp);
X    }
X}
X
Xvoid
Xget_old_rc()
X{
X    UNLINK(rctname);
X    link(rcname,rctname);
X    UNLINK(rcname);
X    link(rcbname,rcname);
X    UNLINK(rcbname);
X}
SHAR_EOF
chmod 0660 rcstuff.c || echo "restore of rcstuff.c fails"
echo "x - extracting rcstuff.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > rcstuff.h &&
X/* $Header: rcstuff.h,v 4.3 85/05/01 11:46:49 lwall Exp $
X *
X * $Log:	rcstuff.h,v $
X * Revision 4.3  85/05/01  11:46:49  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
XEXT char *rcline[MAXRCLINE];/* pointers to lines of .newsrc */
XEXT ART_UNREAD toread[MAXRCLINE];
X			/* number of articles to be read in newsgroup */
X			/* <0 => invalid or unsubscribed newsgroup */
X#define TR_ONE ((ART_UNREAD) 1)
X#define TR_NONE ((ART_UNREAD) 0)
X#define TR_UNSUB ((ART_UNREAD) -1)
X			/* keep this one as -1, some tests use >= TR_UNSUB */
X#define TR_BOGUS ((ART_UNREAD) -2)
X#define TR_JUNK ((ART_UNREAD) -3)
X
XEXT char rcchar[MAXRCLINE]; /* holds the character : or ! while spot is \0 */
XEXT char rcnums[MAXRCLINE]; /* offset from rcline to numbers on line */
XEXT ACT_POS softptr[MAXRCLINE];
X			/* likely ptr to active file entry for newsgroup */
XEXT bool paranoid INIT(FALSE);	/* did we detect some inconsistency in .newsrc? */
X
Xbool	rcstuff_init();
Xbool	get_ng();	/* return TRUE if newsgroup can be found or added */
XNG_NUM	add_newsgroup();
X#ifdef RELOCATE
X    NG_NUM	relocate_newsgroup();	/* move newsgroup around */
X#endif
Xvoid	list_newsgroups();
XNG_NUM	find_ng();	/* return index of newsgroup */
Xvoid	cleanup_rc();
Xvoid	sethash();
Xint	hash();
Xvoid	newsrc_check();
Xvoid	write_rc();
Xvoid	get_old_rc();
SHAR_EOF
chmod 0660 rcstuff.h || echo "restore of rcstuff.h fails"
echo "x - extracting respond.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > respond.c &&
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}
SHAR_EOF
chmod 0660 respond.c || echo "restore of respond.c fails"
echo "x - extracting respond.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > respond.h &&
X/* $Header: respond.h,v 4.3.3.1 90/06/20 22:39:54 davison Trn $
X *
X * $Log:	respond.h,v $
X * Revision 4.3.3.1  90/06/20  22:39:54  davison
X * Initial Trn Release
X * 
X * Revision 4.3  85/05/01  11:47:50  lwall
X * Baseline for release with 4.3bsd.
X * 
X */
X
XEXT char *savedest INIT(Nullch);	/* value of %b */
XEXT char *extractprog INIT(Nullch);	/* value of %e */
XEXT ART_POS savefrom INIT(0);		/* value of %B */
XEXT char *headname INIT(Nullch);
X
X#define SAVE_ABORT 0
X#define SAVE_DONE 1
X
Xvoid	respond_init();
Xint	save_article();
Xint	cancel_article();
Xvoid	reply();
Xvoid	followup();
Xvoid	invoke();
SHAR_EOF
chmod 0660 respond.h || echo "restore of respond.h fails"
echo "x - extracting rn.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > rn.c &&
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.1 90/07/21 20:31:38 davison Trn $";
Xstatic char patchlevel[] = "Trn v1.0 based on Rn patchlevel 47";
X
X/* $Log:	rn.c,v $
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)
SHAR_EOF
echo "End of part 11"
echo "File rn.c is continued in part 12"
echo "12" > 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