[net.sources] expire.c

ecn-pa:ecn-pb:rick (10/27/82)

/*
 * expire - expire daemon runs around and nails all articles that
 *		 have expired.
 */

static char *SccsId = "@(#) expire.c	2.10	6/21/82";

#include "params.h"
#include <ndir.h>

extern char	groupdir[BUFSIZ], rcbuf[BUFLEN];
extern char	*ACTIVE;
extern char	*SPOOL;
extern char	*CAND;
char	ARTFILE[BUFSIZ], NARTFILE[BUFSIZ], OARTFILE[BUFSIZ];
extern char	filename[];
char	*OLDNEWS = "/usr/spool/oldnews";
int	verbose = 0;
int	ignorexp = 0;
int	doarchive = 0;
int	nohistory = 0;
int	rebuild = 0;
#define NART	100
struct multhist {
	char	mh_ident[14];
	char	*mh_file;
}multhist[NART];
long	expincr;
long	atol();
time_t	cgtdate(), time();
FILE *popen();

main(argc, argv)
int argc;
char **argv;
{
	register int i;
	register FILE *fp = NULL, *actfp;
	register char *ptr;
	struct hbuf h;
	struct stat statbuf;
	register time_t now, newtime;
	char ngpat[LBUFLEN];
	char afline[BUFLEN];
	char *p1, *p2;
	FILE *ohfd, *nhfd;
	DIR *ngdirp;
	static struct direct *ngdir;

	expincr = DFLTEXP;
	ngpat[0] = '\0';
	while (argc > 1) {
		switch (argv[1][1]) {
		case 'v':
			if (isdigit(argv[1][2]))
				verbose = argv[1][2] - '0';
			else
				verbose = 1;
			break;
		case 'e':	/* Use this as default expiration time */
			if (argc > 2 && argv[2][0] != '-') {
				argv++;
				argc--;
				expincr = atol(argv[1]) * 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] != '-') {
					strcat(ngpat, argv[1]);
					ngcat(ngpat);
					argv++;
					argc--;
				}
				argv--;
				argc++;
			}
			break;
		case 'a':	/* archive expired articles */
			doarchive++;
			break;
		case 'h':	/* ignore history */
			nohistory++;
			break;
		case 'r':	/* rebuild history file */
			rebuild++;
			nohistory++;
			break;
		default:
			printf("Usage: expire [ -v [level] ] [-e days ] [-i] [-n newsgroups]\n");
			exit(1);
		}
		argc--; argv++;
	}
	if (ngpat[0] == 0)
		strcpy(ngpat, "all,");
	now = time(0);
	if (chdir(SPOOL))
		xerror("Cannot chdir %s", SPOOL);

	sprintf(OARTFILE, "%s/%s", LIB, "ohistory");
	sprintf(ARTFILE, "%s/%s", LIB, "history");
	sprintf(NARTFILE, "%s/%s", LIB, "nhistory");

	if (nohistory) {
		ohfd = xfopen(ACTIVE, "r");
		if (rebuild){
			sprintf(afline,"sort +2 >%s",NARTFILE);
			if ((nhfd=popen(afline,"w")) == NULL)
				xerror("Cannot exec %s",NARTFILE);
		} else
			nhfd = xfopen("/dev/null", "w");
	} else {
		ohfd = xfopen(ARTFILE, "r");
		nhfd = xfopen(NARTFILE, "w");
	}

	while (TRUE) {
		if (nohistory){
			do {
				if (ngdir == NULL) {
					if( ngdirp != NULL )
						closedir(ngdirp);
					if (fgets(afline, BUFLEN, ohfd) == NULL)
						goto out;
					strcpy(groupdir,afline);
					p1 = index(groupdir, '\n');
					if (p1)
						*p1 = NULL;
					ngcat(groupdir);
					if (!ngmatch(groupdir,ngpat))
						continue;
					ngdel(groupdir);
					if ((ngdirp=opendir(groupdir)) == NULL)
						continue;
				}
				ngdir = readdir(ngdirp);
			} while ( ngdir == NULL || ngdir->d_name[0] == '.' );
			sprintf(filename,"%s/%s",groupdir,ngdir->d_name);
			p2 = filename;
			if (verbose > 2)
				printf("article: %s\t", filename);
		} else {
			if (fgets(afline, BUFLEN, ohfd) == NULL)
				break;
			if (verbose > 2)
				printf("article: %s", afline);
			p1 = index(afline, '\t');
			if (p1)
				p2 = index(p1+1, '\t');
			else
				continue;
			if (!p2)
				continue;
			p2++;
			strcpy(groupdir, p2);
			p1 = index(groupdir, '/');
			if (p1)
				*p1 = 0;
			else
				continue;
			ngcat(groupdir);
			if (!ngmatch(groupdir, ngpat)) {
				fputs(afline, nhfd);
				continue;
			}
			ngdel(groupdir);
			strcpy(filename, p2);
			p1 = index(filename, ' ');
			if (p1 == 0)
				p1 = index(filename, '\n');
			if (p1)
				*p1 = 0;
		}

		if (access(filename, 4) || (fp = fopen(filename, "r")) == NULL) {
			if (verbose > 3)
				printf("Can't open %s.\n", filename);
			continue;
		}
		if (hread(&h, fp) == NULL) {
			if (verbose)
				printf("Garbled article %s.\n", filename);
			fclose(fp);
			continue;
		}
		if (rebuild){
			register char *cp;
			register struct multhist *mhp;

			if ((cp=index(h.nbuf,NGDELIM)) == NULL) {
saveit:
				fprintf(nhfd,"%s\t%s\t%s \n",h.ident,h.recdate,filename);
				fclose(fp);
				continue;
			}
			for (mhp=multhist;mhp->mh_ident[0]!=NULL&&mhp<&multhist[NART];mhp++) {
				if (mhp->mh_file == NULL)
					continue;
				if (strcmp(mhp->mh_ident,h.ident) != 0)
					continue;
				if (index(mhp->mh_file,' ') != NULL)
					cp = index(++cp,NGDELIM);
				strcat(filename," ");
				strcat(filename,mhp->mh_file);
				free(mhp->mh_file);
				if (*cp == NULL || (cp=index(++cp,NGDELIM)) == NULL) {
					mhp->mh_file = NULL;
					goto saveit;
				} else
					break;
			}
			if (mhp>=&multhist[NART])
				xerror("Too many articles with multiple newsgroups");
			strcpy(mhp->mh_ident,h.ident);
			cp = malloc(strlen(filename)+1);
			if ( cp == NULL)
				xerror("Out of memory");
			strcpy(cp,filename);
			mhp->mh_file = cp;
			fclose(fp);
			continue;
		}

		if (h.expdate[0])
			h.exptime = cgtdate(h.expdate);
		newtime = cgtdate(h.recdate) + expincr;
		if (!h.expdate[0] || ignorexp==2 ||
		    (ignorexp==1 && newtime < h.exptime))
			h.exptime = newtime;
		if (now >= h.exptime) {
#ifdef DEBUG
			printf("cancel %s\n", filename);
#else
			if (verbose)
				printf("cancel %s\n", filename);
			ulall(p2,&h);
#endif
		}
		else {
			fputs(afline, nhfd);
			if (verbose > 2)
				printf("Good article %s\n", rcbuf);
		}
		fclose(fp);
	}

