/
umud/DOC/
umud/DOC/U/
umud/DOC/U/U-examples/
umud/DOC/internals/
umud/DOC/wizard/
umud/MISC/
umud/MISC/dbchk/
umud/RWHO/rwhod/
/*
	Copyright (C) 1991, Marcus J. Ranum. All rights reserved.
*/

#ifndef	lint
static	char	RCSid[] = "$Header: /home/mjr/hacks/umud/RCS/cron.c,v 1.7 92/05/17 23:32:39 mjr Exp $";
#endif

/* configure all options BEFORE including system stuff. */
#include	"config.h"

/*
#define	CRON_DEBUG
*/

/* define this prototype here to avoid extern/static conflict */
static int lowest_quant();

#ifdef	NOSYSTYPES_H
#include	<types.h>
#else
#include	<sys/types.h>
#endif

#include	"mud.h"
#include	"vars.h"

/* flags for cron entries */
#define	KRON_CMD	01	/* is macro */
#define	KRON_U		02	/* is U-code */
#define	KRON_BILL	04	/* bill owner for call */

typedef struct	kron	{
	int	jobid;
	time_t	interv;
	time_t	last;
	int	runcnt;
	int	flgs;
	char	*who;
	char	*aswho;
	char	*cmd;
	struct	kron	*nxt;
} Kron;

static	Kron	*crontab;
static	int	curjobid = 0;


cron_run(now)
time_t	now;
{
	Kron	*k;
	Kron	*p;
	int	squant = -1;

	k = p = crontab;

#ifdef	CRON_DEBUG
	printf("running cron - quantum is %d\n",cron_quantum);
#endif

	while(k != (Kron *)0) {
		if(now - k->last >= k->interv) {
#ifdef	CRON_DEBUG
			printf("trigger %s runs %s\n",k->who,k->cmd);
#endif
			if(cache_check(k->who)) {
				if(k->flgs & KRON_U) {
					parser_setinput(k->cmd);
					if(parser_compile(k->who)) {
						run_setactor(k->who);
						(void)parser_run(k->who,k->aswho,0,(char **)0);
					}
				} else
				if(k->flgs & KRON_CMD) {
					(void)run(k->who,k->aswho,k->cmd,0,0,1);
				}
			}
			k->last = now;

			if(k->runcnt != -1)
				k->runcnt--;

#ifdef	COMBAT
			/* debit the guy some action points */
			if(k->flgs & KRON_BILL) {
				int	vat;

				if(ut_getnum(k->who,var_action,&vat) < 0 ||
					(vat - (2000 / k->interv) <= 0)) {
					k->runcnt = 0;
#ifdef	CRON_DEBUG
					printf("expire %s action %s\n",k->who,k->cmd);
#endif
				} else {
					vat -= (2000 / k->interv);
					ut_setnum(k->who,k->who,var_action,vat);
				}
			}
#endif
		}

		if(k->runcnt == 0) {
			if(k == crontab)
				crontab = k->nxt;
			else
				p->nxt = k->nxt;
			if(squant == -1)
				squant = k->interv;
			else {
				if(k->interv < squant)
					squant = k->interv;
			}

			if(k->cmd != (char *)0)
				free((mall_t)k->cmd);
			if(k->aswho != (char *)0)
				free((mall_t)k->aswho);
			if(k->who != (char *)0)
				free((mall_t)k->who);
			p = k;
			free((mall_t)k);
			k = p->nxt;
			continue;
		}

		p = k;
		k = k->nxt;
	}
	if(squant != -1 && squant <= cron_quantum) {
		cron_quantum = lowest_quant();
#ifdef	CRON_DEBUG
		printf("new cron quantum %d\n",cron_quantum);
#endif
	}
	return(0);
}





