#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]; }