phantasmal_dgd_v1/
phantasmal_dgd_v1/bin/
phantasmal_dgd_v1/doc/
phantasmal_dgd_v1/mud/doc/
phantasmal_dgd_v1/mud/doc/api/
phantasmal_dgd_v1/mud/doc/kernel/
phantasmal_dgd_v1/mud/doc/kernel/hook/
phantasmal_dgd_v1/mud/doc/kernel/lfun/
phantasmal_dgd_v1/mud/include/
phantasmal_dgd_v1/mud/include/kernel/
phantasmal_dgd_v1/mud/kernel/lib/
phantasmal_dgd_v1/mud/kernel/lib/api/
phantasmal_dgd_v1/mud/kernel/obj/
phantasmal_dgd_v1/mud/kernel/sys/
phantasmal_dgd_v1/mud/tmp/
phantasmal_dgd_v1/mud/usr/System/
phantasmal_dgd_v1/mud/usr/System/keys/
phantasmal_dgd_v1/mud/usr/System/obj/
phantasmal_dgd_v1/mud/usr/System/open/lib/
phantasmal_dgd_v1/mud/usr/common/data/
phantasmal_dgd_v1/mud/usr/common/lib/parsed/
phantasmal_dgd_v1/mud/usr/common/obj/telopt/
phantasmal_dgd_v1/mud/usr/common/obj/ustate/
phantasmal_dgd_v1/mud/usr/game/
phantasmal_dgd_v1/mud/usr/game/include/
phantasmal_dgd_v1/mud/usr/game/obj/
phantasmal_dgd_v1/mud/usr/game/object/
phantasmal_dgd_v1/mud/usr/game/object/stuff/
phantasmal_dgd_v1/mud/usr/game/sys/
phantasmal_dgd_v1/mud/usr/game/text/
phantasmal_dgd_v1/mud/usr/game/users/
phantasmal_dgd_v1/src/host/
phantasmal_dgd_v1/src/host/beos/
phantasmal_dgd_v1/src/host/mac/
phantasmal_dgd_v1/src/host/unix/
phantasmal_dgd_v1/src/host/win32/res/
phantasmal_dgd_v1/src/kfun/
phantasmal_dgd_v1/src/lpc/
phantasmal_dgd_v1/src/parser/
# include <kernel/kernel.h>
# include <kernel/user.h>

private object userd;		/* user daemon */
private int port;		/* port # */
private object user;		/* user object */
private string conntype;	/* connection type */
private int mode;		/* connection mode */
private int blocked;		/* connection blocked? */
private string buffer;		/* buffered output string */

/*
 * NAME:	create()
 * DESCRIPTION:	initialize
 */
static void create(string type)
{
    userd = find_object(USERD);
    conntype = type;
    mode = MODE_ECHO;	/* same as MODE_LINE for binary connection */
}


/*
 * NAME:	set_mode()
 * DESCRIPTION:	set the current connection mode
 */
static void set_mode(int newmode)
{
    if (newmode != mode && newmode != MODE_NOCHANGE) {
	if (newmode == MODE_DISCONNECT) {
	    destruct_object(this_object());
	} else {
	    rlimits (-1; -1) {
		if (newmode >= MODE_UNBLOCK) {
		    if (newmode - MODE_UNBLOCK != blocked) {
			block_input(blocked = newmode - MODE_UNBLOCK);
		    }
		} else {
		    if (blocked) {
			block_input(blocked = FALSE);
		    }
		    mode = newmode;
		}
	    }
	}
    }
}

/*
 * NAME:	query_mode()
 * DESCRIPTION:	return the current connection mode
 */
int query_mode()
{
    return (blocked) ? MODE_BLOCK : mode;
}


/*
 * NAME:	open()
 * DESCRIPTION:	open the connection
 */
static void open(mixed *tls)
{
    int timeout;
    string banner;

    banner = call_other(userd, "query_" + conntype + "_banner", port,
			this_object());
    if (banner) {
	send_message(banner);
    }

    timeout = call_other(userd, "query_" + conntype + "_timeout", port,
			 this_object());
    if (timeout < 0) {
	/* disconnect immediately */
	destruct_object(this_object());
	return;
    }

    if (!user && timeout != 0) {
	call_out("timeout", timeout);
    }
}

