# 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));
}
}