#ifndef lint
static char *RCSid = "$Header: cmds.c,v 1.11 90/04/13 12:27:35 mr-frog Exp $";
#endif

/*
 * cmds.c
 *
 * identify remote host, candidate, et al..
 *
 * Dave Pare, 1986
 */

#include "misc.h"
#include "proto.h"
#include "login.h"

#include <signal.h>
#include <fcntl.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/errno.h>

#ifndef X_OK
#include <sys/file.h>
#endif

int
user(cp, name)
	struct	candidate *cp;
	char	*name;
{
	if ((name && *name) == 0) {
		sendclient(cp->iop, C_CMDERR, "missing name");
		return 0;
	}
	(void) strncpy(cp->remuser, name, sizeof(cp->remuser)-1);
	cp->remuser[sizeof(cp->remuser)-1] = '\0';
	sendclient(cp->iop, C_CMDOK, "hello %s", cp->remuser);
	return 0;
}

/*ARGSUSED*/
int
quit(cp, arg)
	struct	candidate *cp;
	char	*arg;
{
	sendclient(cp->iop, C_EXIT, "so long");
	io_output(cp->iop);
	io_shutdown(cp->iop, IO_WRITE);
	cd_delete(cp);
	return 1;
}

int
coun(cp, name)
	struct	candidate *cp;
	char	*name;
{
	int	cnum;

	if ((name && *name) == 0) {
		sendclient(cp->iop, C_CMDERR,
			"coun command requires name argument");
		return 0;
	}
	if ((cnum = natbyname(name)) < 0) {
		sendclient(cp->iop, C_CMDERR, "country %s does not exist",name);
		return 0;
	}
	cp->cnum = cnum;
	*cp->password = 0;
	(void) strncpy(cp->countryname, name, sizeof(cp->countryname)-1);
	cp->countryname[sizeof(cp->countryname)-1] = '\0';
	sendclient(cp->iop, C_CMDOK, "country name %s", cp->countryname);
	return 0;
}

int
pass(cp, passwd)
	struct	candidate *cp;
	char	*passwd;
{
	if ((passwd && *passwd) == 0) {
		sendclient(cp->iop, C_CMDERR,
			"pass command requires password argument");
		return 0;
	}
	if (*cp->countryname == 0) {
		sendclient(cp->iop, C_CMDERR, "missing country name");
		return 0;
	}
	strncpy(cp->password, passwd, sizeof(cp->password)-1);
	cp->password[sizeof(cp->password)-1] = '\0';
	if (natpass(cp->cnum, cp->password)) {
		sendclient(cp->iop, C_CMDOK, "password ok");
		logerror("%s@%s using country %s", cp->remuser,
			cp->remhost, cp->countryname);
	} else {
		sendclient(cp->iop, C_CMDERR, "password bad, logging entry");
		logerror("%s@%s tried country %s with %s",
			cp->remuser, cp->remhost, cp->countryname,
			cp->password);
		cp->password[0] = 0;
	}
	return 0;
}

