|
|
researchv10 Norman
/*
* rfuncs - functions for readnews.
*/
static char *SccsId = "@(#)rfuncs.c 2.9 3/7/83";
#include "rparams.h"
long nngsize; /* The next upcoming value of ngsize. */
nextng()
{
long curpos;
#ifdef DEBUG
fprintf(stderr, "nextng()\n");
#endif
curpos = ftell(actfp);
next:
#ifdef DEBUG
fprintf(stderr, "next:\n");
#endif
if (actdirect == BACKWARD) {
if (back()) {
fseek(actfp, curpos, 0);
return 1;
}
if (back()) {
fseek(actfp, curpos, 0);
return 1;
}
}
if (fgets(afline, BUFLEN, actfp) == NULL)
return 1;
sscanf(afline, "%s %ld", bfr, &nngsize);
#ifdef DEBUG
fprintf(stderr, "bfr = '%s'\n", bfr);
#endif
ngcat(bfr);
if (!ngmatch(bfr, header.nbuf))
goto next;
ngdel(bfr);
if (xflag)
readmode = SPEC;
else
readmode = NEXT;
if (selectng(bfr))
goto next;
return 0;
}
selectng(name)
char *name;
{
register char *ptr, punct = ',';
register int cur = 0, i;
register char *p;
int next = 0;
char oldptr;
long findngsize();
if (*groupdir)
updaterc();
last = 1;
if (strcmp(name, bfr))
ngsize = findngsize(name);
else
ngsize = nngsize;
#ifdef DEBUG
fprintf(stderr, "selectng(%s) sets ngsize to %ld\n", name, ngsize);
#endif
strcpy(groupdir, name);
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);
}
else
sprintf(rcbuf, "ng: %ld", ngsize+1);
}
/*
* Fast check for common case: 1-###
*/
p = rcbuf;
while (*p != ' ')
p++;
while (*p == ' ')
p++;
if (*p++ == '1' && *p++ == '-') {
i = 0;
while (isdigit(*p))
i = 10 * i + *p++ - '0';
if (*p == ',' && i >= ngsize) {
groupdir[0] = 0;
return 1;
}
}
/*
* The key to understanding this piece of code is that a bit is set iff
* that article has NOT been read. Thus, we fill in the holes when
* commas are found (e.g. 1-20,30-35 will result in filling in the 21-29
* hold), and so we assume the newsrc file is properly ordered, the way
* we write it out.
*/
cur = 0;
/* Zero out the bitmap */
p = &bitmap[ngsize/8+1];
for (ptr = bitmap; ptr <= p; ptr)
*ptr++ = 0;
/* Decode the .newsrc line indicating what we have read. */
for (ptr = rcbuf; *ptr && *ptr != ':'; ptr++)
;
while (*ptr) {
while (!isdigit(*ptr) && *ptr)
ptr++;
if (!*ptr)
break;
sscanf(ptr, "%d", &next);
if (punct == ',') {
while (++cur < next) {
set(cur);
}
}
cur = next;
while (!ispunct(*ptr) && *ptr)
ptr++;
punct = *ptr;
}
if (rflag)
bit = ngsize+1;
else
bit = 0;
nextbit();
ngrp = 1;
return 0;
}
/*
* Figure out the number of the largest article in newsgroup ng,
* and return that value.
*/
long
findngsize(ng)
char *ng;
{
FILE *af;
long s;
char buf[100], n[100];
af = xfopen(ACTIVE, "r");
while (fgets(buf, sizeof buf, af)) {
sscanf(buf, "%s %ld", n, &s);
if (strcmp(n, ng) == 0) {
fclose(af);
return s;
}
}
return 0;
}
#ifdef TMAIL
catchterm()
{
unlink(infile);
unlink(outfile);
xxit(0);
}
/*
* The -M (Mail) interface. This code is a reasonably simple model for
* writing other interfaces. We write out all relavent articles to
* a temp file, then invoke Mail with an option to have it tell us which
* articles it read. Finally we count those articles as really read.
*/
Mail()
{
register FILE *fp = NULL, *ofp;
struct hbuf h;
register char *ptr, *fname;
int news = 0;
ofp = xfopen(mktemp(outfile), "w");
if (aflag && *datebuf)
if ((atime = cgtdate(datebuf)) == -1)
xerror("Cannot parse date string");
while (!nextng())
while (bit <= ngsize) {
sprintf(filename, "%s/%d", dirname(groupdir), bit);
if (access(filename, 4)
|| ((fp = fopen(filename, "r")) == NULL)
|| (hread(&h, fp, TRUE) == NULL)
|| !select(&h, FALSE)) {
#ifdef DEBUG
fprintf(stderr, "Bad article '%s'\n", filename);
#endif
if (fp != NULL) {
fclose(fp);
fp = NULL;
}
clear(bit);
nextbit();
continue;
}
fname = ptr = index(h.from, '(');
if (fname) {
while (ptr && ptr[-1] == ' ')
ptr--;
if (ptr)
*ptr = 0;
fname++;
ptr = fname + strlen(fname) - 1;
if (*ptr == ')')
*ptr = 0;
}
h.subtime = cgtdate(h.subdate);
fprintf(ofp, "From %s %s",
#ifdef INTERNET
h.from[0] ? h.from :
#endif
h.path, ctime(&h.subtime));
if (fname)
fprintf(ofp, "Full-Name: %s\n", fname);
fprintf(ofp, "Newsgroups: %s\n", h.nbuf);
fprintf(ofp, "Subject: %s\n", h.title);
fprintf(ofp, "Article-ID: %s/%d\n\n", groupdir, bit);
tprint(fp, ofp, TRUE);
putc('\n', ofp);
news = TRUE;
fclose(fp);
fp = NULL;
nextbit();
}
updaterc();
fclose(ofp);
if (!news) {
fprintf(stderr, "No news.\n");
unlink(outfile);
return;
}
signal(SIGHUP, catchterm);
signal(SIGTERM, catchterm);
sprintf(bfr, "%s -f %s -T %s", TMAIL, outfile, mktemp(infile));
fwait(fsubr(ushell, bfr, (char *)NULL));
ofp = xfopen(infile, "r");
fseek(actfp, 0L, 0);
while (fgets(afline, BUFLEN, actfp) != NULL) {
last = 0;
sscanf(afline, "%s %ld", bfr, &nngsize);
ngcat(bfr);
if (!ngmatch(bfr, header.nbuf))
continue;
ngdel(bfr);
*groupdir = 0;
if (selectng(bfr))
continue;
fseek(ofp, 0L, 0);
while (fgets(groupdir, BUFLEN, ofp) != NULL) {
nstrip(groupdir);
ptr = index(groupdir, '/');
*ptr = 0;
if (strcmp(bfr, groupdir))
continue;
sscanf(++ptr, "%d", &last);
clear(last);
}
if (last) {
strcpy(groupdir, bfr);
updaterc();
}
}
unlink(infile);
unlink(outfile);
}
#endif
updaterc()
{
register int cur = 1, next = 1, i;
register char *ptr;
char oldptr;
sprintf(rcbuf, "%s%c ", groupdir, zapng ? '!' : ':');
zapng = FALSE;
again:
ptr = &rcbuf[strlen(rcbuf)];
while (get(next))
next++;
cur = next;
while (!(get(next)) && next <= ngsize)
next++;
if (cur == next) {
next = 8193;
goto skip;
}
if (cur + 1 == next)
sprintf(ptr, "%d,", cur);
else
sprintf(ptr, "%d-%d,", cur, next - 1);
skip:
if ((long) next > ngsize) {
if (index(rcbuf, ',') != NULL)
ngdel(rcbuf);
else if (index(rcbuf, '!') == NULL)
return;
ptr = index(rcbuf, ' ');
ptr--;
oldptr = *ptr;
ptr[0] = ':';
ptr[1] = '\0';
i = findrcline(groupdir);
if (i >= 0) {
ptr[0] = oldptr;
ptr[1] = ' ';
rcline[i] = realloc(rcline[i], strlen(rcbuf) + 1);
if (rcline[i] == NULL)
xerror("Cannot realloc");
strcpy(rcline[i], rcbuf);
return;
}
if (++line > LINES)
xerror("Too many newsgroups\n");
ptr[0] = oldptr;
ptr[1] = ' ';
if ((rcline[line] = malloc(strlen(rcbuf) + 1)) == NULL)
xerror("Not enough memory");
strcpy(rcline[line], rcbuf);
return;
}
cur = next;
goto again;
}
newrc(rcname)
{
register FILE *fp;
if (close(creat(rcname, 0666))) {
sprintf(bfr, "Cannot create %s", newsrc);
xerror(bfr);
}
if ((fp = fopen(USERS, "a")) != NULL) {
fprintf(fp, "%s\n", username);
fclose(fp);
chmod(USERS, 0666);
}
}
xerror(message)
char *message;
{
fflush(stdout);
fprintf(stderr, "readnews: %s.\n", message);
xxit(1);
}
nextbit()
{
last = bit;
if (readmode == SPEC || xflag) {
if (rflag)
bit--;
else
bit++;
return;
}
if (rflag)
while (--bit, !get(bit) && bit > 0)
;
else
while (++bit, !get(bit) && bit <= ngsize)
;
}
xxit(status)
int status;
{
unlink(infile);
unlink(outfile);
exit(status);
}
/*
* Return TRUE if the user has not ruled out this article.
*/
select(hp, insist)
register struct hbuf *hp;
int insist;
{
if (insist)
return TRUE;
if (tflag && !titmat(hp, header.title))
return FALSE;
if (aflag && cgtdate(hp->recdate) < atime)
return FALSE;
if (index(hp->nbuf, ',') && seenbefore(hp->ident))
return FALSE;
if (fflag && isfol(hp))
return FALSE;
return TRUE;
}
/*
* Return TRUE if this article is a followup to something.
*/
isfol(hp)
register struct hbuf *hp;
{
if (hp->followid[0])
return TRUE;
if (strncmp(hp->title, "Re:", 3) == 0)
return TRUE;
return FALSE;
}
/*
* Given an article ID, return TRUE if we have already seen that article ID
* in this readnews session. This should only be called for articles
* with commas in the newsgroup name, and prevents the same article, which
* was submitted to multiple newsgroups, from being shown to the same
* person more than once. Bug: if the user quits after seeing the first
* copy, he'll see it again next time in the other newsgroup.
*/
#define NART 100 /* max # articles on multiple newsgroups */
static int nbef = 0;
static char *histbuf[NART];
static char nextabuf[BUFLEN];
seenbefore(artid)
char *artid;
{
register int i;
for (i = 0; i < nbef; i++)
if (strcmp(histbuf[i], artid) == 0)
return TRUE;
if (nbef >= NART - 1) {
return FALSE;
}
/* Remember the name, but don't record it as saved yet. */
strcpy(nextabuf, artid);
return FALSE;
}
/*
* The current article has actually been looked at, so record it as such.
*/
itsbeenseen(artid)
char *artid;
{
if (nextabuf[0] == '\0')
return;
if (strcmp(artid, nextabuf) == 0) {
histbuf[nbef] = (char *) malloc(strlen(artid)+1);
strcpy(histbuf[nbef++], artid);
}
nextabuf[0] = '\0';
}
back()
{
while (fseek(actfp, -2L, 1) != -1 && ftell(actfp) > 0L) {
if (getc(actfp) == '\n')
return 0;
}
if (ftell(actfp) == 0L)
return 0;
return 1;
}
/*
* Copy from one header structure to another.
* Really should just copy memory, if we had a memcpy.
*/
hbufcp(hbuf2, hbuf1)
register struct hbuf *hbuf1, *hbuf2;
{
strcpy(hbuf2->path, hbuf1->path);
strcpy(hbuf2->from, hbuf1->from);
strcpy(hbuf2->replyto, hbuf1->replyto);
strcpy(hbuf2->nbuf, hbuf1->nbuf);
strcpy(hbuf2->title, hbuf1->title);
strcpy(hbuf2->ident, hbuf1->ident);
strcpy(hbuf2->subdate, hbuf1->subdate);
strcpy(hbuf2->recdate, hbuf1->recdate);
strcpy(hbuf2->expdate, hbuf1->expdate);
hbuf2->subtime = hbuf1->subtime;
hbuf2->rectime = hbuf1->rectime;
hbuf2->exptime = hbuf1->exptime;
}
/*
* Trap interrupts.
*/
onsig(n)
int n;
{
signal(n, onsig);
sigtrap = n;
if (rcreadok < 2) {
exit(0);
}
}
/*
* finds the line in your .newsrc file (actually the in-core "rcline"
* copy of it) and returns the index into the array where it was found.
* -1 means it didn't find it.
*
* We play clever games here to make this faster. It's inherently
* quadratic - we spend lots of CPU time here because we search through
* the whole .newsrc for each line. The "prev" variable remembers where
* the last match was found; we start the search there and loop around
* to the beginning, in the hopes that the calls will be roughly in order.
*/
int
findrcline(name)
char *name;
{
register char *p, *ptr;
register int cur;
register int i;
register int top;
static int prev = 0;
top = line; i = prev;
loop:
for (; i <= top; i++) {
for (p = name, ptr = rcline[i]; (cur = *p++); ) {
if (cur != *ptr++)
goto contin2;
}
if (*ptr != ':' && *ptr != '!')
continue;
prev = i;
return i;
contin2:
;
}
if (i > line && line > prev-1) {
i = 0;
top = prev-1;
goto loop;
}
return -1;
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.