/
ColdCore-3.0a9.02/
ColdCore-3.0a9.02/src/
new object $connection: $network;

var $connection active = 0;
var $connection buffer = `[];
var $connection daemon = 0;
var $connection foreign_addr = 0;
var $connection host = "";
var $connection interface = 0;
var $connection line_buffer = 0;
var $connection local_addr = 0;
var $connection local_port = 0;
var $connection port = 0;
var $connection read_block = [];
var $connection remote_addr = 0;
var $connection remote_name = 0;
var $connection remote_port = 0;
var $connection started_at = 0;
var $connection tid = 0;
var $connection timeout = 0;
var $root created_on = 809051864;
var $root defined_settings = #[["interface", #[['get, ['get_interface]], ['set, ['set_interface]], ['parse, ['parse_interface]]]]];
var $root flags = ['methods, 'code, 'core, 'variables];
var $root inited = 1;
var $root managed = [$connection];
var $root manager = $connection;

public method .abort_reading_block() {
    (> .perms(sender()) <);
    read_block = read_block.add('lines, 'aborted);
    .finish_reading_block();
};

public method .active() {
    return active;
};

public method .active_since() {
    return active;
};

public method .address() {
    arg @nolookup;
    var name;
    
    (> .perms(sender()) <);
    return remote_addr;
    if (!remote_name) {
        name = (| $dns.hostname(remote_addr) |);
        if (name)
            remote_name = name;
        else
            remote_name = remote_addr;
    }
    return remote_name;
};

public method .change_connection_interface() {
    arg old, new;
    var i;
    
    (> .perms(caller(), $connection) <);
    if (old)
        sender().del_writer((| class(old) |) || old);
    sender().add_writer((| class(new) |) || new);
};

public method .change_interface() {
    arg new;
    var old;
    
    (> .perms(sender()) <);
    if (interface) {
        old = interface;
        old.connection_going_away(.address(), remote_port);
    }
    interface = new;
    (.manager()).change_connection_interface(old, new);
    interface.connection_starting(.address(), remote_port);
};

public method .close() {
    (sender() != this()) && (> .perms(sender()) <);
    (> $sys.destroy_sender() <);
};

public method .cwritef() {
    arg fname;
    
    (> .perms(sender()) <);
    (> cwritef(fname) <);
};

public method .daemon_shutdown() {
    var c;
    
    // called by $daemon.stop_listening()
    (> .perms(caller(), $daemon) <);
    for c in (.children())
        (> c.close() <);
    (> interface.daemon_shutdown() <);
};

driver method .disconnect() {
    .close();
};

protected method .do_timeout() {
    if (!timeout)
        return;
    .write(("Timeout (" + tostr(timeout)) + ")");
    .close();
};

public method .finish_reading_block() {
    var task_id, lines;
    
    (> .perms(sender()) <);
    task_id = read_block.task_id();
    lines = read_block.lines();
    read_block = 0;
    $scheduler.resume(task_id, lines);
};

protected method .get_ident() {
    return $ident_connection.get(remote_addr, remote_port, local_port);
};

protected method .get_interface() {
    arg @args;
    
    return interface;
};

root method .init_connection() {
    buffer = `[];
    local_addr = (remote_addr = "");
    line_buffer = [];
    timeout = 300;
    tid = -1;
    
    // remove all flags
    .set_flags([]);
};

public method .interface() {
    (caller() == $daemon) || (> .perms(sender()) <);
    return interface;
};

public method .interface_going_away() {
    if ((sender() != interface) && (sender() != (| class(interface) |)))
        throw(~perm, sender() + " is not the interface.");
    interface = 0;
    (> $sys.destroy_sender() <);
};

public method .is_reading_block() {
    return read_block ? 1 : 0;
};

public method .new_connection() {
    var new, i;
    
    (> .perms(caller(), $daemon) <);
    new = .spawn();
    i = interface.new(new);
    new.add_writer(sender());
    new.add_writer(interface);
    new.add_writer((| class(i) |) || i);
    new.add_writer(this());
    new.new_interface(i);
    return new;
};

public method .new_interface() {
    arg obj;
    
    (> .perms(sender()) <);
    interface = obj;
};

protected method .open_connection() {
    arg host, port;
    
    (> open_connection(host, port) <);
};

