/
umud/DOC/
umud/DOC/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: /usr/users/mjr/hacks/umud/RCS/mud.c,v 1.4 91/08/18 21:49:48 mjr Exp $";
#endif


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


#include	<stdio.h>

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

#ifndef VMS
#include	<sys/param.h>
#endif

#ifdef	DAEMON
#include	<signal.h>
#endif

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

/* GLOBAL !*/
int	cron_quantum = 3600;	/* one hour */

static	int	mud_running = 1;
static	char	*mud_myname = (char *)0;


time_t	cronlast;
time_t	currtime;



static	int
usage()
{
	fprintf(stderr,"usage: mud -c configfile -s startupfile\n");
	return(1);
}




/* choke down a file full of commands */
static	int
boot_file(path)
char	*path;
{
	FILE	*bfp;
	char	ibuf[BUFSIZ];

	if((bfp = fopen(path,"r")) == (FILE *)0) {
		logf("can't open ",path,": ",(char *)-1,"\n",(char *)0);
		return(1);
	}

	while(fgets(ibuf,sizeof(ibuf),bfp) != (char *)0)
		if(ibuf[0] != '#' && ibuf[0] != '\n')
			(void)run_boot(ibuf);
	fclose(bfp);
	return(0);
}




/* initiate shutdown (used in signal handlers) */
static	void
shutdown_mud()
{
	logf("mud is down.\n",(char *)0);
	mud_running = 0;
}




/* as simple as possible */
main(ac,av)
int	ac;
char	*av[];
{
	int	x;
	char	*config = (char *)0;
	char	*startup = (char *)0;

	for(x = 1; x < ac; x++) {
		if(av[x][0] == '-') {
			switch(av[x][1]) {
			case 'c':
				config = av[++x];
				break;

			case 's':
				startup = av[++x];
				break;
			default:
				exit(usage());
			}
		} else {
			exit(usage());
		}
	}



	/* if there is a configuration file, run it */
	if(config != (char *)0 && boot_file(config))
		fatal("configure failed.\n",(char *)0);


	syminit();

	if(io_init()) {
		fatal("network init failed\n",(char *)0);
		exit(1);
	}

	if(cache_init()) {
		fatal("cache init failed\n",(char *)0);
		exit(1);
	}


	if(DB_INIT()) {
		fatal("database init failed\n",(char *)0);
		exit(1);
	}


	/* all I/O layers are initialized, now run startup file if one */
	if(startup != (char *)0 && boot_file(startup))
		fatal("startup failed.\n",(char *)0);


	/* MUD name must be set */
	if(mud_myname == (char *)0)
		fatal("mud server name is unset\n",(char *)0);

#ifdef	DAEMON
	(void)signal(SIGINT,shutdown_mud);
	(void)signal(SIGTERM,shutdown_mud);
	(void)signal(SIGQUIT,shutdown_mud);
#endif

	while(mud_running) {
		if(io_loop() != 0)
			break;

		/* flush I/O buffers */
		io_sync();

		/* reset cache pointers */
		cache_reset();


		/* maintenance/cron routines ? */
		(void)time(&currtime);
		if(currtime - cronlast > cron_quantum) {
			(void)cron_run(currtime);
			cronlast = currtime;
		}

		/* free any temporarily allocated memory */
		tmp_sync();
	}

	/* orderly shutdown */
	(void)cache_sync();
	DB_CLOSE();

#ifdef	USE_RWHO
	rwhocli_shutdown();
#endif
	exit(0);
}




/* return our protected name */
char	*
mud_getname()
{
	return(mud_myname);
}




