ds2.10/bin/
ds2.10/extra/
ds2.10/extra/crat/
ds2.10/extra/creremote/
ds2.10/extra/mingw/
ds2.10/extra/wolfpaw/
ds2.10/fluffos-2.16-ds05/
ds2.10/fluffos-2.16-ds05/Win32/
ds2.10/fluffos-2.16-ds05/compat/
ds2.10/fluffos-2.16-ds05/compat/simuls/
ds2.10/fluffos-2.16-ds05/include/
ds2.10/fluffos-2.16-ds05/testsuite/
ds2.10/fluffos-2.16-ds05/testsuite/clone/
ds2.10/fluffos-2.16-ds05/testsuite/command/
ds2.10/fluffos-2.16-ds05/testsuite/data/
ds2.10/fluffos-2.16-ds05/testsuite/etc/
ds2.10/fluffos-2.16-ds05/testsuite/include/
ds2.10/fluffos-2.16-ds05/testsuite/inherit/
ds2.10/fluffos-2.16-ds05/testsuite/inherit/master/
ds2.10/fluffos-2.16-ds05/testsuite/log/
ds2.10/fluffos-2.16-ds05/testsuite/single/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/compiler/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/efuns/
ds2.10/fluffos-2.16-ds05/testsuite/single/tests/operators/
ds2.10/fluffos-2.16-ds05/testsuite/u/
ds2.10/lib/cmds/admins/
ds2.10/lib/cmds/common/
ds2.10/lib/cmds/creators/include/
ds2.10/lib/daemon/services/
ds2.10/lib/daemon/tmp/
ds2.10/lib/doc/
ds2.10/lib/doc/bguide/
ds2.10/lib/doc/efun/all/
ds2.10/lib/doc/efun/arrays/
ds2.10/lib/doc/efun/buffers/
ds2.10/lib/doc/efun/compile/
ds2.10/lib/doc/efun/floats/
ds2.10/lib/doc/efun/functions/
ds2.10/lib/doc/efun/general/
ds2.10/lib/doc/efun/mixed/
ds2.10/lib/doc/efun/numbers/
ds2.10/lib/doc/efun/parsing/
ds2.10/lib/doc/help/classes/
ds2.10/lib/doc/help/races/
ds2.10/lib/doc/lfun/
ds2.10/lib/doc/lfun/all/
ds2.10/lib/doc/lfun/lib/abilities/
ds2.10/lib/doc/lfun/lib/armor/
ds2.10/lib/doc/lfun/lib/bank/
ds2.10/lib/doc/lfun/lib/bot/
ds2.10/lib/doc/lfun/lib/clay/
ds2.10/lib/doc/lfun/lib/clean/
ds2.10/lib/doc/lfun/lib/clerk/
ds2.10/lib/doc/lfun/lib/client/
ds2.10/lib/doc/lfun/lib/combat/
ds2.10/lib/doc/lfun/lib/connect/
ds2.10/lib/doc/lfun/lib/container/
ds2.10/lib/doc/lfun/lib/corpse/
ds2.10/lib/doc/lfun/lib/creator/
ds2.10/lib/doc/lfun/lib/daemon/
ds2.10/lib/doc/lfun/lib/damage/
ds2.10/lib/doc/lfun/lib/deterioration/
ds2.10/lib/doc/lfun/lib/donate/
ds2.10/lib/doc/lfun/lib/door/
ds2.10/lib/doc/lfun/lib/equip/
ds2.10/lib/doc/lfun/lib/file/
ds2.10/lib/doc/lfun/lib/fish/
ds2.10/lib/doc/lfun/lib/fishing/
ds2.10/lib/doc/lfun/lib/flashlight/
ds2.10/lib/doc/lfun/lib/follow/
ds2.10/lib/doc/lfun/lib/ftp_client/
ds2.10/lib/doc/lfun/lib/ftp_data_connection/
ds2.10/lib/doc/lfun/lib/fuel/
ds2.10/lib/doc/lfun/lib/furnace/
ds2.10/lib/doc/lfun/lib/genetics/
ds2.10/lib/doc/lfun/lib/holder/
ds2.10/lib/doc/lfun/lib/id/
ds2.10/lib/doc/lfun/lib/interactive/
ds2.10/lib/doc/lfun/lib/lamp/
ds2.10/lib/doc/lfun/lib/leader/
ds2.10/lib/doc/lfun/lib/light/
ds2.10/lib/doc/lfun/lib/limb/
ds2.10/lib/doc/lfun/lib/living/
ds2.10/lib/doc/lfun/lib/load/
ds2.10/lib/doc/lfun/lib/look/
ds2.10/lib/doc/lfun/lib/manipulate/
ds2.10/lib/doc/lfun/lib/meal/
ds2.10/lib/doc/lfun/lib/messages/
ds2.10/lib/doc/lfun/lib/player/
ds2.10/lib/doc/lfun/lib/poison/
ds2.10/lib/doc/lfun/lib/position/
ds2.10/lib/doc/lfun/lib/post_office/
ds2.10/lib/doc/lfun/lib/potion/
ds2.10/lib/doc/lfun/lib/room/
ds2.10/lib/doc/lfun/lib/server/
ds2.10/lib/doc/lfun/lib/spell/
ds2.10/lib/doc/lfun/lib/torch/
ds2.10/lib/doc/lfun/lib/vendor/
ds2.10/lib/doc/lfun/lib/virt_sky/
ds2.10/lib/doc/lfun/lib/weapon/
ds2.10/lib/doc/lfun/lib/worn_storage/
ds2.10/lib/doc/lpc/constructs/
ds2.10/lib/doc/lpc/etc/
ds2.10/lib/doc/lpc/intermediate/
ds2.10/lib/doc/lpc/types/
ds2.10/lib/doc/misc/
ds2.10/lib/doc/old/
ds2.10/lib/doc/phints/
ds2.10/lib/domains/
ds2.10/lib/domains/Praxis/adm/
ds2.10/lib/domains/Praxis/attic/
ds2.10/lib/domains/Praxis/cemetery/mon/
ds2.10/lib/domains/Praxis/data/
ds2.10/lib/domains/Praxis/death/
ds2.10/lib/domains/Praxis/mountains/
ds2.10/lib/domains/Praxis/obj/armour/
ds2.10/lib/domains/Praxis/obj/magic/
ds2.10/lib/domains/Praxis/obj/weapon/
ds2.10/lib/domains/Praxis/orc_valley/
ds2.10/lib/domains/Ylsrim/
ds2.10/lib/domains/Ylsrim/adm/
ds2.10/lib/domains/Ylsrim/armor/
ds2.10/lib/domains/Ylsrim/broken/
ds2.10/lib/domains/Ylsrim/fish/
ds2.10/lib/domains/Ylsrim/meal/
ds2.10/lib/domains/Ylsrim/npc/
ds2.10/lib/domains/Ylsrim/obj/
ds2.10/lib/domains/Ylsrim/virtual/
ds2.10/lib/domains/Ylsrim/weapon/
ds2.10/lib/domains/alpha/room/
ds2.10/lib/domains/alpha/virtual/
ds2.10/lib/domains/campus/adm/
ds2.10/lib/domains/campus/etc/
ds2.10/lib/domains/campus/meals/
ds2.10/lib/domains/campus/txt/ai/charles/
ds2.10/lib/domains/campus/txt/ai/charles/bak2/
ds2.10/lib/domains/campus/txt/ai/charles/bak2/bak1/
ds2.10/lib/domains/campus/txt/ai/charly/
ds2.10/lib/domains/campus/txt/ai/charly/bak/
ds2.10/lib/domains/campus/txt/jenny/
ds2.10/lib/domains/cave/doors/
ds2.10/lib/domains/cave/etc/
ds2.10/lib/domains/cave/meals/
ds2.10/lib/domains/cave/weap/
ds2.10/lib/domains/default/chamber/
ds2.10/lib/domains/default/creator/
ds2.10/lib/domains/default/doors/
ds2.10/lib/domains/default/etc/
ds2.10/lib/domains/default/vehicle/
ds2.10/lib/domains/default/virtual/
ds2.10/lib/domains/town/save/
ds2.10/lib/domains/town/txt/shame/
ds2.10/lib/domains/town/virtual/
ds2.10/lib/domains/town/virtual/bottom/
ds2.10/lib/domains/town/virtual/space/
ds2.10/lib/estates/
ds2.10/lib/ftp/
ds2.10/lib/lib/comp/
ds2.10/lib/lib/daemons/
ds2.10/lib/lib/daemons/include/
ds2.10/lib/lib/lvs/
ds2.10/lib/lib/user/
ds2.10/lib/lib/virtual/
ds2.10/lib/log/
ds2.10/lib/log/adm/
ds2.10/lib/log/archive/
ds2.10/lib/log/chan/
ds2.10/lib/log/errors/
ds2.10/lib/log/law/adm/
ds2.10/lib/log/law/email/
ds2.10/lib/log/law/names/
ds2.10/lib/log/law/sites-misc/
ds2.10/lib/log/law/sites-register/
ds2.10/lib/log/law/sites-tempban/
ds2.10/lib/log/law/sites-watch/
ds2.10/lib/log/open/
ds2.10/lib/log/reports/
ds2.10/lib/log/router/
ds2.10/lib/log/secure/
ds2.10/lib/log/watch/
ds2.10/lib/obj/book_source/
ds2.10/lib/obj/include/
ds2.10/lib/powers/prayers/
ds2.10/lib/powers/spells/
ds2.10/lib/realms/template/
ds2.10/lib/realms/template/adm/
ds2.10/lib/realms/template/area/
ds2.10/lib/realms/template/area/armor/
ds2.10/lib/realms/template/area/npc/
ds2.10/lib/realms/template/area/obj/
ds2.10/lib/realms/template/area/room/
ds2.10/lib/realms/template/area/weap/
ds2.10/lib/realms/template/bak/
ds2.10/lib/realms/template/cmds/
ds2.10/lib/save/kills/o/
ds2.10/lib/secure/cfg/classes/
ds2.10/lib/secure/cmds/builders/
ds2.10/lib/secure/cmds/creators/include/
ds2.10/lib/secure/cmds/players/include/
ds2.10/lib/secure/daemon/imc2server/
ds2.10/lib/secure/daemon/include/
ds2.10/lib/secure/lib/
ds2.10/lib/secure/lib/include/
ds2.10/lib/secure/lib/net/include/
ds2.10/lib/secure/lib/std/
ds2.10/lib/secure/log/adm/
ds2.10/lib/secure/log/bak/
ds2.10/lib/secure/log/intermud/
ds2.10/lib/secure/log/network/
ds2.10/lib/secure/modules/
ds2.10/lib/secure/npc/
ds2.10/lib/secure/obj/include/
ds2.10/lib/secure/room/
ds2.10/lib/secure/save/
ds2.10/lib/secure/save/backup/
ds2.10/lib/secure/save/boards/
ds2.10/lib/secure/save/players/g/
ds2.10/lib/secure/tmp/
ds2.10/lib/secure/upgrades/files/
ds2.10/lib/secure/verbs/creators/
ds2.10/lib/std/board/
ds2.10/lib/std/lib/
ds2.10/lib/verbs/admins/include/
ds2.10/lib/verbs/builders/
ds2.10/lib/verbs/common/
ds2.10/lib/verbs/common/include/
ds2.10/lib/verbs/creators/
ds2.10/lib/verbs/creators/include/
ds2.10/lib/verbs/rooms/
ds2.10/lib/verbs/rooms/include/
ds2.10/lib/www/client/
ds2.10/lib/www/errors/
ds2.10/lib/www/images/
ds2.10/win32/
#include <lib.h>
#include <news.h>
#include <save.h>
#include <daemons.h>
#include <commands.h>
#include <message_class.h>
#include <talk_type.h>
#include <secrets.h>
#include <socket.h>
#include NETWORK_H

