From 850cf993eb8d5e20b9b845e42e4bdae1a6cae81f Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Sun, 11 Nov 2001 18:59:19 +0000 Subject: Moved rewritten server redirection code from core to irc. This new code should be able to do the redirecting a lot more error-proof. Changed lag-checking to use PINGs instead of NOTIFYs. This breaks scripts using redirection. Hopefully this doesn't break too much things in irssi :) git-svn-id: http://svn.irssi.org/repos/irssi/trunk@1980 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/core/Makefile.am | 2 - src/core/commands.c | 5 +- src/core/server-rec.h | 5 - src/core/servers-redirect.c | 359 ------------------------ src/core/servers-redirect.h | 36 --- src/core/servers.c | 7 - src/fe-common/irc/fe-events.c | 13 +- src/irc/core/Makefile.am | 6 +- src/irc/core/channels-query.c | 63 ++--- src/irc/core/ctcp.c | 4 +- src/irc/core/irc-commands.c | 125 ++------- src/irc/core/irc-servers.c | 6 +- src/irc/core/irc-servers.h | 6 +- src/irc/core/irc.c | 37 ++- src/irc/core/lag.c | 73 +++-- src/irc/core/server-idle.c | 255 ----------------- src/irc/core/server-idle.h | 22 -- src/irc/core/servers-idle.c | 258 +++++++++++++++++ src/irc/core/servers-idle.h | 34 +++ src/irc/core/servers-redirect.c | 569 ++++++++++++++++++++++++++++++++++++++ src/irc/core/servers-redirect.h | 66 +++++ src/irc/notifylist/module.h | 4 +- src/irc/notifylist/notify-ison.c | 44 ++- src/irc/notifylist/notify-whois.c | 6 +- src/irc/notifylist/notifylist.c | 2 - src/perl/common/Server.xs | 41 --- src/perl/common/module.h | 1 - src/perl/irc/Server.xs | 38 +++ src/perl/irc/module.h | 1 + 29 files changed, 1105 insertions(+), 983 deletions(-) delete mode 100644 src/core/servers-redirect.c delete mode 100644 src/core/servers-redirect.h delete mode 100644 src/irc/core/server-idle.c delete mode 100644 src/irc/core/server-idle.h create mode 100644 src/irc/core/servers-idle.c create mode 100644 src/irc/core/servers-idle.h create mode 100644 src/irc/core/servers-redirect.c create mode 100644 src/irc/core/servers-redirect.h (limited to 'src') diff --git a/src/core/Makefile.am b/src/core/Makefile.am index feedfc59..9f5298f7 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -44,7 +44,6 @@ libcore_a_SOURCES = \ rawlog.c \ servers.c \ servers-reconnect.c \ - servers-redirect.c \ servers-setup.c \ settings.c \ signals.c \ @@ -92,7 +91,6 @@ noinst_HEADERS = \ rawlog.h \ servers.h \ servers-reconnect.h \ - servers-redirect.h \ servers-setup.h \ settings.h \ signals.h \ diff --git a/src/core/commands.c b/src/core/commands.c index daea0ea3..ad4b8bd0 100644 --- a/src/core/commands.c +++ b/src/core/commands.c @@ -26,7 +26,6 @@ #include "window-item-def.h" #include "servers.h" -#include "servers-redirect.h" #include "channels.h" #include "lib-config/iconfig.h" @@ -853,10 +852,8 @@ static void parse_command(const char *command, int expand_aliases, } cmd = g_strconcat("command ", newcmd, NULL); - if (server != NULL) - server_redirect_default(SERVER(server), cmd); - g_strdown(cmd); + oldcmd = current_command; current_command = cmd+8; if (!signal_emit(cmd, 3, args, server, item)) { diff --git a/src/core/server-rec.h b/src/core/server-rec.h index 4a75ef80..185809be 100644 --- a/src/core/server-rec.h +++ b/src/core/server-rec.h @@ -21,11 +21,6 @@ GIOChannel *connect_pipe[2]; int connect_tag; int connect_pid; -/* For deciding if event should be handled internally */ -GHashTable *eventtable; /* "event xxx" : GSList* of REDIRECT_RECs */ -GHashTable *eventgrouptable; /* event group : GSList* of REDIRECT_RECs */ -GHashTable *cmdtable; /* "command xxx" : REDIRECT_CMD_REC* */ - RAWLOG_REC *rawlog; LINEBUF_REC *buffer; /* receive buffer */ GHashTable *module_data; diff --git a/src/core/servers-redirect.c b/src/core/servers-redirect.c deleted file mode 100644 index ca340fc6..00000000 --- a/src/core/servers-redirect.c +++ /dev/null @@ -1,359 +0,0 @@ -/* - server-redirect.c : irssi - - Copyright (C) 1999-2000 Timo Sirainen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "module.h" -#include "signals.h" -#include "misc.h" - -#include "servers.h" -#include "servers-redirect.h" - -static int redirect_group; - -static void server_eventtable_destroy(char *key, GSList *value) -{ - GSList *tmp; - - g_free(key); - - for (tmp = value; tmp != NULL; tmp = tmp->next) { - REDIRECT_REC *rec = tmp->data; - - g_free_not_null(rec->arg); - g_free(rec->name); - g_free(rec); - } - g_slist_free(value); -} - -static void server_eventgrouptable_destroy(gpointer key, GSList *value) -{ - g_slist_foreach(value, (GFunc) g_free, NULL); - g_slist_free(value); -} - -static void server_cmdtable_destroy(char *key, REDIRECT_CMD_REC *value) -{ - g_free(key); - - g_slist_foreach(value->events, (GFunc) g_free, NULL); - g_slist_free(value->events); - g_free(value); -} - -static void sig_disconnected(SERVER_REC *server) -{ - g_return_if_fail(IS_SERVER(server)); - - if (server->eventtable != NULL) { - g_hash_table_foreach(server->eventtable, - (GHFunc) server_eventtable_destroy, NULL); - g_hash_table_destroy(server->eventtable); - } - - g_hash_table_foreach(server->eventgrouptable, - (GHFunc) server_eventgrouptable_destroy, NULL); - g_hash_table_destroy(server->eventgrouptable); - - if (server->cmdtable != NULL) { - g_hash_table_foreach(server->cmdtable, - (GHFunc) server_cmdtable_destroy, NULL); - g_hash_table_destroy(server->cmdtable); - } -} - -void server_redirect_initv(SERVER_REC *server, const char *command, - int last, GSList *list) -{ - REDIRECT_CMD_REC *rec; - - g_return_if_fail(IS_SERVER(server)); - g_return_if_fail(command != NULL); - g_return_if_fail(last > 0); - - if (g_hash_table_lookup(server->cmdtable, command) != NULL) { - /* already in hash table. list of events SHOULD be the same. */ - g_slist_foreach(list, (GFunc) g_free, NULL); - g_slist_free(list); - return; - } - - rec = g_new(REDIRECT_CMD_REC, 1); - rec->last = last; - rec->events = list; - g_hash_table_insert(server->cmdtable, g_strdup(command), rec); -} - -void server_redirect_init(SERVER_REC *server, const char *command, - int last, ...) -{ - va_list args; - GSList *list; - char *event; - - va_start(args, last); - list = NULL; - while ((event = va_arg(args, gchar *)) != NULL) - list = g_slist_append(list, g_strdup(event)); - va_end(args); - - server_redirect_initv(server, command, last, list); -} - -int server_redirect_single_event(SERVER_REC *server, const char *arg, - int last, int group, const char *event, - const char *signal, int argpos) -{ - REDIRECT_REC *rec; - GSList *list, *grouplist; - char *origkey; - - g_return_val_if_fail(IS_SERVER(server), 0); - g_return_val_if_fail(event != NULL, 0); - g_return_val_if_fail(signal != NULL, 0); - g_return_val_if_fail(arg != NULL || argpos == -1, 0); - - if (group == 0) group = ++redirect_group; - - rec = g_new0(REDIRECT_REC, 1); - rec->arg = arg == NULL ? NULL : g_strdup(arg); - rec->argpos = argpos; - rec->name = g_strdup(signal); - rec->group = group; - rec->last = last; - - if (g_hash_table_lookup_extended(server->eventtable, event, - (gpointer *) &origkey, - (gpointer *) &list)) { - g_hash_table_remove(server->eventtable, origkey); - } else { - list = NULL; - origkey = g_strdup(event); - } - - grouplist = g_hash_table_lookup(server->eventgrouptable, - GINT_TO_POINTER(group)); - if (grouplist != NULL) { - g_hash_table_remove(server->eventgrouptable, - GINT_TO_POINTER(group)); - } - - list = g_slist_append(list, rec); - grouplist = g_slist_append(grouplist, g_strdup(event)); - - g_hash_table_insert(server->eventtable, origkey, list); - g_hash_table_insert(server->eventgrouptable, - GINT_TO_POINTER(group), grouplist); - - return group; -} - -void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...) -{ - va_list args; - char *event, *signal; - int argpos, group; - - g_return_if_fail(IS_SERVER(server)); - - va_start(args, last); - - group = 0; - while ((event = va_arg(args, gchar *)) != NULL) { - signal = va_arg(args, gchar *); - argpos = va_arg(args, gint); - - group = server_redirect_single_event(server, arg, last > 0, - group, event, signal, - argpos); - last--; - } - - va_end(args); -} - -void server_redirect_default(SERVER_REC *server, const char *command) -{ - REDIRECT_CMD_REC *cmdrec; - REDIRECT_REC *rec; - GSList *events, *list, *grouplist; - char *event, *origkey; - int last; - - g_return_if_fail(IS_SERVER(server)); - g_return_if_fail(command != NULL); - - if (server->cmdtable == NULL) - return; /* not connected yet */ - - cmdrec = g_hash_table_lookup(server->cmdtable, command); - if (cmdrec == NULL) return; - - /* add all events used by command to eventtable and eventgrouptable */ - redirect_group++; grouplist = NULL; last = cmdrec->last; - for (events = cmdrec->events; events != NULL; events = events->next) { - event = events->data; - - if (g_hash_table_lookup_extended(server->eventtable, event, - (gpointer *) &origkey, - (gpointer *) &list)) { - g_hash_table_remove(server->eventtable, origkey); - } else { - list = NULL; - origkey = g_strdup(event); - } - - rec = g_new0(REDIRECT_REC, 1); - rec->argpos = -1; - rec->name = g_strdup(event); - rec->group = redirect_group; - rec->last = last > 0; - - grouplist = g_slist_append(grouplist, g_strdup(event)); - list = g_slist_append(list, rec); - g_hash_table_insert(server->eventtable, origkey, list); - - last--; - } - - g_hash_table_insert(server->eventgrouptable, - GINT_TO_POINTER(redirect_group), grouplist); -} - -void server_redirect_remove_next(SERVER_REC *server, const char *event, - GSList *item) -{ - REDIRECT_REC *rec; - GSList *grouplist, *list, *events, *tmp; - char *origkey; - int group; - - g_return_if_fail(IS_SERVER(server)); - g_return_if_fail(event != NULL); - - if (!g_hash_table_lookup_extended(server->eventtable, event, - (gpointer *) &origkey, - (gpointer *) &list)) - return; - - rec = item == NULL ? list->data : item->data; - if (!rec->last) { - /* this wasn't last expected event */ - return; - } - group = rec->group; - - /* get list of events from this group */ - grouplist = g_hash_table_lookup(server->eventgrouptable, - GINT_TO_POINTER(group)); - - /* remove all of them */ - for (list = grouplist; list != NULL; list = list->next) { - char *event = list->data; - - if (!g_hash_table_lookup_extended(server->eventtable, event, - (gpointer *) &origkey, - (gpointer *) &events)) { - g_warning("server_redirect_remove_next() : " - "event in eventgrouptable but not in " - "eventtable"); - continue; - } - - /* remove the right group */ - for (tmp = events; tmp != NULL; tmp = tmp->next) { - rec = tmp->data; - - if (rec->group == group) - break; - } - - if (rec == NULL) { - g_warning("server_redirect_remove_next() : " - "event in eventgrouptable but not in " - "eventtable (group)"); - continue; - } - - g_free(event); - - events = g_slist_remove(events, rec); - g_free_not_null(rec->arg); - g_free(rec->name); - g_free(rec); - - /* update hash table */ - g_hash_table_remove(server->eventtable, origkey); - if (events == NULL) - g_free(origkey); - else { - g_hash_table_insert(server->eventtable, - origkey, events); - } - } - - g_hash_table_remove(server->eventgrouptable, GINT_TO_POINTER(group)); - g_slist_free(grouplist); -} - -GSList *server_redirect_getqueue(SERVER_REC *server, const char *event, - const char *args) -{ - REDIRECT_REC *rec; - GSList *list; - char **arglist; - int found; - - g_return_val_if_fail(IS_SERVER(server), NULL); - g_return_val_if_fail(event != NULL, NULL); - - list = g_hash_table_lookup(server->eventtable, event); - - for (; list != NULL; list = list->next) { - rec = list->data; - if (rec->argpos == -1) - break; - - if (rec->arg == NULL || args == NULL) - continue; - - /* we need to check that the argument is right.. */ - arglist = g_strsplit(args, " ", -1); - found = (strarray_length(arglist) > rec->argpos && - find_substr(rec->arg, arglist[rec->argpos])); - g_strfreev(arglist); - - if (found) break; - } - - return list; -} - -void servers_redirect_init(void) -{ - redirect_group = 0; - - signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected); -} - -void servers_redirect_deinit(void) -{ - signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected); -} diff --git a/src/core/servers-redirect.h b/src/core/servers-redirect.h deleted file mode 100644 index c9e45ce3..00000000 --- a/src/core/servers-redirect.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __SERVERS_REDIRECT_H -#define __SERVERS_REDIRECT_H - -typedef struct { - int last; /* number of "last" events at the start of the events list */ - GSList *events; /* char* list of events */ -} REDIRECT_CMD_REC; - -typedef struct { - char *name; /* event name */ - - char *arg; /* argument for event we are expecting or NULL */ - int argpos; /* argument position */ - - int group; /* group of events this belongs to */ - int last; /* if this event is received, remove all the events in this group */ -} -REDIRECT_REC; - -void server_redirect_init(SERVER_REC *server, const char *command, int last, ...); -void server_redirect_initv(SERVER_REC *server, const char *command, int last, GSList *list); -/* ... = char *event1, char *event2, ..., NULL */ - -void server_redirect_event(SERVER_REC *server, const char *arg, int last, ...); -/* ... = char *event, char *callback_signal, int argpos, ..., NULL */ - -int server_redirect_single_event(SERVER_REC *server, const char *arg, int last, int group, - const char *event, const char *signal, int argpos); -void server_redirect_default(SERVER_REC *server, const char *command); -void server_redirect_remove_next(SERVER_REC *server, const char *event, GSList *item); -GSList *server_redirect_getqueue(SERVER_REC *server, const char *event, const char *args); - -void servers_redirect_init(void); -void servers_redirect_deinit(void); - -#endif diff --git a/src/core/servers.c b/src/core/servers.c index 0c1bcc6f..fe21f131 100644 --- a/src/core/servers.c +++ b/src/core/servers.c @@ -31,7 +31,6 @@ #include "chat-protocols.h" #include "servers.h" #include "servers-reconnect.h" -#include "servers-redirect.h" #include "servers-setup.h" #include "channels.h" #include "queries.h" @@ -136,10 +135,6 @@ void server_connect_finished(SERVER_REC *server) server->connect_time = time(NULL); server->rawlog = rawlog_create(); - server->eventtable = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal); - server->eventgrouptable = g_hash_table_new((GHashFunc) g_direct_hash, (GCompareFunc) g_direct_equal); - server->cmdtable = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal); - servers = g_slist_append(servers, server); signal_emit("server connected", 1, server); } @@ -553,7 +548,6 @@ void servers_init(void) signal_add("chat protocol deinit", (SIGNAL_FUNC) sig_chat_protocol_deinit); servers_reconnect_init(); - servers_redirect_init(); servers_setup_init(); } @@ -562,7 +556,6 @@ void servers_deinit(void) signal_remove("chat protocol deinit", (SIGNAL_FUNC) sig_chat_protocol_deinit); servers_setup_deinit(); - servers_redirect_deinit(); servers_reconnect_deinit(); module_uniq_destroy("SERVER"); diff --git a/src/fe-common/irc/fe-events.c b/src/fe-common/irc/fe-events.c index 97b505fb..df536f42 100644 --- a/src/fe-common/irc/fe-events.c +++ b/src/fe-common/irc/fe-events.c @@ -309,17 +309,10 @@ static void event_connected(IRC_SERVER_REC *server) return; /* someone has our nick, find out who. */ + server_redirect_event(server, "whois", nick, FALSE, NULL, + "event 311", "nickfind event whois", + "", "event empty", NULL); irc_send_cmdv(server, "WHOIS %s", nick); - server_redirect_event((SERVER_REC *) server, nick, 1, - "event 318", "event empty", 1, - "event 401", "event empty", 1, - "event 311", "nickfind event whois", 1, - "event 301", "event empty", 1, - "event 312", "event empty", 1, - "event 313", "event empty", 1, - "event 317", "event empty", 1, - "event 319", "event empty", 1, NULL); - } static void event_nickfind_whois(IRC_SERVER_REC *server, const char *data) diff --git a/src/irc/core/Makefile.am b/src/irc/core/Makefile.am index d4ee0fa3..9a12b7f4 100644 --- a/src/irc/core/Makefile.am +++ b/src/irc/core/Makefile.am @@ -30,7 +30,8 @@ libirc_core_a_SOURCES = \ modes.c \ mode-lists.c \ netsplit.c \ - server-idle.c + servers-idle.c \ + servers-redirect.c noinst_HEADERS = \ bans.h \ @@ -49,4 +50,5 @@ noinst_HEADERS = \ mode-lists.h \ module.h \ netsplit.h \ - server-idle.h + servers-idle.h \ + servers-redirect.h diff --git a/src/irc/core/channels-query.c b/src/irc/core/channels-query.c index c8a29866..12f21610 100644 --- a/src/irc/core/channels-query.c +++ b/src/irc/core/channels-query.c @@ -209,11 +209,10 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) for (tmp = chans; tmp != NULL; tmp = tmp->next) { chanrec = tmp->data; - server_redirect_event((SERVER_REC *) server, chanstr, 4, - "event 403", "chanquery mode abort", 1, - "event 442", "chanquery mode abort", 1, /* "you're not on that channel" */ - "event 479", "chanquery mode abort", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */ - "event 324", "chanquery mode", 1, NULL); + server_redirect_event(server, "mode channel", chanstr, -1, + "chanquery mode abort", + "event 324", "chanquery mode", + "", "chanquery mode abort", NULL); } break; @@ -223,11 +222,11 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) for (tmp = chans; tmp != NULL; tmp = tmp->next) { chanrec = tmp->data; - server_redirect_event((SERVER_REC *) server, chanstr, 3, - "event 401", "chanquery who abort", 1, - "event 403", "chanquery who abort", 1, - "event 315", "chanquery who end", 1, - "event 352", "silent event who", 1, NULL); + server_redirect_event(server, "who", chanstr, -1, + "chanquery who abort", + "event 315", "chanquery who end", + "event 352", "silent event who", + "", "chanquery who abort", NULL); } break; @@ -240,12 +239,11 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) mode requests - if channels are joined manually irssi could ask modes separately but afterwards join the two b/e/I modes together */ - server_redirect_event((SERVER_REC *) server, chanstr, 4, - "event 403", "chanquery mode abort", 1, - "event 442", "chanquery mode abort", 1, /* "you're not on that channel" */ - "event 479", "chanquery mode abort", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */ - "event 368", "chanquery ban end", 1, - "event 367", "chanquery ban", 1, NULL); + server_redirect_event(server, "mode b", chanstr, -1, + "chanquery mode abort", + "event 367", "chanquery ban", + "event 368", "chanquery ban end", + "", "chanquery mode abort", NULL); } break; @@ -254,12 +252,11 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) for (tmp = chans; tmp != NULL; tmp = tmp->next) { chanrec = tmp->data; - server_redirect_event((SERVER_REC *) server, chanstr, 4, - "event 403", "chanquery mode abort", 1, - "event 442", "chanquery mode abort", 1, /* "you're not on that channel" */ - "event 479", "chanquery mode abort", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */ - "event 349", "chanquery eban end", 1, - "event 348", "chanquery eban", 1, NULL); + server_redirect_event(server, "mode e", chanstr, -1, + "chanquery mode abort", + "event 348", "chanquery eban", + "event 349", "chanquery eban end", + "", "chanquery mode abort", NULL); } break; @@ -268,12 +265,11 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) for (tmp = chans; tmp != NULL; tmp = tmp->next) { chanrec = tmp->data; - server_redirect_event((SERVER_REC *) server, chanstr, 4, - "event 403", "chanquery mode abort", 1, - "event 442", "chanquery mode abort", 1, /* "you're not on that channel" */ - "event 479", "chanquery mode abort", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */ - "event 347", "chanquery ilist end", 1, - "event 346", "chanquery ilist", 1, NULL); + server_redirect_event(server, "mode I", chanstr, -1, + "chanquery mode abort", + "event 346", "chanquery ilist", + "event 347", "chanquery ilist end", + "", "chanquery mode abort", NULL); } break; @@ -423,14 +419,6 @@ static void event_channel_mode(IRC_SERVER_REC *server, const char *data, g_free(params); } -static void multi_query_remove(IRC_SERVER_REC *server, const char *event, const char *data) -{ - GSList *queue; - - while ((queue = server_redirect_getqueue((SERVER_REC *) server, event, data)) != NULL) - server_redirect_remove_next((SERVER_REC *) server, event, queue); -} - static void event_end_of_who(IRC_SERVER_REC *server, const char *data) { IRC_CHANNEL_REC *chanrec; @@ -447,7 +435,6 @@ static void event_end_of_who(IRC_SERVER_REC *server, const char *data) /* instead of multiple End of WHO replies we get only this one... */ server->one_endofwho = TRUE; - multi_query_remove(server, "event 315", data); /* check that the WHO actually did return something (that it understood #chan1,#chan2,..) */ @@ -549,8 +536,6 @@ static void multi_command_error(IRC_SERVER_REC *server, const char *data, char *params, *channel, **chans; int n; - multi_query_remove(server, event, data); - params = event_get_params(data, 2, NULL, &channel); chans = g_strsplit(channel, ",", -1); diff --git a/src/irc/core/ctcp.c b/src/irc/core/ctcp.c index e062a735..b3d56fb6 100644 --- a/src/irc/core/ctcp.c +++ b/src/irc/core/ctcp.c @@ -26,7 +26,7 @@ #include "settings.h" #include "irc-servers.h" -#include "server-idle.h" +#include "servers-idle.h" #include "ignore.h" static void ctcp_queue_clean(IRC_SERVER_REC *server) @@ -57,7 +57,7 @@ void ctcp_send_reply(IRC_SERVER_REC *server, const char *data) return; /* Add to first in idle queue */ - tag = server_idle_add(server, data, NULL, 0, NULL); + tag = server_idle_add(server, data); server->ctcpqueue = g_slist_append(server->ctcpqueue, GINT_TO_POINTER(tag)); } diff --git a/src/irc/core/irc-commands.c b/src/irc/core/irc-commands.c index 94df20d9..18f837e4 100644 --- a/src/irc/core/irc-commands.c +++ b/src/irc/core/irc-commands.c @@ -244,9 +244,6 @@ static void cmd_list(const char *data, IRC_SERVER_REC *server, irc_send_cmdv(server, "LIST %s", str); cmd_params_free(free_arg); - - /* add default redirection */ - server_redirect_default((SERVER_REC *) server, "bogus command list"); } /* SYNTAX: WHO [ | | **] */ @@ -275,9 +272,6 @@ static void cmd_who(const char *data, IRC_SERVER_REC *server, irc_send_cmdv(server, *rest == '\0' ? "WHO %s" : "WHO %s %s", channel, rest); cmd_params_free(free_arg); - - /* add default redirection */ - server_redirect_default((SERVER_REC *) server, "bogus command who"); } static void cmd_names(const char *data, IRC_SERVER_REC *server, @@ -323,43 +317,10 @@ static void cmd_nick(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *item if (!cmd_get_params(data, &free_arg, 1, &nick)) return; - if (strcmp(nick, server->nick) == 0) { - /* don't bother trying to change the nick to the one you - already have */ - cmd_params_free(free_arg); - return; - } - - server->nick_changing = TRUE; irc_send_cmdv(server, "NICK %s", nick); - - nick = g_strdup_printf("%s :%s", nick, nick); - server_redirect_event(SERVER(server), nick, 5, - "event nick", "nickchange over", -1, - "event 433", "nickchange over", 1, - /* 437: ircnet = target unavailable, - dalnet = banned in channel, - can't change nick */ - "event 437", "nickchange over", -1, - "event 432", "nickchange over", 1, - "event 438", "nickchange over", 1, NULL); - g_free(nick); cmd_params_free(free_arg); } -static void sig_nickchange_over(IRC_SERVER_REC *server, const char *data, - const char *nick, const char *addr) -{ - char *signal; - - server->nick_changing = FALSE; - - signal = g_strconcat("event ", current_server_event, NULL); - g_strdown(signal+6); - signal_emit(signal, 4, server, data, nick, addr); - g_free(signal); -} - static char *get_redirect_nicklist(const char *nicks, int *free) { char *str, *ret; @@ -419,20 +380,21 @@ static void cmd_whois(const char *data, IRC_SERVER_REC *server, event_402 = "whois event noserver"; } - server->whois_found = FALSE; - irc_send_cmd_split(server, tmpstr->str, 2, server->max_whois_in_cmd); - /* do automatic /WHOWAS if any of the nicks wasn't found */ query = get_redirect_nicklist(query, &free_nick); str = g_strconcat(qserver, " ", query, NULL); - server_redirect_event(SERVER(server), str, 2, - "event 318", "event 318", 1, - "event 402", event_402, 1, - "event 401", "whois not found", 1, - "event 311", "whois event", 1, NULL); + server_redirect_event(server, "whois", str, *qserver != '\0', + NULL, + "event 318", "event 318", + "event 402", event_402, + "event 401", "whois not found", + "event 311", "whois event", NULL); g_free(str); + server->whois_found = FALSE; + irc_send_cmd_split(server, tmpstr->str, 2, server->max_whois_in_cmd); + if (free_nick) g_free(query); cmd_params_free(free_arg); } @@ -451,13 +413,14 @@ static void sig_whois_not_found(IRC_SERVER_REC *server, const char *data) g_return_if_fail(data != NULL); params = event_get_params(data, 2, NULL, &nick); - irc_send_cmdv(server, "WHOWAS %s 1", nick); server->whowas_found = FALSE; - server_redirect_event(SERVER(server), nick, 1, - "event 369", "whowas event end", 1, - "event 314", "whowas event", 1, - "event 406", "event empty", 1, NULL); + server_redirect_event(server, "whowas", nick, -1, NULL, + "event 314", "whowas event", + "event 369", "whowas event end", + "", "event empty", NULL); + irc_send_cmdv(server, "WHOWAS %s 1", nick); + g_free(params); } @@ -470,7 +433,7 @@ static void event_whowas(IRC_SERVER_REC *server, const char *data, const char *n /* SYNTAX: WHOWAS [ []] */ static void cmd_whowas(const char *data, IRC_SERVER_REC *server) { - char *nicks, *count; + char *nicks, *count, *nicks_redir; void *free_arg; int free_nick; @@ -480,15 +443,15 @@ static void cmd_whowas(const char *data, IRC_SERVER_REC *server) return; if (*nicks == '\0') nicks = server->nick; + nicks_redir = get_redirect_nicklist(nicks, &free_nick); + server_redirect_event(server, "whowas", nicks_redir, -1, NULL, + "event 314", "whowas event", NULL); + if (free_nick) g_free(nicks_redir); + server->whowas_found = FALSE; irc_send_cmdv(server, *count == '\0' ? "WHOWAS %s" : "WHOWAS %s %s", nicks, count); - nicks = get_redirect_nicklist(nicks, &free_nick); - server_redirect_event(SERVER(server), nicks, 1, - "event 369", "event 369", 1, - "event 314", "whowas event", 1, NULL); - if (free_nick) g_free(nicks); cmd_params_free(free_arg); } @@ -914,48 +877,6 @@ static void command_2self(const char *data, IRC_SERVER_REC *server) cmd_params_free(free_arg); } -static void sig_connected(IRC_SERVER_REC *server) -{ - g_return_if_fail(server != NULL); - - /* FIXME: these two aren't probably needed? this whole redirection - thing might need some rethinking :) */ - /* WHOIS */ - /*server_redirect_init(SERVER(server), "", 2, - "event 318", "event 402", "event 401", - "event 301", "event 311", "event 312", "event 313", - "event 317", "event 319", NULL);*/ - - /* NICK */ - /*server_redirect_init(SERVER(server), "", 5, - "event nick", "event 433", "event 437", - "event 432", "event 438", NULL);*/ - - /* problem (doesn't really apply currently since there's no GUI): - - second argument of server_redirect_init() is the command that - generates the redirection automatically when it's called, but the - command handler doesn't really know about the redirection itself. - - every time the command is called, this redirection is generated. - this is a problem if the redirection is wanted sometimes but not - always. for example /WHO #channel could create a window with a - list of people in channel redirecting WHO's events to it's own use, - but /WHO -nogui #channel would use the default WHO handler which - doesn't know anything about redirection. with GUI /WHO the - redirection would be done twice then.. - - so the kludgy workaround currently is this: make the default - handler handle the redirection always.. when default WHO/LIST - handler is called, they call - server_redirect_default("bogus command who") or ..list.. - - this is really a problem if some script/plugin wants to override - some default command to use redirections.. */ - server_redirect_init(SERVER(server), "bogus command who", 2, "event 401", "event 315", "event 352", NULL); - server_redirect_init(SERVER(server), "bogus command list", 1, "event 321", "event 322", "event 323", NULL); -} - void irc_commands_init(void) { tmpstr = g_string_new(NULL); @@ -1048,11 +969,9 @@ void irc_commands_init(void) signal_add("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed); signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); - signal_add("nickchange over", (SIGNAL_FUNC) sig_nickchange_over); signal_add("whois not found", (SIGNAL_FUNC) sig_whois_not_found); signal_add("whois event", (SIGNAL_FUNC) event_whois); signal_add("whowas event", (SIGNAL_FUNC) event_whowas); - signal_add("server connected", (SIGNAL_FUNC) sig_connected); command_set_options("connect", "+ircnet"); command_set_options("topic", "delete"); @@ -1119,11 +1038,9 @@ void irc_commands_deinit(void) signal_remove("channel destroyed", (SIGNAL_FUNC) sig_channel_destroyed); signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); - signal_remove("nickchange over", (SIGNAL_FUNC) sig_nickchange_over); signal_remove("whois not found", (SIGNAL_FUNC) sig_whois_not_found); signal_remove("whois event", (SIGNAL_FUNC) event_whois); signal_remove("whowas event", (SIGNAL_FUNC) event_whowas); - signal_remove("server connected", (SIGNAL_FUNC) sig_connected); g_string_free(tmpstr, TRUE); } diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index 5591e313..a1310be1 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -33,8 +33,9 @@ #include "irc-servers-setup.h" #include "irc-servers.h" #include "channel-rejoin.h" -#include "server-idle.h" +#include "servers-idle.h" #include "servers-reconnect.h" +#include "servers-redirect.h" #include "modes.h" #include "settings.h" @@ -304,6 +305,7 @@ static void server_cmd_timeout(IRC_SERVER_REC *server, GTimeVal *now) /* add to rawlog without CR+LF */ cmd[len-2] = '\0'; rawlog_output(server->rawlog, cmd); + server_redirect_command(server, cmd); /* remove from queue */ g_free(cmd); @@ -506,6 +508,7 @@ void irc_servers_init(void) irc_servers_setup_init(); irc_servers_reconnect_init(); + servers_redirect_init(); servers_idle_init(); } @@ -527,5 +530,6 @@ void irc_servers_deinit(void) irc_servers_setup_deinit(); irc_servers_reconnect_deinit(); + servers_redirect_deinit(); servers_idle_deinit(); } diff --git a/src/irc/core/irc-servers.h b/src/irc/core/irc-servers.h index 1add7cdd..4866091a 100644 --- a/src/irc/core/irc-servers.h +++ b/src/irc/core/irc-servers.h @@ -37,12 +37,16 @@ struct _IRC_SERVER_CONNECT_REC { struct _IRC_SERVER_REC { #include "server-rec.h" + /* For deciding if event should be redirected */ + GSList *redirects; + void *redirect_next; + void *redirect_continue; + char *real_address; /* address the irc server gives */ char *usermode; /* The whole mode string .. */ char *userhost; /* /USERHOST - set when joined to first channel */ int channels_formed; /* channels formed in irc network */ - unsigned int nick_changing:1; /* We've sent nick change command to server */ unsigned int whois_coming:1; /* Mostly just to display away message right.. */ unsigned int whois_found:1; /* Did WHOIS return any entries? */ unsigned int whowas_found:1; /* Did WHOWAS return any entries? */ diff --git a/src/irc/core/irc.c b/src/irc/core/irc.c index a7e58bb6..8b967d4e 100644 --- a/src/irc/core/irc.c +++ b/src/irc/core/irc.c @@ -62,8 +62,10 @@ void irc_send_cmd_full(IRC_SERVER_REC *server, const char *cmd, cmd = str; } - if (send_now) + if (send_now) { rawlog_output(server->rawlog, cmd); + server_redirect_command(server, cmd); + } if (!raw) { /* Add CR+LF to command */ @@ -253,39 +255,34 @@ char *event_get_params(const char *data, int count, ...) return duprec; } -static void irc_server_event(IRC_SERVER_REC *server, const char *line, const char *nick, const char *address) +static void irc_server_event(IRC_SERVER_REC *server, const char *line, + const char *nick, const char *address) { - char *event, *args, *callcmd; - GSList *list; + const char *signal; + char *event, *args; g_return_if_fail(line != NULL); - /* get command.. */ + /* split event / args */ event = g_strconcat("event ", line, NULL); args = strchr(event+6, ' '); if (args != NULL) *args++ = '\0'; else args = ""; while (*args == ' ') args++; + g_strdown(event); - list = server_redirect_getqueue((SERVER_REC *) server, event, args); - if (list == NULL) - callcmd = g_strdup(event); - else { - /* event is redirected somewhere else.. */ - REDIRECT_REC *rec; - - rec = list->data; - callcmd = g_strdup(rec->name); - rawlog_redirect(server->rawlog, callcmd); - server_redirect_remove_next((SERVER_REC *) server, event, list); - } + /* check if event needs to be redirected */ + signal = server_redirect_get_signal(server, event, args); + if (signal == NULL) + signal = event; + else + rawlog_redirect(server->rawlog, signal); + /* emit it */ current_server_event = event+6; - g_strdown(callcmd); - if (!signal_emit(callcmd, 4, server, args, nick, address)) + if (!signal_emit(signal, 4, server, args, nick, address)) signal_emit_id(signal_default_event, 4, server, line, nick, address); current_server_event = NULL; - g_free(callcmd); g_free(event); } diff --git a/src/irc/core/lag.c b/src/irc/core/lag.c index d2c62813..8670956b 100644 --- a/src/irc/core/lag.c +++ b/src/irc/core/lag.c @@ -24,6 +24,7 @@ #include "settings.h" #include "irc-servers.h" +#include "servers-redirect.h" typedef struct { IRC_SERVER_REC *server; @@ -53,6 +54,20 @@ static void lag_free(LAG_REC *rec) g_free(rec); } +static void lag_send(LAG_REC *lag) +{ + IRC_SERVER_REC *server; + + g_get_current_time(&lag->time); + + server = lag->server; + server->lag_sent = server->lag_last_check = time(NULL); + server_redirect_event(server, "ping", NULL, FALSE, + "lag ping error", + "event pong", "lag pong", NULL); + irc_send_cmdv(server, "PING %s", server->real_address); +} + static void lag_get(IRC_SERVER_REC *server) { LAG_REC *lag; @@ -61,57 +76,42 @@ static void lag_get(IRC_SERVER_REC *server) /* nick changes may fail this check, so we should never do this while there's nick change request waiting for reply in server.. */ - if (server->nick_changing) - return; - lag = g_new0(LAG_REC, 1); lags = g_slist_append(lags, lag); lag->server = server; - g_get_current_time(&lag->time); + lag_send(lag); +} - if (server->lag_sent == 0) - server->lag_sent = time(NULL); - server->lag_last_check = time(NULL); +/* we didn't receive PONG for some reason .. try again */ +static void lag_ping_error(IRC_SERVER_REC *server) +{ + LAG_REC *lag; - irc_send_cmdv(server, "NOTICE %s :\001IRSSILAG %ld %ld\001", - server->nick, lag->time.tv_sec, lag->time.tv_usec); + lag = lag_find(server); + if (lag != NULL) + lag_send(lag); } -/* we use "ctcp reply" signal here, because "ctcp reply irssilag" can be - ignored with /IGNORE * CTCPS */ -static void sig_irssilag(IRC_SERVER_REC *server, const char *data, - const char *nick, const char *addr, - const char *target) +static void lag_event_pong(IRC_SERVER_REC *server, const char *data, + const char *nick, const char *addr) { - GTimeVal now, sent; + GTimeVal now; LAG_REC *lag; g_return_if_fail(data != NULL); - if (strncmp(data, "IRSSILAG ", 9) != 0) - return; - data += 9; - lag = lag_find(server); if (lag == NULL) { /* not expecting lag reply.. */ return; } - if (g_strcasecmp(nick, server->nick) != 0) { - /* we didn't sent this - not a lag notice */ - return; - } - - /* OK, it is a lag notice. */ server->lag_sent = 0; - if (sscanf(data, "%ld %ld", &sent.tv_sec, &sent.tv_usec) == 2) { - g_get_current_time(&now); - server->lag = (int) get_timeval_diff(&now, &sent); - signal_emit("server lag", 1, server); - } + g_get_current_time(&now); + server->lag = (int) get_timeval_diff(&now, &lag->time); + signal_emit("server lag", 1, server); lag_free(lag); } @@ -154,11 +154,6 @@ static int sig_check_lag(void) return 1; } -static void sig_empty(void) -{ - /* don't print the "CTCP IRSSILAG reply .." text */ -} - void lag_init(void) { settings_add_int("misc", "lag_check_time", 30); @@ -166,8 +161,8 @@ void lag_init(void) lags = NULL; timeout_tag = g_timeout_add(1000, (GSourceFunc) sig_check_lag, NULL); - signal_add("ctcp reply", (SIGNAL_FUNC) sig_irssilag); - signal_add("ctcp reply irssilag", (SIGNAL_FUNC) sig_empty); + signal_add_first("lag pong", (SIGNAL_FUNC) lag_event_pong); + signal_add("lag ping error", (SIGNAL_FUNC) lag_ping_error); } void lag_deinit(void) @@ -175,6 +170,6 @@ void lag_deinit(void) g_source_remove(timeout_tag); while (lags != NULL) lag_free(lags->data); - signal_remove("ctcp reply", (SIGNAL_FUNC) sig_irssilag); - signal_remove("ctcp reply irssilag", (SIGNAL_FUNC) sig_empty); + signal_remove("lag pong", (SIGNAL_FUNC) lag_event_pong); + signal_remove("lag ping error", (SIGNAL_FUNC) lag_ping_error); } diff --git a/src/irc/core/server-idle.c b/src/irc/core/server-idle.c deleted file mode 100644 index 9443fdf7..00000000 --- a/src/irc/core/server-idle.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - server-idle.c : irssi - - Copyright (C) 1999-2000 Timo Sirainen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "module.h" -#include "signals.h" - -#include "irc-servers.h" -#include "server-idle.h" -#include "servers-redirect.h" - -typedef struct { - char *event; - char *signal; - int argpos; -} REDIRECT_IDLE_REC; - -typedef struct { - char *cmd; - char *arg; - int tag; - - int last; - GSList *redirects; -} SERVER_IDLE_REC; - -static int idle_tag, idlepos; - -/* Add new idle command to queue */ -static SERVER_IDLE_REC *server_idle_create(const char *cmd, const char *arg, int last, va_list args) -{ - REDIRECT_IDLE_REC *rrec; - SERVER_IDLE_REC *rec; - char *event; - - g_return_val_if_fail(cmd != NULL, FALSE); - - rec = g_new0(SERVER_IDLE_REC, 1); - - rec->tag = ++idlepos; - rec->arg = arg == NULL ? NULL : g_strdup(arg); - rec->cmd = g_strdup(cmd); - rec->last = last; - - while ((event = va_arg(args, char *)) != NULL) { - rrec = g_new(REDIRECT_IDLE_REC, 1); - rec->redirects = g_slist_append(rec->redirects, rrec); - - rrec->event = g_strdup(event); - rrec->signal = g_strdup(va_arg(args, char *)); - rrec->argpos = va_arg(args, int); - } - - return rec; -} - -static SERVER_IDLE_REC *server_idle_find_rec(IRC_SERVER_REC *server, int tag) -{ - GSList *tmp; - - g_return_val_if_fail(server != NULL, FALSE); - - for (tmp = server->idles; tmp != NULL; tmp = tmp->next) { - SERVER_IDLE_REC *rec = tmp->data; - - if (rec->tag == tag) - return rec; - } - - return NULL; -} - -/* Add new idle command to queue */ -int server_idle_add(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...) -{ - va_list args; - SERVER_IDLE_REC *rec; - - g_return_val_if_fail(server != NULL, -1); - - va_start(args, last); - rec = server_idle_create(cmd, arg, last, args); - server->idles = g_slist_append(server->idles, rec); - va_end(args); - - return rec->tag; -} - -/* Add new idle command to first of queue */ -int server_idle_add_first(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...) -{ - va_list args; - SERVER_IDLE_REC *rec; - - g_return_val_if_fail(server != NULL, -1); - - va_start(args, last); - rec = server_idle_create(cmd, arg, last, args); - server->idles = g_slist_prepend(server->idles, rec); - va_end(args); - - return rec->tag; -} - -/* Add new idle command to specified position of queue */ -int server_idle_insert(IRC_SERVER_REC *server, const char *cmd, const char *arg, int tag, int last, ...) -{ - va_list args; - SERVER_IDLE_REC *rec; - int pos; - - g_return_val_if_fail(server != NULL, -1); - - va_start(args, last); - - /* find the position of tag in idle list */ - rec = server_idle_find_rec(server, tag); - pos = g_slist_index(server->idles, rec); - - rec = server_idle_create(cmd, arg, last, args); - server->idles = pos < 0 ? - g_slist_append(server->idles, rec) : - g_slist_insert(server->idles, rec, pos); - va_end(args); - return rec->tag; -} - -static void server_idle_destroy(IRC_SERVER_REC *server, SERVER_IDLE_REC *rec) -{ - GSList *tmp; - - g_return_if_fail(server != NULL); - - server->idles = g_slist_remove(server->idles, rec); - - for (tmp = rec->redirects; tmp != NULL; tmp = tmp->next) { - REDIRECT_IDLE_REC *rec = tmp->data; - - g_free(rec->event); - g_free(rec->signal); - g_free(rec); - } - g_slist_free(rec->redirects); - - g_free_not_null(rec->arg); - g_free(rec->cmd); - g_free(rec); -} - -/* Check if record is still in queue */ -int server_idle_find(IRC_SERVER_REC *server, int tag) -{ - return server_idle_find_rec(server, tag) != NULL; -} - -/* Remove record from idle queue */ -int server_idle_remove(IRC_SERVER_REC *server, int tag) -{ - SERVER_IDLE_REC *rec; - - g_return_val_if_fail(server != NULL, FALSE); - - rec = server_idle_find_rec(server, tag); - if (rec == NULL) - return FALSE; - - server_idle_destroy(server, rec); - return TRUE; -} - -/* Execute next idle command */ -static void server_idle_next(IRC_SERVER_REC *server) -{ - SERVER_IDLE_REC *rec; - GSList *tmp; - int group; - - g_return_if_fail(server != NULL); - - if (server->idles == NULL) return; - rec = server->idles->data; - - /* Send command */ - irc_send_cmd(server, rec->cmd); - - /* Add server redirections */ - group = 0; - for (tmp = rec->redirects; tmp != NULL; tmp = tmp->next) { - REDIRECT_IDLE_REC *rrec = tmp->data; - - group = server_redirect_single_event((SERVER_REC *) server, rec->arg, rec->last > 0, - group, rrec->event, rrec->signal, rrec->argpos); - if (rec->last > 0) rec->last--; - } - - server_idle_destroy(server, rec); -} - -static void sig_disconnected(IRC_SERVER_REC *server) -{ - g_return_if_fail(server != NULL); - - if (!IS_IRC_SERVER(server)) - return; - - while (server->idles != NULL) - server_idle_destroy(server, server->idles->data); -} - -static int sig_idle_timeout(void) -{ - GSList *tmp; - - /* Scan through every server */ - for (tmp = servers; tmp != NULL; tmp = tmp->next) { - IRC_SERVER_REC *rec = tmp->data; - - if (IS_IRC_SERVER(rec) && - rec->idles != NULL && rec->cmdcount == 0) { - /* We're idling and we have idle commands to run! */ - server_idle_next(rec); - } - } - return 1; -} - -void servers_idle_init(void) -{ - idlepos = 0; - idle_tag = g_timeout_add(1000, (GSourceFunc) sig_idle_timeout, NULL); - - signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected); -} - -void servers_idle_deinit(void) -{ - g_source_remove(idle_tag); - signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected); -} diff --git a/src/irc/core/server-idle.h b/src/irc/core/server-idle.h deleted file mode 100644 index 8d89f8f5..00000000 --- a/src/irc/core/server-idle.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __SERVER_IDLE_H -#define __SERVER_IDLE_H - -/* Add new idle command to queue */ -int server_idle_add(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...); - -/* Add new idle command to first of queue */ -int server_idle_add_first(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...); - -/* Add new idle command to specified position of queue */ -int server_idle_insert(IRC_SERVER_REC *server, const char *cmd, const char *arg, int tag, int last, ...); - -/* Check if record is still in queue */ -int server_idle_find(IRC_SERVER_REC *server, int tag); - -/* Remove record from idle queue */ -int server_idle_remove(IRC_SERVER_REC *server, int tag); - -void servers_idle_init(void); -void servers_idle_deinit(void); - -#endif diff --git a/src/irc/core/servers-idle.c b/src/irc/core/servers-idle.c new file mode 100644 index 00000000..fb979dab --- /dev/null +++ b/src/irc/core/servers-idle.c @@ -0,0 +1,258 @@ +/* + server-idle.c : irssi + + Copyright (C) 1999-2000 Timo Sirainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "signals.h" + +#include "irc-servers.h" +#include "servers-idle.h" +#include "servers-redirect.h" + +typedef struct { + char *cmd; + char *arg; + int tag; + + char *redirect_cmd; + int remote; + char *failure_signal; + GSList *redirects; +} SERVER_IDLE_REC; + +static int idle_tag, idlepos; + +/* Add new idle command to queue */ +static SERVER_IDLE_REC * +server_idle_create(const char *cmd, const char *redirect_cmd, const char *arg, + int remote, const char *failure_signal, va_list va) +{ + SERVER_IDLE_REC *rec; + const char *event, *signal; + + g_return_val_if_fail(cmd != NULL, FALSE); + + rec = g_new0(SERVER_IDLE_REC, 1); + rec->cmd = g_strdup(cmd); + rec->arg = g_strdup(arg); + rec->tag = ++idlepos; + + rec->redirect_cmd = g_strdup(redirect_cmd); + rec->remote = remote; + rec->failure_signal = g_strdup(failure_signal); + + while ((event = va_arg(va, const char *)) != NULL) { + signal = va_arg(va, const char *); + if (signal == NULL) { + g_warning("server_idle_create(%s): " + "signal not specified for event", + redirect_cmd); + break; + } + + rec->redirects = + g_slist_append(rec->redirects, g_strdup(event)); + rec->redirects = + g_slist_append(rec->redirects, g_strdup(signal)); + } + + return rec; +} + +static SERVER_IDLE_REC *server_idle_find_rec(IRC_SERVER_REC *server, int tag) +{ + GSList *tmp; + + g_return_val_if_fail(server != NULL, FALSE); + + for (tmp = server->idles; tmp != NULL; tmp = tmp->next) { + SERVER_IDLE_REC *rec = tmp->data; + + if (rec->tag == tag) + return rec; + } + + return NULL; +} + +/* Add new idle command to queue */ +int server_idle_add_redir(IRC_SERVER_REC *server, const char *cmd, + const char *redirect_cmd, const char *arg, + int remote, const char *failure_signal, ...) +{ + va_list va; + SERVER_IDLE_REC *rec; + + g_return_val_if_fail(server != NULL, -1); + + va_start(va, failure_signal); + rec = server_idle_create(cmd, redirect_cmd, arg, remote, + failure_signal, va); + server->idles = g_slist_append(server->idles, rec); + va_end(va); + + return rec->tag; +} + +/* Add new idle command to first of queue */ +int server_idle_add_first_redir(IRC_SERVER_REC *server, const char *cmd, + const char *redirect_cmd, const char *arg, + int remote, const char *failure_signal, ...) +{ + va_list va; + SERVER_IDLE_REC *rec; + + g_return_val_if_fail(server != NULL, -1); + + va_start(va, failure_signal); + rec = server_idle_create(cmd, redirect_cmd, arg, remote, + failure_signal, va); + server->idles = g_slist_prepend(server->idles, rec); + va_end(va); + + return rec->tag; +} + +/* Add new idle command to specified position of queue */ +int server_idle_insert_redir(IRC_SERVER_REC *server, const char *cmd, int tag, + const char *redirect_cmd, const char *arg, + int remote, const char *failure_signal, ...) +{ + va_list va; + SERVER_IDLE_REC *rec; + int pos; + + g_return_val_if_fail(server != NULL, -1); + + va_start(va, failure_signal); + + /* find the position of tag in idle list */ + rec = server_idle_find_rec(server, tag); + pos = g_slist_index(server->idles, rec); + + rec = server_idle_create(cmd, redirect_cmd, arg, remote, + failure_signal, va); + server->idles = pos < 0 ? + g_slist_append(server->idles, rec) : + g_slist_insert(server->idles, rec, pos); + va_end(va); + + return rec->tag; +} + +static void server_idle_destroy(IRC_SERVER_REC *server, SERVER_IDLE_REC *rec) +{ + g_return_if_fail(server != NULL); + + server->idles = g_slist_remove(server->idles, rec); + + g_slist_foreach(rec->redirects, (GFunc) g_free, NULL); + g_slist_free(rec->redirects); + + g_free_not_null(rec->arg); + g_free_not_null(rec->redirect_cmd); + g_free_not_null(rec->failure_signal); + g_free(rec->cmd); + g_free(rec); +} + +/* Check if record is still in queue */ +int server_idle_find(IRC_SERVER_REC *server, int tag) +{ + return server_idle_find_rec(server, tag) != NULL; +} + +/* Remove record from idle queue */ +int server_idle_remove(IRC_SERVER_REC *server, int tag) +{ + SERVER_IDLE_REC *rec; + + g_return_val_if_fail(server != NULL, FALSE); + + rec = server_idle_find_rec(server, tag); + if (rec == NULL) + return FALSE; + + server_idle_destroy(server, rec); + return TRUE; +} + +/* Execute next idle command */ +static void server_idle_next(IRC_SERVER_REC *server) +{ + SERVER_IDLE_REC *rec; + + g_return_if_fail(server != NULL); + + if (server->idles == NULL) + return; + rec = server->idles->data; + + /* Send command */ + if (rec->redirect_cmd != NULL) { + server_redirect_event_list(server, rec->redirect_cmd, rec->arg, + rec->remote, rec->failure_signal, + rec->redirects); + } + irc_send_cmd(server, rec->cmd); + + server_idle_destroy(server, rec); +} + +static void sig_disconnected(IRC_SERVER_REC *server) +{ + g_return_if_fail(server != NULL); + + if (!IS_IRC_SERVER(server)) + return; + + while (server->idles != NULL) + server_idle_destroy(server, server->idles->data); +} + +static int sig_idle_timeout(void) +{ + GSList *tmp; + + /* Scan through every server */ + for (tmp = servers; tmp != NULL; tmp = tmp->next) { + IRC_SERVER_REC *rec = tmp->data; + + if (IS_IRC_SERVER(rec) && + rec->idles != NULL && rec->cmdcount == 0) { + /* We're idling and we have idle commands to run! */ + server_idle_next(rec); + } + } + return 1; +} + +void servers_idle_init(void) +{ + idlepos = 0; + idle_tag = g_timeout_add(1000, (GSourceFunc) sig_idle_timeout, NULL); + + signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected); +} + +void servers_idle_deinit(void) +{ + g_source_remove(idle_tag); + signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected); +} diff --git a/src/irc/core/servers-idle.h b/src/irc/core/servers-idle.h new file mode 100644 index 00000000..12b67a96 --- /dev/null +++ b/src/irc/core/servers-idle.h @@ -0,0 +1,34 @@ +#ifndef __SERVERS_IDLE_H +#define __SERVERS_IDLE_H + +/* Add new idle command to queue */ +int server_idle_add_redir(IRC_SERVER_REC *server, const char *cmd, + const char *redirect_cmd, const char *arg, + int remote, const char *failure_signal, ...); +#define server_idle_add(server, cmd) \ + server_idle_add_redir(server, cmd, NULL, NULL, 0, NULL, NULL) + +/* Add new idle command to first of queue */ +int server_idle_add_first_redir(IRC_SERVER_REC *server, const char *cmd, + const char *redirect_cmd, const char *arg, + int remote, const char *failure_signal, ...); +#define server_idle_add_first(server, cmd) \ + server_idle_add_first_redir(server, cmd, NULL, NULL, 0, NULL, NULL) + +/* Add new idle command to specified position of queue */ +int server_idle_insert_redir(IRC_SERVER_REC *server, const char *cmd, int tag, + const char *redirect_cmd, const char *arg, + int remote, const char *failure_signal, ...); +#define server_idle_insert(server, cmd, tag) \ + server_idle_insert_redir(server, cmd, tag, NULL, NULL, 0, NULL, NULL) + +/* Check if record is still in queue */ +int server_idle_find(IRC_SERVER_REC *server, int tag); + +/* Remove record from idle queue */ +int server_idle_remove(IRC_SERVER_REC *server, int tag); + +void servers_idle_init(void); +void servers_idle_deinit(void); + +#endif diff --git a/src/irc/core/servers-redirect.c b/src/irc/core/servers-redirect.c new file mode 100644 index 00000000..814c6b27 --- /dev/null +++ b/src/irc/core/servers-redirect.c @@ -0,0 +1,569 @@ +/* + server-redirect.c : irssi + + Copyright (C) 1999-2000 Timo Sirainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "signals.h" +#include "misc.h" + +#include "irc-servers.h" +#include "servers-redirect.h" + +typedef struct { + int refcount; + + int remote; + int timeout; + GSList *start, *stop; /* char *event, int argpos, ... */ +} REDIRECT_CMD_REC; + +typedef struct { + REDIRECT_CMD_REC *cmd; + time_t created; + int destroyed; + + char *arg; + int remote; + char *failure_signal, *default_signal; + GSList *signals; /* event, signal, ... */ +} REDIRECT_REC; + +static GHashTable *command_redirects; /* "command xxx" : REDIRECT_CMD_REC* */ + +/* Find redirection command record for specified command line. */ +static REDIRECT_CMD_REC *redirect_cmd_find(const char *command) +{ + REDIRECT_CMD_REC *rec; + const char *p; + char *cmd; + + p = strchr(command, ' '); + if (p == NULL) + rec = g_hash_table_lookup(command_redirects, command); + else { + cmd = g_strndup(command, (int) (p-command)); + rec = g_hash_table_lookup(command_redirects, cmd); + g_free(cmd); + } + return rec; +} + +static void redirect_cmd_destroy(REDIRECT_CMD_REC *rec) +{ + GSList *tmp; + + for (tmp = rec->start; tmp != NULL; tmp = tmp->next->next) + g_free(tmp->data); + for (tmp = rec->stop; tmp != NULL; tmp = tmp->next->next) + g_free(tmp->data); + g_slist_free(rec->start); + g_slist_free(rec->stop); + g_free(rec); +} + +static void redirect_cmd_ref(REDIRECT_CMD_REC *rec) +{ + rec->refcount++; +} + +static void redirect_cmd_unref(REDIRECT_CMD_REC *rec) +{ + if (--rec->refcount <= 0) + redirect_cmd_destroy(rec); +} + +static void redirect_destroy(REDIRECT_REC *rec) +{ + redirect_cmd_unref(rec->cmd); + + g_free_not_null(rec->arg); + g_free_not_null(rec->failure_signal); + g_free_not_null(rec->default_signal); + g_slist_foreach(rec->signals, (GFunc) g_free, NULL); + g_slist_free(rec->signals); + g_free(rec); +} + +void server_redirect_register(const char *command, + int remote, int timeout, ...) +{ + va_list va; + GSList *start, *stop, **list; + const char *event; + int argpos; + + va_start(va, timeout); + start = stop = NULL; list = &start; + for (;;) { + event = va_arg(va, const char *); + if (event == NULL) { + if (list == &stop) + break; + list = &stop; + continue; + } + + argpos = va_arg(va, int); + *list = g_slist_append(*list, g_strdup(event)); + *list = g_slist_append(*list, GINT_TO_POINTER(argpos)); + } + + va_end(va); + + server_redirect_register_list(command, remote, timeout, start, stop); +} + +void server_redirect_register_list(const char *command, + int remote, int timeout, + GSList *start, GSList *stop) +{ + REDIRECT_CMD_REC *rec; + gpointer key, value; + + g_return_if_fail(command != NULL); + g_return_if_fail(stop != NULL); + + if (g_hash_table_lookup_extended(command_redirects, command, + &key, &value)) { + /* Already registered - might have changed so destroy + the old one */ + g_hash_table_remove(command_redirects, command); + redirect_cmd_unref(value); + g_free(key); + } + + rec = g_new0(REDIRECT_CMD_REC, 1); + redirect_cmd_ref(rec); + rec->remote = remote; + rec->timeout = timeout; + rec->start = start; + rec->stop = stop; + g_hash_table_insert(command_redirects, g_strdup(command), rec); +} + +void server_redirect_event(IRC_SERVER_REC *server, const char *command, + const char *arg, int remote, + const char *failure_signal, ...) +{ + GSList *signals; + const char *event, *signal; + va_list va; + + va_start(va, failure_signal); + signals = NULL; + while ((event = va_arg(va, const char *)) != NULL) { + signal = va_arg(va, const char *); + if (signal == NULL) { + g_warning("server_redirect_event(%s): " + "signal not specified for event", command); + break; + } + + signals = g_slist_append(signals, g_strdup(event)); + signals = g_slist_append(signals, g_strdup(signal)); + } + + va_end(va); + + server_redirect_event_list(server, command, arg, remote, + failure_signal, signals); +} + +void server_redirect_event_list(IRC_SERVER_REC *server, const char *command, + const char *arg, int remote, + const char *failure_signal, GSList *signals) +{ + REDIRECT_CMD_REC *cmdrec; + REDIRECT_REC *rec; + GSList *default_signal; + char *default_signal_key; + + g_return_if_fail(IS_IRC_SERVER(server)); + g_return_if_fail(command != NULL); + g_return_if_fail((g_slist_length(signals) & 1) == 0); + + if (server->redirect_next != NULL) { + redirect_destroy(server->redirect_next); + server->redirect_next = NULL; + } + + cmdrec = g_hash_table_lookup(command_redirects, command); + if (cmdrec == NULL) { + g_warning("Unknown redirection command: %s", command); + return; + } + + redirect_cmd_ref(cmdrec); + + rec = g_new0(REDIRECT_REC, 1); + rec->created = time(NULL); + rec->cmd = cmdrec; + rec->arg = g_strdup(arg); + rec->remote = remote != -1 ? remote : cmdrec->remote; + rec->failure_signal = g_strdup(failure_signal); + + default_signal = gslist_find_string(signals, ""); + if (default_signal != NULL) { + default_signal_key = default_signal->data; + rec->default_signal = default_signal->next->data; + + signals = g_slist_remove(signals, default_signal_key); + signals = g_slist_remove(signals, rec->default_signal); + g_free(default_signal_key); + } + rec->signals = signals; + + server->redirect_next = rec; +} + +void server_redirect_command(IRC_SERVER_REC *server, const char *command) +{ + REDIRECT_CMD_REC *cmdrec; + REDIRECT_REC *rec; + + g_return_if_fail(IS_IRC_SERVER(server)); + g_return_if_fail(command != NULL); + + if (server->redirect_next != NULL) { + rec = server->redirect_next; + server->redirect_next = NULL; + } else { + cmdrec = redirect_cmd_find(command); + if (cmdrec == NULL) + return; + + /* no redirection wanted, but still register the command + so future redirections wont get messed up. */ + redirect_cmd_ref(cmdrec); + + rec = g_new0(REDIRECT_REC, 1); + rec->created = time(NULL); + rec->cmd = cmdrec; + rec->remote = cmdrec->remote; + } + + server->redirects = g_slist_append(server->redirects, rec); +} + +static int redirect_args_match(const char *event_args, + const char *arg, int pos) +{ + const char *start; + + if (pos == -1) + return TRUE; + + /* skip to the start of the wanted argument */ + while (pos > 0 && *event_args != '\0') { + while (*event_args != ' ' && *event_args != '\0') event_args++; + while (*event_args == ' ') event_args++; + pos--; + } + + /* now compare the arguments */ + start = event_args; + while (*arg != '\0') { + while (*arg != '\0' && *arg != ' ' && *event_args != '\0') { + if (*arg != *event_args) + break; + arg++; event_args++; + } + + if ((*arg == '\0' || *arg == ' ') && + (*event_args == '\0' || *event_args == ' ')) + return TRUE; + + /* compare the next argument */ + while (*arg != ' ' && *arg != '\0') arg++; + while (*arg == ' ') arg++; + + event_args = start; + } + + return FALSE; +} + +static GSList *redirect_cmd_list_find(GSList *list, const char *event) +{ + while (list != NULL) { + const char *str = list->data; + + if (strcmp(str, event) == 0) + break; + list = list->next->next; + } + + return list; +} + +static const char *redirect_match(REDIRECT_REC *redirect, const char *event, + const char *args, int *match_stop) +{ + GSList *tmp, *cmdpos; + int stop_signal; + + for (tmp = redirect->signals; tmp != NULL; tmp = tmp->next->next) { + if (strcmp(tmp->data, event) != 0) + continue; + + /* find the argument position */ + cmdpos = redirect_cmd_list_find(redirect->cmd->start, event); + if (cmdpos != NULL) + stop_signal = FALSE; + else { + cmdpos = redirect_cmd_list_find(redirect->cmd->stop, + event); + stop_signal = cmdpos != NULL; + } + + /* check that arguments match */ + if (args != NULL && redirect->arg != NULL && cmdpos != NULL && + !redirect_args_match(args, redirect->arg, + GPOINTER_TO_INT(cmdpos->next->data))) + continue; + + *match_stop = stop_signal; + return tmp->next->data; + } + + *match_stop = redirect_cmd_list_find(redirect->cmd->stop, + event) != NULL; + return NULL; +} + +static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event, + const char *args, const char **signal, + int *match_stop) +{ + REDIRECT_REC *redirect; + GSList *tmp, *next; + time_t now; + + /* find the redirection */ + *signal = NULL; redirect = NULL; + for (tmp = server->redirects; tmp != NULL; tmp = tmp->next) { + REDIRECT_REC *rec = tmp->data; + + *signal = redirect_match(rec, event, args, match_stop); + if (*signal != NULL) { + redirect = rec; + break; + } + } + + /* remove the destroyed, non-remote and timeouted remote + redirections that should have happened before this redirection */ + now = time(NULL); + for (tmp = server->redirects; tmp != NULL; tmp = next) { + REDIRECT_REC *rec = tmp->data; + + if (rec == redirect) + break; + + next = tmp->next; + if (rec->destroyed || + (rec->remote && (now-rec->created) > rec->cmd->timeout) || + (redirect != NULL && !rec->remote)) { + server->redirects = + g_slist_remove(server->redirects, rec); + if (!rec->destroyed && rec->failure_signal != NULL) { + /* emit the failure signal */ + signal_emit(rec->failure_signal, 1, server); + } + redirect_destroy(rec); + } + } + + return redirect; +} + +const char *server_redirect_get_signal(IRC_SERVER_REC *server, + const char *event, + const char *args) +{ + REDIRECT_REC *redirect; + const char *signal; + int match_stop; + + if (server->redirects == NULL) + return NULL; + + if (server->redirect_continue == NULL) { + /* find the redirection */ + redirect = redirect_find(server, event, args, + &signal, &match_stop); + } else { + /* redirection is already started, now we'll just need to + keep redirecting until stop-event is found. */ + redirect = server->redirect_continue; + signal = redirect_match(redirect, event, NULL, &match_stop); + if (signal == NULL) { + /* unknown event - redirect to the default signal. + FIXME: if stop event isn't properly got, this + could break everything. Add some checks that if + we get eg. 10 different unknown events after this, + or if one of them matches to another redirection, + abort this. */ + signal = redirect->default_signal; + } + } + + if (!match_stop || redirect == NULL) + server->redirect_continue = redirect; + else { + /* stop event - remove this redirection next time this + function is called (can't destroy now or our return + value would be corrupted) */ + redirect->destroyed = TRUE; + server->redirect_continue = NULL; + } + + return signal; +} + +static void sig_disconnected(IRC_SERVER_REC *server) +{ + if (!IS_IRC_SERVER(server)) + return; + + g_slist_foreach(server->redirects, (GFunc) redirect_destroy, NULL); + g_slist_free(server->redirects); + + if (server->redirect_next != NULL) + redirect_destroy(server->redirect_next); +} + +static void cmd_redirect_destroy(char *key, REDIRECT_CMD_REC *cmd) +{ + g_free(key); + redirect_cmd_unref(cmd); +} + +void servers_redirect_init(void) +{ + command_redirects = g_hash_table_new((GHashFunc) g_str_hash, (GCompareFunc) g_str_equal); + + /* WHOIS - register as remote command by default + with a timeout of one minute */ + server_redirect_register("whois", TRUE, 60, + "event 311", 1, /* Begins the WHOIS */ + "event 401", 1, /* No such nick */ + NULL, + "event 318", 1, /* End of WHOIS */ + "event 402", 1, /* No such server */ + NULL); + + /* WHOWAS */ + server_redirect_register("whowas", FALSE, 0, + "event 314", 1, /* Begins the WHOWAS */ + "event 406", 1, /* There was no such nick */ + NULL, + "event 369", 1, /* End of WHOWAS */ + NULL); + + /* WHO */ + server_redirect_register("who", FALSE, 0, + "event 352", 1, /* Begins the WHO */ + "event 401", 1, /* No such nick/channel */ + NULL, + "event 315", 1, /* End of WHO */ + "event 403", 1, /* no such channel */ + NULL); + + /* LIST */ + server_redirect_register("list", FALSE, 0, + "event 321", 1, /* Begins the LIST */ + NULL, + "event 323", 1, /* End of LIST */ + NULL); + + /* ISON */ + server_redirect_register("ison", FALSE, 0, + NULL, + "event 303", 1, /* ISON */ + NULL); + + /* USERHOST */ + server_redirect_register("userhost", FALSE, 0, + "event 401", 1, /* no such nick */ + NULL, + "event 302", 1, /* Userhost */ + "event 461", 1, /* Not enough parameters */ + NULL); + + /* MODE #channel */ + server_redirect_register("mode channel", FALSE, 0, + NULL, + "event 324", 1, /* MODE-reply */ + "event 403", 1, /* no such channel */ + "event 442", 1, /* "you're not on that channel" */ + "event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */ + NULL); + + /* MODE #channel b */ + server_redirect_register("mode b", FALSE, 0, + "event 367", 1, + NULL, + "event 368", 1, /* End of Channel ban List */ + "event 403", 1, /* no such channel */ + "event 442", 1, /* "you're not on that channel" */ + "event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */ + NULL); + + /* MODE #channel e */ + server_redirect_register("mode e", FALSE, 0, + "event 348", 1, + NULL, + "event 349", 1, /* End of ban exceptions */ + "event 482", 1, /* not channel operator - OPN's ircd doesn't want non-ops to see ban exceptions */ + "event 403", 1, /* no such channel */ + "event 442", 1, /* "you're not on that channel" */ + "event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */ + "event 472", -1, /* unknown mode (you should check e-mode's existance from 004 event instead of relying on this) */ + NULL); + + /* MODE #channel I */ + server_redirect_register("mode e", FALSE, 0, + "event 346", 1, + NULL, + "event 347", 1, /* End of invite list */ + "event 403", 1, /* no such channel */ + "event 442", 1, /* "you're not on that channel" */ + "event 479", 1, /* "Cannot join channel (illegal name)" IMHO this is not a logical reply from server. */ + "event 472", -1, /* unknown mode (you should check I-mode's existance from 004 event instead of relying on this) */ + NULL); + + /* PING */ + server_redirect_register("ping", TRUE, 60, + NULL, + "event 402", -1, /* no such server */ + "event pong", -1, /* PONG */ + NULL); + + signal_add("server disconnected", (SIGNAL_FUNC) sig_disconnected); +} + +void servers_redirect_deinit(void) +{ + g_hash_table_foreach(command_redirects, + (GHFunc) cmd_redirect_destroy, NULL); + g_hash_table_destroy(command_redirects); + + signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected); +} diff --git a/src/irc/core/servers-redirect.h b/src/irc/core/servers-redirect.h new file mode 100644 index 00000000..1cb6dac4 --- /dev/null +++ b/src/irc/core/servers-redirect.h @@ -0,0 +1,66 @@ +#ifndef __SERVERS_REDIRECT_H +#define __SERVERS_REDIRECT_H + +/* Register new redirection command. + + remote - Specifies if the command is by default a remote command + (eg. sent to another server). server_redirect_event() may override this. + + timeout - If remote is TRUE, specifies how many seconds to wait for + reply before aborting. + + ... - char *start, int argpos, char *start, int argpos, ..., NULL, + char *stop, int argpos, char *stop, int argpos, ..., NULL + List of events that start and stop this redirection. + Start event list may be just NULL, but there must be at least one + stop event. `argpos' specifies the word number in event string which + is compared to wanted argument, -1 = don't compare, TRUE always. */ +void server_redirect_register(const char *command, + int remote, int timeout, ...); +/* start/stop lists shouldn't be free'd after, and their strings + should be dynamically allocated */ +void server_redirect_register_list(const char *command, + int remote, int timeout, + GSList *start, GSList *stop); + +/* Specify that the next command sent to server will be redirected. + NOTE: This command MUST be called before irc_send_cmd(). + + command - Specifies the registered command that should be used for this + redirection. + + arg - The argument to be compared in event strings. You can give multiple + arguments separated with space. + + remote - Specifies if the command is a remote command, -1 = use default. + + failure_signal - If irssi can't find the stop signal for the redirection, + this signal is called. + + ... - char *event, char *redirect_signal, ..., NULL + If the `event' is "", all the events belonging to the redirection but not + specified here, will be sent there. */ +void server_redirect_event(IRC_SERVER_REC *server, const char *command, + const char *arg, int remote, + const char *failure_signal, ...); +/* Signals list shouldn't be free'd after, and it's strings should be + dynamically allocated */ +void server_redirect_event_list(IRC_SERVER_REC *server, const char *command, + const char *arg, int remote, + const char *failure_signal, GSList *signals); + +/* INTERNAL: */ + +/* irc_send_cmd() calls this to make sure redirecting knows + what's sent to server */ +void server_redirect_command(IRC_SERVER_REC *server, const char *command); +/* Returns the redirection signal for specified event. + This is the function that contains the real redirecting logic. */ +const char *server_redirect_get_signal(IRC_SERVER_REC *server, + const char *event, + const char *args); + +void servers_redirect_init(void); +void servers_redirect_deinit(void); + +#endif diff --git a/src/irc/notifylist/module.h b/src/irc/notifylist/module.h index 546201f6..d88058e4 100644 --- a/src/irc/notifylist/module.h +++ b/src/irc/notifylist/module.h @@ -3,8 +3,6 @@ #define MODULE_NAME "irc/notifylist" -#define ISON_EVENT "event 303" - typedef struct { char *nick; char *user, *host, *realname, *awaymsg; @@ -22,6 +20,8 @@ typedef struct { } NOTIFY_NICK_REC; typedef struct { + int ison_count; /* number of ISON requests sent */ + GSList *notify_users; /* NOTIFY_NICK_REC's of notifylist people who are in IRC */ GSList *ison_tempusers; /* Temporary list for saving /ISON events.. */ } MODULE_SERVER_REC; diff --git a/src/irc/notifylist/notify-ison.c b/src/irc/notifylist/notify-ison.c index 8096c5a9..c515b4d7 100644 --- a/src/irc/notifylist/notify-ison.c +++ b/src/irc/notifylist/notify-ison.c @@ -81,28 +81,19 @@ NOTIFY_NICK_REC *notify_nick_find(IRC_SERVER_REC *server, const char *nick) return NULL; } -static int is_ison_queue_empty(IRC_SERVER_REC *server) +static void ison_send(IRC_SERVER_REC *server, GString *cmd) { - GSList *tmp; - - tmp = server_redirect_getqueue((SERVER_REC *) server, ISON_EVENT, NULL); - for (; tmp != NULL; tmp = tmp->next) { - REDIRECT_REC *rec = tmp->data; - - if (strcmp(rec->name, "notifylist event") == 0) - return FALSE; - } + MODULE_SERVER_REC *mserver; - return TRUE; -} + mserver = MODULE_DATA(server); + mserver->ison_count++; -static void ison_send(IRC_SERVER_REC *server, GString *cmd) -{ g_string_truncate(cmd, cmd->len-1); g_string_prepend(cmd, "ISON :"); + server_redirect_event(server, "ison", NULL, -1, NULL, + "event 303", "notifylist event", NULL); irc_send_cmd(server, cmd->str); - server_redirect_event((SERVER_REC *) server, NULL, 1, ISON_EVENT, "notifylist event", -1, NULL); g_string_truncate(cmd, 0); } @@ -111,6 +102,7 @@ static void ison_send(IRC_SERVER_REC *server, GString *cmd) notify list is in IRC */ static void notifylist_timeout_server(IRC_SERVER_REC *server) { + MODULE_SERVER_REC *mserver; GSList *tmp; GString *cmd; char *nick, *ptr; @@ -121,7 +113,8 @@ static void notifylist_timeout_server(IRC_SERVER_REC *server) if (!IS_IRC_SERVER(server)) return; - if (!is_ison_queue_empty(server)) { + mserver = MODULE_DATA(server); + if (mserver->ison_count > 0) { /* still not received all replies to previous /ISON commands.. */ return; } @@ -184,16 +177,13 @@ static void whois_send(IRC_SERVER_REC *server, char *nicks) for (p = str+strlen(nicks)+1; *p != '\0'; p++) if (*p == ',') *p = ' '; - server_redirect_event((SERVER_REC *) server, str, 2, - "event 318", "notifylist event whois end", 1, - "event 402", "event empty", 1, - "event 401", "event empty", 1, - "event 311", "notifylist event whois", 1, - "event 301", "notifylist event whois away", 1, - "event 312", "event empty", 1, - "event 313", "event empty", 1, - "event 317", "notifylist event whois idle", 1, - "event 319", "event empty", 1, NULL); + server_redirect_event(server, "whois", str, FALSE, + "notifylist event whois end", + "event 318", "notifylist event whois end", + "event 311", "notifylist event whois", + "event 301", "notifylist event whois away", + "event 317", "notifylist event whois idle", + "", "event empty", NULL); g_free(str); } @@ -311,7 +301,7 @@ static void event_ison(IRC_SERVER_REC *server, const char *data) mserver = MODULE_DATA(server); ison_save_users(mserver, online); - if (!is_ison_queue_empty(server)) { + if (--mserver->ison_count > 0) { /* wait for the rest of the /ISON replies */ g_free(params); return; diff --git a/src/irc/notifylist/notify-whois.c b/src/irc/notifylist/notify-whois.c index eb7becd2..c3786294 100644 --- a/src/irc/notifylist/notify-whois.c +++ b/src/irc/notifylist/notify-whois.c @@ -144,8 +144,10 @@ static void event_whois_end(IRC_SERVER_REC *server, const char *data) if (event != NULL) { signal_emit(event, 6, server, rec->nick, - rec->user, rec->host, - rec->realname, rec->awaymsg); + rec->user != NULL ? rec->user : "??", + rec->host != NULL ? rec->host : "??", + rec->realname != NULL ? rec->realname : "??", + rec->awaymsg); } rec->idle_ok = notify->idle_check_time <= 0 || rec->idle_time <= notify->idle_check_time; diff --git a/src/irc/notifylist/notifylist.c b/src/irc/notifylist/notifylist.c index 3d050a9d..0d2b5c21 100644 --- a/src/irc/notifylist/notifylist.c +++ b/src/irc/notifylist/notifylist.c @@ -196,8 +196,6 @@ static void notifylist_init_server(IRC_SERVER_REC *server) rec = g_new0(MODULE_SERVER_REC,1 ); MODULE_DATA_SET(server, rec); - - server_redirect_init((SERVER_REC *) server, "command ison", 1, ISON_EVENT, NULL); } static void notifylist_deinit_server(IRC_SERVER_REC *server) diff --git a/src/perl/common/Server.xs b/src/perl/common/Server.xs index 388c062a..2b214821 100644 --- a/src/perl/common/Server.xs +++ b/src/perl/common/Server.xs @@ -46,47 +46,6 @@ void server_disconnect(server) Irssi::Server server -void -server_redirect_init(server, command, last, ...) - Irssi::Server server - char *command - int last -PREINIT: - STRLEN n_a; - GSList *list; - int n; -CODE: - list = NULL; - for (n = 3; n < items; n++) { - list = g_slist_append(list, SvPV(ST(n), n_a)); - } - server_redirect_initv(server, command, last, list); - -int -server_redirect_single_event(server, arg, last, group, event, signal, argpos) - Irssi::Server server - char *arg - int last - int group - char *event - char *signal - int argpos - -void -server_redirect_event(server, arg, last, ...) - Irssi::Server server - char *arg - int last -PREINIT: - STRLEN n_a; - int n, group; -CODE: - group = 0; - for (n = 3; n+3 <= items; n += 3, last--) { - group = server_redirect_single_event(server, arg, last > 0, group, - (char *) SvPV(ST(n), n_a), (char *) SvPV(ST(n+1), n_a), (int) SvIV(ST(n+2))); - } - int isnickflag(server, flag) Irssi::Server server diff --git a/src/perl/common/module.h b/src/perl/common/module.h index e4843174..5456f630 100644 --- a/src/perl/common/module.h +++ b/src/perl/common/module.h @@ -18,7 +18,6 @@ #include "chatnets.h" #include "servers.h" #include "servers-reconnect.h" -#include "servers-redirect.h" #include "servers-setup.h" #include "channels.h" #include "queries.h" diff --git a/src/perl/irc/Server.xs b/src/perl/irc/Server.xs index 44813fe6..f1d9f62f 100644 --- a/src/perl/irc/Server.xs +++ b/src/perl/irc/Server.xs @@ -35,6 +35,44 @@ ctcp_send_reply(server, data) Irssi::Irc::Server server char *data +MODULE = Irssi::Irc::Server PACKAGE = Irssi::Irc::Server PREFIX = server_ + +void +server_redirect_register(command, remote, timeout, ...) + char *command + int remote + int timeout +PREINIT: + STRLEN n_a; + GSList *start, *stop, **list; + int n; +CODE: + start = stop = NULL; list = &start; + for (n = 3; n < items; n++) { + if (ST(n) == &PL_sv_undef) list = &stop; + if (SvPOK(ST(n))) + *list = g_slist_append(*list, SvPV(ST(n), n_a)); + } + server_redirect_register_list(command, remote, timeout, start, stop); + +void +server_redirect_event(server, command, arg, remote, failure_signal, ...) + Irssi::Irc::Server server + char *command + char *arg + int remote + char *failure_signal +PREINIT: + STRLEN n_a; + GSList *list; + int n; +CODE: + list = NULL; + for (n = 5; n < items; n++) { + list = g_slist_append(list, SvPV(ST(n), n_a)); + } + server_redirect_event_list(server, command, arg, remote, failure_signal, list); + MODULE = Irssi::Irc::Server PACKAGE = Irssi::Irc::Connect PREFIX = irc_server_ Irssi::Irc::Server diff --git a/src/perl/irc/module.h b/src/perl/irc/module.h index 112837a9..d90bb1bf 100644 --- a/src/perl/irc/module.h +++ b/src/perl/irc/module.h @@ -10,6 +10,7 @@ #include "modes.h" #include "mode-lists.h" #include "netsplit.h" +#include "servers-redirect.h" #include "dcc/dcc.h" #include "dcc/dcc-file.h" -- cgit v1.2.3