static	int
cron_add(interv,runcnt,cmd,who,aswho,flg)
time_t	interv;
int	runcnt;
char	*cmd;
char	*who;
char	*aswho;
int	flg;
{
	static	char	*allerr = "cannot allocate cron structure\n";
	Kron	*k;

	if(cmd == (char *)0 || who == (char *)0 || aswho == (char *)0 ||
		*cmd == '\0' || *who == '\0' || *aswho == '\0')
		return(1);

	if((k = (Kron *)malloc(sizeof(Kron))) == (Kron *)0) {
		logf(allerr,(char *)0);
		return(-1);
	}

	k->interv = interv;
	time(&k->last);
	k->runcnt = runcnt;

	k->who = (char *)malloc((unsigned)(strlen(who) + 1));
	if(k->who == (char *)0) {
		logf(allerr,(char *)0);
		return(-1);
	}
	strcpy(k->who,who);

	k->aswho = (char *)malloc((unsigned)(strlen(aswho) + 1));
	if(k->aswho == (char *)0) {
		logf(allerr,(char *)0);
		return(-1);
	}
	strcpy(k->aswho,aswho);

	k->cmd = (char *)malloc((unsigned)(strlen(cmd) + 1));
	if(k->cmd == (char *)0) {
		logf(allerr,(char *)0);
		return(-1);
	}
	strcpy(k->cmd,cmd);
	k->flgs = flg;
	k->nxt = crontab;
	crontab = k;
	k->jobid = curjobid++;
	return(k->jobid);
}





static	int
lowest_quant()
{
	Kron	*k;
	int	lowest = 3600;

	for(k = crontab;k != (Kron *)0; k = k->nxt)
		if(k->interv < lowest)
			lowest = k->interv < CRONQUANT ? CRONQUANT : k->interv;
	return(lowest);
}





static	int
cron_del(jobid,who,pf)
int	jobid;
char	*who;
int	pf;
{
	Kron	*k;
	Kron	*p;

	k = p = crontab;

	while(k != (Kron *)0) {
		if(k->jobid == jobid) {
			int	squant;

			if(!pf && strcmp(who,k->who)) {
				say(who,"Permission denied.\n",(char *)0);
				return(UERR_PERM);
			}

			squant = k->interv;
			if(k == crontab)
				crontab = k->nxt;
			else
				p->nxt = k->nxt;

			if(k->cmd != (char *)0)
				free((mall_t)k->cmd);
			if(k->aswho != (char *)0)
				free((mall_t)k->aswho);
			if(k->who != (char *)0)
				free((mall_t)k->who);
			free((mall_t)k);
			if(squant <= cron_quantum) {
				cron_quantum = lowest_quant();
#ifdef	CRON_DEBUG
				printf("new cron quantum %d\n",cron_quantum);
#endif
			}
			say(who,"Event deleted.\n",(char *)0);
			return(UERR_NONE);
		}
		p = k;
		k = k->nxt;
	}
	say(who,"Unknown event.\n",(char *)0);
	return(UERR_NOMATCH);
}





static	void
cron_list(who)
char	*who;
{
	Kron	*k;
	char	pbuf[80];

	k = crontab;

	while(k != (Kron *)0) {
		sprintf(pbuf,"id# %d, every %d sec., ",k->jobid,k->interv);
		say(who,pbuf,(char *)0);

		if(k->runcnt != -1) {
			sprintf(pbuf,"%d runs, ",k->runcnt);
			say(who,pbuf,(char *)0);
		}

		sprintf(pbuf,"(%s/%s): %-30s\n",k->who,k->aswho,k->cmd);
		say(who,pbuf,(char *)0);
		k = k->nxt;
	}
}



