// $Id: component.c,v 1.72 2008/10/01 10:59:24 lynx Exp $ // vim:syntax=lpc // // this implements a passive listener component #define NO_INHERIT #include "jabber.h" #undef NO_INHERIT #include inherit NET_PATH "xml/common"; inherit NET_PATH "jabber/mixin_parse"; inherit NET_PATH "jabber/mixin_render"; // in theory - or future - scheme plan will be implemented by // a gateway/imtransport which inherits this file #define SCHEME_PLAN volatile protected mapping config; volatile string streamid; volatile string componentname; volatile int authenticated; logon(arg) { #ifdef _flag_log_sockets_XMPP log_file("RAW_XMPP", "\n%O logon\t%O", ME, ctime()); #endif #ifdef INPUT_NO_TELNET input_to(#'feed, INPUT_IGNORE_BANG | INPUT_CHARMODE | INPUT_NO_TELNET); #else enable_telnet(0, ME); input_to(#'feed, INPUT_IGNORE_BANG | INPUT_CHARMODE); #endif if (this_interactive()) set_prompt(""); set_combine_charset(COMBINE_CHARSET); sTextPath(0, "en", "jabber"); } reboot(reason, restart, pass) { // close the stream according to XEP 0190 if (interactive(ME)) { flags |= TCP_PENDING_DISCONNECT; emitraw(""); } } onHandshake() { #ifdef SCHEME_PLAN register_scheme(config["_scheme"]); #else register_target(XMPP + componentname); #endif } #ifdef SCHEME_PLAN jabberMsg(XMLNode node) { mixed *su = parse_uniform(XMPP + node["@from"]); string origin = config["_scheme"] + ":"; unless(su) { P0(("%O could not find uniform source in %O\n", ME, node)) return; } if (su[UUser]) origin += su[UUser]; return ::jabberMsg(node, origin, su); } #endif #ifdef SCHEME_PLAN determine_targetjid(target, vars) { mixed *tu; unless(vars["_INTERNAL_target_jabber_bare"]) { unless(target) vars["_INTERNAL_target_jabber_bare"] = componentname; else { tu = parse_uniform(target); if (stringp(tu[UBody]) && strlen(tu[UBody])) vars["_INTERNAL_target_jabber_bare"] = tu[UBody] + "@" + componentname; else vars["_INTERNAL_target_jabber_bare"] = componentname; } } unless (vars["_INTERNAL_target_jabber"]) { vars["_INTERNAL_target_jabber"] = vars["_INTERNAL_target_jabber_bare"]; } } #endif waitfor_handshake(XMLNode node) { switch (node[Tag]) { case "handshake": if (node[Cdata] == sha1(streamid + config["_secret"])) { PT(("%O component auth succeded as %O\n", ME, componentname)) nodeHandler = #'jabberMsg; authenticated = 1; emitraw(""); onHandshake(); } else { monitor_report("_error_invalid_password", sprintf("%O tried to link to %O using a wrong password", query_ip_name(), componentname)); STREAM_ERROR("not-authorized", ""); remove_interactive(ME); } break; default: P0(("%O got %O while waiting for handshake\n", ME, node)) break; } } int msg(string source, string mc, string data, mapping vars, int showingLog, string target) { #ifdef DEFLANG unless(vars["_language"]) vars["_language"] = DEFLANG; #else unless(vars["_language"]) vars["_language"] = "en"; #endif #ifndef GAMMA // TODO: decide if this is good or bad else if (abbrev("_status_person_absent", mc)) { PT(("Intercepted absent from %O to %O\n", mc, source, ME)) return 1; } #endif switch (mc){ case "_message_echo_private": return 1; } // copied from active unless (vars["_INTERNAL_mood_jabber"]) vars["_INTERNAL_mood_jabber"] = "neutral"; determine_sourcejid(source, vars); determine_targetjid(target, vars); if (vars["_place"]) vars["_place"] = mkjid(vars["_place"]); unless (vars["_INTERNAL_target_jabber"]) return 1; return ::msg(source, mc, data, vars, showingLog, target); } disconnected(remainder) { /* unregistering scheme / target is a bad idea, as the target hostname * does not resolve (in cases where we call it 'icq'), so we're going * to enqueue until the component connects again */ authenticated = 0; return 0; // unexpected } open_stream(node) { string packet; if (node["@xmlns"] != "jabber:component:accept") { remove_interactive(ME); // disconnect } object o = find_object(CONFIG_PATH "config"); if (o) config = o->qConfig(node["@to"]); P2(("\n%O loads config %O\n", ME, config)) streamid = RANDHEXSTRING; packet = sprintf("" "