|
|
1.1 root 1: /*
2: * This software is Copyright (c) 1986 by Rick Adams.
3: *
4: * Permission is hereby granted to copy, reproduce, redistribute or
5: * otherwise use this software as long as: there is no monetary
6: * profit gained specifically from the use or reproduction or this
7: * software, it is not sold, rented, traded or otherwise marketed, and
8: * this copyright notice is included prominently in any copy
9: * made.
10: *
11: * The author make no claims as to the fitness or correctness of
12: * this software for any use whatsoever, and it is provided as is.
13: * Any use of this software is at the user's own risk.
14: *
15: * rfuncs - functions for readnews.
16: */
17:
18: #ifdef SCCSID
19: static char *SccsId = "@(#)rfuncs.c 2.29 3/19/86";
20: #endif /* SCCSID */
21:
22: /*LINTLIBRARY*/
23:
24: #include "rparams.h"
25:
26: char lentab[LINES]; /* length of newsgroupname for each rcline */
27: long nngsize; /* The next upcoming value of ngsize. */
28: long nminartno; /* Smallest article number in this group */
29: int BITMAPSIZE = 0;
30:
31: nextng()
32: {
33: long curpos;
34: #ifdef DEBUG
35: fprintf(stderr, "nextng()\n");
36: #endif
37: curpos = ftell(actfp);
38:
39: next:
40: #ifdef DEBUG
41: fprintf(stderr, "next:\n");
42: #endif
43: if (actdirect == BACKWARD) {
44: if (back()) {
45: (void) fseek(actfp, curpos, 0);
46: return 1;
47: }
48: if (back()) {
49: (void) fseek(actfp, curpos, 0);
50: return 1;
51: }
52: }
53: if (fgets(afline, BUFLEN, actfp) == NULL)
54: return 1;
55: if (sscanf(afline, "%s %ld %ld", bfr, &nngsize, &nminartno) < 3) {
56: bfr[0] = '\0';
57: nngsize = 0;
58: nminartno = 0;
59: }
60: #ifdef DEBUG
61: fprintf(stderr, "bfr = '%s'\n", bfr);
62: #endif
63:
64: if (!ngmatch(bfr, header.nbuf))
65: goto next;
66: if (xflag)
67: readmode = SPEC;
68: else
69: readmode = NEXT;
70: if (selectng(bfr, TRUE, FALSE))
71: goto next;
72: return 0;
73: }
74:
75:
76: selectng(name, fastcheck, resubscribe)
77: char *name;
78: {
79: register char *ptr, punct = ',';
80: register int i;
81: register char *p;
82: register long cur;
83: long next = 0;
84: FILE *af;
85: long s, sm;
86: char buf[100], n[100];
87:
88: #ifdef DEBUG
89: fprintf(stderr,"selectng: groupdir = %s\n", groupdir);
90: #endif /* DEBUG */
91: if (*groupdir)
92: updaterc();
93: last = 1;
94: if (strcmp(name, bfr)) {
95: af = xfopen(ACTIVE, "r");
96: while (fgets(buf, sizeof buf, af) != NULL) {
97: if (sscanf(buf, "%s %ld %ld", n, &s, &sm) == 3 &&
98: strcmp(n, name) == 0) {
99: ngsize = s;
100: minartno = sm;
101: break;
102: }
103: }
104: (void) fclose(af);
105: } else {
106: ngsize = nngsize;
107: minartno = nminartno;
108: }
109: #ifdef DEBUG
110: fprintf(stderr, "selectng(%s) sets ngsize to %ld, minartno to %ld\n",
111: name, ngsize, minartno);
112: #endif
113: (void) strcpy(groupdir, name);
114: if (!xflag) {
115: i = findrcline(name);
116: if (i >= 0) {
117: if (p = index(rcline[i], '!')) {
118: switch (resubscribe) {
119: case FALSE:
120: groupdir[0] = 0;
121: return 1;
122: case TRUE:
123: *p = ':';
124: break;
125: case PERHAPS:
126: zapng = TRUE;
127: break;
128: }
129: } else
130: p = index(rcline[i], ':');
131: if (!p) /* shouldn't happen */
132: p = rcline[i];
133: while (*++p == ' ')
134: ;
135: (void) sprintf(rcbuf, "%s%s%ld", rcline[i],
136: *p == '\0' ? " " : ",", ngsize+1);
137: }
138: else
139: (void) sprintf(rcbuf, "ng: %ld", ngsize+1);
140: } else
141: (void) sprintf(rcbuf, "ng: %ld", ngsize+1);
142: #ifdef DEBUG
143: fprintf(stderr, "rcbuf set to %s\n", rcbuf);
144: #endif /* DEBUG */
145:
146: /*
147: * Fast check for common case: 1-###
148: */
149: if (fastcheck) {
150: p = rcbuf;
151: while (*p != ' ')
152: p++;
153: while (*p == ' ')
154: p++;
155: if (*p++ == '1' && *p++ == '-') {
156: cur = 0;
157: while (isdigit(*p))
158: cur = 10 * cur + *p++ - '0';
159: if (*p == ',' && cur == ngsize) {
160: #ifdef DEBUG
161: fprintf(stderr, "Group: %s, all read\n", groupdir);
162: #endif
163: groupdir[0] = 0;
164: return 1;
165: }
166: if (cur > ngsize) {
167: /*
168: * Claim to have read articles
169: * which "active" believes have
170: * never existed - we believe "active"
171: */
172: fprintf(stderr,
173: "%s %s...\r\n\t%s %ld to %ld\r\n",
174: "Warning: newsgroup", groupdir,
175: "last article claimed read reset from",
176: cur, ngsize);
177: }
178: }
179: }
180:
181: /*
182: * The key to understanding this piece of code is that a bit is set iff
183: * that article has NOT been read. Thus, we fill in the holes when
184: * commas are found (e.g. 1-20,30-35 will result in filling in the 21-29
185: * holes), and so we assume the newsrc file is properly ordered, the way
186: * we write it out.
187: */
188: if ((ngsize-minartno) > BITMAPSIZE) {
189: /* This should never happen */
190: (void) xerror("Bitmap not large enough for newsgroup %s", groupdir);
191: }
192:
193: cur = 0;
194: bzero(bitmap, (int) (ngsize-minartno)/8+1); /* 8 bits per character */
195:
196: /* Decode the .newsrc line indicating what we have read. */
197: for (ptr = rcbuf; *ptr && *ptr != ':'; ptr++)
198: ;
199: while (*ptr) {
200: while (!isdigit(*ptr) && *ptr)
201: ptr++;
202: if (!*ptr)
203: break;
204: (void) sscanf(ptr, "%ld", &next);
205: if (punct == ',') {
206: while (++cur < next) {
207: set(cur);
208: }
209: }
210: cur = next;
211: while (!ispunct(*ptr) && *ptr)
212: ptr++;
213: punct = *ptr;
214: }
215: if (rflag)
216: bit = ngsize+1;
217: else
218: bit = minartno -1;
219: nextbit();
220: ngrp = 1;
221: return 0;
222: }
223:
224: #ifdef TMAIL
225: catchterm()
226: {
227: (void) unlink(infile);
228: (void) unlink(outfile);
229: xxit(0);
230: }
231:
232:
233: /*
234: * The -M (Mail) interface. This code is a reasonably simple model for
235: * writing other interfaces. We write out all relevant articles to
236: * a temp file, then invoke Mail with an option to have it tell us which
237: * articles it read. Finally we count those articles as really read.
238: */
239: Mail()
240: {
241: register FILE *fp = NULL, *ofp;
242: struct hbuf h;
243: register char *ptr, *fname;
244: int news = 0;
245: register int i;
246:
247: for(i=0;i<NUNREC;i++)
248: h.unrec[i] = NULL;
249:
250: ofp = xfopen(mktemp(outfile), "w");
251: if (aflag && *datebuf)
252: if ((atime = cgtdate(datebuf)) == -1)
253: xerror("Cannot parse date string");
254: while (!nextng())
255: while (bit <= ngsize) {
256: (void) sprintf(filename, "%s/%ld", dirname(groupdir), bit);
257: if (access(filename, 4)
258: || ((fp = fopen(filename, "r")) == NULL)
259: || (hread(&h, fp, TRUE) == NULL)
260: || !aselect(&h, FALSE)) {
261: #ifdef DEBUG
262: fprintf(stderr, "Bad article '%s'\n", filename);
263: #endif
264: if (fp != NULL) {
265: (void) fclose(fp);
266: fp = NULL;
267: }
268: clear(bit);
269: nextbit();
270: continue;
271: }
272: fname = ptr = index(h.from, '(');
273: if (fname) {
274: while (ptr && ptr[-1] == ' ')
275: ptr--;
276: if (ptr)
277: *ptr = 0;
278: fname++;
279: ptr = fname + strlen(fname) - 1;
280: if (*ptr == ')')
281: *ptr = 0;
282: }
283: h.subtime = cgtdate(h.subdate);
284: fprintf(ofp, "From %s %s",
285: #ifdef INTERNET
286: h.from[0] ? h.from :
287: #endif
288: h.path, ctime(&h.subtime));
289: if (fname)
290: fprintf(ofp, "Full-Name: %s\n", fname);
291: fprintf(ofp, "Newsgroups: %s\n", h.nbuf);
292: fprintf(ofp, "Subject: %s\n", h.title);
293: fprintf(ofp, "Article-ID: %s/%ld\n\n", groupdir, bit);
294: tprint(fp, ofp, TRUE);
295: putc('\n', ofp);
296: news = TRUE;
297: (void) fclose(fp);
298: fp = NULL;
299: nextbit();
300: }
301: updaterc();
302: (void) fclose(ofp);
303: if (!news) {
304: if (!checkngs())
305: fprintf(stderr, "No news.\n");
306: (void) unlink(outfile);
307: return;
308: }
309: (void) signal(SIGHUP, catchterm);
310: (void) signal(SIGTERM, catchterm);
311: (void) sprintf(bfr, "%s -f %s -T %s", TMAIL, outfile, mktemp(infile));
312: fwait(fsubr(ushell, bfr, (char *)NULL));
313: ofp = xfopen(infile, "r");
314: (void) fseek(actfp, 0L, 0);
315: while (fgets(afline, BUFLEN, actfp) != NULL) {
316: last = 0;
317: if (sscanf(afline, "%s %ld", bfr, &nngsize) < 2) {
318: bfr[0] = '\0';
319: nngsize = 0;
320: }
321: if (!ngmatch(bfr, header.nbuf))
322: continue;
323: *groupdir = 0;
324: if (selectng(bfr, TRUE, FALSE))
325: continue;
326: (void) fseek(ofp, 0L, 0);
327: while (fgets(groupdir, BUFLEN, ofp) != NULL) {
328: (void) nstrip(groupdir);
329: ptr = index(groupdir, '/');
330: *ptr = 0;
331: if (strcmp(bfr, groupdir))
332: continue;
333: (void) sscanf(++ptr, "%ld", &last);
334: clear(last);
335: }
336: if (last) {
337: (void) strcpy(groupdir, bfr);
338: updaterc();
339: }
340: }
341: (void) unlink(infile);
342: (void) unlink(outfile);
343: }
344: #endif
345:
346: updaterc()
347: {
348: register long cur = 1, next = 1;
349: register int i;
350: register char *ptr;
351: char oldptr;
352:
353: sprintf(rcbuf, "%s%c ", groupdir, zapng ? '!' : ':');
354:
355: zapng = FALSE;
356: again:
357: ptr = &rcbuf[strlen(rcbuf)];
358: while (get(next) && next <= ngsize)
359: next++;
360: cur = next;
361: while (!(get(next)) && next <= ngsize)
362: next++;
363: if (cur == next) {
364: next = ngsize + 1;
365: goto skip;
366: }
367: if (ptr[-1] != ' ')
368: *ptr++ = ',';
369: if (cur + 1 == next)
370: (void) sprintf(ptr, "%ld", cur);
371: else
372: (void) sprintf(ptr, "%ld-%ld", cur, next - 1);
373: skip:
374: if ((long) next > ngsize) {
375: if (strpbrk(rcbuf, ":!") == NULL) /* bad line, huh?? */
376: return;
377: ptr = index(rcbuf, ' ');
378: if (ptr == NULL) /* impossible */
379: return;
380: ptr--;
381: oldptr = *ptr;
382: ptr[0] = ':';
383: ptr[1] = '\0';
384: i = findrcline(groupdir);
385: if (i >= 0) {
386: ptr[0] = oldptr;
387: ptr[1] = ' ';
388: rcline[i] = realloc(rcline[i], (unsigned)(strlen(rcbuf) + 1));
389: if (rcline[i] == NULL)
390: xerror("Cannot realloc");
391: (void) strcpy(rcline[i], rcbuf);
392: #ifdef DEBUG
393: fprintf(stderr," new rcline = %s\n", rcline[i]);
394: #endif /* DEBUG */
395: return;
396: }
397: if (++line > LINES)
398: xerror("Too many newsgroups");
399: ptr[0] = oldptr;
400: ptr[1] = ' ';
401: if ((rcline[line] = malloc((unsigned)(strlen(rcbuf) + 1))) == NULL)
402: xerror("Not enough memory");
403: (void) strcpy(rcline[line], rcbuf);
404: #ifdef DEBUG
405: fprintf(stderr," new rcline2 = %s\n", rcline[line]);
406: #endif /* DEBUG */
407: return;
408: }
409: cur = next;
410: goto again;
411: }
412:
413: newrc(rcname)
414: char *rcname;
415: {
416: register FILE *fp;
417:
418: if (close(creat(rcname, 0666))) {
419: (void) sprintf(bfr, "Cannot create %s", newsrc);
420: xerror(bfr);
421: }
422:
423: sprintf(bfr, "%s/users", LIB);
424: if ((fp = fopen(bfr, "a")) != NULL) {
425: fprintf(fp, "%s\n", username);
426: (void) fclose(fp);
427: (void) chmod(bfr, 0666);
428: }
429: }
430:
431: nextbit()
432: {
433: #ifdef DEBUG
434: fprintf(stderr,"nextbit() bit = %ld\n", bit);
435: #endif /* DEBUG */
436: last = bit;
437: if (readmode == SPEC || xflag) {
438: if (rflag)
439: bit--;
440: else
441: bit++;
442: return;
443: }
444: if (rflag)
445: while (--bit, !get(bit) && bit > minartno)
446: ;
447: else
448: while (++bit, !get(bit) && bit <= ngsize)
449: ;
450: #ifdef DEBUG
451: fprintf(stderr,"nextng leaves bit as %ld\n", bit);
452: #endif /* DEBUG */
453: }
454:
455: /*
456: * Return TRUE if the user has not ruled out this article.
457: */
458: aselect(hp, insist)
459: register struct hbuf *hp;
460: int insist;
461: {
462: if (insist)
463: return TRUE;
464: if (tflag && !titmat(hp, header.title))
465: return FALSE;
466: if (aflag && cgtdate(hp->subdate) < atime)
467: return FALSE;
468: if (index(hp->nbuf, ',') && !rightgroup(hp))
469: return FALSE;
470: if (fflag && (hp->followid[0] || prefix(hp->title, "Re:")))
471: return FALSE;
472: return TRUE;
473: }
474:
475: /*
476: * Code to avoid showing multiple articles for news.
477: * Works even if you exit news.
478: * Returns nonzero if we should show this article.
479: */
480: rightgroup(hp)
481: struct hbuf *hp;
482: {
483: char ng[BUFLEN];
484: register char *p, *g;
485: int i, flag;
486:
487: strcpy(ng, hp->nbuf);
488: g = ng;
489: flag = 1;
490: while (g != NULL) {
491: p = index(g, ',');
492: if (p != NULL) {
493: *p++ = '\0';
494: while (*p == ' ')
495: p++;
496: }
497: if (strcmp(g, groupdir) == 0)
498: return flag;
499: if (ngmatch(g, header.nbuf)
500: && ((i = findrcline(g)) >= 0
501: && index(rcline[i], '!') == NULL))
502: flag = 0;
503: g = p;
504: }
505: /* we must be in "junk" or "control" */
506: return TRUE;
507: }
508:
509: back()
510: {
511: while (fseek(actfp, -2L, 1) != -1 && ftell(actfp) > 0L) {
512: if (getc(actfp) == '\n')
513: return 0;
514: }
515: if (ftell(actfp) == 0L)
516: return 0;
517: return 1;
518: }
519:
520: /*
521: * Trap interrupts.
522: */
523: onsig(n)
524: int n;
525: {
526: (void) signal(n, onsig);
527: SigTrap = n;
528: if (rcreadok < 2) {
529: fprintf(stderr, "Aborted early\n");
530: xxit(0);
531: }
532: }
533:
534: /*
535: * finds the line in your .newsrc file (actually the in-core "rcline"
536: * copy of it) and returns the index into the array where it was found.
537: * -1 means it didn't find it.
538: *
539: * We play clever games here to make this faster. It's inherently
540: * quadratic - we spend lots of CPU time here because we search through
541: * the whole .newsrc for each line. The "prev" variable remembers where
542: * the last match was found; we start the search there and loop around
543: * to the beginning, in the hopes that the calls will be roughly in order.
544: */
545: int
546: findrcline(name)
547: register char *name;
548: {
549: register char * p;
550: register int i;
551: register int top;
552: register int len;
553: static int prev;
554: static int didthru;
555:
556: for ( ; didthru <= line; ++didthru)
557: if ((p = index(rcline[didthru], '!')) != 0 ||
558: (p = index(rcline[didthru], ':')) != 0) {
559: lentab[didthru] = (int)(p - rcline[didthru]);
560: }
561: len = strlen(name);
562: top = line;
563: i = prev;
564: loop:
565: for ( ; i <= top; ++i)
566: if (lentab[i] == len && rcline[i] != NULL &&
567: strncmp(name, rcline[i], len) == 0)
568: return prev = i;
569: if (i > line && line > prev - 1) {
570: i = 0;
571: top = prev - 1;
572: goto loop;
573: }
574: return -1;
575: }
576:
577: /*
578: * sortactive - make a local copy of the active file, sorted according
579: * to the user's preferences, according to his .newsrc file.
580: */
581:
582: struct table_elt {
583: int rcindex;
584: long maxart, minart;
585: char yn;
586: };
587:
588: #ifdef SORTACTIVE
589: static int
590: rcsort(a, b)
591: char *a, *b;
592: {
593: return(((struct table_elt *)a)->rcindex -
594: ((struct table_elt *)b)->rcindex);
595: }
596:
597: static char *newactivename = "/tmp/newsaXXXXXX";
598: #endif /* SORTACTIVE */
599:
600: sortactive()
601: {
602: register struct table_elt *tp;
603: register char *p;
604: register FILE *nfp, *afp;
605: char aline[BUFLEN], ngname[BUFLEN];
606: struct table_elt table[LINES];
607: int nlines = 0, i, delta, lastline;
608:
609: #ifdef SORTACTIVE
610: /* make a new sorted copy of ACTIVE */
611: nfp = fopen(mktemp(newactivename), "w");
612: (void) chmod(newactivename, 0600);
613: if (nfp == NULL) {
614: perror(newactivename);
615: return;
616: }
617:
618: /* look up all the lines in ACTIVE, finding their positions in .newsrc */
619: p = ACTIVE;
620: ACTIVE = newactivename;
621: afp = xfopen(p, "r");
622: tp = table;
623: #else /* !SORTACTIVE */
624: afp = xfopen(ACTIVE, "r");
625: #endif /* !SORTACTIVE */
626: while (fgets(aline, sizeof aline, afp) != NULL) {
627: if (sscanf(aline,"%s %ld %ld %c", ngname, &tp->maxart, &tp->minart, &tp->yn) != 4)
628: xerror("Active file corrupt");
629: delta = tp->maxart - tp->minart;
630: if (delta >= BITMAPSIZE)
631: BITMAPSIZE = delta+ 1;
632: #ifdef SORTACTIVE
633: tp->rcindex = findrcline(ngname);
634: if (tp->rcindex < 0) {
635: register FILE *f;
636: /* it's not in his .newsrc, maybe it's aliased? */
637: f = xfopen(ALIASES,"r");
638: while (fscanf(f,"%s %s", afline, bfr) == 2
639: && strcmp(ngname, bfr))
640: ;
641: (void) fclose(f);
642: if (strcmp(ngname, bfr) == 0) {
643: int j;
644: j = findrcline(afline);
645: if (j >= 0) {
646: p = rcline[j];
647: while (*p != ':' && *p != '!' && *p)
648: p++;
649: strcat(bfr, p);
650: rcline[j] = realloc(rcline[j], (unsigned)(strlen(bfr)+1));
651: if (rcline[j] == NULL)
652: xerror("Not enough memory");
653: strcpy(rcline[j], bfr);
654: tp++->rcindex = j;
655: continue;
656: }
657: }
658: if (++line > LINES)
659: xerror("Too many newsgroups");
660: strcat(ngname, ":");
661: rcline[line] = malloc((unsigned)(strlen(ngname) + 1));
662: if (rcline[line] == NULL)
663: xerror("Not enough memory");
664: strcpy(rcline[line], ngname);
665: tp->rcindex = line;
666: }
667: tp++;
668: #endif /* SORTACTIVE */
669: }
670: (void) fclose(afp);
671: BITMAPSIZE = 8 * ((BITMAPSIZE+7) / 8);
672: bitmap = malloc((unsigned)BITMAPSIZE/8);
673: if (bitmap == NULL)
674: xerror("Can't malloc bitmap");
675:
676: #ifdef SORTACTIVE
677: /* sort by position in user's .newsrc file (new groups come up last) */
678: nlines = tp - table;
679: qsort((char *)table, nlines, sizeof table[0], rcsort);
680:
681: tp = table;
682: lastline = tp->rcindex - 1;
683: /* copy active to newactive, in the new order */
684: for (i = 0; i < nlines; i++) {
685: while (++lastline < tp->rcindex) {
686: fprintf(stderr, "Duplicate .newsrc line or bad group %s\n",
687: rcline[lastline]);
688: lentab[lastline] = 0;
689: free(rcline[lastline]);
690: rcline[lastline] = NULL;
691: }
692: if (rcline[tp->rcindex] == NULL)
693: continue;
694: p = rcline[tp->rcindex];
695: while (*p != ':' && *p != '!')
696: fputc(*p++, nfp);
697: (void) fprintf(nfp, " %ld %ld %c\n", tp->maxart, tp->minart,
698: tp->yn);
699: tp++;
700: }
701: (void) fclose(nfp);
702: #endif /* SORTACTIVE */
703: }
704:
705: /* ARGSUSED */
706: checkngs(nbuf, f)
707: char *nbuf;
708: FILE *f;
709: {
710: return 0;
711: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.