// $Id: slave.c,v 1.64 2008/03/28 20:05:44 lynx Exp $ // vim:syntax=lpc // #define TIME_UPDATE_MINWAIT 33 // 33 seconds #include #include virtual inherit NET_PATH "place/storic"; protected volatile string master, mastertrail; protected volatile int members, servers; private volatile int lastup; histClear(a, b, source, vars) { if (b > 49) return ::histClear(a, b, source, vars); } // the flag allows forced update and avoids call_out loops #define UPDATE_NOW 0 #define UPDATE_SOON 1 #define UPDATE_REMINDER 2 qJunction() { return 0; } update(flag) { int t; unless(master) return; t = time() - lastup; P2(("update(%O) - %O to go.\n", flag, TIME_UPDATE_MINWAIT - t)) if (flag == UPDATE_NOW || t > TIME_UPDATE_MINWAIT) { lastup = time(); sendmsg(master, "_request_link", 0, ([ "_amount_members": to_string(size()) ]) ); } else if (flag == UPDATE_SOON) call_out(#'update, TIME_UPDATE_MINWAIT+1-t, UPDATE_REMINDER); } void create() { lastup = time(); // delay linkup by 7 seconds (see below) ::create(); } #if 0 void reset(int again) { if (again) update(UPDATE_SOON); // just in case.. else lastup = time(); // delay linkup by 7 seconds (see below) return ::reset(again); } #endif sIdentification(it) { identification = it; } sMaster(link, modflag) { unless (abbrev("psyc:", link)) link = "psyc://"+ link +"/"+ psycName(); mastertrail = master = lower_case(link); // lower_case UNI policy identification = link; set_context(ME, link); // some kinda kludge until the psyc layer gives us the true UNI // if (abbrev("psyc://ve.", master)) mastertrail = master[10..]; // P2(("mastertrail = %O\n", mastertrail)) //call_out(#'update, 7, UPDATE_NOW); update(UPDATE_NOW); } mixed isValidRelay(mixed x) { return x == master || x == ME; } msg(source, mc, data, vars) { P2(("slave:msg(%O, %O, %O, %O)\n", source, mc, data, vars)) // if (vars["_context"]) return -1; // may not happen // status update from master / identification if (master && source == master || identification && source == identification) { /* a message from our master / identification to us * usually a status update or some other kind of control msg * this control msg logic has moved around, but hasn't changed */ switch(mc) { case "_notice_place_topic": vSet("topic-user", vars["_nick"]); // fall thru case "_notice_place_topic_official": vSet("topic", vars["_topic"]); break; case "_notice_place_topic_removed": vSet("topic-user", vars["_nick"]); break; case "_notice_link_topic": vSet("topic", vars["_topic"]); // fall thru case "_notice_link": if (vars["_filter_presence"] && to_int(vars["_filter_presence"]) != 0) vSet("_filter_presence", source); else vDel("_filter_presence"); //m_delete(vars, "_filter_presence"); break; case "_notice_place_topic_removed_official": vDel("topic"); break; case "_error_necessary_link_place": case "_error_rejected_message_membership": // add protection from loops? castmsg(ME, "_warning_place_link_lost", "Master link [_master] has forgotten about us. Hold on.", ([ "_master" : master ]) ); // fall thru case "_notice_unlink_restart": case "_notice_unlink_restart_complete": // update (UPDATE_NOW); update (UPDATE_SOON); return 1; case "_notice_place_history_cleared": ::histClear(vars["_amount_messages"], 60, source, vars); return 1; case "_status_place_filter_presence": if (vars["_filter_presence"] && to_int(vars["_filter_presence"]) != 0) vSet("_filter_presence", source); else vDel("_filter_presence"); return 1; } if (abbrev("_notice_place_enter", mc)) { // master notifies us that _source_relay was allowed // to enter - kind of fake string relay = vars["_source_relay"]; m_delete(vars, "_source_relay"); vars["_nick_place"] = MYNICK; return ::msg(relay, mc, data, vars); } if (abbrev("_notice_place_leave", mc)) { string relay = vars["_source_relay"]; m_delete(vars, "_source_relay"); vars["_nick_place"] = MYNICK; return ::msg(relay, mc, data, vars); } return castmsg(source, mc, data, vars); } // someone is sending a message via us. // we may send it to the master and if we dont return will pass // it on to local msg() // TODO: need to do some kind of checks if we want to forward // sth for the sender if ((!vars["_context"] // should not happen, but... // things not to forward && !(abbrev("_request_leave", mc) || abbrev("_request_context_leave", mc)) // things we want to forward ||abbrev("_message", mc) || !v("_filter_presence") && (abbrev("_request_enter", mc) || abbrev("_request_context_enter", mc)) ) ) { // source != master implied above // we let upstream handle it // TODO: we _must_ be linked to do this // looks like a job for the notorious queue // // otherwise a slave may send an _request_enter to // the master which is silent and should therefore // drop the packet. // and the user is left alone // the master could catch such behaviour... but... // complicates things and is more harmful than useful // // hrmpf. IMHO we should send it via master, if // this does not work then debug it! // hey, its lynX who told me to do that :) #if 0 sendmsg(master, mc, data, vars + ([ "_location": query_ip_name(source), "_source_relay": ME, ]), source); #else sendmsg(identification, mc, data, vars + ([ // what about peer scheme, host and -port // ah, did just that in usercmd sayvars "_location": objectp(source) ? query_ip_name(source) : source, "_source_relay": vars["_source_relay"] || source ])); #endif // if (abbrev("_message", mc)) return 1; return 1; #if 0 // wo war der Sinn von dem Code? D3(else D(S("slave:msg from %O master %O, mastertrail %O\n", source, master, mastertrail));) if (source == master || (vars["_source"] == master && stringp(source) && trail(mastertrail, source))) { string relay = vars["_source_relay"]; // if this were psyc 1.1, we wouldnt receive messages // relayed, but have proper _context. i guess we want // to implement both forms and maybe one day disallow // one or the other on a per-room basis. if (relay) { // dieser teil war auskommentiert.. // was will mir das sagen? ich werde bugs auslösen? // jopp // vars["_source_relay"] = master; // master could spoof local objects // source = psyc_object(relay) || relay; // geht das? hu? vars["_source_relay"] = vars["_source"]; P2(("slave:msg(%O,%O,%O) relay=%O\n", source, mc, data, relay)) } } #endif } // hm... can we simply do that? return ::msg(source, mc, data, vars); } castmsg(source, mc, data, vars) { P2(("slave:castmsg(%O, %O, %O, %O)\n", source, mc, data, vars)) if (member(vars, "_amount_members")) { members = to_int(vars["_amount_members"]); m_delete(vars, "_amount_members"); } if (member(vars, "_amount_servers")) { servers = to_int(vars["_amount_servers"]); m_delete(vars, "_amount_servers"); } ::castmsg(source, mc, data, vars); } enter(source,mc,data,vars) { update (UPDATE_SOON); return ::enter(source,mc,data,vars); } leave(source,mc,data,vars) { update (UPDATE_SOON); return ::leave(source,mc,data,vars); } memberInfo(person) { unless (members && servers) return ::memberInfo(person); unless (person) person = previous_object(); sendmsg(person, "_status_place_net_members_amount", "[_nick_place] contains [_amount_members] people \ on [_amount_servers] servers.", ([ "_nick_place": MYNICK, "_amount_members": members, "_amount_servers": servers, ]) ); return 0; } showStatus(verbosity, al, source, mc, data, vars) { if (members && master) { sendmsg(source, "_status_place_link", "Network link to [_link] active.", ([ "_link": master ]) ); } return ::showStatus(verbosity, al, source, mc, data, vars); } qAllowExternal(source, mc) { if (source == master) return 1; } reboot(reason, restart, pass) { if (master) { sendmsg(master, "_request_unlink"); master = 0; } return ::reboot(reason, restart, pass); }