inherit LIB_DAEMON;

mapping InstData = ([]);
mapping sockets = ([]);
static string SaveFile;
string Name, Myname;
static int verbose = 0;
static private int icp_socket;

varargs static void yenta(string arg, string clr){
    if(verbose){
        debug_message(arg);
    }
    unguarded( (: log_file("/secure/log/icp", timestamp() +
      " " + strip_colours($(arg)) + "\n") :) );
}

varargs static int validate(int i, int soft){
    if(!undefinedp(i)){
        if(!socket_status(i) || !socket_status(i)[5]){
            yenta(mud_name()+" stack: "+get_stack());
            yenta("%B_BLACK%^BAD SOCKET ALERT. fd "+i+":  "+
                    identify(socket_status(i))+"\n","red");
            if(!soft) error("Bad socket, fd "+i);
            return 0;
        }
    }
    if(previous_object() != this_object() && !((int)master()->valid_apply(({ "ASSIST" }))) ){
        yenta("SECURITY ALERT: validation failure in INSTANCES_D.\n","red");
        if(soft) return 0;
        error("Illegal attempt to access router socket daemon: "+get_stack()+
                " "+identify(previous_object(-1)));
    }
    return 1;
}

static void create() {
    daemon::create();
    Myname = "global";
    if(!sizeof(InstData)) InstData = ([]);
    if(!sizeof(sockets)) sockets = ([]);
    SaveFile = save_file(SAVE_INSTANCES);
    SetSaveFile(SaveFile);
    if(!file_exists(SaveFile) && file_exists(old_savename(SaveFile))){
        cp(old_savename(SaveFile), SaveFile);
    }
    SetNoClean(1);
    if(file_exists(SaveFile)){
        RestoreObject(SaveFile);
    }
    if(ENABLE_INSTANCES){
    }
    call_out("Setup", 0);
    set_heart_beat(10);
}

