/
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"


void    boot();

#ifdef BASIS
#include <attributes.h>
#endif

#include <socket.h>		/* includes socket_errors.h indirectly */

#ifdef __VERSION__
#define VERSION __VERSION__
#endif

// mudlib: Basis
// date:   10/10/92
// author: Truilkan@Basis
// desc:   mudwho client written for MudOS 0.9 (uses DATAGRAM sockets)

// interface:
//
//   call boot() when the mud starts up (in preload() with the code that
//     preloads other socket efun code is a good place to call it from)
//   call halt() when the mud shuts down (e.g. in a shutdown() simul_efun)
//   call add_user(user_object) for each player that logs in (don't forget
//     reconnects by netdeaders).
//   call remove_user(user_object) for each player that logs out.
//     (user::remove() may be a good place to add this call.  Also, you
//     wish to call this when netdeath occurs).

// DAEMON_IP won't need to change unless you want to point to a different
// mudwho dameon.  If you wish to use Portals as your mudwho daemon,
// you'll have to get your mud and mud password added to the Portals
// mudwho daemon database.
//
// Here is information on how to contact existing mudwho daemon admins:
// ---------------------------------------------------------------------
// riemann.math.okstate.edu
// - 139.78.1.15  6889, jds@math.okstate.edu
// amber.ecst.csuchico.edu
// - 132.241.1.43 6889, warlock@ecst.csuchico.edu
// nova.tat.physik.uni-nuebingen.de
// - 134.2.62.161 6889, gamesmgr@taurus.tat.physik.uni-tuebingen.de
// actlab.rtf.utexas.edu

#define LOG_DIR "/log"
#define THIS_MUD MUD_NAME
#define DAEMON_IP   "128.83.194.11"	/* actlab.rtf.utexas.edu */
#define PASSWORD "bing.le"

string  version()
{
    return VERSION;
}

int     getoid( object u )
{
    int     x;

    if( !objectp( u ) )
	return 0;
    sscanf( file_name( u ), "%*s#%d", x );
    return x;
}

// undefine this if you don't want logging of errors
#define LOG_INFO
// only has an effect if LOG_INFO is defined
#undef LOG_CALL_OUTS

// change QUERY_NAME and QUERY_LOGIN_TIME to mesh with your mudlib

#ifdef BASIS			/* for Basis-derived mudlibs */
#define QUERY_NAME query(a_cap_name)
#define QUERY_LOGIN_TIME query(a_create_time)
#else
#define QUERY_NAME query_cap_name()
#define QUERY_LOGIN_TIME query_last_log_on()
#endif

// these values should be okay as long as you are talking to the Portals daemon
#define REFRESH_INTERVAL 390
#define KEEPALIVE_INTERVAL 120
#define PARTITIONS 10

// you shouldn't need to change anything below this comment

#define TAB "\t"
#define GENERATION "0"
#define	UDP_PORT	6888
#define CLIENT_VERSION "mwp 1.2"

static string mwhod_addr;
static string mudname;
static string keepalive_message;
static string boot_message;
static string comments;
static int socket;

void
        log_info( string error )
{

#ifdef LOG_INFO
    log_file( "cmwhod", ctime( time() ) + "\n" + error );
#endif
}

static void
        send_data( string datagram )
{
    int     rc;

    rc = socket_write( socket, datagram, mwhod_addr );
    if( rc != EESUCCESS )
    {
	log_info( "socket_write: " + socket_error( rc ) + "\n" );
    }
}

static string
        header( string op )
{
    return op + TAB + mudname + TAB + PASSWORD;
}

static void
        set_keepalive_message()
{
    /* uptime() is an efun that returns # of seconds the driver has been up */
    keepalive_message = header( "M" ) + TAB + mudname + TAB +
	(time() - uptime()) + TAB + GENERATION + TAB + comments;
}

static void
        set_boot_message()
{
    boot_message = header( "U" ) + TAB + mudname + TAB +
	(time() - uptime()) + TAB + GENERATION + TAB + comments;
}

static void
        set_comments()
{
    comments = version() + "/" + CLIENT_VERSION;
}

void
        add_user( object user, int which )
{
    string  name, datagram;
    int     login_time, theId;
    string  userid;

    if( !user )
    {
	return;
    }
    userid = (theId = getoid( user )) + "@" + MUD_NAME;
    /* refresh approx. 1/PARTITIONS of list each time */
    if( (theId % PARTITIONS) != which )
    {
	return;
    }
    login_time = (int)user->QUERY_LOGIN_TIME;
    name = (string)user->QUERY_NAME;
    datagram =
	header( "A" ) + TAB + mudname + TAB + userid + TAB + login_time + TAB + GENERATION
	+ TAB + name;
    send_data( datagram );
}

void
        add_all_users( int which )
{
    object *all;
    int     j;

    all = users();
    for( j = 0; j < sizeof( all ); j++ )
    {
	add_user( all[ j ], which );
    }
}

void
        refresh( int which )
{
    string  err;

#ifdef LOG_CALL_OUTS
    log_info( "call_out: refresh " + which + "\n" );
#endif

    // do the catch() so the call_out won't be lost in case of runtime error.
    err = catch( add_all_users( which ) );
    if( err )
    {
	log_info( "refresh: " + err + "\n" );
    }
    call_out( "refresh", REFRESH_INTERVAL / PARTITIONS,
	      (which + 1) % PARTITIONS );
}

/*
 * Initialize CMWHOD
 */
void
        create()
{
    int     error;

    rm( LOG_DIR + "/cmwhod" );
    log_info( CLIENT_VERSION + ": cmwhod log for '" + THIS_MUD + "'\n" );
    socket = socket_create( DATAGRAM, "read", "close" );
    if( socket < 0 )
    {
	log_info( "socket_create: " + socket_error( socket ) + "\n" );
	return;
    }
    error = socket_bind( socket, 0 );
    if( error != EESUCCESS )
    {
	log_info( "socket_bind: " + socket_error( error ) + "\n" );
	return;
    }
    set_comments();
    mwhod_addr = DAEMON_IP + " " + UDP_PORT;
    mudname = capitalize( THIS_MUD );
    set_keepalive_message();
    set_boot_message();
    call_out( "keepalive", KEEPALIVE_INTERVAL );
    call_out( "refresh", REFRESH_INTERVAL / PARTITIONS, 0 );
    boot();
}

void
        keepalive()
{

#ifdef LOG_CALL_OUTS
    log_info( "call_out: keepalive:\n" + keepalive_message + "\n" );
#endif

    /* shouldn't be able to get a runtime error here */
    send_data( keepalive_message );
    call_out( "keepalive", KEEPALIVE_INTERVAL );
}

void
        boot()
{
    log_info( "booting" );
    send_data( boot_message );
}

void
        halt()
{
    log_info( "halting" );
    send_data( header( "D" ) );
}

void
        remove_user( object user )
{
    string  datagram;
    string  userid;

    userid = getoid( user ) + "@" + MUD_NAME;
    datagram = header( "Z" ) + TAB + mudname + TAB + userid;
    send_data( datagram );
}