|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T r
Length: 18733 (0x492d)
Types: TextFile
Names: »rfuncs.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/news/src/rfuncs.c«
/*
* This software is Copyright (c) 1986 by Rick Adams.
*
* Permission is hereby granted to copy, reproduce, redistribute or
* otherwise use this software as long as: there is no monetary
* profit gained specifically from the use or reproduction or this
* software, it is not sold, rented, traded or otherwise marketed, and
* this copyright notice is included prominently in any copy
* made.
*
* The author make no claims as to the fitness or correctness of
* this software for any use whatsoever, and it is provided as is.
* Any use of this software is at the user's own risk.
*
* rfuncs - functions for readnews.
*/
#ifdef SCCSID
static char *SccsId = "@(#)rfuncs.c 2.40 2/22/87";
#endif /* SCCSID */
/*LINTLIBRARY*/
#include "rparams.h"
char lentab[LINES]; /* length of newsgroupname for each rcline */
long nngsize; /* The next upcoming value of ngsize. */
long nminartno; /* Smallest article number in this group */
int BITMAPSIZE = 0;
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()) {
(void) fseek(actfp, curpos, 0);
return 1;
}
if (back()) {
(void) fseek(actfp, curpos, 0);
return 1;
}
}
if (fgets(afline, BUFLEN, actfp) == NULL)
return 1;
if (sscanf(afline, "%s %ld %ld", bfr, &nngsize, &nminartno) < 3) {
bfr[0] = '\0';
nngsize = 0;
nminartno = 0;
}
#ifdef DEBUG
fprintf(stderr, "bfr = '%s'\n", bfr);
#endif
if (!ngmatch(bfr, header.nbuf))
goto next;
if (xflag)
readmode = SPEC;
else
readmode = NEXT;
if (selectng(bfr, TRUE, FALSE))
goto next;
return 0;
}
selectng(name, fastcheck, resubscribe)
char *name;
{
register char *ptr, punct = ',';
register int i;
register char *p;
register long cur;
long next = 0;
FILE *af;
long s, sm;
char buf[100], n[100];
#ifdef DEBUG
fprintf(stderr,"selectng: groupdir = %s\n", groupdir);
#endif /* DEBUG */
if (*groupdir)
updaterc();
last = 1;
if (strcmp(name, bfr)) {
af = xfopen(ACTIVE, "r");
while (fgets(buf, sizeof buf, af) != NULL) {
if (sscanf(buf, "%s %ld %ld", n, &s, &sm) == 3 &&
strcmp(n, name) == 0) {
ngsize = s;
minartno = sm;
break;
}
}
(void) fclose(af);
} else {
ngsize = nngsize;
minartno = nminartno;
}
#ifdef DEBUG
fprintf(stderr, "selectng(%s) sets ngsize to %ld, minartno to %ld\n",
name, ngsize, minartno);
#endif
(void) strcpy(groupdir, name);
if (!xflag) {
i = findrcline(name);
if (i >= 0) {
if (p = index(rcline[i], '!')) {
switch (resubscribe) {
case FALSE:
groupdir[0] = 0;
return 1;
case TRUE:
*p = ':';
break;
case PERHAPS:
zapng = TRUE;
break;
}
} else
p = index(rcline[i], ':');
if (!p) /* shouldn't happen */
p = rcline[i];
while (*++p == ' ')
;
(void) sprintf(rcbuf, "%s%s%ld", rcline[i],
*p == '\0' ? " " : ",", ngsize+1);
}
else
(void) sprintf(rcbuf, "ng: %ld", ngsize+1);
} else
(void) sprintf(rcbuf, "ng: %ld", ngsize+1);
#ifdef DEBUG
fprintf(stderr, "rcbuf set to %s\n", rcbuf);
#endif /* DEBUG */
/*
* Fast check for common case: 1-###
*/
if (fastcheck) {
p = rcbuf;
while (*p != ' ')
p++;
while (*p == ' ')
p++;
if (*p++ == '1' && *p++ == '-') {
cur = 0;
while (isdigit(*p))
cur = 10 * cur + *p++ - '0';
if (*p == ',' && cur == ngsize) {
#ifdef DEBUG
fprintf(stderr, "Group: %s, all read\n", groupdir);
#endif
groupdir[0] = 0;
return 1;
}
if (cur > ngsize) {
/*
* Claim to have read articles
* which "active" believes have
* never existed - we believe "active"
*/
fprintf(stderr,
"%s %s...\r\n\t%s %ld to %ld\r\n",
"Warning: newsgroup", groupdir,
"last article claimed read reset from",
cur, ngsize);
}
}
}
/*
* 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
* holes), and so we assume the newsrc file is properly ordered, the way
* we write it out.
*/
if ((ngsize-minartno) > BITMAPSIZE) {
/* resize the bitmap array */
(void) free (bitmap);
BITMAPSIZE = 8 * (((ngsize - minartno) + 7) / 8);
bitmap = malloc((unsigned)BITMAPSIZE/8);
if (bitmap == NULL)
xerror("Can't malloc bitmap");
}
cur = 0;
bzero(bitmap, (int) (ngsize-minartno)/8+1); /* 8 bits per character */
/* 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;
(void) sscanf(ptr, "%ld", &next);
if (punct == ',') {
while (++cur < next) {
set(cur);
}
}
cur = next;
while (!ispunct(*ptr) && *ptr)
ptr++;
punct = *ptr;
}
if (rflag)
bit = ngsize+1;
else
bit = minartno -1;
nextbit();
ngrp = 1;
return 0;
}
#ifdef TMAIL
catchterm()
{
(void) unlink(infile);
(void) unlink(outfile);
xxit(0);
}
/*
* The -M (Mail) interface. This code is a reasonably simple model for
* writing other interfaces. We write out all relevant 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;
register int i;
for(i=0;i<NUNREC;i++)
h.unrec[i] = NULL;
ofp = xfopen(mktemp(outfile), "w");
if (aflag && *datebuf)
if ((atime = cgtdate(datebuf)) == -1)
xerror("Cannot parse date string");
while (!nextng())
while (bit <= ngsize) {
(void) sprintf(filename, "%s/%ld", dirname(groupdir), bit);
if (access(filename, 4)
|| ((fp = art_open (filename, "r")) == NULL)
|| (hread(&h, fp, TRUE) == NULL)
|| !aselect(&h, FALSE)) {
#ifdef DEBUG
fprintf(stderr, "Bad article '%s'\n", filename);
#endif
if (fp != NULL) {
(void) 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/%ld\n\n", groupdir, bit);
tprint(fp, ofp, TRUE);
putc('\n', ofp);
news = TRUE;
(void) fclose(fp);
fp = NULL;
nextbit();
}
updaterc();
(void) fclose(ofp);
if (!news) {
fprintf(stderr, "No news.\n");
(void) unlink(outfile);
return;
}
(void) signal(SIGHUP, catchterm);
(void) signal(SIGTERM, catchterm);
(void) sprintf(bfr, "%s -f %s -T %s", TMAIL, outfile, mktemp(infile));
fwait(fsubr(ushell, bfr, (char *)NULL));
ofp = xfopen(infile, "r");
(void) fseek(actfp, 0L, 0);
while (fgets(afline, BUFLEN, actfp) != NULL) {
last = 0;
if (sscanf(afline, "%s %ld", bfr, &nngsize) < 2) {
bfr[0] = '\0';
nngsize = 0;
}
if (!ngmatch(bfr, header.nbuf))
continue;
*groupdir = 0;
if (selectng(bfr, TRUE, FALSE))
continue;
(void) fseek(ofp, 0L, 0);
while (fgets(groupdir, BUFLEN, ofp) != NULL) {
(void) nstrip(groupdir);
ptr = index(groupdir, '/');
*ptr = 0;
if (strcmp(bfr, groupdir))
continue;
(void) sscanf(++ptr, "%ld", &last);
clear(last);
}
if (last) {
(void) strcpy(groupdir, bfr);
updaterc();
}
}
(void) unlink(infile);
(void) unlink(outfile);
}
#endif
updaterc()
{
register long cur = 1, next = 1;
register int i;
register char *ptr;
char oldptr;
sprintf(rcbuf, "%s%c ", groupdir, zapng ? '!' : ':');
zapng = FALSE;
again:
ptr = &rcbuf[strlen(rcbuf)];
while (get(next) && next <= ngsize)
next++;
cur = next;
while (!(get(next)) && next <= ngsize)
next++;
if (cur == next) {
next = ngsize + 1;
goto skip;
}
if (ptr[-1] != ' ')
*ptr++ = ',';
if (cur + 1 == next)
(void) sprintf(ptr, "%ld", cur);
else
(void) sprintf(ptr, "%ld-%ld", cur, next - 1);
skip:
if ((long) next > ngsize) {
if (strpbrk(rcbuf, ":!") == NULL) /* bad line, huh?? */
return;
ptr = index(rcbuf, ' ');
if (ptr == NULL) /* impossible */
return;
ptr--;
oldptr = *ptr;
ptr[0] = ':';
ptr[1] = '\0';
i = findrcline(groupdir);
if (i >= 0) {
ptr[0] = oldptr;
ptr[1] = ' ';
rcline[i] = realloc(rcline[i], (unsigned)(strlen(rcbuf) + 1));
if (rcline[i] == NULL)
xerror("Cannot realloc");
(void) strcpy(rcline[i], rcbuf);
#ifdef DEBUG
fprintf(stderr," new rcline = %s\n", rcline[i]);
#endif /* DEBUG */
return;
}
if (++line > LINES)
xerror("Too many newsgroups");
ptr[0] = oldptr;
ptr[1] = ' ';
if ((rcline[line] = malloc((unsigned)(strlen(rcbuf) + 1))) == NULL)
xerror("Not enough memory");
(void) strcpy(rcline[line], rcbuf);
#ifdef DEBUG
fprintf(stderr," new rcline2 = %s\n", rcline[line]);
#endif /* DEBUG */
return;
}
cur = next;
goto again;
}
newrc(rcname)
char *rcname;
{
register FILE *fp;
if (close(creat(rcname, 0666))) {
(void) sprintf(bfr, "Cannot create %s", newsrc);
xerror(bfr);
}
sprintf(bfr, "%s/users", LIB);
if ((fp = fopen(bfr, "a")) != NULL) {
fprintf(fp, "%s\n", username);
(void) fclose(fp);
(void) chmod(bfr, 0666);
}
}
nextbit()
{
#ifdef DEBUG
fprintf(stderr,"nextbit() bit = %ld\n", bit);
#endif /* DEBUG */
last = bit;
if (readmode == SPEC || xflag) {
if (rflag)
bit--;
else
bit++;
return;
}
if (rflag)
while (--bit, !get(bit) && bit > minartno)
;
else
while (++bit, !get(bit) && bit <= ngsize)
;
#ifdef DEBUG
fprintf(stderr,"nextng leaves bit as %ld\n", bit);
#endif /* DEBUG */
}
/*
* Return TRUE if the user has not ruled out this article.
*/
aselect(hp, insist)
register struct hbuf *hp;
int insist;
{
if (insist)
return TRUE;
if (tflag && !titmat(hp, header.title))
return FALSE;
if (aflag && cgtdate(hp->subdate) < atime)
return FALSE;
if (index(hp->nbuf, ',') && !rightgroup(hp))
return FALSE;
if (fflag && (hp->followid[0] || prefix(hp->title, "Re:")))
return FALSE;
return TRUE;
}
/*
* Code to avoid showing multiple articles for news.
* Works even if you exit news.
* Returns nonzero if we should show this article.
*/
rightgroup(hp)
struct hbuf *hp;
{
char ng[BUFLEN];
register char *p, *g;
int i, flag;
strcpy(ng, hp->nbuf);
g = ng;
flag = 1;
while (g != NULL) {
p = index(g, ',');
if (p != NULL) {
*p++ = '\0';
while (*p == ' ')
p++;
}
if (strcmp(g, groupdir) == 0)
return flag;
if (ngmatch(g, header.nbuf)
&& ((i = findrcline(g)) >= 0
&& index(rcline[i], '!') == NULL))
flag = 0;
g = p;
}
/* we must be in "junk" or "control" */
return TRUE;
}
back()
{
while (fseek(actfp, -2L, 1) != -1 && ftell(actfp) > 0L) {
if (getc(actfp) == '\n')
return 0;
}
if (ftell(actfp) == 0L)
return 0;
return 1;
}
/*
* Trap interrupts.
*/
onsig(n)
int n;
{
(void) signal(n, onsig);
SigTrap = n;
if (rcreadok < 2) {
fprintf(stderr, "Aborted early\n");
xxit(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)
register char *name;
{
register char * p;
register int i;
register int top;
register int len;
static int prev;
static int didthru;
for ( ; didthru <= line; ++didthru)
if ((p = index(rcline[didthru], '!')) != 0 ||
(p = index(rcline[didthru], ':')) != 0) {
lentab[didthru] = (int)(p - rcline[didthru]);
}
len = strlen(name);
top = line;
i = prev;
loop:
for ( ; i <= top; ++i)
if (lentab[i] == len && rcline[i] != NULL &&
strncmp(name, rcline[i], len) == 0)
return prev = i;
if (i > line && line > prev - 1) {
i = 0;
top = prev - 1;
goto loop;
}
return -1;
}
/*
* sortactive - make a local copy of the active file, sorted according
* to the user's preferences, according to his .newsrc file.
*/
struct table_elt {
int rcindex;
long maxart, minart;
char yn;
};
#ifdef SORTACTIVE
static int
rcsort(a, b)
char *a, *b;
{
return(((struct table_elt *)a)->rcindex -
((struct table_elt *)b)->rcindex);
}
static char *newactivename = "/tmp/newsaXXXXXX";
#endif /* SORTACTIVE */
sortactive()
{
register struct table_elt *tp;
register char *p;
register FILE *nfp, *afp;
char aline[BUFLEN], ngname[BUFLEN];
struct table_elt table[LINES];
int nlines = 0, i, delta, lastline;
#ifdef SORTACTIVE
/* make a new sorted copy of ACTIVE */
nfp = fopen(mktemp(newactivename), "w");
(void) chmod(newactivename, 0600);
if (nfp == NULL) {
perror(newactivename);
return;
}
/* look up all the lines in ACTIVE, finding their positions in .newsrc */
p = ACTIVE;
ACTIVE = newactivename;
afp = xfopen(p, "r");
#else /* !SORTACTIVE */
afp = xfopen(ACTIVE, "r");
#endif /* !SORTACTIVE */
tp = table;
while (fgets(aline, sizeof aline, afp) != NULL) {
if (sscanf(aline,"%s %ld %ld %c", ngname, &tp->maxart,
&tp->minart, &tp->yn) != 4)
xerror("Active file corrupt");
delta = tp->maxart - tp->minart;
if (delta >= BITMAPSIZE)
BITMAPSIZE = delta + 1;
if (Kflag && tp->maxart > 0 && ngmatch(ngname, header.nbuf)) {
int j;
j = findrcline(ngname);
if (j >= 0 && index(rcline[j], '!') == NULL) {
char rbuf[BUFLEN];
if (tp->maxart == 1)
sprintf(rbuf, "%s: 1", ngname);
else
sprintf(rbuf, "%s: 1-%ld", ngname, tp->maxart);
rcline[j] = realloc(rcline[j],
(unsigned)(strlen(rbuf)+1));
if (rcline[j] == NULL)
xerror("Not enough memory");
strcpy(rcline[j], rbuf);
}
}
#ifdef SORTACTIVE
tp->rcindex = findrcline(ngname);
if (tp->rcindex < 0) {
if (++line > LINES)
xerror("Too many newsgroups");
strcat(ngname, ":");
rcline[line] = malloc((unsigned)(strlen(ngname) + 1));
if (rcline[line] == NULL)
xerror("Not enough memory");
strcpy(rcline[line], ngname);
tp->rcindex = line;
}
tp++;
#endif /* SORTACTIVE */
}
(void) fclose(afp);
BITMAPSIZE = 8 * ((BITMAPSIZE+7) / 8);
bitmap = malloc((unsigned)BITMAPSIZE/8);
if (bitmap == NULL)
xerror("Can't malloc bitmap");
#ifdef SORTACTIVE
/* sort by position in user's .newsrc file (new groups come up last) */
nlines = tp - table;
qsort((char *)table, nlines, sizeof table[0], rcsort);
tp = table;
lastline = tp->rcindex - 1;
/* copy active to newactive, in the new order */
for (i = 0; i < nlines; i++) {
while (++lastline < tp->rcindex) {
if (strncmp(rcline[lastline], "options ", 8) == 0) {
fprintf(nfp, "%s\n", rcline[lastline]);
} else {
fprintf(stderr, "Duplicate .newsrc line or bad group %s\n",
rcline[lastline]);
lentab[lastline] = 0;
free(rcline[lastline]);
rcline[lastline] = NULL;
}
}
if (rcline[tp->rcindex] == NULL)
continue;
p = rcline[tp->rcindex];
while (*p != ':' && *p != '!')
fputc(*p++, nfp);
(void) fprintf(nfp, " %ld %ld %c\n", tp->maxart, tp->minart,
tp->yn);
tp++;
}
(void) fclose(nfp);
#endif /* SORTACTIVE */
}
#if defined(BSD4_2) || defined(BSD4_1C)
#include <sys/dir.h>
# else
#include "ndir.h"
#endif
#include <errno.h>
/*
* Routine to display header lines for all articles in newsgroup. If the flag
* argument is FALSE then only articles which are not marked as read in the
* bitmap will be displayed. This routine makes no attempt to determine if
* the article is in multiple groups and therefore should not be displayed at
* this time.
*/
static int *lg_array = NULL;
static int *lg_entry;
static int lg_max = 0;
static int int_sig;
extern int errno;
lg_cmp(p1, p2)
int *p1, *p2;
{
return *p1 - *p2;
}
list_group(lgroup, displines, flag, pngsize)
char *lgroup;
int displines, flag;
long pngsize;
{
char *briefdate();
struct hbuf hh;
register DIR *dirp;
register struct direct *dir;
register FILE *fp_art;
int i;
int entries;
unsigned int alloc_size;
int (*old_sig) ();
extern lg_trap();
char *gets();
/* This should get the numbers from the active file XXX */
if ((dirp = opendir(dirname(lgroup))) == NULL) {
printf("Can't open %s\r\n", dirname(lgroup));
return;
}
entries = 0;
if (lg_array == NULL) {
lg_max = 50;
alloc_size = lg_max * sizeof(int);
lg_array = (int *) malloc(alloc_size);
}
while ((dir = readdir(dirp)) != NULL) {
if (dir->d_ino == 0)
continue;
i = atoi(dir->d_name);
if ((i < 1) || (i > pngsize))
continue;
if (flag == FALSE) {
if (get(i) == 0)
continue;
}
if (++entries > lg_max) {
lg_max += 50;
alloc_size = lg_max * sizeof(int);
lg_array = (int *) realloc((char *) lg_array, alloc_size);
}
lg_array[entries - 1] = i;
}
if (entries == lg_max) {
lg_max++;
alloc_size = lg_max * sizeof(int);
lg_array = (int *) realloc((char *) lg_array, alloc_size);
}
qsort(lg_array, entries, sizeof *lg_array, lg_cmp);
lg_array[entries] = 0;
int_sig = 0;
old_sig = signal(SIGINT, lg_trap);
hh.unrec[0] = NULL;
for (lg_entry = lg_array; *lg_entry != 0 && int_sig == 0; lg_entry++) {
(void) sprintf(filename, "%s/%d", dirname(lgroup), *lg_entry);
fp_art = fopen(filename, "r");
if (fp_art == NULL)
continue;
if (hread(&hh, fp_art, TRUE) == NULL) {
(void) fclose(fp_art);
continue;
}
printf("%5d %-20.20s %-13s %s\r\n",
*lg_entry, hh.from,
briefdate(hh.subdate), hh.title);
for (i = 0; i < displines;) {
if (fgets(bfr, LBUFLEN, fp_art) == NULL) {
break;
}
if ((bfr[0] == '\n') || (bfr[0] == '>')) {
continue;
}
printf("%s", bfr);
i++;
}
(void) fclose(fp_art);
}
(void) fflush(stdout);
closedir(dirp);
(void) signal(SIGINT, old_sig); /* restore to old value */
printf("[Press RETURN to continue]");
(void) fflush(stdout);
while (TRUE) {
errno = 0;
i = getchar();
if (errno == EINTR)
continue;
if (i == '\n' || i == '\r')
break;
if (i == EOF)
break;
if (i == '\4')
break;
}
(void) free(lg_array);
lg_array = NULL;
}
lg_trap(code)
int code;
{
int_sig = 1;
(void) signal(code, lg_trap); /* reset signal */
}