diff options
Diffstat (limited to 'src/irc/core')
-rw-r--r-- | src/irc/core/Makefile.am | 6 | ||||
-rw-r--r-- | src/irc/core/channels-query.c | 63 | ||||
-rw-r--r-- | src/irc/core/ctcp.c | 4 | ||||
-rw-r--r-- | src/irc/core/irc-commands.c | 125 | ||||
-rw-r--r-- | src/irc/core/irc-servers.c | 6 | ||||
-rw-r--r-- | src/irc/core/irc-servers.h | 6 | ||||
-rw-r--r-- | src/irc/core/irc.c | 37 | ||||
-rw-r--r-- | src/irc/core/lag.c | 73 | ||||
-rw-r--r-- | src/irc/core/server-idle.h | 22 | ||||
-rw-r--r-- | src/irc/core/servers-idle.c (renamed from src/irc/core/server-idle.c) | 119 | ||||
-rw-r--r-- | src/irc/core/servers-idle.h | 34 | ||||
-rw-r--r-- | src/irc/core/servers-redirect.c | 569 | ||||
-rw-r--r-- | src/irc/core/servers-redirect.h | 66 |
13 files changed, 842 insertions, 288 deletions
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 [<nicks> | <channels> | **] */ @@ -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 [<nicks> [<count>]] */ 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 <nick> - 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.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/server-idle.c b/src/irc/core/servers-idle.c index 9443fdf7..fb979dab 100644 --- a/src/irc/core/server-idle.c +++ b/src/irc/core/servers-idle.c @@ -22,49 +22,54 @@ #include "signals.h" #include "irc-servers.h" -#include "server-idle.h" +#include "servers-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; + 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 *arg, int last, va_list args) +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) { - REDIRECT_IDLE_REC *rrec; SERVER_IDLE_REC *rec; - char *event; + const char *event, *signal; 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; + rec->arg = g_strdup(arg); + rec->tag = ++idlepos; - while ((event = va_arg(args, char *)) != NULL) { - rrec = g_new(REDIRECT_IDLE_REC, 1); - rec->redirects = g_slist_append(rec->redirects, rrec); + 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; + } - rrec->event = g_strdup(event); - rrec->signal = g_strdup(va_arg(args, char *)); - rrec->argpos = va_arg(args, int); + rec->redirects = + g_slist_append(rec->redirects, g_strdup(event)); + rec->redirects = + g_slist_append(rec->redirects, g_strdup(signal)); } return rec; @@ -87,78 +92,82 @@ static SERVER_IDLE_REC *server_idle_find_rec(IRC_SERVER_REC *server, int tag) } /* Add new idle command to queue */ -int server_idle_add(IRC_SERVER_REC *server, const char *cmd, const char *arg, int last, ...) +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 args; + va_list va; SERVER_IDLE_REC *rec; g_return_val_if_fail(server != NULL, -1); - va_start(args, last); - rec = server_idle_create(cmd, arg, last, args); + 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(args); + va_end(va); 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, ...) +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 args; + va_list va; SERVER_IDLE_REC *rec; g_return_val_if_fail(server != NULL, -1); - va_start(args, last); - rec = server_idle_create(cmd, arg, last, args); + 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(args); + va_end(va); 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, ...) +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 args; + va_list va; SERVER_IDLE_REC *rec; int pos; g_return_val_if_fail(server != NULL, -1); - va_start(args, last); + 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, arg, last, args); + 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(args); + va_end(va); + 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_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); } @@ -188,26 +197,20 @@ int server_idle_remove(IRC_SERVER_REC *server, int tag) 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; + 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--; + 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); } 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 |