/* Do not remove the headers from this file! see /USAGE for more info. */
/*
** imud_d.c -- Intermud-3 Daemon
**
** A daemon responsible for processing the Intermud-3 protocol.
**
** The specification for Intermud-3 can be found at:
** http://www.imaginary.com/intermud/intermud3.html
**
** 95-May-11. Deathblade. Created.
*/
#include <socket.h>
#include <security.h>
#include <log.h>
#include <ports.h>
inherit M_DAEMON_DATA;
inherit M_RECONNECT;
inherit __DIR__ "imud/tell";
inherit __DIR__ "imud/emoteto";
inherit __DIR__ "imud/who";
inherit __DIR__ "imud/finger";
inherit __DIR__ "imud/locate";
inherit __DIR__ "imud/channel";
inherit __DIR__ "imud/mudlist";
inherit __DIR__ "imud/auth";
inherit __DIR__ "imud/ucache";
inherit __DIR__ "imud/oob";
inherit __DIR__ "imud/file";
inherit __DIR__ "imud/mail";
nosave private object router_socket;
private string * router_list = ({ ({ "*gjs", "198.144.203.194 9000"}) });
//private string * router_list = ({ ({ "*gjs", "208.192.43.105 9000"}) });
private int password;
void rcv_startup_reply(string orig_mud, string orig_user,
string targ_user, mixed * message);
void rcv_error(string orig_mud, string orig_user,
string targ_user, mixed * message);
void rcv_oob_req(string orig_mud, string orig_user,
string targ_user, mixed * message);
nosave private mapping dispatch =
([
"tell" : (: rcv_tell :),
"emoteto" : (: rcv_emoteto :),
"who-req" : (: rcv_who_req :),
"who-reply" : (: rcv_who_reply :),
"finger-req" : (: rcv_finger_req :),
"finger-reply" : (: rcv_finger_reply :),
"locate-req" : (: rcv_locate_req :),
"locate-reply" : (: rcv_locate_reply :),
"chanlist-reply" : (: rcv_chanlist_reply :),
"chan-who-req" : (: rcv_chan_who_req :),
"chan-who-reply" : (: rcv_chan_who_reply :),
"channel-m" : (: rcv_channel_m :),
"channel-e" : (: rcv_channel_e :),
"channel-t" : (: rcv_channel_t :),
"chan-user-req" : (: rcv_chan_user_req :),
"chan-user-reply" : (: rcv_chan_user_reply :),
"auth-mud-req" : (: rcv_auth_mud_req :),
"auth-mud-reply" : (: rcv_auth_mud_reply :),
"ucache-update" : (: rcv_ucache_update :),
"mudlist" : (: rcv_mudlist :),
"startup-reply" : (: rcv_startup_reply :),
"error" : (: rcv_error :),
"oob-req" : (: rcv_oob_req :),
]);
private nomask void send_message(string type, string target_mud,
string target_user, mixed * message)
{
string orig_user;
if ( !router_socket )
return;
if ( this_user() )
orig_user = this_user()->query_userid();
if ( catch(router_socket->send(({ type, 5, mud_name(), orig_user,
target_mud,
target_user }) + message)))
{
write("Error, the router seems to be dead.\n"
"Imud stuff isn't going to work till it's back up.\n");
}
}
protected void send_to_router(string type, mixed * message)
{
send_message(type, "*gjs", 0, message);
}
protected void send_to_mud(string type, string mudname, mixed * message)
{
send_message(type, mudname, 0, message);
}
protected void send_to_user(string type, string mudname, string username,
mixed * message)
{
send_message(type, mudname, username, message);
}
protected void send_to_all(string type, mixed * message)
{
send_message(type, 0, 0, message);
}
protected void return_error(string mudname, string username,
string errcode, string errmsg)
{
send_message("error", mudname, username, ({ errcode, errmsg, 0 }));
}
/* handle reads from the router */
private nomask void handle_router_read(object socket, mixed * message)
{
if (message[0]!= "mudlist")
{
string s = sprintf("%O", message);
if ( sizeof(s) > 200 )
s[200..] = "...";
// TBUG(s);
}
if ( !dispatch[message[0]] )
{
/* return an error packet */
send_message("error", message[2], message[3],
({ "unk-type",
sprintf("type '%s' is unrecognized", message[0]),
message }));
return;
}
evaluate(dispatch[message[0]],
message[2], message[3], message[5], message[6..]);
}
/* handle closures of the router socket */
private nomask void handle_router_close(object socket)
{
// TBUG("router closed");
router_socket = 0;
/* mark all the muds as down. when we reconnect we'll get new data */
mudlist_reset_entries();
//### for now, we need to set the password to 0. the router doesn't send
//### "up" status changes when we reconnect (general problem with the
//### the router -- I'm surprised nobody else has mentioned it)
password = 0;
trigger_reconnect("router");
}
/* (re)connect to the router */
private nomask void reconnect()
{
string err;
err = catch(router_socket =
unguarded(1, (: clone_object, SOCKET, SKT_STYLE_CONNECT_M,
router_list[0][1],
(: handle_router_read :),
(: handle_router_close :) :) ));
if ( err )
{
// TBUG(err);
if ( router_socket )
{
router_socket->remove();
router_socket = 0;
}
trigger_reconnect("router");
}
else
{
send_to_router("startup-req-3",
({ password,
query_mudlist_id(),
query_chanlist_id(),
__PORT__,
PORT_I3_TCP_OOB,
0,
/* DO NOT change this; see comments in /secure/user/login.c */
lima_version(),
"Lima",
driver_version(),
"LP",
lib_status(),
ADMIN_EMAIL,
([
"tell" : 1,
"emoteto" : 1,
"who" : 1,
"finger" : 1,
"locate" : 1,
"channel" : 1,
"auth" : 1,
"ucache" : 1,
"file" : 1,
"http" : 80,
"ftp" : 21,
"mail" : 1
]),
0, /* other_data */
}));
}
call_out("relisten_all_channels", 5);
}
void create()
{
string err;
if ( clonep() )
{
destruct(this_object());
return;
}
if ( ADMIN_EMAIL == "user@host.name" )
{
write("ERROR:\n"
" The I3 daemon will not load until you set a proper ADMIN_EMAIL\n"
" value in /include/config.h\n");
destruct(this_object());
return;
}
::create();
mudlist_reset_entries();
reconn_func = (: reconnect :);
oob_startup();
chan_startup();
file_startup();
mail_startup();
trigger_reconnect("router");
set_privilege("Mudlib:daemons");
}
void remove(int coming_back_soon)
{
/*
** coming_back_soon is 0 in most cases, 1 for an update. This is just
** the right value to tell the router when we might be back online.
*/
send_to_router("shutdown", ({ coming_back_soon }));
/* save all current state */
save_me();
if ( router_socket )
router_socket->remove();
chan_shutdown();
oob_shutdown();
remove_call_out();
destruct();
}
protected nomask void log_error_rcv(string mudname, mixed * message)
{
LOG_D->log(LOG_I3_ERROR, sprintf("(<- %s) %s: %s\n%O\n", mudname,
message[0], message[1], message[2]));
/* CHANNEL_D->deliver_channel("errors", */
/* sprintf("I3 (%s): %s", */
/* message[0], */
/* message[1])); */
}
protected nomask void log_error_snd(string mudname, mixed * message)
{
LOG_D->log(LOG_I3_ERROR, sprintf("(-> %s) %s: %s\n%O\n", mudname,
message[0], message[1], message[2]));
}
private nomask void rcv_startup_reply(string orig_mud, string orig_user,
string targ_user, mixed * message)
{
/*
** If the first router listed in the router list is not the one that
** we just connected to, then close the connection and connect to
** the specified router.
*/
//### we need a fail-over mechanism to go to a another (second) router
if ( message[0][0][0] != router_list[0][0] ||
message[0][0][1] != router_list[0][1] )
{
/* tell it we'll be gone indefinitely */
send_to_router("shutdown", ({ 0 }));
router_socket->remove();
}
router_list = message[0];
password = message[1];
/* make sure the new router_list is saved */
save_me();
/* reset the reconnection timers so the next reconnect is 1 minute */
cancel_reconnection("router");
/* if we don't have a socket any more (closed above), then reopen */
if ( !router_socket )
{
trigger_reconnect("router");
}
}
private nomask void rcv_error(string orig_mud, string orig_user,
string targ_user, mixed * message)
{
object ob;
if ( targ_user && (ob = find_user(targ_user)) )
{
tell(ob, sprintf("Error from %s: %s: %s\n",
orig_mud, message[0], message[1]));
}
else
{
log_error_rcv(orig_mud, message);
}
}
private nomask void rcv_oob_req(string orig_mud, string orig_user,
string targ_user, mixed * message)
{
/*
** We always keep the port open and people should be using the
** auth service. There isn't anything to do here right now.
*/
}
string stat_me()
{
string result = "\nROUTER SOCKET: ";
if ( router_socket )
result += router_socket->stat_me();
else
result += "<none>\n";
result +=
m_reconnect::stat_me() +
oob::stat_me();
return result;
}