/*
InterMud 3 client
by Drizzt@Tmi-2
// Leto july 6th 95 - Tried to add some security :)
*/
#include <net/i3.h>
#define I3_DEBUG_OUT 0x01
#define I3_DEBUG_IN 0x02
#define I3_DEBUG_LST 0x04
static object router_socket, oob_socket, debugger;
static mapping services;
static int debug_level;
int router_password, mudlist_id, chanlist_id;
mapping mudlist, chanlist;
// Prototypes :)
void create();
void check_router();
void set_debugging(int level, object person){
// Prevent people from snooping private stuff
if(!adminp(person)) return;
debugger = person;
debug_level = level;
}
mixed *query_debugging(){
return ({ debugger, debug_level });
}
static private void debug_stuff(mixed message){
if(debugger)
message("I3",sprintf("%c[1;32m[I3]: %O%c[0m\n", 27, message, 27), debugger);
}
string query_network_name(string mud){
string *names;
int found,i;
if(mud == "global") return 0;
if(mud && mudlist){
mud = replace_string(mud,"."," ");
/* Match in the Mudlist for a correct name */
mud = lower_case(mud);
names = keys(mudlist);
found = 0;
for(i=0;i<sizeof(names);i++){
if(lower_case(names[i]) == mud) {
mud = names[i];
found = 1;
break;
}
}
if(!found) return 0;
}
return mud;
}
int read_callback(object socket, mixed info){
string func, fname;
// Leto: We should add an origin() and/or prev_obj==SOCKET_OBJ
// check for security.
if(!sizeof(info)) return 0;
if(debug_level & I3_DEBUG_IN) debug_stuff(info);
func = "process_"+info[0];
func = replace_string(func,"-","_");
if(function_exists(func, this_object())) {
/* Internal function (Mudlists, etc) */
call_other(this_object(), func, info);
return 0;
}
/* External Module */
if(!sscanf(info[0], "%s-%*s",fname)) fname = info[0];
call_other(I3_MODULES+fname, func, info);
return 1;
}
int close_callback(object socket){
// Leto: add a check here too, same reason.
socket->remove();
create();
return 1;
}
int send_packet(string type, string user, string mud, string target, mixed *data){
mixed *send, *names;
int i,found;
// Leto: Add origin()==LOCAL_ORGIN || base_name(prev_obj)[0..x]
// == "/adm/daemons/network/I3/" check here.
if(!query_network_name(mud) && mud != "global" && mud != 0) return 0;
mud = query_network_name(mud);
send = ({ type, I3_TTL, MUD_NAME, user, mud, target }) + data;
if(debug_level & I3_DEBUG_OUT) debug_stuff(send);
router_socket->send(send);
return 1;
}
static private int send_chanlist_req(){
send_packet(PRT_CHANLIST_REQ, 0, ROUTER_NAME, 0, ({ chanlist_id }) );
}
// Leto: I can't find anything calling this function.
void process_chanlist_reply(mixed *info){
int i;
string *kys;
if(sizeof(info) != SIZ_CHANLIST_REPLY) return;
chanlist_id = info[6];
if(!chanlist) chanlist = ([]);
chanlist += info[7];
kys = keys(chanlist);
/* Clean up deleted channels */
for(i=0;i<sizeof(kys);i++){
if(!chanlist[kys[i]]) map_delete(chanlist, kys[i]);
}
save_object(I3_SAVE_FILE);
}
static private int send_startup_req_1() {
mixed *packet;
packet = ({ router_password,
mudlist_id,
chanlist_id,
__PORT__,
OOB_TCP,
OOB_UDP,
I3_MUDLIB,
I3_BASE_LIB,
__VERSION__,
"LPmud",
MUD_STAGE,
services });
send_packet(PRT_STARTUP_REQ_1,0,ROUTER_NAME,0,packet);
}
// Leto: This function isn't called either
void process_startup_reply(mixed *info){
if(sizeof(info) != SIZ_STARTUP_REPLY) return;
router_password = info[7];
save_object(I3_SAVE_FILE);
}
/*
Internal Mudlist Routines:
We handle all of them in here because this way we can deal with
only 1 object to save, instead of saving a module, and this object
*/
void process_mudlist(mixed *info){
string *kys;
int i;
if(sizeof(info) != SIZ_MUDLIST) return;
mudlist_id = info[6];
if(!mudlist) mudlist = ([]);
mudlist += info[7];
kys = keys(mudlist);
/* Clean up deleted channels */
for(i=0;i<sizeof(kys);i++){
if(!mudlist[kys[i]]) {
map_delete(mudlist, kys[i]);
if(debug_level & I3_DEBUG_LST) debug_stuff("Removing Mud \""+kys[i]+"\"\n");
continue;
}
}
save_object(I3_SAVE_FILE);
}
mixed query_mud(string arg){
return mudlist[arg];
}
mapping query_mudlist(){
return mudlist;
}
/* End of Mudlist Routines */
void send_error(string mud, string user, string error_code, string message, mixed *packet){
send_packet(PRT_ERROR, 0, mud, user, ({ error_code, message, packet }));
}
void process_error(mixed *info){
object ob;
ob = find_living(info[5]);
if (!ob && debugger) ob = debugger;
if (!ob) log_file("I3","I3 Error from "+info[2]+": "+info[7]+"\n");
else message("I3","I3 Error from "+info[2]+": "+info[7]+"\n", ob);
}
void setup_services(){
mixed dir;
string name;
int i;
services = ([]);
#ifdef I3_SERVICE_DETECT
dir = get_dir(I3_MODULES);
for(i=0;i<sizeof(dir);i++){
sscanf(dir[i],"%s.c", name);
services += ([ name : 1 ]);
}
#endif
services += I3_SERVICES;
return;
}
void create(){
if(sizeof(get_dir(I3_SAVE_FILE))) restore_object(I3_SAVE_FILE);
setup_services();
router_socket = clone_object(SOCKET, SKT_STYLE_CONNECT_M,
I3_ROUTER, (: read_callback :),
(: close_callback :) );
oob_socket = clone_object(SOCKET, SKT_STYLE_LISTEN_M, OOB_TCP,
(: read_callback :), (: close_callback :) );
send_startup_req_1();
// [Deathblade] commented this damn thing out :-). There is
// no such packet.
// send_chanlist_req();
call_out( (: check_router :) , 900 );
}
void remove(){
if(oob_socket) oob_socket->remove();
if(router_socket) router_socket->remove();
destruct(this_object());
}
void check_router() {
if(!router_socket || !oob_socket)
{
log_file("I3","Lost I3 router, reconnecting at "+ctime(time())+".\n");
create();
return;
}
call_out( (: check_router :) , 900 );
}