Path: titcca!takashi!kato From: kato@takashi.cs.titech.JUNET (Akira Kato) Newsgroups: fj.sources Subject: Bnews 2.11 (J) Part 16 Message-ID: <1214@takashi.cs.titech.JUNET> Date: 12 Dec 86 01:30:25 GMT Reply-To: kato@takashi.cs.titech.JUNET (Akira Kato) Distribution: fj Organization: Tokyo Institute of Tech., Dept. of Computer Science, Japan Lines: 1979 This file is a part of Bnews 2.11 (J) distribution. The subject field of this message shows the order to be unshar-ed by /bin/sh. Note that the order of decomposing files is important. The last article will include the word 'Last Part' in its subject. Akira Kato Tokyo Institute of Technology JUNET: kato@cs.titech.junet #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # src # This archive created: Fri Dec 12 10:19:36 1986 export PATH; PATH=/bin:/usr/bin:$PATH if test ! -d 'src' then echo shar: "creating directory 'src'" mkdir 'src' fi echo shar: "entering directory 'src'" cd 'src' echo shar: "extracting 'expire.c'" '(24817 characters)' if test -f 'expire.c' then echo shar: "will not over-write existing file 'expire.c'" else cat << \SHAR_EOF > 'expire.c' /* * This software is Copyright (c) 1986 by Rick Adams. * * Permission is hereby granted to copy, reproduce, redistribute or * otherwise use this software as long as: there is no monetary * profit gained specifically from the use or reproduction or this * software, it is not sold, rented, traded or otherwise marketed, and * this copyright notice is included prominently in any copy * made. * * The author make no claims as to the fitness or correctness of * this software for any use whatsoever, and it is provided as is. * Any use of this software is at the user's own risk. * * expire - expire daemon runs around and nails all articles that * have expired. */ #ifdef SCCSID static char *SccsId = "@(#)expire.c 2.48 11/21/86"; #endif /* SCCSID */ #include "params.h" #include #if defined(BSD4_2) || defined(BSD4_1C) # include # include #else # include "ndir.h" #endif #ifdef LOCKF #include #endif /* LOCKF */ char *Progname = "expire"; /* used by xerror to identify failing program */ /* Number of array entries to allocate at a time. */ #define SPACE_INCREMENT 1000 struct expdata { char *e_name; long e_min, e_max; time_t e_droptime, e_expiretime; char e_ignorexp; char e_doarchive; char e_doexpire; }; extern int errno; char NARTFILE[BUFLEN], OARTFILE[BUFLEN]; char PAGFILE[BUFLEN], DIRFILE[BUFLEN]; char NACTIVE[BUFLEN], OACTIVE[BUFLEN]; char recdate[BUFLEN]; long rectime, exptime; extern char *OLDNEWS; int verbose = 0; int ignorexp = 0; int doarchive = 0; int nohistory = 0; int dorebuild = 0; int usepost = 0; int frflag = 0; int updateactive = 0; char baduser[BUFLEN]; extern char filename[], nbuf[]; struct timeb Now; /* * This code uses realloc to get more of the multhist array. */ struct multhist { char *mh_ident; char *mh_file; } *multhist; unsigned int mh_size; char *calloc(); char *realloc(); struct tm *gmtime(); typedef struct { char *dptr; int dsize; } datum; long expincr; long dropincr; long atol(); time_t cgtdate(), time(); FILE *popen(); struct passwd *pw; struct group *gp; char arpat[LBUFLEN]; int arpatlen = 0; char ngpat[LBUFLEN]; int ngpatlen = 0; char afline[BUFLEN]; char grpsleft[BUFLEN]; struct hbuf h; int ExpireLock; main(argc, argv) int argc; char **argv; { register char *p1, *p2, *p3; register time_t newtime, today; register FILE *fp = NULL; FILE *ohfd, *nhfd; DIR *ngdirp = NULL; static struct direct *ngdir; char fn[BUFLEN]; int i, LockFd; #ifndef DBM char *ptr, chr; FILE *subfd[10]; char *histfile(); #endif /* !DBM */ pathinit(); (void) umask(N_UMASK); /* * Try to run as NEWSUSR/NEWSGRP */ if ((pw = getpwnam(NEWSUSR)) == NULL) xerror("Cannot get NEWSUSR pw entry"); uid = pw->pw_uid; if ((gp = getgrnam(NEWSGRP)) == NULL) xerror("Cannot get NEWSGRP gr entry"); gid = gp->gr_gid; (void) setgid(gid); (void) setuid(uid); expincr = DFLTEXP; dropincr = HISTEXP; ngpat[0] = ','; arpat[0] = ','; while (argc > 1) { switch (argv[1][1]) { case 'v': if (isdigit(argv[1][2])) verbose = argv[1][2] - '0'; else if (argc > 2 && argv[2][0] != '-') { argv++; argc--; verbose = atoi(argv[1]); } else verbose = 1; if (verbose < 3) setbuf(stdout, (char *)NULL); break; case 'e': /* Use this as default expiration time */ if (argc > 2 && argv[2][0] != '-') { argv++; argc--; expincr = atol(argv[1]) * DAYS; } else if (isdigit(argv[1][2])) expincr = atol(&argv[1][2]) * DAYS; break; case 'E': /* Use this as default forget time */ if (argc > 2 && argv[2][0] != '-') { argv++; argc--; dropincr = atol(argv[1]) * DAYS; } else if (isdigit(argv[1][2])) dropincr = atol(&argv[1][2]) * DAYS; break; case 'I': /* Ignore any existing expiration date */ ignorexp = 2; break; case 'i': /* Ignore any existing expiration date */ ignorexp = 1; break; case 'n': if (argc > 2) { argv++; argc--; while (argc > 1 && argv[1][0] != '-') { int argvlen; argvlen = strlen(argv[1]); if (ngpatlen + argvlen + 2 > sizeof (ngpat)) { xerror("Too many groups specified for -n\n"); } if (ngpat[ngpatlen] == '\0') { ngpat[ngpatlen++] = ','; ngpat[ngpatlen] = '\0'; } strcpy(&ngpat[ngpatlen], argv[1]); ngpatlen += argvlen; argv++; argc--; } argv--; argc++; } break; case 'a': /* archive expired articles */ if (access(OLDNEWS,0) < 0){ perror(OLDNEWS); xerror("No archiving possible\n"); } doarchive++; if (argc > 2) { argv++; argc--; while (argc > 1 && argv[1][0] != '-') { int argvlen; argvlen = strlen(argv[1]); if (arpatlen + argvlen + 2 > sizeof (arpat)) { xerror("Too many groups specified for -a\n"); } if (arpat[arpatlen] == '\0') { arpat[arpatlen++] = ','; arpat[arpatlen] = '\0'; } strcpy(&arpat[arpatlen], argv[1]); arpatlen += argvlen; argv++; argc--; } argv--; argc++; } break; case 'h': /* ignore history */ nohistory++; break; case 'r': /* rebuild history file */ dorebuild++; nohistory++; break; case 'p': usepost++; break; case 'f': frflag++; if (argc > 2) { strcpy(baduser, argv[2]); argv++; argc--; } break; case 'u': updateactive++; break; default: printf("Usage: expire [ -v [level] ] [-e days ] [-i] [-a] [-r] [-h] [-p] [-u] [-f username] [-n newsgroups]\n"); xxit(1); } argc--; argv++; } if (dropincr < expincr) { dropincr = HISTEXP; fprintf(stderr, "History expiration time < article expiration time. Default used.\n"); } if (ngpat[0] == ',') (void) strcpy(ngpat, "all,"); if (arpat[0] == ',') (void) strcpy(arpat, "all,"); (void) ftime(&Now); today = Now.time; if (chdir(SPOOL)) xerror("Cannot chdir %s", SPOOL); if (verbose) { printf("expire: nohistory %d, rebuild %d, doarchive %d\n", nohistory, dorebuild, doarchive); printf("newsgroups: %s\n",ngpat); if (doarchive) printf("archiving: %s\n",arpat); } (void) sprintf(OARTFILE, "%s/%s", LIB, "ohistory"); (void) sprintf(NARTFILE, "%s/%s", LIB, "nhistory"); (void) sprintf(OACTIVE, "%s/%s", LIB, "oactive"); (void) sprintf(NACTIVE, "%s/%s", LIB, "nactive"); if (updateactive) goto doupdateactive; #ifdef DBM if (!dorebuild) { (void) sprintf(PAGFILE, "%s/%s", LIB, "nhistory.pag"); (void) sprintf(DIRFILE, "%s/%s", LIB, "nhistory.dir"); (void) close(creat(PAGFILE, 0666)); (void) close(creat(DIRFILE, 0666)); initdbm(NARTFILE); } #endif if (nohistory) { ohfd = xfopen(ACTIVE, "r"); if (dorebuild) { /* Allocate initial space for multiple newsgroup (for an article) array */ multhist = (struct multhist *)calloc (SPACE_INCREMENT, sizeof (struct multhist)); mh_size = SPACE_INCREMENT; (void) sprintf(afline, "exec sort -t\t +1.6 -2 +1 >%s", NARTFILE); if ((nhfd = popen(afline, "w")) == NULL) xerror("Cannot exec %s", afline); } else nhfd = xfopen("/dev/null", "w"); } else { ohfd = xfopen(ARTFILE, "r"); nhfd = xfopen(NARTFILE, "w"); } /* set up exclusive locking so inews doesn't run while expire does */ #if defined(BSD4_2) || defined(LOCKF) LockFd = open(ACTIVE, 2); #ifdef LOCKF (void) lockf(LockFd, F_LOCK, 0); #else /* BSD4_2 */ (void) flock(LockFd, LOCK_EX); #endif /* BSd4_2 */ #else /* !BSD4_2 && !LOCKF */ i = 0; sprintf(afline,"%s.lock", ACTIVE); while (LINK(ACTIVE, afline) < 0 && errno == EEXIST) { if (i++ > 5) xerror("Can't get lock for expire"); sleep(i*2); } #endif /* !BSD4_2 && !LOCKF */ for(i=0;id_name)); p2 = fn; if (verbose > 2) printf("article: %s\n", fn); strcpy(filename, dirname(fn)); fp = access(filename, 04) ? NULL : art_open(filename, "r"); } else { char dc; if (fgets(afline, BUFLEN, ohfd) == NULL) break; if (verbose > 2) printf("article: %s", afline); p1 = index(afline, '\t'); if (!p1) continue; *p1 = '\0'; (void) strcpy(h.ident, afline); *p1 = '\t'; p2 = index(p1 + 1, '\t'); if (!p2) continue; *p2 = '\0'; (void) strcpy(recdate, p1+1); rectime = cgtdate(recdate); *p2++ = '\t'; (void) strcpy(nbuf, p2); p3 = index(nbuf, '/'); if (p3) { register char *p4; p4 = index(p3, '\n'); if (p4) { while (p4[-1] == ' ') p4--; *p4 = '\0'; } /* * convert list of newsgroups from * ng1/num ng2/num ... * to * ng1,ng2,... */ p4 = p3; do { *p3++ = NGDELIM; while (*p4 != '\0' && *p4 != ' ') p4++; if (*p4++ == '\0') { *--p3 = '\0'; break; } while (*p3 = *p4++) { if (*p3 == '/') break; else p3++; } } while (*p3); } else { /* * Nothing after the 2nd tab. This happens * when there's no message left in the spool * directory, only the memory of it in the * history file. Use date in the history file * to decide if we should keep this article. */ grpsleft[0] = '\0'; goto checkdate; } if (!ngmatch(nbuf, ngpat) || ((rectime+expincr > today) && !dorebuild && !frflag && !usepost && recdate[0] != ' ')) goto keephist; if (!dorebuild && !frflag && !usepost && recdate[0] != ' ') { grpsleft[0] = '\0'; goto nailit; /* just expire it */ } /* * Look for the file--possibly several times, * if it was posted to several news groups. */ dc = ' '; p3 = p2; while (dc != '\n') { p1 = index(p3, ' '); if (p1) { dc = ' '; *p1 = '\0'; } else { p1 = index(p3, '\n'); if (p1 && p1 > p3) { dc = '\n'; *p1 = '\0'; } else { fp = NULL; break; } } strcpy(filename, dirname(p3)); if (access(filename, 4) == 0 && ((fp=art_open(filename, "r")) != NULL)) break; p3 = p1 + 1; } if (p1) *p1 = dc; } if (fp == NULL) { /* * this probably means that the article has been * cancelled. Lets assume that, and make an * entry in the history file to that effect. */ if (verbose) perror(filename); strcpy(p2, "cancelled\n"); grpsleft[0] = '\0'; goto checkdate; } for(i=0; itm_mon+1, tm->tm_mday, tm->tm_year, tm->tm_hour, tm->tm_min, filename) == EOF) xerror("History write failed"); (void) fclose(fp); continue; } for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) { if (mhp->mh_file == NULL) continue; if (strcmp(mhp->mh_ident, h.ident)) continue; (void) strcat(filename, " "); (void) strcat(filename, mhp->mh_file); free(mhp->mh_file); mhp->mh_file = NULL; /* * if we have all the links, write to hist now */ if (chrcnt(filename, ' ') == chrcnt(cp,NGDELIM)) goto saveit; break; } /* * Here is where we realloc the multhist space rather * than the old way of static allocation. It's * really trivial. We just clear out the space * in case it was reused. The old static array was * guaranteed to be cleared since it was cleared when * the process started. */ if (mhp >= multhist + mh_size) { multhist = (struct multhist *) realloc ((char *)multhist, sizeof (struct multhist) * (SPACE_INCREMENT + mh_size)); if (multhist == NULL) xerror("Too many articles with multiple newsgroups"); for (mhp = multhist + mh_size; mhp < multhist+mh_size+SPACE_INCREMENT; mhp++) { mhp->mh_ident = NULL; mhp->mh_file = NULL; } mhp = multhist + mh_size; mh_size += SPACE_INCREMENT; } if (mhp->mh_ident == NULL) { mhp->mh_ident = malloc(strlen(h.ident)+1); (void) strcpy(mhp->mh_ident, h.ident); } cp = malloc(strlen(filename) + 1); if (cp == NULL) xerror("Out of memory"); (void) strcpy(cp, filename); mhp->mh_file = cp; (void) fclose(fp); continue; } (void) fclose(fp); if (h.expdate[0]) { Now.time = rectime; exptime = cgtdate(h.expdate); } newtime = (usepost ? cgtdate(h.subdate) : rectime) + expincr; if (!h.expdate[0] || ignorexp == 2 || (ignorexp == 1 && newtime < exptime)) exptime = newtime; if (frflag ? strcmp(baduser,h.from)==0 : today >= exptime) { nailit: #ifdef DEBUG printf("cancel %s\n", filename); #else /* !DEBUG */ if (verbose) printf("cancel %s\n", h.ident); ulall(p2, &h); (void) sprintf(p2, "%s\n", grpsleft); if (verbose > 2 && grpsleft[0]) printf("Some good in %s\n", h.ident); #endif /* !DEBUG */ } else { if (verbose > 2) printf("Good article %s\n", h.ident); grpsleft[0] = '!'; } checkdate: if (grpsleft[0] == '\0' && today >= rectime + dropincr) { if (verbose > 3) printf("Drop history of %s - %s\n", h.ident, recdate); } else { long hpos; keephist: hpos = ftell(nhfd); if (verbose > 3) printf("Retain history of %s - %s\n", h.ident, recdate); if (fputs(afline, nhfd) == EOF) xerror("history write failed"); #ifdef DBM if (!dorebuild) remember(h.ident, hpos); #endif /* DBM */ } } out: if (dorebuild) { register struct multhist *mhp; struct tm *tm; for (mhp = multhist; mhp < multhist+mh_size && mhp->mh_ident != NULL; mhp++) if (mhp->mh_file != NULL) { if (verbose) printf("Article: %s [%s] Cannot find all links\n", mhp->mh_ident, mhp->mh_file); (void) sprintf(filename,"%s/%s",SPOOL,mhp->mh_file); for (p1 = filename; *p1 != ' ' && *p1 != '\0'; p1++) if (*p1 == '.') *p1 = '/'; *p1 = '\0'; if ((fp = art_open(filename, "r")) == NULL) { if (verbose) printf("Can't open %s.\n", filename); continue; } if (!hread(&h, fp, TRUE)) { printf("Garbled article %s.\n", filename); (void) fclose(fp); continue; } else { struct stat statb; if (fstat(fileno(fp), &statb) < 0) rectime = cgtdate(h.subdate); else rectime = statb.st_mtime; } tm = gmtime(&rectime); if ( #ifdef USG fprintf(nhfd,"%s\t%s%2.2d/%2.2d/%d %2.2d:%2.2d\t%s\n", #else /* !USG */ fprintf(nhfd,"%s\t%s%02d/%02d/%d %02d:%02d\t%s\n", #endif /* !USG */ h.ident, h.expdate[0] ? " " : "", tm->tm_mon+1, tm->tm_mday, tm->tm_year, tm->tm_hour, tm->tm_min, mhp->mh_file) == EOF ) xerror("History write failed"); (void) fclose(fp); continue; } (void) pclose(nhfd); free ((char *)multhist); } else if (fclose(nhfd)) xerror("History write failed, %s", errmsg(errno)); if (dorebuild || !nohistory) { (void) rename(ARTFILE, OARTFILE); (void) rename(NARTFILE, ARTFILE); #ifdef DBM if (dorebuild) rebuilddbm( ); else { char tempname[BUFLEN]; (void) sprintf(tempname,"%s.pag", ARTFILE); (void) strcat(NARTFILE, ".pag"); (void) rename(NARTFILE, tempname); (void) sprintf(tempname,"%s.dir", ARTFILE); (void) strcpy(rindex(NARTFILE, '.'), ".dir"); (void) rename(NARTFILE, tempname); } #endif } #ifndef DBM /* rebuild history subfiles */ for (i = 0; i < 10; i++) { (void) sprintf(fn, "%s.d/%c", ARTFILE, i + '0'); close(creat(fn, 0644)); subfd[i] = xfopen(fn, "w+"); } ohfd = xfopen(ARTFILE, "r"); while (fgets(fn, BUFLEN, ohfd) != NULL) { ptr = histfile(fn); chr = *(ptr + strlen(ptr) - 1); if (isdigit(chr)) i = chr - '0'; else i = 0; fputs(fn, subfd[i]); } (void) fclose(ohfd); for (i = 0; i < 10; i++) if (ferror(subfd[i]) || fclose(subfd[i])) xerror("History subfile write"); #endif /* !DBM */ doupdateactive: ohfd = xfopen(ACTIVE, "r"); nhfd = xfopen(NACTIVE, "w"); do { long n; long maxart, minart; char cansub; int gdsize, hassubs; struct stat stbuf; if (fgets(afline, BUFLEN, ohfd) == NULL) continue; if (sscanf(afline,"%s %ld %ld %c",nbuf,&maxart, &minart, &cansub) < 4) xerror("Active file corrupt"); if (!ngmatch(nbuf, ngpat)) { if (fputs(afline, nhfd) == EOF) xerror("active file write failed"); continue; } minart = 99999L; /* Change a group name from a.b.c to a/b/c */ for (p1=nbuf; *p1; p1++) if (*p1 == '.') *p1 = '/'; hassubs = stat(nbuf, &stbuf) != 0 || stbuf.st_nlink != 2; gdsize = strlen(nbuf); if ((ngdirp = opendir(nbuf)) != NULL) { while (ngdir = readdir(ngdirp)) { nbuf[gdsize] = '/'; (void) strcpy(&nbuf[gdsize+1], ngdir->d_name); /* We have to do a stat because of micro.6809 */ if (hassubs && (stat(nbuf, &stbuf) < 0 || !(stbuf.st_mode&S_IFREG)) ) continue; n = atol(ngdir->d_name); if (n > 0 && n < minart) minart = n; if (n > 0 && n > maxart) maxart = n; } closedir(ngdirp); } afline[gdsize] = '\0'; if (minart > maxart) minart = maxart; if (fprintf(nhfd,"%s %05ld %05ld %c\n", afline, maxart, minart, cansub) == EOF) xerror("Active file write failed"); } while (!feof(ohfd)); if (fclose(nhfd)) xerror("Active file write failed, %s", errmsg(errno)); (void) fclose(ohfd); /* unlocking inews as a side effect */ #ifndef BSD4_2 sprintf(bfr, "%s.lock", ACTIVE); (void) UNLINK(bfr); #endif /* !BSD4_2 */ (void) rename(ACTIVE, OACTIVE); (void) rename(NACTIVE, ACTIVE); execl(RNEWS, "rnews", "-U", (char *)NULL); perror(RNEWS); xxit(1); } /* Unlink (using unwound tail recursion) all the articles in 'artlist'. */ ulall(artlist, hp) char *artlist; struct hbuf *hp; { register char *p, *q; int last = 0; char newname[BUFLEN]; time_t timep[2]; char *fn; grpsleft[0] = '\0'; do { if (verbose > 2) printf("ulall '%s', '%s'\n", artlist, hp->subdate); if (nohistory) { last = 1; } else { while (*artlist == ' ' || *artlist == '\n' || *artlist == ',') artlist++; if (*artlist == '\0') return; p = index(artlist, ' '); if (p == NULL) { last = 1; p = index(artlist, '\n'); } if (p == NULL) { last = 1; fn = dirname(artlist); if (UNLINK(fn) < 0 && errno != ENOENT) perror(fn); return; } if (p) *p = 0; } strcpy(newname, artlist); q = index(newname,'/'); if (q) { *q++ = NGDELIM; *q = '\0'; } else { q = index(newname, '\0'); if (q == artlist) /* null -> the end */ return; /* should be impossible to get here */ } fn = dirname(artlist); if (ngmatch(newname, ngpat)) { if (doarchive){ if (ngmatch(newname, arpat)) { q = fn + strlen(SPOOL) + 1; (void) sprintf(newname, "%s/%s", OLDNEWS, q); if (verbose) printf("link %s to %s\n", fn, newname); if (LINK(fn, newname) == -1) { if (mkparents(newname) == 0) if (LINK(fn, newname) == -1) fcopy(fn, newname); } timep[0] = timep[1] = cgtdate(hp->subdate); (void) utime(newname, timep); } } if (verbose) printf("unlink %s\n", fn); if (UNLINK(fn) < 0 && errno != ENOENT) perror(fn); } else { if (verbose > 3) printf("retain %s (%s)\n", hp->ident, fn); strcat(grpsleft, artlist); strcat(grpsleft, " "); } artlist = p + 1; } while (!last); } fcopy(fn, newname) char *fn, *newname; { int f1, f2; int r; char buf[BUFSIZ]; f1 = open(fn, 0); if (f1 < 0) return -1; f2 = open(newname, 1); if (f2 < 0) { if (errno == ENOENT) { f2 = creat(newname,0644); if (f2 < 0) { close(f1); return -1; } } else { close(f1); return -1; } } while((r=read(f1, buf, BUFSIZ)) > 0) write(f2, buf, r); (void) close(f1); (void) close(f2); return 0; } /* * Count instances of c in s */ chrcnt(s, c) register char *s; register c; { register n = 0; register cc; while (cc = *s++) if (cc == c) n++; return n; } /* * If any parent directories of this dir don't exist, create them. */ mkparents(fullname) char *fullname; { char buf[200]; register char *p; int rc; (void) strcpy(buf, fullname); p = rindex(buf, '/'); if (p) *p = '\0'; if (access(buf, 0) == 0) return 0; mkparents(buf); if ((rc = mkdir(buf, 0755)) < 0) perror("mkdir failed"); if (verbose) printf("mkdir %s, rc %d\n", buf, rc); return rc; } /* Make sure this file is a legal article. */ islegal(fullname, path, name) register char *fullname; register char *path; register char *name; { struct stat buffer; (void) sprintf(fullname, "%s/%s", path, name); /* make sure the article is numeric. */ while (*name != '\0') if (!isascii(*name) || !isdigit(*name)) return 0; else name++; /* Now make sure we don't have a group like net.micro.432, * which is numeric but not a regular file -- i.e., check * for being a regular file. */ if ((stat(fullname, &buffer) == 0) && ((buffer.st_mode & S_IFMT) == S_IFREG)) { /* Now that we found a legal group in a/b/c/4 notation, switch it to a.b.c/4 notation. */ for (name = fullname; name != NULL && *name != '\0'; name++) if (*name == '/' && name != rindex (name, '/')) *name = '.'; return 1; } return 0; } #ifdef DBM /* * This is taken mostly intact from ../cvt/cvt.hist.c and is used at the * end by the options that make a new history file. * Routine to convert history file to dbm file. The old 3 field * history file is still kept there, because we need it for expire * and for a human readable copy. But we keep a dbm hashed copy * around by message ID so we can answer the yes/no question "have * we already seen this message". The content is the ftell offset * into the real history file when we get the article - you can't * really do much with this because the file gets compacted. */ FILE *fd; char namebuf[BUFSIZ]; char lb[BUFSIZ]; rebuilddbm() { register char *p; long fpos; (void) sprintf(namebuf, "%s.dir", ARTFILE); (void) close(creat(namebuf, 0666)); (void) sprintf(namebuf, "%s.pag", ARTFILE); (void) close(creat(namebuf, 0666)); (void) sprintf(namebuf, "%s", ARTFILE); fd = fopen(namebuf, "r"); if (fd == NULL) { perror(namebuf); xxit(2); } initdbm(namebuf); while (fpos=ftell(fd), fgets(lb, BUFSIZ, fd) != NULL) { p = index(lb, '\t'); if (p) *p = 0; remember(lb, fpos); } } remember(article, fileoff) register char *article; long fileoff; { datum lhs, rhs; lcase(article); lhs.dptr = article; lhs.dsize = strlen(article) + 1; rhs.dptr = (char *) &fileoff; rhs.dsize = sizeof fileoff; if (verbose > 5) printf("remember: %s @ %ld\n", article, fileoff); if (store(lhs, rhs) < 0) xerror("dbm store failed"); } #endif /* DBM */ xxit(i) { sprintf(bfr,"%s.lock", ACTIVE); (void) UNLINK(bfr); exit(i); } SHAR_EOF if test 24817 -ne "`wc -c < 'expire.c'`" then echo shar: "error transmitting 'expire.c'" '(should have been 24817 characters)' fi fi echo shar: "extracting 'getdate.y'" '(12589 characters)' if test -f 'getdate.y' then echo shar: "will not over-write existing file 'getdate.y'" else cat << \SHAR_EOF > 'getdate.y' %token ID MONTH DAY MERIDIAN NUMBER UNIT MUNIT SUNIT ZONE DAYZONE AGO %{ /* Originally from: Steven M. Bellovin (unc!smb) */ /* Dept. of Computer Science */ /* University of North Carolina at Chapel Hill */ /* @(#)getdate.y 2.14 11/21/86 */ #include #ifdef USG struct timeb { time_t time; unsigned short millitm; short timezone; short dstflag; }; #else #include #endif #include #include "defs.h" #if defined(BSD4_2) || defined (BSD4_1C) #include #else sane #include #endif sane #define NULL 0 #define daysec (24L*60L*60L) static int timeflag, zoneflag, dateflag, dayflag, relflag; static time_t relsec, relmonth; static int hh, mm, ss, merid, daylight; static int dayord, dayreq; static int month, day, year; static int ourzone; #define AM 1 #define PM 2 #define DAYLIGHT 1 #define STANDARD 2 #define MAYBE 3 %} %% timedate: /* empty */ | timedate item; item: tspec = {timeflag++;} | zone = {zoneflag++;} | dtspec = {dateflag++;} | dyspec = {dayflag++;} | rspec = {relflag++;} | nspec; nspec: NUMBER = {if (timeflag && dateflag && !relflag) year = $1; else {timeflag++;hh = $1/100;mm = $1%100;ss = 0;merid = 24;}}; tspec: NUMBER MERIDIAN = {hh = $1; mm = 0; ss = 0; merid = $2;} | NUMBER ':' NUMBER = {hh = $1; mm = $3; merid = 24;} | NUMBER ':' NUMBER MERIDIAN = {hh = $1; mm = $3; merid = $4;} | NUMBER ':' NUMBER NUMBER = {hh = $1; mm = $3; merid = 24; daylight = STANDARD; ourzone = -($4%100 + 60*($4/100));} | NUMBER ':' NUMBER ':' NUMBER = {hh = $1; mm = $3; ss = $5; merid = 24;} | NUMBER ':' NUMBER ':' NUMBER MERIDIAN = {hh = $1; mm = $3; ss = $5; merid = $6;} | NUMBER ':' NUMBER ':' NUMBER NUMBER = {hh = $1; mm = $3; ss = $5; merid = 24; daylight = STANDARD; ourzone = -($6%100 + 60*($6/100));}; zone: ZONE = {ourzone = $1; daylight = STANDARD;} | DAYZONE = {ourzone = $1; daylight = DAYLIGHT;}; dyspec: DAY = {dayord = 1; dayreq = $1;} | DAY ',' = {dayord = 1; dayreq = $1;} | NUMBER DAY = {dayord = $1; dayreq = $2;}; dtspec: NUMBER '/' NUMBER = {month = $1; day = $3;} | NUMBER '/' NUMBER '/' NUMBER = {month = $1; day = $3; year = $5;} | MONTH NUMBER = {month = $1; day = $2;} | MONTH NUMBER ',' NUMBER = {month = $1; day = $2; year = $4;} | NUMBER MONTH = {month = $2; day = $1;} | NUMBER MONTH NUMBER = {month = $2; day = $1; year = $3;}; rspec: NUMBER UNIT = {relsec += 60L * $1 * $2;} | NUMBER MUNIT = {relmonth += $1 * $2;} | NUMBER SUNIT = {relsec += $1;} | UNIT = {relsec += 60L * $1;} | MUNIT = {relmonth += $1;} | SUNIT = {relsec++;} | rspec AGO = {relsec = -relsec; relmonth = -relmonth;}; %% static int mdays[12] = {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; #define epoch 1970 extern struct tm *localtime(); time_t dateconv(mm, dd, yy, h, m, s, mer, zone, dayflag) int mm, dd, yy, h, m, s, mer, zone, dayflag; { time_t tod, jdate; register int i; time_t timeconv(); if (yy < 0) yy = -yy; if (yy < 100) yy += 1900; mdays[1] = 28 + (yy%4 == 0 && (yy%100 != 0 || yy%400 == 0)); if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 || dd < 1 || dd > mdays[--mm]) return (-1); jdate = dd-1; for (i=0; itm_isdst)) jdate += -1*60*60; return (jdate); } time_t dayconv(ord, day, now) int ord, day; time_t now; { register struct tm *loctime; time_t tod; time_t daylcorr(); tod = now; loctime = localtime(&tod); tod += daysec * ((day - loctime->tm_wday + 7) % 7); tod += 7*daysec*(ord<=0?ord:ord-1); return daylcorr(tod, now); } time_t timeconv(hh, mm, ss, mer) register int hh, mm, ss, mer; { if (mm < 0 || mm > 59 || ss < 0 || ss > 59) return (-1); switch (mer) { case AM: if (hh < 1 || hh > 12) return(-1); return (60L * ((hh%12)*60L + mm)+ss); case PM: if (hh < 1 || hh > 12) return(-1); return (60L * ((hh%12 +12)*60L + mm)+ss); case 24: if (hh < 0 || hh > 23) return (-1); return (60L * (hh*60L + mm)+ss); default: return (-1); } } time_t monthadd(sdate, relmonth) time_t sdate, relmonth; { struct tm *ltime; time_t dateconv(); time_t daylcorr(); int mm, yy; if (relmonth == 0) return 0; ltime = localtime(&sdate); mm = 12*ltime->tm_year + ltime->tm_mon + relmonth; yy = mm/12; mm = mm%12 + 1; return daylcorr(dateconv(mm, ltime->tm_mday, yy, ltime->tm_hour, ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE), sdate); } time_t daylcorr(future, now) time_t future, now; { int fdayl, nowdayl; nowdayl = (localtime(&now)->tm_hour+1) % 24; fdayl = (localtime(&future)->tm_hour+1) % 24; return (future-now) + 60L*60L*(nowdayl-fdayl); } static char *lptr; yylex() { extern int yylval; int sign; register char c; register char *p; char idbuf[20]; int pcnt; for (;;) { while (isspace(*lptr)) lptr++; if (isdigit(c = *lptr) || c == '-' || c == '+') { if (c== '-' || c == '+') { if (c=='-') sign = -1; else sign = 1; if (!isdigit(*++lptr)) { /* yylval = sign; return (NUMBER); */ return yylex(); /* skip the '-' sign */ } } else sign = 1; yylval = 0; while (isdigit(c = *lptr++)) yylval = 10*yylval + c - '0'; yylval *= sign; lptr--; return (NUMBER); } else if (isalpha(c)) { p = idbuf; while (isalpha(c = *lptr++) || c=='.') *p++ = c; *p = '\0'; lptr--; return (lookup(idbuf)); } else if (c == '(') { pcnt = 0; do { c = *lptr++; if (c == '\0') return(c); else if (c == '(') pcnt++; else if (c == ')') pcnt--; } while (pcnt > 0); } else return (*lptr++); } } struct table { char *name; int type, value; }; struct table mdtab[] = { {"january", MONTH, 1}, {"february", MONTH, 2}, {"march", MONTH, 3}, {"april", MONTH, 4}, {"may", MONTH, 5}, {"june", MONTH, 6}, {"July", MONTH, 7}, {"august", MONTH, 8}, {"september", MONTH, 9}, {"sept", MONTH, 9}, {"october", MONTH, 10}, {"november", MONTH, 11}, {"december", MONTH, 12}, {"sunday", DAY, 0}, {"monday", DAY, 1}, {"tuesday", DAY, 2}, {"tues", DAY, 2}, {"wednesday", DAY, 3}, {"wednes", DAY, 3}, {"thursday", DAY, 4}, {"thur", DAY, 4}, {"thurs", DAY, 4}, {"friday", DAY, 5}, {"saturday", DAY, 6}, {0, 0, 0}}; #define HRS *60 #define HALFHR 30 struct table mztab[] = { {"a.m.", MERIDIAN, AM}, {"am", MERIDIAN, AM}, {"p.m.", MERIDIAN, PM}, {"pm", MERIDIAN, PM}, {"nst", ZONE, 3 HRS + HALFHR}, /* Newfoundland */ {"n.s.t.", ZONE, 3 HRS + HALFHR}, {"ast", ZONE, 4 HRS}, /* Atlantic */ {"a.s.t.", ZONE, 4 HRS}, {"adt", DAYZONE, 4 HRS}, {"a.d.t.", DAYZONE, 4 HRS}, {"est", ZONE, 5 HRS}, /* Eastern */ {"e.s.t.", ZONE, 5 HRS}, {"edt", DAYZONE, 5 HRS}, {"e.d.t.", DAYZONE, 5 HRS}, {"cst", ZONE, 6 HRS}, /* Central */ {"c.s.t.", ZONE, 6 HRS}, {"cdt", DAYZONE, 6 HRS}, {"c.d.t.", DAYZONE, 6 HRS}, {"mst", ZONE, 7 HRS}, /* Mountain */ {"m.s.t.", ZONE, 7 HRS}, {"mdt", DAYZONE, 7 HRS}, {"m.d.t.", DAYZONE, 7 HRS}, {"pst", ZONE, 8 HRS}, /* Pacific */ {"p.s.t.", ZONE, 8 HRS}, {"pdt", DAYZONE, 8 HRS}, {"p.d.t.", DAYZONE, 8 HRS}, {"yst", ZONE, 9 HRS}, /* Yukon */ {"y.s.t.", ZONE, 9 HRS}, {"ydt", DAYZONE, 9 HRS}, {"y.d.t.", DAYZONE, 9 HRS}, {"hst", ZONE, 10 HRS}, /* Hawaii */ {"h.s.t.", ZONE, 10 HRS}, {"hdt", DAYZONE, 10 HRS}, {"h.d.t.", DAYZONE, 10 HRS}, {"gmt", ZONE, 0 HRS}, {"g.m.t.", ZONE, 0 HRS}, {"bst", DAYZONE, 0 HRS}, /* British Summer Time */ {"b.s.t.", DAYZONE, 0 HRS}, {"eet", ZONE, 0 HRS}, /* European Eastern Time */ {"e.e.t.", ZONE, 0 HRS}, {"eest", DAYZONE, 0 HRS}, /* European Eastern Summer Time */ {"e.e.s.t.", DAYZONE, 0 HRS}, {"met", ZONE, -1 HRS}, /* Middle European Time */ {"m.e.t.", ZONE, -1 HRS}, {"mest", DAYZONE, -1 HRS}, /* Middle European Summer Time */ {"m.e.s.t.", DAYZONE, -1 HRS}, {"wet", ZONE, -2 HRS }, /* Western European Time */ {"w.e.t.", ZONE, -2 HRS }, {"west", DAYZONE, -2 HRS}, /* Western European Summer Time */ {"w.e.s.t.", DAYZONE, -2 HRS}, {"jst", ZONE, -9 HRS}, /* Japan Standard Time */ {"j.s.t.", ZONE, -9 HRS}, /* Japan Standard Time */ /* No daylight savings time */ {"aest", ZONE, -10 HRS}, /* Australian Eastern Time */ {"a.e.s.t.", ZONE, -10 HRS}, {"aesst", DAYZONE, -10 HRS}, /* Australian Eastern Summer Time */ {"a.e.s.s.t.", DAYZONE, -10 HRS}, {"acst", ZONE, -(9 HRS + HALFHR)}, /* Australian Central Time */ {"a.c.s.t.", ZONE, -(9 HRS + HALFHR)}, {"acsst", DAYZONE, -(9 HRS + HALFHR)}, /* Australian Central Summer */ {"a.c.s.s.t.", DAYZONE, -(9 HRS + HALFHR)}, {"awst", ZONE, -8 HRS}, /* Australian Western Time */ {"a.w.s.t.", ZONE, -8 HRS}, /* (no daylight time there, I'm told */ {0, 0, 0}}; struct table unittb[] = { {"year", MUNIT, 12}, {"month", MUNIT, 1}, {"fortnight", UNIT, 14*24*60}, {"week", UNIT, 7*24*60}, {"day", UNIT, 1*24*60}, {"hour", UNIT, 60}, {"minute", UNIT, 1}, {"min", UNIT, 1}, {"second", SUNIT, 1}, {"sec", SUNIT, 1}, {0, 0, 0}}; struct table othertb[] = { {"tomorrow", UNIT, 1*24*60}, {"yesterday", UNIT, -1*24*60}, {"today", UNIT, 0}, {"now", UNIT, 0}, {"last", NUMBER, -1}, {"this", UNIT, 0}, {"next", NUMBER, 2}, {"first", NUMBER, 1}, /* {"second", NUMBER, 2}, */ {"third", NUMBER, 3}, {"fourth", NUMBER, 4}, {"fifth", NUMBER, 5}, {"sixth", NUMBER, 6}, {"seventh", NUMBER, 7}, {"eigth", NUMBER, 8}, {"ninth", NUMBER, 9}, {"tenth", NUMBER, 10}, {"eleventh", NUMBER, 11}, {"twelfth", NUMBER, 12}, {"ago", AGO, 1}, {0, 0, 0}}; struct table milzone[] = { {"a", ZONE, 1 HRS}, {"b", ZONE, 2 HRS}, {"c", ZONE, 3 HRS}, {"d", ZONE, 4 HRS}, {"e", ZONE, 5 HRS}, {"f", ZONE, 6 HRS}, {"g", ZONE, 7 HRS}, {"h", ZONE, 8 HRS}, {"i", ZONE, 9 HRS}, {"k", ZONE, 10 HRS}, {"l", ZONE, 11 HRS}, {"m", ZONE, 12 HRS}, {"n", ZONE, -1 HRS}, {"o", ZONE, -2 HRS}, {"p", ZONE, -3 HRS}, {"q", ZONE, -4 HRS}, {"r", ZONE, -5 HRS}, {"s", ZONE, -6 HRS}, {"t", ZONE, -7 HRS}, {"u", ZONE, -8 HRS}, {"v", ZONE, -9 HRS}, {"w", ZONE, -10 HRS}, {"x", ZONE, -11 HRS}, {"y", ZONE, -12 HRS}, {"z", ZONE, 0 HRS}, {0, 0, 0}}; lookup(id) char *id; { #define gotit (yylval=i->value, i->type) char idvar[128]; register char *j, *k; register struct table *i; int abbrev; (void) strcpy(idvar, id); j = idvar; k = id - 1; while (*++k) *j++ = isupper(*k) ? tolower(*k) : *k; *j = '\0'; if (strlen(idvar) == 3) abbrev = 1; else if (strlen(idvar) == 4 && idvar[3] == '.') { abbrev = 1; idvar[3] = '\0'; } else abbrev = 0; for (i = mdtab; i->name; i++) { k = idvar; for (j = i->name; *j++ == *k++;) { if (abbrev && j == i->name+3) return gotit; if (j[-1] == 0) return gotit; } } for (i = mztab; i->name; i++) if (strcmp(i->name, idvar) == 0) return gotit; for (i=mztab; i->name; i++) if (strcmp(i->name, idvar) == 0) return gotit; for (i=unittb; i->name; i++) if (strcmp(i->name, idvar) == 0) return gotit; if (idvar[strlen(idvar)-1] == 's') idvar[strlen(idvar)-1] = '\0'; for (i=unittb; i->name; i++) if (strcmp(i->name, idvar) == 0) return gotit; for (i = othertb; i->name; i++) if (strcmp(i->name, idvar) == 0) return gotit; if (strlen(idvar) == 1 && isalpha(*idvar)) { for (i = milzone; i->name; i++) if (strcmp(i->name, idvar) == 0) return gotit; } return ID; } time_t getdate(p, now) char *p; struct timeb *now; { #define mcheck(f) if (f>1) err++ time_t monthadd(); int err; struct tm *lt; struct timeb ftz; time_t sdate, tod; lptr = p; if (now == ((struct timeb *) NULL)) { now = &ftz; ftime(&ftz); } lt = localtime(&now->time); year = lt->tm_year; month = lt->tm_mon+1; day = lt->tm_mday; relsec = 0; relmonth = 0; timeflag=zoneflag=dateflag=dayflag=relflag=0; ourzone = now->timezone; daylight = MAYBE; hh = mm = ss = 0; merid = 24; if (err = yyparse()) return (-1); mcheck(timeflag); mcheck(zoneflag); mcheck(dateflag); mcheck(dayflag); if (err) return (-1); if (dateflag || timeflag || dayflag) { sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,daylight); if (sdate < 0) return -1; } else { sdate = now->time; if (relflag == 0) sdate -= (lt->tm_sec + lt->tm_min*60 + lt->tm_hour*(60L*60L)); } sdate += relsec; sdate += monthadd(sdate, relmonth); if (dayflag && !dateflag) { tod = dayconv(dayord, dayreq, sdate); sdate += tod; } return sdate; } yyerror(s) char *s; {} SHAR_EOF if test 12589 -ne "`wc -c < 'getdate.y'`" then echo shar: "error transmitting 'getdate.y'" '(should have been 12589 characters)' fi fi echo shar: "extracting 'install.sh'" '(5843 characters)' if test -f 'install.sh' then echo shar: "will not over-write existing file 'install.sh'" else cat << \SHAR_EOF > 'install.sh' : '@(#)install.sh 1.16 10/29/86' if test "$#" != 6 then echo "usage: $0 spooldir libdir bindir nuser ngroup ostype" exit 1 fi SPOOLDIR=$1 LIBDIR=$2 BINDIR=$3 NEWSUSR=$4 NEWSGRP=$5 OSTYPE=$6 : Get name of local system case $OSTYPE in usg) SYSNAME=`uname -n` if test ! -d $LIBDIR/history.d then mkdir $LIBDIR/history.d chown $NEWSUSR $LIBDIR/history.d chgrp $NEWSGRP $LIBDIR/history.d fi;; v7) SYSNAME=`uuname -l` touch $LIBDIR/history.pag $LIBDIR/history.dir;; *) echo "$0: Unknown Ostype" exit 1;; esac if test "$SYSNAME" = "" then echo "$0: Cannot get system name" exit 1 fi : Ensure SPOOLDIR exists for i in $SPOOLDIR $SPOOLDIR/.rnews do if test ! -d $i then mkdir $i fi chmod 777 $i chown $NEWSUSR $i chgrp $NEWSGRP $i done chown $NEWSUSR $LIBDIR chgrp $NEWSGRP $LIBDIR : Ensure certain files in LIBDIR exist touch $LIBDIR/history $LIBDIR/active $LIBDIR/log $LIBDIR/errlog $LIBDIR/users chmod 666 $LIBDIR/users : If no sys file, make one. if test ! -f $LIBDIR/sys then echo echo Making a $LIBDIR/sys file to link you to oopsvax. echo You must change oopsvax to your news feed. echo If you are not in Japan, remove '"fj"' from your line in the sys file. cat > $LIBDIR/sys << EOF $SYSNAME:world,fj,comp,sci,news,rec,soc,talk,misc,net,mod,to:: oopsvax:world,fj,comp,sci,news,rec,soc,talk,misc,net,mod,to.oopsvax:: EOF fi : If no seq file, make one. if test ! -s $LIBDIR/seq then echo '100' >$LIBDIR/seq fi : If no mailpaths, make one. if test ! -s $LIBDIR/mailpaths then cat <$LIBDIR/mailpaths backbone %s@junet internet %s@junet E_O_F : echo "I have created $LIBDIR/mailpaths for you. The paths are certainly wrong." : echo "You must correct them manually to be able to post to moderated groups." fi sh makeactive.sh $LIBDIR $SPOOLDIR $NEWSUSR $NEWSGRP for i in $LIBDIR/ngfile $BINDIR/inews $LIBDIR/localgroups $LIBDIR/moderators \ $LIBDIR/cunbatch $LIBDIR/c7unbatch do if test -f $i then echo "$i is no longer used. You should remove it." fi done for i in $LIBDIR/csendbatch $LIBDIR/c7sendbatch do if test -f $i then echo "$i is no longer used. You should remove it after" echo "changing your crontab entry to use sendbatch [flags]" fi done if test -f $BINDIR/cunbatch then echo "$BINDIR/cunbatch is not used by the new batching scheme." echo "You should remove it when all of your neighbors have upgraded." fi cat >$LIBDIR/aliases.new </tmp/$$aliases sort $LIBDIR/aliases.new | sed -e 's/ */ /g' -e 's/ */ /g' >/tmp/$$aliases.new comm -23 /tmp/$$aliases.new /tmp/$$aliases >/tmp/$$comm if test -s /tmp/$$comm then echo "The following suggested aliases are missing or incorrect in your" echo "$LIBDIR/aliases file. It is suggested you add them." echo "" cat /tmp/$$comm echo "" echo "A suggested aliases file has been left in $LIBDIR/aliases.new" echo "for your convenience." rm /tmp/$$comm /tmp/$$aliases else rm /tmp/$$comm /tmp/$$aliases $LIBDIR/aliases.new fi fi : if no distributions file, make one if test ! -f $LIBDIR/distributions then cat >$LIBDIR/distributions < 'iparams.h' /* * iparams - parameters for inews. */ /* @(#)iparams.h 2.17 11/21/86 */ #include "params.h" #include extern int errno; /* external declarations specific to inews */ extern char nbuf[LBUFLEN], *ARTICLE, *INFILE, *ALIASES, *PARTIAL; #ifndef ROOTID extern int ROOTID; #endif #ifdef NOTIFY extern char *TELLME; #endif /* NOTIFY */ struct msgtype { char *m_name; char *m_who_to; int (*m_func)(); }; extern struct msgtype msgtype[]; extern FILE *infp, *actfp; extern int tty, is_ctl; extern char filename[BUFLEN], is_mod[NAMELEN], not_here[SBUFLEN], *DFLTNG; SHAR_EOF if test 577 -ne "`wc -c < 'iparams.h'`" then echo shar: "error transmitting 'iparams.h'" '(should have been 577 characters)' fi fi echo shar: "done with directory 'src'" cd .. exit 0 # End of shell archive