|
|
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: * expire - expire daemon runs around and nails all articles that ! 16: * have expired. ! 17: */ ! 18: ! 19: #ifdef SCCSID ! 20: static char *SccsId = "@(#)expire.c 2.43 3/19/86"; ! 21: #endif /* SCCSID */ ! 22: ! 23: #include "params.h" ! 24: #include <errno.h> ! 25: #if defined(BSD4_2) || defined(BSD4_1C) ! 26: # include <sys/dir.h> ! 27: #else ! 28: # include "ndir.h" ! 29: #endif ! 30: ! 31: char *Progname = "expire"; /* used by xerror to identify failing program */ ! 32: ! 33: /* Number of array entries to allocate at a time. */ ! 34: #define SPACE_INCREMENT 1000 ! 35: ! 36: struct expdata { ! 37: char *e_name; ! 38: long e_min, e_max; ! 39: time_t e_droptime, e_expiretime; ! 40: char e_ignorexp; ! 41: char e_doarchive; ! 42: char e_doexpire; ! 43: }; ! 44: ! 45: extern int errno; ! 46: char NARTFILE[BUFLEN], OARTFILE[BUFLEN]; ! 47: char PAGFILE[BUFLEN], DIRFILE[BUFLEN]; ! 48: char NACTIVE[BUFLEN], OACTIVE[BUFLEN]; ! 49: char recdate[BUFLEN]; ! 50: long rectime, exptime; ! 51: extern char *OLDNEWS; ! 52: int verbose = 0; ! 53: int ignorexp = 0; ! 54: int doarchive = 0; ! 55: int nohistory = 0; ! 56: int dorebuild = 0; ! 57: int usepost = 0; ! 58: int frflag = 0; ! 59: int updateactive = 0; ! 60: char baduser[BUFLEN]; ! 61: extern char filename[], nbuf[]; ! 62: ! 63: /* ! 64: * This code uses realloc to get more of the multhist array. ! 65: */ ! 66: struct multhist { ! 67: char *mh_ident; ! 68: char *mh_file; ! 69: } *multhist; ! 70: unsigned int mh_size; ! 71: char *calloc(); ! 72: char *realloc(); ! 73: ! 74: typedef struct { ! 75: char *dptr; ! 76: int dsize; ! 77: } datum; ! 78: ! 79: long expincr; ! 80: long dropincr; ! 81: long atol(); ! 82: time_t cgtdate(), time(); ! 83: FILE *popen(); ! 84: struct passwd *pw; ! 85: struct group *gp; ! 86: char arpat[LBUFLEN]; ! 87: int arpatlen = 0; ! 88: char ngpat[LBUFLEN]; ! 89: int ngpatlen = 0; ! 90: char afline[BUFLEN]; ! 91: char grpsleft[BUFLEN]; ! 92: struct hbuf h; ! 93: ! 94: main(argc, argv) ! 95: int argc; ! 96: char **argv; ! 97: { ! 98: register char *p1, *p2, *p3; ! 99: register time_t now, newtime; ! 100: register FILE *fp = NULL; ! 101: FILE *ohfd, *nhfd; ! 102: DIR *ngdirp = NULL; ! 103: static struct direct *ngdir; ! 104: char fn[BUFLEN]; ! 105: int i; ! 106: #ifndef DBM ! 107: char *ptr, chr; ! 108: FILE *subfd[10]; ! 109: char *histfile(); ! 110: #endif /* !DBM */ ! 111: ! 112: pathinit(); ! 113: (void) umask(N_UMASK); ! 114: ! 115: /* ! 116: * Try to run as NEWSUSR/NEWSGRP ! 117: */ ! 118: if ((pw = getpwnam(NEWSUSR)) == NULL) ! 119: xerror("Cannot get NEWSUSR pw entry"); ! 120: ! 121: uid = pw->pw_uid; ! 122: if ((gp = getgrnam(NEWSGRP)) == NULL) ! 123: xerror("Cannot get NEWSGRP gr entry"); ! 124: gid = gp->gr_gid; ! 125: (void) setgid(gid); ! 126: (void) setuid(uid); ! 127: ! 128: expincr = DFLTEXP; ! 129: dropincr = HISTEXP; ! 130: ngpat[0] = ','; ! 131: arpat[0] = ','; ! 132: while (argc > 1) { ! 133: switch (argv[1][1]) { ! 134: case 'v': ! 135: if (isdigit(argv[1][2])) ! 136: verbose = argv[1][2] - '0'; ! 137: else if (argc > 2 && argv[2][0] != '-') { ! 138: ! 139: argv++; ! 140: argc--; ! 141: verbose = atoi(argv[1]); ! 142: } else ! 143: verbose = 1; ! 144: if (verbose < 3) ! 145: setbuf(stdout, (char *)NULL); ! 146: break; ! 147: case 'e': /* Use this as default expiration time */ ! 148: if (argc > 2 && argv[2][0] != '-') { ! 149: argv++; ! 150: argc--; ! 151: expincr = atol(argv[1]) * DAYS; ! 152: } else if (isdigit(argv[1][2])) ! 153: expincr = atol(&argv[1][2]) * DAYS; ! 154: break; ! 155: case 'E': /* Use this as default forget time */ ! 156: if (argc > 2 && argv[2][0] != '-') { ! 157: argv++; ! 158: argc--; ! 159: dropincr = atol(argv[1]) * DAYS; ! 160: } else if (isdigit(argv[1][2])) ! 161: dropincr = atol(&argv[1][2]) * DAYS; ! 162: if (dropincr < expincr) { ! 163: dropincr = HISTEXP; ! 164: fprintf(stderr, "History expiration time < article expiration time. Default used.\n"); ! 165: } ! 166: break; ! 167: case 'I': /* Ignore any existing expiration date */ ! 168: ignorexp = 2; ! 169: break; ! 170: case 'i': /* Ignore any existing expiration date */ ! 171: ignorexp = 1; ! 172: break; ! 173: case 'n': ! 174: if (argc > 2) { ! 175: argv++; ! 176: argc--; ! 177: while (argc > 1 && argv[1][0] != '-') { ! 178: int argvlen; ! 179: argvlen = strlen(argv[1]); ! 180: if (ngpatlen + argvlen + 2 > sizeof (ngpat)) { ! 181: xerror("Too many groups specified for -n\n"); ! 182: } ! 183: if (ngpat[ngpatlen] == '\0') { ! 184: ngpat[ngpatlen++] = ','; ! 185: ngpat[ngpatlen] = '\0'; ! 186: } ! 187: strcpy(&ngpat[ngpatlen], argv[1]); ! 188: ngpatlen += argvlen; ! 189: argv++; ! 190: argc--; ! 191: } ! 192: argv--; ! 193: argc++; ! 194: } ! 195: break; ! 196: case 'a': /* archive expired articles */ ! 197: if (access(OLDNEWS,0) < 0){ ! 198: perror(OLDNEWS); ! 199: xerror("No archiving possible\n"); ! 200: } ! 201: doarchive++; ! 202: if (argc > 2) { ! 203: argv++; ! 204: argc--; ! 205: while (argc > 1 && argv[1][0] != '-') { ! 206: int argvlen; ! 207: argvlen = strlen(argv[1]); ! 208: if (arpatlen + argvlen + 2 > sizeof (arpat)) { ! 209: xerror("Too many groups specified for -a\n"); ! 210: } ! 211: if (arpat[arpatlen] == '\0') { ! 212: arpat[arpatlen++] = ','; ! 213: arpat[arpatlen] = '\0'; ! 214: } ! 215: strcpy(&arpat[arpatlen], argv[1]); ! 216: arpatlen += argvlen; ! 217: argv++; ! 218: argc--; ! 219: } ! 220: argv--; ! 221: argc++; ! 222: } ! 223: break; ! 224: case 'h': /* ignore history */ ! 225: nohistory++; ! 226: break; ! 227: case 'r': /* rebuild history file */ ! 228: dorebuild++; ! 229: nohistory++; ! 230: break; ! 231: case 'p': ! 232: usepost++; ! 233: break; ! 234: case 'f': ! 235: frflag++; ! 236: if (argc > 2) { ! 237: strcpy(baduser, argv[2]); ! 238: argv++; ! 239: argc--; ! 240: } ! 241: break; ! 242: case 'u': ! 243: updateactive++; ! 244: break; ! 245: default: ! 246: printf("Usage: expire [ -v [level] ] [-e days ] [-i] [-a] [-r] [-h] [-p] [-u] [-f username] [-n newsgroups]\n"); ! 247: xxit(1); ! 248: } ! 249: argc--; ! 250: argv++; ! 251: } ! 252: if (ngpat[0] == ',') ! 253: (void) strcpy(ngpat, "all,"); ! 254: if (arpat[0] == ',') ! 255: (void) strcpy(arpat, "all,"); ! 256: now = time((time_t)0); ! 257: if (chdir(SPOOL)) ! 258: xerror("Cannot chdir %s", SPOOL); ! 259: ! 260: if (verbose) { ! 261: printf("expire: nohistory %d, rebuild %d, doarchive %d\n", ! 262: nohistory, dorebuild, doarchive); ! 263: printf("newsgroups: %s\n",ngpat); ! 264: if (doarchive) ! 265: printf("archiving: %s\n",arpat); ! 266: } ! 267: ! 268: (void) sprintf(OARTFILE, "%s/%s", LIB, "ohistory"); ! 269: (void) sprintf(NARTFILE, "%s/%s", LIB, "nhistory"); ! 270: ! 271: (void) sprintf(OACTIVE, "%s/%s", LIB, "oactive"); ! 272: (void) sprintf(NACTIVE, "%s/%s", LIB, "nactive"); ! 273: ! 274: if (updateactive) ! 275: goto doupdateactive; ! 276: ! 277: #ifdef DBM ! 278: if (!dorebuild) { ! 279: (void) sprintf(PAGFILE, "%s/%s", LIB, "nhistory.pag"); ! 280: (void) sprintf(DIRFILE, "%s/%s", LIB, "nhistory.dir"); ! 281: (void) close(creat(PAGFILE, 0666)); ! 282: (void) close(creat(DIRFILE, 0666)); ! 283: initdbm(NARTFILE); ! 284: } ! 285: #endif ! 286: ! 287: if (nohistory) { ! 288: ohfd = xfopen(ACTIVE, "r"); ! 289: if (dorebuild) { ! 290: /* Allocate initial space for multiple newsgroup (for an ! 291: article) array */ ! 292: multhist = (struct multhist *)calloc (SPACE_INCREMENT, ! 293: sizeof (struct multhist)); ! 294: mh_size = SPACE_INCREMENT; ! 295: ! 296: (void) sprintf(afline, "exec sort -t\t +1.6 -2 +1 >%s", NARTFILE); ! 297: if ((nhfd = popen(afline, "w")) == NULL) ! 298: xerror("Cannot exec %s", afline); ! 299: } else ! 300: nhfd = xfopen("/dev/null", "w"); ! 301: } else { ! 302: ohfd = xfopen(ARTFILE, "r"); ! 303: nhfd = xfopen(NARTFILE, "w"); ! 304: } ! 305: ! 306: for(i=0;i<NUNREC;i++) ! 307: h.unrec[i] = NULL; ! 308: ! 309: while (TRUE) { ! 310: fp = NULL; ! 311: if (nohistory) { ! 312: do { ! 313: if (ngdir == NULL) { ! 314: if ( ngdirp != NULL ) ! 315: closedir(ngdirp); ! 316: if (fgets(afline, BUFLEN, ohfd) == NULL) ! 317: goto out; ! 318: (void) strcpy(nbuf, afline); ! 319: p1 = index(nbuf, ' '); ! 320: if (p1 == NULL) ! 321: p1 = index(nbuf, '\n'); ! 322: if (p1 != NULL) ! 323: *p1 = NULL; ! 324: if (!ngmatch(nbuf, ngpat)) ! 325: continue; ! 326: ! 327: /* Change a group name from ! 328: a.b.c to a/b/c */ ! 329: for (p1=nbuf; *p1; p1++) ! 330: if (*p1 == '.') ! 331: *p1 = '/'; ! 332: ! 333: if ((ngdirp = opendir(nbuf)) == NULL) ! 334: continue; ! 335: ! 336: } ! 337: ngdir = readdir(ngdirp); ! 338: /* Continue looking if not an article. */ ! 339: } while (ngdir == NULL || !islegal(fn,nbuf,ngdir->d_name)); ! 340: ! 341: p2 = fn; ! 342: if (verbose > 2) ! 343: printf("article: %s\n", fn); ! 344: strcpy(filename, dirname(fn)); ! 345: fp = access(filename, 04) ? NULL : fopen(filename, "r"); ! 346: } else { ! 347: char dc; ! 348: if (fgets(afline, BUFLEN, ohfd) == NULL) ! 349: break; ! 350: if (verbose > 2) ! 351: printf("article: %s", afline); ! 352: p1 = index(afline, '\t'); ! 353: if (!p1) ! 354: continue; ! 355: *p1 = '\0'; ! 356: (void) strcpy(h.ident, afline); ! 357: *p1 = '\t'; ! 358: p2 = index(p1 + 1, '\t'); ! 359: if (!p2) ! 360: continue; ! 361: *p2 = '\0'; ! 362: (void) strcpy(recdate, p1+1); ! 363: rectime = cgtdate(recdate); ! 364: *p2++ = '\t'; ! 365: (void) strcpy(nbuf, p2); ! 366: p3 = index(nbuf, '/'); ! 367: if (p3) { ! 368: register char *p4; ! 369: ! 370: p4 = index(p3, '\n'); ! 371: if (p4) { ! 372: while (p4[-1] == ' ') ! 373: p4--; ! 374: *p4 = '\0'; ! 375: } ! 376: ! 377: /* ! 378: * convert list of newsgroups from ! 379: * ng1/num ng2/num ... ! 380: * to ! 381: * ng1,ng2,... ! 382: */ ! 383: p4 = p3; ! 384: do { ! 385: *p3++ = NGDELIM; ! 386: while (*p4 != '\0' && *p4 != ' ') ! 387: p4++; ! 388: if (*p4++ == '\0') { ! 389: *--p3 = '\0'; ! 390: break; ! 391: } ! 392: while (*p3 = *p4++) { ! 393: if (*p3 == '/') ! 394: break; ! 395: else ! 396: p3++; ! 397: } ! 398: } while (*p3); ! 399: } else { ! 400: /* ! 401: * Nothing after the 2nd tab. This happens ! 402: * when there's no message left in the spool ! 403: * directory, only the memory of it in the ! 404: * history file. Use date in the history file ! 405: * to decide if we should keep this article. ! 406: */ ! 407: grpsleft[0] = '\0'; ! 408: goto checkdate; ! 409: } ! 410: if (!ngmatch(nbuf, ngpat) || ! 411: ((rectime+expincr > now) && !dorebuild && !frflag ! 412: && !usepost && recdate[0] != ' ')) ! 413: goto keephist; ! 414: if (recdate[0] != ' ') { ! 415: grpsleft[0] = '\0'; ! 416: goto nailit; /* just expire it */ ! 417: } ! 418: ! 419: /* ! 420: * Look for the file--possibly several times, ! 421: * if it was posted to several news groups. ! 422: */ ! 423: dc = ' '; ! 424: p3 = p2; ! 425: while (dc != '\n') { ! 426: p1 = index(p3, ' '); ! 427: if (p1) { ! 428: dc = ' '; ! 429: *p1 = '\0'; ! 430: } else { ! 431: p1 = index(p3, '\n'); ! 432: if (p1 && p1 > p3) { ! 433: dc = '\n'; ! 434: *p1 = '\0'; ! 435: } else { ! 436: fp = NULL; ! 437: break; ! 438: } ! 439: } ! 440: strcpy(filename, dirname(p3)); ! 441: if (access(filename, 4) == 0 && ! 442: ((fp=fopen(filename, "r")) != NULL)) ! 443: break; ! 444: p3 = p1 + 1; ! 445: } ! 446: if (p1) ! 447: *p1 = dc; ! 448: } ! 449: ! 450: if (fp == NULL) { ! 451: /* ! 452: * this probably means that the article has been ! 453: * cancelled. Lets assume that, and make an ! 454: * entry in the history file to that effect. ! 455: */ ! 456: if (verbose) ! 457: perror(filename); ! 458: strcpy(p2, "cancelled\n"); ! 459: grpsleft[0] = '\0'; ! 460: goto checkdate; ! 461: } ! 462: for(i=0; i<NUNREC; i++) ! 463: if (h.unrec[i] != NULL) ! 464: free(h.unrec[i]); ! 465: else ! 466: break; ! 467: if (!hread(&h, fp, TRUE)) { ! 468: printf("Garbled article %s.\n", filename); ! 469: (void) fclose(fp); ! 470: /* ! 471: * Usually means disk ran out of space. ! 472: * Drop this article from our history file ! 473: * completely, so we have a chance of picking ! 474: * it up again from another feed .. ! 475: */ ! 476: goto nailit; ! 477: } ! 478: if (dorebuild) { ! 479: register char *cp, *lastslash; ! 480: register struct multhist *mhp; ! 481: ! 482: if (recdate[0] == '\0') { ! 483: struct stat statb; ! 484: if (fstat(fileno(fp), &statb) < 0) ! 485: rectime = cgtdate(h.subdate); ! 486: else ! 487: rectime = statb.st_mtime; ! 488: } else ! 489: rectime = cgtdate(recdate); ! 490: /* ! 491: * Format of filename until now was /SPOOL/a/b/c/4 ! 492: * and this code changes it to a.b.c/4 (the correct ! 493: * kind of entry in the history file.) ! 494: * ! 495: * This can't be a strcpy because the addresses overlap ! 496: * and some machines can't handle that. ! 497: */ ! 498: p1 = filename; ! 499: cp = p1 + strlen(SPOOL); ! 500: while (*++cp) { ! 501: if (*cp == '/') { ! 502: lastslash = p1; ! 503: *p1++ = '.'; ! 504: } else ! 505: *p1++ = *cp; ! 506: } ! 507: *p1 = '\0'; ! 508: *lastslash = '/'; ! 509: ! 510: if ((cp = index(h.nbuf, NGDELIM)) == NULL) { ! 511: struct tm *tm; ! 512: saveit: ! 513: tm = localtime(&rectime); ! 514: #ifdef USG ! 515: fprintf(nhfd,"%s\t%s%2.2d/%2.2d/%d %2.2d:%2.2d\t%s\n", ! 516: #else /* !USG */ ! 517: fprintf(nhfd,"%s\t%s%02d/%02d/%d %02d:%02d\t%s\n", ! 518: #endif /* !USG */ ! 519: h.ident, h.expdate[0] ? " " : "", ! 520: tm->tm_mon+1, tm->tm_mday, tm->tm_year, ! 521: tm->tm_hour, tm->tm_min, filename); ! 522: (void) fclose(fp); ! 523: continue; ! 524: } ! 525: for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) { ! 526: if (mhp->mh_file == NULL) ! 527: continue; ! 528: if (strcmp(mhp->mh_ident, h.ident)) ! 529: continue; ! 530: (void) strcat(filename, " "); ! 531: (void) strcat(filename, mhp->mh_file); ! 532: free(mhp->mh_file); ! 533: mhp->mh_file = NULL; ! 534: /* ! 535: * if we have all the links, write to hist now ! 536: */ ! 537: if (chrcnt(filename, ' ') == chrcnt(cp,NGDELIM)) ! 538: goto saveit; ! 539: break; ! 540: } ! 541: ! 542: /* ! 543: * Here is where we realloc the multhist space rather ! 544: * than the old way of static allocation. It's ! 545: * really trivial. We just clear out the space ! 546: * in case it was reused. The old static array was ! 547: * guaranteed to be cleared since it was cleared when ! 548: * the process started. ! 549: */ ! 550: if (mhp >= multhist + mh_size) { ! 551: multhist = (struct multhist *) ! 552: realloc ((char *)multhist, ! 553: sizeof (struct multhist) * ! 554: (SPACE_INCREMENT + mh_size)); ! 555: if (multhist == NULL) ! 556: xerror("Too many articles with multiple newsgroups"); ! 557: for (mhp = multhist + mh_size; ! 558: mhp < multhist+mh_size+SPACE_INCREMENT; ! 559: mhp++) { ! 560: mhp->mh_ident = NULL; ! 561: mhp->mh_file = NULL; ! 562: } ! 563: mhp = multhist + mh_size; ! 564: mh_size += SPACE_INCREMENT; ! 565: } ! 566: ! 567: if (mhp->mh_ident == NULL) { ! 568: mhp->mh_ident = malloc(strlen(h.ident)+1); ! 569: (void) strcpy(mhp->mh_ident, h.ident); ! 570: } ! 571: cp = malloc(strlen(filename) + 1); ! 572: if (cp == NULL) ! 573: xerror("Out of memory"); ! 574: (void) strcpy(cp, filename); ! 575: mhp->mh_file = cp; ! 576: (void) fclose(fp); ! 577: continue; ! 578: } ! 579: ! 580: (void) fclose(fp); ! 581: rectime = cgtdate(recdate); ! 582: ! 583: if (h.expdate[0]) ! 584: exptime = cgtdate(h.expdate); ! 585: newtime = (usepost ? cgtdate(h.subdate) : rectime) + expincr; ! 586: if (!h.expdate[0] || ignorexp == 2 || ! 587: (ignorexp == 1 && newtime < exptime)) ! 588: exptime = newtime; ! 589: if (frflag ? strcmp(baduser,h.from)==0 : now >= exptime) { ! 590: nailit: ! 591: #ifdef DEBUG ! 592: printf("cancel %s\n", filename); ! 593: #else /* !DEBUG */ ! 594: if (verbose) ! 595: printf("cancel %s\n", h.ident); ! 596: ulall(p2, &h); ! 597: (void) sprintf(p2, "%s\n", grpsleft); ! 598: if (verbose > 2 && grpsleft[0]) ! 599: printf("Some good in %s\n", h.ident); ! 600: #endif /* !DEBUG */ ! 601: } else { ! 602: if (verbose > 2) ! 603: printf("Good article %s\n", h.ident); ! 604: grpsleft[0] = '!'; ! 605: } ! 606: ! 607: checkdate: ! 608: if (grpsleft[0] == '\0' && now >= rectime + dropincr) { ! 609: if (verbose > 3) ! 610: printf("Drop history of %s - %s\n", ! 611: h.ident, recdate); ! 612: } else { ! 613: long hpos; ! 614: keephist: ! 615: hpos = ftell(nhfd); ! 616: ! 617: if (verbose > 3) ! 618: printf("Retain history of %s - %s\n", ! 619: h.ident, recdate); ! 620: if (fputs(afline, nhfd) == EOF) ! 621: xerror("history write failed"); ! 622: #ifdef DBM ! 623: if (!dorebuild) ! 624: remember(h.ident, hpos); ! 625: #endif /* DBM */ ! 626: } ! 627: } ! 628: out: ! 629: if (dorebuild) { ! 630: register struct multhist *mhp; ! 631: struct tm *tm; ! 632: for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) ! 633: if (mhp->mh_file != NULL) { ! 634: if (verbose) ! 635: printf("Article: %s [%s] Cannot find all links\n", mhp->mh_ident, mhp->mh_file); ! 636: (void) sprintf(filename,"%s/%s",SPOOL,mhp->mh_file); ! 637: for (p1 = filename; *p1 != ' ' && *p1 != '\0'; p1++) ! 638: if (*p1 == '.') ! 639: *p1 = '/'; ! 640: *p1 = '\0'; ! 641: if ((fp = fopen(filename, "r")) == NULL) { ! 642: if (verbose) ! 643: printf("Can't open %s.\n", filename); ! 644: continue; ! 645: } ! 646: if (!hread(&h, fp, TRUE)) { ! 647: printf("Garbled article %s.\n", filename); ! 648: (void) fclose(fp); ! 649: continue; ! 650: } else { ! 651: struct stat statb; ! 652: if (fstat(fileno(fp), &statb) < 0) ! 653: rectime = cgtdate(h.subdate); ! 654: else ! 655: rectime = statb.st_mtime; ! 656: } ! 657: tm = localtime(&rectime); ! 658: if ( ! 659: #ifdef USG ! 660: fprintf(nhfd,"%s\t%s%2.2d/%2.2d/%d %2.2d:%2.2d\t%s\n", ! 661: #else /* !USG */ ! 662: fprintf(nhfd,"%s\t%s%02d/%02d/%d %02d:%02d\t%s\n", ! 663: #endif /* !USG */ ! 664: h.ident, h.expdate[0] ? " " : "", ! 665: tm->tm_mon+1, tm->tm_mday, tm->tm_year, ! 666: tm->tm_hour, tm->tm_min, mhp->mh_file) ! 667: == EOF ) ! 668: xerror("History write failed"); ! 669: (void) fclose(fp); ! 670: continue; ! 671: } ! 672: (void) pclose(nhfd); ! 673: free ((char *)multhist); ! 674: } else ! 675: fclose(nhfd); ! 676: ! 677: if (dorebuild || !nohistory) { ! 678: (void) rename(ARTFILE, OARTFILE); ! 679: (void) rename(NARTFILE, ARTFILE); ! 680: #ifdef DBM ! 681: if (dorebuild) ! 682: rebuilddbm( ); ! 683: else { ! 684: char tempname[BUFLEN]; ! 685: (void) sprintf(tempname,"%s.pag", ARTFILE); ! 686: (void) strcat(OARTFILE, ".pag"); ! 687: (void) strcat(NARTFILE, ".pag"); ! 688: (void) rename(tempname, OARTFILE); ! 689: (void) rename(NARTFILE, tempname); ! 690: (void) sprintf(tempname,"%s.dir", ARTFILE); ! 691: (void) strcpy(rindex(OARTFILE, '.'), ".dir"); ! 692: (void) strcpy(rindex(NARTFILE, '.'), ".dir"); ! 693: (void) rename(tempname, OARTFILE); ! 694: (void) rename(NARTFILE, tempname); ! 695: } ! 696: #endif ! 697: } ! 698: #ifndef DBM ! 699: /* rebuild history subfiles */ ! 700: for (i = 0; i < 10; i++) { ! 701: (void) sprintf(fn, "%s.d/%c", ARTFILE, i + '0'); ! 702: close(creat(fn, 0644)); ! 703: subfd[i] = xfopen(fn, "w+"); ! 704: } ! 705: ohfd = xfopen(ARTFILE, "r"); ! 706: while (fgets(fn, BUFLEN, ohfd) != NULL) { ! 707: ptr = histfile(fn); ! 708: chr = *(ptr + strlen(ptr) - 1); ! 709: if (isdigit(chr)) ! 710: i = chr - '0'; ! 711: else ! 712: i = 0; ! 713: fputs(fn, subfd[i]); ! 714: } ! 715: (void) fclose(ohfd); ! 716: for (i = 0; i < 10; i++) ! 717: fclose(subfd[i]); ! 718: #endif /* !DBM */ ! 719: ! 720: doupdateactive: ! 721: ohfd = xfopen(ACTIVE, "r"); ! 722: nhfd = xfopen(NACTIVE, "w"); ! 723: do { ! 724: long n; ! 725: long maxart, minart; ! 726: char cansub; ! 727: int gdsize, hassubs; ! 728: struct stat stbuf; ! 729: ! 730: if (fgets(afline, BUFLEN, ohfd) == NULL) ! 731: continue; ! 732: if (sscanf(afline,"%s %ld %ld %c",nbuf,&maxart, &minart, ! 733: &cansub) < 4) ! 734: xerror("Active file corrupt"); ! 735: if (!ngmatch(nbuf, ngpat)) { ! 736: if (fputs(afline, nhfd) == EOF) ! 737: xerror("active file write failed"); ! 738: continue; ! 739: } ! 740: minart = 99999L; ! 741: /* Change a group name from a.b.c to a/b/c */ ! 742: for (p1=nbuf; *p1; p1++) ! 743: if (*p1 == '.') ! 744: *p1 = '/'; ! 745: ! 746: hassubs = stat(nbuf, &stbuf) != 0 || stbuf.st_nlink != 2; ! 747: gdsize = strlen(nbuf); ! 748: if ((ngdirp = opendir(nbuf)) != NULL) { ! 749: while (ngdir = readdir(ngdirp)) { ! 750: nbuf[gdsize] = '/'; ! 751: (void) strcpy(&nbuf[gdsize+1], ngdir->d_name); ! 752: /* We have to do a stat because of micro.6809 */ ! 753: if (hassubs && (stat(nbuf, &stbuf) < 0 || ! 754: !(stbuf.st_mode&S_IFREG)) ) ! 755: continue; ! 756: n = atol(ngdir->d_name); ! 757: if (n > 0 && n < minart) ! 758: minart = n; ! 759: if (n > 0 && n > maxart) ! 760: maxart = n; ! 761: } ! 762: closedir(ngdirp); ! 763: } ! 764: afline[gdsize] = '\0'; ! 765: if (minart > maxart) ! 766: minart = maxart; ! 767: if (fprintf(nhfd,"%s %05ld %05ld %c\n", afline, maxart, ! 768: minart, cansub) == EOF) ! 769: xerror("Active file write failed"); ! 770: } while (!feof(ohfd)); ! 771: (void) fclose(nhfd); ! 772: (void) fclose(ohfd); ! 773: ! 774: (void) rename(ACTIVE, OACTIVE); ! 775: (void) rename(NACTIVE, ACTIVE); ! 776: ! 777: xxit(0); ! 778: } ! 779: ! 780: /* Unlink (using unwound tail recursion) all the articles in 'artlist'. */ ! 781: ulall(artlist, hp) ! 782: char *artlist; ! 783: struct hbuf *hp; ! 784: { ! 785: register char *p, *q; ! 786: int last = 0; ! 787: char newname[BUFLEN]; ! 788: time_t timep[2]; ! 789: char *fn; ! 790: ! 791: grpsleft[0] = '\0'; ! 792: do { ! 793: if (verbose > 2) ! 794: printf("ulall '%s', '%s'\n", artlist, hp->subdate); ! 795: if (nohistory) { ! 796: last = 1; ! 797: } else { ! 798: while (*artlist == ' ' || *artlist == '\n' || *artlist == ',') ! 799: artlist++; ! 800: if (*artlist == '\0') ! 801: return; ! 802: p = index(artlist, ' '); ! 803: if (p == NULL) { ! 804: last = 1; ! 805: p = index(artlist, '\n'); ! 806: } ! 807: if (p == NULL) { ! 808: last = 1; ! 809: fn = dirname(artlist); ! 810: if (unlink(fn) < 0 && errno != ENOENT) ! 811: perror(fn); ! 812: return; ! 813: } ! 814: if (p) ! 815: *p = 0; ! 816: } ! 817: strcpy(newname, artlist); ! 818: q = index(newname,'/'); ! 819: if (q) { ! 820: *q++ = NGDELIM; ! 821: *q = '\0'; ! 822: } else { ! 823: q = index(newname, '\0'); ! 824: if (q == artlist) /* null -> the end */ ! 825: return; ! 826: /* should be impossible to get here */ ! 827: } ! 828: fn = dirname(artlist); ! 829: if (ngmatch(newname, ngpat)) { ! 830: if (doarchive){ ! 831: if (ngmatch(newname, arpat)) { ! 832: q = fn + strlen(SPOOL) + 1; ! 833: (void) sprintf(newname, "%s/%s", OLDNEWS, q); ! 834: if (verbose) ! 835: printf("link %s to %s\n", fn, newname); ! 836: if (link(fn, newname) == -1) { ! 837: if (mkparents(newname) == 0) ! 838: if (link(fn, newname) == -1) ! 839: fcopy(fn, newname); ! 840: } ! 841: timep[0] = timep[1] = cgtdate(hp->subdate); ! 842: (void) utime(newname, timep); ! 843: } ! 844: } ! 845: if (verbose) ! 846: printf("unlink %s\n", fn); ! 847: if (unlink(fn) < 0 && errno != ENOENT) ! 848: perror(fn); ! 849: } else { ! 850: if (verbose > 3) ! 851: printf("retain %s (%s)\n", hp->ident, fn); ! 852: strcat(grpsleft, artlist); ! 853: strcat(grpsleft, " "); ! 854: } ! 855: artlist = p + 1; ! 856: } while (!last); ! 857: } ! 858: ! 859: fcopy(fn, newname) ! 860: char *fn, *newname; ! 861: { ! 862: int f1, f2; ! 863: int r; ! 864: char buf[BUFSIZ]; ! 865: f1 = open(fn, 0); ! 866: if (f1 < 0) ! 867: return -1; ! 868: f2 = open(newname, 1); ! 869: if (f2 < 0) { ! 870: if (errno == ENOENT) { ! 871: f2 = creat(newname,0644); ! 872: if (f2 < 0) { ! 873: close(f1); ! 874: return -1; ! 875: } ! 876: } else { ! 877: close(f1); ! 878: return -1; ! 879: } ! 880: } ! 881: while((r=read(f1, buf, BUFSIZ)) > 0) ! 882: write(f2, buf, r); ! 883: (void) close(f1); ! 884: (void) close(f2); ! 885: return 0; ! 886: } ! 887: ! 888: /* ! 889: * Count instances of c in s ! 890: */ ! 891: chrcnt(s, c) ! 892: register char *s; ! 893: register c; ! 894: { ! 895: register n = 0; ! 896: register cc; ! 897: ! 898: while (cc = *s++) ! 899: if (cc == c) ! 900: n++; ! 901: return n; ! 902: } ! 903: ! 904: /* ! 905: * If any parent directories of this dir don't exist, create them. ! 906: */ ! 907: mkparents(fullname) ! 908: char *fullname; ! 909: { ! 910: char buf[200]; ! 911: register char *p; ! 912: int rc; ! 913: ! 914: (void) strcpy(buf, fullname); ! 915: p = rindex(buf, '/'); ! 916: if (p) ! 917: *p = '\0'; ! 918: if (access(buf, 0) == 0) ! 919: return 0; ! 920: mkparents(buf); ! 921: if ((rc = mkdir(buf, 0755)) < 0) ! 922: perror("mkdir failed"); ! 923: if (verbose) ! 924: printf("mkdir %s, rc %d\n", buf, rc); ! 925: ! 926: return rc; ! 927: } ! 928: ! 929: ! 930: /* Make sure this file is a legal article. */ ! 931: islegal(fullname, path, name) ! 932: register char *fullname; ! 933: register char *path; ! 934: register char *name; ! 935: { ! 936: struct stat buffer; ! 937: ! 938: (void) sprintf(fullname, "%s/%s", path, name); ! 939: ! 940: /* make sure the article is numeric. */ ! 941: while (*name != '\0') ! 942: if (!isascii(*name) || !isdigit(*name)) ! 943: return 0; ! 944: else ! 945: name++; ! 946: ! 947: /* Now make sure we don't have a group like net.micro.432, ! 948: * which is numeric but not a regular file -- i.e., check ! 949: * for being a regular file. ! 950: */ ! 951: if ((stat(fullname, &buffer) == 0) && ! 952: ((buffer.st_mode & S_IFMT) == S_IFREG)) { ! 953: /* Now that we found a legal group in a/b/c/4 ! 954: notation, switch it to a.b.c/4 notation. */ ! 955: for (name = fullname; name != NULL && *name != '\0'; name++) ! 956: if (*name == '/' && name != rindex (name, '/')) ! 957: *name = '.'; ! 958: ! 959: return 1; ! 960: } ! 961: return 0; ! 962: } ! 963: ! 964: #ifdef DBM ! 965: /* ! 966: * This is taken mostly intact from ../cvt/cvt.hist.c and is used at the ! 967: * end by the options that make a new history file. ! 968: * Routine to convert history file to dbm file. The old 3 field ! 969: * history file is still kept there, because we need it for expire ! 970: * and for a human readable copy. But we keep a dbm hashed copy ! 971: * around by message ID so we can answer the yes/no question "have ! 972: * we already seen this message". The content is the ftell offset ! 973: * into the real history file when we get the article - you can't ! 974: * really do much with this because the file gets compacted. ! 975: */ ! 976: ! 977: FILE *fd; ! 978: ! 979: char namebuf[BUFSIZ]; ! 980: char lb[BUFSIZ]; ! 981: ! 982: rebuilddbm() ! 983: { ! 984: register char *p; ! 985: long fpos; ! 986: ! 987: (void) umask(0); ! 988: (void) sprintf(namebuf, "%s.dir", ARTFILE); ! 989: (void) close(creat(namebuf, 0666)); ! 990: (void) sprintf(namebuf, "%s.pag", ARTFILE); ! 991: (void) close(creat(namebuf, 0666)); ! 992: (void) sprintf(namebuf, "%s", ARTFILE); ! 993: ! 994: fd = fopen(namebuf, "r"); ! 995: if (fd == NULL) { ! 996: perror(namebuf); ! 997: xxit(2); ! 998: } ! 999: ! 1000: initdbm(namebuf); ! 1001: while (fpos=ftell(fd), fgets(lb, BUFSIZ, fd) != NULL) { ! 1002: p = index(lb, '\t'); ! 1003: if (p) ! 1004: *p = 0; ! 1005: remember(lb, fpos); ! 1006: } ! 1007: } ! 1008: ! 1009: remember(article, fileoff) ! 1010: register char *article; ! 1011: long fileoff; ! 1012: { ! 1013: datum lhs, rhs; ! 1014: ! 1015: lcase(article); ! 1016: lhs.dptr = article; ! 1017: lhs.dsize = strlen(article) + 1; ! 1018: rhs.dptr = (char *) &fileoff; ! 1019: rhs.dsize = sizeof fileoff; ! 1020: ! 1021: if (verbose > 5) ! 1022: printf("remember: %s @ %ld\n", article, fileoff); ! 1023: if (store(lhs, rhs) < 0) ! 1024: xerror("dbm store failed"); ! 1025: } ! 1026: #endif /* DBM */ ! 1027: ! 1028: xxit(i) ! 1029: { ! 1030: exit(i); ! 1031: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.