string GetMyInstanceName(){
    return Myname;
}

mixed InstCreate(string name, string addy, int port){
    object prev = previous_object();
    string newglobal, newconf, pfile = base_name(this_player());
    if(base_name(prev) != CMD_INSTCONFIG) return 0;
    if(ENABLE_INSTANCES){
        return "Only the global instance can create instances.";
    }
    if(InstData[name]) return name + " already exists.";
    foreach(mixed key, mixed val in InstData){
        if(val && val["port"] == port){
            return key + " is already on port "+port;
        }
    }
    InstData[name] = ([ "addy" : addy, "port" : port ]);
    SaveObject(SaveFile, 1);
    cp(NETWORK_H, "/secure/include/network."+port+".h");
    cp(ROOMS_H, "/secure/include/rooms."+port+".h");
    cp(SECRETS_H, "/secure/include/secrets."+port+".h");
    catch( cp(SAVE_IMC2+".o", SAVE_IMC2 + "." + port + ".o") );
    catch( cp(SAVE_MAP+".o", SAVE_MAP + "." + port + ".o") );
    catch( cp(SAVE_ROOMS+".o", SAVE_ROOMS + "." + port + ".o") );
    catch( cp(SAVE_RACES+".o", SAVE_RACES + "." + port + ".o") );
    catch( cp(SAVE_CLASSES+".o", SAVE_CLASSES + "." + port + ".o") );
    catch( cp(NEWS_WELCOME, NEWS_WELCOME + "." +port) );
    catch( cp(pfile+".o", pfile+"."+port+".o") );
    newglobal = read_file("/secure/cfg/global_template.cfg");
    if(newglobal){
        newglobal = replace_string(newglobal, "TEMPLATE_CONFIG",
                "/secure/include/config."+port+".h");
        newglobal = replace_string(newglobal, "TEMPLATE_NETWORK",
                "/secure/include/network."+port+".h");
        newglobal = replace_string(newglobal, "TEMPLATE_ROOMS",
                "/secure/include/rooms."+port+".h");
        newglobal = replace_string(newglobal, "TEMPLATE_SECRETS",
                "/secure/include/secrets."+port+".h");
    }
    write_file("/secure/include/global."+port+".h", newglobal, 1);
    newconf = read_file(CONFIG_H);
    if(newconf){
        string *confarr = explode(newconf, "\n");
        newconf = "";
        foreach(string line in confarr){
            if(!strsrch(line, "#define DISABLE_INTERMUD")){
                line = "#define DISABLE_INTERMUD         1";
            }
            if(!strsrch(line, "#define DISABLE_IMC2")){
                line = "#define DISABLE_IMC2             1";
            }
            if(!strsrch(line, "#define ENABLE_INSTANCES")){
                line = "#define ENABLE_INSTANCES         1";
            }
            if(!strsrch(line, "#define LOG_REMOTE_CHANS")){
                line = "#define LOG_REMOTE_CHANS         0";
            }
            if(!strsrch(line, "#define LOG_LOCAL_CHANS")){
                line = "#define LOG_LOCAL_CHANS          0";
            }
            newconf +=  line + "\n";
        }
        write_file("/secure/include/config."+port+".h", newconf, 1);
    }
    if(true()){
        string newcfg = read_file("/secure/cfg/instance_template.cfg");
        string oldcfg = read_file("/secure/cfg/mudos.cfg");
        if(newcfg && oldcfg){
            string mlib, mbin;
            sscanf(oldcfg, "%*smudlib directory :%s\n", mlib);
            sscanf(oldcfg, "%*sbinary directory :%s\n", mbin);
            newcfg = replace_string(newcfg, "TEMPLATE_NAME", name);
            newcfg = replace_string(newcfg, "TEMPLATE_PORT", itoa(port));
            if(mlib) mlib = trim(mlib);
            if(mbin) mbin = trim(mbin);
            newcfg = replace_string(newcfg, "TEMPLATE_LIB", mlib);
            newcfg = replace_string(newcfg, "TEMPLATE_BIN", mbin);
            newcfg = replace_string(newcfg, "TEMPLATE_GLOBAL", 
                    "global."+port+".h");
            write_file("/secure/cfg/mudos."+port+".cfg", newcfg, 1);
            write_file("/secure/cfg/mudos."+port+".win32", newcfg, 1);
        }
        newcfg = read_file("/secure/cfg/runmud_template.bat");
        if(newcfg && query_windows()){
            newcfg = replace_string(newcfg, "TEMPLATE_MUDOS",
              "mudos."+port+".win32");
            write_file("/secure/cfg/runmud_"+port+".bat", newcfg, 1);
        }
    }
    SaveObject(SaveFile, 1);
    return 1;
}

