# 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