lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* 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;
}