Tue, 15 Jul 2025 00:49:09 -0500
Add Purple.ConversationManager.get_all_for_account
This method gets a list of all conversations belonging to an account which is
a pretty common use case and we had a number of places where we were doing
this build/check manually and this just helps avoid that.
This also removed Purple.ConversationManager.get_all as
Purple.ConversationManager implements Gio.ListModel so it wasn't necessary.
Testing Done:
Opened a conversation the echo user and then deleted my demo account and verified that the window was closed.
Also called in the turtles.
Reviewed at https://reviews.imfreedom.org/r/4065/
--- a/libpurple/accounts.c Sun Jul 13 00:50:19 2025 -0500 +++ b/libpurple/accounts.c Tue Jul 15 00:49:09 2025 -0500 @@ -479,7 +479,8 @@ PurpleAccountManager *manager = NULL; PurpleConversationManager *conv_manager = NULL; PurpleCredentialManager *cred_manager = NULL; - GList *iter = NULL; + GListModel *conversations = NULL; + guint n_items = 0; g_return_if_fail(account != NULL); @@ -496,18 +497,19 @@ manager = purple_account_manager_get_default(); purple_account_manager_remove(manager, account); - /* Remove any open conversation for this account */ + /* Remove any conversations for this account. */ conv_manager = purple_conversation_manager_get_default(); - iter = purple_conversation_manager_get_all(conv_manager); - while(iter != NULL) { - PurpleConversation *conv = iter->data; + conversations = purple_conversation_manager_get_all_for_account(conv_manager, + account); + n_items = g_list_model_get_n_items(G_LIST_MODEL(conversations)); + for(guint i = 0; i < n_items; i++) { + PurpleConversation *conversation = NULL; - if(purple_conversation_get_account(conv) == account) { - g_object_unref(conv); - } - - iter = g_list_delete_link(iter, iter); + conversation = g_list_model_get_item(G_LIST_MODEL(conversations), i); + purple_conversation_manager_remove(conv_manager, conversation); + g_clear_object(&conversation); } + g_clear_object(&conversations); /* This is async because we do not want the * account being overwritten before we are done.
--- a/libpurple/purpleconversationmanager.c Sun Jul 13 00:50:19 2025 -0500 +++ b/libpurple/purpleconversationmanager.c Tue Jul 15 00:49:09 2025 -0500 @@ -1085,19 +1085,30 @@ return manager->filename; } -GList * -purple_conversation_manager_get_all(PurpleConversationManager *manager) { - GList *result = NULL; +GListModel * +purple_conversation_manager_get_all_for_account(PurpleConversationManager *manager, + PurpleAccount *account) +{ + GListStore *model = NULL; + g_return_val_if_fail(PURPLE_IS_CONVERSATION_MANAGER(manager), NULL); + g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL); + + model = g_list_store_new(PURPLE_TYPE_CONVERSATION); for(guint i = 0; i < manager->conversations->len; i++) { + PurpleAccount *conv_account = NULL; PurpleConversation *conversation = NULL; conversation = g_ptr_array_index(manager->conversations, i); - result = g_list_append(result, conversation); + conv_account = purple_conversation_get_account(conversation); + + if(conv_account == account) { + g_list_store_append(model, conversation); + } } - return result; + return G_LIST_MODEL(model); } PurpleConversation *
--- a/libpurple/purpleconversationmanager.h Sun Jul 13 00:50:19 2025 -0500 +++ b/libpurple/purpleconversationmanager.h Tue Jul 15 00:49:09 2025 -0500 @@ -64,6 +64,20 @@ gboolean purple_conversation_manager_add(PurpleConversationManager *manager, PurpleConversation *conversation); /** + * purple_conversation_manager_get_all_for_account: + * @account: the account + * + * Gets a list of conversations for a given account. + * + * Returns: (transfer full): The list of conversations. + * + * + * Since: 3.0 + */ +PURPLE_AVAILABLE_IN_3_0 +GListModel *purple_conversation_manager_get_all_for_account(PurpleConversationManager *manager, PurpleAccount *account); + +/** * purple_conversation_manager_new: * @filename: (nullable): The filename to serialize to. * @@ -122,20 +136,6 @@ const char *purple_conversation_manager_get_filename(PurpleConversationManager *manager); /** - * purple_conversation_manager_get_all: - * @manager: The #PurpleConversationManager instance. - * - * Gets a list of all conversations that @manager knows about. - * - * Returns: (transfer container) (element-type PurpleConversation): A list of - * all of the conversations that @manager knows about. - * - * Since: 3.0 - */ -PURPLE_AVAILABLE_IN_3_0 -GList *purple_conversation_manager_get_all(PurpleConversationManager *manager); - -/** * purple_conversation_manager_find_dm: * @manager: The instance. * @contact: The contact.
--- a/libpurple/tests/test_conversation_manager.c Sun Jul 13 00:50:19 2025 -0500 +++ b/libpurple/tests/test_conversation_manager.c Tue Jul 15 00:49:09 2025 -0500 @@ -78,6 +78,8 @@ PurpleAccount *account = NULL; PurpleConversationManager *manager = NULL; PurpleConversation *conversation = NULL; + PurpleConversation *conversation1 = NULL; + GListModel *conversations = NULL; guint added_counter = 0; guint removed_counter = 0; guint changed_counter = 0; @@ -118,7 +120,20 @@ g_assert_cmpuint(changed_counter, ==, 1); g_assert_cmpuint(g_list_model_get_n_items(G_LIST_MODEL(manager)), ==, 1); - /* Remove the contact. */ + /* Verify that get_all_for_account works. */ + conversations = purple_conversation_manager_get_all_for_account(manager, + account); + g_assert_true(G_IS_LIST_MODEL(conversations)); + birb_assert_list_model_n_items(conversations, 1); + + conversation1 = g_list_model_get_item(G_LIST_MODEL(conversations), 0); + birb_assert_type(conversation1, PURPLE_TYPE_CONVERSATION); + g_assert_true(conversation1 == conversation); + g_clear_object(&conversation1); + + g_assert_finalize_object(conversations); + + /* Remove the conversation. */ added_counter = 0; removed_counter = 0; changed_counter = 0;
--- a/protocols/ircv3/purpleircv3connection.c Sun Jul 13 00:50:19 2025 -0500 +++ b/protocols/ircv3/purpleircv3connection.c Tue Jul 15 00:49:09 2025 -0500 @@ -75,37 +75,43 @@ purple_ircv3_connection_rejoin_channels(PurpleIRCv3Connection *connection) { PurpleAccount *account = NULL; PurpleConversationManager *manager = NULL; - GList *conversations = NULL; + GListModel *conversations = NULL; + guint n_items = 0; account = purple_connection_get_account(PURPLE_CONNECTION(connection)); manager = purple_conversation_manager_get_default(); - conversations = purple_conversation_manager_get_all(manager); - while(conversations != NULL) { - PurpleConversation *conversation = conversations->data; - PurpleAccount *conv_account = NULL; + conversations = purple_conversation_manager_get_all_for_account(manager, + account); - conv_account = purple_conversation_get_account(conversation); - if(conv_account == account) { - IbisMessage *message = NULL; - const char *id = purple_conversation_get_id(conversation); + n_items = g_list_model_get_n_items(G_LIST_MODEL(conversations)); + for(guint i = 0; i < n_items; i++) { + PurpleConversation *conversation = NULL; + + conversation = g_list_model_get_item(G_LIST_MODEL(conversations), i); - /* We set the online status and clear the error on the conversation - * so that we can get any updated value if the join fails. - */ - purple_conversation_set_online(conversation, TRUE); - purple_conversation_set_error(conversation, NULL); + /* We set the online status and clear the error on the conversation + * so that we can get any updated value if the join fails. + */ + purple_conversation_set_online(conversation, TRUE); + purple_conversation_set_error(conversation, NULL); - /* If this is not the status conversation we need to rejoin it. */ - if(conversation != connection->status_conversation) { - message = ibis_message_new(IBIS_MSG_JOIN); - ibis_message_set_params(message, id, NULL); - ibis_client_write(connection->client, message); - } + /* If this is not the status conversation we need to rejoin it. */ + if(conversation != connection->status_conversation) { + IbisMessage *message = NULL; + const char *id = NULL; + + id = purple_conversation_get_id(conversation); + + message = ibis_message_new(IBIS_MSG_JOIN); + ibis_message_set_params(message, id, NULL); + ibis_client_write(connection->client, message); } - conversations = g_list_delete_link(conversations, conversations); + g_clear_object(&conversation); } + + g_clear_object(&conversations); } static inline void
--- a/protocols/ircv3/purpleircv3messagehandlers.c Sun Jul 13 00:50:19 2025 -0500 +++ b/protocols/ircv3/purpleircv3messagehandlers.c Tue Jul 15 00:49:09 2025 -0500 @@ -848,21 +848,24 @@ IbisMessage *ibis_message, gpointer data) { - PurpleIRCv3Connection *connection = data; + PurpleIRCv3Connection *v3_connection = data; + PurpleAccount *account = NULL; + PurpleConnection *connection = data; PurpleContact *contact = NULL; PurpleContactInfo *info = NULL; PurpleConversationManager *manager = NULL; PurplePresence *presence = NULL; - GList *conversations = NULL; + GListModel *conversations = NULL; GStrv params = NULL; guint n_params = 0; char *message = NULL; char *reason = NULL; + guint n_items = 0; params = ibis_message_get_params(ibis_message); n_params = g_strv_length(params); - contact = purple_ircv3_connection_find_or_create_contact(connection, + contact = purple_ircv3_connection_find_or_create_contact(v3_connection, ibis_message); info = PURPLE_CONTACT_INFO(contact); @@ -884,18 +887,24 @@ purple_presence_set_primitive(presence, PURPLE_PRESENCE_PRIMITIVE_OFFLINE); manager = purple_conversation_manager_get_default(); - conversations = purple_conversation_manager_get_all(manager); - while(conversations != NULL) { - PurpleConversation *conversation = conversations->data; + account = purple_connection_get_account(connection); + conversations = purple_conversation_manager_get_all_for_account(manager, + account); + n_items = g_list_model_get_n_items(G_LIST_MODEL(conversations)); + for(guint i = 0; i < n_items; i++) { + PurpleConversation *conversation = NULL; PurpleConversationMembers *members = NULL; + conversation = g_list_model_get_item(G_LIST_MODEL(conversations), i); + members = purple_conversation_get_members(conversation); purple_conversation_members_remove_member(members, info, TRUE, message); - conversations = g_list_delete_link(conversations, conversations); + g_clear_object(&conversation); } + g_clear_object(&conversations); g_clear_pointer(&message, g_free); g_clear_pointer(&reason, g_free);