# include <kernel/kernel.h>
# include <kernel/user.h>
# ifdef SYS_NETWORKING
#  include <kernel/net.h>
#  define PORT	LIB_PORT
# else
#  define PORT	DRIVER
# endif
# include <status.h>


object *users;				/* user mappings */
object telnet_manager, binary_manager;	/* user object managers */
mapping names;				/* name : connection object */
object *connections;			/* saved connections */

/*
 * NAME:	create()
 * DESCRIPTION:	initialize object
 */
static void create()
{
    /* load essential objects */
    if (!find_object(TELNET_CONN)) { compile_object(TELNET_CONN); }
    if (!find_object(BINARY_CONN)) { compile_object(BINARY_CONN); }
    if (!find_object(DEFAULT_USER)) { compile_object(DEFAULT_USER); }

    /* initialize user arrays */
    users = ({ });
    names = ([ ]);
}

/*
 * NAME:	telnet_connection()
 * DESCRIPTION:	return a new telnet connection object
 */
object telnet_connection(mixed *tls)
{
    if (previous_program() == PORT) {
	return clone_object(TELNET_CONN);
    }
}

/*
 * NAME:	binary_connection()
 * DESCRIPTION:	return a new binary connection object
 */
object binary_connection(mixed *tls)
{
    if (previous_program() == PORT) {
	return clone_object(BINARY_CONN);
    }
}

/*
 * NAME:	set_telnet_manager()
 * DESCRIPTION:	set the telnet manager object, which determines what the
 *		user object is, based on the first line of input
 */
void set_telnet_manager(object manager)
{
    if (SYSTEM()) {
	telnet_manager = manager;
    }
}

/*
 * NAME:	set_binary_manager()
 * DESCRIPTION:	set the binary manager object, which determines what the
 *		user object is, based on the first line of input
 */
void set_binary_manager(object manager)
{
    if (SYSTEM()) {
	binary_manager = manager;
    }
}


/*
 * NAME:	telnet_user()
 * DESCRIPTION:	select user object for telnet connection, based on line of
 *		input
 */
object telnet_user(string str)
{
    if (previous_program() == LIB_CONN) {
	object user;

	user = names[str];
	if (!user) {
	    if (telnet_manager) {
		user = telnet_manager->select(str);
		if (function_object("query_conn", user) != LIB_USER) {
		    error("Invalid user object");
		}
	    } else {
		user = clone_object(DEFAULT_USER);
	    }
	}
	return user;
    }
}

/*
 * NAME:	binary_user()
 * DESCRIPTION:	select user object for binary connection, based on line of
 *		input
 */
object binary_user(string str)
{
    if (previous_program() == LIB_CONN) {
	object user;

	user = names[str];
	if (!user) {
	    if (binary_manager && str != "admin") {
		user = binary_manager->select(str);
		if (function_object("query_conn", user) != LIB_USER) {
		    error("Invalid user object");
		}
	    } else {
		user = clone_object(DEFAULT_USER);
	    }
	}
	return user;
    }
}

/*
 * NAME:	query_telnet_timeout()
 * DESCRIPTION:	return the current telnet connection timeout
 */
int query_telnet_timeout()
{
    if (previous_program() == LIB_CONN) {
	return (telnet_manager) ?
		telnet_manager->query_timeout(previous_object()) :
		DEFAULT_TIMEOUT;
    }
}

/*
 * NAME:	query_binary_timeout()
 * DESCRIPTION:	return the current binary connection timeout
 */
int query_binary_timeout()
{
    if (previous_program() == LIB_CONN) {
	return (binary_manager) ?
		binary_manager->query_timeout(previous_object()) :
		DEFAULT_TIMEOUT;
    }
}

/*
 * NAME:	query_telnet_banner()
 * DESCRIPTION:	return the current telnet login banner
 */
string query_telnet_banner()
{
    if (previous_program() == LIB_CONN) {
	return (telnet_manager) ?
		telnet_manager->query_banner(previous_object()) :
		"\nDGD " + status()[ST_VERSION] + " (telnet)\n\nlogin: ";
    }
}

/*
 * NAME:	query_binary_banner()
 * DESCRIPTION:	return the current binary login banner
 */
string query_binary_banner()
{
    if (previous_program() == LIB_CONN) {
	return (binary_manager) ?
		binary_manager->query_banner(previous_object()) :
		"\r\nDGD " + status()[ST_VERSION] + " (binary)\r\n\r\nlogin: ";
    }
}


/*
 * NAME:	login()
 * DESCRIPTION:	login user
 */
void login(object user, string name)
{
    if (previous_program() == LIB_USER) {
	users = (users - ({ nil })) | ({ user });
	names[name] = user;
    }
}

/*
 * NAME:	logout()
 * DESCRIPTION:	log user out
 */
void logout(object user, string name)
{
    if (previous_program() == LIB_USER) {
	users -= ({ user });
	names[name] = nil;
    }
}


/*
 * NAME:	query_users()
 * DESCRIPTION:	return the current telnet and binary users
 */
object *query_users()
{
    if (previous_program() == AUTO) {
	object *usr;
	int i, changed;

	usr = users - ({ nil });
	changed = FALSE;
	for (i = sizeof(usr); --i >= 0; ) {
	    if (!usr[i]->query_conn()) {
		usr[i] = nil;
		changed = TRUE;
	    }
	}
	return (changed) ? usr - ({ nil }) : usr;
    }
}

/*
 * NAME:	query_connections()
 * DESCRIPTION:	return the current connections
 */
object *query_connections()
{
    if (previous_program() == API_USER) {
	return users();
    }
}

/*
 * NAME:	find_user()
 * DESCRIPTION:	find the user associated with a certain name
 */
object find_user(string name)
{
    if (previous_program() == API_USER) {
	return names[name];
    }
}


/*
 * NAME:	prepare_reboot()
 * DESCRIPTION:	prepare for a reboot
 */
void prepare_reboot()
{
    if (previous_program() == DRIVER) {
	connections = users();
    }
}

/*
 * NAME:	reboot()
 * DESCRIPTION:	handle a reboot
 */
void reboot()
{
    if (previous_program() == DRIVER) {
	int i;

	for (i = sizeof(connections); --i >= 0; ) {
	    connections[i]->reboot();
	}

	connections = nil;
	users = ({ });
	names = ([ ]);
    }
}
