/* @(#)uuclean.c	2.1	 */
#include "uucp.h"
#include <signal.h>
#include <pwd.h>
#include <sys/types.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/dir.h>



/*
 * search through the spool directory (Spool) and delete
 * all files with a requested prefix which are older than
 * (nomtime) secounds. If the -m option is set, the program 
 * will try to send mail to the usid of the file.
 * options:
 *	m	-> send mail for deleted file
 *	d	-> directory to clean
 *	n	-> time to age files before delete (in hours)
 *	p	-> prefix for search
 *	x	-> turn on debug outputs
 * exit:
 *	0	-> normal return
 *	1	-> can not read directory
 */
#define DPREFIX "U"
#define NOMTIME 72	/* hours to age files before deletion */

char *strcpy();
int	wrnf;

#define MAXPRE 25
char	Sys[MAXPRE][DIRSIZ+1];
int	Nsys = 0;
char	*Logfile;
char	*Mailfile;
char	*mf;
char	*xf;
int	onemf;
int	jjn;
char	**Env;
main(argc, argv, envp)
char *argv[];
char	**envp;
{
	register FILE *pdirf;
	struct stat stbuf;
	int	mflg=0,pflg=0;
	int	ret;
	char	msg[BUFSIZ];
	extern int onintr();
	extern int errno;
	time_t nomtime, ptime, time();
	void exit();
	char file[NAMESIZE];

	Env = envp;
	strcpy(Progname, "uuclean");
	nstat.t_qtime = time((long *)0);
	Pchar = 'K';
	nomtime = NOMTIME * 3600L;

	while (argc>1 && argv[1][0] == '-') {
		switch (argv[1][1]) {
		case 'd':
			Spool = &argv[1][2];
			break;
		case 'm':
			mflg = 1;
			if(argv[1][2]){
				onemf++;
				Mailfile = &argv[1][2];
			}
			break;
		case 'n':
			nomtime = atoi(&argv[1][2]) * 3600L;
			break;

		/*
		 * Specify prefix(es) -pstring
		 * 	string		-> prefix
		 * 	""		-> null forces uuclean to operate on all 		 *			-> files
		 */
		case 'p':
			if(strcmp(&argv[1][2], "all") == SAME)
				pflg = 2;
			else{
				pflg = 1;
				stpre(&argv[1][2]);
			}
			break;
		case 's':
			stsys(&argv[1][2]);
			break;
		case 'x':
			Debug = atoi(&argv[1][2]);
			if (Debug <= 0)
				Debug = 1;
			break;
		case 'w':
			wrnf++;
			if(argv[1][2])
				Logfile = &argv[1][2];
			break;
		default:
			printf("unknown flag %s\n", argv[1]); break;
		}
		--argc;  argv++;
	}

	if(pflg == 0){
		pflg++;
		stpre("LCK");
		stpre("C");
		stpre("X");
		stpre("T");
		stpre("TM");
		stpre("D");
		stpre("STST");
		stpre("LTMP");
	}
	if ((pdirf = fopen(Spool, "r")) == NULL) {
		printf("%s directory unreadable\n", Spool);
		exit(1);
	}
	DEBUG(4, "DEBUG# %s\n", "START");
	ret = chdir(Spool);
	ASSERT(ret == 0, "UUCLEAN:CANNOT CHDIR TO SPOOL - ", Spool, errno);


	/*
	 * Set LOGNAME so mail comes from uucp
	 */
	ret = guinfo(geteuid(), User, msg);
	setuucp(User);
	time(&ptime);
	while (gnamef(pdirf, file)) {
		if (Nsys && chksys(file) == FALSE)
			continue;
		if(pflg == 1)
		if (chkpre(file) == FALSE) 
			continue;
		if (stat(file, &stbuf) == -1) {
			DEBUG(4, "stat on %s failed\n", file);
			continue;
		}
		if ((stbuf.st_mode & S_IFMT) == S_IFDIR)
			continue;
		if ((ptime - stbuf.st_mtime) < nomtime)
			continue;
		if(wrnf){
			wrnent(file, "", 0, stbuf.st_mtime);
			continue;
		}
		if ((file[0] == CMDPRE) && (file[1] == '.')){
			jjn = atoi(&file[strlen(file) - 4]);
			notfyuser(file);
			kill(jjn);
		}
		DEBUG(4, "unlink file %s\n", file);
		if(unlink(file) == -1)
			continue;
		wrnent(file, "", 1, stbuf.st_mtime);
		if (mflg) 
			sdmail(file, (int) stbuf.st_uid);
	}

	fclose(pdirf);
	exit(0);
}


char Pre[MAXPRE][DIRSIZ+1];
int Npre = 0;

/*
 * check for prefix
 *	file	-> file name to check
 *
 *	return codes:
 *		FALSE	->  not prefix
 *		TRUE	->  is prefix
 */
chkpre(file)
register char *file;
{
	register int i;

	for (i = 0; i < Npre; i++) {
		if (prefix(Pre[i], file))
			return(TRUE);
	}
	return(FALSE);
}
chksys(file)
register char *file;
{
	register int i;

	if(Nsys == 0)
		return(TRUE);
	for (i = 0; i < Nsys; i++) {
		if (substr(Sys[i], file) == TRUE)
			return(TRUE);
	}
	return(FALSE);
}
substr(p, q)
register char *p,*q;
{
	register n;

	n = strlen(p);
	for(;*q;q++){
		if(*p == *q){
			if(strncmp(p,q,n) == SAME)
				return(TRUE);
		}
	}
	return(FALSE);
}

/*
 * store prefix
 *	p	-> prefix
 *
 *	return codes:  none
 */
