diff --git a/doc/en/weechat_plugin_api.en.adoc b/doc/en/weechat_plugin_api.en.adoc index 1c03e17f9..610406fd6 100644 --- a/doc/en/weechat_plugin_api.en.adoc +++ b/doc/en/weechat_plugin_api.en.adoc @@ -15485,7 +15485,7 @@ if (hashtable_in) weechat_hashtable_set ( hashtable_in, "message", - "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :hello!"); + "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :Hello world!"); hashtable_out = weechat_info_get_hashtable ("irc_message_parse", hashtable_in); /* @@ -15493,14 +15493,17 @@ if (hashtable_in) * "tags" : "time=2015-06-27T16:40:35.000Z;tag2=value\\sspace" * "tag_time" : "2015-06-27T16:40:35.000Z" * "tag_tag2" : "value space" - * "message_without_tags": ":nick!user@host PRIVMSG #weechat :hello!" + * "message_without_tags": ":nick!user@host PRIVMSG #weechat :Hello world!" * "nick" : "nick" * "user" : "user" * "host" : "nick!user@host" * "command" : "PRIVMSG" * "channel" : "#weechat" - * "arguments" : "#weechat :hello!" - * "text" : "hello!" + * "arguments" : "#weechat :Hello world!" + * "text" : "Hello world!" + * "param1" : "#weechat" + * "param2" : "Hello world!" + * "num_params" : "2" * "pos_command" : "65" * "pos_arguments" : "73" * "pos_channel" : "73" diff --git a/doc/fr/weechat_plugin_api.fr.adoc b/doc/fr/weechat_plugin_api.fr.adoc index d5e7032a5..490676564 100644 --- a/doc/fr/weechat_plugin_api.fr.adoc +++ b/doc/fr/weechat_plugin_api.fr.adoc @@ -15810,7 +15810,7 @@ if (hashtable_in) weechat_hashtable_set ( hashtable_in, "message", - "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :hello!"); + "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :Hello world!"); hashtable_out = weechat_info_get_hashtable ("irc_message_parse", hashtable_in); /* @@ -15818,14 +15818,17 @@ if (hashtable_in) * "tags" : "time=2015-06-27T16:40:35.000Z;tag2=value\\sspace" * "tag_time" : "2015-06-27T16:40:35.000Z" * "tag_tag2" : "value space" - * "message_without_tags": ":nick!user@host PRIVMSG #weechat :hello!" + * "message_without_tags": ":nick!user@host PRIVMSG #weechat :Hello world!" * "nick" : "nick" " "user" : "user" * "host" : "nick!user@host" * "command" : "PRIVMSG" * "channel" : "#weechat" - * "arguments" : "#weechat :hello!" - * "text" : "hello!" + * "arguments" : "#weechat :Hello world!" + * "text" : "Hello world!" + * "param1" : "#weechat" + * "param2" : "Hello world!" + * "num_params" : "2" * "pos_command" : "65" * "pos_arguments" : "73" * "pos_channel" : "73" diff --git a/doc/it/weechat_plugin_api.it.adoc b/doc/it/weechat_plugin_api.it.adoc index 4719ae3bc..0e1159767 100644 --- a/doc/it/weechat_plugin_api.it.adoc +++ b/doc/it/weechat_plugin_api.it.adoc @@ -16126,7 +16126,7 @@ if (hashtable_in) weechat_hashtable_set ( hashtable_in, "message", - "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :hello!"); + "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :Hello world!"); hashtable_out = weechat_info_get_hashtable ("irc_message_parse", hashtable_in); /* @@ -16134,14 +16134,17 @@ if (hashtable_in) * "tags" : "time=2015-06-27T16:40:35.000Z;tag2=value\\sspace" * "tag_time" : "2015-06-27T16:40:35.000Z" * "tag_tag2" : "value space" - * "message_without_tags": ":nick!user@host PRIVMSG #weechat :hello!" + * "message_without_tags": ":nick!user@host PRIVMSG #weechat :Hello world!" * "nick" : "nick" * "user" : "user" * "host" : "nick!user@host" * "command" : "PRIVMSG" * "channel" : "#weechat" - * "arguments" : "#weechat :hello!" - * "text" : "hello!" + * "arguments" : "#weechat :Hello world!" + * "text" : "Hello world!" + * "param1" : "#weechat" + * "param2" : "Hello world!" + * "num_params" : "2" * "pos_command" : "65" * "pos_arguments" : "73" * "pos_channel" : "73" diff --git a/doc/ja/weechat_plugin_api.ja.adoc b/doc/ja/weechat_plugin_api.ja.adoc index e14463d1f..3b33360fc 100644 --- a/doc/ja/weechat_plugin_api.ja.adoc +++ b/doc/ja/weechat_plugin_api.ja.adoc @@ -15544,7 +15544,7 @@ if (hashtable_in) weechat_hashtable_set ( hashtable_in, "message", - "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :hello!"); + "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :Hello world!"); hashtable_out = weechat_info_get_hashtable ("irc_message_parse", hashtable_in); /* @@ -15552,14 +15552,17 @@ if (hashtable_in) * "tags" : "time=2015-06-27T16:40:35.000Z;tag2=value\\sspace" * "tag_time" : "2015-06-27T16:40:35.000Z" * "tag_tag2" : "value space" - * "message_without_tags": ":nick!user@host PRIVMSG #weechat :hello!" + * "message_without_tags": ":nick!user@host PRIVMSG #weechat :Hello world!" * "nick" : "nick" * "user" : "user" * "host" : "nick!user@host" * "command" : "PRIVMSG" * "channel" : "#weechat" - * "arguments" : "#weechat :hello!" - * "text" : "hello!" + * "arguments" : "#weechat :Hello world!" + * "text" : "Hello world!" + * "param1" : "#weechat" + * "param2" : "Hello world!" + * "num_params" : "2" * "pos_command" : "65" * "pos_arguments" : "73" * "pos_channel" : "73" diff --git a/doc/sr/weechat_plugin_api.sr.adoc b/doc/sr/weechat_plugin_api.sr.adoc index 57e834112..98cc86171 100644 --- a/doc/sr/weechat_plugin_api.sr.adoc +++ b/doc/sr/weechat_plugin_api.sr.adoc @@ -14958,7 +14958,7 @@ if (hashtable_in) weechat_hashtable_set ( hashtable_in, "message", - "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :hello!"); + "@time=2015-06-27T16:40:35.000Z;tag2=value\\sspace :nick!user@host PRIVMSG #weechat :Hello world!"); hashtable_out = weechat_info_get_hashtable ("irc_message_parse", hashtable_in); /* @@ -14966,14 +14966,17 @@ if (hashtable_in) * "tags" : "time=2015-06-27T16:40:35.000Z;tag2=value\\sspace" * "tag_time" : "2015-06-27T16:40:35.000Z" * "tag_tag2" : "value space" - * "message_without_tags": ":nick!user@host PRIVMSG #weechat :hello!" + * "message_without_tags": ":nick!user@host PRIVMSG #weechat :Hello world!" * "nick" : "nick" * "user" : "user" * "host" : "nick!user@host" * "command" : "PRIVMSG" * "channel" : "#weechat" - * "arguments" : "#weechat :hello!" - * "text" : "hello!" + * "arguments" : "#weechat :Hello world!" + * "text" : "Hello world!" + * "param1" : "#weechat" + * "param2" : "Hello world!" + * "num_params" : "2" * "pos_command" : "65" * "pos_arguments" : "73" * "pos_channel" : "73" diff --git a/src/plugins/irc/irc-info.c b/src/plugins/irc/irc-info.c index 892c1f3ed..c41e2970b 100644 --- a/src/plugins/irc/irc-info.c +++ b/src/plugins/irc/irc-info.c @@ -1192,6 +1192,8 @@ irc_info_init () "\"channel\": channel, " "\"arguments\": arguments (includes channel), " "\"text\": text (for example user message), " + "\"param1\" ... \"paramN\": parsed command parameters, " + "\"num_params\": number of parsed command parameters, " "\"pos_command\": index of \"command\" message (\"-1\" if " "\"command\" was not found), " "\"pos_arguments\": index of \"arguments\" message (\"-1\" if " diff --git a/src/plugins/irc/irc-message.c b/src/plugins/irc/irc-message.c index eeaf91d6a..b80a268d0 100644 --- a/src/plugins/irc/irc-message.c +++ b/src/plugins/irc/irc-message.c @@ -34,6 +34,107 @@ #include "irc-tag.h" +/* + * Parses command arguments and returns: + * - params (array of strings) + * - num_params (integer) + * + * Leading spaces are skipped, trailing spaces are preserved. + * + * Trailing parameters (if starting with ":") are returned as a single + * parameter. + * + * Example: + * + * " #channel nick :trailing parameters " + * + * ==> params[0] == "#channel" + * params[1] == "nick" + * params[2] == "trailing parameters " + * params[3] == NULL + * num_params = 3 + */ + +void +irc_message_parse_params (const char *parameters, + char ***params, int *num_params) +{ + const char *ptr_params, *pos_end, *pos_next; + int alloc_params, trailing; + + if (!params && !num_params) + return; + + if (params) + *params = NULL; + if (num_params) + *num_params = 0; + + if (!parameters) + return; + + alloc_params = 0; + if (params) + { + *params = malloc ((alloc_params + 1) * sizeof ((*params)[0])); + if (!*params) + return; + *params[0] = NULL; + } + + ptr_params = parameters; + while (ptr_params[0] == ' ') + { + ptr_params++; + } + + trailing = 0; + while (1) + { + pos_end = NULL; + if (ptr_params[0] == ':') + { + ptr_params++; + trailing = 1; + } + else + { + pos_end = strchr (ptr_params, ' '); + } + if (!pos_end) + pos_end = ptr_params + strlen (ptr_params); + pos_next = pos_end; + while (pos_next[0] == ' ') + { + pos_next++; + } + if (!pos_next[0]) + pos_end = pos_next; + if (params) + { + alloc_params++; + *params = realloc (*params, + (alloc_params + 1) * sizeof ((*params)[0])); + if (!*params) + return; + (*params)[alloc_params - 1] = weechat_strndup (ptr_params, + pos_end - ptr_params); + (*params)[alloc_params] = NULL; + } + if (num_params) + *num_params += 1; + if (trailing) + break; + ptr_params = pos_end; + while (ptr_params[0] == ' ') + { + ptr_params++; + } + if (!ptr_params[0]) + break; + } +} + /* * Parses an IRC message and returns: * - tags (string) @@ -44,24 +145,26 @@ * - channel (string) * - arguments (string) * - text (string) + * - params (array of strings) + * - num_params (integer) * - pos_command (integer: command index in message) * - pos_arguments (integer: arguments index in message) * - pos_channel (integer: channel index in message) * - pos_text (integer: text index in message) * * Example: - * @time=2015-06-27T16:40:35.000Z :nick!user@host PRIVMSG #weechat :hello! + * @time=2015-06-27T16:40:35.000Z :nick!user@host PRIVMSG #weechat :Hello world! * * Result: * tags: "time=2015-06-27T16:40:35.000Z" - * msg_without_tags: ":nick!user@host PRIVMSG #weechat :hello!" + * msg_without_tags: ":nick!user@host PRIVMSG #weechat :Hello world!" * nick: "nick" * user: "user" * host: "nick!user@host" * command: "PRIVMSG" * channel: "#weechat" - * arguments: "#weechat :hello!" - * text: "hello!" + * arguments: "#weechat :Hello world!" + * text: "Hello world!" * pos_command: 47 * pos_arguments: 55 * pos_channel: 55 @@ -73,6 +176,7 @@ irc_message_parse (struct t_irc_server *server, const char *message, char **tags, char **message_without_tags, char **nick, char **user, char **host, char **command, char **channel, char **arguments, char **text, + char ***params, int *num_params, int *pos_command, int *pos_arguments, int *pos_channel, int *pos_text) { @@ -96,6 +200,10 @@ irc_message_parse (struct t_irc_server *server, const char *message, *arguments = NULL; if (text) *text = NULL; + if (params) + *params = NULL; + if (num_params) + *num_params = 0; if (pos_command) *pos_command = -1; if (pos_arguments) @@ -113,7 +221,7 @@ irc_message_parse (struct t_irc_server *server, const char *message, /* * we will use this message as example: * - * @time=2015-06-27T16:40:35.000Z :nick!user@host PRIVMSG #weechat :hello! + * @time=2015-06-27T16:40:35.000Z :nick!user@host PRIVMSG #weechat :Hello world! */ if (ptr_message[0] == '@') @@ -142,7 +250,7 @@ irc_message_parse (struct t_irc_server *server, const char *message, if (message_without_tags) *message_without_tags = strdup (ptr_message); - /* now we have: ptr_message --> ":nick!user@host PRIVMSG #weechat :hello!" */ + /* now we have: ptr_message --> ":nick!user@host PRIVMSG #weechat :Hello world!" */ if (ptr_message[0] == ':') { /* read host/nick */ @@ -185,7 +293,7 @@ irc_message_parse (struct t_irc_server *server, const char *message, } } - /* now we have: ptr_message --> "PRIVMSG #weechat :hello!" */ + /* now we have: ptr_message --> "PRIVMSG #weechat :Hello world!" */ if (ptr_message[0]) { pos = strchr (ptr_message, ' '); @@ -200,11 +308,12 @@ irc_message_parse (struct t_irc_server *server, const char *message, { pos++; } - /* now we have: pos --> "#weechat :hello!" */ + /* now we have: pos --> "#weechat :Hello world!" */ if (arguments) *arguments = strdup (pos); if (pos_arguments) *pos_arguments = pos - message; + irc_message_parse_params (pos, params, num_params); if ((pos[0] == ':') && ((strncmp (ptr_message, "JOIN ", 5) == 0) || (strncmp (ptr_message, "PART ", 5) == 0))) @@ -336,6 +445,8 @@ irc_message_parse (struct t_irc_server *server, const char *message, * - channel * - arguments * - text + * - num_params + * - param1, param2, ..., paramN * - pos_command * - pos_arguments * - pos_channel @@ -349,13 +460,14 @@ irc_message_parse_to_hashtable (struct t_irc_server *server, const char *message) { char *tags, *message_without_tags, *nick, *user, *host, *command, *channel; - char *arguments, *text, str_pos[32]; + char *arguments, *text, **params, str_key[64], str_pos[32]; char empty_str[1] = { '\0' }; - int pos_command, pos_arguments, pos_channel, pos_text; + int i, num_params, pos_command, pos_arguments, pos_channel, pos_text; struct t_hashtable *hashtable; irc_message_parse (server, message, &tags, &message_without_tags, &nick, &user, &host, &command, &channel, &arguments, &text, + ¶ms, &num_params, &pos_command, &pos_arguments, &pos_channel, &pos_text); hashtable = weechat_hashtable_new (32, @@ -384,6 +496,13 @@ irc_message_parse_to_hashtable (struct t_irc_server *server, (arguments) ? arguments : empty_str); weechat_hashtable_set (hashtable, "text", (text) ? text : empty_str); + snprintf (str_pos, sizeof (str_pos), "%d", num_params); + weechat_hashtable_set (hashtable, "num_params", str_pos); + for (i = 0; i < num_params; i++) + { + snprintf (str_key, sizeof (str_key), "param%d", i + 1); + weechat_hashtable_set (hashtable, str_key, params[i]); + } snprintf (str_pos, sizeof (str_pos), "%d", pos_command); weechat_hashtable_set (hashtable, "pos_command", str_pos); snprintf (str_pos, sizeof (str_pos), "%d", pos_arguments); @@ -562,11 +681,23 @@ irc_message_ignored (struct t_irc_server *server, const char *message) return 0; /* parse raw message */ - irc_message_parse (server, message, - NULL, NULL, &nick, NULL, &host, - NULL, &channel, NULL, - NULL, NULL, NULL, - NULL, NULL); + irc_message_parse (server, + message, + NULL, /* tags */ + NULL, /* message_without_tags */ + &nick, + NULL, /* user */ + &host, + NULL, /* command */ + &channel, + NULL, /* arguments */ + NULL, /* text */ + NULL, /* params */ + NULL, /* num_params */ + NULL, /* pos_command */ + NULL, /* pos_arguments */ + NULL, /* pos_channel */ + NULL); /* pos_text */ /* remove colors from host */ host_no_color = (host) ? irc_color_decode (host, 0) : NULL; diff --git a/src/plugins/irc/irc-message.h b/src/plugins/irc/irc-message.h index 5b118128b..cb6d168ed 100644 --- a/src/plugins/irc/irc-message.h +++ b/src/plugins/irc/irc-message.h @@ -23,11 +23,14 @@ struct t_irc_server; struct t_irc_channel; +extern void irc_message_parse_params (const char *parameters, + char ***params, int *num_params); extern void irc_message_parse (struct t_irc_server *server, const char *message, char **tags, char **message_without_tags, char **nick, char **user, char **host, char **command, char **channel, char **arguments, char **text, + char ***params, int *num_params, int *pos_command, int *pos_arguments, int *pos_channel, int *pos_text); extern struct t_hashtable *irc_message_parse_to_hashtable (struct t_irc_server *server, diff --git a/src/plugins/irc/irc-notify.c b/src/plugins/irc/irc-notify.c index 53695f173..56d8a2860 100644 --- a/src/plugins/irc/irc-notify.c +++ b/src/plugins/irc/irc-notify.c @@ -868,9 +868,23 @@ irc_notify_hsignal_cb (const void *pointer, void *data, const char *signal, } for (i = 0; i < num_messages; i++) { - irc_message_parse (ptr_server, messages[i], NULL, NULL, NULL, - NULL, NULL, NULL, NULL, &arguments, NULL, - NULL, NULL, NULL, NULL); + irc_message_parse (ptr_server, + messages[i], + NULL, /* tags */ + NULL, /* message_without_tags */ + NULL, /* nick */ + NULL, /* user */ + NULL, /* host */ + NULL, /* command */ + NULL, /* channel */ + &arguments, + NULL, /* text */ + NULL, /* params */ + NULL, /* num_params */ + NULL, /* pos_command */ + NULL, /* pos_arguments */ + NULL, /* pos_channel */ + NULL); /* pos_text */ if (arguments) { pos = strchr (arguments, ' '); @@ -966,10 +980,23 @@ irc_notify_hsignal_cb (const void *pointer, void *data, const char *signal, { for (i = 0; i < num_messages; i++) { - irc_message_parse (ptr_server, messages[i], NULL, NULL, - NULL, NULL, NULL, &irc_cmd, NULL, - &arguments, NULL, NULL, NULL, NULL, - NULL); + irc_message_parse (ptr_server, + messages[i], + NULL, /* tags */ + NULL, /* message_without_tags */ + NULL, /* nick */ + NULL, /* user */ + NULL, /* host */ + &irc_cmd, + NULL, /* channel */ + &arguments, + NULL, /* text */ + NULL, /* params */ + NULL, /* num_params */ + NULL, /* pos_command */ + NULL, /* pos_arguments */ + NULL, /* pos_channel */ + NULL); /* pos_text */ if (irc_cmd && arguments) { if (strcmp (irc_cmd, "401") == 0) diff --git a/src/plugins/irc/irc-raw.c b/src/plugins/irc/irc-raw.c index c81a0814c..a2a3abde4 100644 --- a/src/plugins/irc/irc-raw.c +++ b/src/plugins/irc/irc-raw.c @@ -160,9 +160,23 @@ irc_raw_message_match_filter (struct t_irc_raw_message *raw_message, else if (strncmp (filter, "m:", 2) == 0) { /* filter by IRC command */ - irc_message_parse (raw_message->server, raw_message->message, - NULL, NULL, NULL, NULL, NULL, &command, NULL, - NULL, NULL, NULL, NULL, NULL, NULL); + irc_message_parse (raw_message->server, + raw_message->message, + NULL, /* tags */ + NULL, /* message_without_tags */ + NULL, /* nick */ + NULL, /* user */ + NULL, /* host */ + &command, + NULL, /* channel */ + NULL, /* arguments */ + NULL, /* text */ + NULL, /* params */ + NULL, /* num_params */ + NULL, /* pos_command */ + NULL, /* pos_arguments */ + NULL, /* pos_channel */ + NULL); /* pos_text */ match = (command && (weechat_strcasecmp (command, filter + 2) == 0)) ? 1 : 0; if (command) diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index a0d27bc86..f396c1c9b 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -2740,8 +2740,22 @@ irc_server_send_one_msg (struct t_irc_server *server, int flags, ptr_msg = (new_msg) ? new_msg : message; msg_encoded = NULL; - irc_message_parse (server, ptr_msg, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, &pos_channel, + irc_message_parse (server, + ptr_msg, + NULL, /* tags */ + NULL, /* message_without_tags */ + NULL, /* nick */ + NULL, /* user */ + NULL, /* host */ + NULL, /* command */ + NULL, /* channel */ + NULL, /* arguments */ + NULL, /* text */ + NULL, /* params */ + NULL, /* num_params */ + NULL, /* pos_command */ + NULL, /* pos_arguments */ + &pos_channel, &pos_text); switch (IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_CHARSET_MESSAGE)) @@ -2957,9 +2971,23 @@ irc_server_sendf (struct t_irc_server *server, int flags, const char *tags, for (i = 0; i < items_count; i++) { /* run modifier "irc_out1_xxx" (like "irc_out_xxx", but before split) */ - irc_message_parse (server, items[i], NULL, NULL, - &nick, NULL, NULL, &command, &channel, NULL, NULL, - NULL, NULL, NULL, NULL); + irc_message_parse (server, + items[i], + NULL, /* tags */ + NULL, /* message_without_tags */ + &nick, + NULL, /* user */ + NULL, /* host */ + &command, + &channel, + NULL, /* arguments */ + NULL, /* text */ + NULL, /* params */ + NULL, /* num_params */ + NULL, /* pos_command */ + NULL, /* pos_arguments */ + NULL, /* pos_channel */ + NULL); /* pos_text */ snprintf (str_modifier, sizeof (str_modifier), "irc_out1_%s", (command) ? command : "unknown"); @@ -3224,9 +3252,22 @@ irc_server_msgq_flush () ptr_data); irc_message_parse (irc_recv_msgq->server, - ptr_data, NULL, NULL, NULL, NULL, NULL, - &command, NULL, NULL, NULL, NULL, NULL, - NULL, NULL); + ptr_data, + NULL, /* tags */ + NULL, /* message_without_tags */ + NULL, /* nick */ + NULL, /* user */ + NULL, /* host */ + &command, + NULL, /* channel */ + NULL, /* arguments */ + NULL, /* text */ + NULL, /* params */ + NULL, /* num_params */ + NULL, /* pos_command */ + NULL, /* pos_arguments */ + NULL, /* pos_channel */ + NULL); /* pos_text */ snprintf (str_modifier, sizeof (str_modifier), "irc_in_%s", (command) ? command : "unknown"); @@ -3264,11 +3305,23 @@ irc_server_msgq_flush () ptr_msg); } - irc_message_parse (irc_recv_msgq->server, ptr_msg, - NULL, NULL, &nick, NULL, &host, - &command, &channel, &arguments, - NULL, NULL, NULL, - &pos_channel, &pos_text); + irc_message_parse (irc_recv_msgq->server, + ptr_msg, + NULL, /* tags */ + NULL, /* message_without_tags */ + &nick, + NULL, /* user */ + &host, + &command, + &channel, + &arguments, + NULL, /* text */ + NULL, /* params */ + NULL, /* num_params */ + NULL, /* pos_command */ + NULL, /* pos_arguments */ + &pos_channel, + &pos_text); msg_decoded = NULL; diff --git a/tests/unit/plugins/irc/test-irc-message.cpp b/tests/unit/plugins/irc/test-irc-message.cpp index accd26186..d8c1a5e73 100644 --- a/tests/unit/plugins/irc/test-irc-message.cpp +++ b/tests/unit/plugins/irc/test-irc-message.cpp @@ -28,6 +28,7 @@ extern "C" #include "src/core/wee-config-file.h" #include "src/core/wee-hashtable.h" #include "src/core/wee-hook.h" +#include "src/core/wee-string.h" #include "src/plugins/irc/irc-config.h" #include "src/plugins/irc/irc-ignore.h" #include "src/plugins/irc/irc-message.h" @@ -158,7 +159,8 @@ extern "C" #define WEE_CHECK_PARSE(__tags, __message_without_tags, __nick, __user, \ __host, __command, __channel, __arguments, \ - __text, __pos_command, __pos_arguments, \ + __text, __params, __num_params, \ + __pos_command, __pos_arguments, \ __pos_channel, __pos_text, __server, __message) \ tags = NULL; \ message_without_tags = NULL; \ @@ -169,6 +171,8 @@ extern "C" channel = NULL; \ arguments = NULL; \ text = NULL; \ + params = NULL; \ + num_params = -1; \ pos_command = -1; \ pos_channel = -1; \ pos_text = -1; \ @@ -176,7 +180,8 @@ extern "C" irc_message_parse (__server, __message, &tags, \ &message_without_tags, \ &nick, &user, &host, &command, &channel, \ - &arguments, &text, &pos_command, &pos_arguments, \ + &arguments, &text, ¶ms, &num_params, \ + &pos_command, &pos_arguments, \ &pos_channel, &pos_text); \ \ if (__tags == NULL) \ @@ -251,6 +256,29 @@ extern "C" { \ STRCMP_EQUAL(__text, text); \ } \ + if (__params == NULL) \ + { \ + POINTERS_EQUAL(NULL, params); \ + } \ + else \ + { \ + ptr_params = __params; \ + for (i = 0; ptr_params[i]; i++) \ + { \ + if (!params[i]) \ + { \ + snprintf (str_error, sizeof (str_error), \ + "params[%d] should not be NULL", \ + i); \ + FAIL(str_error); \ + } \ + else \ + { \ + STRCMP_EQUAL(ptr_params[i], params[i]); \ + } \ + } \ + POINTERS_EQUAL(NULL, params[i]); \ + } \ LONGS_EQUAL(__pos_command, pos_command); \ LONGS_EQUAL(__pos_arguments, pos_arguments); \ LONGS_EQUAL(__pos_channel, pos_channel); \ @@ -277,6 +305,147 @@ TEST_GROUP(IrcMessage) { }; +/* + * Tests functions: + * irc_message_parse_params + */ + +TEST(IrcMessage, ParseParams) +{ + char **params; + int num_params; + + irc_message_parse_params (NULL, NULL, NULL); + irc_message_parse_params ("", NULL, NULL); + + params = (char **)0x1; + num_params = -1; + irc_message_parse_params (NULL, ¶ms, &num_params); + LONGS_EQUAL(0, num_params); + POINTERS_EQUAL(NULL, params); + + /* empty string */ + params = NULL; + num_params = -1; + irc_message_parse_params ("", ¶ms, &num_params); + LONGS_EQUAL(1, num_params); + CHECK(params); + STRCMP_EQUAL("", params[0]); + POINTERS_EQUAL(NULL, params[1]); + string_free_split (params); + + /* empty trailing parameter */ + params = NULL; + num_params = -1; + irc_message_parse_params (":", ¶ms, &num_params); + LONGS_EQUAL(1, num_params); + CHECK(params); + STRCMP_EQUAL("", params[0]); + POINTERS_EQUAL(NULL, params[1]); + string_free_split (params); + + /* single parameter */ + params = NULL; + num_params = -1; + irc_message_parse_params ("param1", ¶ms, &num_params); + LONGS_EQUAL(1, num_params); + CHECK(params); + STRCMP_EQUAL("param1", params[0]); + POINTERS_EQUAL(NULL, params[1]); + string_free_split (params); + + /* two parameters */ + params = NULL; + num_params = -1; + irc_message_parse_params ("param1 param2", ¶ms, &num_params); + LONGS_EQUAL(2, num_params); + CHECK(params); + STRCMP_EQUAL("param1", params[0]); + STRCMP_EQUAL("param2", params[1]); + POINTERS_EQUAL(NULL, params[2]); + string_free_split (params); + + /* trailing spaces */ + params = NULL; + num_params = -1; + irc_message_parse_params ("param1 param2 ", ¶ms, &num_params); + LONGS_EQUAL(2, num_params); + CHECK(params); + STRCMP_EQUAL("param1", params[0]); + STRCMP_EQUAL("param2 ", params[1]); + POINTERS_EQUAL(NULL, params[2]); + string_free_split (params); + + /* leading and trailing spaces */ + params = NULL; + num_params = -1; + irc_message_parse_params (" param1 param2 ", ¶ms, &num_params); + LONGS_EQUAL(2, num_params); + CHECK(params); + STRCMP_EQUAL("param1", params[0]); + STRCMP_EQUAL("param2 ", params[1]); + POINTERS_EQUAL(NULL, params[2]); + string_free_split (params); + + /* empty trailing parameter */ + params = NULL; + num_params = -1; + irc_message_parse_params ("param1 :", ¶ms, &num_params); + LONGS_EQUAL(2, num_params); + CHECK(params); + STRCMP_EQUAL("param1", params[0]); + STRCMP_EQUAL("", params[1]); + POINTERS_EQUAL(NULL, params[2]); + string_free_split (params); + + /* trailing parameter */ + params = NULL; + num_params = -1; + irc_message_parse_params ("param1 :trailing params ", ¶ms, &num_params); + LONGS_EQUAL(2, num_params); + CHECK(params); + STRCMP_EQUAL("param1", params[0]); + STRCMP_EQUAL("trailing params ", params[1]); + POINTERS_EQUAL(NULL, params[2]); + string_free_split (params); + + /* trailing parameter with colon inside */ + params = NULL; + num_params = -1; + irc_message_parse_params ("param1 param2 param3 :trailing params :here ", + ¶ms, &num_params); + LONGS_EQUAL(4, num_params); + CHECK(params); + STRCMP_EQUAL("param1", params[0]); + STRCMP_EQUAL("param2", params[1]); + STRCMP_EQUAL("param3", params[2]); + STRCMP_EQUAL("trailing params :here ", params[3]); + POINTERS_EQUAL(NULL, params[4]); + string_free_split (params); + + /* with params set to NULL */ + params = (char **)0x1; + num_params = -1; + irc_message_parse_params ("param1 param2 param3 :trailing params :here ", + NULL, &num_params); + LONGS_EQUAL(4, num_params); + POINTERS_EQUAL(0x1, params); + + /* with num_params set to NULL */ + params = NULL; + num_params = -1; + irc_message_parse_params ("param1 param2 param3 :trailing params :here ", + ¶ms, NULL); + LONGS_EQUAL(-1, num_params); + CHECK(params); + STRCMP_EQUAL("param1", params[0]); + STRCMP_EQUAL("param2", params[1]); + STRCMP_EQUAL("param3", params[2]); + STRCMP_EQUAL("trailing params :here ", params[3]); + POINTERS_EQUAL(NULL, params[4]); + string_free_split (params); +} + /* * Tests functions: * irc_message_parse @@ -285,19 +454,56 @@ TEST_GROUP(IrcMessage) TEST(IrcMessage, Parse) { char *tags, *message_without_tags, *nick, *user, *host, *command, *channel; - char *arguments, *text; - int pos_command, pos_arguments, pos_channel, pos_text; + char *arguments, *text, **params, str_error[4096]; + const char **ptr_params; + const char *params_away[] = { "I am away", NULL }; + const char *params_caps[] = { + "*", "LS", "identify-msg multi-prefix sasl", NULL + }; + const char *params_join[] = { "#channel", NULL }; + const char *params_join_extended[] = { + "#channel", "account", "real name", NULL + }; + const char *params_kick[] = { "#channel", "nick2", "kick reason", NULL }; + const char *params_mode[] = { "#channel", "+o", "nick", NULL }; + const char *params_mode_colon[] = { "#channel", "+o nick", NULL }; + const char *params_nick[] = { "newnick", NULL }; + const char *params_notice[] = { + "AUTH", "*** Looking up your hostname...", NULL + }; + const char *params_ping[] = { "arguments", NULL }; + const char *params_part[] = { "#channel", NULL }; + const char *params_invite[] = { "nick2", "#channel", NULL }; + const char *params_privmsg_no_msg[] = { "#channel", NULL }; + const char *params_privmsg[] = { "#channel", "the message", NULL }; + const char *params_privmsg_nick2[] = { "nick2", "the message", NULL }; + const char *params_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", NULL + }; + const char *params_301[] = { + "mynick", "nick", "away message for nick", NULL + }; + const char *params_error[] = { + "nick", "#channel", "Cannot send to channel", NULL + }; + int i, num_params, pos_command, pos_arguments, pos_channel, pos_text; WEE_CHECK_PARSE(NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, -1, -1, -1, -1, -1, NULL, NULL); WEE_CHECK_PARSE(NULL, "", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, -1, -1, -1, -1, -1, NULL, ""); WEE_CHECK_PARSE(NULL, ":nick!user@host", "nick", "user", "nick!user@host", NULL, NULL, NULL, NULL, + NULL, -1, -1, -1, -1, -1, NULL, ":nick!user@host"); @@ -305,10 +511,12 @@ TEST(IrcMessage, Parse) WEE_CHECK_PARSE(NULL, ":nick!user@host AWAY", "nick", "user", "nick!user@host", "AWAY", NULL, NULL, NULL, + NULL, -1, 16, -1, -1, -1, NULL, ":nick!user@host AWAY"); WEE_CHECK_PARSE(NULL, ":nick!user@host AWAY :I am away", "nick", "user", "nick!user@host", "AWAY", NULL, ":I am away", "I am away", + params_away, 1, 16, 21, -1, 22, NULL, ":nick!user@host AWAY :I am away"); @@ -318,6 +526,7 @@ TEST(IrcMessage, Parse) "irc.example.com", NULL, "irc.example.com", "CAP", "*", "* LS :identify-msg multi-prefix sasl", "LS :identify-msg multi-prefix sasl", + params_caps, 3, 17, 21, 21, 23, NULL, ":irc.example.com CAP * LS :identify-msg multi-prefix sasl"); @@ -325,12 +534,14 @@ TEST(IrcMessage, Parse) /* JOIN */ WEE_CHECK_PARSE(NULL, ":nick!user@host JOIN #channel", "nick", "user", "nick!user@host", "JOIN", "#channel", "#channel", NULL, + params_join, 1, 16, 21, 21, -1, NULL, ":nick!user@host JOIN #channel"); /* JOIN with colon */ WEE_CHECK_PARSE(NULL, ":nick!user@host JOIN :#channel", "nick", "user", "nick!user@host", "JOIN", "#channel", ":#channel", NULL, + params_join, 1, 16, 21, 22, -1, NULL, ":nick!user@host JOIN :#channel"); @@ -338,6 +549,7 @@ TEST(IrcMessage, Parse) WEE_CHECK_PARSE(NULL, ":nick!user@host JOIN #channel account :real name", "nick", "user", "nick!user@host", "JOIN", "#channel", "#channel account :real name", "account :real name", + params_join_extended, 3, 16, 21, 21, 30, NULL, ":nick!user@host JOIN #channel account :real name"); @@ -345,6 +557,7 @@ TEST(IrcMessage, Parse) WEE_CHECK_PARSE(NULL, ":nick1!user@host KICK #channel nick2 :kick reason", "nick1", "user", "nick1!user@host", "KICK", "#channel", "#channel nick2 :kick reason", "nick2 :kick reason", + params_kick, 3, 17, 22, 22, 31, NULL, ":nick1!user@host KICK #channel nick2 :kick reason"); @@ -352,6 +565,7 @@ TEST(IrcMessage, Parse) WEE_CHECK_PARSE(NULL, ":nick!user@host MODE #channel +o nick", "nick", "user", "nick!user@host", "MODE", "#channel", "#channel +o nick", "+o nick", + params_mode, 3, 16, 21, 21, 30, NULL, ":nick!user@host MODE #channel +o nick"); @@ -359,6 +573,7 @@ TEST(IrcMessage, Parse) WEE_CHECK_PARSE(NULL, ":nick!user@host MODE #channel :+o nick", "nick", "user", "nick!user@host", "MODE", "#channel", "#channel :+o nick", "+o nick", + params_mode_colon, 2, 16, 21, 21, 31, NULL, ":nick!user@host MODE #channel :+o nick"); @@ -366,6 +581,7 @@ TEST(IrcMessage, Parse) WEE_CHECK_PARSE(NULL, ":oldnick!user@host NICK :newnick", "oldnick", "user", "oldnick!user@host", "NICK", NULL, ":newnick", "newnick", + params_nick, 1, 19, 24, -1, 25, NULL, ":oldnick!user@host NICK :newnick"); @@ -374,24 +590,28 @@ TEST(IrcMessage, Parse) "AUTH", NULL, NULL, "NOTICE", "AUTH", "AUTH :*** Looking up your hostname...", "*** Looking up your hostname...", + params_notice, 2, 0, 7, 7, 13, NULL, "NOTICE AUTH :*** Looking up your hostname..."); /* PING */ WEE_CHECK_PARSE(NULL, "PING :arguments", NULL, NULL, NULL, "PING", NULL, ":arguments", "arguments", + params_ping, 1, 0, 5, -1, 6, NULL, "PING :arguments"); /* PART */ WEE_CHECK_PARSE(NULL, ":nick!user@host PART #channel", "nick", "user", "nick!user@host", "PART", "#channel", "#channel", NULL, + params_part, 1, 16, 21, 21, -1, NULL, ":nick!user@host PART #channel"); /* PART with colon */ WEE_CHECK_PARSE(NULL, ":nick!user@host PART :#channel", "nick", "user", "nick!user@host", "PART", "#channel", ":#channel", NULL, + params_part, 1, 16, 21, 22, -1, NULL, ":nick!user@host PART :#channel"); @@ -400,30 +620,36 @@ TEST(IrcMessage, Parse) "user", "nick!user@host", "INVITE", "#channel", "nick2 #channel", NULL, + params_invite, 2, 16, 23, 29, -1, NULL, ":nick!user@host INVITE nick2 #channel"); /* PRIVMSG */ WEE_CHECK_PARSE(NULL, ":nick PRIVMSG", "nick", NULL, "nick", "PRIVMSG", NULL, NULL, NULL, + NULL, -1, 6, -1, -1, -1, NULL, ":nick PRIVMSG"); WEE_CHECK_PARSE(NULL, ":nick@host PRIVMSG", "nick", NULL, "nick@host", "PRIVMSG", NULL, NULL, NULL, + NULL, -1, 11, -1, -1, -1, NULL, ":nick@host PRIVMSG"); WEE_CHECK_PARSE(NULL, ":nick!user@host PRIVMSG", "nick", "user", "nick!user@host", "PRIVMSG", NULL, NULL, NULL, + NULL, -1, 16, -1, -1, -1, NULL, ":nick!user@host PRIVMSG"); WEE_CHECK_PARSE(NULL, ":nick!user@host PRIVMSG #channel", "nick", "user", "nick!user@host", "PRIVMSG", "#channel", "#channel", NULL, + params_privmsg_no_msg, 1, 16, 24, 24, -1, NULL, ":nick!user@host PRIVMSG #channel"); WEE_CHECK_PARSE(NULL, ":nick!user@host PRIVMSG #channel :the message", "nick", "user", "nick!user@host", "PRIVMSG", "#channel", "#channel :the message", "the message", + params_privmsg, 2, 16, 24, 24, 34, NULL, ":nick!user@host PRIVMSG #channel :the message"); @@ -432,6 +658,7 @@ TEST(IrcMessage, Parse) ":nick!user@host PRIVMSG #channel :the message", "nick", "user", "nick!user@host", "PRIVMSG", "#channel", "#channel :the message", "the message", + params_privmsg, 2, 47, 55, 55, 65, NULL, "@time=2019-08-03T12:13:00.000Z :nick!user@host PRIVMSG " @@ -442,6 +669,7 @@ TEST(IrcMessage, Parse) ":nick!user@host PRIVMSG #channel :the message", "nick", "user", "nick!user@host", "PRIVMSG", "#channel", "#channel :the message", "the message", + params_privmsg, 2, 49, 58, 58, 69, NULL, "@time=2019-08-03T12:13:00.000Z :nick!user@host " @@ -451,6 +679,7 @@ TEST(IrcMessage, Parse) WEE_CHECK_PARSE(NULL, ":nick!user@host PRIVMSG nick2 :the message", "nick", "user", "nick!user@host", "PRIVMSG", "nick2", "nick2 :the message", "the message", + params_privmsg_nick2, 2, 16, 24, 24, 31, NULL, ":nick!user@host PRIVMSG nick2 :the message"); @@ -471,6 +700,7 @@ TEST(IrcMessage, Parse) "TOPICLEN=450 KICKLEN=450 CHANNELLEN=30 KEYLEN=23 " "CHANTYPES=# PREFIX=(ov)@+ CASEMAPPING=ascii CAPAB " "IRCD=dancer :are available on this server", + params_005, 16, 17, 21, 21, 28, NULL, ":irc.example.com 005 mynick MODES=4 CHANLIMIT=#:20 " @@ -486,6 +716,7 @@ TEST(IrcMessage, Parse) "mynick", "mynick nick :away message for nick", "nick :away message for nick", + params_301, 3, 17, 21, 21, 28, NULL, ":irc.example.com 301 mynick nick :away message for nick"); @@ -496,6 +727,7 @@ TEST(IrcMessage, Parse) "nick", NULL, NULL, "404", "#channel", "nick #channel :Cannot send to channel", "Cannot send to channel", + params_error, 3, 0, 4, 9, 19, NULL, "404 nick #channel :Cannot send to channel"); @@ -505,6 +737,7 @@ TEST(IrcMessage, Parse) "#channel", "nick #channel :Cannot send to channel", "Cannot send to channel", + params_error, 3, 17, 21, 26, 36, NULL, ":irc.example.com 404 nick #channel :Cannot send to channel"); @@ -519,12 +752,47 @@ TEST(IrcMessage, ParseToHashtable) { struct t_hashtable *hashtable; + hashtable = irc_message_parse_to_hashtable (NULL, "PING :arguments here"); + CHECK(hashtable); + STRCMP_EQUAL("", + (const char *)hashtable_get (hashtable, "tags")); + POINTERS_EQUAL(NULL, + (const char *)hashtable_get (hashtable, "tag_time")); + STRCMP_EQUAL(NULL, + (const char *)hashtable_get (hashtable, "tag_tag2")); + STRCMP_EQUAL("PING :arguments here", + (const char *)hashtable_get (hashtable, "message_without_tags")); + STRCMP_EQUAL("", + (const char *)hashtable_get (hashtable, "nick")); + STRCMP_EQUAL("", + (const char *)hashtable_get (hashtable, "host")); + STRCMP_EQUAL("PING", + (const char *)hashtable_get (hashtable, "command")); + STRCMP_EQUAL("", + (const char *)hashtable_get (hashtable, "channel")); + STRCMP_EQUAL(":arguments here", + (const char *)hashtable_get (hashtable, "arguments")); + STRCMP_EQUAL("arguments here", + (const char *)hashtable_get (hashtable, "text")); + STRCMP_EQUAL("1", + (const char *)hashtable_get (hashtable, "num_params")); + STRCMP_EQUAL("arguments here", + (const char *)hashtable_get (hashtable, "param1")); + STRCMP_EQUAL("0", + (const char *)hashtable_get (hashtable, "pos_command")); + STRCMP_EQUAL("5", + (const char *)hashtable_get (hashtable, "pos_arguments")); + STRCMP_EQUAL("-1", + (const char *)hashtable_get (hashtable, "pos_channel")); + STRCMP_EQUAL("6", + (const char *)hashtable_get (hashtable, "pos_text")); + hashtable_free (hashtable); + hashtable = irc_message_parse_to_hashtable ( NULL, "@time=2019-08-03T12:13:00.000Z;tag2=value\\sspace " ":nick!user@host PRIVMSG #channel :the message"); CHECK(hashtable); - STRCMP_EQUAL("time=2019-08-03T12:13:00.000Z;tag2=value\\sspace", (const char *)hashtable_get (hashtable, "tags")); STRCMP_EQUAL("2019-08-03T12:13:00.000Z", @@ -545,6 +813,12 @@ TEST(IrcMessage, ParseToHashtable) (const char *)hashtable_get (hashtable, "arguments")); STRCMP_EQUAL("the message", (const char *)hashtable_get (hashtable, "text")); + STRCMP_EQUAL("2", + (const char *)hashtable_get (hashtable, "num_params")); + STRCMP_EQUAL("#channel", + (const char *)hashtable_get (hashtable, "param1")); + STRCMP_EQUAL("the message", + (const char *)hashtable_get (hashtable, "param2")); STRCMP_EQUAL("65", (const char *)hashtable_get (hashtable, "pos_command")); STRCMP_EQUAL("73", @@ -553,7 +827,6 @@ TEST(IrcMessage, ParseToHashtable) (const char *)hashtable_get (hashtable, "pos_channel")); STRCMP_EQUAL("83", (const char *)hashtable_get (hashtable, "pos_text")); - hashtable_free (hashtable); }