[net.news.b] assorted 2.10.1 bug fixes and changes

geoff@utcsstat.UUCP (Geoff Collyer) (05/08/84)

I don't think I've seen any of these bugs posted yet.

I put sortactive() in our readnews and got loud screams from
users who were suddenly seeing groups they had never read before
in front of all their old favourites.  If you want groups not in the
user's .newsrc yet in the active file to appear *last*, add the
marked lines in the middle of sortactive() (in rfuncs.c)

		table[nlines].rcpos = findrcline(line);
+		if (table[nlines].rcpos == -1)		/* not in .newsrc */
+			table[nlines].rcpos = LINES;	/* huge, sort to the end */
		table[nlines].actpos = actpos;

Elsewhere in rfuncs.c, I found some more sscanf's whose return
values were unchecked (yawn).  I suppose I should 'egrep scanf *.c'
some day and fix them once and for all.  Line numbers are approximate.

35c35,38
< 	sscanf(afline, "%s %ld", bfr, &nngsize);
---
> 	if (sscanf(afline, "%s %ld", bfr, &nngsize) < 2) {
> 		bfr[0] = '\0';
> 		nngsize = 0;
> 	}
257c256,259
< 		sscanf(afline, "%s %ld", bfr, &nngsize);
---
> 		if (sscanf(afline, "%s %ld", bfr, &nngsize) < 2) {
> 			bfr[0] = '\0';
> 			nngsize = 0;
> 		}

There's a latent bug in selectng() in rfuncs.c which only showed up
here when a user without an options line in his .newsrc tried
`readnews -x' and was told `No news.';  he knew this was too good
to be true and reported it.

