# include <kernel/kernel.h> # include <kernel/user.h> private object userd; /* user daemon */ 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 */ } # ifdef __SKOTOS__ /* * NAME: execute_program() * DESCRIPTION: execute a program on the host */ void execute_program(string cmdline) { if (previous_program() == AUTO) { user = previous_object(); ::execute_program(cmdline); } } /* * NAME: _program_terminated() * DESCRIPTION: internal version of program_terminated() */ private void _program_terminated(mixed *tls) { user->program_terminated(); destruct_object(this_object()); } /* * NAME: program_terminated() * DESCRIPTION: called when the executing program has terminated */ static void program_terminated() { _program_terminated(allocate(DRIVER->query_tls_size())); } # endif /* __SKOTOS__ */ # ifdef SYS_NETWORKING /* * NAME: connect() * DESCRIPTION: establish an outbount connection */ void connect(string destination, int port) { if (previous_program() == AUTO) { ::connect(destination, port); user = previous_object(); } } # endif /* * 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 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"); if (banner) { send_message(banner); } timeout = call_other(userd, "query_" + conntype + "_timeout"); if (timeout < 0) { /* disconnect immediately */ destruct_object(this_object()); return; } if (!user && timeout != 0) { call_out("timeout", timeout); } # ifdef SYS_NETWORKING else { set_mode(user->login(nil)); } # endif } /* * 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_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 */ 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 void receive_message(mixed *tls, string str) { if (!user) { user = call_other(userd, conntype + "_user", str); set_mode(user->login(str)); } else { set_mode(user->receive_message(str)); } } /* * NAME: message() * DESCRIPTION: send a message across the connection */ int message(string str) { if (previous_object() == user) { int len; buffer = nil; len = send_message(str); if (len != strlen(str)) { /* * string couldn't be sent completely; buffer the remainder */ buffer = str[len ..]; return FALSE; } else { 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()); } } # if defined(SYS_DATAGRAMS) && !defined(SYS_NETWORKING) /* * 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)); } } # endif