mixed InstDelete(mixed arg){
    object prev = previous_object();
    mixed which;
    if(base_name(prev) != CMD_INSTCONFIG) return 0;
    if(ENABLE_INSTANCES){
        return "Only the global instance can delete instances.";
    }
    if(InstData[arg]) which = arg;
    else {
        if(stringp(arg)) which = atoi(arg);
        else if(intp(arg)) which = arg;
        foreach(mixed key, mixed val in InstData){
            if(val && val["port"] == which){
                which = key;
                break;
            }
        }
    }

    if(which && InstData[which]){
        mixed port = itoa(InstData[which]["port"]);
        rm("/secure/include/config."+port+".h");
        rm("/secure/include/global."+port+".h");
        rm("/secure/include/rooms."+port+".h");
        rm("/secure/include/network."+port+".h");
        rm("/secure/include/secrets."+port+".h");
        rm("/secure/cfg/mudos."+port+".cfg");
        rm(NEWS_WELCOME + "." + port);
        this_object()->ProcessClose(which);
        InstData[which] = 0;
        SaveObject(SaveFile, 1);
        return 1;
    }
    else return "No such instance exists.";
}

string array GetInstances(){
    return filter(keys(InstData), (: $1 :));
}

mapping GetInstData(){
    mapping ret = ([]);
    foreach(mixed key, mixed val in InstData){
        if(key) ret[key] = copy(val);
    }
    return ret;
}