stpre(p)
char	*p;
{
	if (Npre < MAXPRE)
		strncat(Pre[Npre++], p, DIRSIZ);
	return;
}
/*
 * store system name
 *	p	-> system
 *
 *	return codes:  none
 */
stsys(p)
char	*p;
{
	if (Nsys < MAXPRE)
		strncat(Sys[Nsys++], p, DIRSIZ);
	return;
}


/*
 * notfiy requestor of deleted requres
 * return
 *	none
 */
notfyuser(file)
register char *file;
{
	register FILE *fp;
	register int numrq;
	char frqst[100], lrqst[100];
	char msg[BUFSIZ];
	char *args[10];
	char *strcat();
	struct stat sb;
	int	statop;

	xf = file;
	if ((fp = fopen(file, "r")) == NULL)
		return;
	if(stat(file, &sb) != -1)
		nstat.t_qtime = sb.st_mtime;
	if (fgets(frqst, sizeof(frqst), fp) == NULL) {
		fclose(fp);
		return;
	}
	numrq = 1;
	while (fgets(lrqst, sizeof(lrqst), fp))
		numrq++;
	fclose(fp);
	sprintf(msg,
		"uuclean: File %s delete. \nCould not contact remote. \n%d requests deleted.\n",
		 file, numrq);
	if (numrq == 1) {
		strcat(msg, "REQUEST: ");
		strcat(msg, frqst);
	} else {
		strcat(msg, "FIRST REQUEST: ");
		strcat(msg, frqst);
		strcat(msg, "\nLAST REQUEST: ");
		strcat(msg, lrqst);
	}
	getargs(frqst, args);
	/*
	 * Notify user via mail
	 */
	statop = strchr(args[4], 'o') != NULL;
	if(onemf){
		mf = Mailfile;
		stmesg(args[3], msg, "");
	}
	if(statop){
		if(args[0][0] == 'S'){
			mf = args[7];
		}else
		if(args[0][0] == 'R'){
			mf = args[5];
		}
		stmesg(args[3], msg, "");
		return;
	}
	mailst(args[3], msg, "");
	return;
}
stmesg(u, f, m)
char	*u, *f, *m;
{
	struct tm *tp;
	FILE	*Cf;
	extern struct tm *localtime();
	time_t	time();
	time_t	clock;
	long	td,th,tm,ts;

	if((Cf = fopen(mf, "a+")) == NULL){
		return;
	}
	chmod(mf, 0666);
DEBUG(4,"STM %d\n",Cf);
	fprintf(Cf, "uucp job %.4s ", xf + strlen(xf)-4);
	time(&clock);
	tp = localtime(&clock);
	fprintf(Cf, "(%d/%d-%d:%2.2d:%2.2d) ", tp->tm_mon + 1,
		tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);
	td = clock - nstat.t_qtime;
	ts = td%60;
	td /= 60;
	tm = td%60;
	td /= 60;
	th = td;
	fprintf(Cf, "(%ld:%ld:%ld) ", th, tm, ts);
	fprintf(Cf, "%s %s", f, m);
	fclose(Cf);
}


/*
 * determine the owner of the file (file,
 * create a message string and call "mailst"
 * to send the cleanup message.
 * This is only implemented for local system
 * mail at this time.
 */
sdmail(file, uid)
register char *file;
{
	static struct passwd *pwd;
	struct passwd *getpwuid();
	char mstr[40];

	sprintf(mstr, "uuclean deleted file %s\n", file);
	if (pwd->pw_uid == uid) {
		mailst(pwd->pw_name, mstr, "");
	return(0);
	}

	setpwent();
	if ((pwd = getpwuid(uid)) != NULL) {
		mailst(pwd->pw_name, mstr, "");
	}
	return(0);
}

cleanup(code)
{

	exit(code);
}

/*
 * Make del entry
 *	file	-> ptr to file string
 *	status	-> ptr to status string
 * Returns:
 *	none
 */
wrnent(file, status, f, tv)
register char *file, *status;
time_t tv;
{
	register struct tm *tp;
	extern struct tm *localtime();
	time_t clock;
	char	*lfile;
	static int pid = 0;
	static FILE *Df = 0, *Wf = 0;

	if (pid == 0){
		pid = getpid();
	}
	if(f == 1)
		if(Df == NULL){
			if((Df = fopen(LOGDEL, "a+")) == NULL){
				return;
			}
		}
	if(Wf == NULL){
		if(Logfile != NULL){
			if((Wf = fopen(Logfile, "w")) == NULL){
				return;
			}
		}else
			Wf = stdout;
	}
	time(&clock);
	tp = localtime(&clock);
	if(wrnf)
		stamp(Wf, tp, status, file, clock, tv);
	if(f)
		stamp(Df, tp, status, file, clock, tv);
	return;
}
stamp(fd, tp, status, file, c, tv)
FILE	*fd;
struct tm *tp;
char *status, *file;
time_t tv, c;
{
	int	sec, hr, day, min;
	time_t td;

	fprintf(fd, "(%d/%d-%d:%2.2d:%2.2d) ", tp->tm_mon + 1,
		tp->tm_mday, tp->tm_hour, tp->tm_min, tp->tm_sec);
	td = c - tv;
	if(td < 0)
		td = -td;
	day = td/(3600L*24L);
	td %= 3600L*24L;
	hr = td/3600;
	td %= 3600;
	min = td/60;
	sec = td%60;
	fprintf(fd, "(%2.2d:%2.2d:%2.2d:%2.2d) ", day, hr, min, sec);
	fprintf(fd, "%s (%s)\n", status, file);
	fflush(fd);
}
