[net.news.b] Fix for readnews presenting articles you've already seen

rees@apollo.UUCP (07/06/84)

After all the discussion about how readnews presents the same article
multiple times in different sessions if it is posted to multiple groups,
I feel compelled to post my version of the fix to this problem.

The old method just remembered the Message-ID and refrained from showing
you the same article in the same session, but forgot the Message-ID
across sessions.  My method doesn't rely on Message-IDs at all, but
just decides whether this article has already been looked at in a
different group by looking at what groups you subscribe to.  I think
this is the same method that vnews uses.

One side effect is that readnews spends more time in findrcline(), a
routine with bad time complexity w.r.t. number of newsgroups.  I have
a fix for that, too, that uses hashing, and will post it one of these
days.

I have so many other fixes to rfuncs.c that diff couldn't make anything
reasonable out of my changes, so I'll have to just describe them.  This
is all in rfuncs.c.

In select(), make this change:

< 	if (index(hp->nbuf, ',') && seenbefore(hp->ident))
---
> 	if (index(hp->nbuf, ',') && seenbefore(hp))

Now, take out the routines seenbefore() and itsbeenseen() and replace them
with these:

/*
 * For all groups to which this article was posted, if the user subscribes
 * to that group, and that group is not the current group, return TRUE
 * meaning it's already been seen in another group.
 * If that group is the current group, return FALSE, meaning it hasn't been
 * seen yet.
 * This is the new method.  The old method remembered the message-ids, but
 * that didn't work across invocations.
 * If you use this, you should also use the hashed version of findrcline().
 *	- Jim Rees
 */
seenbefore(hp)
struct hbuf *hp;
{
	char *ng, ngbuf[64], *p;
	int n;

	ng = hp->nbuf;
	for (;;) {
		/* copy next newsgroup name from hp->nbuf into ngbuf */
		for (p = ngbuf; *ng && *ng != ','; )
			*p++ = *ng++;
		*p = '\0';
		/* skip the comma if there is one */
		if (*ng != '\0')
			ng++;
		if (DoesSubscribe(ngbuf))
			break;
		if (*ng == '\0')
			/*
			 * Shouldn't ever get here; it means we don't subscribe
			 * to any of the groups this article appears in.
			 */
			return FALSE;
	}
	if (!strcmp(ngbuf, groupdir))
		return FALSE;
	return TRUE;
}

DoesSubscribe(ng)
char *ng;
{
	int n;

	if (!ngmatch(ng, header.nbuf))
		/* Not in the subscription list */
		return FALSE;
	if ((n = findrcline(ng)) < 0)
		/* In the list, but not in .newsrc */
		return TRUE;
	if (index(rcline[n], '!') != NULL)
		/* In .newsrc, but unsubscribed */
		return FALSE;
	return TRUE;
}

/*
 * The current article has actually been looked at, so record it as such.
 * This is a dummy.  It hasn't been used since seenbefore() was changed.
 */
itsbeenseen(artid)
char *artid;
{
}