diff --git a/src/irc/core/channels-query.c b/src/irc/core/channels-query.c index 12f21610..ed2f9083 100644 --- a/src/irc/core/channels-query.c +++ b/src/irc/core/channels-query.c @@ -167,7 +167,7 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) { SERVER_QUERY_REC *rec; IRC_CHANNEL_REC *chanrec; - GSList *tmp, *chans, *newchans; + GSList *chans, *newchans; char *cmd, *chanstr_commas, *chanstr; int onlyone; @@ -206,71 +206,51 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) switch (query) { case CHANNEL_QUERY_MODE: cmd = g_strdup_printf("MODE %s", chanstr_commas); - for (tmp = chans; tmp != NULL; tmp = tmp->next) { - chanrec = tmp->data; - - server_redirect_event(server, "mode channel", chanstr, -1, - "chanquery mode abort", - "event 324", "chanquery mode", - "", "chanquery mode abort", NULL); - } + server_redirect_event(server, "mode channel", chanstr, -1, + "chanquery mode abort", + "event 324", "chanquery mode", + "", "chanquery mode abort", NULL); break; case CHANNEL_QUERY_WHO: cmd = g_strdup_printf("WHO %s", chanstr_commas); - for (tmp = chans; tmp != NULL; tmp = tmp->next) { - chanrec = tmp->data; - - server_redirect_event(server, "who", chanstr, -1, - "chanquery who abort", - "event 315", "chanquery who end", - "event 352", "silent event who", - "", "chanquery who abort", 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; case CHANNEL_QUERY_BMODE: cmd = g_strdup_printf("MODE %s b", chanstr_commas); - for (tmp = chans; tmp != NULL; tmp = tmp->next) { - chanrec = tmp->data; - - /* check all the multichannel problems with all - 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, "mode b", chanstr, -1, - "chanquery mode abort", - "event 367", "chanquery ban", - "event 368", "chanquery ban end", - "", "chanquery mode abort", NULL); - } + /* check all the multichannel problems with all + 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, "mode b", chanstr, -1, + "chanquery mode abort", + "event 367", "chanquery ban", + "event 368", "chanquery ban end", + "", "chanquery mode abort", NULL); break; case CHANNEL_QUERY_EMODE: cmd = g_strdup_printf("MODE %s e", chanstr_commas); - for (tmp = chans; tmp != NULL; tmp = tmp->next) { - chanrec = tmp->data; - - server_redirect_event(server, "mode e", chanstr, -1, - "chanquery mode abort", - "event 348", "chanquery eban", - "event 349", "chanquery eban end", - "", "chanquery mode abort", 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; case CHANNEL_QUERY_IMODE: cmd = g_strdup_printf("MODE %s I", chanstr_commas); - for (tmp = chans; tmp != NULL; tmp = tmp->next) { - chanrec = tmp->data; - - server_redirect_event(server, "mode I", chanstr, -1, - "chanquery mode abort", - "event 346", "chanquery ilist", - "event 347", "chanquery ilist end", - "", "chanquery mode abort", 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; default: diff --git a/src/irc/core/irc-commands.c b/src/irc/core/irc-commands.c index b9fe59b1..18f837e4 100644 --- a/src/irc/core/irc-commands.c +++ b/src/irc/core/irc-commands.c @@ -418,7 +418,6 @@ static void sig_whois_not_found(IRC_SERVER_REC *server, const char *data) server_redirect_event(server, "whowas", nick, -1, NULL, "event 314", "whowas event", "event 369", "whowas event end", - "event 406", "event empty", "", "event empty", NULL); irc_send_cmdv(server, "WHOWAS %s 1", nick); diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index a1310be1..2d4dcbcc 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -211,20 +211,33 @@ static int command_has_target(const char *cmd, const char *target) /* Purge server output, either all or for specified target */ void irc_server_purge_output(IRC_SERVER_REC *server, const char *target) { - GSList *tmp, *next; + GSList *tmp, *next, *link; + REDIRECT_REC *redirect; char *cmd; if (target != NULL && *target == '\0') target = NULL; for (tmp = server->cmdqueue; tmp != NULL; tmp = next) { - next = tmp->next; + next = tmp->next->next; cmd = tmp->data; + redirect = tmp->next->data; if ((target == NULL || command_has_target(cmd, target)) && g_strncasecmp(cmd, "PONG ", 5) != 0) { + /* remove the redirection */ + link = tmp->next; + server->cmdqueue = + g_slist_remove_link(server->cmdqueue, link); + g_slist_free_1(link); + + if (redirect != NULL) + server_redirect_destroy(redirect); + + /* remove the command */ server->cmdqueue = g_slist_remove(server->cmdqueue, cmd); + g_free(cmd); server->cmdcount--; } } @@ -241,10 +254,16 @@ static void sig_connected(IRC_SERVER_REC *server) static void sig_disconnected(IRC_SERVER_REC *server) { + GSList *tmp; + if (!IS_IRC_SERVER(server)) return; - g_slist_foreach(server->cmdqueue, (GFunc) g_free, NULL); + for (tmp = server->cmdqueue; tmp != NULL; tmp = tmp->next->next) { + g_free(tmp->data); + if (tmp->next->data != NULL) + server_redirect_destroy(tmp->next->data); + } g_slist_free(server->cmdqueue); g_free_not_null(server->real_address); @@ -268,6 +287,8 @@ static void sig_server_quit(IRC_SERVER_REC *server, const char *msg) static void server_cmd_timeout(IRC_SERVER_REC *server, GTimeVal *now) { + REDIRECT_REC *redirect; + GSList *link; long usecs; char *cmd; int len; @@ -290,6 +311,7 @@ static void server_cmd_timeout(IRC_SERVER_REC *server, GTimeVal *now) /* send command */ cmd = server->cmdqueue->data; + redirect = server->cmdqueue->next->data; len = strlen(cmd); if (net_sendbuffer_send(server->handle, cmd, len) == -1) { @@ -305,11 +327,15 @@ 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); + server_redirect_command(server, cmd, redirect); /* remove from queue */ g_free(cmd); server->cmdqueue = g_slist_remove(server->cmdqueue, cmd); + + link = server->cmdqueue; + server->cmdqueue = g_slist_remove_link(server->cmdqueue, link); + g_slist_free_1(link); } /* check every now and then if there's data to be sent in command buffer */ diff --git a/src/irc/core/irc-servers.h b/src/irc/core/irc-servers.h index 4866091a..a7322f09 100644 --- a/src/irc/core/irc-servers.h +++ b/src/irc/core/irc-servers.h @@ -38,9 +38,10 @@ struct _IRC_SERVER_REC { #include "server-rec.h" /* For deciding if event should be redirected */ - GSList *redirects; - void *redirect_next; - void *redirect_continue; + GSList *redirects; + GSList *redirect_queue; /* should be updated from redirect_next each time cmdqueue is updated */ + REDIRECT_REC *redirect_next; + REDIRECT_REC *redirect_continue; char *real_address; /* address the irc server gives */ char *usermode; /* The whole mode string .. */ @@ -66,7 +67,7 @@ struct _IRC_SERVER_REC { there actually is, to make flood control remember how many messages can be sent before starting the flood control */ - GSList *cmdqueue; + GSList *cmdqueue; /* command, redirection, ... */ GTimeVal wait_cmd; /* don't send anything to server before this */ GTimeVal last_cmd; /* last time command was sent to server */ diff --git a/src/irc/core/irc.c b/src/irc/core/irc.c index 8b967d4e..b3ab9897 100644 --- a/src/irc/core/irc.c +++ b/src/irc/core/irc.c @@ -64,7 +64,8 @@ void irc_send_cmd_full(IRC_SERVER_REC *server, const char *cmd, if (send_now) { rawlog_output(server->rawlog, cmd); - server_redirect_command(server, cmd); + server_redirect_command(server, cmd, server->redirect_next); + server->redirect_next = NULL; } if (!raw) { @@ -87,9 +88,18 @@ void irc_send_cmd_full(IRC_SERVER_REC *server, const char *cmd, } /* add to queue */ - server->cmdqueue = immediate ? - g_slist_prepend(server->cmdqueue, g_strdup(cmd)) : - g_slist_append(server->cmdqueue, g_strdup(cmd)); + if (immediate) { + server->cmdqueue = g_slist_prepend(server->cmdqueue, + server->redirect_next); + server->cmdqueue = g_slist_prepend(server->cmdqueue, + g_strdup(cmd)); + } else { + server->cmdqueue = g_slist_append(server->cmdqueue, + g_strdup(cmd)); + server->cmdqueue = g_slist_append(server->cmdqueue, + server->redirect_next); + } + server->redirect_next = NULL; } /* Send command to IRC server */ diff --git a/src/irc/core/irc.h b/src/irc/core/irc.h index 3ff3e249..957b1e05 100644 --- a/src/irc/core/irc.h +++ b/src/irc/core/irc.h @@ -5,6 +5,7 @@ typedef struct _IRC_CHATNET_REC IRC_CHATNET_REC; typedef struct _IRC_SERVER_CONNECT_REC IRC_SERVER_CONNECT_REC; typedef struct _IRC_SERVER_REC IRC_SERVER_REC; typedef struct _IRC_CHANNEL_REC IRC_CHANNEL_REC; +typedef struct _REDIRECT_REC REDIRECT_REC; /* From ircd 2.9.5: none I line with ident diff --git a/src/irc/core/servers-redirect.c b/src/irc/core/servers-redirect.c index 814c6b27..dbd89c34 100644 --- a/src/irc/core/servers-redirect.c +++ b/src/irc/core/servers-redirect.c @@ -33,7 +33,7 @@ typedef struct { GSList *start, *stop; /* char *event, int argpos, ... */ } REDIRECT_CMD_REC; -typedef struct { +struct _REDIRECT_REC { REDIRECT_CMD_REC *cmd; time_t created; int destroyed; @@ -42,7 +42,7 @@ typedef struct { int remote; char *failure_signal, *default_signal; GSList *signals; /* event, signal, ... */ -} REDIRECT_REC; +}; static GHashTable *command_redirects; /* "command xxx" : REDIRECT_CMD_REC* */ @@ -88,7 +88,7 @@ static void redirect_cmd_unref(REDIRECT_CMD_REC *rec) redirect_cmd_destroy(rec); } -static void redirect_destroy(REDIRECT_REC *rec) +void server_redirect_destroy(REDIRECT_REC *rec) { redirect_cmd_unref(rec->cmd); @@ -199,7 +199,7 @@ void server_redirect_event_list(IRC_SERVER_REC *server, const char *command, g_return_if_fail((g_slist_length(signals) & 1) == 0); if (server->redirect_next != NULL) { - redirect_destroy(server->redirect_next); + server_redirect_destroy(server->redirect_next); server->redirect_next = NULL; } @@ -232,18 +232,15 @@ void server_redirect_event_list(IRC_SERVER_REC *server, const char *command, server->redirect_next = rec; } -void server_redirect_command(IRC_SERVER_REC *server, const char *command) +void server_redirect_command(IRC_SERVER_REC *server, const char *command, + REDIRECT_REC *redirect) { 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 { + if (redirect == NULL) { cmdrec = redirect_cmd_find(command); if (cmdrec == NULL) return; @@ -252,13 +249,13 @@ void server_redirect_command(IRC_SERVER_REC *server, const char *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; + redirect = g_new0(REDIRECT_REC, 1); + redirect->created = time(NULL); + redirect->cmd = cmdrec; + redirect->remote = cmdrec->remote; } - server->redirects = g_slist_append(server->redirects, rec); + server->redirects = g_slist_append(server->redirects, redirect); } static int redirect_args_match(const char *event_args, @@ -316,35 +313,43 @@ static const char *redirect_match(REDIRECT_REC *redirect, const char *event, const char *args, int *match_stop) { GSList *tmp, *cmdpos; + const char *signal; int stop_signal; + /* get the signal for redirection event - if it's not found we'll + use the default signal */ + signal = NULL; 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; + if (strcmp(tmp->data, event) == 0) { + signal = tmp->next->data; + break; } - - /* 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; + /* 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; + } + + if (signal == NULL && cmdpos == NULL) { + /* event not found from specified redirection events nor + registered command events */ + return 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))) + return NULL; + + *match_stop = stop_signal; + return signal != NULL ? signal : redirect->default_signal; } static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event, @@ -386,7 +391,7 @@ static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event, /* emit the failure signal */ signal_emit(rec->failure_signal, 1, server); } - redirect_destroy(rec); + server_redirect_destroy(rec); } } @@ -404,6 +409,7 @@ const char *server_redirect_get_signal(IRC_SERVER_REC *server, if (server->redirects == NULL) return NULL; + match_stop = FALSE; if (server->redirect_continue == NULL) { /* find the redirection */ redirect = redirect_find(server, event, args, @@ -442,11 +448,12 @@ 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_foreach(server->redirects, + (GFunc) server_redirect_destroy, NULL); g_slist_free(server->redirects); if (server->redirect_next != NULL) - redirect_destroy(server->redirect_next); + server_redirect_destroy(server->redirect_next); } static void cmd_redirect_destroy(char *key, REDIRECT_CMD_REC *cmd) diff --git a/src/irc/core/servers-redirect.h b/src/irc/core/servers-redirect.h index 1cb6dac4..88235600 100644 --- a/src/irc/core/servers-redirect.h +++ b/src/irc/core/servers-redirect.h @@ -53,13 +53,17 @@ void server_redirect_event_list(IRC_SERVER_REC *server, const char *command, /* 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); +void server_redirect_command(IRC_SERVER_REC *server, const char *command, + REDIRECT_REC *redirect); /* 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); +/* Destroy redirection record */ +void server_redirect_destroy(REDIRECT_REC *rec); + void servers_redirect_init(void); void servers_redirect_deinit(void);