diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/irc/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/irc/Makefile.am | 2 | ||||
-rw-r--r-- | src/plugins/irc/irc-channel.c | 2 | ||||
-rw-r--r-- | src/plugins/irc/irc-debug.c | 3 | ||||
-rw-r--r-- | src/plugins/irc/irc-raw.c | 43 | ||||
-rw-r--r-- | src/plugins/irc/irc-raw.h | 21 | ||||
-rw-r--r-- | src/plugins/irc/irc-redirect.c | 1272 | ||||
-rw-r--r-- | src/plugins/irc/irc-redirect.h | 116 | ||||
-rw-r--r-- | src/plugins/irc/irc-server.c | 129 | ||||
-rw-r--r-- | src/plugins/irc/irc-server.h | 3 | ||||
-rw-r--r-- | src/plugins/irc/irc-upgrade.c | 89 | ||||
-rw-r--r-- | src/plugins/irc/irc-upgrade.h | 2 | ||||
-rw-r--r-- | src/plugins/irc/irc.c | 9 |
13 files changed, 1643 insertions, 49 deletions
diff --git a/src/plugins/irc/CMakeLists.txt b/src/plugins/irc/CMakeLists.txt index d751b90da..93ccf9cca 100644 --- a/src/plugins/irc/CMakeLists.txt +++ b/src/plugins/irc/CMakeLists.txt @@ -37,6 +37,7 @@ irc-msgbuffer.c irc-msgbuffer.h irc-nick.c irc-nick.h irc-protocol.c irc-protocol.h irc-raw.c irc-raw.h +irc-redirect.c irc-redirect.h irc-sasl.c irc-sasl.h irc-server.c irc-server.h irc-upgrade.c irc-upgrade.h) diff --git a/src/plugins/irc/Makefile.am b/src/plugins/irc/Makefile.am index da7b374be..105c7eeb8 100644 --- a/src/plugins/irc/Makefile.am +++ b/src/plugins/irc/Makefile.am @@ -61,6 +61,8 @@ irc_la_SOURCES = irc.c \ irc-protocol.h \ irc-raw.c \ irc-raw.h \ + irc-redirect.c \ + irc-redirect.h \ irc-sasl.c \ irc-sasl.h \ irc-server.c \ diff --git a/src/plugins/irc/irc-channel.c b/src/plugins/irc/irc-channel.c index 6271d59a6..6ffed14e0 100644 --- a/src/plugins/irc/irc-channel.c +++ b/src/plugins/irc/irc-channel.c @@ -920,7 +920,7 @@ irc_channel_print_log (struct t_irc_channel *channel) struct t_irc_nick *ptr_nick; weechat_log_printf (""); - weechat_log_printf (" => channel %s (addr:0x%lx)]", channel->name, channel); + weechat_log_printf (" => channel %s (addr:0x%lx):", channel->name, channel); weechat_log_printf (" type . . . . . . . . . . : %d", channel->type); weechat_log_printf (" topic. . . . . . . . . . : '%s'", channel->topic); weechat_log_printf (" modes. . . . . . . . . . : '%s'", channel->modes); diff --git a/src/plugins/irc/irc-debug.c b/src/plugins/irc/irc-debug.c index 3d8a1202c..c46d5a99d 100644 --- a/src/plugins/irc/irc-debug.c +++ b/src/plugins/irc/irc-debug.c @@ -27,6 +27,7 @@ #include "../weechat-plugin.h" #include "irc.h" #include "irc-debug.h" +#include "irc-redirect.h" #include "irc-server.h" @@ -52,6 +53,8 @@ irc_debug_signal_debug_dump_cb (void *data, const char *signal, irc_server_print_log (); + irc_redirect_pattern_print_log (); + weechat_log_printf (""); weechat_log_printf ("***** End of \"%s\" plugin dump *****", weechat_plugin->name); diff --git a/src/plugins/irc/irc-raw.c b/src/plugins/irc/irc-raw.c index d2e5764e4..ba7401d36 100644 --- a/src/plugins/irc/irc-raw.c +++ b/src/plugins/irc/irc-raw.c @@ -211,10 +211,10 @@ irc_raw_message_add_to_list (time_t date, const char *prefix, */ struct t_irc_raw_message * -irc_raw_message_add (struct t_irc_server *server, int send, int modified, +irc_raw_message_add (struct t_irc_server *server, int flags, const char *message) { - char *buf, *buf2, prefix[256]; + char *buf, *buf2, prefix[256], prefix_arrow[16]; const unsigned char *ptr_buf; const char *hexa = "0123456789ABCDEF"; int pos_buf, pos_buf2, char_size, i; @@ -247,16 +247,43 @@ irc_raw_message_add (struct t_irc_server *server, int send, int modified, } buf2[pos_buf2] = '\0'; } + + /* build prefix with arrow */ + prefix_arrow[0] = '\0'; + switch (flags & (IRC_RAW_FLAG_RECV | IRC_RAW_FLAG_SEND + | IRC_RAW_FLAG_MODIFIED | IRC_RAW_FLAG_REDIRECT)) + { + case IRC_RAW_FLAG_RECV: + strcpy (prefix_arrow, IRC_RAW_PREFIX_RECV); + break; + case IRC_RAW_FLAG_RECV | IRC_RAW_FLAG_MODIFIED: + strcpy (prefix_arrow, IRC_RAW_PREFIX_RECV_MODIFIED); + break; + case IRC_RAW_FLAG_RECV | IRC_RAW_FLAG_REDIRECT: + strcpy (prefix_arrow, IRC_RAW_PREFIX_RECV_REDIRECT); + break; + case IRC_RAW_FLAG_SEND: + strcpy (prefix_arrow, IRC_RAW_PREFIX_SEND); + break; + case IRC_RAW_FLAG_SEND | IRC_RAW_FLAG_MODIFIED: + strcpy (prefix_arrow, IRC_RAW_PREFIX_SEND_MODIFIED); + break; + default: + if (flags && IRC_RAW_FLAG_RECV) + strcpy (prefix_arrow, IRC_RAW_PREFIX_RECV); + else + strcpy (prefix_arrow, IRC_RAW_PREFIX_SEND); + break; + } + snprintf (prefix, sizeof (prefix), "%s%s%s%s%s", (server) ? weechat_color ("chat_server") : "", (server) ? server->name : "", (server) ? " " : "", - (send) ? + (flags & IRC_RAW_FLAG_SEND) ? weechat_color ("chat_prefix_quit") : weechat_color ("chat_prefix_join"), - (send) ? - ((modified) ? IRC_RAW_PREFIX_SEND_MOD : IRC_RAW_PREFIX_SEND) : - ((modified) ? IRC_RAW_PREFIX_RECV_MOD : IRC_RAW_PREFIX_RECV)); + prefix_arrow); new_raw_message = irc_raw_message_add_to_list (time (NULL), prefix, @@ -275,7 +302,7 @@ irc_raw_message_add (struct t_irc_server *server, int send, int modified, */ void -irc_raw_print (struct t_irc_server *server, int send, int modified, +irc_raw_print (struct t_irc_server *server, int flags, const char *message) { struct t_irc_raw_message *new_raw_message; @@ -287,7 +314,7 @@ irc_raw_print (struct t_irc_server *server, int send, int modified, if (!irc_raw_buffer && (weechat_irc_plugin->debug >= 1)) irc_raw_open (0); - new_raw_message = irc_raw_message_add (server, send, modified, message); + new_raw_message = irc_raw_message_add (server, flags, message); if (new_raw_message) { if (irc_raw_buffer) diff --git a/src/plugins/irc/irc-raw.h b/src/plugins/irc/irc-raw.h index 1a5cfd61c..bd913e3b0 100644 --- a/src/plugins/irc/irc-raw.h +++ b/src/plugins/irc/irc-raw.h @@ -20,11 +20,18 @@ #ifndef __WEECHAT_IRC_RAW_H #define __WEECHAT_IRC_RAW_H 1 -#define IRC_RAW_BUFFER_NAME "irc_raw" -#define IRC_RAW_PREFIX_RECV "-->" -#define IRC_RAW_PREFIX_RECV_MOD "==>" -#define IRC_RAW_PREFIX_SEND "<--" -#define IRC_RAW_PREFIX_SEND_MOD "<==" +#define IRC_RAW_BUFFER_NAME "irc_raw" + +#define IRC_RAW_PREFIX_RECV "-->" +#define IRC_RAW_PREFIX_RECV_MODIFIED "==>" +#define IRC_RAW_PREFIX_RECV_REDIRECT "R>>" +#define IRC_RAW_PREFIX_SEND "<--" +#define IRC_RAW_PREFIX_SEND_MODIFIED "<==" + +#define IRC_RAW_FLAG_RECV 1 +#define IRC_RAW_FLAG_SEND 2 +#define IRC_RAW_FLAG_MODIFIED 4 +#define IRC_RAW_FLAG_REDIRECT 8 struct t_irc_raw_message { @@ -45,8 +52,8 @@ extern void irc_raw_open (int switch_to_buffer); extern struct t_irc_raw_message *irc_raw_message_add_to_list (time_t date, const char *prefix, const char *message); -extern void irc_raw_print (struct t_irc_server *server, int send, - int modified, const char *message); +extern void irc_raw_print (struct t_irc_server *server, int flags, + const char *message); extern void irc_raw_message_free_all (); extern int irc_raw_add_to_infolist (struct t_infolist *infolist, struct t_irc_raw_message *raw_message); diff --git a/src/plugins/irc/irc-redirect.c b/src/plugins/irc/irc-redirect.c new file mode 100644 index 000000000..d16bc89ab --- /dev/null +++ b/src/plugins/irc/irc-redirect.c @@ -0,0 +1,1272 @@ +/* + * Copyright (C) 2010 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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 3 of the License, or + * (at your option) any later version. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * irc-redirect.c: redirection of IRC command output + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <time.h> + +#include "../weechat-plugin.h" +#include "irc.h" +#include "irc-redirect.h" +#include "irc-server.h" + + +struct t_irc_redirect_pattern *irc_redirect_patterns = NULL; +struct t_irc_redirect_pattern *last_irc_redirect_pattern = NULL; + +/* default redirect patterns */ +struct t_irc_redirect_pattern irc_redirect_patterns_default[] = +{ + { "ison", 0, 0, + /* + * ison: start: - + * stop: 303: ison + * extra: - + */ + NULL, + "303", + NULL, + NULL, NULL, + }, + { "list", 0, 0, + /* + * list: start: 321: /list start + * stop: 323: end of /list + * extra: - + */ + "321", + "323", + NULL, + NULL, NULL, + }, + { "mode_channel", 0, 0, + /* + * mode_channel: start: - + * stop: 324: mode + * 403: no such channel + * 442: not on channel + * 479: cannot join channel (illegal name) + * extra: 329: channel creation date + */ + NULL, + "324:3,403:3,442:3,479:3", + "329:3", + NULL, NULL, + }, + { "mode_channel_ban", 0, 0, /* mode #channel b */ + /* + * mode_channel_ban: start: 367: ban + * stop: 368: end of channel ban list + * 403: no such channel + * 442: not on channel + * 479: cannot join channel (illegal name) + * extra: - + */ + "367:3", + "368:3,403:3,442:3,479:3", + NULL, + NULL, NULL, + }, + { "mode_channel_ban_exception", 0, 0, /* mode #channel e */ + /* + * mode_channel_ban_exception: start: 348: ban exception + * stop: 349: end of ban exceptions + * 403: no such channel + * 442: not on channel + * 472: unknown mode char to me + * 479: cannot join channel (illegal name) + * 482: you're not channel operator + * extra: - + */ + "348:3", + "349:3,403:3,442:3,472,479:3,482:3", + NULL, + NULL, NULL, + }, + { "mode_channel_invite", 0, 0, /* mode #channel I */ + /* + * mode_channel_invite: start: 346: invite + * stop: 347: end of invite list + * 403: no such channel + * 442: not on channel + * 472: unknown mode char to me + * 479: cannot join channel (illegal name) + * 482: you're not channel operator + * extra: - + */ + "346:3", + "347:3,403:3,442:3,472,479:3,482:3", + NULL, + NULL, NULL, + }, + { "mode_user", 0, 0, + /* + * mode_user: start: - + * stop: mode: mode + * 221: user mode string + * 403: no such channel + * 501: unknown mode flag + * 502: can't change mode for other users + * extra; - + */ + NULL, + "mode:2,221:3,403:3,501,502", + NULL, + NULL, NULL, + }, + { "names", 0, 0, + /* + * names: start: 353: list of nicks on channel + * stop: 366: end of /names list + * extra; - + */ + "353:4", + "366:3", + NULL, + NULL, NULL, + }, + { "ping", 0, 0, + /* + * ping: start: - + * stop: pong: pong + * 402: no such server + * extra: - + */ + NULL, + "pong,402", + NULL, + NULL, NULL, + }, + { "time", 0, 0, + /* + * time: start: - + * stop: 391: local time from server + * extra: - + */ + NULL, + "391", + NULL, + NULL, NULL, + }, + { "topic", 0, 0, + /* + * topic: start: - + * stop: 331: no topic is set + * 332: topic + * 403: no such channel + * extra: 333: infos about topic (nick and date changed) + */ + NULL, + "331:3,332:3,403:3", + "333:3", + NULL, NULL, + }, + { "userhost", 0, 0, + /* + * userhost: start: 401: no such nick/channel + * stop: 302: userhost + * 461: not enough parameters + * extra: - + */ + "401:3", + "302,461", + NULL, + NULL, NULL, + }, + { "who", 0, 0, + /* + * who: start: 352: who + * 354: whox + * 401: no such nick/channel + * stop: 315: end of /who list + * 403: no such channel + * extra: - + */ + "352:3,354,401:3", + "315:3,403:3", + NULL, + NULL, NULL, + }, + { "whois", 0, 0, + /* + * whois: start: 311: whois (user) + * stop: 318: whois (end) + * 401: no such nick/channel + * 402: no such server + * 431: no nickname given + * 461: not enough parameters + * extra: 318: whois (end) + */ + "311:3", + "318:3,401:3,402:3,431:3,461", + "318:3", + NULL, NULL, + }, + { "whowas", 0, 0, + /* + * whowas: start: 314: whowas (user) + * 406: there was no such nickname + * stop: 369: end of whowas + * extra: - + */ + "314:3,406:3", + "369:3", + NULL, + NULL, NULL, + }, + { NULL, 0, 0, NULL, NULL, NULL, NULL, NULL } +}; + + +/* + * irc_redirect_pattern_search: search a redirect pattern in list of patterns + */ + +struct t_irc_redirect_pattern * +irc_redirect_pattern_search (const char *name) +{ + struct t_irc_redirect_pattern *ptr_redirect_pattern; + + if (!name) + return NULL; + + for (ptr_redirect_pattern = irc_redirect_patterns; ptr_redirect_pattern; + ptr_redirect_pattern = ptr_redirect_pattern->next_redirect) + { + if (strcmp (ptr_redirect_pattern->name, name) == 0) + return ptr_redirect_pattern; + } + + /* redirect pattern not found */ + return NULL; +} + +/* + * irc_redirect_pattern_new: create a new redirect pattern + */ + +struct t_irc_redirect_pattern * +irc_redirect_pattern_new (const char *name, int temp_pattern, int timeout, + const char *cmd_start, const char *cmd_stop, + const char *cmd_extra) +{ + struct t_irc_redirect_pattern *ptr_redirect_pattern, *new_redirect_pattern; + + if (!name) + return NULL; + + if (!cmd_stop || !cmd_stop[0]) + { + weechat_printf (NULL, + _("%s%s: missing argument \"%s\" for redirect pattern"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, + "cmd_stop"); + return NULL; + } + + /* check if redirect pattern already exists */ + ptr_redirect_pattern = irc_redirect_pattern_search (name); + if (ptr_redirect_pattern) + { + weechat_printf (NULL, + _("%s%s: redirect pattern \"%s\" already exists"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, + name); + return NULL; + } + + new_redirect_pattern = malloc (sizeof (*new_redirect_pattern)); + if (!new_redirect_pattern) + return NULL; + + /* initialize new redirect */ + new_redirect_pattern->name = strdup (name); + new_redirect_pattern->temp_pattern = temp_pattern; + new_redirect_pattern->timeout = (timeout > 0) ? timeout : IRC_REDIRECT_TIMEOUT_DEFAULT; + new_redirect_pattern->cmd_start = (cmd_start) ? strdup (cmd_start) : NULL; + new_redirect_pattern->cmd_stop = strdup (cmd_stop); + new_redirect_pattern->cmd_extra = (cmd_extra) ? strdup (cmd_extra) : NULL; + + /* add redirect pattern to end of list */ + new_redirect_pattern->prev_redirect = last_irc_redirect_pattern; + if (irc_redirect_patterns) + last_irc_redirect_pattern->next_redirect = new_redirect_pattern; + else + irc_redirect_patterns = new_redirect_pattern; + last_irc_redirect_pattern = new_redirect_pattern; + new_redirect_pattern->next_redirect = NULL; + + return new_redirect_pattern; +} + +/* + * irc_redirect_pattern_free: free a redirect pattern and remove it from list + */ + +void +irc_redirect_pattern_free (struct t_irc_redirect_pattern *redirect_pattern) +{ + struct t_irc_redirect_pattern *new_redirect_patterns; + + if (!redirect_pattern) + return; + + /* remove redirect */ + if (last_irc_redirect_pattern == redirect_pattern) + last_irc_redirect_pattern = redirect_pattern->prev_redirect; + if (redirect_pattern->prev_redirect) + { + (redirect_pattern->prev_redirect)->next_redirect = redirect_pattern->next_redirect; + new_redirect_patterns = irc_redirect_patterns; + } + else + new_redirect_patterns = redirect_pattern->next_redirect; + + if (redirect_pattern->next_redirect) + (redirect_pattern->next_redirect)->prev_redirect = redirect_pattern->prev_redirect; + + /* free data */ + if (redirect_pattern->name) + free (redirect_pattern->name); + if (redirect_pattern->cmd_start) + free (redirect_pattern->cmd_start); + if (redirect_pattern->cmd_stop) + free (redirect_pattern->cmd_stop); + if (redirect_pattern->cmd_extra) + free (redirect_pattern->cmd_extra); + + free (redirect_pattern); + + irc_redirect_patterns = new_redirect_patterns; +} + +/* + * irc_redirect_pattern_free_all: free all redirect patterns + */ + +void +irc_redirect_pattern_free_all () +{ + while (irc_redirect_patterns) + { + irc_redirect_pattern_free (irc_redirect_patterns); + } +} + +/* + * irc_redirect_new_with_commands: create a new redirect for a command on a + * server (with start/stop/extra commands in + * arguments) + */ + +struct t_irc_redirect * +irc_redirect_new_with_commands (struct t_irc_server *server, + const char *pattern, const char *signal, + int count, const char *string, int timeout, + const char *cmd_start, + const char *cmd_stop, + const char *cmd_extra, + const char *cmd_filter) +{ + struct t_irc_redirect *new_redirect; + char **items[4], *pos, *error; + int i, j, num_items[4]; + long value; + struct t_hashtable *hash_cmd[4]; + + new_redirect = malloc (sizeof (*new_redirect)); + if (!new_redirect) + return NULL; + + /* create hashtables with commands */ + for (i = 0; i < 4; i++) + { + hash_cmd[i] = NULL; + items[i] = NULL; + } + if (cmd_start) + items[0] = weechat_string_split (cmd_start, ",", 0, 0, &num_items[0]); + if (cmd_stop) + items[1] = weechat_string_split (cmd_stop, ",", 0, 0, &num_items[1]); + if (cmd_extra) + items[2] = weechat_string_split (cmd_extra, ",", 0, 0, &num_items[2]); + if (cmd_filter) + items[3] = weechat_string_split (cmd_filter, ",", 0, 0, &num_items[3]); + for (i = 0; i < 4; i++) + { + if (items[i]) + { + hash_cmd[i] = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_INTEGER, + NULL, + NULL); + for (j = 0; j < num_items[i]; j++) + { + if (i < 3) + { + value = -1; + pos = strchr (items[i][j], ':'); + if (pos) + { + pos[0] = '\0'; + value = strtol (pos + 1, &error, 10); + if (!error || error[0]) + value = -1; + } + weechat_string_toupper (items[i][j]); + weechat_hashtable_set (hash_cmd[i], items[i][j], &value); + } + else + { + weechat_hashtable_set (hash_cmd[i], items[i][j], NULL); + } + } + weechat_string_free_split (items[i]); + } + } + + /* initialize new redirect */ + new_redirect->server = server; + new_redirect->pattern = strdup (pattern); + new_redirect->signal = strdup (signal); + new_redirect->count = (count >= 1) ? count : 1; + new_redirect->current_count = 1; + new_redirect->string = (string) ? strdup (string) : NULL; + new_redirect->timeout = timeout; + new_redirect->command = NULL; + new_redirect->start_time = 0; + new_redirect->cmd_start = hash_cmd[0]; + new_redirect->cmd_stop = hash_cmd[1]; + new_redirect->cmd_extra = hash_cmd[2]; + new_redirect->cmd_start_received = 0; + new_redirect->cmd_stop_received = 0; + new_redirect->cmd_filter = hash_cmd[3]; + new_redirect->output = NULL; + new_redirect->output_size = 0; + + /* add redirect to end of list */ + new_redirect->prev_redirect = server->last_redirect; + if (server->redirects) + (server->last_redirect)->next_redirect = new_redirect; + else + server->redirects = new_redirect; + server->last_redirect = new_redirect; + new_redirect->next_redirect = NULL; + + return new_redirect; +} + +/* + * irc_redirect_new: create a new redirect for a command on a server + */ + +struct t_irc_redirect * +irc_redirect_new (struct t_irc_server *server, + const char *pattern, const char *signal, + int count, const char *string, int timeout, + const char *cmd_filter) +{ + struct t_irc_redirect_pattern *ptr_redirect_pattern; + struct t_irc_redirect *new_redirect; + + if (!server->is_connected) + { + weechat_printf (NULL, + _("%s%s: no connection to server \"%s\" for redirect"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, + server->name); + return NULL; + } + + if (!pattern || !pattern[0]) + { + weechat_printf (NULL, _("%s%s: missing argument \"%s\" for redirect"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "pattern"); + return NULL; + } + if (!signal || !signal[0]) + { + weechat_printf (NULL, _("%s%s: missing argument \"%s\" for redirect"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "signal"); + return NULL; + } + + ptr_redirect_pattern = irc_redirect_pattern_search (pattern); + if (!ptr_redirect_pattern) + { + weechat_printf (NULL, _("%s%s: redirect pattern \"%s\" not found"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, + pattern); + return NULL; + } + + new_redirect = irc_redirect_new_with_commands (server, pattern, signal, + count, string, + (timeout > 0) ? timeout : ptr_redirect_pattern->timeout, + ptr_redirect_pattern->cmd_start, + ptr_redirect_pattern->cmd_stop, + ptr_redirect_pattern->cmd_extra, + cmd_filter); + + /* + * remove redirect pattern if it is temporary (created by external + * plugin/script) + */ + if (new_redirect && ptr_redirect_pattern->temp_pattern) + irc_redirect_pattern_free (ptr_redirect_pattern); + + irc_redirect_print_log (server); + + return new_redirect; +} + +/* + * irc_redirect_search_available: search first redirect available for server + */ + +struct t_irc_redirect * +irc_redirect_search_available (struct t_irc_server *server) +{ + struct t_irc_redirect *ptr_redirect; + + if (!server) + return NULL; + + for (ptr_redirect = server->redirects; ptr_redirect; + ptr_redirect = ptr_redirect->next_redirect) + { + if (ptr_redirect->start_time == 0) + return ptr_redirect; + } + + /* no redirect available */ + return NULL; +} + +/* + * irc_redirect_init_command: initalize a redirect with IRC command sent to + * server + */ + +void +irc_redirect_init_command (struct t_irc_redirect *redirect, + const char *command) +{ + char *pos; + + if (!redirect) + return; + + if (command) + { + pos = strchr (command, '\r'); + if (!pos) + pos = strchr (command, '\n'); + if (pos) + redirect->command = weechat_strndup (command, pos - command); + else + redirect->command = strdup (command); + } + else + redirect->command = NULL; + + redirect->start_time = time (NULL); + + if (weechat_irc_plugin->debug >= 2) + { + weechat_printf (redirect->server->buffer, + _("%s: starting redirection for command \"%s\" " + "on server \"%s\" (redirect pattern: \"%s\")"), + IRC_PLUGIN_NAME, + redirect->command, + redirect->server->name, + redirect->pattern); + } +} + +/* + * irc_redirect_message_match_hash: return 1 if a message matches hashtable + * with commands, 0 if it doesn't match + */ + +int +irc_redirect_message_match_hash (struct t_irc_redirect *redirect, + char **message_argv, int message_argc, + const char *command, + struct t_hashtable *cmd_hash) +{ + int *value; + + value = weechat_hashtable_get (cmd_hash, command); + if (!value) + return 0; + + /* + * if string is in redirect and that this command requires string to + * be in message, then search for this string + */ + if (redirect->string && redirect->string[0] && (*value >= 0)) + { + if (*value >= message_argc) + return 0; + + if (strcmp (message_argv[*value], redirect->string) != 0) + return 0; + } + + return 1; +} + +/* + * irc_redirect_message_add: add a message to redirect output + */ + +void +irc_redirect_message_add (struct t_irc_redirect *redirect, const char *message, + const char *command) +{ + /* + * if command is not for output, then don't add message + * (it is silently ignored) + */ + if (redirect->cmd_filter + && !weechat_hashtable_has_key (redirect->cmd_filter, command)) + return; + + /* add message to output */ + if (redirect->output) + { + redirect->output_size += strlen("\n") + strlen (message); + redirect->output = realloc (redirect->output, redirect->output_size); + if (redirect->output) + strcat (redirect->output, "\n"); + } + else + { + redirect->output_size = strlen (message) + 1; + redirect->output = malloc (redirect->output_size); + if (redirect->output) + redirect->output[0] = '\0'; + } + if (redirect->output) + strcat (redirect->output, message); +} + +/* + * irc_redirect_stop: end of a redirection: send data to callback and free + * redirect (if count has been reached) + */ + +void +irc_redirect_stop (struct t_irc_redirect *redirect, const char *error) +{ + struct t_hashtable *hashtable; + char signal_name[1024], str_int[64]; + + redirect->current_count++; + + if (error || (redirect->current_count > redirect->count)) + { + /* + * error or max count reached, then we run callback and remove + * redirect + */ + hashtable = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + if (hashtable) + { + /* set error and output (main fields) */ + weechat_hashtable_set (hashtable, "error", + (error) ? (char *)error : ""); + weechat_hashtable_set (hashtable, "output", + (redirect->output) ? redirect->output : ""); + snprintf (str_int, sizeof (str_int), "%d", redirect->output_size); + weechat_hashtable_set (hashtable, "output_size", str_int); + + /* set some other fields with values from redirect */ + weechat_hashtable_set (hashtable, "server", redirect->server->name); + weechat_hashtable_set (hashtable, "pattern", redirect->pattern); + weechat_hashtable_set (hashtable, "signal", redirect->signal); + weechat_hashtable_set (hashtable, "command", redirect->command); + } + + snprintf (signal_name, sizeof (signal_name), "irc_redirection_%s_%s", + redirect->signal, redirect->pattern); + weechat_hook_hsignal_send (signal_name, hashtable); + + if (hashtable) + weechat_hashtable_free (hashtable); + + irc_redirect_free (redirect); + } + else + { + /* + * max count not yet reached, then we prepare redirect to continue + * redirection + */ + redirect->cmd_start_received = 0; + redirect->cmd_stop_received = 0; + } +} + +/* + * irc_redirect_message: try to redirect a received message (from IRC server) + * to a redirect in server + * return: 1 if message has been redirected + * 0 if no matching redirect was found + * if message has been redirected, irc plugin will + * discard it (do not display anything) + */ + +int +irc_redirect_message (struct t_irc_server *server, const char *message, + const char *command) +{ + struct t_irc_redirect *ptr_redirect, *ptr_next_redirect; + int rc, match_stop, message_argc; + char **message_argv; + + if (!server || !server->redirects || !message || !command) + return 0; + + rc = 0; + + message_argv = weechat_string_split (message, " ", 0, 0, &message_argc); + + ptr_redirect = server->redirects; + while (ptr_redirect) + { + ptr_next_redirect = ptr_redirect->next_redirect; + + if (ptr_redirect->start_time > 0) + { + if (ptr_redirect->cmd_stop_received) + { + if (ptr_redirect->cmd_extra + && irc_redirect_message_match_hash (ptr_redirect, + message_argv, + message_argc, + command, + ptr_redirect->cmd_extra)) + { + irc_redirect_message_add (ptr_redirect, message, command); + irc_redirect_stop (ptr_redirect, NULL); + rc = 1; + goto end; + } + irc_redirect_stop (ptr_redirect, NULL); + } + else + { + /* message matches a start command? */ + if (ptr_redirect->cmd_start + && !ptr_redirect->cmd_start_received + && irc_redirect_message_match_hash (ptr_redirect, + message_argv, + message_argc, + command, + ptr_redirect->cmd_start)) + { + /* + * message is a start command for redirection, then add + * message to output for redirection and mark start + * command as "received" for this redirect + */ + irc_redirect_message_add (ptr_redirect, message, command); + ptr_redirect->cmd_start_received = 1; + rc = 1; + goto end; + } + /* + * if matching stop command, or start command received, we are + * in redirection: add message to output and close redirection + * if matching stop command + */ + match_stop = irc_redirect_message_match_hash (ptr_redirect, + message_argv, + message_argc, + command, + ptr_redirect->cmd_stop); + if (match_stop || ptr_redirect->cmd_start_received) + { + /* + * add message to output if matching stop of if command + * is numeric + */ + irc_redirect_message_add (ptr_redirect, message, command); + if (match_stop) + { + ptr_redirect->cmd_stop_received = 1; + if (ptr_redirect->cmd_extra) + { + if (irc_redirect_message_match_hash (ptr_redirect, + message_argv, + message_argc, + command, + ptr_redirect->cmd_extra)) + { + /* + * this command is a stop and extra command, + * then remove redirect + */ + irc_redirect_stop (ptr_redirect, NULL); + } + } + else + { + /* + * no extra command after stop, then remove + * redirect + */ + irc_redirect_stop (ptr_redirect, NULL); + } + } + rc = 1; + goto end; + } + } + } + + ptr_redirect = ptr_next_redirect; + } + +end: + if (message_argv) + weechat_string_free_split (message_argv); + + return rc; +} + +/* + * irc_redirect_free: free a redirect and remove it from list + */ + +void +irc_redirect_free (struct t_irc_redirect *redirect) +{ + struct t_irc_server *server; + struct t_irc_redirect *new_redirects; + int priority; + struct t_irc_outqueue *ptr_outqueue; + + if (!redirect) + return; + + server = redirect->server; + + /* remove redirect */ + if (server->last_redirect == redirect) + server->last_redirect = redirect->prev_redirect; + if (redirect->prev_redirect) + { + (redirect->prev_redirect)->next_redirect = redirect->next_redirect; + new_redirects = server->redirects; + } + else + new_redirects = redirect->next_redirect; + + if (redirect->next_redirect) + (redirect->next_redirect)->prev_redirect = redirect->prev_redirect; + + /* remove any pointer to this redirect */ + for (priority = 0; priority < IRC_SERVER_NUM_OUTQUEUES_PRIO; priority++) + { + for (ptr_outqueue = server->outqueue[priority]; ptr_outqueue; + ptr_outqueue = ptr_outqueue->next_outqueue) + { + if (ptr_outqueue->redirect == redirect) + ptr_outqueue->redirect = NULL; + } + } + + /* free data */ + if (redirect->pattern) + free (redirect->pattern); + if (redirect->signal) + free (redirect->signal); + if (redirect->string) + free (redirect->string); + if (redirect->command) + free (redirect->command); + if (redirect->cmd_start) + weechat_hashtable_free (redirect->cmd_start); + if (redirect->cmd_stop) + weechat_hashtable_free (redirect->cmd_stop); + if (redirect->cmd_extra) + weechat_hashtable_free (redirect->cmd_extra); + if (redirect->cmd_filter) + weechat_hashtable_free (redirect->cmd_filter); + if (redirect->output) + free (redirect->output); + + free (redirect); + + server->redirects = new_redirects; +} + +/* + * irc_redirect_free_all: free all redirects in list + */ + +void +irc_redirect_free_all (struct t_irc_server *server) +{ + while (server->redirects) + { + irc_redirect_free (server->redirects); + } +} + +/* + * irc_redirect_pattern_add_to_infolist: add a redirect pattern in an infolist + * return 1 if ok, 0 if error + */ + +int +irc_redirect_pattern_add_to_infolist (struct t_infolist *infolist, + struct t_irc_redirect_pattern *redirect_pattern) +{ + struct t_infolist_item *ptr_item; + + if (!infolist || !redirect_pattern) + return 0; + + ptr_item = weechat_infolist_new_item (infolist); + if (!ptr_item) + return 0; + + if (!weechat_infolist_new_var_string (ptr_item, "name", redirect_pattern->name)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "temp_pattern", redirect_pattern->temp_pattern)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "timeout", redirect_pattern->timeout)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "cmd_start", redirect_pattern->cmd_start)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "cmd_stop", redirect_pattern->cmd_stop)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "cmd_extra", redirect_pattern->cmd_extra)) + return 0; + + return 1; +} + +/* + * irc_redirect_add_to_infolist: add a redirect in an infolist + * return 1 if ok, 0 if error + */ + +int +irc_redirect_add_to_infolist (struct t_infolist *infolist, + struct t_irc_redirect *redirect) +{ + struct t_infolist_item *ptr_item; + + if (!infolist || !redirect) + return 0; + + ptr_item = weechat_infolist_new_item (infolist); + if (!ptr_item) + return 0; + + if (!weechat_infolist_new_var_pointer (ptr_item, "server", redirect->server)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "server_name", redirect->server->name)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "pattern", redirect->pattern)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "signal", redirect->signal)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "count", redirect->count)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "current_count", redirect->current_count)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "string", redirect->string)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "timeout", redirect->timeout)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "command", redirect->command)) + return 0; + if (!weechat_infolist_new_var_time (ptr_item, "start_time", redirect->start_time)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "cmd_start", weechat_hashtable_get_string (redirect->cmd_start, "keys_values"))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "cmd_stop", weechat_hashtable_get_string (redirect->cmd_stop, "keys_values"))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "cmd_extra", weechat_hashtable_get_string (redirect->cmd_extra, "keys_values"))) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "cmd_start_received", redirect->cmd_start_received)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "cmd_stop_received", redirect->cmd_stop_received)) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "cmd_filter", weechat_hashtable_get_string (redirect->cmd_filter, "keys_values"))) + return 0; + if (!weechat_infolist_new_var_string (ptr_item, "output", redirect->output)) + return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "output_size", redirect->output_size)) + return 0; + + return 1; +} + +/* + * irc_redirect_pattern_print_log: print redirect infos in log (usually for + * crash dump) + */ + +void +irc_redirect_pattern_print_log () +{ + struct t_irc_redirect_pattern *ptr_redirect_pattern; + + for (ptr_redirect_pattern = irc_redirect_patterns; ptr_redirect_pattern; + ptr_redirect_pattern = ptr_redirect_pattern->next_redirect) + { + weechat_log_printf (""); + weechat_log_printf ("[redirect_pattern (addr:0x%lx)]", ptr_redirect_pattern); + weechat_log_printf (" name . . . . . . . . : '%s'", ptr_redirect_pattern->name); + weechat_log_printf (" temp_pattern . . . . : %d", ptr_redirect_pattern->temp_pattern); + weechat_log_printf (" timeout. . . . . . . : %d", ptr_redirect_pattern->timeout); + weechat_log_printf (" cmd_start. . . . . . : '%s'", ptr_redirect_pattern->cmd_start); + weechat_log_printf (" cmd_stop . . . . . . : '%s'", ptr_redirect_pattern->cmd_stop); + weechat_log_printf (" cmd_extra. . . . . . : '%s'", ptr_redirect_pattern->cmd_extra); + weechat_log_printf (" prev_redirect. . . . : 0x%lx", ptr_redirect_pattern->prev_redirect); + weechat_log_printf (" next_redirect. . . . : 0x%lx", ptr_redirect_pattern->next_redirect); + } +} + +/* + * irc_redirect_print_log: print redirect infos in log (usually for crash dump) + */ + +void +irc_redirect_print_log (struct t_irc_server *server) +{ + struct t_irc_redirect *ptr_redirect; + + for (ptr_redirect = server->redirects; ptr_redirect; + ptr_redirect = ptr_redirect->next_redirect) + { + weechat_log_printf (""); + weechat_log_printf (" => redirect (addr:0x%lx):", ptr_redirect); + weechat_log_printf (" server. . . . . . . : 0x%lx ('%s')", + ptr_redirect->server, ptr_redirect->server->name); + weechat_log_printf (" pattern . . . . . . : '%s'", ptr_redirect->pattern); + weechat_log_printf (" signal. . . . . . . : '%s'", ptr_redirect->signal); + weechat_log_printf (" count . . . . . . . : %d", ptr_redirect->count); + weechat_log_printf (" current_count . . . : %d", ptr_redirect->current_count); + weechat_log_printf (" string. . . . . . . : '%s'", ptr_redirect->string); + weechat_log_printf (" timeout . . . . . . : %d", ptr_redirect->timeout); + weechat_log_printf (" command . . . . . . : '%s'", ptr_redirect->command); + weechat_log_printf (" start_time. . . . . : %ld", ptr_redirect->start_time); + weechat_log_printf (" cmd_start . . . . . : 0x%lx (hashtable: '%s')", + ptr_redirect->cmd_start, + weechat_hashtable_get_string (ptr_redirect->cmd_start, "keys_values")); + weechat_log_printf (" cmd_stop. . . . . . : 0x%lx (hashtable: '%s')", + ptr_redirect->cmd_stop, + weechat_hashtable_get_string (ptr_redirect->cmd_stop, "keys_values")); + weechat_log_printf (" cmd_extra . . . . . : 0x%lx (hashtable: '%s')", + ptr_redirect->cmd_extra, + weechat_hashtable_get_string (ptr_redirect->cmd_extra, "keys_values")); + weechat_log_printf (" cmd_start_received. : %d", ptr_redirect->cmd_start_received); + weechat_log_printf (" cmd_stop_received . : %d", ptr_redirect->cmd_stop_received); + weechat_log_printf (" cmd_filter. . . . . : 0x%lx (hashtable: '%s')", + ptr_redirect->cmd_filter, + weechat_hashtable_get_string (ptr_redirect->cmd_filter, "keys_values")); + weechat_log_printf (" output. . . . . . . : '%s'", ptr_redirect->output); + weechat_log_printf (" output_size . . . . : %d", ptr_redirect->output_size); + weechat_log_printf (" prev_redirect . . . : 0x%lx", ptr_redirect->prev_redirect); + weechat_log_printf (" next_redirect . . . : 0x%lx", ptr_redirect->next_redirect); + } +} + +/* + * irc_redirect_pattern_hsignal_cb: callback for hsignal "irc_redirect_pattern" + * It is called when other plugins/scripts are + * creating a redirect pattern (irc plugin + * itself does not use this function) + */ + +int +irc_redirect_pattern_hsignal_cb (void *data, const char *signal, + struct t_hashtable *hashtable) +{ + const char *pattern, *str_timeout, *cmd_start, *cmd_stop, *cmd_extra; + char *error; + int number, timeout; + + /* make C compiler happy */ + (void) data; + (void) signal; + + if (!hashtable) + return WEECHAT_RC_ERROR; + + pattern = weechat_hashtable_get (hashtable, "pattern"); + str_timeout = weechat_hashtable_get (hashtable, "timeout"); + cmd_start = weechat_hashtable_get (hashtable, "cmd_start"); + cmd_stop = weechat_hashtable_get (hashtable, "cmd_stop"); + cmd_extra = weechat_hashtable_get (hashtable, "cmd_extra"); + + if (!pattern || !pattern[0]) + { + weechat_printf (NULL, + _("%s%s: missing argument \"%s\" for redirect " + "pattern"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "pattern"); + return WEECHAT_RC_ERROR; + } + + if (!cmd_stop || !cmd_stop[0]) + { + weechat_printf (NULL, + _("%s%s: missing argument \"%s\" for redirect " + "pattern"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "cmd_stop"); + return WEECHAT_RC_ERROR; + } + + timeout = 0; + if (str_timeout && str_timeout[0]) + { + number = (int)strtol (str_timeout, &error, 10); + if (error && !error[0]) + timeout = number; + } + + /* + * create a temporary redirect pattern (it will be removed when a + * redirect will use it) + */ + irc_redirect_pattern_new (pattern, 1, timeout, + cmd_start, cmd_stop, cmd_extra); + + return WEECHAT_RC_OK; +} + +/* + * irc_redirect_command_hsignal_cb: callback for hsignal "irc_redirect_command" + * It is called when other plugins/scripts are + * redirecting an IRC command (irc plugin + * itself does not use this function) + */ + +int +irc_redirect_command_hsignal_cb (void *data, const char *signal, + struct t_hashtable *hashtable) +{ + const char *server, *pattern, *redirect_signal, *str_count, *string; + const char *str_timeout, *cmd_filter; + char *error; + struct t_irc_server *ptr_server; + int number, count, timeout; + + /* make C compiler happy */ + (void) data; + (void) signal; + + if (!hashtable) + return WEECHAT_RC_ERROR; + + server = weechat_hashtable_get (hashtable, "server"); + pattern = weechat_hashtable_get (hashtable, "pattern"); + redirect_signal = weechat_hashtable_get (hashtable, "signal"); + str_count = weechat_hashtable_get (hashtable, "count"); + string = weechat_hashtable_get (hashtable, "string"); + str_timeout = weechat_hashtable_get (hashtable, "timeout"); + cmd_filter = weechat_hashtable_get (hashtable, "cmd_filter"); + + if (!server || !server[0]) + { + weechat_printf (NULL, + _("%s%s: missing argument \"%s\" for redirect"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, "server"); + return WEECHAT_RC_ERROR; + } + ptr_server = irc_server_search (server); + if (!ptr_server) + { + weechat_printf (NULL, + _("%s%s: server \"%s\" not found for redirect"), + weechat_prefix ("error"), IRC_PLUGIN_NAME, server); + return WEECHAT_RC_ERROR; + } + + count = 1; + if (str_count && str_count[0]) + { + number = (int)strtol (str_count, &error, 10); + if (error && !error[0]) + count = number; + } + + timeout = 0; + if (str_timeout && str_timeout[0]) + { + number = (int)strtol (str_timeout, &error, 10); + if (error && !error[0]) + timeout = number; + } + + irc_redirect_new (ptr_server, pattern, redirect_signal, + count, string, timeout, cmd_filter); + + return WEECHAT_RC_OK; +} + +/* + * irc_redirect_init: create default redirect patterns + */ + +void +irc_redirect_init () +{ + int i; + + for (i = 0; irc_redirect_patterns_default[i].name; i++) + { + irc_redirect_pattern_new (irc_redirect_patterns_default[i].name, + 0, + irc_redirect_patterns_default[i].timeout, + irc_redirect_patterns_default[i].cmd_start, + irc_redirect_patterns_default[i].cmd_stop, + irc_redirect_patterns_default[i].cmd_extra); + } +} + +/* + * irc_redirect_end: free all redirect patterns + */ + +void +irc_redirect_end () +{ + irc_redirect_pattern_free_all (); +} diff --git a/src/plugins/irc/irc-redirect.h b/src/plugins/irc/irc-redirect.h new file mode 100644 index 000000000..77f54d8a0 --- /dev/null +++ b/src/plugins/irc/irc-redirect.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2010 Sebastien Helleu <flashcode@flashtux.org> + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat 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 3 of the License, or + * (at your option) any later version. + * + * WeeChat 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 WeeChat. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __WEECHAT_IRC_REDIRECT_H +#define __WEECHAT_IRC_REDIRECT_H 1 + +#define IRC_REDIRECT_TIMEOUT_DEFAULT 60 + +struct t_irc_server; + +/* template for redirections (IRC plugin creates some templates at startup) */ + +struct t_irc_redirect_pattern +{ + char *name; /* name */ + int temp_pattern; /* temporary pattern (created by */ + /* external plugin/script) */ + int timeout; /* default timeout (in seconds) */ + char *cmd_start; /* command(s) starting redirection */ + /* (can be NULL or empty) */ + char *cmd_stop; /* command(s) stopping redirection */ + /* (not NULL, at least one command) */ + char *cmd_extra; /* extra command(s) after end commands */ + struct t_irc_redirect_pattern *prev_redirect; /* link to previous redir. */ + struct t_irc_redirect_pattern *next_redirect; /* link to next redir. */ +}; + +/* command redirection (created when a command is redirected) */ + +struct t_irc_redirect +{ + struct t_irc_server *server; /* server for this redirection */ + char *pattern; /* name of pattern used for this redir. */ + char *signal; /* name of signal sent after redirection */ + int count; /* how many times redirect is executed */ + int current_count; /* current count */ + char *string; /* we search this string in messages */ + int timeout; /* timeout (in seconds) */ + char *command; /* command sent to server, which is */ + /* redirected */ + time_t start_time; /* time when command is sent to server */ + /* (this is begining of this redirect) */ + struct t_hashtable *cmd_start; /* command(s) starting redirection */ + /* (can be NULL or empty) */ + struct t_hashtable *cmd_stop; /* command(s) stopping redirection */ + /* (not NULL, at least one command) */ + struct t_hashtable *cmd_extra; /* extra command(s) after end command(s) */ + int cmd_start_received; /* one of start commands received ? */ + int cmd_stop_received; /* one of stop commands received ? */ + struct t_hashtable *cmd_filter; /* command(s) to add to output */ + /* (if NULL or empty, all cmds are sent) */ + char *output; /* output of IRC command (gradually */ + /* filled with IRC messages) */ + int output_size; /* size (in bytes) of output string */ + struct t_irc_redirect *prev_redirect; /* link to previous redirect */ + struct t_irc_redirect *next_redirect; /* link to next redirect */ +}; + +extern struct t_irc_redirect_pattern *irc_redirect_patterns; +extern struct t_irc_redirect_pattern *last_irc_redirect_pattern; + +extern struct t_irc_redirect_pattern *irc_redirect_pattern_new (const char *name, + int temp_pattern, + int timeout, + const char *cmd_start, + const char *cmd_stop, + const char *cmd_extra); +extern struct t_irc_redirect *irc_redirect_new_with_commands (struct t_irc_server *server, + const char *pattern, + const char *signal, + int count, + const char *string, + int timeout, + const char *cmd_start, + const char *cmd_stop, + const char *cmd_extra, + const char *cmd_filter); +extern struct t_irc_redirect *irc_redirect_search_available (struct t_irc_server *server); +extern void irc_redirect_init_command (struct t_irc_redirect *redirect, + const char *command); +extern void irc_redirect_stop (struct t_irc_redirect *redirect, + const char *error); +extern int irc_redirect_message (struct t_irc_server *server, + const char *message, const char *command); +extern void irc_redirect_free (struct t_irc_redirect *redirect); +extern void irc_redirect_free_all (struct t_irc_server *server); +extern int irc_redirect_pattern_add_to_infolist (struct t_infolist *infolist, + struct t_irc_redirect_pattern *redirect_pattern); +extern int irc_redirect_add_to_infolist (struct t_infolist *infolist, + struct t_irc_redirect *redirect); +extern void irc_redirect_pattern_print_log (); +extern void irc_redirect_print_log (struct t_irc_server *server); +extern int irc_redirect_pattern_hsignal_cb (void *data, const char *signal, + struct t_hashtable *hashtable); +extern int irc_redirect_command_hsignal_cb (void *data, const char *signal, + struct t_hashtable *hashtable); +extern void irc_redirect_init (); +extern void irc_redirect_end (); + +#endif /* __WEECHAT_IRC_REDIRECT_H */ diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index f26615784..6ffaeefd0 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -52,6 +52,7 @@ #include "irc-nick.h" #include "irc-protocol.h" #include "irc-raw.h" +#include "irc-redirect.h" #include "irc-sasl.h" @@ -467,6 +468,8 @@ irc_server_alloc (const char *name) new_server->outqueue[i] = NULL; new_server->last_outqueue[i] = NULL; } + new_server->redirects = NULL; + new_server->last_redirect = NULL; new_server->buffer = NULL; new_server->buffer_as_string = NULL; new_server->channels = NULL; @@ -768,7 +771,8 @@ irc_server_apply_command_line_options (struct t_irc_server *server, void irc_server_outqueue_add (struct t_irc_server *server, int priority, const char *command, const char *msg1, - const char *msg2, int modified, const char *tags) + const char *msg2, int modified, const char *tags, + struct t_irc_redirect *redirect) { struct t_irc_outqueue *new_outqueue; @@ -780,6 +784,7 @@ irc_server_outqueue_add (struct t_irc_server *server, int priority, new_outqueue->message_after_mod = (msg2) ? strdup (msg2) : NULL; new_outqueue->modified = modified; new_outqueue->tags = (tags) ? strdup (tags) : NULL; + new_outqueue->redirect = redirect; new_outqueue->prev_outqueue = server->last_outqueue[priority]; new_outqueue->next_outqueue = NULL; @@ -902,6 +907,7 @@ irc_server_free_data (struct t_irc_server *server) { irc_server_outqueue_free_all (server, i); } + irc_redirect_free_all (server); if (server->channels) irc_channel_free_all (server); if (server->buffer_as_string) @@ -1267,7 +1273,7 @@ irc_server_outqueue_send (struct t_irc_server *server) '\r'); if (pos) pos[0] = '\0'; - irc_raw_print (server, 1, 0, + irc_raw_print (server, IRC_RAW_FLAG_SEND, server->outqueue[priority]->message_before_mod); if (pos) pos[0] = '\r'; @@ -1278,7 +1284,8 @@ irc_server_outqueue_send (struct t_irc_server *server) '\r'); if (pos) pos[0] = '\0'; - irc_raw_print (server, 1, server->outqueue[priority]->modified, + irc_raw_print (server, IRC_RAW_FLAG_SEND | + ((server->outqueue[priority]->modified) ? IRC_RAW_FLAG_MODIFIED : 0), server->outqueue[priority]->message_after_mod); if (pos) pos[0] = '\r'; @@ -1300,6 +1307,13 @@ irc_server_outqueue_send (struct t_irc_server *server) irc_server_send (server, server->outqueue[priority]->message_after_mod, strlen (server->outqueue[priority]->message_after_mod)); server->last_user_message = time_now; + + /* start redirection if redirect is set */ + if (server->outqueue[priority]->redirect) + { + irc_redirect_init_command (server->outqueue[priority]->redirect, + server->outqueue[priority]->message_after_mod); + } } irc_server_outqueue_free (server, priority, server->outqueue[priority]); @@ -1468,16 +1482,11 @@ irc_server_parse_message_to_hashtable (const char *message) if (!hashtable) return NULL; - weechat_hashtable_set (hashtable, "nick", - (nick) ? (void *)nick : (void *)empty_str); - weechat_hashtable_set (hashtable, "host", - (host) ? (void *)host : (void *)empty_str); - weechat_hashtable_set (hashtable, "command", - (command) ? (void *)command : (void *)empty_str); - weechat_hashtable_set (hashtable, "channel", - (channel) ? (void *)channel : (void *)empty_str); - weechat_hashtable_set (hashtable, "arguments", - (arguments) ? (void *)arguments : (void *)empty_str); + weechat_hashtable_set (hashtable, "nick", (nick) ? nick : empty_str); + weechat_hashtable_set (hashtable, "host", (host) ? host : empty_str); + weechat_hashtable_set (hashtable, "command", (command) ? command : empty_str); + weechat_hashtable_set (hashtable, "channel", (channel) ? channel : empty_str); + weechat_hashtable_set (hashtable, "arguments", (arguments) ? arguments : empty_str); return hashtable; } @@ -1505,6 +1514,7 @@ irc_server_send_one_msg (struct t_irc_server *server, int flags, char str_modifier[64], modifier_data[256]; int rc, queue_msg, add_to_queue, first_message, anti_flood; time_t time_now; + struct t_irc_redirect *ptr_redirect; rc = 1; @@ -1596,6 +1606,8 @@ irc_server_send_one_msg (struct t_irc_server *server, int flags, tags_to_send = irc_server_get_tags_to_send (tags); + ptr_redirect = irc_redirect_search_available (server); + if (add_to_queue > 0) { /* queue message (do not send anything now) */ @@ -1603,14 +1615,21 @@ irc_server_send_one_msg (struct t_irc_server *server, int flags, (new_msg && first_message) ? message : NULL, buffer, (new_msg) ? 1 : 0, - tags_to_send); + tags_to_send, + ptr_redirect); } else { if (first_message) - irc_raw_print (server, 1, 0, message); + { + irc_raw_print (server, IRC_RAW_FLAG_SEND, message); + } if (new_msg) - irc_raw_print (server, 1, 1, ptr_msg); + { + irc_raw_print (server, + IRC_RAW_FLAG_SEND | IRC_RAW_FLAG_MODIFIED, + ptr_msg); + } /* send signal with command that will be sent to server */ irc_server_send_signal (server, "irc_out", @@ -1629,6 +1648,8 @@ irc_server_send_one_msg (struct t_irc_server *server, int flags, if (queue_msg > 0) server->last_user_message = time_now; } + if (ptr_redirect) + irc_redirect_init_command (ptr_redirect, buffer); } if (tags_to_send) @@ -1648,7 +1669,10 @@ irc_server_send_one_msg (struct t_irc_server *server, int flags, free (msg_encoded); } else - irc_raw_print (server, 1, 1, _("(message dropped)")); + { + irc_raw_print (server, IRC_RAW_FLAG_SEND | IRC_RAW_FLAG_MODIFIED, + _("(message dropped)")); + } if (nick) free (nick); @@ -1849,7 +1873,8 @@ irc_server_msgq_flush () if (ptr_data[0]) { - irc_raw_print (irc_recv_msgq->server, 0, 0, ptr_data); + irc_raw_print (irc_recv_msgq->server, IRC_RAW_FLAG_RECV, + ptr_data); irc_server_parse_message (ptr_data, NULL, NULL, &command, NULL, NULL); @@ -1882,8 +1907,11 @@ irc_server_msgq_flush () pos[0] = '\0'; if (new_msg) - irc_raw_print (irc_recv_msgq->server, 0, 1, + { + irc_raw_print (irc_recv_msgq->server, + IRC_RAW_FLAG_RECV | IRC_RAW_FLAG_MODIFIED, ptr_msg); + } irc_server_parse_message (ptr_msg, &nick, &host, &command, &channel, @@ -1926,11 +1954,22 @@ irc_server_msgq_flush () "?"); /* parse and execute command */ - irc_protocol_recv_command (irc_recv_msgq->server, - (msg_decoded_without_color) ? - msg_decoded_without_color : ((msg_decoded) ? msg_decoded : ptr_msg), - command, - channel); + if (irc_redirect_message (irc_recv_msgq->server, + (msg_decoded_without_color) ? + msg_decoded_without_color : ((msg_decoded) ? msg_decoded : ptr_msg), + command)) + { + /* message redirected, we'll not display it! */ + } + else + { + /* message not redirected, display it */ + irc_protocol_recv_command (irc_recv_msgq->server, + (msg_decoded_without_color) ? + msg_decoded_without_color : ((msg_decoded) ? msg_decoded : ptr_msg), + command, + channel); + } if (nick) free (nick); @@ -1956,7 +1995,8 @@ irc_server_msgq_flush () } else { - irc_raw_print (irc_recv_msgq->server, 0, 1, + irc_raw_print (irc_recv_msgq->server, + IRC_RAW_FLAG_RECV | IRC_RAW_FLAG_MODIFIED, _("(message dropped)")); } if (new_msg) @@ -2125,7 +2165,8 @@ int irc_server_timer_cb (void *data, int remaining_calls) { struct t_irc_server *ptr_server; - time_t new_time; + struct t_irc_redirect *ptr_redirect, *ptr_next_redirect; + time_t current_time; static struct timeval tv; int away_check; @@ -2133,7 +2174,7 @@ irc_server_timer_cb (void *data, int remaining_calls) (void) data; (void) remaining_calls; - new_time = time (NULL); + current_time = time (NULL); for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) @@ -2141,7 +2182,7 @@ irc_server_timer_cb (void *data, int remaining_calls) /* check if reconnection is pending */ if ((!ptr_server->is_connected) && (ptr_server->reconnect_start > 0) - && (new_time >= (ptr_server->reconnect_start + ptr_server->reconnect_delay))) + && (current_time >= (ptr_server->reconnect_start + ptr_server->reconnect_delay))) { irc_server_reconnect (ptr_server); } @@ -2155,7 +2196,7 @@ irc_server_timer_cb (void *data, int remaining_calls) /* check for lag */ if ((weechat_config_integer (irc_config_network_lag_check) > 0) && (ptr_server->lag_check_time.tv_sec == 0) - && (new_time >= ptr_server->lag_next_check)) + && (current_time >= ptr_server->lag_next_check)) { irc_server_sendf (ptr_server, 0, NULL, "PING %s", (ptr_server->current_address) ? @@ -2171,7 +2212,7 @@ irc_server_timer_cb (void *data, int remaining_calls) if (away_check > 0) { if ((ptr_server->last_away_check == 0) - || (new_time >= ptr_server->last_away_check + (away_check * 60))) + || (current_time >= ptr_server->last_away_check + (away_check * 60))) { irc_server_check_away (ptr_server); } @@ -2180,7 +2221,7 @@ irc_server_timer_cb (void *data, int remaining_calls) /* check if it's time to autojoin channels (after command delay) */ if ((ptr_server->command_time != 0) - && (new_time >= ptr_server->command_time + + && (current_time >= ptr_server->command_time + IRC_SERVER_OPTION_INTEGER(ptr_server, IRC_SERVER_OPTION_COMMAND_DELAY))) { irc_server_autojoin_channels (ptr_server); @@ -2195,10 +2236,10 @@ irc_server_timer_cb (void *data, int remaining_calls) &tv); /* refresh lag item if needed */ if (((ptr_server->lag_last_refresh == 0) - || (new_time >= ptr_server->lag_last_refresh + weechat_config_integer (irc_config_network_lag_refresh_interval))) + || (current_time >= ptr_server->lag_last_refresh + weechat_config_integer (irc_config_network_lag_refresh_interval))) && (ptr_server->lag >= weechat_config_integer (irc_config_network_lag_min_show))) { - ptr_server->lag_last_refresh = new_time; + ptr_server->lag_last_refresh = current_time; weechat_bar_item_update ("lag"); } /* lag timeout? => disconnect */ @@ -2212,6 +2253,21 @@ irc_server_timer_cb (void *data, int remaining_calls) irc_server_disconnect (ptr_server, 0, 1); } } + + /* remove redirects if timeout occurs */ + ptr_redirect = ptr_server->redirects; + while (ptr_redirect) + { + ptr_next_redirect = ptr_redirect->next_redirect; + + if ((ptr_redirect->start_time > 0) + && (ptr_redirect->start_time + ptr_redirect->timeout < current_time)) + { + irc_redirect_stop (ptr_redirect, "timeout"); + } + + ptr_redirect = ptr_next_redirect; + } } } } @@ -2285,6 +2341,9 @@ irc_server_close_connection (struct t_irc_server *server) irc_server_outqueue_free_all (server, i); } + /* remove all redirects */ + irc_redirect_free_all (server); + /* server is now disconnected */ server->is_connected = 0; server->ssl_connected = 0; @@ -4230,6 +4289,8 @@ irc_server_print_log () weechat_log_printf (" outqueue[%02d] . . . . : 0x%lx", i, ptr_server->outqueue[i]); weechat_log_printf (" last_outqueue[%02d]. . : 0x%lx", i, ptr_server->last_outqueue[i]); } + weechat_log_printf (" redirects. . . . . . : 0x%lx", ptr_server->redirects); + weechat_log_printf (" last_redirect. . . . : 0x%lx", ptr_server->last_redirect); weechat_log_printf (" buffer . . . . . . . : 0x%lx", ptr_server->buffer); weechat_log_printf (" buffer_as_string . . : 0x%lx", ptr_server->buffer_as_string); weechat_log_printf (" channels . . . . . . : 0x%lx", ptr_server->channels); @@ -4237,6 +4298,8 @@ irc_server_print_log () weechat_log_printf (" prev_server. . . . . : 0x%lx", ptr_server->prev_server); weechat_log_printf (" next_server. . . . . : 0x%lx", ptr_server->next_server); + irc_redirect_print_log (ptr_server); + for (ptr_channel = ptr_server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h index d841c761c..251afb337 100644 --- a/src/plugins/irc/irc-server.h +++ b/src/plugins/irc/irc-server.h @@ -108,6 +108,7 @@ struct t_irc_outqueue char *message_after_mod; /* msg after modifier(s) */ int modified; /* msg was modified by modifier(s) */ char *tags; /* tags (used by Relay plugin) */ + struct t_irc_redirect *redirect; /* command redirection */ struct t_irc_outqueue *next_outqueue; /* link to next msg in queue */ struct t_irc_outqueue *prev_outqueue; /* link to prev msg in queue */ }; @@ -169,6 +170,8 @@ struct t_irc_server struct t_irc_outqueue *outqueue[2]; /* queue for outgoing messages */ /* with 2 priorities (high/low) */ struct t_irc_outqueue *last_outqueue[2]; /* last outgoing message */ + struct t_irc_redirect *redirects; /* command redirections */ + struct t_irc_redirect *last_redirect; /* last command redirection */ struct t_gui_buffer *buffer; /* GUI buffer allocated for server */ char *buffer_as_string; /* used to return buffer info */ struct t_irc_channel *channels; /* opened channels on server */ diff --git a/src/plugins/irc/irc-upgrade.c b/src/plugins/irc/irc-upgrade.c index de5aa11d5..1e5d48c29 100644 --- a/src/plugins/irc/irc-upgrade.c +++ b/src/plugins/irc/irc-upgrade.c @@ -34,6 +34,7 @@ #include "irc-channel.h" #include "irc-nick.h" #include "irc-raw.h" +#include "irc-redirect.h" struct t_irc_server *irc_upgrade_current_server = NULL; @@ -51,6 +52,8 @@ irc_upgrade_save_all_data (struct t_upgrade_file *upgrade_file) struct t_irc_server *ptr_server; struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick; + struct t_irc_redirect *ptr_redirect; + struct t_irc_redirect_pattern *ptr_redirect_pattern; struct t_irc_raw_message *ptr_raw_message; int rc; @@ -73,6 +76,7 @@ irc_upgrade_save_all_data (struct t_upgrade_file *upgrade_file) if (!rc) return 0; + /* save server channels and nicks */ for (ptr_channel = ptr_server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) { @@ -112,6 +116,27 @@ irc_upgrade_save_all_data (struct t_upgrade_file *upgrade_file) return 0; } } + + /* save server redirects */ + for (ptr_redirect = ptr_server->redirects; ptr_redirect; + ptr_redirect = ptr_redirect->next_redirect) + { + /* save channel */ + infolist = weechat_infolist_new (); + if (!infolist) + return 0; + if (!irc_redirect_add_to_infolist (infolist, ptr_redirect)) + { + weechat_infolist_free (infolist); + return 0; + } + rc = weechat_upgrade_write_object (upgrade_file, + IRC_UPGRADE_TYPE_REDIRECT, + infolist); + weechat_infolist_free (infolist); + if (!rc) + return 0; + } } /* save raw messages */ @@ -134,6 +159,30 @@ irc_upgrade_save_all_data (struct t_upgrade_file *upgrade_file) return 0; } + /* save redirect patterns */ + for (ptr_redirect_pattern = irc_redirect_patterns; ptr_redirect_pattern; + ptr_redirect_pattern = ptr_redirect_pattern->next_redirect) + { + /* save only temporary patterns (created by other plugins/scripts) */ + if (ptr_redirect_pattern->temp_pattern) + { + infolist = weechat_infolist_new (); + if (!infolist) + return 0; + if (!irc_redirect_pattern_add_to_infolist (infolist, ptr_redirect_pattern)) + { + weechat_infolist_free (infolist); + return 0; + } + rc = weechat_upgrade_write_object (upgrade_file, + IRC_UPGRADE_TYPE_REDIRECT_PATTERN, + infolist); + weechat_infolist_free (infolist); + if (!rc) + return 0; + } + } + return 1; } @@ -204,6 +253,7 @@ irc_upgrade_read_cb (void *data, char *buf, option_name[64]; const char *buffer_name, *str, *nick; struct t_irc_nick *ptr_nick; + struct t_irc_redirect *ptr_redirect; struct t_gui_buffer *ptr_buffer; /* make C compiler happy */ @@ -382,6 +432,45 @@ irc_upgrade_read_cb (void *data, } } break; + case IRC_UPGRADE_TYPE_REDIRECT: + if (irc_upgrade_current_server) + { + ptr_redirect = irc_redirect_new_with_commands ( + irc_upgrade_current_server, + weechat_infolist_string (infolist, "pattern"), + weechat_infolist_string (infolist, "signal"), + weechat_infolist_integer (infolist, "count"), + weechat_infolist_string (infolist, "string"), + weechat_infolist_integer (infolist, "timeout"), + weechat_infolist_string (infolist, "cmd_start"), + weechat_infolist_string (infolist, "cmd_stop"), + weechat_infolist_string (infolist, "cmd_extra"), + weechat_infolist_string (infolist, "cmd_filter")); + if (ptr_redirect) + { + ptr_redirect->current_count = weechat_infolist_integer (infolist, "current_count"); + str = weechat_infolist_string (infolist, "command"); + if (str) + ptr_redirect->command = strdup (str); + ptr_redirect->start_time = weechat_infolist_time (infolist, "start_time"); + ptr_redirect->cmd_start_received = weechat_infolist_integer (infolist, "cmd_start_received"); + ptr_redirect->cmd_stop_received = weechat_infolist_integer (infolist, "cmd_stop_received"); + str = weechat_infolist_string (infolist, "output"); + if (str) + ptr_redirect->output = strdup (str); + ptr_redirect->output_size = weechat_infolist_integer (infolist, "output_size"); + } + } + break; + case IRC_UPGRADE_TYPE_REDIRECT_PATTERN: + irc_redirect_pattern_new ( + weechat_infolist_string (infolist, "name"), + weechat_infolist_integer (infolist, "temp_pattern"), + weechat_infolist_integer (infolist, "timeout"), + weechat_infolist_string (infolist, "cmd_start"), + weechat_infolist_string (infolist, "cmd_stop"), + weechat_infolist_string (infolist, "cmd_extra")); + break; case IRC_UPGRADE_TYPE_RAW_MESSAGE: irc_raw_message_add_to_list (weechat_infolist_time (infolist, "date"), weechat_infolist_string (infolist, "prefix"), diff --git a/src/plugins/irc/irc-upgrade.h b/src/plugins/irc/irc-upgrade.h index 431c9d0bb..724fd15c9 100644 --- a/src/plugins/irc/irc-upgrade.h +++ b/src/plugins/irc/irc-upgrade.h @@ -30,6 +30,8 @@ enum t_irc_upgrade_type IRC_UPGRADE_TYPE_CHANNEL, IRC_UPGRADE_TYPE_NICK, IRC_UPGRADE_TYPE_RAW_MESSAGE, + IRC_UPGRADE_TYPE_REDIRECT_PATTERN, + IRC_UPGRADE_TYPE_REDIRECT, }; extern int irc_upgrade_save (); diff --git a/src/plugins/irc/irc.c b/src/plugins/irc/irc.c index 61737e64f..68e3abb3c 100644 --- a/src/plugins/irc/irc.c +++ b/src/plugins/irc/irc.c @@ -40,6 +40,7 @@ #include "irc-channel.h" #include "irc-nick.h" #include "irc-raw.h" +#include "irc-redirect.h" #include "irc-upgrade.h" @@ -164,6 +165,8 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) irc_info_init (); + irc_redirect_init (); + /* hook some signals */ irc_debug_init (); weechat_hook_signal ("quit", &irc_signal_quit_cb, NULL); @@ -173,6 +176,10 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_hook_signal ("xfer_send_accept_resume", &irc_server_xfer_send_accept_resume_cb, NULL); weechat_hook_signal ("irc_input_send", &irc_input_send_cb, NULL); + /* hook hsignals for redirection */ + weechat_hook_hsignal ("irc_redirect_pattern", &irc_redirect_pattern_hsignal_cb, NULL); + weechat_hook_hsignal ("irc_redirect_command", &irc_redirect_command_hsignal_cb, NULL); + /* modifiers */ weechat_hook_modifier ("irc_color_decode", &irc_color_modifier_cb, NULL); weechat_hook_modifier ("irc_color_encode", &irc_color_modifier_cb, NULL); @@ -262,5 +269,7 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) irc_config_free (); + irc_redirect_end (); + return WEECHAT_RC_OK; } |