|
|
1.1 ! root 1: /* ! 2: * funcs - functions used by both inews and readnews. ! 3: */ ! 4: ! 5: static char *SccsId = "@(#)funcs.c 2.10 6/24/83"; ! 6: ! 7: #include "params.h" ! 8: ! 9: /* ! 10: * Append NGDELIM to string. ! 11: */ ! 12: ngcat(s) ! 13: register char *s; ! 14: { ! 15: if (*s) { ! 16: while (*s++); ! 17: s -= 2; ! 18: if (*s++ == NGDELIM) ! 19: return; ! 20: } ! 21: *s++ = NGDELIM; ! 22: *s = '\0'; ! 23: } ! 24: ! 25: /* ! 26: * News group matching. ! 27: * ! 28: * nglist is a list of newsgroups. ! 29: * sublist is a list of subscriptions. ! 30: * sublist may have "meta newsgroups" in it. ! 31: * All fields are NGDELIM separated, ! 32: * and there is an NGDELIM at the end of each argument. ! 33: * ! 34: * Currently implemented glitches: ! 35: * sublist uses 'all' like shell uses '*', and '.' like shell '/'. ! 36: * If subscription X matches Y, it also matches Y.anything. ! 37: */ ! 38: ngmatch(nglist, sublist) ! 39: register char *nglist, *sublist; ! 40: { ! 41: register char *n, *s; ! 42: register int rc; ! 43: ! 44: rc = FALSE; ! 45: for (n = nglist; *n != '\0' && rc == FALSE;) { ! 46: for (s = sublist; *s != '\0';) { ! 47: if (*s != NEGCHAR) ! 48: rc |= ptrncmp(s, n); ! 49: else ! 50: rc &= ~ptrncmp(s+1, n); ! 51: while (*s++ != NGDELIM); ! 52: } ! 53: while (*n++ != NGDELIM); ! 54: } ! 55: return(rc); ! 56: } ! 57: ! 58: /* ! 59: * Compare two newsgroups for equality. ! 60: * The first one may be a "meta" newsgroup. ! 61: */ ! 62: ptrncmp(ng1, ng2) ! 63: register char *ng1, *ng2; ! 64: { ! 65: while (*ng1 != NGDELIM) { ! 66: if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') { ! 67: ng1 += 3; ! 68: while (*ng2 != NGDELIM && *ng2 != '.') ! 69: if (ptrncmp(ng1, ng2++)) ! 70: return(TRUE); ! 71: return (ptrncmp(ng1, ng2)); ! 72: } else if (*ng1++ != *ng2++) ! 73: return(FALSE); ! 74: } ! 75: return (*ng2 == '.' || *ng2 == NGDELIM); ! 76: } ! 77: ! 78: /* ! 79: * Remove newsgroups in 'a' not subscribed to by 'b'. ! 80: */ ! 81: ngsquash(ap, bp) ! 82: register char *ap, *bp; ! 83: { ! 84: register char *tp; ! 85: char tbuf[BUFLEN]; ! 86: ! 87: /* replace NGDELIM by '\0' in a */ ! 88: for (tp = ap; *tp != '\0'; tp++) ! 89: if (*tp == NGDELIM) ! 90: *tp = '\0'; ! 91: /* ap = building, tp = checking. */ ! 92: tp = ap; ! 93: while (*tp != '\0') { ! 94: ngcat(strcpy(tbuf, tp)); ! 95: if (ngmatch(tbuf, bp)) { ! 96: while ((*ap++ = *tp++) != '\0') ! 97: ; ! 98: ap[-1] = NGDELIM; ! 99: } else ! 100: while (*tp++ != '\0'); ! 101: } ! 102: *ap = '\0'; ! 103: } ! 104: ! 105: /* ! 106: * Exec the shell. ! 107: * This version resets uid, gid, and umask. ! 108: * Called with fsubr(ushell, s, NULL) ! 109: */ ! 110: /* ARGSUSED */ ! 111: ushell(s, dummy) ! 112: char *s, *dummy; ! 113: { ! 114: umask(savmask); ! 115: setgid(gid); ! 116: setuid(uid); ! 117: xshell(s); ! 118: } ! 119: ! 120: /* ! 121: * Exec the shell. ! 122: * This version restricts PATH to bin and /usr/bin. ! 123: * Called with fsubr(pshell, s, NULL) ! 124: */ ! 125: extern char **environ; ! 126: ! 127: /* ARGSUSED */ ! 128: pshell(s, dummy) ! 129: char *s, *dummy; ! 130: { ! 131: static char *penv[] = { SYSPATH, NULL }; ! 132: register char **ep, *p; ! 133: register int found; ! 134: ! 135: found = FALSE; ! 136: for (ep = environ; p = *ep; ep++) { ! 137: if (strncmp(p, "PATH=", 5) == 0) { ! 138: *ep = penv[0]; ! 139: found = TRUE; ! 140: } ! 141: } ! 142: if (!found) ! 143: environ = &penv[0]; ! 144: xshell(s); ! 145: } ! 146: ! 147: /* ! 148: * Exec the shell. ! 149: */ ! 150: xshell(s) ! 151: char *s; ! 152: { ! 153: execl(SHELL, SHELL, "-c", s, 0); ! 154: xerror("No shell!"); ! 155: } ! 156: ! 157: /* ! 158: * Fork and call a subroutine with two args. ! 159: * Return pid without waiting. ! 160: */ ! 161: fsubr(f, s1, s2) ! 162: int (*f)(); ! 163: char *s1, *s2; ! 164: { ! 165: register int pid; ! 166: ! 167: while ((pid = fork()) == -1) ! 168: sleep(1); ! 169: if (pid == 0) { ! 170: (*f)(s1, s2); ! 171: exit(0); ! 172: } ! 173: return(pid); ! 174: } ! 175: ! 176: /* ! 177: * Wait on a child process. ! 178: */ ! 179: fwait(pid) ! 180: register int pid; ! 181: { ! 182: register int w; ! 183: int status; ! 184: void (*onhup)(), (*onint)(); ! 185: ! 186: onint = (void (*)()) signal(SIGINT, SIG_IGN); ! 187: onhup = (void (*)()) signal(SIGHUP, SIG_IGN); ! 188: while ((w = wait(&status)) != pid && w != -1) ! 189: ; ! 190: if (w == -1) ! 191: status = -1; ! 192: signal(SIGINT, onint); ! 193: signal(SIGHUP, onhup); ! 194: return(status); ! 195: } ! 196: ! 197: /* ! 198: * Get user name and home directory. ! 199: */ ! 200: getuser() ! 201: { ! 202: static int flag = TRUE; ! 203: register struct passwd *p; ! 204: ! 205: if (flag) { ! 206: if ((p = getpwuid(uid)) == NULL) ! 207: xerror("Cannot get user's name"); ! 208: if (username[0] == 0) ! 209: strcpy(username, p->pw_name); ! 210: strcpy(userhome, p->pw_dir); ! 211: flag = FALSE; ! 212: } ! 213: strcpy(header.path, username); ! 214: } ! 215: ! 216: /* ! 217: * Strip trailing newlines, blanks, and tabs from 's'. ! 218: * Return TRUE if newline was found, else FALSE. ! 219: */ ! 220: nstrip(s) ! 221: register char *s; ! 222: { ! 223: register char *p; ! 224: register int rc; ! 225: ! 226: rc = FALSE; ! 227: p = s; ! 228: while (*p) ! 229: if (*p++ == '\n') ! 230: rc = TRUE; ! 231: while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t')); ! 232: *++p = '\0'; ! 233: return(rc); ! 234: } ! 235: ! 236: /* ! 237: * Delete trailing NGDELIM. ! 238: */ ! 239: ngdel(s) ! 240: register char *s; ! 241: { ! 242: if (*s++) { ! 243: while (*s++); ! 244: s -= 2; ! 245: if (*s == NGDELIM) ! 246: *s = '\0'; ! 247: } ! 248: } ! 249: ! 250: /* ! 251: * Return the ptr in sp at which the character c appears; ! 252: * NULL if not found ! 253: * ! 254: * These are the v7 index and rindex routines, stolen for portability. ! 255: * (Some Unix systems call them strchr and strrchr, notably PWB 2.0 ! 256: * and its derivitives such as Unix/TS 2.0, Unix 3.0, etc.) Others, ! 257: * like v6, don't have them at all. ! 258: */ ! 259: ! 260: char * ! 261: index(sp, c) ! 262: register char *sp, c; ! 263: { ! 264: do { ! 265: if (*sp == c) ! 266: return(sp); ! 267: } while (*sp++); ! 268: return(NULL); ! 269: } ! 270: ! 271: /* ! 272: * Return the ptr in sp at which the character c last ! 273: * appears; NULL if not found ! 274: */ ! 275: ! 276: char * ! 277: rindex(sp, c) ! 278: register char *sp, c; ! 279: { ! 280: register char *r; ! 281: ! 282: r = NULL; ! 283: do { ! 284: if (*sp == c) ! 285: r = sp; ! 286: } while (*sp++); ! 287: return(r); ! 288: } ! 289: static FILE *sysfile; ! 290: ! 291: char *fldget(); ! 292: ! 293: /* ! 294: * Open SUBFILE. ! 295: */ ! 296: s_openr() ! 297: { ! 298: sysfile = xfopen(SUBFILE, "r"); ! 299: } ! 300: ! 301: /* ! 302: * Read SUBFILE. ! 303: */ ! 304: s_read(sp) ! 305: register struct srec *sp; ! 306: { ! 307: register char *p; ! 308: again: ! 309: p = bfr; ! 310: if (fgets(p, LBUFLEN, sysfile) == NULL) ! 311: return(FALSE); ! 312: if (!nstrip(p)) ! 313: xerror("SUBFILE line too long."); ! 314: if (*p == '#') ! 315: goto again; ! 316: sp->s_xmit[0] = '\0'; ! 317: sp->s_flags[0] = '\0'; ! 318: ! 319: p = fldget(sp->s_name, p); ! 320: if (*p++ == '\0') ! 321: xerror("Bad SUBFILE line."); ! 322: /* ! 323: * A sys file line reading "ME" means the name of the local system. ! 324: */ ! 325: if (strcmp(sp->s_name, "ME") == 0) ! 326: strcpy(sp->s_name, FULLSYSNAME); ! 327: p = fldget(sp->s_nbuf, p); ! 328: lcase(sp->s_nbuf); ! 329: ngcat(sp->s_nbuf); ! 330: if (*p++ == '\0') ! 331: return(TRUE); ! 332: ! 333: p = fldget(sp->s_flags, p); ! 334: if (*p++ == '\0') ! 335: return(TRUE); ! 336: ! 337: fldget(sp->s_xmit, p); ! 338: return(TRUE); ! 339: } ! 340: ! 341: char * ! 342: fldget(q, p) ! 343: register char *q, *p; ! 344: { ! 345: while (*p && *p != ':') { ! 346: if (*p == '\\' && p[1]==':') ! 347: p++; ! 348: *q++ = *p++; ! 349: } ! 350: *q = '\0'; ! 351: return(p); ! 352: } ! 353: ! 354: /* ! 355: * Find the SUBFILE record for a system. ! 356: */ ! 357: s_find(sp, system) ! 358: register struct srec *sp; ! 359: char *system; ! 360: { ! 361: s_openr(); ! 362: while (s_read(sp)) ! 363: if (strncmp(system, sp->s_name, SNLN) == 0) { ! 364: s_close(); ! 365: return(TRUE); ! 366: } ! 367: s_close(); ! 368: return(FALSE); ! 369: } ! 370: ! 371: /* ! 372: * Close sysfile. ! 373: */ ! 374: s_close() ! 375: { ! 376: fclose(sysfile); ! 377: } ! 378: ! 379: /* ! 380: * Local open routine. ! 381: */ ! 382: FILE * ! 383: xfopen(name, mode) ! 384: register char *name, *mode; ! 385: { ! 386: register FILE *fp; ! 387: char *fname; ! 388: ! 389: if ((fp = fopen(name, mode)) == NULL) { ! 390: fname = rindex(name, '/'); ! 391: /* ! 392: * IHCC users only see the "filename" that was in trouble, not the ! 393: * whole path. (for security!) ! 394: */ ! 395: #ifdef IHCC ! 396: sprintf(bfr, "Cannot open %s (%s)", ++fname, mode); ! 397: #else ! 398: sprintf(bfr, "Cannot open %s (%s)", name, mode); ! 399: #endif ! 400: xerror(bfr); ! 401: } ! 402: /* kludge for setuid not being honored for root */ ! 403: if ((uid == 0) && (duid != 0) && ((mode == "a") || (mode == "w"))) ! 404: chown(name, duid, dgid); ! 405: return(fp); ! 406: } ! 407: ! 408: time_t ! 409: cgtdate(datestr) ! 410: char *datestr; ! 411: { ! 412: time_t i; ! 413: char junk[40],month[40],day[30],time[60],year[50]; ! 414: ! 415: if ((i = getdate(datestr, (struct timeb *) NULL)) >= 0) ! 416: return i; ! 417: sscanf(datestr, "%s %s %s %s %s", junk, month, day, time, year); ! 418: sprintf(bfr, "%s %s, %s %s", month, day, year, time); ! 419: return getdate(bfr, (struct timeb *) NULL); ! 420: } ! 421: ! 422: lcase(s) ! 423: register char *s; ! 424: { ! 425: register char *ptr; ! 426: ! 427: for (ptr = s; *ptr; ptr++) ! 428: if (isupper(*ptr)) ! 429: *ptr = tolower(*ptr); ! 430: } ! 431: ! 432: ohwrite(hp, fp) ! 433: register struct hbuf *hp; ! 434: register FILE *fp; ! 435: { ! 436: ngdel(strcpy(bfr, hp->nbuf)); ! 437: fprintf(fp, "A%s\n%s\n%s!%s\n%s\n%s\n", hp->oident, bfr, FULLSYSNAME, hp->path, hp->subdate, hp->title); ! 438: } ! 439: ! 440: static int hascaught = 0; ! 441: static catchintr() ! 442: { ! 443: hascaught = 1; ! 444: printf("\n"); ! 445: fflush(stdout); ! 446: } ! 447: ! 448: /* ! 449: * Print a recorded message warning the poor luser what he is doing ! 450: * and demand that he understands it before proceeding. Only do ! 451: * this for newsgroups listed in LIBDIR/recording. ! 452: */ ! 453: recording(ngrps) ! 454: char *ngrps; ! 455: { ! 456: char recbuf[100]; ! 457: FILE *fd; ! 458: char nglist[100], fname[100]; ! 459: char lngrps[100]; ! 460: char *oldsig; ! 461: int c, n, yes; ! 462: ! 463: sprintf(recbuf, "%s/%s", LIB, "recording"); ! 464: fd = fopen(recbuf, "r"); ! 465: if (fd == NULL) ! 466: return 0; ! 467: strcpy(lngrps, ngrps); ! 468: ngcat(lngrps); ! 469: while ((fgets(recbuf, sizeof recbuf, fd)) != NULL) { ! 470: sscanf(recbuf, "%s %s", nglist, fname); ! 471: ngcat(nglist); ! 472: if (ngmatch(lngrps, nglist)) { ! 473: fclose(fd); ! 474: if (fname[0] == '/') ! 475: strcpy(recbuf, fname); ! 476: else ! 477: sprintf(recbuf, "%s/%s", LIB, fname); ! 478: fd = fopen(recbuf, "r"); ! 479: if (fd == NULL) ! 480: return 0; ! 481: while ((c = getc(fd)) != EOF) ! 482: putc(c, stderr); ! 483: hascaught = 0; ! 484: oldsig = (char *) signal(SIGINT, catchintr); ! 485: fprintf(stderr, "Do you understand this? Hit <return> to proceed, <BREAK> to abort: "); ! 486: n = read(2, recbuf, 100); ! 487: c = recbuf[0]; ! 488: yes = (c=='y' || c=='Y' || c=='\n' || c=='\n' || c==0); ! 489: signal(SIGINT, oldsig); ! 490: if (hascaught || n <= 0 || !yes) ! 491: return -1; ! 492: } ! 493: } ! 494: return 0; ! 495: } ! 496: ! 497: /* ! 498: * Return a compact representation of the person who posted the given ! 499: * message. A sender or internet name will be used, otherwise ! 500: * the last part of the path is used preceeded by an optional ".." ! 501: */ ! 502: char * ! 503: tailpath(hp) ! 504: struct hbuf *hp; ! 505: { ! 506: char *p, *r; ! 507: static char resultbuf[BUFLEN]; ! 508: char pathbuf[PATHLEN]; ! 509: char *malloc(); ! 510: ! 511: /* ! 512: * This only happens for articles posted by old news software ! 513: * in non-internet format. ! 514: */ ! 515: resultbuf[0] = '\0'; ! 516: strcpy(pathbuf, hp->path); ! 517: p = index(pathbuf, ' '); ! 518: if (p) ! 519: *p = '\0'; /* Chop off trailing " (name)" */ ! 520: r = rindex(pathbuf, '!'); ! 521: if (r == 0) { ! 522: r = pathbuf; ! 523: } ! 524: else { ! 525: while (r > pathbuf && *--r != '!') ! 526: ; ! 527: if (r > pathbuf) { ! 528: r++; ! 529: strcpy(resultbuf, "..!"); ! 530: } ! 531: } ! 532: strcat(resultbuf, r); ! 533: return resultbuf; ! 534: } ! 535: ! 536: /* ! 537: * Generate the name of the person responsible for posting this article, ! 538: * in order to check that two articles were posted by the same person. ! 539: */ ! 540: char * ! 541: senderof(hp) ! 542: struct hbuf *hp; ! 543: { ! 544: char *q, *tp; ! 545: ! 546: if (hp->sender[0]) ! 547: tp = hp->sender; ! 548: else if (hp->from[0]) ! 549: tp = hp->from; ! 550: else ! 551: tp = tailpath(hp); ! 552: ! 553: /* Remove full name */ ! 554: q = index(tp, ' '); ! 555: if (q) ! 556: *q = '\0'; ! 557: ! 558: q = malloc(strlen(tp) + 1); ! 559: strcpy(q, tp); ! 560: return q; ! 561: } ! 562: ! 563: /* ! 564: * Returns 1 iff addr looks like a valid internet address ! 565: * (as opposed to a routing path). ! 566: * The current check insists on *@*.* as a format. ! 567: */ ! 568: goodinternet(addr) ! 569: register char *addr; ! 570: { ! 571: register char *at, *dot; ! 572: ! 573: at = index(addr, '@'); ! 574: if (at == NULL) ! 575: return 0; ! 576: dot = index(at, '.'); ! 577: if (dot == NULL) ! 578: return 0; ! 579: /* ! 580: * A more thorough check would insist on only alphanumerics ! 581: * and dots to the right of the @. ! 582: */ ! 583: return 1; ! 584: } ! 585: ! 586: rwaccess(fname) ! 587: char *fname; ! 588: { ! 589: int fd; ! 590: ! 591: fd = open(fname, 2); ! 592: if (fd < 0) ! 593: return 0; ! 594: close(fd); ! 595: return 1; ! 596: } ! 597: ! 598: exists(fname) ! 599: char *fname; ! 600: { ! 601: int fd; ! 602: ! 603: fd = open(fname, 0); ! 604: if (fd < 0) ! 605: return 0; ! 606: close(fd); ! 607: return 1; ! 608: } ! 609: ! 610: prefix(full, pref) ! 611: register char *full, *pref; ! 612: { ! 613: while (*full++ == *pref++) ! 614: ; ! 615: if (*--pref == 0) ! 616: return 1; ! 617: else ! 618: return 0; ! 619: } ! 620: ! 621: char * ! 622: dirname(ngname) ! 623: char *ngname; ! 624: { ! 625: static char rbuf[100]; ! 626: register char *p; ! 627: ! 628: sprintf(rbuf, "%s/%s", SPOOL, ngname); ! 629: #ifdef UPWARDCOMPAT ! 630: /* First check the old style name. */ ! 631: if (exists(rbuf)) ! 632: return rbuf; ! 633: #endif ! 634: ! 635: /* Use the new style name for all new stuff. */ ! 636: for (p=rbuf+strlen(SPOOL); *p; p++) ! 637: if (*p == '.') ! 638: *p = '/'; ! 639: return rbuf; ! 640: } ! 641: ! 642: #ifdef notdef ! 643: char * ! 644: dotname(ngname) ! 645: char *ngname; ! 646: { ! 647: static char rbuf[100]; ! 648: register char *p; ! 649: ! 650: #ifdef UPWARDCOMPAT ! 651: /* First check the old style name. */ ! 652: sprintf(rbuf, "%s/.%s", SPOOL, ngname); ! 653: if (exists(rbuf)) ! 654: return rbuf; ! 655: #endif ! 656: ! 657: /* Use the new style name for all new stuff. */ ! 658: sprintf(rbuf, "%s/%s", SPOOL, ngname); ! 659: for (p=rbuf+strlen(SPOOL); *p; p++) ! 660: if (*p == '.') ! 661: *p = '/'; ! 662: strcat(rbuf, "/bounds"); ! 663: return rbuf; ! 664: } ! 665: #endif ! 666: ! 667: /* ! 668: * Return TRUE iff ngname is a valid newsgroup name, active ! 669: * or inactive. ! 670: */ ! 671: validng(ngname) ! 672: char *ngname; ! 673: { ! 674: return exists(dirname(ngname)); ! 675: } ! 676: ! 677: /* ! 678: * arpadate is like ctime(3) except that the time is returned in ! 679: * an acceptable ARPANET time format instead of ctime format. ! 680: */ ! 681: char * ! 682: arpadate(longtime) ! 683: time_t *longtime; ! 684: { ! 685: register char *p, *q, *ud; ! 686: char *cp; ! 687: register int i; ! 688: static char b[40]; ! 689: struct timeb t; ! 690: extern struct tm *localtime(); ! 691: extern char *ctime(); ! 692: extern struct timeb *ftime(); ! 693: #ifdef USG ! 694: struct tm *bp; ! 695: extern char *tzname[]; ! 696: #else ! 697: extern char *timezone(); ! 698: #endif ! 699: ! 700: /* Get current time. This will be used resolve the timezone. */ ! 701: ud = ctime(longtime); ! 702: ftime(&t); ! 703: ! 704: /* Crack the UNIX date line in a singularly unoriginal way. */ ! 705: q = b; ! 706: ! 707: p = &ud[0]; /* Mon */ ! 708: *q++ = *p++; ! 709: *q++ = *p++; ! 710: *q++ = *p++; ! 711: *q++ = ','; *q++ = ' '; ! 712: ! 713: p = &ud[8]; /* 16 */ ! 714: if (*p == ' ') ! 715: p++; ! 716: else ! 717: *q++ = *p++; ! 718: *q++ = *p++; *q++ = '-'; ! 719: ! 720: p = &ud[4]; /* Sep */ ! 721: *q++ = *p++; *q++ = *p++; *q++ = *p++; *q++ = '-'; ! 722: ! 723: p = &ud[22]; /* 1979 */ ! 724: *q++ = *p++; *q++ = *p++; *q++ = ' '; ! 725: ! 726: p = &ud[11]; /* 01:03:52 */ ! 727: for (i = 8; i > 0; i--) ! 728: *q++ = *p++; ! 729: ! 730: /* -PST or -PDT */ ! 731: #ifdef USG ! 732: bp = localtime(&t.time); ! 733: p = tzname[bp->tm_isdst]; ! 734: #else ! 735: p = timezone(t.timezone, localtime(&t.time)->tm_isdst); ! 736: #endif ! 737: if (p[3] != '\0') { ! 738: /* hours from GMT */ ! 739: p += 3; ! 740: *q++ = *p++; ! 741: if (p[1] == ':') ! 742: *q++ = '0'; ! 743: else ! 744: *q++ = *p++; ! 745: *q++ = *p++; p++; *q++ = *p++; *q++ = *p++; ! 746: } else { ! 747: *q++ = ' '; *q++ = *p++; *q++ = *p++; *q++ = *p++; ! 748: } ! 749: *q = '\0'; ! 750: ! 751: return (b); ! 752: } ! 753: ! 754: char * ! 755: replyname(hptr) ! 756: struct hbuf *hptr; ! 757: { ! 758: register char *ptr; ! 759: static char tbuf[PATHLEN]; ! 760: ! 761: ptr = hptr->path; ! 762: if (prefix(ptr, FULLSYSNAME)) ! 763: ptr = index(ptr, '!') + 1; ! 764: #ifdef INTERNET ! 765: if (hptr->from[0]) ! 766: ptr = hptr->from; ! 767: if (hptr->replyto[0]) ! 768: ptr = hptr->replyto; ! 769: #endif ! 770: strcpy(tbuf, ptr); ! 771: ptr = index(tbuf, '('); ! 772: if (ptr) { ! 773: while (ptr[-1] == ' ') ! 774: ptr--; ! 775: *ptr = 0; ! 776: } ! 777: #ifndef INTERNET ! 778: /* ! 779: * Play games stripping off multiple berknet ! 780: * addresses (a!b!c:d:e => a!b!d:e) here. ! 781: */ ! 782: for (ptr=tbuf; *ptr; ptr++) ! 783: if (index(NETCHRS, *ptr) && *ptr == ':' && index(ptr+1, ':')) ! 784: strcpy(ptr, index(ptr+1, ':')); ! 785: #endif ! 786: return tbuf; ! 787: } ! 788: ! 789: /* ! 790: * Given an article ID, find the line in the history file that mentions it. ! 791: * Return the text of the line, or NULL if not found. A pointer to a ! 792: * static area is returned. ! 793: */ ! 794: char * ! 795: findhist(artid) ! 796: char *artid; ! 797: { ! 798: static char lbuf[256]; ! 799: char oidbuf[BUFSIZ]; ! 800: FILE *hfp; ! 801: char *p; ! 802: ! 803: /* Try to understand old artid's as well. Assume .UUCP domain. */ ! 804: if (artid[0] != '<') { ! 805: p = index(artid, '.'); ! 806: if (p) ! 807: *p++ = '\0'; ! 808: sprintf(oidbuf, "<%s@%s.UUCP>", p, artid); ! 809: if (p) ! 810: *--p = '.'; ! 811: } else ! 812: strcpy(oidbuf, artid); ! 813: hfp = xfopen(ARTFILE, "r"); ! 814: while (fgets(lbuf, BUFLEN, hfp) != NULL) { ! 815: p = index(lbuf, '\t'); ! 816: if (p == NULL) ! 817: p = index(lbuf, '\n'); ! 818: *p = 0; ! 819: if (strcmp(lbuf, artid) == 0 || strcmp(lbuf, oidbuf) == 0) { ! 820: fclose(hfp); ! 821: *p = '\t'; ! 822: *(lbuf + strlen(lbuf) - 1) = 0; /* zap the \n */ ! 823: return(lbuf); ! 824: } ! 825: } ! 826: fclose(hfp); ! 827: return(NULL); ! 828: } ! 829: ! 830: /* ! 831: * Hunt up the article "artid", and return the newsgroup/artnum ! 832: * where it can be found. ! 833: */ ! 834: char * ! 835: findfname(artid) ! 836: char *artid; ! 837: { ! 838: char *line, *p, *q; ! 839: char *findhist(); ! 840: FILE *rv; ! 841: static char fname[256]; ! 842: ! 843: line = findhist(artid); ! 844: if (line) { ! 845: /* Look for it stored as an article, where it should be */ ! 846: p = index(line, '\t'); ! 847: p = index(p+1, '\t'); ! 848: p++; ! 849: if (*p) { ! 850: q = index(p, ' '); ! 851: if (q) ! 852: *q = 0; ! 853: strcpy(fname, p); ! 854: return fname; ! 855: } ! 856: } ! 857: ! 858: return NULL; ! 859: } ! 860: ! 861: /* ! 862: * Hunt up the article "artid", fopen it for read, and return a ! 863: * file descriptor to it. We look everywhere we can think of. ! 864: */ ! 865: FILE * ! 866: hfopen(artid) ! 867: char *artid; ! 868: { ! 869: char *p; ! 870: char *findhist(); ! 871: FILE *rv = NULL; ! 872: char fname[256]; ! 873: ! 874: p = findfname(artid); ! 875: if (p) { ! 876: strcpy(fname, dirname(p)); ! 877: rv = fopen(fname, "r"); /* NOT xfopen! */ ! 878: if (rv != NULL) ! 879: return rv; ! 880: } ! 881: ! 882: xerror("Cannot hfopen article %s", artid); ! 883: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.