From 40bfded594a7821340b8434c4fb459ec2cde6f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Helleu?= Date: Sat, 6 Apr 2024 22:44:04 +0200 Subject: [PATCH] irc: fix display of reply for CTCP request received on a channel when capability echo-message is enabled --- ChangeLog.adoc | 1 + src/plugins/irc/irc-ctcp.c | 140 +++++++++++++++---- src/plugins/irc/irc-ctcp.h | 5 + src/plugins/irc/irc-protocol.c | 55 ++++---- tests/unit/plugins/irc/test-irc-protocol.cpp | 92 ++++++++---- 5 files changed, 213 insertions(+), 80 deletions(-) diff --git a/ChangeLog.adoc b/ChangeLog.adoc index cddfe7bc2..74bf6da28 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -53,6 +53,7 @@ Bug fixes:: * exec: remove trailing space on buffers with free content when line numbers are not displayed * exec: add missing exec tags in lines of buffers with free content (issue #2086) * fset: allow filename starting with "~" in command `/fset -export` + * irc: fix display of reply for CTCP request received on a channel when capability echo-message is enabled * irc: add missing tags on self action messages when capability echo-message is enabled (issue #2074) * irc: don't strip monospace color code 0x11 from incoming messages (issue #2073) * irc: fix random date displayed when a received message contains tags but no "time" (issue #2064) diff --git a/src/plugins/irc/irc-ctcp.c b/src/plugins/irc/irc-ctcp.c index 8b400041f..405bed8b3 100644 --- a/src/plugins/irc/irc-ctcp.c +++ b/src/plugins/irc/irc-ctcp.c @@ -169,6 +169,45 @@ irc_ctcp_get_reply (struct t_irc_server *server, const char *ctcp) return irc_ctcp_get_default_reply (ctcp); } +/* + * Extracts CTCP type and arguments from message, which format is: + * \01TYPE arguments...\01 + * + * Strings *type and *arguments are set with type and arguments parsed, + * both are set to NULL in case of error. + */ + +void +irc_ctcp_parse_type_arguments (const char *message, + char **type, char **arguments) +{ + const char *pos_end, *pos_space; + + if (!message || !type || !arguments) + return; + + *type = NULL; + *arguments = NULL; + + if (message[0] != '\01') + return; + + pos_end = strrchr (message + 1, '\01'); + if (!pos_end) + return; + + pos_space = strchr (message + 1, ' '); + + *type = weechat_strndup ( + message + 1, + (pos_space) ? pos_space - message - 1 : pos_end - message - 1); + if (!*type) + return; + + *arguments = (pos_space) ? + weechat_strndup (pos_space + 1, pos_end - pos_space - 1) : NULL; +} + /* * Displays CTCP requested by a nick. */ @@ -319,7 +358,68 @@ irc_ctcp_display_reply_from_nick (struct t_irc_protocol_ctxt *ctxt, } /* - * Displays CTCP replied to a nick. + * Displays CTCP reply to a nick (internal function). + */ + +void +irc_ctcp_display_reply_to_nick_internal (struct t_irc_protocol_ctxt *ctxt, + const char *target, + const char *type, + const char *args) +{ + weechat_printf_date_tags ( + irc_msgbuffer_get_target_buffer (ctxt->server, target, NULL, + "ctcp", NULL), + 0, + irc_protocol_tags (ctxt, + "irc_ctcp,irc_ctcp_reply,self_msg," + "notify_none,no_highlight"), + _("%sCTCP reply to %s%s%s: %s%s%s%s%s"), + weechat_prefix ("network"), + irc_nick_color_for_msg (ctxt->server, 0, NULL, target), + target, + IRC_COLOR_RESET, + IRC_COLOR_CHAT_CHANNEL, + type, + (args && args[0]) ? IRC_COLOR_RESET : "", + (args && args[0]) ? " " : "", + (args) ? args : ""); +} + +/* + * Displays CTCP reply to a nick. + */ + +void +irc_ctcp_display_reply_to_nick (struct t_irc_protocol_ctxt *ctxt, + const char *target, + const char *arguments) +{ + char *ctcp_type, *ctcp_args, *ctcp_args_no_colors; + + if (!ctxt || !arguments || (arguments[0] != '\01')) + return; + + irc_ctcp_parse_type_arguments (arguments, &ctcp_type, &ctcp_args); + + if (ctcp_type) + { + ctcp_args_no_colors = (ctcp_args) ? + irc_color_decode (ctcp_args, 1) : NULL; + irc_ctcp_display_reply_to_nick_internal (ctxt, target, ctcp_type, + ctcp_args_no_colors); + if (ctcp_args_no_colors) + free (ctcp_args_no_colors); + } + + if (ctcp_type) + free (ctcp_type); + if (ctcp_args) + free (ctcp_args); +} + +/* + * Replies to CTCP from a nick and displays reply. */ void @@ -328,8 +428,8 @@ irc_ctcp_reply_to_nick (struct t_irc_protocol_ctxt *ctxt, const char *arguments) { struct t_arraylist *list_messages; - int i, list_size; - char *msg_color, *dup_ctcp, *dup_ctcp_upper, *dup_args; + int i, list_size, length; + char *dup_ctcp, *dup_ctcp_upper, *dup_args, *message; const char *ptr_message; dup_ctcp = NULL; @@ -373,7 +473,8 @@ irc_ctcp_reply_to_nick (struct t_irc_protocol_ctxt *ctxt, if (!list_messages) goto end; - if (weechat_config_boolean (irc_config_look_display_ctcp_reply)) + if (weechat_config_boolean (irc_config_look_display_ctcp_reply) + && !weechat_hashtable_has_key (ctxt->server->cap_list, "echo-message")) { list_size = weechat_arraylist_size (list_messages); for (i = 0; i < list_size; i++) @@ -381,27 +482,16 @@ irc_ctcp_reply_to_nick (struct t_irc_protocol_ctxt *ctxt, ptr_message = (const char *)weechat_arraylist_get (list_messages, i); if (!ptr_message) break; - msg_color = irc_color_decode (ptr_message, 1); - if (!msg_color) - break; - weechat_printf_date_tags ( - irc_msgbuffer_get_target_buffer (ctxt->server, ctxt->nick, - NULL, "ctcp", NULL), - 0, - irc_protocol_tags (ctxt, - "irc_ctcp,irc_ctcp_reply,self_msg," - "notify_none,no_highlight"), - _("%sCTCP reply to %s%s%s: %s%s%s%s%s"), - weechat_prefix ("network"), - irc_nick_color_for_msg (ctxt->server, 0, NULL, ctxt->nick), - ctxt->nick, - IRC_COLOR_RESET, - IRC_COLOR_CHAT_CHANNEL, - dup_ctcp_upper, - (msg_color[0]) ? IRC_COLOR_RESET : "", - (msg_color[0]) ? " " : "", - msg_color); - free (msg_color); + /* build arguments: '\01' + CTCP + ' ' + message + '\01' */ + length = 1 + strlen (dup_ctcp_upper) + 1 + strlen (ptr_message) + 1 + 1; + message = malloc (length); + if (message) + { + snprintf (message, length, + "\01%s %s\01", dup_ctcp_upper, ptr_message); + irc_ctcp_display_reply_to_nick (ctxt, ctxt->nick, message); + free (message); + } } } diff --git a/src/plugins/irc/irc-ctcp.h b/src/plugins/irc/irc-ctcp.h index 11cd250fe..083d1ef1d 100644 --- a/src/plugins/irc/irc-ctcp.h +++ b/src/plugins/irc/irc-ctcp.h @@ -38,8 +38,13 @@ extern char *irc_ctcp_convert_legacy_format (const char *format); extern const char *irc_ctcp_get_default_reply (const char *ctcp); extern const char *irc_ctcp_get_reply (struct t_irc_server *server, const char *ctcp); +extern void irc_ctcp_parse_type_arguments (const char *message, + char **type, char **arguments); extern void irc_ctcp_display_reply_from_nick (struct t_irc_protocol_ctxt *ctxt, const char *arguments); +extern void irc_ctcp_display_reply_to_nick (struct t_irc_protocol_ctxt *ctxt, + const char *target, + const char *arguments); extern char *irc_ctcp_eval_reply (struct t_irc_server *server, const char *format); extern void irc_ctcp_recv (struct t_irc_protocol_ctxt *ctxt, diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index 32e5a91b8..ac1fb725d 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -2538,10 +2538,24 @@ IRC_PROTOCOL_CALLBACK(notice) weechat_hashtable_set (ctxt->server->echo_msg_recv, ctxt->irc_message, &time_now); } - if (!cap_echo_message || !msg_already_received) + if (!cap_echo_message || !ctxt->nick_is_me) { irc_ctcp_display_reply_from_nick (ctxt, pos_args); } + else + { + if (msg_already_received) + { + irc_ctcp_display_reply_from_nick (ctxt, pos_args); + } + else + { + irc_ctcp_display_reply_to_nick ( + ctxt, + (ctxt->nick_is_me) ? pos_target : ctxt->nick, + pos_args); + } + } if (msg_already_received) weechat_hashtable_remove (ctxt->server->echo_msg_recv, ctxt->irc_message); } @@ -3033,36 +3047,27 @@ irc_protocol_privmsg_display_ctcp_send (struct t_irc_protocol_ctxt *ctxt, const char *target, const char *arguments) { - const char *pos_space, *pos_end; char *ctcp_type, *ctcp_args; if (!arguments || !arguments[0]) return; - pos_end = strrchr (arguments + 1, '\01'); - if (!pos_end) - return; + irc_ctcp_parse_type_arguments (arguments, &ctcp_type, &ctcp_args); - pos_space = strchr (arguments + 1, ' '); - - ctcp_type = weechat_strndup ( - arguments + 1, - (pos_space) ? - pos_space - arguments - 1 : pos_end - arguments - 1); - ctcp_args = (pos_space) ? - weechat_strndup (pos_space + 1, pos_end - pos_space - 1) : NULL; - - irc_input_user_message_display ( - ctxt->server, - ctxt->date, - ctxt->date_usec, - ctxt->tags, - target, - ctxt->address, - "privmsg", - ctcp_type, - ctcp_args, - 0); /* decode_colors */ + if (ctcp_type) + { + irc_input_user_message_display ( + ctxt->server, + ctxt->date, + ctxt->date_usec, + ctxt->tags, + target, + ctxt->address, + "privmsg", + ctcp_type, + ctcp_args, + 0); /* decode_colors */ + } if (ctcp_type) free (ctcp_type); diff --git a/tests/unit/plugins/irc/test-irc-protocol.cpp b/tests/unit/plugins/irc/test-irc-protocol.cpp index bf4ac67cb..aa0ea10dd 100644 --- a/tests/unit/plugins/irc/test-irc-protocol.cpp +++ b/tests/unit/plugins/irc/test-irc-protocol.cpp @@ -3041,9 +3041,13 @@ TEST(IrcProtocolWithServer, privmsg) "irc_privmsg,irc_ctcp,nick_bob,host_user@host,log1"); snprintf (message, sizeof (message), "CTCP reply to bob: VERSION %s", info); - CHECK_SRV("--", message, - "irc_privmsg,irc_ctcp,irc_ctcp_reply,self_msg,notify_none," - "no_highlight,nick_alice,log1"); + if (echo_message == 0) + { + /* reply is displayed only if echo-message is NOT enabled */ + CHECK_SRV("--", message, + "irc_privmsg,irc_ctcp,irc_ctcp_reply,self_msg,notify_none," + "no_highlight,nick_alice,log1"); + } snprintf (message, sizeof (message), "NOTICE bob :\01VERSION %s\01", info); CHECK_SENT(message); @@ -3090,9 +3094,13 @@ TEST(IrcProtocolWithServer, privmsg) CHECK_SENT(message); snprintf (message, sizeof (message), "CTCP reply to bob: VERSION %s", info); - CHECK_SRV("--", message, - "irc_privmsg,irc_ctcp,irc_ctcp_reply,self_msg,notify_none," - "no_highlight,nick_alice,log1"); + if (echo_message == 0) + { + /* reply is displayed only if echo-message is NOT enabled */ + CHECK_SRV("--", message, + "irc_privmsg,irc_ctcp,irc_ctcp_reply,self_msg,notify_none," + "no_highlight,nick_alice,log1"); + } free (info); RECV(":bob!user@host PRIVMSG alice :\01DCC"); CHECK_SENT(NULL); @@ -3131,10 +3139,14 @@ TEST(IrcProtocolWithServer, privmsg) CHECK_CHAN("--", "CTCP requested by bob: PING 1703496549 905284", "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," "irc_ctcp,nick_bob,host_user@host,log1"); - CHECK_SRV("--", "CTCP reply to bob: PING 1703496549 905284", - "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," - "irc_ctcp,irc_ctcp_reply,self_msg,notify_none," - "no_highlight,nick_alice,log1"); + if (echo_message == 0) + { + /* reply is displayed only if echo-message is NOT enabled */ + CHECK_SRV("--", "CTCP reply to bob: PING 1703496549 905284", + "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," + "irc_ctcp,irc_ctcp_reply,self_msg,notify_none," + "no_highlight,nick_alice,log1"); + } RECV("@time=2023-12-25T10:29:09.456789Z " ":bob!user@host PRIVMSG #test :\01UNKNOWN\01"); CHECK_SENT(NULL); @@ -3161,10 +3173,14 @@ TEST(IrcProtocolWithServer, privmsg) CHECK_CHAN("--", "CTCP requested by bob: PING 1703496549 905284", "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," "irc_ctcp,nick_bob,host_user@host,log1"); - CHECK_SRV("--", "CTCP reply to bob: PING 1703496549 905284", - "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," - "irc_ctcp,irc_ctcp_reply,self_msg,notify_none," - "no_highlight,nick_alice,log1"); + if (echo_message == 0) + { + /* reply is displayed only if echo-message is NOT enabled */ + CHECK_SRV("--", "CTCP reply to bob: PING 1703496549 905284", + "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," + "irc_ctcp,irc_ctcp_reply,self_msg,notify_none," + "no_highlight,nick_alice,log1"); + } RECV("@time=2023-12-25T10:29:09.456789Z " ":bob!user@host PRIVMSG @#test :\01UNKNOWN\01"); CHECK_SENT(NULL); @@ -3261,10 +3277,14 @@ TEST(IrcProtocolWithServer, privmsg) CHECK_SRV("--", "CTCP requested by bob: PING 1703496549 905284", "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," "irc_ctcp,nick_bob,host_user@host,log1"); - CHECK_SRV("--", "CTCP reply to bob: PING 1703496549 905284", - "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," - "irc_ctcp,irc_ctcp_reply,self_msg,notify_none," - "no_highlight,nick_alice,log1"); + if (echo_message == 0) + { + /* reply is displayed only if echo-message is NOT enabled */ + CHECK_SRV("--", "CTCP reply to bob: PING 1703496549 905284", + "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," + "irc_ctcp,irc_ctcp_reply,self_msg,notify_none," + "no_highlight,nick_alice,log1"); + } RECV("@time=2023-12-25T10:29:09.456789Z " ":bob!user@host PRIVMSG alice :\01UNKNOWN\01"); CHECK_SENT(NULL); @@ -3283,10 +3303,14 @@ TEST(IrcProtocolWithServer, privmsg) "irc_ctcp,nick_bob,host_user@host,log1"); snprintf (message, sizeof (message), "CTCP reply to bob: VERSION %s", info); - CHECK_SRV("--", message, - "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," - "irc_ctcp,irc_ctcp_reply,self_msg,notify_none,no_highlight," - "nick_alice,log1"); + if (echo_message == 0) + { + /* reply is displayed only if echo-message is NOT enabled */ + CHECK_SRV("--", message, + "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," + "irc_ctcp,irc_ctcp_reply,self_msg,notify_none,no_highlight," + "nick_alice,log1"); + } snprintf (message, sizeof (message), "NOTICE bob :\01VERSION %s\01", info); CHECK_SENT(message); @@ -3307,7 +3331,7 @@ TEST(IrcProtocolWithServer, privmsg) CHECK_SENT(NULL); /* - * valid CTCP to channel from self nick + * valid CTCP to user from self nick * (case of bouncer or if echo-message capability is enabled) */ RECV("@time=2023-12-25T10:29:09.456789Z " @@ -3332,10 +3356,6 @@ TEST(IrcProtocolWithServer, privmsg) "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," "irc_ctcp,self_msg,notify_none,no_highlight,nick_alice," "host_user@host,log1"); - /* - * with echo-message capability, when the same message is received - * for the second time, the request and reply are displayed - */ RECV("@time=2023-12-25T10:29:09.456789Z " ":alice!user@host PRIVMSG alice :\01CLIENTINFO\01"); CHECK_SENT("NOTICE alice :\01CLIENTINFO ACTION CLIENTINFO DCC " @@ -3343,11 +3363,23 @@ TEST(IrcProtocolWithServer, privmsg) CHECK_SRV("--", "CTCP requested by alice: CLIENTINFO", "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," "irc_ctcp,nick_alice,host_user@host,log1"); - CHECK_SRV("--", "CTCP reply to alice: CLIENTINFO ACTION CLIENTINFO " - "DCC PING SOURCE TIME VERSION", - "irc_privmsg,irc_tag_time=2023-12-25T10:29:09.456789Z," + RECV("@time=2023-12-25T10:29:09.456789Z " + ":alice!user@host NOTICE alice :\01CLIENTINFO DCC PING " + "SOURCE TIME VERSION\01"); + CHECK_SENT(NULL); + CHECK_SRV("--", "CTCP reply to alice: CLIENTINFO DCC PING " + "SOURCE TIME VERSION", + "irc_notice,irc_tag_time=2023-12-25T10:29:09.456789Z," "irc_ctcp,irc_ctcp_reply,self_msg,notify_none," "no_highlight,nick_alice,host_user@host,log1"); + RECV("@time=2023-12-25T10:29:09.456789Z " + ":alice!user@host NOTICE alice :\01CLIENTINFO DCC PING " + "SOURCE TIME VERSION\01"); + CHECK_SENT(NULL); + CHECK_SRV("--", "CTCP reply from alice: CLIENTINFO DCC PING " + "SOURCE TIME VERSION", + "irc_notice,irc_tag_time=2023-12-25T10:29:09.456789Z," + "irc_ctcp,nick_alice,host_user@host,log1"); } /* close xfer buffer */