static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/player/login.c,v 2.6 1995/10/22 21:03:49 empire Exp $";

/*
 * player.c
 *
 * Allow the player to log in
 *
 * Dave Pare, 1994
 */

#include "misc.h"
#include "proto.h"
#include "player.h"
#include "com.h"
#include "lwp.h"
#include "io.h"

#ifdef aix
#include <unistd.h>
#endif /* aix */
#include <netinet/in.h>
#include <errno.h>

struct comstr login_coms[];

/*ARGSUSED*/
void
player_login(argc, argv, ud)
	int	argc;
	char	**argv;
	void	*ud;
{
	s_char	buf[128];
	s_char	space[512];
	s_char	*av[64];
	int	ac;
	int	cmd;

	
	player->proc = LwpCurrent;


	pr_id(player, C_INIT, "Empire server ready\n");

	while (!io_eof(player->iop) && !io_error(player->iop)) {
		io_output(player->iop, IO_WAIT);
		if (io_gets(player->iop, buf, sizeof(buf)) < 0) {
			io_input(player->iop, IO_WAIT);
			continue;
		}
		ac = parse(buf, av, 0, space, 0);
		cmd = comtch(av[0], login_coms, 0, 0);
		if (cmd < 0) {
			pr_id(player, C_BADCMD, "Command %s not found\n", av[0]);
			continue;
		}
		switch (login_coms[cmd].c_addr(player, ac, av)) {
		case RET_OK:
			break;
		case RET_FAIL:
			break;
		case RET_SYN:
			pr_id(player, C_BADCMD, "Usage %s\n", login_coms[cmd].c_form);
			break;
		default:
			break;
		}
		if (player->state >= PS_SHUTDOWN)
			break;
	}
	player->state = PS_SHUTDOWN;
	if (!io_eof(player->iop)) {
		(void) pr_player(player, C_EXIT, "so long...\n");
		io_noblocking(player->iop, 0);
		while (io_output(player->iop, IO_WAIT) > 0)
			;
	}
	player_delete(player); 
	lwpExit();
	/*NOTREACHED*/
}

int
client_cmd(player, ac, av)
	struct	player *player;
	int	ac;
	char	**av;
{
	int i;

	if (ac < 1 || av[1] == '\0')
		return RET_SYN;

	for (i = 1; i < ac; ++i) {
		if (i > 1)
			(void) strncat(player->client, " ", sizeof(player->client)-1);
		(void) strncat(player->client, av[i], sizeof(player->client)-1);
	}
	player->client[sizeof(player->client)-1] = '\0';
	pr_id(player, C_CMDOK, "talking to %s\n", player->client);
	return RET_OK;
}

int
user_cmd(player, ac, av)
	struct	player *player;
	int	ac;
	char	**av;
{
	if (ac < 1 || av[1] == '\0')
		return RET_SYN;
	(void) strncpy(player->userid, av[1], sizeof(player->userid)-1);
	player->userid[sizeof(player->userid)-1] = '\0';
	pr_id(player, C_CMDOK, "hello %s\n", player->userid);
	return RET_OK;
}

int
coun_cmd(player, ac, av)
	struct	player *player;
	int	ac;
	char	**av;
{
	natid	cnum;

	if (ac < 1 || av[1] == '\0')
		return RET_SYN;
	if (natbyname(av[1], &cnum) < 0) {
		pr_id(player, C_CMDERR, "country %s does not exist\n",av[1]);
		return 0;
	}
	player->cnum = cnum;
	player->validated = 0;
	pr_id(player, C_CMDOK, "country name %s\n", av[1]);
	return 0;
}

int
pass_cmd(player, ac, av)
	struct	player *player;
	int	ac;
	char	**av;
{
	if (ac < 1 || av[1] == '\0')
		return RET_SYN;
	if (player->cnum == 255) {
		pr_id(player, C_CMDERR, "need country first\n");
		return RET_FAIL;
	}
	if (!natpass(player->cnum, av[1])) {
		pr_id(player, C_CMDERR, "password bad, logging entry\n");
		logerror("%s tried country #%d with %s",
			 praddr(player), player->cnum, av[1]);
		return RET_FAIL;
	}
	player->validated++;
	pr_id(player, C_CMDOK, "password ok\n");
	logerror("%s using country #%d", praddr(player), player->cnum);
	return RET_OK;
}

