/
LIB3/
LIB3/D/ADMIN/
LIB3/D/ADMIN/OBJ/
LIB3/D/ADMIN/ROOM/W/
LIB3/D/HOME/
LIB3/D/HOME/CITY/ARENA/
LIB3/D/HOME/CITY/ITEMS/
LIB3/D/HOME/CITY/POSTOFFI/
LIB3/DOC/
LIB3/GLOBAL/SPECIAL/
LIB3/GLOBAL/VIRTUAL/
LIB3/NET/
LIB3/NET/CONFIG/
LIB3/NET/DAEMON/CHARS/
LIB3/NET/GOPHER/
LIB3/NET/INHERIT/
LIB3/NET/OBJ/
LIB3/NET/SAVE/
LIB3/NET/VIRTUAL/
LIB3/OBJ/B_DAY/
LIB3/OBJ/HANDLERS/TERM_TYP/
LIB3/PLAYERS/B/
LIB3/PLAYERS/N/
LIB3/ROOM/
LIB3/SAVE/
LIB3/SAVE/BOARDS/
LIB3/SAVE/ENVIRON/
LIB3/SAVE/POST/
LIB3/STD/COMMANDS/SHADOWS/
LIB3/STD/CREATOR/
LIB3/STD/DOM/
LIB3/STD/EFFECTS/
LIB3/STD/EFFECTS/HEALING/
LIB3/STD/EFFECTS/OTHER/
LIB3/STD/EFFECTS/POISONS/
LIB3/STD/ENVIRON/
LIB3/STD/GUILDS/
LIB3/STD/LIQUIDS/
LIB3/STD/ROOM/
LIB3/STD/TRIGGER/SHADOW/
LIB3/W/
LIB3/W/BANNOR/
LIB3/W/NEWSTYLE/
/* Dosmud hack */
#include "std.h"

#include "udp.h"
#include "socket.h"
#include "inet.h"
/*
 * This has the list of cd muds that are known.  We get this from the
 * mudlist server when we boot.
 */

#undef DEBUG

#ifdef DEBUG
#define TP(STR) if (find_player("pinkfish")) tell_object(find_player("pinkfish"), STR)
#else
#define TP(STR)
#endif

object  monitor;
mapping known_muds;
int     my_port, my_socket;

void    create()
{
    known_muds = ([ ]);
    seteuid( getuid() );
    call_out( "send_startup_udp", 2 );
    call_out( "do_pings", 30 * 60 );	/* Do this every 5 minutes */
}				/* create() */

void    send_startup_udp()
{
    NAMESERVER->lookup_service( "cd_udp", ( MUD_NAME ), "finish_lookup" );
}				/* send_startup_udp() */

void    do_pings()
{
    int     i;
    string *muds, ping_packet;

    call_out( "do_pings", 5 * 60 );
/* Both to keep us alive in tehir arrays and to check on dead muds. */
    muds = keys( known_muds );
    for( i = 0; i < sizeof( muds ); i++ )
    {
	if( !mapp( known_muds[ muds[ i ] ] ) )
	    continue;
	known_muds[ muds[ i ] ][ UDP_NO_CONTACT ] = known_muds[ muds[ i ] ][ UDP_NO_CONTACT ] + 1;
	PING_Q->send_ping_q( known_muds[ muds[ i ] ][ "HOSTADDRESS" ],
			     known_muds[ muds[ i ] ][ "PORTUDP" ] );
	if( known_muds[ muds[ i ] ][ UDP_NO_CONTACT ] >= MAX_RETRYS )
	{
	    map_delete( known_muds, muds[ i ] );
	}
    }
}				/* do_pings() */

