diff --git a/CHANGESTODO b/CHANGESTODO index b58d1d5..a3ff028 100644 --- a/CHANGESTODO +++ b/CHANGESTODO @@ -1779,6 +1779,10 @@ see also: http://about.psyc.eu/SPAM evtl nicht alle im richtigen channel, um den enter zu sehen..) == IRC ISSUES 1.0 ====================================================== +- according to rfc and ircd source IRC parser should accept when the last + argument is just a word instead of a phrase prefixed by : + this is unusual, but legal: "PRIVMSG #blah hello" + + some irc clients do not implement their own pinging, and some NATs really kill your irc session if it is too quiet too long. we need optional server side pings diff --git a/world/net/irc/common.c b/world/net/irc/common.c index 7b5aa8c..061b705 100644 --- a/world/net/irc/common.c +++ b/world/net/irc/common.c @@ -44,6 +44,11 @@ parse(a) { if (a == "") return; // don't let " \n" execute "/s" unless (sscanf(a, ":%s %s", from, t)) t = a; sscanf(t, "%s :%s", t, text); + // when 'text' is not present, the last argument could be a single + // word text according to rfc. this has never seemed to hurt, but + // we are not exactly compliant in that sense. we could copy the + // last arg over into text, but that requires to change the api + // into explode()-based. WONTFIX unless (sscanf(t, "%s %s", cmd, args)) cmd = t; if (cmd) ircMsg(from, lower_case(cmd), args, text, a); return 1; diff --git a/world/net/person.c b/world/net/person.c index 475c091..74b9397 100644 --- a/world/net/person.c +++ b/world/net/person.c @@ -476,10 +476,15 @@ qLocation(string service) { return v("locations")[service]; } -// returns 0 if that was just an update -// 1 on success +// returns 0 if that was just an update. 1 on success. +// this was originally used by sip/udp only, then slowly +// integrated into existing code sLocation(string service, mixed data) { ASSERT("sLocation", v("locations"), v("locations")) + // should this function also call register_location ? + // yes because a delivery error should remove clients + // from the location table, too.. not just proper + // unlink requests FIXME if (v("locations")[service] == data) return 0; unless (data) { string retval = v("locations")[service]; @@ -526,7 +531,8 @@ static linkSet(service, location, source) { } #endif #ifdef NEW_UNLINK -static linkDel(service, source) { +static linkDel(service, source, variant) { + string mc = "_notice_unlink"; string candidate = v("locations")[service]; unless (candidate) { P3(("linkDel(%O, %O) called in %O: no such candidate!\n", @@ -536,19 +542,42 @@ static linkDel(service, source) { P1(("linkDel(%O, %O) called in %O: unlinking %O.\n", service, source, ME, candidate)); unless (source) source = candidate; + // sLocation? register_location(candidate, 0); + // maybe actual deletion would need to be delayed after + // letting locations know. they might still be sending + // stuff to us, right? m_delete(v("locations"), service || 0); - if (service) sendmsg(source, "_notice_unlink_service", 0, + if (variant) mc += variant; + if (service) sendmsg(source, mc, 0, ([ "_service" : service, "_location_service" : candidate, "_identification" : v("_source") ])); - else sendmsg(source, "_notice_unlink", 0, + else sendmsg(source, mc, 0, ([ "_location" : candidate, "_identification" : v("_source") ])); return candidate; } #endif +static linkCleanUp(variant) { + mixed type, loc; + + foreach (type, loc : v("locations")) { + P2(("linkCleanUp(%O) to %O's ex-%O-client %O\n", + variant, ME, type, loc)) +#ifdef NEW_UNLINK + linkDel(type, 0, variant); +#else + // no clue if the UNL is still out there.. + // lets send a ping so it can reconnect + // but first we have to delete it from our structures! + m_delete(v("locations"), 0); + sendmsg(loc, "_status_unlinked", 0, ([])); +#endif + } +} + // extend sName() from name.c sName2(a) { int e; @@ -615,7 +644,9 @@ sName2(a) { availability = v("availability"); #endif // _flag_disable_module_presence - unless (v("locations")) vSet("locations", ([ ])); + if (v("locations")) linkCleanUp("_crash"); + else vSet("locations", ([ ])); + // protection against file read errors if (IS_NEWBIE) { if (boss(a)) { @@ -630,7 +661,7 @@ sName2(a) { destruct(ME); return 0; } -#ifndef RELAY +#ifdef _flag_enable_administrator_by_nick else if (strstr(lower_case(a), "admin") != -1) { this_player()->w("_failure_object_create_admin", "This nickname is available to administrators only."); @@ -647,20 +678,6 @@ sName2(a) { // maybe use v("identification") here? vSet("_source", psyc_name(ME)); - - // TODO: needs to be foreached for all types of locations? - if (e = v("locations")[0]) { -#ifdef NEW_UNLINK - linkDel(0); -#else - P2(("sending _status_unlinked to ex-client %O\n", e)) - // no clue if the UNL is still out there.. - // lets send a ping so it can reconnect - // but first we have to delete it from our structures! - m_delete(v("locations"), 0); - sendmsg(e, "_status_unlinked", 0, ([])); -#endif - } return MYNICK; // means new name accepted } @@ -2640,9 +2657,12 @@ quit(immediate, variant) { int rc; P3(("person:QUIT(%O,%O) in %O\n", immediate,variant, ME)) -#ifdef NEW_UNLINK - linkDel(0); -#endif + // keeping services running while logging out should be possible.. but + //linkDel(0); + if (v("locations")) { + linkCleanUp(); + vDel("locations"); + } if (immediate == 1 || (immediate && find_call_out(#'quit) != -1)) { rc = save(); if (sizeof(places)) { diff --git a/world/net/psyc/user.c b/world/net/psyc/user.c index 6ff48dc..e0b3005 100644 --- a/world/net/psyc/user.c +++ b/world/net/psyc/user.c @@ -10,7 +10,7 @@ qHasCurrentPlace() { return 0; } logon() { #ifdef NO_EXTERNAL_LOGINS - return destruct(ME); + return destruct(ME); #endif // psyc users dont have their own socket, so the driver // does not call disconnected() for them - this enables the diff --git a/world/net/user.c b/world/net/user.c index e95d7fb..cfcbcb7 100644 --- a/world/net/user.c +++ b/world/net/user.c @@ -896,19 +896,27 @@ case "_status_presence": case "_notice_person_absent_netburp": if (vars["_context"] != place) return 1; break; -#if 1 case "_failure_unsuccessful_delivery": case "_failure_network_connect_invalid_port": // is this the right place to do this? i have seen a recursion where // person.c was never asked for opinion, so i'm putting this into user.c +#ifdef ALPHA + string loc; + foreach (t, loc : v("locations")) + if (vars["_source_relay"] == loc) { + P1(("%O in %O talking to its %O location at %O.", + mc, ME, t, loc)) + sLocation(t, 0); + } +#else // TODO: walk thru entire locations mapping! if (vars["_source_relay"] == v("locations")[0]) { - P0(("%O got %O, deleting 0 from %O\n", ME, - mc, v("locations"))) - m_delete(v("locations"), 0); + P0(("%O got %O, deleting 0 from %O\n", ME, + mc, v("locations"))) + m_delete(v("locations"), 0); } - // fall thru - not strictly necessary but adds a feature #endif + // fall thru - not strictly necessary but adds a feature case "_failure_redirect_permanent": // we currently have no implementation for permanent changes case "_failure_redirect_temporary": @@ -1271,7 +1279,8 @@ w(string mc, string data, mapping vars, mixed source, int showingLog) { if (!loc) { // oh.. happens on beta? P1(("%O late deletion of a %O zero location - should never happen\n", ME, type)) - m_delete(v("locations"), type); + //m_delete(v("locations"), type); + sLocation(type, 0); continue; } #endif