rsalz@bbn.com (Rich Salz) (12/04/90)
Submitted-by: Wayne Davison <davison@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@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@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@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@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.