|
|
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.