Generic connection object

    This object determines behavior for connections.

    Server methods:

        connect()                       Indicates onnection
        disconnect()                    Indicates disconnection
        parse(s)                        Indicates text line from user

    Private methods:

        echo_welcome()                  Echo welcome screen to user

    Commands:

        connect_cmd()                   Connect to an existing user
        create_cmd()                    Create a new user
        quit_cmd()                      Quit and log out

parent commands
object connection

var connection user 0
var connection addr 0
var connection port 0

method init
    arg ancestors;

    (> pass(ancestors) <);
    if (definer() in ancestors) {
        user = 0;
        addr = 0;
        port = 0;
    }
.

method uninit
    arg ancestors;

    if (!caller().is_agent('hierarchy))
	throw(~perm, "Caller is not an agent of hierarchy protocol.");
    catch any {
        if (definer() in ancestors) {
            if (user)
                user.connection_gone();
            user = 0;
        }
    }
    pass(ancestors);
.

eval
    .initialize();
    .set_name("Generic connection object");
    .add_command("conn?ect *", 'template, 'connect_cmd);
    .add_command("create *", 'template, 'create_cmd);
    .add_command("@quit", 'template, 'quit_cmd);
.

method tell
    arg s;

    if (sender() != user)
        throw(~perm, "Sender not the player.");
    echo(s);
.

method connect
    arg addr_arg, port_arg;

    if (sender() != 0)
        throw(~perm, "Sender not the server.");
    addr = addr_arg;
    port = port_arg;
    .echo_welcome();
    $sys.connection_starting();
.

method disconnect
    if (sender() != 0)
        throw(~perm, "Sender not the server.");
    if (user)
        user.connection_gone(addr, port);
    .destroy();
.

method parse
    arg str;
    var cmd;

    if (sender() != 0)
        throw(~perm, "Sender not the server.");

    // If we're logged in, forward the line to the player.
    if (user) {
        if (user.parse(str) == 'disconnect)
            disconnect();
        return;
    }

    // Display tracebacks, even though user may be clueless.
    catch any {
        cmd = .match_command(str);
        if (cmd)
            .(cmd[1])(@cmd[2]);
        else
            .echo_welcome();
    } with handler {
        for str in (traceback())
            echo(str);
    }
.

method echo_welcome
    if (sender() != this() || caller() != definer())
        throw(~perm, "Invalid access to private method.");
    if (!(| echo_file("welcome") |))
        echo("<The file 'welcome' is missing.>");
.

method connect_cmd
    arg dummy, words;
    var words, u, password, salt;

    if (sender() != this())
        throw(~perm, "Sender is not this.");

    // Get user name and password.
    words = explode(words);
    if (listlen(words) != 2) {
        echo("Usage: connect <name> <password>");
        return;
    }

    // Look for a user with the given name.
    catch ~usernf {
        u = $sys.find_user(words[1]);
    } with handler {
        echo("The user \"" + words[1] + "\" does not exist.");
        return;
    }

    // Check if the password is correct.
    if (!u.check_password(words[2])) {
        echo("That is the wrong password for " + words[1] + ".");
        return;
    }

    // Forward remaining lines to the user.
    user = u;
    user.connection_logged_in(addr, port);
.

method create_cmd
    arg dummy, words;
    var words;

    if (sender() != this())
        throw(~perm, "Sender is not this.");

    // Get user name and password.
    words = explode(words);
    if (listlen(words) != 2) {
        echo("Usage: create <name> <password>");
        return;
    }

    // Look for an existing user with the given name.
    catch ~usernf {
        $sys.find_user(words[1]);
        echo("The user \"" + words[1] + "\" already exists.");
        return;
    }

    // Create a new user and log it in.
    user = $sys.create_user(words[1], words[2]);
    user.connection_logged_in(addr, port);
.

method quit_cmd
    arg dummy;

    if (sender() != this())
        throw(~perm, "Sender is not this.");
    disconnect();
.