void    finish_lookup( string service, string addr, int port, mixed *args )
{
    string  host;
    int     dport, i;
    mixed * muds;

    TP( "Finished lookup.\n" );
    TP( service + ":" + addr + ":" + port + "\n" );
    my_port = 6942;
    muds = MUDLIST_UDP;
    for( i = 0; i < sizeof( muds ); i += 2 )
    {
	this_object()->send_udp( muds[ i ], muds[ i + 1 ], "@@@" + UDP_STARTUP +
				 this_object()->start_message() +
				 "@@@\n" );
	(UDP_PATH + "mudlist_q")->send_mudlist_q( muds[ i ], muds[ i + 1 ] );
    }
    if( !my_socket )
    {
	TP( "Creating socket.\n" );
	my_socket = socket_create( DATAGRAM, "read_callback", "close_callback" );
	if( my_socket <= 0 )
	    return;
	TP( "Binding socket.\n" );
	if( socket_bind( my_socket, my_port ) <= 0 )
	{
	    TP( "Failing to bind....\n" );
	    socket_close( my_socket );
	}
    }
}				/* finish_lookup() */

string  start_message()
{
    return "||NAME:" + capitalize( MUD_NAME ) +
	"||VERSION:10.10" +
	"||MUDLIB:Discworld" +
	"||HOST:" + query_host_name() +
	"||PORT:7680" +
	"||TCP:some" +
	"||PORTUDP:" + my_port +
	"||TIME:" + ctime( time() );
}				/* start_message() */

void    send_udp( string host, int port, string msg )
{
    int     sock;

    if( monitor )
	tell_object( monitor, "Sending " + msg );
    sock = socket_create( DATAGRAM, "read_callback", "close_callback" );
    if( sock <= 0 )
    {
	log_file( "CD_NAMESERVER", "Failed to open socket to " + host + " " + port + "\n" );
	return;
    }
    socket_write( sock, msg, host + " " + port );
    socket_close( sock );
}				/* send_udp() */

void    read_callback( int sock, string msg, string addr )
{
    string  func, rest, *bits, name, arg;
    mapping args;
    int     i;

    if( !msg )
	msg = "";
/*
   if(bits[i])
 */
    if( monitor )
	tell_object( monitor, "Got " + msg );
    if( !sscanf( msg, "@@@%s||%s@@@%*s", func, rest ) )
    {
	if( !sscanf( msg, "@@@%s@@@%*s", func ) )
	{
	    return;
	}
	rest = "";
    }
    sscanf( addr, "%s %*s", addr );
    if( rest )
	bits = explode( rest, "||" );
    else
	bits = ({ });
    args = ([ ]);
    for( i = 0; i < sizeof( bits ); i++ )
    {
	if( bits[ i ] )
	    if( sscanf( bits[ i ], "%s:%s", name, arg ) == 2 )
	    {
		args[ name ] = arg;
	    }
    }
    args[ "HOSTADDRESS" ] = addr;
    if( mapp( known_muds[ args[ "NAME" ] ] ) )
	known_muds[ args[ "NAME" ] ][ UDP_NO_CONTACT ] = 0;
/* Ok, now we need to lookup the command and execute it... */
    if( file_size( UDP_PATH + func + ".c" ) > 0 )
	(UDP_PATH + func)->incoming_request( args );
/* Otherwise, we just ignore it... */
}				/* read_callback() */

mapping query_known_muds()
{
    return known_muds + ([ ]);
}

void    set_mud_info( string name, mapping junk )
{
    if( previous_object() != this_object() &&
	    file_name( previous_object() )[ 0..strlen( UDP_PATH ) - 1 ] != UDP_PATH )
	return;
    if( !known_muds[ name ] )
    {
/* Send them a mudlist query... */
	(UDP_PATH + "mudlist_q")->send_mudlist_q( junk[ "HOSTADDRESS" ],
						  junk[ "PORTUDP" ] );
    }
    known_muds[ name ] = junk;
    if( lower_case( name ) != name )
	known_muds[ lower_case( name ) ] = name;
}				/* set_mud_info() */

void    zap_mud_info( string name, mapping junk )
{
    if( previous_object() != this_object() &&
	    file_name( previous_object() )[ 0..strlen( UDP_PATH ) - 1 ] != UDP_PATH )
	return;
    map_delete( known_muds, name );
}				/* zap_mud_info() */

mapping query_mud_info( string name )
{
    mixed   bing;

    bing = known_muds[ name ];
    if( stringp( bing ) )
	return known_muds[ bing ];
    return bing;
}				/* query_mud_info() */

int     query_my_port()
{
    return my_port;
}

void    set_monitor( object ob )
{
    monitor = ob;
}
object  query_monitor()
{
    return monitor;
}