/**
* An intermud (3) handler; Galileo, 12-05-98
* Changed to work on Skylib; Shaydz; 2000
* @changed Cleaned up a little, moved some of the includes
* to here and added some documentation.
* - Sandoz, June 2003.
*/
#define SAVE_FILE "/secure/save/handlers/intermud"
/*
* #define ROUTERS ({ ({"*gjs", "198.144.203.194 9000"}) })
*/
#define ROUTERS ({ ({"*i4", "204.209.44.3 8080"}) })
inherit "/secure/std/modules/tcp_client";
#include <network.h>
#include <intermud.h>
class list {
int id;
mapping list;
} /* class list */
class intermud {
int passwd, configured;
class list channel_list, mud_list;
string connected;
mixed routers;
} /* class intermud */
class admin_channel {
int type;
string *members;
} /* admin_channel() */
nosave int shutdown, call_id;
nosave string *skylibs = ({ });
string *listen_channels = ({ });
mapping admin_channels = ([ ]);
class intermud config;
private void save_me();
mixed *packet_allocate(string);
private void create() {
string host;
int port;
config = new( class intermud,
mud_list : new( class list, list : ([ ]) ),
channel_list : new( class list, list : ([ ]) ) );
tcp_client::mudlib_setup();
config->routers = ROUTERS;
sscanf( config->routers[0][1], "%s %d", host, port );
listen_channels = DEFAULT_CHANNELS;
unguarded( (: restore_object, SAVE_FILE, 1 :) );
config->connected = NULL;
config->configured = NULL;
open_socket( host, port, MUD );
} /* create() */
private void save_me() {
call_id = 0;
unguarded( (: save_object, SAVE_FILE :) );
} /* save_me() */
/** @ignore yes */
void dest_me() {
tcp_client::dest_me();
} /* dest_me() */
/**
* This method queries whether the specified mud exists or not.
* @param mud the mud to check
* @return the name of the mud if it exists, or 0 if not
*/
string mud_exists( string mud ) {
string *muds;
muds = keys( config->mud_list->list );
mud = lower_case(mud);
for( int i = 0; i < sizeof(muds); i++ )
if( lower_case( muds[i] ) == mud )
return muds[i];
return 0;
} /* mud_exists() */
/**
* This method allocates a packet of the specified type.
* @param type the type of the packet to allocate
* @return the newly allocated packet
*/
mixed *packet_allocate( string type ) {
mixed *packet;
if( !undefinedp( PACKET_SIZES[type] ) ) {
packet = allocate( S_P + PACKET_SIZES[type] );
} else {
log_file("INTERMUD_H", "%s: Invalid packet allocation - %s",
ctime(time()), type );
return 0;
}
packet[P_TYPE] = type;
packet[P_TTL] = 5;
packet[P_SOURCE] = MUD_NAME;
return packet;
} /* allocate_packet() */
/** @ignore yes */
private void packet_invalid( mixed *packet ) {
log_file("INTERMUD_H", "%s: Invalid packet\n%O\n",
ctime(time()), packet );
} /* packet_invalid() */
#include "intermud/channel.h"
#include "intermud/emoteto.h"
#include "intermud/error.h"
#include "intermud/finger.h"
#include "intermud/locate.h"
#include "intermud/startup.h"
#include "intermud/tell.h"
#include "intermud/who.h"
private int find_string( string str, string find ) {
return strsrch( lower_case(str), find, 1 ) != -1;
} /* find_string() */
// Update our mudlist information
private void mudlist_reply( mixed *packet ) {
mapping mudlist;
string *tmp;
if( sizeof(packet) != ( S_P + SIZEOF_MUDLIST ) ) {
packet_invalid(packet);
return;
}
if( packet[ S_P + MUDLIST_ID ] == config->mud_list->id )
return;
// Find any muds using a version of the Skylib mudlib.
skylibs |= keys( filter( packet[S_P + MUDLIST_INFO], (: sizeof($2) ?
find_string( $2[MUDLIST_INFO_MUDLIB], "skylib") : 0 :) ) );
// Find any muds using a version of Skylib as the base mudlib.
skylibs |= keys( filter( packet[S_P + MUDLIST_INFO], (: sizeof($2) ?
find_string( $2[MUDLIST_INFO_BMUDLIB], "skylib") : 0 :) ) );
// Only cache active muds, it gets out of hands otherwise.
mudlist = filter( packet[S_P + MUDLIST_INFO], (: sizeof($2) ?
$2[MUDLIST_INFO_STATE] == -1 : 0 :) );
config->mud_list->list += mudlist;
// Remove muds that are going down, if they're in our list.
tmp = keys( filter( packet[S_P + MUDLIST_INFO], (: sizeof($2) ?
$2[MUDLIST_INFO_STATE] >= 0 : 0 :) ) );
config->mud_list->list = filter( config->mud_list->list,
(: member_array( $1, $3 ) == -1 :), tmp );
skylibs -= tmp;
if( config->configured && mud_name() == "Divided Sky")
administrate_channel("skylib", skylibs, 0 );
save_me();
} /* mudlist_reply() */
/**
* This method is used by the mudlist command.
* @param mud the mud to get info on
* @param flags the flags
* @return a string describing our progress
*/
string mudlist( string mud, mapping flags ) {
string *muds, *f_keys, f_val;
int index;
if( strlen(mud) ) {
if( mud = mud_exists(mud) ) {
return sprintf("Name: %s, %s\n"
"IP: %s %d\nTCP: %d\n"
"UDP: %d\nMudLib: %s\n"
"BaseLib: %s\nDriver: %s\n"
"Status: %s\nAdmin: %s\n"
"Services: %s\n", mud,
config->mud_list->list[mud][MUDLIST_INFO_MUDTYPE],
config->mud_list->list[mud][MUDLIST_INFO_IPADDR],
config->mud_list->list[mud][MUDLIST_INFO_PPORT],
config->mud_list->list[mud][MUDLIST_INFO_TCPPORT],
config->mud_list->list[mud][MUDLIST_INFO_UDPPORT],
config->mud_list->list[mud][MUDLIST_INFO_MUDLIB],
config->mud_list->list[mud][MUDLIST_INFO_BMUDLIB],
config->mud_list->list[mud][MUDLIST_INFO_DRIVER],
config->mud_list->list[mud][MUDLIST_INFO_STATUS],
config->mud_list->list[mud][MUDLIST_INFO_EMAIL],
implode( keys( config->mud_list->list[mud]
[MUDLIST_INFO_SERVICES] ), ", ") );
} else {
return "No mud is registered with that name.\n";
}
}
muds = keys( config->mud_list->list );
f_keys = keys(flags);
for( int i = 0; i < sizeof(f_keys); i++ ) {
if( !sizeof(muds) )
break;
if( f_keys[i] == "S") {
for( int j = 0; j < sizeof( flags[ f_keys[ i ] ] ); j++ ) {
switch( flags[ f_keys[ i ] ][ j ] ) {
default : f_val = NULL;
case "a": f_val = "auth"; break;
case "A": f_val = "amcp"; break;
case "c": f_val = "channel"; break;
case "e": f_val = "emoteto"; break;
case "f": f_val = "finger"; break;
case "F": f_val = "file"; break;
case "h": f_val = "http"; break;
case "l": f_val = "locate"; break;
case "m": f_val = "mail"; break;
case "n": f_val = "news"; break;
case "N": f_val = "nntp"; break;
case "P": f_val = "ftp"; break;
case "r": f_val = "rcp"; break;
case "s": f_val = "smtp"; break;
case "t": f_val = "tell"; break;
case "u": f_val = "ucache"; break;
case "w": f_val = "who"; break;
}
if( f_val )
muds = filter( muds, (: config->mud_list->list[$1]
[MUDLIST_INFO_SERVICES][$(f_val)] :) );
}
continue;
} else {
f_val = flags[f_keys[i]];
}
if( f_keys[i] == "n") {
muds = filter( muds, (: regexp( lower_case($1),
lower_case( $(f_val) ) ) :) );
continue;
}
switch( f_keys[i] ) {
default : index = -1; break;
case "d": index = MUDLIST_INFO_DRIVER; break;
case "i": index = MUDLIST_INFO_IPADDR; break;
case "m": index = MUDLIST_INFO_MUDLIB; break;
case "t": index = MUDLIST_INFO_MUDTYPE; break;
case "s": index = MUDLIST_INFO_STATUS; break;
}
if( index != -1 )
muds = filter( muds, (: regexp( lower_case(
config->mud_list->list[$1][$(index)] ),
lower_case( $(f_val) ) ) :) );
}
if( sizeof(muds) )
return create_table( ({"Intermuds", "mud"}), muds, 1 );
else
return "No muds match your request.\n";
} /* mudlist() */
protected void client_close_callback( int fd ) {
config->connected = NULL;
tcp_client::client_close_callback(fd);
} /* client_close_callback() */
protected void client_write_callback( int fd ) {
if( !config->connected )
startup_req();
tcp_client::client_write_callback(fd);
} /* client_write_callback() */
protected void client_read_callback( int fd, mixed *packet ) {
tcp_client::client_read_callback( fd, packet );
if( !packet )
return;
switch (packet[P_TYPE]) {
default: packet_invalid(packet); return;
case CHANNEL_E_PACKET: channel_e(packet); return;
case CHANNEL_M_PACKET: channel_m(packet); return;
case CHANNEL_T_PACKET: channel_t(packet); return;
case CHANLIST_REPLY_PACKET: chanlist_reply(packet); return;
case CHAN_WHO_REPLY_PACKET: chan_who_reply(packet); return;
case CHAN_WHO_REQ_PACKET: chan_who_request(packet); return;
case EMOTETO_PACKET: emoteto_reply(packet); return;
case ERROR_PACKET: packet_error(packet); return;
case FINGER_REPLY_PACKET: finger_reply(packet); return;
case FINGER_REQ_PACKET: finger_request(packet); return;
case LOCATE_REPLY_PACKET: locate_reply(packet); return;
case LOCATE_REQ_PACKET: locate_request(packet); return;
case MUDLIST_PACKET: mudlist_reply(packet); return;
case STARTUP_REPLY_PACKET: startup_reply(packet); return;
case TELL_PACKET: tell_reply(packet); return;
case WHO_REPLY_PACKET: who_reply(packet); return;
case WHO_REQ_PACKET: who_request(packet); return;
}
} /* client_read_callback() */
/**
* This method initiates intermud shutdown.
* It disconnects all channels etc.
*/
int shutdown() {
mixed *packet;
packet = packet_allocate(SHUTDOWN_PACKET);
if( shutdown )
return 0; // Already in progress
packet[P_DESTINATION] = config->routers[0][0];
packet[S_P + SHUTDOWN_DELAY] = 180;
map( available_channels(), (: listen_channel( $1, 0 ) :) );
add_buffer( 0, packet );
send_buffer( 0 );
call_out("dest_me", 60 );
shutdown = 1;
return 1;
} /* shutdown() */