/* ARGSUSED */
cmd__cronconfig(ac,av,who,aswho)
int	ac;
char	*av[];
char	*who;
char	*aswho;
{
	/* define an event */
	if(!strcmp(av[1],"defevent") || !strcmp(av[1],"defUevent")) {
		int	eid;
		int	iv;
		int	rc = -1; /* repeat forever */

		char	*twho;
		char	*taswho;
		int	flg = 0;

		if(!strcmp(av[1],"defUevent"))
			flg |= KRON_U;
		else
			flg |= KRON_CMD;

		if(ac < 4) {
			logf("usage: defevent interval macro [who] [aswho] [count]\n",(char *)0);
			return(UERR_ARGCNT);
		}


		if((iv = atoi(av[2])) < CRONQUANT) {
			logf("event interval is too short\n",(char *)0);
			iv = CRONQUANT;
		}

		if(iv < cron_quantum) {
			cron_quantum = iv;
#ifdef	CRON_DEBUG
			printf("new cron quantum %d\n",cron_quantum);
#endif
		}

		twho = who;
		if(ac > 4)
			twho = av[4];

		taswho = who;
		if(ac > 5)
			taswho = av[5];

		if(ac > 6)
			rc = atoi(av[6]);

		eid = cron_add(iv,rc,av[3],twho,taswho,flg);

		if(eid < 0) {
			logf("event not added\n",(char *)0);
			return(UERR_FATAL);
		}
		logf("added event: ",av[3],"\n",(char *)0);
		return(UERR_NONE);
	}


	/* UNdefine an event */
	if(!strcmp(av[1],"undefevent")) {
		if(ac != 3) {
			logf("usage: undefevent event-id\n",(char *)0);
			return(UERR_ARGCNT);
		}

		return(cron_del(atoi(av[2]),who,1));
	}

	if(!strcmp(av[1],"list")) {
		cron_list(who);
		return(UERR_NONE);
	}

	if(!strcmp(av[1],"help")) {
		say(who,av[0]," undefevent event-id\n",(char *)0);
		say(who,av[0]," defevent interval macro [who] [aswho] [count]\n",(char *)0);
		say(who,av[0]," list\n",(char *)0);
		return(UERR_NONE);
	}
	
	logf("_cronconfig: I don't understand ",av[1],"\n",(char *)0);
	return(UERR_BADPARM);
}


#ifdef	COMBAT
/* ARGSUSED */
cmd__crondel(ac,av,who,aswho)
int	ac;
char	*av[];
char	*who;
char	*aswho;
{
	return(cron_del(atoi(av[1]),who,0));
}




/* ARGSUSED */
cmd__cronlist(ac,av,who,aswho)
int	ac;
char	*av[];
char	*who;
char	*aswho;
{
	Kron	*k;
	char	pbuf[80];
	int	got = 0;

	for(k = crontab; k != (Kron *)0; k = k->nxt) {
		if(strcmp(who,k->who))
			continue;
		sprintf(pbuf,"id# %d, every %d sec., ",k->jobid,k->interv);
		say(who,pbuf,(char *)0);

		if(k->runcnt != -1) {
			sprintf(pbuf,"%d runs, ",k->runcnt);
			say(who,pbuf,(char *)0);
		}
		sprintf(pbuf,": %-30s\n",k->cmd);
		say(who,pbuf,(char *)0);
		got++;
	}
	if(!got)
		say(who,"No cron entries.\n",(char *)0);
	return(UERR_NONE);
}




/* ARGSUSED */
cmd__cron(ac,av,who,aswho)
int	ac;
char	*av[];
char	*who;
char	*aswho;
{
	int	eid;
	int	iv;
	int	rc = -1; /* repeat forever */
	char	*twho;
	int	flg = 0;

	if(!strcmp(av[0],"_Ucron"))
		flg |= KRON_U|KRON_BILL;
	else
		flg |= KRON_CMD|KRON_BILL;


	if(ac < 3) {
		say(who,"usage: ",av[0]," second-count command [repeats] [object-actor]\n",(char *)0);
		return(UERR_ARGCNT);
	}

	if((iv = atoi(av[1])) < CRONQUANT) {
		logf("event interval is too short\n",(char *)0);
		iv = CRONQUANT;
	}

	twho = who;
	if(ac > 4)
		twho = av[4];
	if(!ut_isobjown(aswho,twho) && !ut_flagged(aswho,var_wiz)) {
		say(who,"You do not own ",ut_name(twho),".\n",(char *)0);
		return(UERR_PERM);
	}

	if(ac > 3)
		rc = atoi(av[3]);


	if(iv < cron_quantum) {
		cron_quantum = iv;
#ifdef	CRON_DEBUG
		printf("new cron quantum %d\n",cron_quantum);
#endif
	}
	eid = cron_add(iv,rc,av[2],twho,twho,flg);

	if(eid < 0) {
		say(who,"Event not added.\n",(char *)0);
		return(UERR_FATAL);
	} else {
		char	fubb[MAXOID];
		say(who,"Added event ",itoa(eid,fubb),".\n",(char *)0);
		eval_cmd_returnint(eid);
		return(UERR_NONE);
	}
}
#endif