summaryrefslogtreecommitdiff
path: root/src/plugins/irc
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2011-08-26 10:31:37 +0200
committerSebastien Helleu <flashcode@flashtux.org>2011-08-26 10:31:37 +0200
commit4853a530b630440d34d2ce2f8f478523658dbca2 (patch)
tree57baab29d9e31de18e22c7b34811ceecd65ed00b /src/plugins/irc
parentebf72c7eda87e70aed16e890581307f527567bed (diff)
downloadweechat-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.c111
-rw-r--r--src/plugins/irc/irc-info.c42
-rw-r--r--src/plugins/irc/irc-input.c57
-rw-r--r--src/plugins/irc/irc-message.c520
-rw-r--r--src/plugins/irc/irc-message.h2
-rw-r--r--src/plugins/irc/irc-protocol.c22
-rw-r--r--src/plugins/irc/irc-server.c88
-rw-r--r--src/plugins/irc/irc-server.h12
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);