out:
	if (rebuild){
		register struct multhist *mhp;
		for (mhp=multhist;mhp->mh_ident[0]!=NULL&&mhp<&multhist[NART];mhp++)
			/* should "never" happen */
			if (mhp->mh_file != NULL )
				printf("Article: %s %s Cannot find all links\n",mhp->mh_ident,mhp->mh_file);
	pclose(nhfd);
	}

	if (rebuild || !nohistory){
		unlink(OARTFILE);
		link(ARTFILE, OARTFILE);
		unlink(ARTFILE);
		link(NARTFILE, ARTFILE);
		unlink(NARTFILE);
	}
	exit(0);
}

ulall(artlist,h)
char *artlist;
struct hbuf *h;
{
	char *p;
	int last = 0;
	char newname[BUFLEN];
	char newgroup[BUFLEN];
	time_t timep[2];

	if (nohistory){
		last = 1;
	} else {
		while (*artlist == ' ' || *artlist == '\n' || *artlist == ',')
			artlist++;
		if (*artlist == 0)
			return;
		p = index(artlist, ' ');
		if (p == 0) {
			last = 1;
			p = index(artlist, '\n');
		}
		if (p == 0) {
			last = 1;
			p = index(artlist, ',');
		}
		if (p == 0) {
			last = 1;
			unlink(artlist);
			return;
		}
		if (p)
			*p = 0;
	}
	if (doarchive && access(OLDNEWS, 0) == 0) {
		strcpy(newgroup, artlist);
		p = index(newgroup, '/');
		*p = 0;
		sprintf(newname, "%s/%s/%s", OLDNEWS, newgroup, h->ident);
		if (verbose > 1)
			printf("link %s to %s\n", newname, filename);
		if (link(artlist, newname) == -1) {
			if (mkdir(newgroup) == 0)
				link(artlist, newname);
		}
		timep[0] = timep[1] = cgtdate(h->subdate);
		utime(newname,timep);
	}

	if (verbose)
		printf("unlink %s\n", artlist);
	unlink(artlist);
	if (!last)
		ulall(p+1,h);
}

xerror(message)
char *message;
{
	printf("expire: %s.\n", message);
	fflush(stdout);
	exit(1);
}

mkdir(groupdir)
register char *groupdir;
{
	char buf[BUFLEN];
	register struct passwd *pw;
	extern char *NEWSU;
	int rc;

	if (access(OLDNEWS, 2) < 0)
		return -1;
	sprintf(buf, "mkdir %s/%s", OLDNEWS, groupdir);
	rc = system(buf);
	sprintf(buf, "%s/%s", OLDNEWS, groupdir);
	if (verbose)
		printf("mkdir %s, rc %d\n", buf, rc);
	chmod(buf, 0755);
	if ((pw = getpwnam(NEWSU)) != NULL)
		chown(buf, pw->pw_uid, pw->pw_gid);
	return rc;
}