diff options
-rw-r--r-- | ChangeLog.adoc | 1 | ||||
-rw-r--r-- | src/plugins/irc/irc-protocol.c | 39 | ||||
-rw-r--r-- | src/plugins/irc/irc-server.c | 33 | ||||
-rw-r--r-- | src/plugins/irc/irc-server.h | 1 | ||||
-rw-r--r-- | tests/unit/plugins/irc/test-irc-protocol.cpp | 31 |
5 files changed, 97 insertions, 8 deletions
diff --git a/ChangeLog.adoc b/ChangeLog.adoc index c80dd1e8c..012a06aa5 100644 --- a/ChangeLog.adoc +++ b/ChangeLog.adoc @@ -16,6 +16,7 @@ For a list of important changes that require manual actions, please look at rele Bug fixes:: * core: force key "return" to command "/input return" when migrating legacy keys + * irc: reply to a CTCP request sent to self nick (issue #1966) [[v4.0.0]] == Version 4.0.0 (2023-06-24) diff --git a/src/plugins/irc/irc-protocol.c b/src/plugins/irc/irc-protocol.c index ee764cb1c..ad13d08c2 100644 --- a/src/plugins/irc/irc-protocol.c +++ b/src/plugins/irc/irc-protocol.c @@ -2454,6 +2454,8 @@ IRC_PROTOCOL_CALLBACK(notice) struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick; int notify_private, is_channel, is_channel_orig, nick_is_me, display_host; + int cap_echo_message, msg_already_received; + time_t time_now; struct t_gui_buffer *ptr_buffer; IRC_PROTOCOL_MIN_PARAMS(2); @@ -2479,8 +2481,23 @@ IRC_PROTOCOL_CALLBACK(notice) if (nick && (pos_args[0] == '\01')) { - irc_ctcp_display_reply_from_nick (server, date, tags, command, nick, - address, pos_args); + cap_echo_message = weechat_hashtable_has_key (server->cap_list, + "echo-message"); + msg_already_received = weechat_hashtable_has_key ( + server->echo_msg_recv, irc_message); + if (!msg_already_received && cap_echo_message) + { + time_now = time (NULL); + weechat_hashtable_set (server->echo_msg_recv, + irc_message, &time_now); + } + if (!cap_echo_message || !msg_already_received) + { + irc_ctcp_display_reply_from_nick (server, date, tags, command, nick, + address, pos_args); + } + if (msg_already_received) + weechat_hashtable_remove (server->echo_msg_recv, irc_message); } else { @@ -3024,7 +3041,9 @@ IRC_PROTOCOL_CALLBACK(privmsg) { char *msg_args, *msg_args2, str_tags[1024], *str_color, *color; const char *pos_target, *remote_nick, *pv_tags; - int status_msg, is_channel, nick_is_me; + int status_msg, is_channel, nick_is_me, cap_echo_message; + int msg_already_received; + time_t time_now; struct t_irc_channel *ptr_channel; struct t_irc_nick *ptr_nick; @@ -3175,7 +3194,17 @@ IRC_PROTOCOL_CALLBACK(privmsg) /* CTCP to user */ if (msg_args[0] == '\01') { - if (nick_is_me) + cap_echo_message = weechat_hashtable_has_key (server->cap_list, + "echo-message"); + msg_already_received = weechat_hashtable_has_key ( + server->echo_msg_recv, irc_message); + if (!msg_already_received && cap_echo_message) + { + time_now = time (NULL); + weechat_hashtable_set (server->echo_msg_recv, + irc_message, &time_now); + } + if (nick_is_me && cap_echo_message && !msg_already_received) { irc_protocol_privmsg_display_ctcp_send ( server, remote_nick, address, msg_args); @@ -3185,6 +3214,8 @@ IRC_PROTOCOL_CALLBACK(privmsg) irc_ctcp_recv (server, date, tags, command, NULL, params[0], address, nick, remote_nick, msg_args, irc_message); } + if (msg_already_received) + weechat_hashtable_remove (server->echo_msg_recv, irc_message); goto end; } diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c index b8ad806c6..a86c2d34a 100644 --- a/src/plugins/irc/irc-server.c +++ b/src/plugins/irc/irc-server.c @@ -1768,6 +1768,11 @@ irc_server_alloc (const char *name) WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_TIME, NULL, NULL); + new_server->echo_msg_recv = weechat_hashtable_new ( + 32, + WEECHAT_HASHTABLE_STRING, + WEECHAT_HASHTABLE_TIME, + NULL, NULL); new_server->batches = NULL; new_server->last_batch = NULL; new_server->buffer = NULL; @@ -2254,6 +2259,7 @@ irc_server_free_data (struct t_irc_server *server) weechat_hashtable_free (server->join_manual); weechat_hashtable_free (server->join_channel_key); weechat_hashtable_free (server->join_noswitch); + weechat_hashtable_free (server->echo_msg_recv); /* free server data */ for (i = 0; i < IRC_SERVER_NUM_OPTIONS; i++) @@ -3915,6 +3921,23 @@ irc_server_check_join_smart_filtered_cb (void *data, } /* + * Callback called for each message received with echo-message: deletes old + * messages in the hashtable. + */ + +void +irc_server_check_echo_msg_recv_cb (void *data, + struct t_hashtable *hashtable, + const void *key, const void *value) +{ + /* make C compiler happy */ + (void) data; + + if (*((time_t *)value) + (60 * 5) < time (NULL)) + weechat_hashtable_remove (hashtable, key); +} + +/* * Timer called each second to perform some operations on servers. */ @@ -4094,6 +4117,9 @@ irc_server_timer_cb (const void *pointer, void *data, int remaining_calls) NULL); } } + weechat_hashtable_map (ptr_server->echo_msg_recv, + &irc_server_check_echo_msg_recv_cb, + NULL); ptr_batch = ptr_server->batches; while (ptr_batch) { @@ -4196,6 +4222,9 @@ irc_server_close_connection (struct t_irc_server *server) /* remove all keys for joins without switch */ weechat_hashtable_remove_all (server->join_noswitch); + /* remove all messages stored (with capability echo-message) */ + weechat_hashtable_remove_all (server->echo_msg_recv); + /* remove all batched events pending */ irc_batch_free_all (server); @@ -6476,6 +6505,7 @@ irc_server_hdata_server_cb (const void *pointer, void *data, WEECHAT_HDATA_VAR(struct t_irc_server, join_manual, HASHTABLE, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, join_channel_key, HASHTABLE, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, join_noswitch, HASHTABLE, 0, NULL, NULL); + WEECHAT_HDATA_VAR(struct t_irc_server, echo_msg_recv, HASHTABLE, 0, NULL, NULL); WEECHAT_HDATA_VAR(struct t_irc_server, batches, POINTER, 0, NULL, "irc_batch"); WEECHAT_HDATA_VAR(struct t_irc_server, last_batch, POINTER, 0, NULL, "irc_batch"); WEECHAT_HDATA_VAR(struct t_irc_server, buffer, POINTER, 0, NULL, "buffer"); @@ -7265,6 +7295,9 @@ irc_server_print_log () weechat_log_printf (" join_noswitch . . . . . . : 0x%lx (hashtable: '%s')", ptr_server->join_noswitch, weechat_hashtable_get_string (ptr_server->join_noswitch, "keys_values")); + weechat_log_printf (" echo_msg_recv . . . . . . : 0x%lx (hashtable: '%s')", + ptr_server->echo_msg_recv, + weechat_hashtable_get_string (ptr_server->echo_msg_recv, "keys_values")); weechat_log_printf (" batches . . . . . . . . . : 0x%lx", ptr_server->batches); weechat_log_printf (" last_batch. . . . . . . . : 0x%lx", ptr_server->last_batch); weechat_log_printf (" buffer. . . . . . . . . . : 0x%lx", ptr_server->buffer); diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h index cbfb05d82..4b88cfb33 100644 --- a/src/plugins/irc/irc-server.h +++ b/src/plugins/irc/irc-server.h @@ -289,6 +289,7 @@ struct t_irc_server struct t_hashtable *join_manual; /* manual joins pending */ struct t_hashtable *join_channel_key; /* keys pending for joins */ struct t_hashtable *join_noswitch; /* joins w/o switch to buffer */ + struct t_hashtable *echo_msg_recv; /* msg received with echo-message */ struct t_irc_batch *batches; /* batched events (cap "batch") */ struct t_irc_batch *last_batch; /* last batch */ struct t_gui_buffer *buffer; /* GUI buffer allocated for server */ diff --git a/tests/unit/plugins/irc/test-irc-protocol.cpp b/tests/unit/plugins/irc/test-irc-protocol.cpp index aed04e590..0a685c9aa 100644 --- a/tests/unit/plugins/irc/test-irc-protocol.cpp +++ b/tests/unit/plugins/irc/test-irc-protocol.cpp @@ -2950,10 +2950,33 @@ TEST(IrcProtocolWithServer, privmsg) * valid CTCP to channel from self nick * (case of bouncer of if echo-message capability is enabled) */ - RECV(":alice!user@host PRIVMSG bob :\01VERSION\01"); - CHECK_PV("bob", "--", "CTCP query to bob: VERSION", - "irc_privmsg,irc_ctcp,self_msg,notify_none,no_highlight," - "nick_alice,host_user@host,log1"); + RECV(":alice!user@host PRIVMSG alice :\01CLIENTINFO\01"); + if (i == 0) + { + CHECK_SRV("--", "CTCP requested by alice: CLIENTINFO", + "irc_privmsg,irc_ctcp,host_user@host,log1"); + CHECK_SRV("--", "CTCP reply to alice: CLIENTINFO ACTION DCC " + "CLIENTINFO FINGER PING SOURCE TIME USERINFO VERSION", + "irc_privmsg,irc_ctcp,irc_ctcp_reply,self_msg,notify_none," + "no_highlight,log1"); + } + else + { + CHECK_PV("alice", "--", "CTCP query to alice: CLIENTINFO", + "irc_privmsg,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(":alice!user@host PRIVMSG alice :\01CLIENTINFO\01"); + CHECK_SRV("--", "CTCP requested by alice: CLIENTINFO", + "irc_privmsg,irc_ctcp,host_user@host,log1"); + CHECK_SRV("--", "CTCP reply to alice: CLIENTINFO ACTION DCC " + "CLIENTINFO FINGER PING SOURCE TIME USERINFO VERSION", + "irc_privmsg,irc_ctcp,irc_ctcp_reply,self_msg,notify_none," + "no_highlight,log1"); + } /* close xfer buffer */ if (xfer_buffer) |