From b8048b166652f62507c75065b0c673da366e8517 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Helleu?= Date: Sat, 22 Nov 2025 12:30:11 +0100 Subject: [PATCH] irc: fix reset of color when multiple modes are set with command `/mode` --- CHANGELOG.md | 1 + src/plugins/irc/irc-mode.c | 35 +++---- src/plugins/irc/irc-mode.h | 2 +- src/plugins/irc/irc-protocol.c | 4 +- tests/unit/plugins/irc/test-irc-mode.cpp | 100 ++++++++++++++++--- tests/unit/plugins/irc/test-irc-protocol.cpp | 18 ++-- 6 files changed, 120 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d417ee832..7b23c0ba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - irc: fix warning on creation of irc.msgbuffer option when the server name contains upper case letters ([#2281](https://github.com/weechat/weechat/issues/2281)) - irc: display a warning for each unknown or invalid server option in commands /connect and /server - irc: fix colors in messages 367 (ban mask), 728 (quiet mask) and MODE ([#2286](https://github.com/weechat/weechat/issues/2286)) +- irc: fix reset of color when multiple modes are set with command `/mode` - relay/api: fix crash when an invalid HTTP request is received from a client - relay/api: return HTTP error 404 instead of 400 when the buffer is not found in resources completion and input - relay/api: return HTTP error 400 in case of invalid body in resource ping diff --git a/src/plugins/irc/irc-mode.c b/src/plugins/irc/irc-mode.c index dfc93e5b9..b549cccd6 100644 --- a/src/plugins/irc/irc-mode.c +++ b/src/plugins/irc/irc-mode.c @@ -28,6 +28,7 @@ #include "../weechat-plugin.h" #include "irc.h" +#include "irc-color.h" #include "irc-mode.h" #include "irc-config.h" #include "irc-server.h" @@ -37,18 +38,24 @@ /* - * Gets mode arguments: skip colons before arguments. + * Gets mode arguments: skips colons before arguments and converts IRC color + * codes into WeeChat color codes, so that the result can be displayed in a + * buffer. */ char * -irc_mode_get_arguments (const char *arguments) +irc_mode_get_arguments_colors (const char *arguments) { - char **argv, **argv2, *new_arguments; + char **argv, **new_arguments; int argc, i; if (!arguments || !arguments[0]) return strdup (""); + new_arguments = weechat_string_dyn_alloc (1024); + if (!new_arguments) + return NULL; + argv = weechat_string_split (arguments, " ", NULL, WEECHAT_STRING_SPLIT_STRIP_LEFT | WEECHAT_STRING_SPLIT_STRIP_RIGHT @@ -57,26 +64,20 @@ irc_mode_get_arguments (const char *arguments) 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]; + if ((*new_arguments)[0]) + weechat_string_dyn_concat (new_arguments, " ", -1); + weechat_string_dyn_concat ( + new_arguments, + (argv[i][0] == ':') ? IRC_COLOR_MSG(argv[i] + 1) : IRC_COLOR_MSG(argv[i]), + -1); + weechat_string_dyn_concat (new_arguments, IRC_COLOR_RESET, -1); } - argv2[argc] = NULL; - - new_arguments = weechat_string_rebuild_split_string ( - (const char **)argv2, " ", 0, -1); weechat_string_free_split (argv); - free (argv2); - return new_arguments; + return weechat_string_dyn_free (new_arguments, 0); } /* diff --git a/src/plugins/irc/irc-mode.h b/src/plugins/irc/irc-mode.h index b04835506..899c36be5 100644 --- a/src/plugins/irc/irc-mode.h +++ b/src/plugins/irc/irc-mode.h @@ -25,7 +25,7 @@ struct t_irc_server; struct t_irc_channel; -extern char *irc_mode_get_arguments (const char *arguments); +extern char *irc_mode_get_arguments_colors (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 7921ca4ce..39f3d5826 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -2182,7 +2182,7 @@ IRC_PROTOCOL_CALLBACK(mode) } ptr_nick = irc_nick_search (ctxt->server, ptr_channel, ctxt->nick); ptr_buffer = (ptr_channel) ? ptr_channel->buffer : ctxt->server->buffer; - modes_args = irc_mode_get_arguments (msg_modes_args); + modes_args = irc_mode_get_arguments_colors (msg_modes_args); weechat_printf_datetime_tags ( irc_msgbuffer_get_target_buffer (ctxt->server, NULL, ctxt->command, NULL, ptr_buffer), @@ -2199,7 +2199,7 @@ IRC_PROTOCOL_CALLBACK(mode) IRC_COLOR_RESET, ctxt->params[1], /* mode */ (modes_args && modes_args[0]) ? " " : "", - (modes_args && modes_args[0]) ? IRC_COLOR_MSG(modes_args) : "", + (modes_args && modes_args[0]) ? modes_args : "", IRC_COLOR_CHAT_DELIMITERS, IRC_COLOR_RESET, irc_nick_color_for_msg (ctxt->server, 1, ptr_nick, ctxt->nick), diff --git a/tests/unit/plugins/irc/test-irc-mode.cpp b/tests/unit/plugins/irc/test-irc-mode.cpp index aec1a4e65..2f15e36fd 100644 --- a/tests/unit/plugins/irc/test-irc-mode.cpp +++ b/tests/unit/plugins/irc/test-irc-mode.cpp @@ -25,11 +25,13 @@ extern "C" { +#include "src/gui/gui-color.h" +#include "src/plugins/irc/irc-color.h" #include "src/plugins/irc/irc-mode.h" } #define WEE_CHECK_GET_ARGS(__result, __arguments) \ - str = irc_mode_get_arguments (__arguments); \ + str = irc_mode_get_arguments_colors (__arguments); \ STRCMP_EQUAL(__result, str); \ free (str); @@ -44,23 +46,93 @@ TEST_GROUP(IrcMode) TEST(IrcMode, GetArguments) { - char *str; + char *str, string[1024], expected[1024]; /* 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 (" ")); + WEE_CHECK_GET_ARGS("", NULL); + WEE_CHECK_GET_ARGS("", ""); + WEE_CHECK_GET_ARGS("", " "); /* 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")); + snprintf (string, sizeof (string), "abc%c02_blue", IRC_COLOR_COLOR_CHAR); + snprintf (expected, sizeof (expected), + "abc%s_blue%s", + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset")); + WEE_CHECK_GET_ARGS(expected, string); + snprintf (string, sizeof (string), + "abc%c02_blue def%c02_blue", + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR); + snprintf (expected, sizeof (expected), + "abc%s_blue%s def%s_blue%s", + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset"), + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset")); + WEE_CHECK_GET_ARGS(expected, string); + snprintf (string, sizeof (string), + "abc%c02_blue def%c02_blue ghi%c02_blue", + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR); + snprintf (expected, sizeof (expected), + "abc%s_blue%s def%s_blue%s ghi%s_blue%s", + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset"), + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset"), + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset")); + WEE_CHECK_GET_ARGS(expected, string); /* 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")); + snprintf (string, sizeof (string), ":abc%c02_blue", IRC_COLOR_COLOR_CHAR); + snprintf (expected, sizeof (expected), + "abc%s_blue%s", + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset")); + WEE_CHECK_GET_ARGS(expected, string); + snprintf (string, sizeof (string), + ":abc%c02_blue def%c02_blue", + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR); + snprintf (expected, sizeof (expected), + "abc%s_blue%s def%s_blue%s", + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset"), + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset")); + WEE_CHECK_GET_ARGS(expected, string); + snprintf (string, sizeof (string), + "abc%c02_blue :def%c02_blue", + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR); + WEE_CHECK_GET_ARGS(expected, string); + snprintf (string, sizeof (string), + "abc%c02_blue :def%c02_blue ghi%c02_blue", + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR); + snprintf (expected, sizeof (expected), + "abc%s_blue%s def%s_blue%s ghi%s_blue%s", + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset"), + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset"), + gui_color_get_custom ("|blue"), + gui_color_get_custom ("reset")); + WEE_CHECK_GET_ARGS(expected, string); + snprintf (string, sizeof (string), + "abc%c02_blue :def%c02_blue :ghi%c02_blue", + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR); + WEE_CHECK_GET_ARGS(expected, string); + snprintf (string, sizeof (string), + ":abc%c02_blue :def%c02_blue :ghi%c02_blue", + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR, + IRC_COLOR_COLOR_CHAR); + WEE_CHECK_GET_ARGS(expected, string); } diff --git a/tests/unit/plugins/irc/test-irc-protocol.cpp b/tests/unit/plugins/irc/test-irc-protocol.cpp index 0f0c7b4e7..f1d08089c 100644 --- a/tests/unit/plugins/irc/test-irc-protocol.cpp +++ b/tests/unit/plugins/irc/test-irc-protocol.cpp @@ -2316,14 +2316,20 @@ TEST(IrcProtocolWithServer, mode) "irc_mode,nick_admin,host_user@host,log3"); STRCMP_EQUAL(NULL, ptr_channel->modes); - /* ban added on channel */ - RECV(":admin!user@host MODE #test +b bob!user_\00304red@host_\00304red"); - CHECK_CHAN("--", "Mode #test [+b bob!user_red@host_red] by admin", + /* bans added on channel */ + RECV(":admin!user@host MODE #test +bb " + "bob!user_\00304red@host_\00304red " + "carol!user_\00304red@host_\00304red"); + CHECK_CHAN("--", "Mode #test [+bb bob!user_red@host_red " + "carol!user_red@host_red] by admin", "irc_mode,nick_admin,host_user@host,log3"); - /* ban removed from channel */ - RECV(":admin!user@host MODE #test -b bob!user_\00304red@host_\00304red"); - CHECK_CHAN("--", "Mode #test [-b bob!user_red@host_red] by admin", + /* bans removed from channel */ + RECV(":admin!user@host MODE #test -bb " + "bob!user_\00304red@host_\00304red " + "carol!user_\00304red@host_\00304red"); + CHECK_CHAN("--", "Mode #test [-bb bob!user_red@host_red " + "carol!user_red@host_red] by admin", "irc_mode,nick_admin,host_user@host,log3"); /* nick mode '@' on channel #test */