/*ARGSUSED*/
int
play_cmd(player, ac, av)
	struct	player *player;
	int	ac;
	char	**av;
{
	extern char *banfil;
	struct	player *other;
	natid	cnum;

	if (ac == 4) {
		(void) strncpy(player->userid, av[1], sizeof(player->userid)-1);
		player->userid[sizeof(player->userid)-1] = '\0';
		player->validated = 0;
		if (natbyname(av[2], &cnum) < 0) {
			pr_id(player, C_CMDERR, "country %s does not exist\n", av[2]);
			return 0;
		}
		if (!natpass(cnum, av[3])) {
			pr_id(player, C_CMDERR, "password bad, logging entry\n");
			logerror("%s tried country #%d with %s",
				 praddr(player), cnum, av[3]);
			return RET_FAIL;
		}
		player->cnum = cnum;
		player->validated++;
	}
	if (player->cnum == 255 || !player->validated) {
		pr_id(player, C_CMDERR, "need country and password\n");
		return RET_FAIL;
	}
	if ((other = player_find_other(player, (natid)player->cnum)) != 0) {
		pr_id(player, C_EXIT, "country in use by %s\n",
		      praddr(other));
		return RET_FAIL;
	}
	if (match_user(banfil, player)) {
		logerror("Attempted login by BANNED host %s",
			 praddr(player));
		pr("Your login has been banned from this game\n");
		io_shutdown(player->iop, IO_READ);
		return RET_FAIL;
	}
	player_main(player);
	player->state = PS_SHUTDOWN;
	return RET_OK;
}

/*ARGSUSED*/
int
kill_cmd(player, ac, av)
	struct	player *player;
	int	ac;
	char	**av;
{
	struct	player *other;

	if (player->cnum == 255 || !player->validated) {
		pr_id(player, C_CMDERR, "need country and password\n");
		return RET_FAIL;
	}
	/* XXX find cnum other than us */
	if ((other = player_find_other(player, player->cnum)) == 0) {
		pr_id(player, C_EXIT, "country not in use\n");
		return RET_FAIL;
	}
	io_shutdown(other->iop, IO_READ|IO_WRITE);
	pr_id(player, C_EXIT, "closed socket of offending job\n");
	return RET_OK;
}

/*ARGSUSED*/
int
list_cmd(player, ac, av)
	struct	player *player;
	int	ac;
	char	**av;
{
	struct	player *lp;
	int	first = 1;

	if (player->cnum != 0 || !player->validated) {
		pr_id(player, C_CMDERR, "Permission denied\n");
		return 0;
	}
	for (lp = player_next(0); lp != 0; lp = player_next(lp)) {
		if (first) {
			pr_id(player, C_DATA, "user@host\tcountry\tpid\n");
			first = 0;
		}
		pr_id(player, C_DATA, "%s\t%d\n", praddr(lp), lp->cnum);
	}
	if (first == 0)
		pr_id(player, C_DATA, "\n");
	return 0;
}

/*ARGSUSED*/
int
quit_cmd(player, ac, av)
	struct	player *player;
	int	ac;
	char	**av;
{
	pr_id(player, C_EXIT, "so long\n");
	io_shutdown(player->iop, IO_READ);
	return RET_OK;
}

struct comstr login_coms[] = {
	"list",				0, list_cmd, 0, 0,
	"client clientname [version info]", 0, client_cmd, 0, 0,
	"user username",		0, user_cmd, 0, 0,
	"coun countryname",		0, coun_cmd, 0, 0,
	"pass password",		0, pass_cmd, 0, 0,
	"play [user country pass]",	0, play_cmd, 0, 0,
	"quit ",			0, quit_cmd, 0, 0,
	"kill {self}",			0, kill_cmd, 0, 0,
	0,				0, 0, 0, 0,
};