/*
 * NAME:	close()
 * DESCRIPTION:	close the connection
 */
static void close(mixed *tls, int dest)
{
    rlimits (-1; -1) {
	if (user) {
	    catch {
		user->logout(dest);
	    }
	}
	if (!dest) {
	    destruct_object(this_object());
	}
    }
}

/*
 * NAME:	disconnect()
 * DESCRIPTION:	break connection
 */
void disconnect()
{
    if (previous_program() == LIB_USER) {
	destruct_object(this_object());
    }
}

/*
 * NAME:	reboot()
 * DESCRIPTION:	destruct connection object after a reboot
 */
void reboot()
{
    if (previous_object() == userd || SYSTEM()) {
	if (user) {
	    catch {
		user->logout(FALSE);
	    }
	}
	destruct_object(this_object());
    }
}

/*
 * NAME:	set_port()
 * DESCRIPTION:	set the port number
 */
void set_port(int num)
{
    if (previous_object() == userd) {
	port = num;
    }
}

/*
 * NAME:	query_port()
 * DESCRIPTION:	return the port number
 */
int query_port()
{
    return port;
}

/*
 * NAME:	set_user()
 * DESCRIPTION:	set or change the user object directly
 */
void set_user(object obj, string str)
{
    if (KERNEL()) {
	user = obj;
	if (query_ip_number(this_object())) {
	    set_mode(obj->login(str));
	}
    }
}

/*
 * NAME:	query_user()
 * DESCRIPTION:	return the associated user object
 */
nomask object query_user()
{
    return user;
}

/*
 * NAME:	timeout()
 * DESCRIPTION:	if the connection timed out, disconnect
 */
static void timeout()
{
    if (!user || user->query_conn() != this_object()) {
	destruct_object(this_object());
    }
}

/*
 * NAME:	receive_message()
 * DESCRIPTION:	forward a message to user object
 */
static int receive_message(mixed *tls, string str)
{
    int mode;

    if (!user) {
	user = call_other(userd, conntype + "_user", port, str);
	set_mode(mode = user->login(str));
    } else {
	set_mode(mode = user->receive_message(str));
    }
    return mode;
}

/*
 * NAME:	message()
 * DESCRIPTION:	send a message across the connection
 */
int message(string str)
{
    if (previous_object() == user) {
	rlimits (-1; -1) {
	    int len;

	    len = send_message(str);
	    if (len != strlen(str)) {
		/*
		 * string couldn't be sent completely; buffer the remainder
		 */
		buffer = str[len ..];
		return FALSE;
	    } else {
		if (buffer) {
		    buffer = nil;
		}
		return TRUE;
	    }
	}
    }
}

/*
 * NAME:	message_done()
 * DESCRIPTION:	called when output is completed
 */
static void message_done(mixed *tls)
{
    if (buffer) {
	send_message(buffer);
	buffer = nil;
    } else if (user) {
	set_mode(user->message_done());
    }
}

/*
 * NAME:	datagram_challenge()
 * DESCRIPTION:	set the challenge for the datagram channel
 */
void datagram_challenge(string str)
{
    if (previous_object() == user) {
	::datagram_challenge(str);
    }
}

/*
 * NAME:	open_datagram()
 * DESCRIPTION:	open a datagram channel for this connection
 */
static void open_datagram(mixed *tls)
{
    if (user) {
	user->open_datagram();
    }
}

/*
 * NAME:	receive_datagram()
 * DESCRIPTION:	forward a datagram to the user
 */
static void receive_datagram(mixed *tls, string str)
{
    if (user) {
	user->receive_datagram(str);
    }
}

/*
 * NAME:	datagram()
 * DESCRIPTION:	send a datagram across the connection
 */
int datagram(string str)
{
    if (previous_object() == user) {
	return (send_datagram(str) == strlen(str));
    }
}