diff options
-rw-r--r-- | src/irc/core/irc-servers.h | 2 | ||||
-rw-r--r-- | src/irc/core/irc.c | 2 | ||||
-rw-r--r-- | src/irc/core/servers-redirect.c | 99 | ||||
-rw-r--r-- | src/irc/core/servers-redirect.h | 2 | ||||
-rw-r--r-- | src/irc/proxy/listen.c | 4 | ||||
-rw-r--r-- | src/perl/irc/Server.xs | 10 |
6 files changed, 80 insertions, 39 deletions
diff --git a/src/irc/core/irc-servers.h b/src/irc/core/irc-servers.h index 7352b876..cdf5721e 100644 --- a/src/irc/core/irc-servers.h +++ b/src/irc/core/irc-servers.h @@ -42,7 +42,7 @@ struct _IRC_SERVER_REC { GSList *redirects; GSList *redirect_queue; /* should be updated from redirect_next each time cmdqueue is updated */ REDIRECT_REC *redirect_next; - REDIRECT_REC *redirect_continue; + GSList *redirect_active; /* redirects start event has been received for, must have unique prefix */ char *last_nick; /* last /NICK, kept even if it resulted as not valid change */ diff --git a/src/irc/core/irc.c b/src/irc/core/irc.c index 797923be..bcee0987 100644 --- a/src/irc/core/irc.c +++ b/src/irc/core/irc.c @@ -303,7 +303,7 @@ static void irc_server_event(IRC_SERVER_REC *server, const char *line, g_strdown(event); /* check if event needs to be redirected */ - signal = server_redirect_get_signal(server, event, args); + signal = server_redirect_get_signal(server, recoded_nick, event, args); if (signal == NULL) signal = event; else diff --git a/src/irc/core/servers-redirect.c b/src/irc/core/servers-redirect.c index 24b9f98d..fb540c3a 100644 --- a/src/irc/core/servers-redirect.c +++ b/src/irc/core/servers-redirect.c @@ -46,6 +46,7 @@ struct _REDIRECT_REC { REDIRECT_CMD_REC *cmd; time_t created; int failures; + char *prefix; unsigned int destroyed:1; unsigned int aborted:1; @@ -110,6 +111,7 @@ void server_redirect_destroy(REDIRECT_REC *rec) { redirect_cmd_unref(rec->cmd); + g_free_not_null(rec->prefix); g_free_not_null(rec->arg); g_free_not_null(rec->failure_signal); g_free_not_null(rec->default_signal); @@ -386,13 +388,29 @@ static const char *redirect_match(REDIRECT_REC *redirect, const char *event, else { cmdpos = redirect_cmd_list_find(redirect->cmd->stop, event); - match_list = cmdpos != NULL ? MATCH_STOP : MATCH_NONE; + if (cmdpos != NULL) + match_list = MATCH_STOP; + else if (redirect->default_signal != NULL && + args == NULL && + strncmp(event, "event ", 6) == 0 && + i_isdigit(event[6])) { + /* If there is a default signal, the + * redirection has already started and + * this is a numeric, use it */ + /* XXX this should depend on the + * REDIRECT_CMD_REC, not REDIRECT_REC */ + if (signal == NULL) + signal = redirect->default_signal; + match_list = MATCH_START; + } else { + match_list = MATCH_NONE; + } } } if (signal == NULL && cmdpos == NULL) { /* event not found from specified redirection events nor - registered command events */ + registered command events, and no default signal */ return NULL; } @@ -428,8 +446,7 @@ static void redirect_abort(IRC_SERVER_REC *server, REDIRECT_REC *rec) signal_emit(rec->last_signal, 1, server); } - if (server->redirect_continue == rec) - server->redirect_continue = NULL; + server->redirect_active = g_slist_remove(server->redirect_active, rec); server_redirect_destroy(rec); } @@ -452,6 +469,10 @@ static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event, for (tmp = server->redirects; tmp != NULL; tmp = tmp->next) { REDIRECT_REC *rec = tmp->data; + /* already active, don't try to start it again */ + if (g_slist_find(server->redirect_active, rec) != NULL) + continue; + match_signal = redirect_match(rec, event, args, match); if (match_signal != NULL && *match != MATCH_NONE) { redirect = rec; @@ -488,10 +509,13 @@ static REDIRECT_REC *redirect_find(IRC_SERVER_REC *server, const char *event, } static const char * -server_redirect_get(IRC_SERVER_REC *server, const char *event, - const char *args, REDIRECT_REC **redirect, int *match) +server_redirect_get(IRC_SERVER_REC *server, const char *prefix, + const char *event, const char *args, + REDIRECT_REC **redirect, int *match) { const char *signal; + GSList *ptr, *next; + REDIRECT_REC *r; *redirect = NULL; *match = MATCH_NONE; @@ -499,33 +523,39 @@ server_redirect_get(IRC_SERVER_REC *server, const char *event, if (server->redirects == NULL) return NULL; - if (server->redirect_continue == NULL) { - /* find the redirection */ - *redirect = redirect_find(server, event, args, &signal, match); - } else { + for (ptr = server->redirect_active; ptr != NULL; ptr = next) { + next = ptr->next; + r = ptr->data; + if (prefix != NULL && r->prefix != NULL && + strcmp(prefix, r->prefix)) { + /* not from this server */ + continue; + } /* redirection is already started, now we'll just need to keep redirecting until stop-event is found. */ - *redirect = server->redirect_continue; + *redirect = r; signal = redirect_match(*redirect, event, NULL, match); if (signal == NULL) { - /* unknown event - redirect to the default signal. */ - if (strncmp(event, "event ", 6) == 0 && - i_isdigit(event[6])) { - signal = (*redirect)->default_signal; - if (*match == MATCH_NONE) - *match = MATCH_START; - } else { - /* not a numeric, so we've lost the - stop event.. */ - (*redirect)->aborted = TRUE; - redirect_abort(server, *redirect); + /* not a numeric, so we've lost the + stop event.. */ + (*redirect)->aborted = TRUE; + redirect_abort(server, *redirect); - *redirect = NULL; - signal = NULL; - } + *redirect = NULL; } + if (*redirect != NULL) + break; + } + + if (*redirect == NULL) { + /* find the redirection */ + *redirect = redirect_find(server, event, args, &signal, match); } + /* remember which server is replying to our request */ + if (*redirect != NULL && prefix != NULL && (*redirect)->prefix == NULL) + (*redirect)->prefix = g_strdup(prefix); + if (*redirect != NULL && (*redirect)->first_signal != NULL && !(*redirect)->first_signal_sent) { /* emit the first_signal */ @@ -537,6 +567,7 @@ server_redirect_get(IRC_SERVER_REC *server, const char *event, } const char *server_redirect_get_signal(IRC_SERVER_REC *server, + const char *prefix, const char *event, const char *args) { @@ -544,22 +575,26 @@ const char *server_redirect_get_signal(IRC_SERVER_REC *server, const char *signal; int match; - signal = server_redirect_get(server, event, args, &redirect, &match); - if (match != MATCH_STOP || redirect == NULL) - server->redirect_continue = redirect; - else { + signal = server_redirect_get(server, prefix, event, args, &redirect, &match); + if (redirect == NULL) + ; + else if (match != MATCH_STOP) { + if (g_slist_find(server->redirect_active, redirect) == NULL) + server->redirect_active = g_slist_prepend(server->redirect_active, redirect); + } else { /* stop event - remove this redirection next time this function is called (can't destroy now or our return value would be corrupted) */ if (--redirect->count <= 0) redirect->destroyed = TRUE; - server->redirect_continue = NULL; + server->redirect_active = g_slist_remove(server->redirect_active, redirect); } return signal; } const char *server_redirect_peek_signal(IRC_SERVER_REC *server, + const char *prefix, const char *event, const char *args, int *redirected) @@ -568,7 +603,7 @@ const char *server_redirect_peek_signal(IRC_SERVER_REC *server, const char *signal; int match; - signal = server_redirect_get(server, event, args, &redirect, &match); + signal = server_redirect_get(server, prefix, event, args, &redirect, &match); *redirected = match != MATCH_NONE; return signal; } @@ -578,6 +613,8 @@ static void sig_disconnected(IRC_SERVER_REC *server) if (!IS_IRC_SERVER(server)) return; + g_slist_free(server->redirect_active); + server->redirect_active = NULL; g_slist_foreach(server->redirects, (GFunc) server_redirect_destroy, NULL); g_slist_free(server->redirects); diff --git a/src/irc/core/servers-redirect.h b/src/irc/core/servers-redirect.h index c9be1613..6182e3ab 100644 --- a/src/irc/core/servers-redirect.h +++ b/src/irc/core/servers-redirect.h @@ -64,6 +64,7 @@ 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 *prefix, const char *event, const char *args); /* Returns the redirection signal for specified event. @@ -72,6 +73,7 @@ const char *server_redirect_get_signal(IRC_SERVER_REC *server, `redirected' is set to TRUE, if this event belongs to redirection even while there might be no redirection signal. */ const char *server_redirect_peek_signal(IRC_SERVER_REC *server, + const char *prefix, const char *event, const char *args, int *redirected); diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index c250ed16..bab08421 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -391,7 +391,7 @@ static void sig_server_event(IRC_SERVER_REC *server, const char *line, while (*args == ' ') args++; g_strdown(event); - signal = server_redirect_peek_signal(server, event, args, &redirected); + signal = server_redirect_peek_signal(server, nick, event, args, &redirected); if ((signal != NULL && strncmp(signal, "proxy ", 6) != 0) || (signal == NULL && redirected)) { /* we want to send this to one client (or proxy itself) only */ @@ -401,7 +401,7 @@ static void sig_server_event(IRC_SERVER_REC *server, const char *line, } if (signal != NULL) { - server_redirect_get_signal(server, event, args); + server_redirect_get_signal(server, nick, event, args); if (sscanf(signal+6, "%p", &client) == 1) { /* send it to specific client only */ if (g_slist_find(proxy_clients, client) != NULL) diff --git a/src/perl/irc/Server.xs b/src/perl/irc/Server.xs index a3359bbc..a330fb20 100644 --- a/src/perl/irc/Server.xs +++ b/src/perl/irc/Server.xs @@ -116,24 +116,26 @@ CODE: event_hash2list(hvref(signals))); char * -server_redirect_get_signal(server, event, args) +server_redirect_get_signal(server, prefix, event, args) Irssi::Irc::Server server + char *prefix char *event char *args CODE: - RETVAL = (char *) server_redirect_get_signal(server, event, args); + RETVAL = (char *) server_redirect_get_signal(server, prefix, event, args); OUTPUT: RETVAL char * -server_redirect_peek_signal(server, event, args) +server_redirect_peek_signal(server, prefix, event, args) Irssi::Irc::Server server + char *prefix char *event char *args PREINIT: int redirection; CODE: - RETVAL = (char *) server_redirect_peek_signal(server, event, args, &redirection); + RETVAL = (char *) server_redirect_peek_signal(server, prefix, event, args, &redirection); OUTPUT: RETVAL |