|
|
1.1 root 1: /*
2: * rfuncs - functions for readnews.
3: */
4:
5: static char *SccsId = "@(#)rfuncs.c 2.9 3/7/83";
6:
7: #include "rparams.h"
8:
9: long nngsize; /* The next upcoming value of ngsize. */
10:
11: nextng()
12: {
13: long curpos;
14: #ifdef DEBUG
15: fprintf(stderr, "nextng()\n");
16: #endif
17: curpos = ftell(actfp);
18:
19: next:
20: #ifdef DEBUG
21: fprintf(stderr, "next:\n");
22: #endif
23: if (actdirect == BACKWARD) {
24: if (back()) {
25: fseek(actfp, curpos, 0);
26: return 1;
27: }
28: if (back()) {
29: fseek(actfp, curpos, 0);
30: return 1;
31: }
32: }
33: if (fgets(afline, BUFLEN, actfp) == NULL)
34: return 1;
35: sscanf(afline, "%s %ld", bfr, &nngsize);
36: #ifdef DEBUG
37: fprintf(stderr, "bfr = '%s'\n", bfr);
38: #endif
39:
40: ngcat(bfr);
41: if (!ngmatch(bfr, header.nbuf))
42: goto next;
43: ngdel(bfr);
44: if (xflag)
45: readmode = SPEC;
46: else
47: readmode = NEXT;
48: if (selectng(bfr))
49: goto next;
50: return 0;
51: }
52:
53:
54: selectng(name)
55: char *name;
56: {
57: register char *ptr, punct = ',';
58: register int cur = 0, i;
59: register char *p;
60: int next = 0;
61: char oldptr;
62: long findngsize();
63:
64: if (*groupdir)
65: updaterc();
66: last = 1;
67: if (strcmp(name, bfr))
68: ngsize = findngsize(name);
69: else
70: ngsize = nngsize;
71: #ifdef DEBUG
72: fprintf(stderr, "selectng(%s) sets ngsize to %ld\n", name, ngsize);
73: #endif
74: strcpy(groupdir, name);
75: if (!xflag) {
76: i = findrcline(name);
77: if (i >= 0) {
78: if (index(rcline[i], '!')) {
79: groupdir[0] = 0;
80: return 1;
81: }
82: sprintf(rcbuf, "%s,%ld", rcline[i], ngsize+1);
83: }
84: else
85: sprintf(rcbuf, "ng: %ld", ngsize+1);
86: }
87:
88: /*
89: * Fast check for common case: 1-###
90: */
91: p = rcbuf;
92: while (*p != ' ')
93: p++;
94: while (*p == ' ')
95: p++;
96: if (*p++ == '1' && *p++ == '-') {
97: i = 0;
98: while (isdigit(*p))
99: i = 10 * i + *p++ - '0';
100: if (*p == ',' && i >= ngsize) {
101: groupdir[0] = 0;
102: return 1;
103: }
104: }
105:
106: /*
107: * The key to understanding this piece of code is that a bit is set iff
108: * that article has NOT been read. Thus, we fill in the holes when
109: * commas are found (e.g. 1-20,30-35 will result in filling in the 21-29
110: * hold), and so we assume the newsrc file is properly ordered, the way
111: * we write it out.
112: */
113: cur = 0;
114: /* Zero out the bitmap */
115: p = &bitmap[ngsize/8+1];
116: for (ptr = bitmap; ptr <= p; ptr)
117: *ptr++ = 0;
118:
119: /* Decode the .newsrc line indicating what we have read. */
120: for (ptr = rcbuf; *ptr && *ptr != ':'; ptr++)
121: ;
122: while (*ptr) {
123: while (!isdigit(*ptr) && *ptr)
124: ptr++;
125: if (!*ptr)
126: break;
127: sscanf(ptr, "%d", &next);
128: if (punct == ',') {
129: while (++cur < next) {
130: set(cur);
131: }
132: }
133: cur = next;
134: while (!ispunct(*ptr) && *ptr)
135: ptr++;
136: punct = *ptr;
137: }
138: if (rflag)
139: bit = ngsize+1;
140: else
141: bit = 0;
142: nextbit();
143: ngrp = 1;
144: return 0;
145: }
146:
147: /*
148: * Figure out the number of the largest article in newsgroup ng,
149: * and return that value.
150: */
151: long
152: findngsize(ng)
153: char *ng;
154: {
155: FILE *af;
156: long s;
157: char buf[100], n[100];
158:
159: af = xfopen(ACTIVE, "r");
160: while (fgets(buf, sizeof buf, af)) {
161: sscanf(buf, "%s %ld", n, &s);
162: if (strcmp(n, ng) == 0) {
163: fclose(af);
164: return s;
165: }
166: }
167: return 0;
168: }
169:
170: #ifdef TMAIL
171: catchterm()
172: {
173: unlink(infile);
174: unlink(outfile);
175: xxit(0);
176: }
177:
178:
179: /*
180: * The -M (Mail) interface. This code is a reasonably simple model for
181: * writing other interfaces. We write out all relavent articles to
182: * a temp file, then invoke Mail with an option to have it tell us which
183: * articles it read. Finally we count those articles as really read.
184: */
185: Mail()
186: {
187: register FILE *fp = NULL, *ofp;
188: struct hbuf h;
189: register char *ptr, *fname;
190: int news = 0;
191:
192: ofp = xfopen(mktemp(outfile), "w");
193: if (aflag && *datebuf)
194: if ((atime = cgtdate(datebuf)) == -1)
195: xerror("Cannot parse date string");
196: while (!nextng())
197: while (bit <= ngsize) {
198: sprintf(filename, "%s/%d", dirname(groupdir), bit);
199: if (access(filename, 4)
200: || ((fp = fopen(filename, "r")) == NULL)
201: || (hread(&h, fp, TRUE) == NULL)
202: || !select(&h, FALSE)) {
203: #ifdef DEBUG
204: fprintf(stderr, "Bad article '%s'\n", filename);
205: #endif
206: if (fp != NULL) {
207: fclose(fp);
208: fp = NULL;
209: }
210: clear(bit);
211: nextbit();
212: continue;
213: }
214: fname = ptr = index(h.from, '(');
215: if (fname) {
216: while (ptr && ptr[-1] == ' ')
217: ptr--;
218: if (ptr)
219: *ptr = 0;
220: fname++;
221: ptr = fname + strlen(fname) - 1;
222: if (*ptr == ')')
223: *ptr = 0;
224: }
225: h.subtime = cgtdate(h.subdate);
226: fprintf(ofp, "From %s %s",
227: #ifdef INTERNET
228: h.from[0] ? h.from :
229: #endif
230: h.path, ctime(&h.subtime));
231: if (fname)
232: fprintf(ofp, "Full-Name: %s\n", fname);
233: fprintf(ofp, "Newsgroups: %s\n", h.nbuf);
234: fprintf(ofp, "Subject: %s\n", h.title);
235: fprintf(ofp, "Article-ID: %s/%d\n\n", groupdir, bit);
236: tprint(fp, ofp, TRUE);
237: putc('\n', ofp);
238: news = TRUE;
239: fclose(fp);
240: fp = NULL;
241: nextbit();
242: }
243: updaterc();
244: fclose(ofp);
245: if (!news) {
246: fprintf(stderr, "No news.\n");
247: unlink(outfile);
248: return;
249: }
250: signal(SIGHUP, catchterm);
251: signal(SIGTERM, catchterm);
252: sprintf(bfr, "%s -f %s -T %s", TMAIL, outfile, mktemp(infile));
253: fwait(fsubr(ushell, bfr, (char *)NULL));
254: ofp = xfopen(infile, "r");
255: fseek(actfp, 0L, 0);
256: while (fgets(afline, BUFLEN, actfp) != NULL) {
257: last = 0;
258: sscanf(afline, "%s %ld", bfr, &nngsize);
259: ngcat(bfr);
260: if (!ngmatch(bfr, header.nbuf))
261: continue;
262: ngdel(bfr);
263: *groupdir = 0;
264: if (selectng(bfr))
265: continue;
266: fseek(ofp, 0L, 0);
267: while (fgets(groupdir, BUFLEN, ofp) != NULL) {
268: nstrip(groupdir);
269: ptr = index(groupdir, '/');
270: *ptr = 0;
271: if (strcmp(bfr, groupdir))
272: continue;
273: sscanf(++ptr, "%d", &last);
274: clear(last);
275: }
276: if (last) {
277: strcpy(groupdir, bfr);
278: updaterc();
279: }
280: }
281: unlink(infile);
282: unlink(outfile);
283: }
284: #endif
285:
286: updaterc()
287: {
288: register int cur = 1, next = 1, i;
289: register char *ptr;
290: char oldptr;
291:
292: sprintf(rcbuf, "%s%c ", groupdir, zapng ? '!' : ':');
293:
294: zapng = FALSE;
295: again:
296: ptr = &rcbuf[strlen(rcbuf)];
297: while (get(next))
298: next++;
299: cur = next;
300: while (!(get(next)) && next <= ngsize)
301: next++;
302: if (cur == next) {
303: next = 8193;
304: goto skip;
305: }
306: if (cur + 1 == next)
307: sprintf(ptr, "%d,", cur);
308: else
309: sprintf(ptr, "%d-%d,", cur, next - 1);
310: skip:
311: if ((long) next > ngsize) {
312: if (index(rcbuf, ',') != NULL)
313: ngdel(rcbuf);
314: else if (index(rcbuf, '!') == NULL)
315: return;
316: ptr = index(rcbuf, ' ');
317: ptr--;
318: oldptr = *ptr;
319: ptr[0] = ':';
320: ptr[1] = '\0';
321: i = findrcline(groupdir);
322: if (i >= 0) {
323: ptr[0] = oldptr;
324: ptr[1] = ' ';
325: rcline[i] = realloc(rcline[i], strlen(rcbuf) + 1);
326: if (rcline[i] == NULL)
327: xerror("Cannot realloc");
328: strcpy(rcline[i], rcbuf);
329: return;
330: }
331: if (++line > LINES)
332: xerror("Too many newsgroups\n");
333: ptr[0] = oldptr;
334: ptr[1] = ' ';
335: if ((rcline[line] = malloc(strlen(rcbuf) + 1)) == NULL)
336: xerror("Not enough memory");
337: strcpy(rcline[line], rcbuf);
338: return;
339: }
340: cur = next;
341: goto again;
342: }
343:
344:
345: newrc(rcname)
346: {
347: register FILE *fp;
348:
349: if (close(creat(rcname, 0666))) {
350: sprintf(bfr, "Cannot create %s", newsrc);
351: xerror(bfr);
352: }
353:
354: if ((fp = fopen(USERS, "a")) != NULL) {
355: fprintf(fp, "%s\n", username);
356: fclose(fp);
357: chmod(USERS, 0666);
358: }
359: }
360:
361:
362: xerror(message)
363: char *message;
364: {
365: fflush(stdout);
366: fprintf(stderr, "readnews: %s.\n", message);
367: xxit(1);
368: }
369:
370:
371: nextbit()
372: {
373: last = bit;
374: if (readmode == SPEC || xflag) {
375: if (rflag)
376: bit--;
377: else
378: bit++;
379: return;
380: }
381: if (rflag)
382: while (--bit, !get(bit) && bit > 0)
383: ;
384: else
385: while (++bit, !get(bit) && bit <= ngsize)
386: ;
387: }
388:
389:
390: xxit(status)
391: int status;
392: {
393: unlink(infile);
394: unlink(outfile);
395: exit(status);
396: }
397:
398:
399: /*
400: * Return TRUE if the user has not ruled out this article.
401: */
402: select(hp, insist)
403: register struct hbuf *hp;
404: int insist;
405: {
406: if (insist)
407: return TRUE;
408: if (tflag && !titmat(hp, header.title))
409: return FALSE;
410: if (aflag && cgtdate(hp->recdate) < atime)
411: return FALSE;
412: if (index(hp->nbuf, ',') && seenbefore(hp->ident))
413: return FALSE;
414: if (fflag && isfol(hp))
415: return FALSE;
416: return TRUE;
417: }
418:
419:
420: /*
421: * Return TRUE if this article is a followup to something.
422: */
423: isfol(hp)
424: register struct hbuf *hp;
425: {
426: if (hp->followid[0])
427: return TRUE;
428: if (strncmp(hp->title, "Re:", 3) == 0)
429: return TRUE;
430: return FALSE;
431: }
432:
433:
434: /*
435: * Given an article ID, return TRUE if we have already seen that article ID
436: * in this readnews session. This should only be called for articles
437: * with commas in the newsgroup name, and prevents the same article, which
438: * was submitted to multiple newsgroups, from being shown to the same
439: * person more than once. Bug: if the user quits after seeing the first
440: * copy, he'll see it again next time in the other newsgroup.
441: */
442: #define NART 100 /* max # articles on multiple newsgroups */
443: static int nbef = 0;
444: static char *histbuf[NART];
445: static char nextabuf[BUFLEN];
446: seenbefore(artid)
447: char *artid;
448: {
449: register int i;
450:
451: for (i = 0; i < nbef; i++)
452: if (strcmp(histbuf[i], artid) == 0)
453: return TRUE;
454: if (nbef >= NART - 1) {
455: return FALSE;
456: }
457: /* Remember the name, but don't record it as saved yet. */
458: strcpy(nextabuf, artid);
459: return FALSE;
460: }
461:
462: /*
463: * The current article has actually been looked at, so record it as such.
464: */
465: itsbeenseen(artid)
466: char *artid;
467: {
468: if (nextabuf[0] == '\0')
469: return;
470: if (strcmp(artid, nextabuf) == 0) {
471: histbuf[nbef] = (char *) malloc(strlen(artid)+1);
472: strcpy(histbuf[nbef++], artid);
473: }
474: nextabuf[0] = '\0';
475: }
476:
477: back()
478: {
479: while (fseek(actfp, -2L, 1) != -1 && ftell(actfp) > 0L) {
480: if (getc(actfp) == '\n')
481: return 0;
482: }
483: if (ftell(actfp) == 0L)
484: return 0;
485: return 1;
486: }
487:
488: /*
489: * Copy from one header structure to another.
490: * Really should just copy memory, if we had a memcpy.
491: */
492: hbufcp(hbuf2, hbuf1)
493: register struct hbuf *hbuf1, *hbuf2;
494: {
495: strcpy(hbuf2->path, hbuf1->path);
496: strcpy(hbuf2->from, hbuf1->from);
497: strcpy(hbuf2->replyto, hbuf1->replyto);
498: strcpy(hbuf2->nbuf, hbuf1->nbuf);
499: strcpy(hbuf2->title, hbuf1->title);
500: strcpy(hbuf2->ident, hbuf1->ident);
501: strcpy(hbuf2->subdate, hbuf1->subdate);
502: strcpy(hbuf2->recdate, hbuf1->recdate);
503: strcpy(hbuf2->expdate, hbuf1->expdate);
504: hbuf2->subtime = hbuf1->subtime;
505: hbuf2->rectime = hbuf1->rectime;
506: hbuf2->exptime = hbuf1->exptime;
507: }
508:
509:
510: /*
511: * Trap interrupts.
512: */
513: onsig(n)
514: int n;
515: {
516: signal(n, onsig);
517: sigtrap = n;
518: if (rcreadok < 2) {
519: exit(0);
520: }
521: }
522:
523: /*
524: * finds the line in your .newsrc file (actually the in-core "rcline"
525: * copy of it) and returns the index into the array where it was found.
526: * -1 means it didn't find it.
527: *
528: * We play clever games here to make this faster. It's inherently
529: * quadratic - we spend lots of CPU time here because we search through
530: * the whole .newsrc for each line. The "prev" variable remembers where
531: * the last match was found; we start the search there and loop around
532: * to the beginning, in the hopes that the calls will be roughly in order.
533: */
534: int
535: findrcline(name)
536: char *name;
537: {
538: register char *p, *ptr;
539: register int cur;
540: register int i;
541: register int top;
542: static int prev = 0;
543:
544: top = line; i = prev;
545: loop:
546: for (; i <= top; i++) {
547: for (p = name, ptr = rcline[i]; (cur = *p++); ) {
548: if (cur != *ptr++)
549: goto contin2;
550: }
551: if (*ptr != ':' && *ptr != '!')
552: continue;
553: prev = i;
554: return i;
555: contin2:
556: ;
557: }
558: if (i > line && line > prev-1) {
559: i = 0;
560: top = prev-1;
561: goto loop;
562: }
563: return -1;
564: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.