/
CDC-1.2b/
CDC-1.2b/src/
parent $root
object $sys

var $sys admins []
var $sys exit_starting_room $void
var $root child_index 1
var $root owners [$sys]
var $root fertile 0
var $root inited 1
var $sys agents [$sys, $housekeeper, $scheduler, $root, $daemon, $user, $backdoor]
var $sys startup #[['time, 794116991], ['objects, [$login_daemon, $http_daemon, $finger_daemon, $backdoor]], ['heartbeat_interval, 5]]
var $sys starting #[['quota, 75000], ['exit_source, $void], ['place, $creation], ['new_user_class, $admin], ['anonymous_user_class, $guest]]
var $root owned [$sys]
var $sys server_address ["127.0.0.1", "localhost"]
var $root manager $sys
var $root writable [$sys]
var $root readable ['parameters, 'methods, 'code]
var $root info ["The system object has special server-granted permissions, and performs tasks which require these permisions. It receives the 'heartbeat message, as well as being pivitol in such tasks as generating new connections and creating objects."]
var $root dbref 'sys
var $sys system_email_addresses #[['default, "[email not set]"]]
var $sys core_version "1.2"
var $sys validate_email_addresses 1
var $sys load #[['load, "0.0, 0.0, 0.0"]]
var $sys next_pulse 794119075
var $sys backup #[['interval, 3600], ['last, 794117896], ['next, 794121496]]

method startup
    arg args;
    var opt, str, obj;
    
    args = sublist(args, 3);
    catch any {
        if (sender() != 0)
            throw(~perm, "Sender is not the server.");
    
        // Set up five-second heartbeat.
        set_heartbeat(startup['heartbeat_interval]);
    
        // set the startup time, reset backup time.
        startup = startup.add('time, time());
        backup = backup.add('next, time() + (backup['interval]));
    
        // tell objects who should know, that we are up.
        for obj in (startup['objects]) {
            .log(("Calling " + (obj.dbref())) + ".startup()");
            (| obj.startup(@args) |);
        }
    } with handler {
        .log(("Startup ERROR at " + ctime()) + ":");
        .log($parse.traceback(traceback(), -1, ""));
    }
.

method server_info
    arg what, [long];
    var tmp;
    
    switch (what) {
        case 'up_time:
            return time() - (startup['time]);
        case 'startup_time:
            return startup['time];
        case 'server_hostname:
            return server_address[2];
        case 'server_ip:
            return server_address[1];
        case 'load:
            return .load();
        case 'last_backup:
            return backup['last];
        case 'driver_version:
            tmp = version();
            return (((((long ? "ColdX " | "") + tostr(tmp[1])) + ".") + tostr(tmp[2])) + "-") + tostr(tmp[3]);
        case 'core_version:
            return (long ? "the Cold Dark Core " | "") + core_version;
        default:
            throw(~unknown, "Unknown flag.");
    }
.

method callers
    (> .perms(sender(), 'system) <);
    return (> callers() <);
.

method create_user
    arg name, password, email, [type];
    var user;
    
    if ((!(| .perms(caller(), $login_interface) |)) && (!(| .perms(sender(), 'system) |)))
        throw(~perm, "Caller and Sender are not allowed to call this method.");
    type = [@type, 'new_user_class][1];
    catch any {
        user = (starting[type]).spawn(name);
        user.set_name(name);
        if (type == 'new_user_class)
            user.set_password(password);
        else
            user.set_password(crypt(substr(crypt("", substr(name, 1, 2)), 1, random(13))) + "12");
        user.set_manager(user);
        user.set_data('email, email, 0);
        user.chown([user]);
    } with handler {
        // Failed to initialize the child; destroy it.
        if (!(| user.destroy() |)) {
            (| user.uninitialize() |);
            (| del_dbref(user.dbref('symbol)) |);
            (| del_dbref(tosym(name)) |);
            (| destroy(user) |);
        }
        rethrow(error());
    }
    return user;
.

method admins
    return admins;
.

method is_admin
    arg obj;
    
    return (obj == $sys) || (obj in admins);
.

method binary_dump
    if (!($sys.is_admin(sender())))
        throw(~perm, "Sender is not an admin.");
    return binary_dump();
.

method shutdown
    arg [why];
    var line1, line2;
    
    if ((!($sys.is_admin(sender()))) || (definer() != this()))
        throw(~perm, "Sender is not an admin.");
    why = [@why, ""][1];
    
    // tell everybody everything
    line1 = "*** SHUTDOWN called by " + (sender().namef('ref));
    if (why) {
        line1 = line1 + " because:";
        line2 = ("*** " + why) + " ***";
    }
    .log(line1 + " ***");
    $channels.announce('all, line1 + " ***");
    if (why) {
        .log(line2);
        $channels.announce('all, line2);
    }
    return shutdown();
.

method change_sender_parents
    arg parents;
    var p;
    
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    (> chparents(sender(), parents) <);
.

method spawn_sender
    arg suffix, manager, [owners];
    var namestr;
    
    (> .perms(caller(), $root, $sys) <);
    if (!owners)
        owners = [manager];
    namestr = (tostr(sender().dbref('symbol)) + "_") + suffix;
    return .create([sender()], tosym(namestr), manager, owners);
.

method assign_dbref
    arg name;
    var keepers, x;
    
    (> .perms(caller(), $root, $sys) <);
    if (type(name) != 'symbol)
        throw(~type, "Name must be given as a symbol.");
    
    // don't run this for now--tosym is fucked.
    if (0) {
        // yeah, we change it to a string, but they don't have to know that.
        name = tostr(name);
    
        // lowercase all names:
        name = lowercase(name);
    
        // If it isn't a keeper toss the good old error
        keepers = "abcdefghijklmnopqrstuvwxyz1234567890_";
        for x in [1 .. strlen(name)] {
            if (!((name[x]) in keepers))
                throw(~type, "Name has one or more non-alphanumeric characters.");
        }
        name = tosym(name);
    }
    
    // make sure nobody has it yet
    if ((| get_objnum(name) |) != ~namenf)
        throw(~perm, "Name already assigned to " + (get_objnum(name).namef('ref)));
    
    // woo woo, i'm filled with joy, lets give them the name.
    add_dbref(name, sender());
.

method destroy_sender
    (> .perms(caller(), $root) <);
    (| .deassign_dbref(sender().dbref('symbol)) |);
    (> destroy(sender()) <);
.

method is_system
    arg obj;
    
    return (obj in admins) || ((obj in agents) || (obj.has_ancestor($backdoor)));
.

method log
    arg text;
    var l;
    
    if ((!(| .perms(sender(), 'system) |)) && (!(| .perms(caller(), 'system) |)))
        throw(~perm, "Only system objects can log.");
    if (type(text) == 'list) {
        for l in (text)
            .log(l);
    } else {
        log((($time.time_stamp()) + "> ") + text);
    }
.

method open_connection
    arg [args];
    
    (> .perms(caller(), $network) <);
    (> open_connection(@args) <);
.

method heartbeat
    if (sender() != 0)
        throw(~perm, "Sender is not the server.");
    $scheduler.pulse();
    
    // system pulse's happen every half hour
    if (time() > next_pulse)
        (| .pulse() |);
.

method do_backup
    arg who;
    var line, name;
    
    (> .perms(sender(), 'system) <);
    catch any {
        name = who.namef('ref);
        .log(("BACKUP (" + name) + ") ");
        line = (("It is: " + ($time.ltime())) + " -- BACKUP -- called by ") + name;
        $channels.announce('System, line);
    }
    backup = backup.add('next, time() + (backup['interval]));
    backup = backup.add('last, time());
    pause();
    pause();
    .text_dump();
.

method set_startup
    arg what, value;
    var valid;
    
    (> .perms(sender(), .admins()) <);
    valid = startup.keys();
    if ((!what) in valid)
        throw(~type, "Key must be one of " + toliteral(valid));
    startup = startup.add(what, value);
.

method sender_data
    var output, i;
    
    if (caller() != $root)
        throw(~perm, "Caller is not $root.");
    return data(sender());
.

method get_system_email
    arg what;
    var email;
    
    // email directory for system services, such as arch admins.
    email = (| system_email_addresses[what] |);
    if (!email)
        email = (| system_email_addresses['default] |) || "<no email set>";
    return email;
.

method new_admin
    if (caller() != $admin)
        throw(~perm, "Caller is not $admin.");
    admins = setadd(admins, sender());
.

method admin_going_away
    if (caller != $admin)
        throw(~perm, "Caller is not $admin.");
    admins = setremove(admins, sender());
.

method agents
    return agents;
.

method text_dump
    .perms(sender(), 'this);
    pause();
    return text_dump();
.

method get_startup
    arg what;
    
    return starting[what];
.

method set_starting
    arg what, value;
    var valid;
    
    (> .perms(sender(), .admins()) <);
    valid = starting.keys();
    if ((!what) in valid)
        throw(~type, "Key must be one of " + toliteral(valid));
    starting = starting.add(what, value);
.

method execute
    arg script, args, [background];
    
    (> .perms(sender(), @admins) <);
    (> execute(script, args, @background) <);
.

method get_starting
    arg what;
    
    return starting[what];
.

method create
    arg parents, name, manager, [owners];
    var new;
    
    .perms(sender(), 'system);
    new = create(parents);
    catch any {
        new.set_dbref(name);
        new.initialize();
        new.set_manager(manager);
        new.chown([@owners, [new]][1]);
    } with handler {
        // Failed to initialize the child; destroy it.
        if (!(| new.destroy() |)) {
            (| new.uninitialize() |);
            (| del_dbref(new.dbref('symbol)) |);
            (| del_dbref(tosym(name)) |);
            (| destroy(new) |);
        }
        rethrow(error());
    }
    return new;
.

method system
    return admins + agents;
.

method bind_port
    arg port, obj;
    
    (> .perms(caller(), $network, $backdoor) <);
    (> bind_port(port, obj) <);
.

method deassign_dbref
    arg name;
    
    (> .perms(caller(), $root, $sys) <);
    del_dbref(name);
.

method del_system_email
    arg key;
    
    (> .perms(sender(), 'manager) <);
    system_email_addresses = dict_del(system_email_addresses, key);
.

method add_system_email
    arg key, email;
    
    (> .perms(sender(), 'manager) <);
    if (type(key) != 'symbol)
        throw(~type, "Key is not a symbol.");
    if (type(email) != 'string)
        throw(~type, "Email address is not a string.");
    system_email_addresses = dict_add(system_email_addresses, key, email);
.

method compile
    arg code, name;
    var line;
    
    (> .perms(sender()) <);
    line = ("SYSTEM: ." + tostr(name)) + "() MODIFIED";
    line = (line + " by ") + (sender().namef('ref));
    .log(line);
    return (> pass(code, name) <);
.

method unbind_port
    arg port, obj;
    
    (> .perms(caller(), $network, $backdoor) <);
    (> unbind_port(port) <);
.

method tasks
    return (> tasks() <);
.

method resume
    arg task, [args];
    
    (> resume(task, @args) <);
.

method suspend
    return (> suspend() <);
.

method validate_email_addresses
    return validate_email_addresses;
.

method reassign_connection
    arg obj;
    
    (> .perms(caller(), $network, $backdoor) <);
    (> reassign_connection(obj) <);
.

method cancel
    arg [args];
    
    return (> cancel(@args) <);
.

method signal
    arg sig, sigstr;
    var line;
    
    if (sender() || caller())
        throw(~perm, "Sender is not the server.");
    line = ("** Caught Signal: " + sigstr) + " **";
    (| $channels.announce('System, line) |);
    if (!(sig in [1, 13, 16, 30, 31])) {
        (| $channels.announce('System, "******************************") |);
        (| $channels.announce('System, "** IMMINENT SERVER SHUTDOWN **") |);
        (| $channels.announce('System, "******************************") |);
    }
.

method load
    arg [args];
    
    (> .perms(sender(), 'system) <);
    if (args)
        return (> load() <);
    else
        return load['load];
.

method do_loadcheck
    (> .perms(sender(), 'system) <);
    load = load.add('load, load());
    (| $channels.announce('System, (($time.ltime()) + " LOADCHECK: ") + (load['load])) |);
.

method pulse
    (> .perms([caller(), sender()], this()) <);
    next_pulse = time() + 1800;
    if (time() > (backup['next]))
        .do_backup(this());
    
    // if (time() > load['next_check_time])
    .do_loadcheck();
.

method status
    return (> status() <);
.

method ip
    arg [args];
    
    return (> ip(@args) <);
.

method hostname
    arg [args];
    
    return (> hostname(@args) <);
.