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

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

inherit DAEMON;

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_errors(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_errors(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;
}