/*ARGSUSED*/
int
play(cp, arg)
	struct	candidate *cp;
	char	*arg;
{
	extern	char playerbin[];
	extern	int errno;
	int	pid;
	int	i;
	int	val = 1;
	char	country[40];
	char	buf[120];
	struct	login *lp;

	if (*cp->password == 0) {
		sendclient(cp->iop, C_CMDERR, "no password entered");
		return 0;
	}
	if (cp->cnum < 0) {
		sendclient(cp->iop, C_CMDERR, "no country entered");
		return 0;
	}
	if ((lp = lo_cnum((natid)cp->cnum)) != 0) {
		if (kill(lp->pid, 0) < 0) {
			logerror("country %d 'in use' but pid %d not found",
				cp->cnum, lp->pid);
			lo_delete(lp);
		} else {
			sendclient(cp->iop, C_EXIT, 
				"country in use by %s@%s (pid=%d)",
				lp->remuser, lp->remhost, lp->pid);
			return 0;
		}
	}
	io_output(cp->iop);
#ifndef linux
	if (access(playerbin, X_OK) == -1) {
		sprintf(buf, "cannot execute %s!", playerbin);
		sendclient(cp->iop, C_EXIT, buf);
		return 0;
	}
#endif
	pid = fork();
	if (pid == -1) {
		logerror("fork error");
		sendclient(cp->iop, C_DATA, "fork error on server end");
		return 0;
	}
	if (pid != 0) {
		lp = lo_new();
		lp->cnum = cp->cnum;
		lp->pid = pid;
		strcpy(lp->remuser, cp->remuser);
		strcpy(lp->remhost, cp->remhost);
		cd_delete(cp);
		return 1;
	}
	if (setsockopt(io_fileno(cp->iop), SOL_SOCKET, SO_KEEPALIVE,
	    &val, sizeof(val)) < 0)
		logerror("play setsockopt error");
	dup2(io_fileno(cp->iop), 0);
	dup2(io_fileno(cp->iop), 1);
	dup2(io_fileno(cp->iop), 2);
#ifdef notdef
	setfdtablesize(20);
#endif
	for (i=getfdtablesize()-1; i >= 3; i--)
		close(i);
	sprintf(country, "%d", cp->cnum);
#ifdef BAN
	execl(playerbin, "emp_player", country, cp->remuser, cp->remhost, 0);
#else
	execl(playerbin, "emp_player", country, 0);
#endif /* BAN */
	sprintf(buf, "%x cannot exec %s, error %d\n", C_EXIT, playerbin, errno);
	write(1, buf, strlen(buf));
	exit(1);
	/*NOTREACHED*/
}

/*ARGSUSED*/
int
killpl(cp, arg)
	struct	candidate *cp;
	char	*arg;
{
	extern	char playerbin[];
	extern	int errno;
	int	pid;
	int	i;
	int	val = 1;
	char	country[40];
	char	buf[120];
	struct	login *lp;

	if (*cp->password == 0)
		sendclient(cp->iop, C_CMDERR, "no password entered");
	else if (cp->cnum < 0)
		sendclient(cp->iop, C_CMDERR, "no country entered");
	else if ((lp = lo_cnum((natid)cp->cnum)) != 0) {
		if (kill(lp->pid, 0) < 0) {
			logerror("country %d 'in use' but pid %d not found",
				cp->cnum, lp->pid);
			lo_delete(lp);
			sendclient(cp->iop, C_EXIT, "process terminated");
		} else if (kill(lp->pid, SIGKILL) < 0)
			sendclient(cp->iop, C_EXIT,
				"process %d cannot be terminated", lp->pid);
		else
			sendclient(cp->iop, C_EXIT, 
				"process %d (from %s@%s) terminated",
				lp->pid, lp->remuser, lp->remhost);
	}
	else
		sendclient(cp->iop, C_EXIT, "country not in use");

	return 0;
}

/*ARGSUSED*/
int
list(us, arg)
	struct	candidate *us;
	char	*arg;
{
	register struct login *lp;
	int	first = 1;

	if (us->cnum != 0 || us->password[0] == 0) {
		sendclient(us->iop, C_CMDERR, "Permission denied");
		return 0;
	}
	lp = 0;
	while (lp = lo_next(lp)) {
		if (first) {
			sendclient(us->iop, C_DATA, "user@host\tcountry\tpid");
			first = 0;
		}
		sendclient(us->iop, C_DATA, "%s@%s\t%d\t%d",
			lp->remuser, lp->remhost, lp->cnum, lp->pid);
	}
	if (first == 0)
		sendclient(us->iop, C_DATA, 0);
	return 0;
}

int	iswatching;

/*ARGSUSED*/
int
wat(cp, arg)
	register struct candidate *cp;
	char	*arg;
{
	if (cp->state == STAT_WATCH) {
		cp->state = STAT_NORM;
		iswatching--;
		return 0;
	}
	iswatching++;
	list(cp, 0);
	cp->state = STAT_WATCH;
	return 0;
}
