merentha_fluffos_v2/
merentha_fluffos_v2/bin/
merentha_fluffos_v2/fluffos-2.9-ds2.03/
merentha_fluffos_v2/fluffos-2.9-ds2.03/ChangeLog.old/
merentha_fluffos_v2/fluffos-2.9-ds2.03/Win32/
merentha_fluffos_v2/fluffos-2.9-ds2.03/compat/
merentha_fluffos_v2/fluffos-2.9-ds2.03/compat/simuls/
merentha_fluffos_v2/fluffos-2.9-ds2.03/include/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/clone/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/command/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/data/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/etc/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/include/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/inherit/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/inherit/master/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/log/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/single/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/single/tests/compiler/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/single/tests/efuns/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/single/tests/operators/
merentha_fluffos_v2/fluffos-2.9-ds2.03/testsuite/u/
merentha_fluffos_v2/fluffos-2.9-ds2.03/tmp/
merentha_fluffos_v2/fluffos-2.9-ds2.03/windows/
merentha_fluffos_v2/lib/cfg/
merentha_fluffos_v2/lib/cfg/races/
merentha_fluffos_v2/lib/cmds/abilities/
merentha_fluffos_v2/lib/cmds/actions/
merentha_fluffos_v2/lib/cmds/spells/
merentha_fluffos_v2/lib/daemon/include/
merentha_fluffos_v2/lib/daemon/services/
merentha_fluffos_v2/lib/doc/
merentha_fluffos_v2/lib/doc/building/
merentha_fluffos_v2/lib/doc/help/classes/
merentha_fluffos_v2/lib/doc/help/general/
merentha_fluffos_v2/lib/doc/help/races/
merentha_fluffos_v2/lib/doc/help/skills/
merentha_fluffos_v2/lib/doc/help/stats/
merentha_fluffos_v2/lib/doc/man/efuns/
merentha_fluffos_v2/lib/doc/man/lfuns/
merentha_fluffos_v2/lib/doc/news/
merentha_fluffos_v2/lib/doc/old/
merentha_fluffos_v2/lib/doc/old/concepts/
merentha_fluffos_v2/lib/doc/old/lpc/constructs/
merentha_fluffos_v2/lib/doc/old/lpc/types/
merentha_fluffos_v2/lib/domains/ROOMS/
merentha_fluffos_v2/lib/domains/obj/armour/
merentha_fluffos_v2/lib/domains/obj/monsters/
merentha_fluffos_v2/lib/domains/obj/other/
merentha_fluffos_v2/lib/domains/obj/weapons/
merentha_fluffos_v2/lib/realms/petrarch/
merentha_fluffos_v2/lib/save/daemons/
merentha_fluffos_v2/lib/save/rid/
merentha_fluffos_v2/lib/save/users/a/
merentha_fluffos_v2/lib/save/users/p/
merentha_fluffos_v2/lib/save/users/t/
merentha_fluffos_v2/lib/std/login/
merentha_fluffos_v2/lib/std/obj/
merentha_fluffos_v2/win32/
// Petrarch
// Merentha Lib 1.0
// network.c

#include <daemons.h>
#include <socket.h>
#include <std.h>

inherit DAEMON;
string convert_map_to_string3(mapping str);

mapping __MUDS=([]);
static string *__Services=({"rcre_request","rcre_reply","ping_request","ping_reply","rwho_request","rfinger_request","rtell_request","rwho_reply","rfinger_reply","rtell_reply"});

mapping query_mud_list() { return __MUDS; }

mapping convert_string_to_map(string str) {
    mapping tmp=([]);
    string *parts=explode(str,"||M||");
    string key, val;
    int i=sizeof(parts);
    while(i--) {
        sscanf(parts[i], "%s:||:||:%s", key, val);
        tmp[key]=val;
    }
    return tmp;
}
mapping convert_string_to_map2(string str) {
    mapping tmp=([]);
    string *parts=explode(str,"||MM||");
    string key, val;
    int i=sizeof(parts);
    while(i--) {
        sscanf(parts[i], "%s::||::||::%s", key, val);
        tmp[key]=val;
    }
    return tmp;
}
mapping convert_string_to_map3(string str) {
    mapping tmp=([]);
    string *parts=explode(str,"||MMM||");
    string key, val;
    int i=sizeof(parts);
    while(i--) {
        sscanf(parts[i], "%s:::||:::||:::%s", key, val);
        tmp[key]=val;
    }
    return tmp;
}

