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

string *banned_muds = ({});
mapping bad_connects = ([]);

static void process_startup_req(int protocol, mixed info, int fd){
    // Handles startup stuff.
    //  Loads info into newinfo mapping.
    //  Error if mud is already connected.
    mapping newinfo;
    string site_ip;
    string *brethren = ({});
    // router name is info[4], I'll just pretend I'm every router though, ha-ha!
    // also, should verify that all the fields are the right type

    //trr("info: "+identify(info));
    //trr("Incoming data from fd("+fd+"), address "+socket_address(fd)+".","blue");
    check_discs();
    //trr("The known status of that fd is "+identify(socket_status(fd)),"blue");
    //trr("muds on that fd: "+identify(filter(keys(this_object()->query_connected_muds()), (: this_object()->query_connected_muds()[$1] == $(fd) :) )),"blue");
    server_log("%^BLUE%^process_startup_req: protocol="+protocol+", mud="+info[2]);

    if(member_array(info[2], banned_muds) != -1) {
        server_log("%^RED%^"+info[2]+" denied. reason: banned.");
        trr("---\n","blue");
        return;
    }

    if(!info[2] || !sizeof(info[2])) {
        server_log("%^RED%^"+info[2]+" denied. reason: null name");
        trr("---\n","blue");
        return;
    }

    //    brethren = 
    //filter(keys(mudinfo), 
    //(: mudinfo[$1]["ip"] == 
    //clean_fd(socket_address($(fd))) :) ); 
    foreach(mixed element in keys(mudinfo)){
        if(member_array(element,keys(connected_muds)) == -1) continue;
        if(mudinfo[element] && mudinfo[element]["ip"] == clean_fd(socket_address(fd)))
            brethren += ({ element });
    }

    trr("Number of muds with the same ip: "+sizeof(brethren));
    if(sizeof(brethren) > MAXMUDS && !mudinfo[info[2]]){
        write_data(fd,({ "error", 5, router_name, 0, info[2], 0,
            "not-allowed", "Too many muds from your IP.", info }) );
        return;
    }

    if(fd && member_array(fd,keys(this_object()->query_connected_fds())) != -1){
        string existing_mud = this_object()->query_connected_fds()[fd];
        trr("Socket status: "+identify(socket_status(fd)),"red");
        server_log("%^RED%^FD CONFLICT, MUD: "+info[2]+", FD: "+fd);
        trr("---\n","blue");
        if(mudinfo[existing_mud]) mudinfo[existing_mud]["disconnect_time"] = time();
        map_delete(connected_muds, existing_mud);
        //broadcast_mudlist(existing_mud);
        schedule_broadcast(existing_mud);
    }

    if(sizeof(info)<18){ 
        // smallest protocol is protocol 1/2 which have size 18
        //trr("THIS SHOULDNT BE HERE");
        write_data(fd,({
            "error",
            5,
            router_name,
            0,
            info[2],
            0,
            "bad-pkt",
            "Bad startup_req packet",
            info
          }));
        return;
    }
    //trr("fd is:" +fd,"cyan");
    site_ip=socket_address(fd);
    site_ip = clean_fd(site_ip);
    //trr("site_ip: "+site_ip,"cyan");
    newinfo = ([
      "name":info[2],
      "ip":site_ip,
      "connect_time":time(),
      "disconnect_time":0,
      "password":info[6],
      "old_mudlist_id":info[7],
      "old_chanlist_id":info[8],
      "player_port":info[9],
      "imud_tcp_port":info[10],
      "imud_udp_port":info[11],
      "mudlib":info[12],
      "base_mudlib":info[13],
      "driver":info[14],
      "mud_type":info[15],
      "open_status":info[16],
      "protocol":protocol,
      "restart_delay":-1,
      "router" : my_name,
    ]);
    //trr("newinfo: "+identify(newinfo));

    if(protocol == 2 && sizeof(info) == 20 ) protocol = 3;

    switch(protocol){
    case 1:
    case 2:
        if(sizeof(info)!=18){
            server_log("error: wrong size packet. Got: "+sizeof(info)+", wanted 18");
            trr("---\n","blue");
            write_data(fd,({
                "error",
                5,
                router_name,
                0,
                info[2],
                0,
                "bad-pkt",
                "Bad startup_req packet",
                info
              }));
            return;
        }
        newinfo["services"]=info[17];
        newinfo["admin_email"]="Unknown"; // only in protocol 3
        newinfo["other_data"]=0; // only in protocol 3
        break;
    case 3:
        if(sizeof(info)!=20){
            server_log("error. wrong size packet. Got: "+sizeof(info)+", wanted 20");
            trr("---\n","blue");

            write_data(fd,({
                "error",
                5,
                router_name,
                0,
                info[2],
                0,
                "bad-pkt",
                "Bad startup_req packet",
                info
              }));
            return;
        }
        newinfo["admin_email"]=info[17];
        newinfo["services"]=info[18];
        newinfo["other_data"]=info[19];
        break;
    default:
        server_log("error. I dunno what.");

        write_data(fd,({
            "error",
            5,
            router_name,
            0,
            info[2], // mud name
            0,
            "not-imp",
            "unknown protocol: "+protocol,
            info
          }));
        return;
    }
    // Check valid values...
    if(
      !stringp(newinfo["open_status"]) ||
      !stringp(newinfo["admin_email"]) ||
      !stringp(newinfo["mud_type"]) ||
      !stringp(newinfo["driver"]) ||
      !stringp(newinfo["base_mudlib"]) ||
      !stringp(newinfo["mudlib"]) ||
      !mapp(newinfo["services"]) ||
      !intp(newinfo["imud_udp_port"]) ||
      !intp(newinfo["imud_tcp_port"]) ||
      !intp(newinfo["player_port"]) ||
      !intp(newinfo["password"]) ||
      !intp(newinfo["old_chanlist_id"]) ||
      !intp(newinfo["old_mudlist_id"]) ||
      (!mapp(newinfo["other_data"]) && newinfo["other_data"]!=0)
    ){
        write_data(fd,({
            "error",
            5,
            router_name,
            0,
            info[2],
            0,
            "bad-pkt",
            "Bad startup_req packet",
            info
          }));
        return;
    }
    if(connected_muds[info[2]]){
        // if MUD is already connected
        trr("ROUTER_D: mud already connected on fd"+connected_muds[info[2]],"red");
        trr("ROUTER_D: Xref back: mud on fd"+connected_muds[info[2]]+" is "+
          "supposed to be "+this_object()->query_connected_fds()[this_object()->query_connected_muds()[info[2]]],"red");
        server_log("mud already connected");
        trr("---\n","blue");
        if(this_object()->query_mudinfo()[info[2]]["ip"] != explode(socket_address(fd)," ")[0] ||
          mudinfo[info[2]]["password"] != newinfo["password"]){
            write_data(fd,({
                "error",
                5,
                router_name,
                0,
                info[2], // mud name
                0,
                "bad-proto", // doesn't seem to me like it should be bad-proto...
                // see what the official one uses for this
                // it might just boot the earlier MUD off?
                "MUD already connected", // Error message
                info
              }));

            //This message to the already-connected mud serves 
            //to alert the legit mud that something may be wrong, and
            //also will trigger a closure of the socket if it turns out
            //to actually be in a zombie state.
            write_data(connected_muds[info[2]],({
                "error",
                5,
                router_name,
                0,
                info[2], // mud name
                0,
                "bad-mojo", 
                "Another mud is trying to be you.", 
                ({ explode(socket_address(fd)," ")[0], info[12], info[13], info[17], info[9] })
              }));
            return;
        }
        if(this_object()->query_mudinfo()[info[2]]["ip"] == explode(socket_address(fd)," ")[0] &&
          mudinfo[info[2]]["password"] == newinfo["password"] ){
            server_log("Since it's the same ip and password, I'll remove the current connection");
            //this_object()->remove_mud(info[2],1);
            if(mudinfo[info[2]]) mudinfo[info[2]]["disconnect_time"] = time();
            map_delete(connected_muds, info[2]);
            //broadcast_mudlist(info[2]);
            schedule_broadcast(info[2]);
        }
    }

    if(mudinfo[info[2]] && sizeof(mudinfo[info[2]]) && mudinfo[info[2]]["password"] != newinfo["password"]){
        // if MUD is already known, not connected, and wrong password
        if(newinfo["ip"]==mudinfo[info[2]]["ip"] && info[2] != "Dead Souls"){
            // same IP as last time and it isn't Dead Souls
            server_log("Wrong password, but right IP");
            trr("Expected "+mudinfo[info[2]]["password"]+
              " but got "+newinfo["password"]);
            write_data(fd,({
                "error",5,router_name,0,info[2],0,
                "warning", // nothing in error summary that seems applicable?
                // Change later if I find a better error code
                "wrong password, but I'll allow you since it's the same IP as last time",0
              }));
        }
        else{
            trr("wrong password, and from a new IP (or a mud named Dead Souls)","red");
            trr("---\n","blue");
            if(!bad_connects[newinfo["ip"]]) bad_connects[newinfo["ip"]] = 1;
            else bad_connects[newinfo["ip"]] = bad_connects[newinfo["ip"]] + 1;
            if(bad_connects[newinfo["ip"]] > 100){
                trr("ROUTER_D: "+newinfo["ip"]+" blacklisted!","red");
                this_object()->AddBlacklistedMud(newinfo["ip"]);
                bad_connects[newinfo["ip"]] = 0;
            }
            server_log("%^RED%^WRONG PASSWORD, AND FROM A NEW IP");
            write_data(fd,({
                "error",
                5,
                router_name,
                0,
                info[2], // mud name
                0,
                "not-allowed", // Change later!
                "wrong password, and from a new IP", // Error message
                info
              }));
            return;
        }
    }
    if(!mudinfo[info[2]] || !newinfo["password"] || mudinfo[info[2]]["password"] != newinfo["password"] ){
        // if new MUD, assign it a password
        newinfo["password"]=random_numbers(9,1);
        trr("ROUTER_D: Assigning password "+newinfo["password"],"white");
        //trr("Ok. this is the password: "+newinfo["password"],"white");
        // Change this maybe... see if the password is supposed to be in a certain range
    }
    else {
        trr("ROUTER_D: password: Known: "+mudinfo[info[2]]["password"]+", current: "+newinfo["password"],"green");
    }
    // MUD should be okay at this point.
    //trr("about to update the mudinfo...","white");
    mudinfo[info[2]]=newinfo; // update the mudinfo
    connected_muds[info[2]] = fd; // add this MUD to list of connected muds
    //trr("about to send the startup reply...","white");
    send_startup_reply(info[2]); // reply to MUD
    mudinfo_update_counter++;
    mudinfo_updates[info[2]]=mudinfo_update_counter;
    send_mudlist_updates(info[2], newinfo["old_mudlist_id"]);
    send_full_mudlist(info[2]);
    broadcast_mudlist(info[2]);
    broadcast_chanlist("foo",info[2]);
    if(this_object()->query_imc(info[2])){ 
        //tc(info[2]+" is a imc2 thing","cyan");
        //IMC2_SERVER_D->acknowledge_startup(fd, info[2]);
    }
    if(bad_connects[newinfo["ip"]]) bad_connects[newinfo["ip"]] = 0;
    if(member_array("channel", keys(newinfo["services"])) != -1){
        //send_chanlist_reply(info[2], ( newinfo["old_chanlist_id"]) ? newinfo["old_chanlist_id"] : (random(1138) * 1138)  );

    }
    else {
        //trr("-------------------------------","blue");
        trr("It looks like "+info[2]+" doesn't have a channel service?!?","blue");
        //trr("These are the services reported: "+identify(newinfo["services"]),"blue");
        //trr("This is what newinfo looks like: "+identify(newinfo),"blue");
        //trr("-------------------------------","blue");
    }
    trr(timestamp()+" process_startup_req: for mud: "+info[2]+" complete.\n---\n","blue");
}