# HG changeset patch # User Gary Kramlich # Date 1745296919 18000 # Node ID ce4987105a4e6192bdafa498122be5c2f60f4a0d # Parent 42e7b89033fe233131739bca2b36f79fb0539884 IRCv3: Do a who after joining a channel This is necessary to synchronize away states and some other stuff. This also allows us to ignore the implicit namreply when joining a channel since the who messages contain a superset of that information. Testing Done: Connected to my local ergo and look at the packet capture and verified that no namreply was sent and that the conversation member list looked correct. Bugs closed: PIDGIN-17936 Reviewed at https://reviews.imfreedom.org/r/3981/ diff -r 42e7b89033fe -r ce4987105a4e protocols/ircv3/purpleircv3connection.c --- a/protocols/ircv3/purpleircv3connection.c Mon Apr 21 23:09:08 2025 -0500 +++ b/protocols/ircv3/purpleircv3connection.c Mon Apr 21 23:41:59 2025 -0500 @@ -483,6 +483,13 @@ G_CALLBACK(purple_ircv3_message_handler_mode), connection, G_CONNECT_DEFAULT); + g_signal_connect_object(client, "message::" IBIS_RPL_WHOREPLY, + G_CALLBACK(purple_ircv3_message_handler_whoreply), + connection, G_CONNECT_DEFAULT); + g_signal_connect_object(client, "message::" IBIS_RPL_ENDOFWHO, + G_CALLBACK(purple_ircv3_message_handler_ignore), + connection, G_CONNECT_DEFAULT); + g_signal_connect_object(client, "message", G_CALLBACK(purple_ircv3_connection_unknown_message_cb), connection, G_CONNECT_AFTER); @@ -590,6 +597,14 @@ /* away-notify tells us when users in a channel go away or come back. */ ibis_capabilities_lookup_and_request(capabilities, IBIS_CAPABILITY_AWAY_NOTIFY); + + /* no-implicit-names tells the server to not send us the namreply message + * when joining a channel. These messages are not useful to use since we + * immediately send a WHO command on the channel when we join which has a + * super set of the information in namreply. + */ + ibis_capabilities_lookup_and_request(capabilities, + IBIS_CAPABILITY_NO_IMPLICIT_NAMES); } static void diff -r 42e7b89033fe -r ce4987105a4e protocols/ircv3/purpleircv3messagehandlers.c --- a/protocols/ircv3/purpleircv3messagehandlers.c Mon Apr 21 23:09:08 2025 -0500 +++ b/protocols/ircv3/purpleircv3messagehandlers.c Mon Apr 21 23:41:59 2025 -0500 @@ -235,7 +235,7 @@ } gboolean -purple_ircv3_message_handler_join(G_GNUC_UNUSED IbisClient *client, +purple_ircv3_message_handler_join(IbisClient *client, G_GNUC_UNUSED const char *command, IbisMessage *message, gpointer data) @@ -243,6 +243,7 @@ PurpleIRCv3Connection *connection = data; PurpleContact *contact = NULL; PurpleConversation *conversation = NULL; + IbisMessage *who_message = NULL; GStrv params = NULL; const char *conversation_name = NULL; @@ -266,6 +267,11 @@ conversation_name); purple_ircv3_add_contact_to_conversation(contact, conversation, TRUE); + /* Now fire off a who message to sync the conversation. */ + who_message = ibis_message_new(IBIS_MSG_WHO); + ibis_message_set_params(who_message, conversation_name, NULL); + ibis_client_write(client, who_message); + return TRUE; } @@ -1103,3 +1109,88 @@ return TRUE; } + +gboolean +purple_ircv3_message_handler_whoreply(IbisClient *client, + G_GNUC_UNUSED const char *command, + IbisMessage *ibis_message, + gpointer data) +{ + PurpleIRCv3Connection *v3_connection = data; + PurpleContact *contact = NULL; + PurplePresence *presence = NULL; + GStrv params = NULL; + char *sid = NULL; + guint n_params = 0; + const char *flags = NULL; + + params = ibis_message_get_params(ibis_message); + n_params = g_strv_length(params); + + /* A standard RPL_WHOREPLY has 7 parameters: + * + * : + * + * We ignore hopcount and realname for now as we don't have a good use case + * to use it. + */ + if(n_params < 7) { + g_message("received RPL_WHOREPLY with %u params, need at least 7", + n_params); + return FALSE; + } + + /* Find the contact and update everything for it. */ + contact = purple_ircv3_connection_find_or_create_contact_from_nick(v3_connection, + params[5]); + + sid = g_strdup_printf("%s!%s@%s", params[5], params[2], params[3]); + purple_contact_info_set_sid(PURPLE_CONTACT_INFO(contact), sid); + + /* Process the flags starting with presence. */ + flags = params[6]; + + presence = purple_contact_info_get_presence(PURPLE_CONTACT_INFO(contact)); + if(flags[0] == 'G') { + purple_presence_set_primitive(presence, + PURPLE_PRESENCE_PRIMITIVE_AWAY); + } else { + purple_presence_set_primitive(presence, + PURPLE_PRESENCE_PRIMITIVE_AVAILABLE); + } + + /* Increment flags to the next value. */ + flags += 1; + + /* Check if a server admin. */ + if(flags[0] == '*') { + /* We'll need to create badge for this at some point */ + + flags += 1; + } + + /* If we got a channel update the member's prefix (badges). */ + if(!purple_strequal(params[1], "*")) { + PurpleConversation *conversation = NULL; + PurpleConversationMember *member = NULL; + + conversation = purple_ircv3_connection_find_or_create_conversation(v3_connection, + params[1]); + + member = purple_conversation_find_or_add_member(conversation, + PURPLE_CONTACT_INFO(contact), + FALSE, NULL); + + /* Now run through the remaining flags looking for channel member + * prefixes and adding badges for the ones we find. + */ + for(guint i = 0; flags[i] != '\0'; i++) { + /* We abuse the fact that if a badge can't be found it is ignored + * to avoid having to check the prefix before adding the badge. + */ + purple_ircv3_add_badge_to_member(member, client, flags[i]); + } + } + + return TRUE; +} diff -r 42e7b89033fe -r ce4987105a4e protocols/ircv3/purpleircv3messagehandlers.h --- a/protocols/ircv3/purpleircv3messagehandlers.h Mon Apr 21 23:09:08 2025 -0500 +++ b/protocols/ircv3/purpleircv3messagehandlers.h Mon Apr 21 23:41:59 2025 -0500 @@ -51,6 +51,7 @@ G_GNUC_INTERNAL gboolean purple_ircv3_message_handler_wallops(IbisClient *client, const char *command, IbisMessage *message, gpointer data); G_GNUC_INTERNAL gboolean purple_ircv3_message_handler_kick(IbisClient *client, const char *command, IbisMessage *message, gpointer data); G_GNUC_INTERNAL gboolean purple_ircv3_message_handler_mode(IbisClient *client, const char *command, IbisMessage *message, gpointer data); +G_GNUC_INTERNAL gboolean purple_ircv3_message_handler_whoreply(IbisClient *client, const char *command, IbisMessage *message, gpointer data); G_END_DECLS