sources-request@mirror.UUCP (11/06/86)
Submitted by: seismo!rick (Rick Adams) Mod.sources: Volume 7, Issue 54 Archive-name: 2.11news/Part15 # To extract, sh this file # # news 2.11 source part 5 of 9 # if test ! -d src then mkdir src fi echo x - src/expire.c 1>&2 sed 's/.//' >src/expire.c <<'*-*-END-of-src/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.47 10/23/86"; -#endif /* SCCSID */ - -#include "params.h" -#include <errno.h> -#if defined(BSD4_2) || defined(BSD4_1C) -# include <sys/dir.h> -# include <sys/file.h> -#else -# include "ndir.h" -# ifdef LOCKF -# include <unistd.h> -# endif /* LOCKF */ -#endif - -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;i<NUNREC;i++) - h.unrec[i] = NULL; - - while (TRUE) { - fp = NULL; - if (nohistory) { - recdate[0] = '\0'; - do { - if (ngdir == NULL) { - if ( ngdirp != NULL ) - closedir(ngdirp); - if (fgets(afline, BUFLEN, ohfd) == NULL) - goto out; - (void) strcpy(nbuf, afline); - p1 = index(nbuf, ' '); - if (p1 == NULL) - p1 = index(nbuf, '\n'); - if (p1 != NULL) - *p1 = NULL; - if (!ngmatch(nbuf, ngpat)) - continue; - - /* Change a group name from - a.b.c to a/b/c */ - for (p1=nbuf; *p1; p1++) - if (*p1 == '.') - *p1 = '/'; - - if ((ngdirp = opendir(nbuf)) == NULL) - continue; - - } - ngdir = readdir(ngdirp); - /* Continue looking if not an article. */ - } while (ngdir == NULL || !islegal(fn,nbuf,ngdir->d_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; i<NUNREC; i++) - if (h.unrec[i] != NULL) - free(h.unrec[i]); - else - break; - if (!hread(&h, fp, TRUE)) { - printf("Garbled article %s.\n", filename); - (void) fclose(fp); - /* - * Usually means disk ran out of space. - * Drop this article from our history file - * completely, so we have a chance of picking - * it up again from another feed .. - */ - goto nailit; - } - if (nohistory) { - if (recdate[0] == '\0') { - struct stat statb; - if (fstat(fileno(fp), &statb) < 0) - rectime = cgtdate(h.subdate); - else - rectime = statb.st_mtime; - } else - rectime = cgtdate(recdate); - } - if (dorebuild) { - register char *cp, *lastslash; - register struct multhist *mhp; - - /* - * Format of filename until now was /SPOOL/a/b/c/4 - * and this code changes it to a.b.c/4 (the correct - * kind of entry in the history file.) - * - * This can't be a strcpy because the addresses overlap - * and some machines can't handle that. - */ - p1 = filename; - cp = p1 + strlen(SPOOL); - while (*++cp) { - if (*cp == '/') { - lastslash = p1; - *p1++ = '.'; - } else - *p1++ = *cp; - } - *p1 = '\0'; - *lastslash = '/'; - - if ((cp = index(h.nbuf, NGDELIM)) == NULL) { - struct tm *tm; -saveit: - tm = gmtime(&rectime); - if (fprintf(nhfd, -#ifdef USG - "%s\t%s%2.2d/%2.2d/%d %2.2d:%2.2d\t%s\n", -#else /* !USG */ - "%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, 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) umask(0); - (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); -} *-*-END-of-src/expire.c-*-* echo x - src/readr.c 1>&2 sed 's/.//' >src/readr.c <<'*-*-END-of-src/readr.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. - * - * readr - /bin/mail and msgs interface and associated functions. - */ - -#ifdef SCCSID -static char *SccsId = "@(#)readr.c 2.58 10/23/86"; -#endif /* SCCSID */ - -#include "rparams.h" -#if defined(BSD4_2) || defined(BSD4_1C) -#include <sys/dir.h> -#else -#include "ndir.h" -#endif /* !BSD4_2 && !BSD4_1C */ -#include <setjmp.h> -#include <errno.h> - -extern int errno; - -char *Progname = "readnews"; /* used by xerror to identify failing program */ - -static char lbuf[BUFLEN*2]; -long atol(); - -#define saveart oobit = bit;strcpy(ofilename1, filename);strcpy(ogroupdir, groupdir);hptr = h;h = hold;hold = hptr;ongsize = pngsize -#define NLINES(h, fp) (h->numlines[0] ? h->intnumlines : (h->intnumlines=linecnt(fp),sprintf(h->numlines, "%d", h->intnumlines), h->intnumlines)) - -char *tft = "/tmp/folXXXXXX"; - -/* - * These were made static for u370 with its buggy cc. - * I judged it better to have one copy with no ifdefs than - * to conditionally compile them as automatic variables - * in readr (which they originally were). Performance - * considerations might warrant moving some of the simple - * things into register variables, but I don't know what - * breaks the u370 cc. - */ -static char goodone[BUFLEN]; /* last decent article */ -static char ogroupdir[BUFLEN]; /* last groupdir */ -static char address[PATHLEN]; /* for reply copy */ -static char edcmdbuf[128]; -static int rfq = 0; /* for last article */ -static long ongsize; /* Previous ngsize */ -static long pngsize; /* Printing ngsize */ -static char *bptr; /* temp pointer. */ -static struct srec srec; /* srec for sys file entries */ -static char *tfilename; /* temporary file name */ -static char ofilename1[BUFLEN]; /* previous file name */ -static struct hbuf hbuf1, hbuf2, /* for minusing */ - *h = &hbuf1, /* current header */ - *hold = &hbuf2, /* previous header */ - *hptr; /* temporary */ -static char *ptr1, *ptr2, *ptr3; /* for reply manipulation */ -static int abs = FALSE; /* TRUE if we asked absolutely */ -static char tf[100]; -static long oobit; /* last bit, really */ -static int dgest = 0; -static FILE *ofp; /* Current output file to terminal*/ -static FILE *fp; /* current article to be printed*/ -static int holdup; /* 1 iff should stop before hdr */ -static int ignorenews; /* 1 iff readnews -p > /dev/null*/ -static time_t timelastsaved; /* time newsrc last written out */ -static jmp_buf sigjmpbuf; /* for signal processing */ -static int canlongjmp; /* TRUE if setjmp on sigjmp valid */ - -int catchcont(); -readr() -{ - register char *m = getenv("MORE"); - register char *m2, cc; - - /* - * Turn of more's 'l' option, so \f kludge will work. - * This is really revolting! - */ - if (m2 = m) { - while (cc = *m++) - if (cc != 'l') - *m2++ = cc; - *m2 = '\0'; - } - -#ifdef DEBUG - fprintf(stderr, "readr()\n"); -#endif - if (aflag) { - if (*datebuf) { - if ((atime = cgtdate(datebuf)) == -1) - xerror("Cannot parse date string"); - } else - atime = 0; - } - - if (pflag && ignoring()) - ignorenews = TRUE; - - if (xflag) - uflag = 0; - if (uflag) - (void) time(&timelastsaved); - - ofp = stdout; - if (cflag && coptbuf[0] != '\0') { - (void) umask(022); - (void) mktemp(outfile); /* get "unique" file name */ - (void) close(creat(outfile,0666)); - ofp = xfopen(outfile, "w"); - (void) umask(N_UMASK); - cflag = FALSE; - pflag = TRUE; - } - - /* loop reading articles. */ - fp = NULL; - obit = -1; - nextng(); - for ( ;; ) { - if (getnextart(FALSE)) - break; -#ifdef DEBUG - fprintf(stderr,"after getnextart, fp %x, pos %ld, bit %ld, group '%s', filename '%s'\n", - fp, ftell(fp), bit, groupdir, filename); -#endif - (void) strcpy(goodone, filename); - if (pflag || lflag || eflag) { - /* This code should be gotten rid of */ - if (SigTrap) { - qfflush(ofp); - fprintf(ofp, "\n"); - cdump(ofp); - xxit(0); /* kludge! drop when qfflush works */ - return; - } - clear(bit); - nextbit(); - FCLOSE(fp); - continue; - } - for ( ;; ) { - char *pp; - int nlines; - int (*ointr)(); -#ifdef SIGCONT - int (*ocont)(); -#endif - (void) setjmp(sigjmpbuf); - canlongjmp = TRUE; - - SigTrap = FALSE; - if (!cflag) { - if (rfq) - (void) sprintf(bfr, "Last article. [qfr] "); - else { - nlines = NLINES(h, fp); - if (nlines <= 0) { - (void) sprintf(bfr, "(0 lines) Next? [nqfr] "); - FCLOSE(fp); - } else { - (void) sprintf(bfr, "(%d lines) More? [ynq] ", nlines); - } - } - } else - (void) sprintf(bfr, "? "); - fprintf(ofp, "%s", bfr); - (void) fflush(ofp); - bptr = lbuf; - ointr = signal(SIGINT, catchcont); -#ifdef SIGCONT - ocont = signal(SIGCONT, catchcont); -#endif - pp = fgets(bptr, BUFLEN, stdin); - canlongjmp = FALSE; - (void) signal(SIGINT, ointr); -#ifdef SIGCONT - (void) signal(SIGCONT, ocont); -#endif - if (pp != NULL) - break; - if (!SigTrap) - return; -#ifdef SIGCONT - if (SigTrap != SIGCONT) -#endif - fprintf(ofp, "\n"); - } - (void) nstrip(bptr); - while (*bptr == ' ' || *bptr == '\t') - bptr++; - if (command()) - break; - } - - if (!pflag && !news) { - fprintf(stderr, "No news.\n"); - } - cout(ofp); -} - -#define EOL() if (*bptr != '\0') { fprintf(ofp, "? for commands.\n"); return FALSE; } -/* - * Process one command, which has already been typed in. - */ -command() -{ - char *findhist(); - long i; - - switch (*bptr++) { - - /* No. Go on to next article. */ - case 'n': - EOL(); - readmode = NEXT; - if (!cflag) - FCLOSE(fp); - fprintf(ofp, "\n"); - clear(bit); - saveart; - nextbit(); - break; - - /* Undigestify the article. */ - case 'd': - dgest = 1; - /* fall through */ - - /* yes: print this article, go on. */ - case 'y': - EOL(); - /* fall through. */ - - /* The user hit return. Default is 'y' unless rfq, then it's 'q'. */ - case '\0': - if (!bptr[-1] && rfq) - return TRUE; - readmode = NEXT; - showtail(fp); - clear(bit); - saveart; - nextbit(); - break; - - /* - * Unsubscribe to the newsgroup and go on to next group - */ - case 'u': - fprintf(ofp, "To unsubscribe, use 'U'\n"); - break; - - case 'U': - fprintf(ofp, "Unsubscribing to newsgroup: %s\n", groupdir); - obit = -1; - FCLOSE(fp); - if (cflag) - clear(bit); - else - putc('\n', ofp); - rfq = 0; - zapng = TRUE; - saveart; - if (nextng()) { - if (actdirect == BACKWARD) - fprintf(ofp, "Can't back up.\n"); - else - return TRUE; - } - break; - - /* Print the current version of news */ - case 'v': - fprintf(ofp, "News version: %s\n", news_version); - break; - - /* reprint the article */ - case 'p': - EOL(); - if (!cflag) - goto minus; - readmode = NEXT; - if (!cflag) { - FCLOSE(fp); - bit = last; - putc('\n', ofp); - } - obit = -1; - break; - - /* decrypt joke */ - case 'D': - caesar_command(); - readmode = NEXT; - clear(bit); - saveart; - nextbit(); - break; - - /* write out the article someplace */ - case 's': - case 'w': - { - char *grn = groupdir; - tfilename = filename; - if (*bptr == '-') { - bptr++; - grn = ogroupdir; - if (*ofilename1) - tfilename = ofilename1; - } - if (*bptr != '\0' && *bptr != ' ') { - fprintf(ofp, "Bad file name.\n"); - break; - } - while (*bptr == ' ') - bptr++; - if (*bptr != '|' && *bptr != '/') { - char hetyped[BUFLEN]; - char *boxptr; - struct stat stbf; - (void) strcpy(hetyped, bptr); - if (hetyped[0] == '~' && hetyped[1] == '/') { - strcpy(hetyped, bptr+2); - strcpy(bptr, userhome); - } else if (boxptr = getenv("NEWSBOX")) { - if (index(boxptr, '%')) { - sprintf(bptr, boxptr, grn); - if (stat(bptr, &stbf) < 0) { - if (mkdir(bptr, 0777) < 0) { - fprintf(ofp, "Cannot create directory %s", bptr); - break; - } - } else if ((stbf.st_mode & S_IFMT) != S_IFDIR) { - fprintf(ofp, "%s is not a directory", bptr); - break; - } - } else - strcpy(bptr, boxptr); - } else - (void) strcpy(bptr, "."); - (void) strcat(bptr, "/"); - if (hetyped[0] != '\0') - (void) strcat(bptr, hetyped); - else - (void) strcat(bptr, "Articles"); - } - fwait(fsubr(save, tfilename, bptr)); - } - break; - - /* back up */ - case '-': -minus: - rfq = 0; - abs = TRUE; - if (!*ofilename1) { - fprintf(ofp, "Can't back up.\n"); - break; - } - if (cflag) - clear(bit); - else { - FCLOSE(fp); - putc('\n', ofp); - } - hptr = h; - h = hold; - hold = hptr; - (void) strcpy(bfr, filename); - (void) strcpy(filename, ofilename1); - (void) strcpy(ofilename1, bfr); - obit = bit; - if (strcmp(groupdir, ogroupdir)) { - (void) strcpy(bfr, groupdir); - selectng(ogroupdir, TRUE, FALSE); - (void) strcpy(groupdir, ogroupdir); - (void) strcpy(ogroupdir, bfr); - ngrp = 1; - back(); - } - bit = oobit; - oobit = obit; - obit = -1; - (void) getnextart(TRUE); - return FALSE; - - /* skip forwards */ - case '+': -caseplus: - if (*bptr == '\0') - (void) strcat(bptr, "1"); - rfq = 0; - if (cflag) - clear(bit); - saveart; - last = bit; - for (i = 0; i < atol(bptr); i++) { - nextbit(); - if ((bit > pngsize) || (rflag && bit < 1)) - break; - } - if (!cflag) { - putc('\n', ofp); - FCLOSE(fp); - } - obit = -1; - break; - - /* exit - time updated to that of most recently read article */ - case 'q': - EOL(); - return TRUE; - - /* exit - no time update. */ - case 'x': - EOL(); - xxit(0); - - /* cancel the article. */ - case 'c': - (void) cancel_command(); - break; - - /* escape to shell */ - case '!': - fwait(fsubr(ushell, bptr, (char *)NULL)); - fprintf(ofp, "\n"); - hdr(); - break; - - /* mail reply */ - case 'r': - (void) reply_command(); - break; - - /* send to some system */ - case 'X': - xmit_command(); - break; - /* mark the rest of the articles in this group as read */ - case 'K': - saveart; - while (bit <= pngsize && bit >= minartno) { - clear(bit); - nextbit(); - } - FCLOSE(fp); - break; - - /* next newsgroup */ - case 'P': - *bptr = '-'; - case 'N': - FCLOSE(fp); - if (next_ng_command()) - return TRUE; - break; - - case 'b': /* back up 1 article */ - i = bit - 1; - goto tryartnum; - case '0': /* specific no. */ - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - (void) sscanf(--bptr, "%ld", &i); - if (i == 0) { - fprintf(ofp, "Bad article no.\n"); - break; - } - if (i > pngsize) { - fprintf(ofp, "Not that many articles.\n"); - break; - } -tryartnum: - readmode = SPEC; - abs = TRUE; - bit = i; - obit = -1; - if (!cflag) { - putc('\n', ofp); - FCLOSE(fp); - } - rfq = 0; - break; - - /* specific message ID. */ - case '<': - ptr1 = findhist(--bptr); - if (ptr1 == NULL) { - fprintf(ofp, "No such article: %s.\n", bptr); - break; - } - ptr2 = index(ptr1, '\t'); - ptr3 = index(++ptr2, '\t'); - ptr2 = index(++ptr3, ' '); - if (ptr2) - *ptr2 = '\0'; - ptr2 = index(ptr3, '/'); - if (!ptr2) { - *ptr3 = '\0'; - if (strcmp(++ptr3, "cancelled") == 0) { - fprintf(ofp, "Article %s has been cancelled.\n", - bptr); - break; - } - fprintf(ofp, "Article %s (dated %s) has expired.\n", - bptr, index(ptr1, '\t')+1); - break; - } - *ptr2++ = '\0'; - abs = TRUE; - if (cflag) - clear(bit); - else { - FCLOSE(fp); - putc('\n', ofp); - } - saveart; - (void) strcpy(ogroupdir, ptr3); - if (strcmp(groupdir, ogroupdir)) { - (void) strcpy(bfr, groupdir); - selectng(ogroupdir, TRUE, PERHAPS); - (void) strcpy(groupdir, ogroupdir); - (void) strcpy(ogroupdir, bfr); - ngrp = 1; - back(); - } - (void) sscanf(ptr2, "%ld", &bit); - oobit = obit; - obit = -1; - i = bit; - (void) getnextart(TRUE); - if (bit != i || strcmp(groupdir, ptr3) != 0) { - (void) fprintf(ofp, "Can't read %s/%ld.\n", ptr3, i); - goto minus; - } - rfq = 0; - break; - - /* follow-up article */ - case 'f': - if (strcmp(h->followto, "poster") == 0) { - (void) reply_command(); - break; - } - - if (*bptr == '-') - tfilename = ofilename1; - else - tfilename = filename; - (void) sprintf(bfr,"%s/%s %s", BIN, "postnews", tfilename); - (void) system(bfr); - break; - - /* erase - pretend we haven't seen this article. */ - case 'e': - if (rfq || *bptr == '-') { - if (strcmp(groupdir, ogroupdir)) { - i = bit; - (void) strcpy(bfr, groupdir); - selectng(ogroupdir, FALSE, PERHAPS); - set(oobit); - fprintf(ofp,"Holding article %ld newsgroup %s\n", oobit, ogroupdir), - (void) strcpy(groupdir, ogroupdir); - selectng(bfr, FALSE, FALSE); - bit = i; - } else { - fprintf(ofp,"Holding article %ld\n", oobit); - set(oobit); - } - } else { - fprintf(ofp,"Holding article %ld\n", bit); - set(bit); - goto caseplus; /* skip this article for now */ - } - break; - - case 'H': - case 'h': - if (!hflag) - dash(8, ofp); - if (*bptr == '-') { - if (oobit > 0) - fprintf(ofp, "Article %ld:\n", oobit); - hprint(hold, ofp, 1 + (bptr[-1]=='H')); - } else { - fprintf(ofp, "Article %ld of %ld: %s\n", - rfq ? oobit : bit, pngsize, h->ident); - hprint(h, ofp, 1 + (bptr[-1]=='H')); - } - if (!hflag) - dash(8, ofp); - break; - - case '#': - fprintf(ofp, "Article %ld of %ld: newsgroup %s\n", - rfq ? oobit : bit, pngsize, rfq ? ogroupdir : groupdir); - break; - - /* error */ - case '?': - help(ofp); - break; - default: - fprintf(ofp, "? for commands.\n"); - break; - } - - return FALSE; -} - -cancel_command() -{ - int notauthor; - tfilename = filename; - hptr = h; - if (*bptr == '-') { - if (*ofilename1) { - tfilename = ofilename1; - hptr = hold; - } - bptr++; - } - EOL(); - readmode = SPEC; - (void) strcpy(rcbuf, hptr->path); - ptr1 = index(rcbuf, ' '); - if (ptr1) - *ptr1 = 0; - notauthor = strcmp(username, rcbuf); - if (uid != ROOTID && uid && notauthor) { - fprintf(ofp, "Can't cancel what you didn't write.\n"); - return FALSE; - } - if (!cancel(ofp, hptr, notauthor) && hptr == h) { - clear(bit); - saveart; - nextbit(); - obit = -1; - if (!cflag) - putc('\n', ofp); - FCLOSE(fp); - } - return TRUE; -} - -reply_command() -{ - register char *pathptr; - int edit = 1; - char *ed, *fbp; - int idlen; - FILE *tfp; - char *replyname(); - char subj[BUFLEN]; - char folbuf[BUFLEN]; - struct stat statb; - long creatm; - - hptr = h; - while (*bptr && index("d-", *bptr)) { - switch (*bptr) { - /* Followup the previous article. */ - case '-': - hptr = hold; - break; - - /* Don't edit the headers */ - case 'd': - edit = 0; - break; - } - bptr++; - } - EOL(); - ptr1 = index(MAILPARSER, ' '); - if (ptr1) - *ptr1 = '\0'; - if (edit && access(MAILPARSER, 1)) { -#ifdef IHCC - fprintf(stderr, "Can't edit headers, 'recmail' missing.\n"); -#else - fprintf(stderr, "Can't edit headers without %s\n", MAILPARSER); -#endif - edit = 0; - } - if (ptr1) - *ptr1 = ' '; - - *rcbuf = '\0'; - pathptr = replyname(hptr);; - for (ptr1 = address, ptr2 = pathptr; *ptr2; ptr1++, ptr2++) { - if (index("\"\\$", *ptr2)) - *ptr1++ = '\\'; - *ptr1 = *ptr2; - } - *ptr1 = '\0'; - - folbuf[0] = '\0'; /* References */ - if (hptr->followid[0]) { - fbp = hptr->followid; - idlen = strlen(hptr->ident); - - /* - * If the references line is too long, truncate it. - * The "3" is for the comma, the space, and the '\0' at - * the end of the string. - */ - while (fbp && strlen(fbp) + idlen > BUFLEN - 3) - fbp = index(fbp + 1, '<'); - if (fbp != NULL) { - (void) strcpy(folbuf, fbp); - (void) strcat(folbuf, ", "); - } - } - (void) strcat(folbuf, hptr->ident); - - (void) strcpy(subj, hptr->title); /* Subject */ - while (isspace(*bptr)) - bptr++; - if (*bptr != '\0') - (void) strcpy(subj, bptr); - if (!prefix(subj, "Re:")){ - (void) strcpy(bfr, subj); - (void) sprintf(subj, "Re: %s", bfr); - } - if (!edit) { - fprintf(ofp, "To: %s\n", pathptr); - ed = index(MAILER, '%'); - if (ed && ed[1] == 's') - fprintf(ofp, "Subject: %s\n", subj); - (void) fflush(ofp); - } - - /* Put the user in the editor to create the body of the followup. */ - if (edit) { - int oumask; - - (void) strcpy(tf, tft); - (void) mktemp(tf); - - ed = getenv("EDITOR"); - if (ed == NULL) - ed = DFTEDITOR; - - oumask = umask(077); - if ((tfp = fopen(tf, "w")) == NULL) { - perror(tf); - creatm = 0L; - } else { - fprintf(tfp, "To: %s\n", pathptr); - fprintf(tfp, "Subject: %s\n", subj); -#ifdef INTERNET - fprintf(tfp, "News-Path: %s\n", hptr->path); -#endif /* INTERNET */ - fprintf(tfp, "References: %s\n\n", folbuf); - fstat(fileno(tfp), &statb); - creatm = statb.st_mtime; - (void) fclose(tfp); - } - (void) umask(oumask); - - (void) sprintf(edcmdbuf, "%s %s", ed, tf); - (void) system(edcmdbuf); - (void) strcpy(rcbuf, MAILPARSER); - (void) strcat(rcbuf, " -t"); - (void) strcat(rcbuf, " < "); - (void) strcat(rcbuf, tf); - if (access(tf, 4) || stat(tf, &statb)) { - fprintf(stderr, "Reply not sent: no input file.\n"); - return FALSE; - } - if (statb.st_mtime == creatm) { - fprintf(stderr, "Reply not sent: cancelled.\n"); - (void) unlink(tf); - return FALSE; - } - fprintf(ofp,"Sending reply.\n"); - (void) fflush(stdout); - if (vfork() == 0) { - (void) system(rcbuf); - (void) unlink(tf); - _exit(0); - } - } else { - (void) sprintf(rcbuf, MAILER, hptr->title); - (void) sprintf(bfr, "%s %s", rcbuf, address); - (void) system(bfr); - } - hdr(); - return TRUE; -} - -xmit_command() -{ - tfilename = filename; - if (*bptr == '-') { - if (*ofilename1) - tfilename = ofilename1; - bptr++; - } - if (*bptr != '\0' && *bptr != ' ') { - fprintf(ofp, "Bad system name.\n"); - return; - } - while (*bptr == ' ') - bptr++; - if (*bptr == '\0') { - fprintf(ofp, "Missing system name.\n"); - return; - } - if (s_find(&srec, bptr) == NULL) { - fprintf(ofp, "%s not in SYSFILE\n", bptr); - return; - } - (void) transmit(&srec, tfilename); -} - -next_ng_command() -{ - obit = -1; - if (!*bptr || *bptr == '-') { - if (cflag) - clear(bit); - else - putc('\n', ofp); - if (*bptr) - actdirect = BACKWARD; - rfq = 0; - saveart; - if (nextng()) { - if (actdirect == BACKWARD) - fprintf(ofp, "Can't back up.\n"); - else - return TRUE; - } - return FALSE; - } - while (isspace(*bptr)) - bptr++; - if (!validng(bptr)) { - fprintf(ofp, "No such group.\n"); - return FALSE; - } - if (cflag) - clear(bit); - else - putc('\n', ofp); - readmode = SPEC; - rfq = 0; - saveart; - back(); - selectng(bptr, TRUE, TRUE); - return FALSE; -} - -caesar_command() -{ - char temp[BUFLEN]; - FILE *pfp, *popen(); - - fprintf(stderr, "Caesar decoding:\n"); - (void) sprintf(temp, "%s/%s", LIB, "caesar"); - if (*bptr) { - (void) strcat(temp, " "); - (void) strcat(temp, bptr); - } - if (NLINES(h, fp) > LNCNT && *PAGER) { - (void) strcat(temp, " | "); - (void) strcat(temp, PAGER); - } - pfp = popen(temp, "w"); - tprint(fp, pfp, FALSE); - FCLOSE(fp); - (void) pclose(pfp); -} - -/* - * Show the user the tail, if any, of the message on file - * descriptor fd, and close fd. The digester is considered, - * and the pager is used if appropriate. - */ -showtail(fd) -FILE *fd; -{ - if (fd == NULL) - return; - - if (dgest) { - digest(fd, ofp, h); - } else if (!lflag && !pflag && !eflag) { - pprint(fd); - } - (void) fclose(fd); -} - -/* - * Print out the rest of the article through the pager. - */ -pprint(fd) -FILE *fd; -{ -#ifdef PAGE - /* Filter the tail of long messages through PAGER. */ - if (NLINES(h, fd) > LNCNT && *PAGER) { - if (!index(PAGER, FMETA)) { - FILE *pfp, *popen(); - - pfp = popen(PAGER, "w"); - if (pfp == NULL) - pfp = ofp; - /* - * What follows is an attempt to prevent the - * next message from scrolling part of this - * message off the top of the screen before - * the poor luser can read it. - */ - tprint(fd, pfp, FALSE); - putc('\f', pfp); - putc('\n', pfp); - putc(' ', pfp); - (void) pclose(pfp); - } - else - pout(ofp); - holdup = TRUE; - } - else -#endif - tprint(fd, ofp, FALSE); -} - -/* - * Find the next article we want to consider, if we're done with - * the last one, and show the header. - */ -getnextart(minus) -int minus; -{ - int noaccess; - register DIR *dirp; - register struct direct *dir; - long nextnum, tnum; - - noaccess = 0; - - if (minus) - goto nextart2; /* Kludge for "-" command. */ - - if (bit == obit) /* Return if still on same article as last time */ - return 0; - - SigTrap = FALSE; - -nextart: -#ifdef DEBUG - fprintf(stderr,"nextart:\n"); -#endif /* DEBUG */ - dgest = 0; - - if (bit < minartno && !rflag) - bit = minartno; - - /* If done with this newsgroup, find the next one. */ - while (ngsize <= 0 || (!rflag && ((long) bit > ngsize)) || (rflag && bit < minartno)) { - if (nextng()) { - if (actdirect == BACKWARD) { - fprintf(ofp, "Can't back up.\n"); - actdirect = FORWARD; - continue; - } else - if (rfq++ || pflag || cflag) - return 1; - break; - } - if (rflag) - bit = ngsize + 1; - else - bit = minartno - 1; - if (uflag && !xflag) { - time_t now; - (void) time(&now); - if (now - timelastsaved > 5*60 /* 5 minutes */) { - if (!xflag) - fprintf(stderr,"[Saving .newsrc]\n"); - writeoutrc(); - timelastsaved = now; - } - } - noaccess = 0; - } - -nextart2: -#ifdef DEBUG - fprintf(stderr, "article: %s/%ld\n", groupdir, bit); -#endif - if (rcreadok) - rcreadok = 2; /* have seen >= 1 article */ - (void) sprintf(filename, "%s/%ld", dirname(groupdir), bit); - if (rfq && goodone[0]) - strcpy(filename, goodone); - if (SigTrap) { - if (SigTrap == SIGHUP) - return 1; - if (!rcreadok) - xxit(0); - fprintf(ofp, "Abort (n)? "); - (void) fflush(ofp); - (void) gets(bfr); - if (*bfr == 'y' || *bfr == 'Y') - xxit(0); - SigTrap = FALSE; - } -#ifdef DEBUG - fprintf(stderr, "filename = '%s'\n", filename); -#endif - /* Decide if we want to show this article. */ - if (bit <= 0 || (fp = art_open(filename, "r")) == NULL) { - /* don't show the header if the article was specifically - * requested and it isn't there - */ - if (lbuf[0] == '<') { - lbuf[0] = '\0'; - bit = -1; - return 1; - } - /* since there can be holes in legal article numbers, */ - /* we wait till we hit 5 consecutive bad articles */ - /* before we haul off and scan the directory */ - if (++noaccess < 5) - goto badart; - noaccess = 0; - dirp = opendir(dirname(groupdir)); - if (dirp == NULL) { - if (errno != EACCES) - fprintf(stderr,"Can't open %s\n", dirname(groupdir)); - goto badart; - } - nextnum = rflag ? minartno - 1 : ngsize + 1; - while ((dir = readdir(dirp)) != NULL) { - tnum = atol(dir->d_name); - if (tnum <= 0) - continue; - if (rflag ? (tnum > nextnum && tnum < bit) - : (tnum < nextnum && tnum > bit)) - nextnum = tnum; - } - closedir(dirp); - if (rflag ? (nextnum >= bit) : (nextnum <= bit)) - goto badart; -#ifdef DEBUG - fprintf(stderr,"nextnum = %ld\n",nextnum); -#endif /* DEBUG */ - do { - clear(bit); - nextbit(); - } while (rflag ? (nextnum < bit) : (nextnum > bit)); - obit = -1; - abs = FALSE; - if (ignorenews) /* ignored news is still news */ - news = TRUE; - goto nextart; - } else - noaccess = 0; - - if (ignorenews || hread(h, fp, TRUE) == NULL - || (!rfq && !aselect(h, abs))) { - if (ignorenews) - news = TRUE; - badart: -#ifdef DEBUG - fprintf(stderr, "Bad article '%s'\n", filename); -#endif - FCLOSE(fp); - clear(bit); - obit = -1; - nextbit(); - abs = FALSE; - goto nextart; - } - abs = FALSE; - actdirect = FORWARD; - news = TRUE; - hdr(); - if (pflag) - tprint(fp, ofp, FALSE); - else if (cflag && !lflag && !eflag) { - (void) fflush(ofp); - pprint(fp); - } - if (cflag || lflag || eflag || pflag) { - SigTrap = FALSE; - FCLOSE(fp); - } - obit = bit; - return 0; -} - -/* - * Print out whatever the appropriate header is - */ -hdr() -{ - char *briefdate(); - - if (rfq) - return; - - if (lflag || eflag) { - hprint(h, ofp, 0); - return; - } - - /* Print out a header */ - if (ngrp) { - pngsize = ngsize; - ngrp--; - nghprint(groupdir); - } - if (!hflag) - fprintf(ofp, "Article %ld of %ld, %s.\n", - bit, pngsize, briefdate(h->subdate)); - hprint(h, ofp, pflag ? 1 : 0); -} - -nghprint(title) -char *title; -{ - char *tstr = "Newsgroup "; - int l = strlen(title) + strlen(tstr); - - fprintf(ofp, "\n"); - if (!hflag) { - dash(l, ofp); - fprintf(ofp, "%s%s\n", tstr, title); - dash(l, ofp); - } else { - fprintf(ofp, "%s%s, ", tstr, title); - if (bit == pngsize) - fprintf(ofp, "%ld\n", pngsize); - else - fprintf(ofp, "%ld-%ld\n", bit, pngsize); - } - fprintf(ofp, "\n"); -} - -/* - * Routine to catch a continue signal. - */ -catchcont(sig) -int sig; -{ - (void) signal(sig, catchcont); - SigTrap = sig; - (void) fflush(ofp); -#ifdef SIGCONT - if (fp && sig == SIGCONT) - hdr(); - if (sig != SIGCONT) -#endif /* SIGCONT */ - putc('\n', ofp); - if (canlongjmp) - longjmp(sigjmpbuf,1); -} - -xxit(status) -int status; -{ - (void) unlink(infile); - (void) unlink(outfile); -#ifdef SORTACTIVE - if (strncmp(ACTIVE,"/tmp/", 5) == 0) - (void) unlink(ACTIVE); -#endif /* SORTACTIVE */ - exit(status); -} *-*-END-of-src/readr.c-*-* echo x - src/pathinit.c 1>&2 sed 's/.//' >src/pathinit.c <<'*-*-END-of-src/pathinit.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. - * - * This function initializes all the strings used for the various - * filenames. They cannot be compiled into the program, since that - * would be non-portable. With this convention, the netnews sub-system - * can be owned by any non-privileged user. It is also possible - * to work when the administration randomly moves users from one - * filesystem to another. The convention is that a particular user - * (HOME, see Makefile) is searched for in /etc/passwd and all files - * are presumed relative to there. This method also allows one copy - * of the object code to be used on ANY machine. (this code runs - * un-modified on 50+ machines at IH!!) - * - * The disadvantage to using this method is that all netnews programs - * (inews, readnews, rnews, checknews) must first search /etc/passwd - * before they can start up. This can cause significant overhead if - * you have a big password file. - * - * Some games are played with ifdefs to get four .o files out of this - * one source file. INEW is defined for inews, READ for readnews, - * CHKN for checknews, and EXP for expire. - */ - -#ifdef SCCSID -static char *SccsId = "@(#)pathinit.c 1.18 10/23/86"; -#endif /* SCCSID */ - -#if defined(INEW) || defined(EXP) -#include "iparams.h" -#endif /* INEW || EXP */ - -#ifdef READ -#include "rparams.h" -#endif /* READ */ - -#if defined(CHKN) -#include "params.h" -#endif /* CHKN */ - - -char *FULLSYSNAME, *SPOOL, *LIB, *BIN, *ACTIVE, *SUBFILE, *ARTFILE, - *username, *userhome; - -#ifdef INEW -char *LOCKFILE, *SEQFILE, *ARTICLE, *INFILE, *TELLME; - -int c_cancel(), c_newgroup(), c_ihave(), c_sendme(), c_rmgroup(), - c_sendsys(), c_senduuname(), c_version(), c_checkgroups(), c_unimp(); - -struct msgtype msgtype[] = { - "cancel", NULL, c_cancel, - "newgroup", NULL, c_newgroup, - "ihave", NULL, c_ihave, - "sendme", NULL, c_sendme, - "sendbad", NULL, c_sendme, - "rmgroup", NULL, c_rmgroup, - "sendsys", NULL, c_sendsys, - "senduuname", NULL, c_senduuname, - "version", NULL, c_version, - "checkgroups", NULL, c_checkgroups, - "delsub", NULL, c_unimp, - NULL, NULL, NULL -}; -#endif /* INEW */ - -#if defined(INEW) || defined(READ) -char *ALIASES; -#endif /* INEW || READ */ - -#ifdef EXP -char *OLDNEWS; -#endif /* EXP */ - -#ifdef READ -char *MAILPARSER; -#endif /* READ */ - -#ifdef HIDDENNET -char *LOCALSYSNAME; -#endif /* HIDDENNET */ - - -struct passwd *getpwnam(); -char *rindex(); - -#define Sprintf(where,fmt,arg) (void) sprintf(bfr,fmt,arg); where = AllocCpy(bfr) - -char * -AllocCpy(cp) -register char *cp; -{ - register char *mp; - char *malloc(); - - mp = malloc((unsigned)strlen(cp) + 1); - - if (mp == NULL) - xerror("malloc failed on %s", cp); - - (void) strcpy(mp, cp); - return mp; -} - -pathinit() -{ -#if defined(INEW) && defined(NOTIFY) - FILE *nfd; /* notify file descriptor */ - char *p; -#endif /* INEW && NOTIFY */ -#ifndef ROOTID - struct passwd *pw; /* struct for pw lookup */ -#endif /* !ROOTID */ -#ifdef EXP - char *p; -#endif /* EXP */ -#ifndef CHKN - struct utsname ubuf; - - uname(&ubuf); -#ifdef HIDDENNET - FULLSYSNAME = AllocCpy(HIDDENNET); - LOCALSYSNAME = AllocCpy(ubuf.nodename); -#else /* !HIDDENNET */ - FULLSYSNAME = AllocCpy(ubuf.nodename); -#endif /* !HIDDENNET */ -#endif /* !CHKN */ - -#ifdef HOME - /* Relative to the home directory of user HOME */ - (void) sprintf(bfr, "%s/%s", logdir(HOME), SPOOLDIR); - SPOOL = AllocCpy(bfr); - (void) sprintf(bfr, "%s/%s", logdir(HOME), LIBDIR); - LIB = AllocCpy(bfr); -#else /* !HOME */ - /* Fixed paths defined in Makefile */ - SPOOL = AllocCpy(SPOOLDIR); - LIB = AllocCpy(LIBDIR); -#endif /* !HOME */ - -#ifdef IHCC - (void) sprintf(bfr, "%s/%s", logdir(HOME), BINDIR); - BIN = AllocCpy(bfr); -#else /* !IHCC */ - Sprintf(BIN, "%s", BINDIR); -#endif /* !IHCC */ - - Sprintf(ACTIVE, "%s/active", LIB); - -#ifdef EXP - (void) strcpy(bfr, SPOOL); - p = rindex(bfr, '/'); - if (p) { - strcpy(++p, "oldnews"); - OLDNEWS = AllocCpy(bfr); - } else - OLDNEWS = AllocCpy("oldnews"); -#endif /* EXP */ - -#ifndef CHKN - Sprintf(SUBFILE, "%s/sys", LIB); - Sprintf(ARTFILE, "%s/history", LIB); -# endif /* !CHKN */ - -# ifdef READ -#ifdef SENDMAIL - Sprintf(MAILPARSER, "%s -oi -oem", SENDMAIL); -#else /* !SENDMAIL */ - Sprintf(MAILPARSER, "%s/recmail", LIB); -#endif /* !SENDMAIL */ -# endif /* READ */ - -# if defined(READ) || defined(INEW) - Sprintf(ALIASES, "%s/aliases", LIB); -# endif /* READ || INEW */ -# ifdef INEW - Sprintf(LOCKFILE, "%s/LOCK", LIB); - Sprintf(SEQFILE, "%s/seq", LIB); - Sprintf(ARTICLE, "%s/.arXXXXXX", SPOOL); - Sprintf(INFILE, "%s/.inXXXXXX", SPOOL); -/* - * The person notified by the netnews sub-system. Again, no name is - * compiled in, but instead the information is taken from a file. - * If the file does not exist, a "default" person will get the mail. - * If the file exists, but is empty, nobody will get the mail. This - * may seem backwards, but is a better fail-safe. - */ -# ifdef NOTIFY - parse_notify(); -# endif /* NOTIFY */ - -/* - * Since the netnews owner's id number is different on different - * systems, we'll extract it from the /etc/passwd file. If no entry, - * default to root. This id number seems to only be used to control who - * can input certain control messages or cancel any message. Note that - * entry is the name from the "notify" file as found above if possible. - * Defining ROOTID in defs.h hardwires in a number and avoids - * another search of /etc/passwd. - */ -# ifndef ROOTID - if ((pw = getpwnam(TELLME)) != NULL) - ROOTID = pw->pw_uid; - else if ((pw = getpwnam(HOME)) != NULL) - ROOTID = pw->pw_uid; - else - ROOTID = 0; /* nobody left, let only root */ -# endif /* !ROOTID */ -#endif /* INEW */ -} - -#ifdef INEW -#ifdef NOTIFY -/* - * Attempt to parse the LIB/notify file into the global structure msgtype[]. - */ -parse_notify() -{ - FILE *nfd; - int valid = 0, done = 0; - register struct msgtype *mp; - char mtype[BUFLEN], addr[BUFLEN]; - - (void) sprintf(bfr, "%s/notify", LIB); -#ifndef ROOTID - TELLME = AllocCpy(NOTIFY); -#endif /* !ROOTID */ - if ( (nfd = fopen(bfr, "r")) == NULL) { - /* - * Set defaults to NOTIFY - */ -#ifdef debug - log("parse_notify: %s/notify not found", LIB); -#endif /* debug */ - (void)setmsg("all", NOTIFY); - return; - } - do { - mtype[0] = addr[0] = 0; - switch( get_notify(nfd, mtype, addr) ) { - case 0: - continue; - case 1: - valid += setmsg(mtype, ""); - break; - case 2: - valid += setmsg(mtype, addr); - break; - case -1: - if( !valid ) { -#ifdef debug - log("parse_notify: no valid entries found."); -#endif /* debug */ - setmsg("all", ""); /* send mail to no one */ - } - done = 1; - } - } while( !done ); - - /* - * point to zero length string for all entries we haven't touched - */ - for(mp=msgtype; mp->m_name; mp++) - if(mp->m_who_to == 0) - mp->m_who_to = ""; -} - -setmsg(what, to) -char *what, *to; -{ - register struct msgtype *mp; -#ifdef debug - log("setmsg: what='%s', to='%s'", what, to); -#endif /* debug */ - /* - * Special case for "all" - */ - if(strcmp(what, "all") == 0) { - for(mp=msgtype; mp->m_name; mp++) { - mp->m_who_to = AllocCpy(to); -#ifdef debug - log("setmsg: '%s'='%s'", mp->m_name, mp->m_who_to); -#endif /* debug */ - } - return 1; - } - - for(mp=msgtype; mp->m_name; mp++) - if(strcmp(mp->m_name, what) == 0) { - mp->m_who_to = AllocCpy(to); -#ifdef debug - log("setmsg: '%s'='%s'", mp->m_name, mp->m_who_to); -#endif /* debug */ - return 1; - } - return 0; -} - -static -get_notify(fp, s, t) -FILE *fp; -register char *s, *t; -{ - register char *cp; - char buf[BUFSIZ]; - - if( cp=fgets(buf, sizeof(buf), fp ) ) { - if( *cp == '\n' ) - return 0; - while(*cp && *cp != ' ' && *cp != '\t' && *cp != '\n') - *s++ = *cp++; - *s = '\0'; /* terminate first string */ - - while(*cp && (*cp == ' ' || *cp == '\t' || *cp == '\n') ) - cp++; /* look for start of second */ - if( !*cp || *cp == '\n' ) - return 1; /* no second string */ - - while( *cp && *cp != '\n' ) - *t++ = *cp++; - *t = '\0'; - return 2; - } else - return -1; -} -#endif /* NOTIFY */ -#endif /* INEW */ *-*-END-of-src/pathinit.c-*-* echo x - src/localize.sample 1>&2 sed 's/.//' >src/localize.sample <<'*-*-END-of-src/localize.sample-*-*' -rm -f Makefile -cp Makefile.dst Makefile -chmod u+w Makefile -ed Makefile <<'EOF' -/^UUXFLAGS/s/-r -z/-r -z -n -gd/ -g/^#V7 /s/// -g/^#BSD4_3 /s/// -g/^#BSD4_1 /d -g/^#USG /d -/^LIBDIR/s;/usr/lib/news;/usr/new/lib/news; -/^BINDIR/s;/usr/bin;/usr/new; -w -q -EOF -rm -f defs.h -cp defs.dist defs.h -chmod u+w defs.h -ed - defs.h <<'EOF' -/ROOTID/s/10/352/ -/N_UMASK/s/000/002/ -/DFTXMIT/s/-z/-z -gd/ -/UXMIT/s/-z/-z -gd/ -/NONEWGROUPS/s;/\* ;; -/INTERNET/s;/\* ;; -/MYDOMAIN/s;.UUCP;.CSS.GOV; -/GHNAME/s;/\* ;; -/DOXREFS/s;/\* ;; -/BSD4_2/s;/\* ;; -/ALWAYSALIAS/s;/\* ;; -/SENDMAIL/s;/\* ;; -/HIDDENNET/s;frooz;seismo; -s;/\* ;; -/MYORG/s/Frobozz Inc., St. Louis/Center for Seismic Studies, Arlington, VA/ -/ORGDISTRIB/s;/\* ;; -/ORGDISTRIB/s;froozum;css; -w -q -EOF *-*-END-of-src/localize.sample-*-* exit