static void SendData(mixed fd, mixed data){
    int array targets = ({});
    if(stringp(fd) && !undefinedp(InstData[fd])) fd = InstData[fd]["fd"];
    if(fd == -2) return;
    if(fd == -1){
        foreach(string name in keys(InstData)){
            if(name && InstData[name]) targets += ({ InstData[name]["fd"] });
        }
    }
    else targets = ({ fd });
    foreach(int target in targets){
        this_object()->write_data(target, data);
    }
}

varargs void SendWhoUpdate(string name, int status){
    mapping data = ([ "status" : status ]);
    object ob = find_player(name);
    if(ob && !ob->GetInvis()){
        string title = ob->GetShort();
        if(sizeof(strip_colours(title)) > 50){
            title = capitalize(name)+" the Long-Titled.";
        }
        data["title"] = title;
        data["level"] = ob->GetLevel();
        data["arch"] = archp(ob);
        data["creator"] = creatorp(ob);
        data["builder"] = builderp(ob);
        if(interactive(ob)) data["status"] = 1;
        else data["status"] = -1;
    }
    else data["status"] = 0;
    SendData(-1, ({ "who-update", 5, Myname, name, 0, 0, data }) );
} 

void UpdateInvis(int i){
    object ob = previous_object();
    string name;
    if(!ob || !interactive(ob)) return;
    name = ob->GetKeyName(); 
    if(!sizeof(name)) return;
    call_out("SendWhoUpdate", 0, name);
}