driver method .parse() {
    arg incoming;
    var lines, line, index;
    
    lines = buf_to_strings(buffer + incoming);
    index = listlen(lines);
    buffer = lines[index];
    lines = delete(lines, index);
    line_buffer += lines;
    while (line_buffer) {
        line = line_buffer[1];
        line_buffer = delete(line_buffer, 1);
        (| .parse_line(line) |);
    }
};

public method .parse_interface() {
    arg value, @args;
    var obj;
    
    obj = (> $object_lib.to_dbref(value) <);
    return obj;
};

protected method .parse_line() {
    arg line;
    
    if (read_block) {
        read_block = read_block.parse(line);
        line = .rehash_read_status();
        if ((!line) && (line != ""))
            return;
    }
    if ((interface.parse_line(line)) == 'disconnect)
        (> .close() <);
};

private method .push_buffered(): forked  {
    var line;
    
    // called when a read() suspends the connection--to finish unbuffering i/o
    while (line_buffer) {
        line = line_buffer[1];
        line_buffer = delete(line_buffer, 1);
        (| .parse_line(line) |);
    }
};

protected method .rehash_read_status() {
    switch (read_block.status()) {
        case 'abort:
            .abort_reading_block();
        case 'not_done:
            // do nothing
        case 'done:
            .finish_reading_block();
        case 'pass_command:
            return read_block.command();
    }
    return 0;
};

protected method .set_active() {
    arg value;
    
    active = value;
};

public method .set_daemon() {
    arg obj;
    
    (> .perms(sender()) <);
    daemon = obj;
};

protected method .set_interface() {
    arg name, definer, value, @args;
    
    interface = value;
};

public method .set_remote_port() {
    arg port;
    
    (> .perms(sender()) <);
    remote_port = port;
};

public method .set_timeout() {
    arg seconds;
    
    (> .perms(sender(), interface, this()) <);
    timeout = seconds;
    if (!timeout)
        (| clear_var('timeout) |);
};

public method .start() {
    arg remote, local, rport, lport;
    
    // Make this method 'fork' from the regular thread stack
    (> .perms(caller(), $daemon) <);
    active = time();
    remote_addr = remote;
    remote_port = rport;
    local_addr = local;
    local_port = lport;
    
    //    if (timeout)
    //        $scheduler.add_task(timeout, 'do_timeout);
    interface.connection_starting(.address(), remote_port);
};

public method .start_reading_block() {
    arg count;
    
    (> .perms(sender()) <);
    read_block = $read_parser.new_with(task_id(), count);
    (| .push_buffered() |);
    return (> $scheduler.suspend(this()) <);
};

public method .timeout() {
    return timeout;
};

root method .uninit_connection() {
    (| close_connection() |);
    active = 0;
    if (interface)
        (| interface.connection_going_away(remote_addr, remote_port) |);
    interface = 0;
    if (read_block)
        read_block = read_block.add('lines, 'disconnected);
    .finish_reading_block();
    if (tid != (-1))
        $scheduler.del_task(tid);
    tid = 0;
};

public method .write() {
    arg what, @how;
    var elem, sep;
    
    sep = ('non_terminated in how) ? `[] : `[13, 10];
    switch (type(what)) {
        case 'string:
            what = $buffer.from_strings([what], sep);
        case 'list:
            what = $buffer.from_strings(what, sep);
        case 'buffer:
        default:
            throw(~type, "Write: strings, list of strings and buffers.");
    }
    cwrite(what);
};

public method .write_buffer() {
    arg buffer;
    
    if ((sender() != interface) && (sender() != (| class(interface) |)))
        throw(~perm, sender() + " cannot write this connection.");
    if (type(buffer) != 'buffer)
        throw(~type, "Argument must be a buffer.");
    cwrite(buffer);
};

public method .write_string() {
    arg string;
    
    if ((sender() != interface) && (sender() != (| class(interface) |)))
        throw(~perm, sender() + " cannot write this connection.");
    if (type(string) != 'string)
        throw(~type, "Argument must be a string.");
    cwrite($buffer.from_string(string));
};

public method .write_strings() {
    arg strings;
    
    if ((sender() != interface) && (sender() != (| class(interface) |)))
        throw(~perm, sender() + " cannot write this connection.");
    if (type(strings) != 'list)
        throw(~type, "Argument must be a list of strings.");
    cwrite($buffer.from_strings(string));
};