summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog.adoc1
-rw-r--r--src/plugins/irc/irc-protocol.c39
-rw-r--r--src/plugins/irc/irc-server.c33
-rw-r--r--src/plugins/irc/irc-server.h1
-rw-r--r--tests/unit/plugins/irc/test-irc-protocol.cpp31
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)