varargs void SendTell(string who, string msg, string interwho){
    object prev, ob = this_player();
    string sender, vname;
    if(interwho){
        ob = previous_object();
        if(base_name(ob) != SERVICES_D) return;
        sender = interwho;
        vname = interwho;
    }
    if(!ob || ob->GetForced()) return;
    if(!sender) sender = ob->GetKeyName();
    if(!vname) vname = ob->GetName();
    SendData(-1, ({ "tell", 5, Myname, sender, 0, who, vname, msg }) );
}

static void ProcessStartup(mixed data, string addy, int port, int fd){
    string name = data[2];
    InstData[name] = ([]);
    InstData[name]["addy"] = addy;
    InstData[name]["port"] = port;
    InstData[name]["fd"] = fd;
    InstData[name]["online"] = 1;
    InstData[name]["users"] = ([]);
    if(sizeof(data[7])){
        foreach(mixed foo in data[7]){
            if(stringp(foo)) InstData[name]["users"][foo] = 1;
        }
    }
    if(ENABLE_INSTANCES){
        Myname = data[4];
        call_out("SendStartup", 1, fd);
    }
}

static void ProcessClose(string name){
    if(!sizeof(InstData[name])) return;
    if(InstData[name]["fd"] > -1){
        this_object()->close_connection(InstData[name]["fd"]);
    }
    InstData[name]["fd"] = -1;
    InstData[name]["online"] = 0;
}

static void ProcessWhoUpdate(mixed data){
    if(!sizeof(InstData[data[2]])) return;
    if(!sizeof(InstData[data[2]]["users"])){
        InstData[data[2]]["users"] = ([]);
    }
    InstData[data[2]]["users"][data[3]] = data[6];
}

static void ProcessTell(mixed data){
    object who = find_player(data[5]);
    string ret;
    if(!who) return;
    ret = "%^BOLD%^RED%^"+capitalize(data[3]) +
        " tells you:%^RESET%^ " + data[7];
    who->eventPrint(ret, MSG_CONV);
    who->SetProperty("reply", data[3]);
    who->SetProperty("reply_time", time());
    who->eventTellHist(ret);
}

static void ProcessShout(mixed data){
    Name = capitalize(data[3]);
    users()->eventHearTalk(this_object(), 0, TALK_WORLD,
            "shout", data[6][0], data[6][1]);
}

string GetName(){
    return Name;
}

static void ReceiveICPData(mixed data, string addy, int port, int fd){
    string name;
    if(!arrayp(data)) return;
    if(sizeof(data) < 7) return;
    name = data[2];
    if(data[0] != "startup-req"){
        if( InstData[name] && InstData[name]["online"]){
            if(InstData[name]["addy"] != addy) return;
            if(InstData[name]["port"] != port ) return;
            if(!undefinedp(InstData[name]["fd"]) && 
                    InstData[name]["fd"] != fd) return;
        }
        else{
            return;
        }
    }
    switch(data[0]){
        case "startup-req" :
            if(data[6] != INSTANCE_PW) return;
            else ProcessStartup(data, addy, port, fd);
        break;
        case "channel-p" :
            CHAT_D->eventSendChannel(data[6]...);
        break;
        case "who-update":
            ProcessWhoUpdate(data);
        break;
        case "tell":
            ProcessTell(data);
        break;
        case "shout":
            ProcessShout(data);
        break;
        case "close-req" :
            ProcessClose(name);
        break;

        default :
        break;
    }
    if(undefinedp(InstData[name]["fd"])) InstData[name]["fd"] = fd;
}

