# include "phantasmal/ssh.h"

# define DEBUG SSH_DEBUG

inherit conn LIB_CONN;
inherit user LIB_USER;


/* ========================================================================= *
 *			SSH glue for the kernel library                      *
 * ========================================================================= */

static void start_transport(string str);      /* supplied by transport layer */
static void create_ssh();

private string name;		/* name of this user */
private int tried_password;	/* password flag; by default only one attempt */


/*
 * NAME:	message()
 * DESCRIPTION:	send a message to the other side
 */
static int message(string str)
{
    return user::message(str);
}

/*
 * NAME:	message_done()
 * DESCRIPTION:	forward message_done to user
 */
static int message_done()
{
    object user;
    mixed mode;

    user = query_user();
    if (user) {
	mode = user->message_done();
	if (mode && (mode == MODE_DISCONNECT || mode >= MODE_UNBLOCK)) {
	    return mode;
	}
    }
    return MODE_NOCHANGE;
}

/*
 * NAME:	login()
 * DESCRIPTION:	accept a SSH connection
 */
int login(string str)
{
    if (previous_program() == LIB_CONN) {
	user::connection(previous_object());
	previous_object()->set_mode(MODE_RAW);
	start_transport(str);
    }
    return MODE_RAW;
}

/*
 * NAME:	logout()
 * DESCRIPTION:	disconnect
 */
void logout(int quit)
{
    if (previous_program() == LIB_CONN) {
	conn::close(nil, quit);
	if (quit) {
	    destruct_object(this_object());
	}
    }
}

/*
 * NAME:	set_mode()
 * DESCRIPTION:	pass on mode changes to the real connection object
 */
void set_mode(int mode)
{
    if (SYSTEM() && mode >= MODE_UNBLOCK) {
	query_conn()->set_mode(mode);
    }
}

/*
 * NAME:	user_input()
 * DESCRIPTION:	send input to user object
 */
static int user_input(string str)
{
    DRIVER->message(object_name(this_object())+":user_input(\""+str+"\") from "+previous_program()+"\n");
    return conn::receive_message(nil, str);
}

/*
 * NAME:	datagram_challenge()
 * DESCRIPTION:	there is no datagram channel to be opened
 */
void datagram_challenge(string str)
{
}

/*
 * NAME:	datagram()
 * DESCRIPTION:	don't send a datagram to the client
 */
int datagram(string str)
{
    return 0;
}

/*
 * NAME:	disconnect()
 * DESCRIPTION:	forward a disconnect to the connection
 */
void disconnect()
{
    if (previous_program() == LIB_USER) {
	user::disconnect();
    }
}

/*
 * NAME:	ssh_get_user()
 * DESCRIPTION:	check if user exists and can login
 */
static int ssh_get_user(string str)
{
    set_port(SSH_PORT);
    if (name) {
	return (str == name && !tried_password && query_user());
    } else {
	name = str;
	return (user_input(str) != MODE_DISCONNECT && query_user());
    }
}

/*
 * NAME:	check_password()
 * DESCRIPTION:	check whether a supplied password is correct
 */
static int ssh_check_password(string str)
{
    if (tried_password) {
	return FALSE;
    }
    tried_password = TRUE;
    DRIVER->message("ssh_check_password("+str+")\n");
    return (user_input(str) != MODE_DISCONNECT);
}

/*
 * NAME:	ssh_login()
 * DESCRIPTION:	actually login the user
 */
static void ssh_login()
{
    query_user()->do_login();
}

/*
 * NAME:	ssh_shell()
 * DESCRIPTION:	a shell session has been started
 */
static void ssh_shell()
{
}

/*
 * NAME:	create_glue()
 * DESCRIPTION:	initialize ssh kernel glue
 */
static void create_glue()
{
    conn::create("telnet");	/* pretend */
}

/*
 * NAME:	create()
 * DESCRIPTION:	initialize ssh object
 */
static void create(int clone)
{
    if (clone) {
	create_ssh();
        conn::set_port(SSH_PORT);
    }
}

int query_port() { return SSH_PORT; }
