diff --git a/ChangeLog.adoc b/ChangeLog.adoc index 20528961b..3b41166c3 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -42,6 +42,7 @@ Bug fixes:: * core: set max length to 4096 for /secure passphrase (issue #1323) * core: refilter only affected buffers on filter change (issue #1309, issue #1311) * fset: fix slow refresh of fset buffer during /reload (issue #1313) + * irc: fix parsing of MODE command when there are colons after the first mode argument (issue #1296) * irc: fix memory leak in infos "irc_server_isupport" and "irc_server_isupport_value" * irc: fix length of string for SHA-512, SHA-256 and SHA-1 in help on ssl_fingerprint option * irc: display an error with /allchan -current or /allpv -current if the current buffer is not an irc buffer (issue #1325) diff --git a/src/plugins/irc/irc-mode.c b/src/plugins/irc/irc-mode.c index d05ae2318..3648cffc5 100644 --- a/src/plugins/irc/irc-mode.c +++ b/src/plugins/irc/irc-mode.c @@ -34,6 +34,49 @@ #include "irc-modelist.h" +/* + * Gets mode arguments: skip colons before arguments. + */ + +char * +irc_mode_get_arguments (const char *arguments) +{ + char **argv, **argv2, *new_arguments; + int argc, i; + + if (!arguments || !arguments[0]) + return strdup (""); + + argv = weechat_string_split (arguments, " ", + WEECHAT_STRING_SPLIT_STRIP_LEFT + | WEECHAT_STRING_SPLIT_STRIP_RIGHT + | WEECHAT_STRING_SPLIT_COLLAPSE_SEPS, + 0, &argc); + if (!argv) + return strdup (""); + + argv2 = malloc (sizeof (*argv) * (argc + 1)); + if (!argv2) + { + weechat_string_free_split (argv); + return strdup ("");; + } + + for (i = 0; i < argc; i++) + { + argv2[i] = (argv[i][0] == ':') ? argv[i] + 1 : argv[i]; + } + argv2[argc] = NULL; + + new_arguments = weechat_string_build_with_split_string ( + (const char **)argv2, " "); + + weechat_string_free_split (argv); + free (argv2); + + return new_arguments; +} + /* * Gets type of channel mode, which is a letter from 'A' to 'D': * A = Mode that adds or removes a nick or address to a list. Always has a @@ -397,7 +440,11 @@ irc_mode_channel_set (struct t_irc_server *server, break; } if (ptr_arg) + { + if (ptr_arg[0] == ':') + ptr_arg++; current_arg++; + } if (smart_filter && !irc_mode_smart_filtered (server, pos[0])) diff --git a/src/plugins/irc/irc-mode.h b/src/plugins/irc/irc-mode.h index bb7982475..a26e62188 100644 --- a/src/plugins/irc/irc-mode.h +++ b/src/plugins/irc/irc-mode.h @@ -23,6 +23,7 @@ struct t_irc_server; struct t_irc_channel; +extern char *irc_mode_get_arguments (const char *arguments); extern char irc_mode_get_chanmode_type (struct t_irc_server *server, char chanmode); extern int irc_mode_channel_set (struct t_irc_server *server, diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index 777141e2c..5bc2cec5c 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -1424,7 +1424,7 @@ IRC_PROTOCOL_CALLBACK(kill) IRC_PROTOCOL_CALLBACK(mode) { - char *pos_modes, *pos_modes_args; + char *pos_modes, *pos_modes_args, *modes_args; int smart_filter, local_mode; struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick; @@ -1449,6 +1449,7 @@ IRC_PROTOCOL_CALLBACK(mode) local_mode = (irc_server_strcasecmp (server, nick, server->nick) == 0); ptr_nick = irc_nick_search (server, ptr_channel, nick); ptr_buffer = (ptr_channel) ? ptr_channel->buffer : server->buffer; + modes_args = irc_mode_get_arguments (pos_modes_args); weechat_printf_date_tags ( irc_msgbuffer_get_target_buffer (server, NULL, command, NULL, ptr_buffer), @@ -1464,12 +1465,14 @@ IRC_PROTOCOL_CALLBACK(mode) IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_RESET, pos_modes, - (pos_modes_args) ? " " : "", - (pos_modes_args) ? pos_modes_args : "", + (modes_args && modes_args[0]) ? " " : "", + (modes_args && modes_args[0]) ? modes_args : "", IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_RESET, irc_nick_color_for_msg (server, 1, ptr_nick, nick), nick); + if (modes_args) + free (modes_args); } else { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0b7a245eb..e397eeed8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -46,6 +46,7 @@ add_library(weechat_unit_tests_core STATIC ${LIB_WEECHAT_UNIT_TESTS_CORE_SRC}) set(LIB_WEECHAT_UNIT_TESTS_PLUGINS_SRC unit/plugins/irc/test-irc-color.cpp unit/plugins/irc/test-irc-config.cpp + unit/plugins/irc/test-irc-mode.cpp unit/plugins/irc/test-irc-protocol.cpp ) add_library(weechat_unit_tests_plugins MODULE ${LIB_WEECHAT_UNIT_TESTS_PLUGINS_SRC}) diff --git a/tests/Makefile.am b/tests/Makefile.am index c0c3667c0..d91d83b61 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -63,6 +63,7 @@ lib_LTLIBRARIES = lib_weechat_unit_tests_plugins.la lib_weechat_unit_tests_plugins_la_SOURCES = unit/plugins/irc/test-irc-color.cpp \ unit/plugins/irc/test-irc-config.cpp \ + unit/plugins/irc/test-irc-mode.cpp \ unit/plugins/irc/test-irc-protocol.cpp lib_weechat_unit_tests_plugins_la_LDFLAGS = -module -no-undefined diff --git a/tests/unit/plugins/irc/test-irc-mode.cpp b/tests/unit/plugins/irc/test-irc-mode.cpp new file mode 100644 index 000000000..6d9d7d643 --- /dev/null +++ b/tests/unit/plugins/irc/test-irc-mode.cpp @@ -0,0 +1,72 @@ +/* + * test-irc-mode.cpp - test IRC mode functions + * + * Copyright (C) 2019 Sébastien Helleu + * + * This file is part of WeeChat, the extensible chat client. + * + * WeeChat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * WeeChat is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with WeeChat. If not, see . + */ + +#include "CppUTest/TestHarness.h" + +extern "C" +{ +#include "src/plugins/irc/irc-mode.h" +} + +#define WEE_CHECK_GET_ARGS(__result, __arguments) \ + str = irc_mode_get_arguments (__arguments); \ + if (__result == NULL) \ + { \ + POINTERS_EQUAL(NULL, str); \ + } \ + else \ + { \ + STRCMP_EQUAL(__result, str); \ + } \ + if (str) \ + free (str); + +TEST_GROUP(IrcMode) +{ +}; + +/* + * Tests functions: + * irc_mode_get_arguments + */ + +TEST(IrcMode, GetArguments) +{ + char *str; + + /* invalid arguments */ + WEE_CHECK_GET_ARGS("", irc_mode_get_arguments (NULL)); + WEE_CHECK_GET_ARGS("", irc_mode_get_arguments ("")); + WEE_CHECK_GET_ARGS("", irc_mode_get_arguments (" ")); + + /* simple arguments */ + WEE_CHECK_GET_ARGS("abc", irc_mode_get_arguments ("abc")); + WEE_CHECK_GET_ARGS("abc def", irc_mode_get_arguments ("abc def")); + WEE_CHECK_GET_ARGS("abc def ghi", irc_mode_get_arguments ("abc def ghi")); + + /* some arguments starting with a colon */ + WEE_CHECK_GET_ARGS("abc", irc_mode_get_arguments (":abc")); + WEE_CHECK_GET_ARGS("abc def", irc_mode_get_arguments (":abc def")); + WEE_CHECK_GET_ARGS("abc def", irc_mode_get_arguments ("abc :def")); + WEE_CHECK_GET_ARGS("abc def ghi", irc_mode_get_arguments ("abc :def ghi")); + WEE_CHECK_GET_ARGS("abc def ghi", irc_mode_get_arguments ("abc :def :ghi")); + WEE_CHECK_GET_ARGS("abc def ghi", irc_mode_get_arguments (":abc :def :ghi")); +}