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

/*
 * candidate.c
 *
 * get a new candidate
 *
 * Dave Pare, 1986
 */

#include <stdio.h>
#include "misc.h"
#include "login.h"
#include "tm.h"
#include "proto.h"

#include <sys/socket.h>
#include <netinet/in.h>
#ifdef	BIND
#include <netdb.h>
#endif	BIND

struct	candidate canlist;
int	maxcandidates;
int	ncandidates;

cd_init()
{
	extern	int errno;

	initque(&canlist.queue);
	maxcandidates = getfdtablesize() - 4;
	ncandidates = 0;
	logerror("max candidates is %d", maxcandidates);
}

/*ARGSUSED*/
cd_new(iop, op, assoc)
	iop_t	iop;
	int	op;
	char	*assoc;
{
	extern	service();
	extern	char *inet_ntoa();
	register struct candidate *cp;
	struct	sockaddr_in sin;
	int	foo;
	int	ns;
	int	set = 1;
#ifdef	BIND
	struct hostent	*host;
#endif	BIND

	foo = sizeof(sin);
	ns = accept(io_fileno(iop), (struct sockaddr *) &sin, &foo);
	if (ns < 0) {
		logerror("new socket accept");
		return;
	}
	(void) setsockopt(ns, SOL_SOCKET, SO_KEEPALIVE, &set, sizeof(set));
	if (ns >= maxcandidates) {
		close(ns);
		logerror("new fd %d, max fd %d, no fd's left for new user!",
			ns, maxcandidates);
		return;
	}
	cp = (struct candidate *) malloc(sizeof(*cp));
#ifdef	BIND
	host = gethostbyaddr((char *)&(sin.sin_addr),
		sizeof(sin.sin_addr),AF_INET);
		
	if (host != NULL)
		strncpy(cp->remhost,host->h_name,sizeof(cp->remhost));
	else
#endif	BIND
		strcpy(cp->remhost, inet_ntoa(sin.sin_addr));
	cp->cnum = -1;
	*cp->countryname = 0;
	*cp->password = 0;
	*cp->remuser = 0;
	cp->cmd = 0;
	cp->state = 0;
	cp->iop = io_open(ns, IO_READ|IO_WRITE, 512, service, (char *)cp);
	if (cp->iop == 0) {
		(void) close(ns);
		logerror("io_open failed");
		return;
	}
	insque(&cp->queue, &canlist.queue);
	sendclient(cp->iop, C_INIT, "Empire server ready");
}

cd_delete(cp)
	struct	candidate *cp;
{
	extern	int iswatching;

	if (cp->iop)
		io_close(cp->iop);
	remque(&cp->queue);
	free((char *)cp);
	if (iswatching)
		dowatch();
}

struct candidate *
cd_next(cp)
	struct	candidate *cp;
{
	if (cp == 0)
		cp = (struct candidate *) canlist.queue.q_forw;
	else
		cp = (struct candidate *) cp->queue.q_forw;
	if (cp == &canlist)
		return 0;
	return cp;
}
