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: }

Defined functions

chrcnt defined in line 891; used 2 times
  • in line 537(2)
fcopy defined in line 859; used 1 times
islegal defined in line 931; used 1 times
main defined in line 94; never used
mkparents defined in line 907; used 2 times
rebuilddbm defined in line 982; used 1 times
remember defined in line 1009; used 2 times
ulall defined in line 781; used 1 times
xxit defined in line 1028; used 3 times

Defined variables

DIRFILE defined in line 47; used 2 times
NACTIVE defined in line 48; used 3 times
NARTFILE defined in line 46; used 9 times
OACTIVE defined in line 48; used 2 times
OARTFILE defined in line 46; used 6 times
PAGFILE defined in line 47; used 2 times
Progname defined in line 31; never used
SccsId defined in line 20; never used
afline defined in line 90; used 15 times
arpat defined in line 86; used 10 times
arpatlen defined in line 87; used 6 times
baduser defined in line 60; used 2 times
doarchive defined in line 54; used 4 times
dorebuild defined in line 56; used 10 times
dropincr defined in line 80; used 6 times
expincr defined in line 79; used 6 times
exptime defined in line 50; used 4 times
frflag defined in line 58; used 3 times
gp defined in line 85; used 2 times
grpsleft defined in line 91; used 10 times
h defined in line 92; used 28 times
ignorexp defined in line 53; used 4 times
lb defined in line 980; used 3 times
mh_size defined in line 70; used 9 times
multhist defined in line 69; used 13 times
namebuf defined in line 979; used 8 times
ngpat defined in line 88; used 13 times
ngpatlen defined in line 89; used 6 times
nohistory defined in line 55; used 7 times
pw defined in line 84; used 2 times
recdate defined in line 49; used 9 times
rectime defined in line 50; used 12 times
updateactive defined in line 59; used 2 times
usepost defined in line 57; used 3 times
verbose defined in line 52; used 21 times

Defined struct's

expdata defined in line 36; never used
multhist defined in line 66; used 12 times

Defined macros

SPACE_INCREMENT defined in line 34; used 5 times
Last modified: 1986-03-20
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2194
Valid CSS Valid XHTML 1.0 Strict