string convert_map_to_string(mapping str) {
    string *k=keys(str);
    string tmp="";
    int i=sizeof(k);
    while(i--) {
        tmp+=k[i]+":||:||:"+str[k[i]];
        if(i) tmp+="||M||";
    }
    return tmp;
}
string convert_map_to_string2(mapping str) {
    string *k=keys(str);
    string tmp="";
    int i=sizeof(k);
    while(i--) {
        tmp+=k[i]+"::||::||::"+convert_map_to_string3(str[k[i]]);
        if(i) tmp+="||MM||";
    }
    return tmp;
}
string convert_map_to_string3(mapping str) {
    string *k=keys(str);
    string tmp="";
    int i=sizeof(k);
    while(i--) {
        tmp+=k[i]+":::||:::||:::"+str[k[i]];
        if(i) tmp+="||MMM||";
    }
    return tmp;
}

void open_socket_to_send(string address, mapping message) {
   string *args;
    int s, error;

   if(!message || !address) return;
   if(message["args"] && stringp(message["args"])) {
      args=explode(message["args"], "\n");
      if(sizeof(args)>6) {
        message["args"]=implode(args[0..5],"\n");
        open_socket_to_send(address, message);
        message["args"]=implode(args[6..<0],"\n");
        open_socket_to_send(address, message);
        return;
      }
   }

    s = socket_create(DATAGRAM, "close_callback");
    if (s < 0) {
        log_file("network", "(osts) socket_create: "+socket_error(s)+"\n");
        return;
    }
    log_file("network", "(osts) Created socket descriptor " + s + "\n");
    error = socket_bind(s, 0);
    if (error != EESUCCESS) {
        log_file("network", "(osts) socket_bind: " + socket_error(error) + "\n");
        socket_close(s);
        return;
    }
    socket_write(s,convert_map_to_string(message), address);
    socket_close(s);
}

varargs void read_callback(int s, mixed message, string host) {
    string args, junk;

    if(!message || !stringp(message)) {
        log_file("network", "(rcb) Received non-message from socket: "+s+"\n");
        return;
    }
    message=convert_string_to_map(message);
    sscanf(socket_address(s), "%s %s", junk, args);
    if(junk=="0.0.0.0") sscanf(host, "%s %s", junk, args);
    if(mapp(message)) {
        if(!message["name"]) { return; }
        if(!message["service"] || member_array(message["service"],__Services)==-1) { return; }
        __MUDS[message["name"]]=([
          "name":message["name"],
          "address":junk,
          "udp_port":message["udp_port"],
          "port":message["port"],
          "mudlib":message["mudlib"],
          "driver":message["driver"],
          "pings":0,
        ]);
        args=call_other(this_object(),({message["service"],message}));
        if(!args) { return; }
        if(strsrch(message["service"],"_request")!=-1) {
            open_socket_to_send(""+junk+" "+message["udp_port"],
              (["name":mud_name(),
                "port":query_host_port(),
                "udp_port":MERENTHA_INTERMUD,
                "mudlib":mudlib(),
                "driver":driver(),
                "remote_user":message["remote_user"],
                "args":args,
                "service":replace_string(message["service"],"_request","_reply"),
              ]) );
            return;
        }
    }
}

void close_callback(int s) {
    log_file("network", "(ccb) Closed socket: "+s+"\n");
}

void create_main_socket() {
    int s, error;

    s = socket_create(DATAGRAM, "read_callback");
    if (s < 0) {
        log_file("network","(main) socket_create: "+socket_error(s)+"\n");
        return;
    }
    log_file("network", "(main) Created socket descriptor " + s + "\n");

    error = socket_bind(s, MERENTHA_INTERMUD);
    if (error != EESUCCESS) {
        log_file("network", "(main) socket_bind: " + socket_error(error) + "\n");
        socket_close(s);
        return;
    }
}

void create() {
    restore_object("/save/daemons/network");
    call_out("create_main_socket", 0);
    call_out("send_ping_request", 5);
}

void save_network() {
    save_object("/save/daemons/network");
}

/************** SERVICES **************/
string rwho_reply(mapping message) {
    object player;
    if(player=find_player(message["remote_user"]))
        message("rwho", message["args"], player);
    return 0;
}

string rfinger_reply(mapping message) {
    object player;
    if(player=find_player(message["remote_user"]))
        message("rwho", message["args"], player);
    return 0;
}

string rtell_reply(mapping message) {
    object player;
    if(player=find_player(message["remote_user"]))
        message("rwho", message["args"], player);
    return 0;
}

string ping_reply(mapping message) {
    mapping remote_muds=convert_string_to_map2(message["args"]);
    string *new_names, *old_names;
    int i;
    if(!remote_muds || !mapp(remote_muds)) return 0;
    old_names=keys(__MUDS);
    i=sizeof(new_names=keys(remote_muds));
    while(i--) {
        if(member_array(new_names[i], old_names)==-1 && lower_case(new_names[i])!=lower_case(mud_name()) && remote_muds["pings"]<MAX_PINGS) {
            __MUDS[new_names[i]]=convert_string_to_map3(remote_muds[new_names[i]]);
            old_names=keys(__MUDS);
        }
    }
}