75,82c78,83
< 	if (!xflag) {
< 		i = findrcline(name);
< 		if (i >= 0) {
< 			if (index(rcline[i], '!')) {
< 				groupdir[0] = 0;
< 				return 1;
< 			}
< 			sprintf(rcbuf, "%s,%ld", rcline[i], ngsize+1);
---
> 	if (xflag || (i = findrcline(name)) < 0)
> 		sprintf(rcbuf, "ng: %ld", ngsize+1);
> 	else {
> 		if (index(rcline[i], '!')) {
> 			groupdir[0] = 0;
> 			return 1;
84,85c85
< 		else
< 			sprintf(rcbuf, "ng: %ld", ngsize+1);
---
> 		sprintf(rcbuf, "%s,%ld", rcline[i], ngsize+1);

The problem is that under -x, the old code didn't initialise rcbuf.
If the above diffs aren't enough, here's the new code fragment:

	if (xflag || (i = findrcline(name)) < 0)
		sprintf(rcbuf, "ng: %ld", ngsize+1);
	else {
		if (index(rcline[i], '!')) {
			groupdir[0] = 0;
			return 1;
		}
		sprintf(rcbuf, "%s,%ld", rcline[i], ngsize+1);
	}

Our readr.c didn't ever print the `Last article' prompt and I fixed it
by rearranging readr() (I also fixed a debugging printf format):

		if (getnextart(FALSE)) {	/* no more articles */
			if (sigtrap || !news)
				break;		/* don't print Last article */
			/* else fall through */
		}
		else {
#ifdef DEBUG
			printf("after getnextart, fp %x, pos %ld, bit %d, group '%s', filename '%s'\n",
				fp, ftell(fp), bit, groupdir, filename);
#endif
			strcpy(goodone, filename);
			if (pflag || lflag || eflag) {
				/* This code should be gotten rid of */
				if (sigtrap) {
					qfflush(ofp);
					fprintf(ofp, "\n");
					cdump(ofp);
					_exit(0); /* kludge! drop when qfflush works */
					return;
				}
				clear(bit);
				nextbit();
				if (fp) {
					fclose(fp);
					fp = NULL;
				}
				continue;
			}
		}
		for (; ; ) {

If you are using sortactive(), you'll probably want to read the
user's .newrc, even under -x, so that you can sort the active file
into .newsrc order.  In readnews.c, I changed a few lines and added two:

225c225,226
< 	if (!xflag && (rcfp = xfopen(newsrc, "r"))) {
---
> 	/* must read newsrc under xflag for sortactive() */
> 	if ((rcfp = xfopen(newsrc, "r"))) {

	sortactive();
+	if (xflag)
+		line = -1;	/* ignore newsrc by forgetting its contents */

That's all for today.

Geoff Collyer, U. of Toronto Computing Services

rees@apollo.UUCP (05/11/84)

The trouble with Geoff's fix to readr() is that it now prompts you
on the last article even if you have one of the non-interactive
flags on (like -e, my favorite flag).  Of course the original code
wasn't right either.

It seems to me that you want to either do the interactive stuff,
in the inner for() loop, or the non-interactive stuff.  Here is
my version of readr().  I tested the simple cases but can't claim
to fully understand this code even now.

readr()
{
	int gotart;

#ifdef DEBUG
	fprintf(stderr, "readr()\n");
#endif
	if (aflag) {
		if (*datebuf) {
			if ((atime = cgtdate(datebuf)) == -1)
				xerror("Cannot parse date string");
		} else 
			atime = 0L;
	}

	if (pflag && ignoring())
		ignorenews = TRUE;

	if (uflag)
		time(&timelastsaved);

	ofp = stdout;
	if (cflag && coptbuf[0] != '\0') {
		umask(022);
		mktemp(outfile);	/* get "unique" file name */
		ofp = xfopen(outfile, "w");
		umask(N_UMASK);
		cflag = FALSE;
		pflag = TRUE;
	}

	/* loop reading articles. */
	fp = NULL;
	obit = -1;
	nextng();
	for ( ;; ) {
		gotart = !getnextart(FALSE);
		if (!news)
			break;
#ifdef DEBUG
		printf("after getnextart, fp %x, pos %ld, bit %d, group '%s', filename '%s'\n",
			fp, ftell(fp), bit, groupdir, filename);
#endif
		if (gotart)
			strcpy(goodone, filename);
		if (pflag || lflag || eflag) {
			/* This code should be gotten rid of */
			if (sigtrap) {
				qfflush(ofp);
				fprintf(ofp, "\n");
				cdump(ofp);
				_exit(0); /* kludge! drop when qfflush works */
				return;
			}
			if (gotart) {
				clear(bit);
				nextbit();
			} else
				break;
			if (fp) {
				fclose(fp);
				fp = NULL;
			}
			continue;
		}
		for (; ; ) {
			char *pp;
#ifdef	SIGCONT
			int (*ocont)();
#endif
			sigtrap = FALSE;
			if (!cflag) {
				if (rfq)
					fprintf(ofp, "Last article.  [qfr] ");
				else
					fprintf(ofp, "(%d lines) More? [ynq] ", NLINES(h, fp));
			} else
				fprintf(ofp, "? ");
			fflush(ofp);
			bptr = lbuf;
#ifdef SIGCONT
			ocont = signal(SIGCONT, catchcont);
#endif
			pp = fgets(bptr, BUFLEN, stdin);
#ifdef SIGCONT
			signal(SIGCONT, ocont);
#endif
			if (pp != NULL)
				break;
			if (!sigtrap)
				return;
#ifdef SIGCONT
			if (sigtrap != SIGCONT)
#endif
				fprintf(ofp, "\n");
		}
		nstrip(bptr);
		while (*bptr == ' ' || *bptr == '\t')
			bptr++;
		i = command();
		if (i)
			break;
	}

	if (!news)
		fprintf(stderr, "No news.\n");
	cout(ofp);
}

geoff@utcsstat.UUCP (Geoff Collyer) (05/15/84)

I'm sorry that I broke the non-interactive modes of readnews with my
latest batch of changes.  I still don't know what -e does, because it
isn't documented (in readnews(1) anyway), and I don't have enough spare
time to decrypt the source.  I guess this is a penalty for trying to
provide five or six user interfaces in one monolithic, lumbering hulk.

I think Mr. Rees's fix is cleaner than mine.  I certainly don't fully
understand readr() and I doubt that anyone does.  The news swillware is
full of gotos, continues, four-page functions and global variables.
I'd like to know why the main, essential, core logic of readnews is
scattered across three functions in three source files.

joe@fluke.UUCP (05/16/84)

Geoff's (and Jim's) fix both have the undesirable side effect that if
you try to do anything "interesting" at the "Last article" prompt,
readnews will probably dump core.  The reason is that many of the
options in the big switch in command() try to close(fp).  If you are at
the "Last article" prompt, fp == NULL and fclose immediately gets an
illegal reference and dumps.  The fix is to enclose all occurrences of
the two lines
	fclose(fp);
	fp = NULL;
in command() with
	if (fp != NULL) {
		<as above>
	}
Note that there are already several cases which have taken into account
that fp might be NULL.  I think there are six or seven unprotected
fclose's.

Also, if you unsubscribe to the last newsgroup in the active file,
readnews doesn't print the Last article prompt.  I haven't looked into
this one very closely yet.  Maybe I'll install Jim's version of readr
first.

/Joe