string *GetRemoteUsers(string inst){
    string *ret = ({});
    if(!InstData || !InstData[inst] || !InstData[inst]["users"]) return ret;
    else ret = filter(keys(InstData[inst]["users"]),
            (: mapp(InstData[$(inst)]["users"][$1])
             && InstData[$(inst)]["users"][$1]["status"] > 0 :) );
    return ret;
}

void eventSendChannel(string name, string ch, string msg, int emote, 
        string target, string targmsg){
    mixed packet = ({ name, ch, msg, emote, target, targmsg });
    if(base_name(previous_object()) != CHAT_D) return;
    SendData(-1, ({ "channel-p", 5, Myname, 0, 0, 0, packet }) );
}

void eventSendShout(string msg, string lang){
    string name;
    mixed packet = ({ msg, lang });
    object ob = previous_object();
    if(!ob || !interactive(ob) || ob->GetForced()) return;
    name = ob->GetName();
    SendData(-1, ({ "shout", 5, Myname, name, 0, 0, packet }) );
}

static void eventWrite(mixed *packet){
    SendData(packet[4], packet);
}

static void close_connection(int fd){
    int sockerr;
    mixed *sockstat = ({});
    validate();
    if(fd < 0) return;
    sockstat = socket_status(fd);
    if(!sockstat || !sizeof(sockstat)) return;
    if(sockstat[1] == "LISTEN") return;
    yenta("About to try closing socket: "+fd, "white");
    yenta("Pre-closing state: "+sockstat[1],"yellow");
    sockerr = socket_close(fd);
    yenta("closing socket:"+fd,"white");
    yenta("closing sockerr:"+sockerr,"white");
    yenta("Post-closing state: "+socket_status(fd)[1],"yellow");
    yenta("---\n","white");
}

static void close_callback(int fd){
    yenta("close_callback: fd="+fd+"\n");
    if(fd < 0 || !sizeof(socket_status(fd))) return;
    if(socket_status(fd)[1] == "LISTEN") return;
    if(socket_status(fd)[1] == "DATA_XFER") return;
    close_connection(fd);
}

static void listen_callback(int fd){
    mixed fdstat,newfd;
    validate();

    if ((newfd = socket_accept(fd, "read_callback", "write_callback")) < 0) {
        return;
    }
    else {
        yenta("socket_accepted: "+newfd+
                ", "+identify(socket_status(newfd))+"\n","white");
    }
}

static void read_callback(int fd, mixed info){
    mixed sstat;
    string addy;
    int port;
    validate(fd);
    sstat = socket_status(fd);
    if(sizeof(sstat) > 3){
        string a, b, c, d;
        int p, i;
        i = sscanf(sstat[4],"%s.%s.%s.%s.%d",a,b,c,d,p);
        if(i > 4){
            port = (p - OFFSET_ICP); 
            addy = a+"."+b+"."+c+"."+d;
        }
    }
    if(bufferp(info)){
        yenta("fd "+fd+" is sending me buffer data!");
        yenta("As far as I can tell, it is: "+identify(read_buffer(info)),"blue");
    }
    else yenta("%^WHITE%^data from fd "+fd+":\n%^BLUE%^"+identify(info));
    ReceiveICPData(info, addy, port, fd);
}

static void write_callback(int fd){
    validate(fd);
    if(!sockets[fd]) return;
    if(sockets[fd]["write_status"] == EEALREADY) {
        this_object()->write_data(fd, sockets[fd]["pending"]);
        sockets[fd]["pending"] = 0;
    } 
    else {
        sockets[fd]["write_status"] = EESUCCESS;
    }
}

static void write_data_retry(int fd, mixed data, int counter){
    int rc;
    int maxtry = 20;
    if(fd < 0) return;
    validate(fd);
    if (counter == maxtry) {
        return;
    }
    rc = socket_write(fd, data);
    if(!sockets) sockets = ([]);
    if(!sockets[fd]){
        sockets[fd]=([]);
    }
    sockets[fd]["write_status"] = rc;
    switch (rc) {
        case EESUCCESS:
            break;
        case EEALREADY:
            sockets[fd]["pending"] = data;
            break;
        case EECALLBACK:
            break;
        case EESECURITY:
            break;
        case EEFDRANGE:
            break;
        case EENOTCONN:
            break;
        case EEBADF:
            break;
        default:
            if (counter < maxtry) {
                if(counter < 2 || counter > maxtry-1)
                    call_out( (: write_data_retry :), 2 , fd, data, counter + 1 ); 
                return;
            }
    }
}