string rwho_request(mapping message) {
    string *u=users()->query_cap_name();
    int i=to_int(message["screen_width"]);
    if(!i) i=75;
    return "\n"+border("%^RED%^"+format_page(u, 4, i-4),"rwho : "+mud_name(), i);
}

string rfinger_request(mapping message) {
    int i=to_int(message["screen_width"]);
    if(!i) i=75;
    if(message["target"] && message["target"]!="0") return "\n"+FINGER_D->get_player_info(message["target"], i);
    else return "\n"+FINGER_D->get_player_list(i);
}

string rtell_request(mapping message) {
    object ob;
    if(!ob=find_player(message["target"])) {
        return ""+message["target"]+" could not be found in "+mud_name()+".";
    }
    message("communication",capitalize(message["remote_user"])+"@"+message["name"]+" tells you: "+message["args"], ob);
    return ""+capitalize(message["target"])+" received your message.";
}

string rcre_request(mapping message) { 
    CHAT_D->send_message(message["remote_user"],"intermer",message["args"]);
    return 0; 
}

string ping_request(mapping message) { 
    if(to_int(message["known_muds"])<sizeof(__MUDS)) return convert_map_to_string2(__MUDS);
    return 0; 
}

string get_mud_address(string name) {
    if(!__MUDS) return "0";
    if(!__MUDS[name]) return 0;
    return ""+__MUDS[name]["address"]+" "+__MUDS[name]["udp_port"];
}

varargs int send_rwho_request(string mud, string player, int width) {
    string address=get_mud_address(mud);
    if(!address) return notify_fail("No such MUD.\n");
    if(address=="0") return notify_fail("No MUDs.\n");
    open_socket_to_send(address, 
      (["name":mud_name(),
        "port":query_host_port(),
        "udp_port":MERENTHA_INTERMUD,
        "mudlib":mudlib(),
        "driver":driver(),
        "remote_user":player,
        "screen_width":(width?width:75),
        "service":"rwho_request",
      ]) );
    return 1;
}

varargs int send_finger_request(string mud, string player, string target, int width) {
    string address=get_mud_address(mud);
    if(!address) return notify_fail("No such MUD.\n");
    if(address=="0") return notify_fail("No MUDs.\n");
    open_socket_to_send(address,
      (["name":mud_name(),
        "port":query_host_port(),
        "udp_port":MERENTHA_INTERMUD,
        "mudlib":mudlib(),
        "driver":driver(),
        "remote_user":player,
        "screen_width":(width?width:75),
        "service":"rfinger_request",
        "target":target,
      ]) );
    return 1;
}

int send_rtell_request(string mud, string player, string target, string message) {
    string address=get_mud_address(replace_string(mud, ".", " "));
    if(!address) return notify_fail("No such MUD.\n");
    if(address=="0") return notify_fail("No MUDs.\n");
    open_socket_to_send(address,
      (["name":mud_name(),
        "port":query_host_port(),
        "mudlib":mudlib(),
        "udp_port":MERENTHA_INTERMUD,
        "driver":driver(),
        "remote_user":player,
        "service":"rtell_request",
        "target":target,
        "args":message,
      ]) );
    return 1;
}

int send_rcre_request(string player, string message) {
    string address, *names;
    int i=sizeof(names=keys(__MUDS));
    while(i--) {
        address=get_mud_address(names[i]);
        if(!address) continue;
        if(address=="0") continue;
        open_socket_to_send(address,
          (["name":mud_name(),
            "port":query_host_port(),
            "udp_port":MERENTHA_INTERMUD,
            "mudlib":mudlib(),
            "driver":driver(),
            "remote_user":player+"@"+mud_name(),
            "service":"rcre_request",
            "args":message,
          ]) );
    }
    return 1;
}

int send_ping_request() {
    string address, *names;
    int i=sizeof(names=keys(__MUDS));
    while(i--) {
        __MUDS[names[i]]["pings"]=__MUDS[names[i]]["pings"]+1;
        if(to_int(__MUDS[names[i]]["pings"])>MAX_PINGS) map_delete(__MUDS,names[i]);
        address=get_mud_address(names[i]);
        if(!address) continue;
        if(address=="0") continue;
        open_socket_to_send(address,
          (["name":mud_name(),
            "port":query_host_port(),
            "udp_port":MERENTHA_INTERMUD,
            "mudlib":mudlib(),
            "driver":driver(),
            "service":"ping_request",
            "known_muds":sizeof(__MUDS),
          ]) );
    }
    call_out("save_network", 90);
    call_out("send_ping_request", 900);
    return 1;
}