2.9BSD/usr/contrib/news/src/expire.c

Compare this file to the similar file:
Show the results in this format:

/*
 * expire - expire daemon runs around and nails all articles that
 *		 have expired.
 *
 * Note: This version of expire contains some code to implement new
 * history features, e.g. to work without a history file or to rebuild
 * the history file.  This code was written for B news 2.9 and would
 * need some conversion to deal with the 2.10 heirarchical subgroups
 * in subdirectories.  This would imply a recursive traversal of the
 * tree.  Such code could be written but I didn't have the energy to
 * convert this 2.9 style code.
 */

static char	*SccsId = "@(#)expire.c	2.16	6/24/83";

#include "params.h"
#include "ndir.h"

#define NART	100

extern char	groupdir[BUFSIZ], rcbuf[BUFLEN];
extern char	ACTIVE[];
extern char	SPOOL[];
extern char	ARTFILE[];
extern char	filename[];
char	NARTFILE[BUFSIZ], OARTFILE[BUFSIZ];
char	OLDNEWS[BUFLEN];
int	verbose = 0;
int	ignorexp = 0;
int	doarchive = 0;
int	nohistory = 0;
int	rebuild = 0;

/*
 * The code dealing with this is ifdeffed out.
 * However, it should be redone to malloc the mh_ident
 * fields, and realloc the multhist array, so that the
 * fixed constant NART can be done away with.  Apparently
 * when rebuilding the history file, 100 is much too small.
 */
struct multhist {
	char	mh_ident[BUFLEN];
	char	*mh_file;
} multhist[NART];

typedef struct {
	char *dptr;
	int dsize;
} datum;

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, *p3;
	FILE	*ohfd, *nhfd;
	DIR	*ngdirp;
	static struct direct *ngdir;
	char fn[BUFLEN];
	datum	key;

	pathinit();
	umask(N_UMASK);
	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;
			if (verbose < 3)
				setbuf(stdout, NULL);
			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;
#ifdef notdef
/*
 * Nohistory and Rebuild are broken by the new directory format.
 * A recursive directory traversal needs to be made.  I don't
 * have the energy to do this - hopefully someone else will.
 */
		case 'h':	/* ignore history */
			nohistory++;
			break;
		case 'r':	/* rebuild history file */
			rebuild++;
			nohistory++;
			break;
#endif
		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");
#ifdef DBM
	dbminit(ARTFILE);
#endif
	if (verbose)
		printf("expire: nohistory %d, rebuild %d, doarchive %d\n",
			nohistory, rebuild, doarchive);

	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) {
#ifdef notdef
			do {
				if (ngdir == NULL) {
					if ( ngdirp != NULL )
						closedir(ngdirp);
					if (fgets(afline, BUFLEN, ohfd) == NULL)
						goto out;
					strcpy(groupdir, afline);
					p1 = index(groupdir, ' ');
					if (p1 == NULL)
						p1 = index(groupdir, '\n');
					if (p1 != NULL)
						*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(fn, "%s/%s", groupdir, ngdir->d_name);
			p2 = fn;
			if (verbose > 2)
				printf("article: %s\t", fn);
#endif
		} 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);
			p3 = index(groupdir, '/');
			if (p3)
				*p3 = 0;
			else {
				/*
				 * Nothing after the 2nd tab.  This happens
				 * when a control message is stored in the
				 * history file.  Use the date in the history
				 * file to decide expiration.
				 */
				h.expdate[0] = 0;
				strcpy(h.recdate, p1+1);
				goto checkdate;
			}
			ngcat(groupdir);
			if (!ngmatch(groupdir, ngpat)) {
				fputs(afline, nhfd);
				continue;
			}
			ngdel(groupdir);
			strcpy(fn, p2);
			p1 = index(fn, ' ');
			if (p1 == 0)
				p1 = index(fn, '\n');
			if (p1)
				*p1 = 0;
		}

		strcpy(filename, dirname(fn));
		if (access(filename, 4)
		|| (fp = fopen(filename, "r")) == NULL) {
			if (verbose > 3)
				printf("Can't open %s.\n", filename);
			continue;
		}
		if (hread(&h, fp, TRUE) == NULL) {
			if (verbose)
				printf("Garbled article %s.\n", filename);
			fclose(fp);
			continue;
		}
#ifdef notdef
		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;
		}
#endif

		fclose(fp);
checkdate:
		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);
# ifdef DBM
			key.dptr = h.ident;
			key.dsize = strlen(key.dptr) +1;
			delete(key);
# endif
#endif
		} else {
			fputs(afline, nhfd);
			if (verbose > 2)
				printf("Good article %s\n", rcbuf);
		}
	}

out:
#ifdef notdef
	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);
	}
#endif

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

/* Unlink (using tail recursion) all the articles in 'artlist'. */
ulall(artlist, h)
char	*artlist;
struct hbuf *h;
{
	char	*p;
	int	last = 0;
	char	newname[BUFLEN];
	char	newgroup[BUFLEN];
	time_t	timep[2];
	char *fn;

	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;
			fn = dirname(artlist);
			unlink(fn);
			return;
		}
		if (p)
			*p = 0;
	}
	fn = dirname(artlist);
	if (doarchive && access(OLDNEWS, 0) == 0) {
		p = fn + strlen(SPOOL) + 1;
		sprintf(newname, "%s/%s", OLDNEWS, p);
		if (verbose > 1)
			printf("link %s to %s\n", fn, newname);
		if (link(fn, newname) == -1) {
			if (mkparents(newname) == 0)
				link(fn, newname);
		}
		timep[0] = timep[1] = cgtdate(h->subdate);
		utime(newname, timep);
	}

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


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

/*
 * If any parent directories of this dir don't exist, create them.
 */
mkparents(dirname)
char *dirname;
{
	char buf[200], sysbuf[200];
	register char *p;
	int rc;
	struct passwd *pw;

	strcpy(buf, dirname);
	p = rindex(buf, '/');
	if (p)
		*p = '\0';
	if (exists(buf))
		return;
	mkparents(buf);
	sprintf(sysbuf, "mkdir %s", buf);
	rc = system(sysbuf);
	strcpy(sysbuf, buf);
	if (verbose)
		printf("mkdir %s, rc %d\n", sysbuf, rc);
	chmod(sysbuf, 0755);
	if ((pw = getpwnam(NEWSU)) != NULL)
		chown(sysbuf, pw->pw_uid, pw->pw_gid);
}