#include <kernel/user.h>
#include <kernel/kernel.h>
#include <phantasmal/log.h>
#include <phantasmal/lpc_names.h>
#include <phantasmal/telnet.h>
#include <phantasmal/mudclient.h>
inherit COMMON_AUTO;
private int suspended, shutdown;
private mapping telopt_handler;
int support_protocol;
mapping protocol_names;
void upgraded(varargs int clone);
string autodetect_client_str(void);
static void create(varargs int clone) {
if(clone) {
error("Can't clone MudClientD!");
}
upgraded();
}
void upgraded(varargs int clone) {
object handler;
if(!SYSTEM())
return;
/* The default user object isn't a System program any more, so
any Common or System things that it'll need compiled should
be compiled for it here. Ditto for PHANTASMAL_USER. */
if(!find_object(US_SCROLL_TEXT)) compile_object(US_SCROLL_TEXT);
if(!find_object(MUDCLIENT_CONN)) compile_object(MUDCLIENT_CONN);
support_protocol = 0;
protocol_names = ([
"MCP" : PROTOCOL_MCP,
"IMP" : PROTOCOL_IMP,
"FIRECLIENT" : PROTOCOL_IMP,
"PUEBLO" : PROTOCOL_PUEBLO,
"MXP" : PROTOCOL_MXP,
"MSP" : PROTOCOL_MSP,
"ZMP" : PROTOCOL_ZMP,
"ZENITH" : PROTOCOL_ZMP,
"MCCP" : PROTOCOL_MCCP,
]);
if(!find_object(TELOPT_DEFAULT_HANDLER))
compile_object(TELOPT_DEFAULT_HANDLER);
handler = find_object(TELOPT_DEFAULT_HANDLER);
telopt_handler = ([
TELOPT_ECHO : handler,
TELOPT_SGA : handler,
TELOPT_TM : handler,
TELOPT_LINEMODE : handler,
]);
}
void suspend_input(int shutdownp) {
if(!SYSTEM() && !KERNEL())
return;
if(suspended)
LOGD->write_syslog("Suspended again without release!", LOG_ERR);
suspended = 1;
if(shutdownp)
shutdown = 1;
}
void release_input(void) {
if(!SYSTEM() && !KERNEL())
return;
if(!suspended)
LOGD->write_syslog("Released without suspend!", LOG_ERR);
suspended = 0;
}
object select(string str)
{
object game_driver, conn;
if(!SYSTEM() && !KERNEL())
return nil;
game_driver = CONFIGD->get_game_driver();
conn = clone_object(MUDCLIENT_CONN);
conn->receive_message(str);
return conn;
}
int query_timeout(object connection)
{
if(!SYSTEM() && !KERNEL())
return -1;
if(suspended || shutdown)
return -1;
connection->set_mode(MODE_RAW);
return DEFAULT_TIMEOUT;
}
string query_banner(object connection)
{
object game_driver;
string send_back, telnet_options;
if(!SYSTEM() && !KERNEL())
return nil;
game_driver = CONFIGD->get_game_driver();
if(!game_driver) {
if(shutdown)
return "MUD is shutting down... Try again later.\n\r";
if(suspended)
return "MUD is suspended. Try again in a minute or two.\n\r";
return "Phantasmal (no gamedriver)\n\r\n\rLogin: ";
}
telnet_options = "";
if(shutdown)
send_back = game_driver->get_shutdown_message(connection);
else if(suspended)
send_back = game_driver->get_suspended_message(connection);
else {
string proto_options;
/* Okay, so if all of that doesn't happen... Then we should
probably negotiate a proper telnet connection, not just send a
message telling them to bugger off and then close the connection.
It's a shame, really. I *like* closing the connection on them.
*/
send_back = game_driver->get_welcome_message(connection);
if(!send_back)
error("(nil) welcome message on Mudclient port!");
send_back = autodetect_client_str() + send_back;
/* Start with IAC WONT TELOPT_ECHO, IAC DO TELOPT_LINEMODE */
telnet_options = " ";
telnet_options[0] = TP_IAC;
telnet_options[1] = TP_WONT;
telnet_options[2] = TELOPT_ECHO;
telnet_options[3] = TP_IAC;
telnet_options[4] = TP_DO;
telnet_options[5] = TELOPT_LINEMODE;
proto_options = " ";
proto_options[0] = TP_IAC;
proto_options[1] = TP_WILL;
if(support_protocol & PROTOCOL_MXP) {
proto_options[2] = TELOPT_MXP;
telnet_options = telnet_options + proto_options;
}
if(support_protocol & PROTOCOL_MSP) {
proto_options[2] = TELOPT_MSP;
telnet_options = telnet_options + proto_options;
}
if(support_protocol & PROTOCOL_ZMP) {
proto_options[2] = TELOPT_ZMP;
telnet_options = telnet_options + proto_options;
}
}
send_back = implode(explode(send_back, "\r"), "");
send_back = implode(explode(send_back, "\n"), "\n\r");
return telnet_options + send_back;
}
void protocol_allow(string protocol, int should_attempt) {
int pnum;
protocol = STRINGD->to_upper(protocol);
if(protocol_names[protocol]) {
pnum = protocol_names[protocol];
} else {
error("Unrecognized protocol " + protocol + " requested in MUDCLIENTD!");
}
if(should_attempt)
support_protocol |= pnum;
else
support_protocol &= ~pnum;
}
string autodetect_client_str(void) {
string ret;
ret = "";
if(support_protocol & PROTOCOL_IMP)
ret += "Autodetecting IMP...v1.30\n\r";
if(support_protocol & PROTOCOL_MCP)
ret += "#$#mcp version: 2.1 to: 2.1\n\r";
if(support_protocol & PROTOCOL_PUEBLO)
ret += "This world is Pueblo 2.50 enhanced.\n\r";
return ret;
}
void set_telopt_handler(int option_num, object handler) {
if(SYSTEM() || COMMON() || GAME()) {
if(option_num == TELOPT_SGA || option_num == TELOPT_ECHO
|| option_num == TELOPT_TM || option_num == TELOPT_LINEMODE) {
LOGD->write_syslog("Setting uncommon handler for standard telnet"
+ "option!", LOG_WARN);
}
telopt_handler[option_num] = handler;
} else {
error("Non-privileged code attempted to call "
+ "MUDCLIENTD::set_telopt_handler!");
}
}
object get_telopt_handler(int option_num) {
return telopt_handler[option_num];
}