diff options
author | Sebastien Helleu <flashcode@flashtux.org> | 2011-08-26 10:31:37 +0200 |
---|---|---|
committer | Sebastien Helleu <flashcode@flashtux.org> | 2011-08-26 10:31:37 +0200 |
commit | 4853a530b630440d34d2ce2f8f478523658dbca2 (patch) | |
tree | 57baab29d9e31de18e22c7b34811ceecd65ed00b /src/plugins/irc | |
parent | ebf72c7eda87e70aed16e890581307f527567bed (diff) | |
download | weechat-4853a530b630440d34d2ce2f8f478523658dbca2.zip |
irc: improve split of privmsg, add split of some other messages (bug #29879), add new info_hashtable "irc_message_split", split irc messages in relay plugin
List of new features/bugs fixed:
- improve split of privmsg: keep CTCP in split
- add split of messages: ison, join, notice, wallops, 005, 353
- add new info_hashtable "irc_message_split" (for plugins/scripts)
- in relay plugin: split irc messages sent to clients of irc proxy
Diffstat (limited to 'src/plugins/irc')
-rw-r--r-- | src/plugins/irc/irc-command.c | 111 | ||||
-rw-r--r-- | src/plugins/irc/irc-info.c | 42 | ||||
-rw-r--r-- | src/plugins/irc/irc-input.c | 57 | ||||
-rw-r--r-- | src/plugins/irc/irc-message.c | 520 | ||||
-rw-r--r-- | src/plugins/irc/irc-message.h | 2 | ||||
-rw-r--r-- | src/plugins/irc/irc-protocol.c | 22 | ||||
-rw-r--r-- | src/plugins/irc/irc-server.c | 88 | ||||
-rw-r--r-- | src/plugins/irc/irc-server.h | 12 |
8 files changed, 751 insertions, 103 deletions
diff --git a/src/plugins/irc/irc-command.c b/src/plugins/irc/irc-command.c index 5346df5ed..7495262de 100644 --- a/src/plugins/irc/irc-command.c +++ b/src/plugins/irc/irc-command.c @@ -334,20 +334,16 @@ irc_command_allserv (void *data, struct t_gui_buffer *buffer, int argc, } /* - * irc_command_me_channel: send a ctcp action to a channel + * irc_command_me_channel_display: display a ctcp action on channel */ void -irc_command_me_channel (struct t_irc_server *server, - struct t_irc_channel *channel, - const char *arguments) +irc_command_me_channel_display (struct t_irc_server *server, + struct t_irc_channel *channel, + const char *arguments) { char *string; - irc_server_sendf (server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, - "PRIVMSG %s :\01ACTION %s\01", - channel->name, - (arguments && arguments[0]) ? arguments : ""); string = (arguments && arguments[0]) ? irc_color_decode (arguments, weechat_config_boolean (irc_config_network_colors_receive)) : NULL; @@ -366,6 +362,42 @@ irc_command_me_channel (struct t_irc_server *server, } /* + * irc_command_me_channel: send a ctcp action to a channel + */ + +void +irc_command_me_channel (struct t_irc_server *server, + struct t_irc_channel *channel, + const char *arguments) +{ + struct t_hashtable *hashtable; + int number; + char hash_key[32]; + const char *str_args; + + hashtable = irc_server_sendf (server, + IRC_SERVER_SEND_OUTQ_PRIO_HIGH | IRC_SERVER_SEND_RETURN_HASHTABLE, + NULL, + "PRIVMSG %s :\01ACTION %s\01", + channel->name, + (arguments && arguments[0]) ? arguments : ""); + if (hashtable) + { + number = 1; + while (1) + { + snprintf (hash_key, sizeof (hash_key), "args%d", number); + str_args = weechat_hashtable_get (hashtable, hash_key); + if (!str_args) + break; + irc_command_me_channel_display (server, channel, str_args); + number++; + } + weechat_hashtable_free (hashtable); + } +} + +/* * irc_command_me_all_channels: send a ctcp action to all channels of a server */ @@ -1737,7 +1769,7 @@ irc_command_ison (void *data, struct t_gui_buffer *buffer, int argc, if (argc > 1) { irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, - "ISON %s", argv_eol[1]); + "ISON :%s", argv_eol[1]); } else { @@ -2682,9 +2714,10 @@ int irc_command_notice (void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *string; - int arg_nick, arg_text; + char *string, hash_key[32], *str_args; + int arg_nick, arg_text, number; struct t_irc_channel *ptr_channel; + struct t_hashtable *hashtable; IRC_BUFFER_GET_SERVER(buffer); @@ -2703,28 +2736,42 @@ irc_command_notice (void *data, struct t_gui_buffer *buffer, int argc, } IRC_COMMAND_CHECK_SERVER("notice", 1); - - string = irc_color_decode (argv_eol[arg_text], - weechat_config_boolean (irc_config_network_colors_receive)); ptr_channel = irc_channel_search (ptr_server, argv[arg_nick]); - weechat_printf_tags ((ptr_channel) ? ptr_channel->buffer : ptr_server->buffer, - "notify_none,no_highlight", - "%s%s%s%s -> %s%s%s: %s", - weechat_prefix ("network"), - IRC_COLOR_NOTICE, - /* TRANSLATORS: "Notice" is command name in IRC protocol (translation is frequently the same word) */ - _("Notice"), - IRC_COLOR_CHAT, - (irc_channel_is_channel (argv[arg_nick])) ? - IRC_COLOR_CHAT_CHANNEL : IRC_COLOR_CHAT_NICK, - argv[arg_nick], - IRC_COLOR_CHAT, - (string) ? string : argv_eol[arg_text]); - if (string) - free (string); - irc_server_sendf (ptr_server, IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, - "NOTICE %s :%s", - argv[arg_nick], argv_eol[arg_text]); + hashtable = irc_server_sendf (ptr_server, + IRC_SERVER_SEND_OUTQ_PRIO_HIGH | IRC_SERVER_SEND_RETURN_HASHTABLE, + NULL, + "NOTICE %s :%s", + argv[arg_nick], argv_eol[arg_text]); + if (hashtable) + { + number = 1; + while (1) + { + snprintf (hash_key, sizeof (hash_key), "args%d", number); + str_args = weechat_hashtable_get (hashtable, hash_key); + if (!str_args) + break; + string = irc_color_decode (str_args, + weechat_config_boolean (irc_config_network_colors_receive)); + weechat_printf_tags ((ptr_channel) ? ptr_channel->buffer : ptr_server->buffer, + "notify_none,no_highlight", + "%s%s%s%s -> %s%s%s: %s", + weechat_prefix ("network"), + IRC_COLOR_NOTICE, + /* TRANSLATORS: "Notice" is command name in IRC protocol (translation is frequently the same word) */ + _("Notice"), + IRC_COLOR_CHAT, + (irc_channel_is_channel (argv[arg_nick])) ? + IRC_COLOR_CHAT_CHANNEL : IRC_COLOR_CHAT_NICK, + argv[arg_nick], + IRC_COLOR_CHAT, + (string) ? string : str_args); + if (string) + free (string); + number++; + } + weechat_hashtable_free (hashtable); + } } else { diff --git a/src/plugins/irc/irc-info.c b/src/plugins/irc/irc-info.c index a482be480..0cad62129 100644 --- a/src/plugins/irc/irc-info.c +++ b/src/plugins/irc/irc-info.c @@ -240,23 +240,34 @@ struct t_hashtable * irc_info_get_info_hashtable_cb (void *data, const char *info_name, struct t_hashtable *hashtable) { - const char *message; + const char *server, *message; + struct t_irc_server *ptr_server; struct t_hashtable *value; /* make C compiler happy */ (void) data; - if (weechat_strcasecmp (info_name, "irc_parse_message") == 0) + if (!hashtable) + return NULL; + + if (weechat_strcasecmp (info_name, "irc_message_parse") == 0) { - if (hashtable) + message = weechat_hashtable_get (hashtable, "message"); + if (message) { - message = (const char *)weechat_hashtable_get (hashtable, - "message"); - if (message) - { - value = irc_message_parse_to_hashtable (message); - return value; - } + value = irc_message_parse_to_hashtable (message); + return value; + } + } + else if (weechat_strcasecmp (info_name, "irc_message_split") == 0) + { + server = weechat_hashtable_get (hashtable, "server"); + ptr_server = (server) ? irc_server_search (server) : NULL; + message = weechat_hashtable_get (hashtable, "message"); + if (message) + { + value = irc_message_split (ptr_server, message); + return value; } } @@ -592,7 +603,7 @@ irc_info_init () &irc_info_get_info_cb, NULL); /* info_hashtable hooks */ - weechat_hook_info_hashtable ("irc_parse_message", + weechat_hook_info_hashtable ("irc_message_parse", N_("parse an IRC message"), N_("\"message\": IRC message"), /* TRANSLATORS: please do not translate key names (enclosed by quotes) */ @@ -600,6 +611,15 @@ irc_info_init () "\"command\": command, \"channel\": channel, " "\"arguments\": arguments (includes channel)"), &irc_info_get_info_hashtable_cb, NULL); + weechat_hook_info_hashtable ("irc_message_split", + N_("split an IRC message (to fit in 512 bytes)"), + N_("\"message\": IRC message, \"server\": server " + "name (optional)"), + /* TRANSLATORS: please do not translate key names (enclosed by quotes) */ + N_("\"msg1\" ... \"msgN\": messages to send " + "(without final \"\\r\\n\"), " + "\"args1\" ... \"argsN\": arguments of messages"), + &irc_info_get_info_hashtable_cb, NULL); /* infolist hooks */ weechat_hook_infolist ("irc_server", diff --git a/src/plugins/irc/irc-input.c b/src/plugins/irc/irc-input.c index cce50d1f7..0a1b7b5ec 100644 --- a/src/plugins/irc/irc-input.c +++ b/src/plugins/irc/irc-input.c @@ -22,6 +22,7 @@ */ #include <stdlib.h> +#include <stdio.h> #include <string.h> #include "../weechat-plugin.h" @@ -85,8 +86,9 @@ void irc_input_send_user_message (struct t_gui_buffer *buffer, int flags, const char *tags, char *message) { - int max_length; - char *pos, *pos_max, *last_space, *pos_next, *next, saved_char; + int number; + char hash_key[32], *str_args; + struct t_hashtable *hashtable; IRC_BUFFER_GET_SERVER_CHANNEL(buffer); @@ -100,45 +102,24 @@ irc_input_send_user_message (struct t_gui_buffer *buffer, int flags, weechat_prefix ("error"), IRC_PLUGIN_NAME); return; } - - next = NULL; - last_space = NULL; - saved_char = '\0'; - - max_length = 512 - 16 - 65 - 10 - strlen (ptr_server->nick) - - strlen (ptr_channel->name); - - if (max_length > 0) + hashtable = irc_server_sendf (ptr_server, + flags | IRC_SERVER_SEND_RETURN_HASHTABLE, + tags, + "PRIVMSG %s :%s", + ptr_channel->name, message); + if (hashtable) { - if ((int)strlen (message) > max_length) + number = 1; + while (1) { - pos = message; - pos_max = message + max_length; - while (pos[0]) - { - if (pos[0] == ' ') - last_space = pos; - pos_next = weechat_utf8_next_char (pos); - if (pos_next > pos_max) - break; - pos = pos_next; - } - if (last_space && (last_space < pos)) - pos = last_space + 1; - saved_char = pos[0]; - pos[0] = '\0'; - next = pos; + snprintf (hash_key, sizeof (hash_key), "args%d", number); + str_args = weechat_hashtable_get (hashtable, hash_key); + if (!str_args) + break; + irc_input_user_message_display (buffer, str_args); + number++; } - } - - irc_server_sendf (ptr_server, flags, tags, - "PRIVMSG %s :%s", ptr_channel->name, message); - irc_input_user_message_display (buffer, message); - - if (next) - { - next[0] = saved_char; - irc_input_send_user_message (buffer, flags, tags, next); + weechat_hashtable_free (hashtable); } } diff --git a/src/plugins/irc/irc-message.c b/src/plugins/irc/irc-message.c index c4314e0f6..28c965642 100644 --- a/src/plugins/irc/irc-message.c +++ b/src/plugins/irc/irc-message.c @@ -338,3 +338,523 @@ irc_message_replace_vars (struct t_irc_server *server, /* return result */ return res; } + +/* + * irc_message_split_add: add a message + arguments in hashtable + */ + +void +irc_message_split_add (struct t_hashtable *hashtable, int number, + const char *message, const char *arguments) +{ + char key[32]; + + if (message) + { + snprintf (key, sizeof (key), "msg%d", number); + weechat_hashtable_set (hashtable, key, message); + if (weechat_irc_plugin->debug >= 2) + { + weechat_printf (NULL, + "irc_message_split_add >> %s='%s' (%d bytes)", + key, message, + strlen (message)); + } + } + if (arguments) + { + snprintf (key, sizeof (key), "args%d", number); + weechat_hashtable_set (hashtable, key, arguments); + if (weechat_irc_plugin->debug >= 2) + { + weechat_printf (NULL, + "irc_message_split_add >> %s='%s'", + key, arguments); + } + } +} + +/* + * irc_message_split_string: split "arguments" using delimiter and max length + * messages added to hashtable are: + * host + command + target + XXX + suffix + * (where XXX is part of "arguments") + * return 1 if split ok, 0 if error + */ + +int +irc_message_split_string (struct t_hashtable *hashtable, + const char *host, + const char *command, + const char *target, + const char *prefix, + const char *arguments, + const char *suffix, + const char delimiter, + int max_length_host) +{ + const char *pos, *pos_max, *pos_next, *pos_last_delim; + char message[1024], *dup_arguments; + int max_length, number; + + /* + * Examples of arguments for this function: + * + * message..: :nick!user@host.com PRIVMSG #channel :Hello world! + * arguments: + * host : ":nick!user@host.com" + * command : "PRIVMSG" + * target : "#channel" + * prefix : ":" + * arguments: "Hello world!" + * suffix : "" + * + * message..: :nick!user@host.com PRIVMSG #channel :\01ACTION is eating\01 + * arguments: + * host : ":nick!user@host.com" + * command : "PRIVMSG" + * target : "#channel" + * prefix : ":\01ACTION " + * arguments: "is eating" + * suffix : "\01" + */ + + max_length = 510; + if (max_length_host >= 0) + max_length -= max_length_host; + else + max_length -= (host) ? strlen (host) + 1 : 0; + max_length -= strlen (command) + 1; + if (target) + max_length -= strlen (target); + if (prefix) + max_length -= strlen (prefix); + if (suffix) + max_length -= strlen (suffix); + + if (max_length < 2) + return 0; + + /* debug message */ + if (weechat_irc_plugin->debug >= 2) + { + weechat_printf (NULL, + "irc_message_split_string: host='%s', command='%s', " + "target='%s', prefix='%s', arguments='%s', " + "suffix='%s', max_length=%d", + host, command, target, prefix, arguments, suffix, + max_length); + } + + number = 1; + + if (!arguments || !arguments[0]) + { + snprintf (message, sizeof (message), "%s%s%s %s%s%s%s", + (host) ? host : "", + (host) ? " " : "", + command, + (target) ? target : "", + (target && target[0]) ? " " : "", + (prefix) ? prefix : "", + (suffix) ? suffix : ""); + irc_message_split_add (hashtable, 1, message, ""); + return 1; + } + + while (arguments && arguments[0]) + { + pos = arguments; + pos_max = pos + max_length; + pos_last_delim = NULL; + while (pos && pos[0]) + { + if (pos[0] == delimiter) + pos_last_delim = pos; + pos_next = weechat_utf8_next_char (pos); + if (pos_next > pos_max) + break; + pos = pos_next; + } + if (pos[0] && pos_last_delim) + pos = pos_last_delim; + dup_arguments = weechat_strndup (arguments, pos - arguments); + if (dup_arguments) + { + snprintf (message, sizeof (message), "%s%s%s %s%s%s%s%s", + (host) ? host : "", + (host) ? " " : "", + command, + (target) ? target : "", + (target && target[0]) ? " " : "", + (prefix) ? prefix : "", + dup_arguments, + (suffix) ? suffix : ""); + irc_message_split_add (hashtable, number, message, dup_arguments); + number++; + free (dup_arguments); + } + arguments = (pos == pos_last_delim) ? pos + 1 : pos; + } + + return 1; +} + +/* + * irc_message_split_join: split a JOIN message, taking care of keeping + * channel keys with channel names + * return 1 if split ok, 0 if error + */ + +int +irc_message_split_join (struct t_hashtable *hashtable, + const char *host, const char *arguments) +{ + int number, channels_count, keys_count, length, length_no_channel; + int length_to_add, index_channel; + char **channels, **keys, *pos, *str; + char msg_to_send[2048], keys_to_add[2048]; + + number = 1; + + channels = NULL; + channels_count = 0; + keys = NULL; + keys_count = 0; + + pos = strchr (arguments, ' '); + if (pos) + { + str = weechat_strndup (arguments, pos - arguments); + if (!str) + return 0; + channels = weechat_string_split (str, ",", 0, 0, &channels_count); + free (str); + while (pos[0] == ' ') + { + pos++; + } + if (pos[0]) + keys = weechat_string_split (pos, ",", 0, 0, &keys_count); + } + else + { + channels = weechat_string_split (arguments, ",", 0, 0, &channels_count); + } + + snprintf (msg_to_send, sizeof (msg_to_send), "%s%sJOIN", + (host) ? host : "", + (host) ? " " : ""); + length = strlen (msg_to_send); + length_no_channel = length; + keys_to_add[0] = '\0'; + index_channel = 0; + while (index_channel < channels_count) + { + length_to_add = 1 + strlen (channels[index_channel]); + if (index_channel < keys_count) + length_to_add += 1 + strlen (keys[index_channel]); + if ((length + length_to_add < 510) || (length == length_no_channel)) + { + if (length + length_to_add < (int)sizeof (msg_to_send)) + { + strcat (msg_to_send, (length == length_no_channel) ? " " : ","); + strcat (msg_to_send, channels[index_channel]); + } + if (index_channel < keys_count) + { + if (strlen (keys_to_add) + 1 + + strlen (keys[index_channel]) < (int)sizeof (keys_to_add)) + { + strcat (keys_to_add, (keys_to_add[0]) ? "," : " "); + strcat (keys_to_add, keys[index_channel]); + } + } + length += length_to_add; + index_channel++; + } + else + { + strcat (msg_to_send, keys_to_add); + irc_message_split_add (hashtable, number, + msg_to_send, + msg_to_send + length_no_channel + 1); + number++; + snprintf (msg_to_send, sizeof (msg_to_send), "%s%sJOIN", + (host) ? host : "", + (host) ? " " : ""); + length = strlen (msg_to_send); + keys_to_add[0] = '\0'; + } + } + + if (length > length_no_channel) + { + strcat (msg_to_send, keys_to_add); + irc_message_split_add (hashtable, number, + msg_to_send, + msg_to_send + length_no_channel + 1); + } + + if (channels) + weechat_string_free_split (channels); + if (keys) + weechat_string_free_split (keys); + + return 1; +} + +/* + * irc_message_split_privmsg: split a PRIVMSG message, taking care of keeping + * the '\01' char used in CTCP messages + * return 1 if split ok, 0 if error + */ + +int +irc_message_split_privmsg (struct t_hashtable *hashtable, + char *host, char *command, char *target, + char *arguments, int max_length_host) +{ + char prefix[512], suffix[2], *pos, saved_char; + int length, rc; + + /* + * message sent looks like: + * PRIVMSG #channel :hello world! + * + * when IRC server sends message to other people, message looks like: + * :nick!user@host.com PRIVMSG #channel :hello world! + */ + + /* for CTCP, target2 will be '\01xxxx' and suffix '\01' */ + prefix[0] = '\0'; + suffix[0] = '\0'; + length = strlen (arguments); + if ((arguments[0] == '\01') + && (arguments[length - 1] == '\01')) + { + pos = strchr (arguments, ' '); + if (pos) + { + pos++; + saved_char = pos[0]; + pos[0] = '\0'; + snprintf (prefix, sizeof (prefix), ":%s", arguments); + pos[0] = saved_char; + arguments[length - 1] = '\0'; + arguments = pos; + suffix[0] = '\01'; + suffix[1] = '\0'; + } + } + if (!prefix[0]) + strcpy (prefix, ":"); + + rc = irc_message_split_string (hashtable, host, command, target, + prefix, arguments, suffix, + ' ', max_length_host); + + return rc; +} + +/* + * irc_message_split_005: split a 005 message (isupport) + * return 1 if split ok, 0 if error + */ + +int +irc_message_split_005 (struct t_hashtable *hashtable, + char *host, char *command, char *target, char *arguments) +{ + char *pos, suffix[512]; + + /* + * 005 message looks like: + * :server 005 mynick MODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 + * HOSTLEN=63 TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 + * CHANTYPES=# PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB IRCD=dancer + * :are available on this server + */ + + /* search suffix */ + suffix[0] = '\0'; + pos = strstr (arguments, " :"); + if (pos) + { + snprintf (suffix, sizeof (suffix), "%s", pos); + pos[0] = '\0'; + } + + return irc_message_split_string (hashtable, host, command, target, + NULL, arguments, suffix, ' ', -1); +} + +/* + * irc_message_split: split an IRC message about to be sent to IRC server + * The maximum length of an IRC message is 510 bytes for + * user data + final "\r\n", so full size is 512 bytes. + * The split takes care about type of message to do a split + * at best place in message. + * The hashtable returned contains keys "msg1", "msg2", ..., + * "msgN" with split of message (these messages do not + * include the final "\r\n"). + * Hashtable contains "args1", "args2", ..., "argsN" with + * split of arguments only (no host/command here). + * Each message in hashtable has command and arguments, and + * then is ready to be sent to IRC server. + */ + +struct t_hashtable * +irc_message_split (struct t_irc_server *server, const char *message) +{ + struct t_hashtable *hashtable; + char **argv, **argv_eol, *host, *command, *arguments, target[512]; + int split_ok, argc, index_args, max_length_nick, max_length_host; + + split_ok = 0; + host = NULL; + command = NULL; + arguments = NULL; + index_args = 0; + + /* debug message */ + if (weechat_irc_plugin->debug >= 2) + weechat_printf (NULL, "irc_message_split: message='%s'", message); + + hashtable = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + if (!hashtable) + return NULL; + + if (!message || !message[0]) + goto end; + + argv = weechat_string_split (message, " ", 0, 0, &argc); + argv_eol = weechat_string_split (message, " ", 1, 0, NULL); + + if (argc < 2) + goto end; + + if (argv[0][0] == ':') + { + if (argc < 3) + goto end; + host = argv[0]; + command = argv[1]; + arguments = argv_eol[2]; + index_args = 2; + } + else + { + command = argv[0]; + arguments = argv_eol[1]; + index_args = 1; + } + + max_length_nick = (server && (server->nick_max_length > 0)) ? + server->nick_max_length : 16; + max_length_host = 1 + /* ":" */ + max_length_nick + /* nick */ + 1 + /* "!" */ + 63 + /* host */ + 1; /* " " */ + + if ((weechat_strcasecmp (command, "ison") == 0) + || (weechat_strcasecmp (command, "wallops") == 0)) + { + split_ok = irc_message_split_string (hashtable, host, command, + NULL, ":", + (argv_eol[index_args][0] == ':') ? + argv_eol[index_args] + 1 : argv_eol[index_args], + NULL, ' ', max_length_host); + } + else if (weechat_strcasecmp (command, "join") == 0) + { + /* split join (if it's more than 510 bytes) */ + if (strlen (message) > 510) + split_ok = irc_message_split_join (hashtable, host, arguments); + } + else if (weechat_strcasecmp (command, "notice") == 0) + { + if (index_args + 1 <= argc - 1) + { + split_ok = irc_message_split_string (hashtable, host, command, + argv[index_args], ":", + (argv_eol[index_args + 1][0] == ':') ? + argv_eol[index_args + 1] + 1 : argv_eol[index_args + 1], + NULL, ' ', max_length_host); + } + } + else if (weechat_strcasecmp (command, "privmsg") == 0) + { + /* split privmsg */ + if (index_args + 1 <= argc - 1) + { + split_ok = irc_message_split_privmsg (hashtable, host, command, + argv[index_args], + (argv_eol[index_args + 1][0] == ':') ? + argv_eol[index_args + 1] + 1 : argv_eol[index_args + 1], + max_length_host); + } + } + else if (weechat_strcasecmp (command, "005") == 0) + { + /* split 005 (isupport) */ + if (index_args + 1 <= argc - 1) + { + split_ok = irc_message_split_005 (hashtable, host, command, + argv[index_args], + (argv_eol[index_args + 1][0] == ':') ? + argv_eol[index_args + 1] + 1 : argv_eol[index_args + 1]); + } + } + else if (weechat_strcasecmp (command, "353") == 0) + { + /* + * split 353 (list of users on channel): + * :server 353 mynick = #channel :mynick nick1 @nick2 +nick3 + */ + if (index_args + 2 <= argc - 1) + { + if (irc_channel_is_channel (argv[index_args + 1])) + { + snprintf (target, sizeof (target), "%s %s", + argv[index_args], argv[index_args + 1]); + split_ok = irc_message_split_string (hashtable, host, command, + target, ":", + (argv_eol[index_args + 2][0] == ':') ? + argv_eol[index_args + 2] + 1 : argv_eol[index_args + 2], + NULL, ' ', -1); + } + else + { + if (index_args + 3 <= argc - 1) + { + snprintf (target, sizeof (target), "%s %s %s", + argv[index_args], argv[index_args + 1], + argv[index_args + 2]); + split_ok = irc_message_split_string (hashtable, host, command, + target, ":", + (argv_eol[index_args + 3][0] == ':') ? + argv_eol[index_args + 3] + 1 : argv_eol[index_args + 3], + NULL, ' ', -1); + } + } + } + } + +end: + if (!split_ok + || (weechat_hashtable_get_integer (hashtable, "items_count") == 0)) + { + irc_message_split_add (hashtable, 1, message, arguments); + } + + weechat_string_free_split (argv); + weechat_string_free_split (argv_eol); + + return hashtable; +} diff --git a/src/plugins/irc/irc-message.h b/src/plugins/irc/irc-message.h index e68d994f8..25eb4c4d8 100644 --- a/src/plugins/irc/irc-message.h +++ b/src/plugins/irc/irc-message.h @@ -32,5 +32,7 @@ extern const char *irc_message_get_address_from_host (const char *host); extern char *irc_message_replace_vars (struct t_irc_server *server, struct t_irc_channel *channel, const char *string); +extern struct t_hashtable *irc_message_split (struct t_irc_server *server, + const char *message); #endif /* __WEECHAT_IRC_MESSAGE_H */ diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index 9512c1dcf..17dbd7b77 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -1908,9 +1908,9 @@ IRC_PROTOCOL_CALLBACK(001) IRC_PROTOCOL_CALLBACK(005) { - char *pos, *pos2, *pos_start; - int length_isupport, length; - + char *pos, *pos2, *pos_start, *error; + int length_isupport, length, nick_max_length; + /* * 005 message looks like: * :server 005 mynick MODES=4 CHANLIMIT=#:20 NICKLEN=16 USERLEN=10 @@ -1938,6 +1938,22 @@ IRC_PROTOCOL_CALLBACK(005) pos2[0] = ' '; } + /* save max nick length */ + pos = strstr (argv_eol[3], "NICKLEN="); + if (pos) + { + pos += 8; + pos2 = strchr (pos, ' '); + if (pos2) + pos2[0] = '\0'; + error = NULL; + nick_max_length = (int)strtol (pos, &error, 10); + if (error && !error[0] && (nick_max_length > 0)) + server->nick_max_length = nick_max_length; + if (pos2) + pos2[0] = ' '; + } + /* save whole message (concatenate to existing isupport, if any) */ pos_start = NULL; pos = strstr (argv_eol[3], " :"); diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index 2de04d13d..fed0b122d 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -633,6 +633,7 @@ irc_server_alloc (const char *name) new_server->isupport = NULL; new_server->prefix_modes = NULL; new_server->prefix_chars = NULL; + new_server->nick_max_length = 0; new_server->reconnect_delay = 0; new_server->reconnect_start = 0; new_server->command_time = 0; @@ -1738,32 +1739,85 @@ irc_server_send_one_msg (struct t_irc_server *server, int flags, /* * irc_server_sendf: send formatted data to IRC server * many messages may be sent, separated by '\n' + * if flags contains "IRC_SERVER_SEND_RETURN_HASHTABLE", then + * hashtable with split of message is returned + * (see function irc_message_split() in irc-message.c) + * note: hashtable must be freed after use */ -void +struct t_hashtable * irc_server_sendf (struct t_irc_server *server, int flags, const char *tags, const char *format, ...) { - va_list args; - static char buffer[4096]; - char **items; - int i, items_count; + char **items, hash_key[32]; + const char *str_message, *str_args; + int i, items_count, number, ret_number, rc; + struct t_hashtable *hashtable, *ret_hashtable; if (!server) - return; + return NULL; - va_start (args, format); - vsnprintf (buffer, sizeof (buffer) - 1, format, args); - va_end (args); - - items = weechat_string_split (buffer, "\n", 0, 0, &items_count); + weechat_va_format (format); + if (!vbuffer) + return NULL; + + ret_hashtable = NULL; + ret_number = 1; + if (flags & IRC_SERVER_SEND_RETURN_HASHTABLE) + { + ret_hashtable = weechat_hashtable_new (8, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_STRING, + NULL, + NULL); + } + + rc = 1; + items = weechat_string_split (vbuffer, "\n", 0, 0, &items_count); for (i = 0; i < items_count; i++) { - if (!irc_server_send_one_msg (server, flags, items[i], tags)) - break; + /* split message if needed (max is 512 bytes including final "\r\n") */ + hashtable = irc_message_split (server, items[i]); + if (hashtable) + { + number = 1; + while (1) + { + snprintf (hash_key, sizeof (hash_key), "msg%d", number); + str_message = weechat_hashtable_get (hashtable, hash_key); + if (!str_message) + break; + snprintf (hash_key, sizeof (hash_key), "args%d", number); + str_args = weechat_hashtable_get (hashtable, hash_key); + + rc = irc_server_send_one_msg (server, flags, str_message, tags); + if (!rc) + break; + + if (ret_hashtable) + { + snprintf (hash_key, sizeof (hash_key), "msg%d", ret_number); + weechat_hashtable_set (ret_hashtable, hash_key, str_message); + if (str_args) + { + snprintf (hash_key, sizeof (hash_key), "args%d", ret_number); + weechat_hashtable_set (ret_hashtable, hash_key, str_args); + } + ret_number++; + } + number++; + } + weechat_hashtable_free (hashtable); + if (!rc) + break; + } } if (items) weechat_string_free_split (items); + + free (vbuffer); + + return ret_hashtable; } /* @@ -3550,14 +3604,14 @@ irc_server_autojoin_channels (struct t_irc_server *server) if (ptr_channel->key) { irc_server_sendf (server, - IRC_SERVER_SEND_OUTQ_PRIO_LOW, NULL, + IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, "JOIN %s %s", ptr_channel->name, ptr_channel->key); } else { irc_server_sendf (server, - IRC_SERVER_SEND_OUTQ_PRIO_LOW, NULL, + IRC_SERVER_SEND_OUTQ_PRIO_HIGH, NULL, "JOIN %s", ptr_channel->name); } @@ -3995,6 +4049,7 @@ irc_server_hdata_server_cb (void *data, const char *hdata_name) WEECHAT_HDATA_VAR(struct t_irc_server, isupport, STRING, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, prefix_modes, STRING, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, prefix_chars, STRING, NULL); + WEECHAT_HDATA_VAR(struct t_irc_server, nick_max_length, INTEGER, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, reconnect_delay, INTEGER, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, reconnect_start, TIME, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, command_time, TIME, NULL); @@ -4180,6 +4235,8 @@ irc_server_add_to_infolist (struct t_infolist *infolist, return 0; if (!weechat_infolist_new_var_string (ptr_item, "prefix_chars", server->prefix_chars)) return 0; + if (!weechat_infolist_new_var_integer (ptr_item, "nick_max_length", server->nick_max_length)) + return 0; if (!weechat_infolist_new_var_integer (ptr_item, "reconnect_delay", server->reconnect_delay)) return 0; if (!weechat_infolist_new_var_time (ptr_item, "reconnect_start", server->reconnect_start)) @@ -4481,6 +4538,7 @@ irc_server_print_log () weechat_log_printf (" isupport . . . . . . : '%s'", ptr_server->isupport); weechat_log_printf (" prefix_modes . . . . : '%s'", ptr_server->prefix_modes); weechat_log_printf (" prefix_chars . . . . : '%s'", ptr_server->prefix_chars); + weechat_log_printf (" nick_max_length. . . : %d", ptr_server->nick_max_length); weechat_log_printf (" reconnect_delay. . . : %d", ptr_server->reconnect_delay); weechat_log_printf (" reconnect_start. . . : %ld", ptr_server->reconnect_start); weechat_log_printf (" command_time . . . . : %ld", ptr_server->command_time); diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h index ae2c53677..01ec048bd 100644 --- a/src/plugins/irc/irc-server.h +++ b/src/plugins/irc/irc-server.h @@ -98,8 +98,9 @@ enum t_irc_server_option #define IRC_SERVER_NUM_OUTQUEUES_PRIO 2 /* flags for irc_server_sendf() */ -#define IRC_SERVER_SEND_OUTQ_PRIO_HIGH 1 -#define IRC_SERVER_SEND_OUTQ_PRIO_LOW 2 +#define IRC_SERVER_SEND_OUTQ_PRIO_HIGH 1 +#define IRC_SERVER_SEND_OUTQ_PRIO_LOW 2 +#define IRC_SERVER_SEND_RETURN_HASHTABLE 4 /* output queue of messages to server (for sending slowly to server) */ @@ -154,6 +155,7 @@ struct t_irc_server char *isupport; /* copy of message 005 (ISUPPORT) */ char *prefix_modes; /* prefix modes from msg 005 (eg "aohv") */ char *prefix_chars; /* prefix chars from msg 005 (eg "&@%+") */ + int nick_max_length; /* max lenth of nick (from msg 005) */ int reconnect_delay; /* current reconnect delay (growing) */ time_t reconnect_start; /* this time + delay = reconnect time */ time_t command_time; /* this time + command_delay = time to */ @@ -240,8 +242,10 @@ extern void irc_server_send_signal (struct t_irc_server *server, const char *full_message, const char *tags); extern void irc_server_set_send_default_tags (const char *tags); -extern void irc_server_sendf (struct t_irc_server *server, int flags, - const char *tags, const char *format, ...); +extern struct t_hashtable *irc_server_sendf (struct t_irc_server *server, + int flags, + const char *tags, + const char *format, ...); extern struct t_irc_server *irc_server_search (const char *server_name); extern void irc_server_set_buffer_title (struct t_irc_server *server); extern struct t_gui_buffer *irc_server_create_buffer (struct t_irc_server *server); |