static int write_data(int fd, mixed data){
    int ret;
    if(fd < 0) return;
    if(!validate(fd, 1)) return 0;
    write_data_retry(fd, data, 0);
    return ret;
}

static void Setup(){
    //yenta("icp setup got called");
    if ((icp_socket = socket_create(MUD, "read_callback", "close_callback")) < 0){
        log_file("/secure/log/icp","setup: Failed to create socket.\n");
        return;
    }
    if (socket_bind(icp_socket, PORT_ICP) < 0) {
        socket_close(icp_socket);
        log_file("/secure/log/icp","setup: Failed to bind socket to port.\n");
        return;
    }
    if (socket_listen(icp_socket, "listen_callback") < 0) {
        socket_close(icp_socket);
        log_file("/secure/log/icp","setup: Failed to listen to socket.\n");
        return;
    }
    log_file("/secure/log/icp","icp setup ended\n");
}

int eventCreateSocket(string host, int port){
    int x, ret;

    x = socket_create(MUD, "read_callback", "close_callback");
    if( x < 0 ) {
        yenta("Error in socket_create(): "+socket_error(x));
        return 0;
    }
    ret = x;
    x = socket_bind(x, 0);
    if( x != EESUCCESS ) {
        socket_close(ret);
        log_file("/secure/log/icp", "Error in socket_bind(): "+x);
        return 0;
    }
    x = socket_connect(ret, host + " " + (port + OFFSET_ICP), 
            "read_callback", "close_callback");
    if( x != EESUCCESS ) {
        socket_close(ret);
        yenta("Error in socket_connect(): "+socket_error(x));
        return x;
    }
    return ret;
}

int DoConnect(string ip, int port, string myname, string name){
    int sstat;
    validate();
    sstat = eventCreateSocket(ip, port);
    if( sstat < 0 ) return;
    if(!sockets) sockets = ([]);
    sockets[sstat] = ([]);
    return sstat;
}

static void InstConnect(string wat){
    int ret = DoConnect(InstData[wat]["addy"],
            InstData[wat]["port"],"global",wat);
    if(ret > -1){
        InstData[wat]["fd"] = ret;
        call_out("SendStartup", 1, ret);
    }
    else{
        yenta("InstConnect FAIL", "red");
    }
}

static void SendStartup(int fd){
    string name;
    foreach(mixed key, mixed val in InstData){
        if(key && val["fd"] == fd){
            name = key;
            break;
        }
    }
    SendData(fd, 
            ({"startup-req", 5, Myname, 0, name, 0, INSTANCE_PW, local_users()}));
    foreach(string user in local_users()){
        call_out("SendWhoUpdate", 0, user, 1);
    }
}

static void CheckConnections(){
    mixed socks = socket_names();
    mapping conns = ([]);
    if(ENABLE_INSTANCES){
        return;
    }
    if(!sizeof(keys(InstData))){
        return;
    }
    socks = filter(socks, (: $1[5] == this_object() :) );
    foreach(mixed arr in socks){
        if(sizeof(arr) > 4){
            string a, b, c, d;
            int p, i;
            i = sscanf(arr[4],"%s.%s.%s.%s.%d",a,b,c,d,p);
            if(i < 5) continue;
            foreach(mixed key, mixed val in InstData){
                if(key && mapp(val)){
                    InstData[key]["fd"] = -2;
                    if(val["port"] == (p - OFFSET_ICP) &&
                            val["addy"] == a+"."+b+"."+c+"."+d){
                        InstData[key]["fd"] = arr[0];
                        conns[key] = copy(InstData[key]);
                    }
                }
            }
        }
    }
    foreach(string foo in keys(InstData)){
        if(!foo || !InstData[foo]) continue;
        InstData[foo]["online"] = 0;
        if(member_array(foo, keys(conns)) == -1 
          || InstData[foo]["fd"] == -1){
            InstConnect(foo);
        }
        else InstData[foo]["online"] = 1;
    }
}

void heart_beat(){
    if(!ENABLE_INSTANCES) CheckConnections();
}