/* ARGSUSED */
cmd__mudconfig(ac,av,who,aswho)
int	ac;
char	*av[];
char	*who;
char	*aswho;
{
	if(!strcmp(av[1],"shutdown")) {
		logf("shutdown by ",who,"\n",(char *)0);
		shutdown_mud();
		return(0);
	}

	if(!strcmp(av[1],"log")) {
		if(ac != 3)
			return(1);
		if(logf_open(av[2]))
			return(1);
		logf("log is now ",av[2],"\n",(char *)0);
		return(0);
	}

	if(!strcmp(av[1],"chdir")) {
		if(ac != 3) {
			logf("chdir: must provide directory.\n",(char *)0);
			return(1);
		}
		if(chdir(av[2])) {
			logf("cannot cd to ",av[2]," ",(char *)-1,"\n",(char *)0);
			return(1);
		}
		logf("working directory is now ",av[2],"\n",(char *)0);
		return(0);
	}

	if(!strcmp(av[1],"name")) {
		if(ac != 3 || av[2][0] == '\0') {
			logf("must provide mud name.\n",(char *)0);
			return(1);
		}
		if(mud_myname != (char *)0) {
			logf("mud name is already set!\n",(char *)0);
			return(1);
		}
		mud_myname = (char *)malloc((unsigned)strlen(av[2]) + 1);
		if(mud_myname == (char *)0)
			fatal("cannot allocate mud name buffer!\n",(char *)0);
		(void)strcpy(mud_myname,av[2]);
		logf("mud name is ",mud_myname,"\n",(char *)0);
		return(0);
	}

#ifdef	DAEMON
	/* daemonize ourself */
	if(!strcmp(av[1],"daemonize")) {
		(void)signal(SIGHUP,SIG_IGN);
		(void)signal(SIGCHLD,SIG_IGN);
		(void)signal(SIGALRM,SIG_IGN);
		if(fork())
			exit(0);
#ifdef	SETSID
		(void)setsid();
#endif
		logf("daemonized.\n",(char *)0);
		return(0);
	}
#endif

	/* define a known remote MUD */
	if(!strcmp(av[1],"defmud")) {
		char	*timp = (char *)0;

		if(ac < 9 || ac > 10) {
			logf("usage: defmud name host symbolichost remotepassword localpassword port playerport [timeout]\n",(char *)0);
			return(1);
		}
		if(ac == 10)
			timp = av[9];
		if(xmit_def_mudent(av[2],av[3],av[4],av[5],av[6],av[7],av[8],timp)) {
			logf("mud entry ",av[2]," NOT defined\n",(char *)0);
			return(1);
		}
		logf("added mud entry ",av[2],"\n",(char *)0);
		return(1);
	}

	if (!strcmp(av[1], "defknownmud")) {
		if (ac != 3) {
			logf("usage: defknownmud name\n", (char *) 0);
			return 1;
		}
		if (xmit_def_knownmud(av[2])) {
			logf("known-mud entry ", av[2], " NOT defined\n", (char *)0);
			return 1;
		}
		logf("added known mud ", av[2], "\n", (char *) 0);
		return 1;
	}

	/* define a global macro */
	if(!strcmp(av[1],"defmac")) {
		if(ac != 4) {
			logf("usage: defmac name macro\n",(char *)0);
			return(1);
		}
		if(symdef(av[2],av[3])) {
			logf("macro defn failed ",(char *)-1,"\n",(char *)0);
			return(1);
		}
		logf("defn macro ",av[2],"\n",(char *)0);
		return(0);
	}

	/* UNdefine a global macro */
	if(!strcmp(av[1],"undefmac")) {
		if(ac != 3) {
			logf("usage: undefmac name\n",(char *)0);
			return(1);
		}
		if(symundef(av[2])) {
			logf("macro undefined: ",av[2],"\n",(char *)0);
			return(1);
		}
		logf("undefn macro ",av[2],"\n",(char *)0);
		return(0);
	}

#ifdef	USE_RWHO
	if(!strcmp(av[1],"rwhoserver")) {
		char	*info;

		if(ac < 4) {
			logf("usage: rwhoserver hostname password\n",(char *)0);
			return(1);
		}

		info = ac > 4 ? av[4] : version;

		if(mud_myname == (char *)0) {
			logf("must set MUD name first\n",(char *)0);
			return(1);
		}
		if(rwhocli_setup(av[2],av[3],mud_myname,info)) {
			logf("could not establish RWHO server\n",(char *)0);
			return(1);
		}
		return(0);
	}

	if(!strcmp(av[1],"rwhodown")) {
		rwhocli_shutdown();
		logf("rwho service shut down\n",(char *)0);
		return(0);
	}

	if(!strcmp(av[1],"rwhoupdate")) {
		update_rwho();
		return(0);
	}
#endif

	/* backup */
	if(!strcmp(av[1],"backup")) {
		int	sequence;
		int	modulus = 0;
		char	nxbuf[MAXOID];
		char	filename[MAXPATHLEN];
		FILE	*fp;

		if(ac != 3 && ac != 4) {
			logf("usage: backup <filename> [modulus]\n",(char *)0);
			return(1);
		}

		/* check for modulus */
		if( ac == 4 )
			modulus = atoi(av[3]);

		/* get the backup sequence number */
		if(ut_getnum(system_object,var_bsequence,&sequence))
			sequence = 0;

		sequence++;

		if(modulus > 0)
			sequence %= modulus;

		/* assume this works */
		ut_setnum(who,system_object,var_bsequence,sequence);

		itoa(sequence,nxbuf);

		if(cache_sync()) {
			logf("couldn't sync cache for backup #",
			     nxbuf,"\n",(char *)0);
			return(1);
		}
		sprintf(filename,"%s.%s",av[2],nxbuf);

		if(DB_BACKUP(filename)) {
			logf("couldn't write backup file ",filename,"\n",
			     (char *)0);
			return(1);
		}

		logf("wrote backup file ",filename,"\n",(char *)0);
		return(0);
	}



	if(!strcmp(av[1],"help")) {
		say(who,av[0]," shutdown\n",(char *)0);
		say(who,av[0]," log file-name\n",(char *)0);
		say(who,av[0]," chdir directory-name\n",(char *)0);
		say(who,av[0]," name mud-name\n",(char *)0);
#ifdef	DAEMON
		say(who,av[0]," daemonize\n",(char *)0);
#endif
		say(who,av[0]," defmud MUDname hostIP-addr hostname remotepassword localpassword serverport playerport [timeout]\n",(char *)0);
		say(who,av[0]," defknownmud MUDname\n",(char *)0);
		say(who,av[0]," defmac name macro\n",(char *)0);
		say(who,av[0]," undefmac name\n",(char *)0);
#ifdef	USE_RWHO
		say(who,av[0]," rwhoserver hostname password [comment]\n",(char *)0);
		say(who,av[0]," rwhodown\n",(char *)0);
#endif
		say(who,av[0]," backup file-name [modulus]\n",(char *)0);
		return(0);
	}
	
	logf("_mudconfig: I don't understand ",av[1],"\n",(char *)0);
	return(0);
}