Add find_or_create method to Purple.ContactManager

Wed, 26 Feb 2025 00:35:17 -0600

author
Markus Fischer <ivanhoe@fiscari.de>
date
Wed, 26 Feb 2025 00:35:17 -0600
changeset 43187
f1c824ae3ccd
parent 43186
f869ebb47d88
child 43188
8bb4549ab7f6

Add find_or_create method to Purple.ContactManager

Testing Done:
Ran the unit test in valgrind.

Bugs closed: PIDGIN-18037

Reviewed at https://reviews.imfreedom.org/r/3846/

libpurple/purplecontactmanager.c file | annotate | diff | comparison | revisions
libpurple/purplecontactmanager.h file | annotate | diff | comparison | revisions
libpurple/tests/test_contact_manager.c file | annotate | diff | comparison | revisions
--- a/libpurple/purplecontactmanager.c	Fri Feb 21 00:03:24 2025 -0600
+++ b/libpurple/purplecontactmanager.c	Wed Feb 26 00:35:17 2025 -0600
@@ -677,6 +677,46 @@
 	return NULL;
 }
 
+PurpleContact *
+purple_contact_manager_find_or_create(PurpleContactManager *manager,
+                                      PurpleAccount *account, const char *id,
+                                      gboolean *found)
+{
+	PurpleContact *contact = NULL;
+	PurpleContact *new_contact = NULL;
+	GListStore *contacts = NULL;
+	guint position = 0;
+	gboolean new_contact_found = FALSE;
+
+	g_return_val_if_fail(PURPLE_IS_CONTACT_MANAGER(manager), NULL);
+	g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
+	g_return_val_if_fail(!purple_strempty(id), NULL);
+
+	new_contact = purple_contact_new(account, id);
+
+	contacts = g_hash_table_lookup(manager->accounts, account);
+	if(G_IS_LIST_STORE(contacts)) {
+		new_contact_found =
+			g_list_store_find_with_equal_func(contacts, new_contact,
+			                                  purple_contact_manager_find_with_id_helper,
+			                                  &position);
+	}
+
+	if(new_contact_found) {
+		g_clear_object(&new_contact);
+		contact = g_list_model_get_item(G_LIST_MODEL(contacts), position);
+	} else {
+		purple_contact_manager_add(manager, new_contact);
+		contact = new_contact;
+	}
+
+	if(found != NULL) {
+		*found = new_contact_found;
+	}
+
+	return contact;
+}
+
 void
 purple_contact_manager_add_person(PurpleContactManager *manager,
                                   PurplePerson *person)
--- a/libpurple/purplecontactmanager.h	Fri Feb 21 00:03:24 2025 -0600
+++ b/libpurple/purplecontactmanager.h	Wed Feb 26 00:35:17 2025 -0600
@@ -156,6 +156,21 @@
 PurpleContact *purple_contact_manager_find_with_id(PurpleContactManager *manager, PurpleAccount *account, const gchar *id);
 
 /**
+ * purple_contact_manager_find_or_create:
+ * @account: the account whose contact to find
+ * @id: the id of the contact to find
+ * @found: (out) (optional): a return address for a boolean which will be set to true
+ *         if the contact was found
+ *
+ * Looks for a [class@Purple.Contact] that belongs to @account with an id of @id
+ * or creates a new one.
+ *
+ * Returns: (transfer full): The [class@Purple.Contact] that was either found or newly created.
+ */
+PURPLE_AVAILABLE_IN_3_0
+PurpleContact *purple_contact_manager_find_or_create(PurpleContactManager *manager, PurpleAccount *account, const char *id, gboolean *found);
+
+/**
  * purple_contact_manager_add_person:
  * @manager: The instance.
  * @person: The [class@Purple.Person to add].
--- a/libpurple/tests/test_contact_manager.c	Fri Feb 21 00:03:24 2025 -0600
+++ b/libpurple/tests/test_contact_manager.c	Wed Feb 26 00:35:17 2025 -0600
@@ -247,6 +247,39 @@
 	g_clear_object(&manager);
 }
 
+static void
+test_purple_contact_manager_find_or_create(void) {
+	PurpleAccount *account = NULL;
+	PurpleContact *contact1 = NULL;
+	PurpleContact *contact2 = NULL;
+	gboolean found;
+	PurpleContactManager *manager = NULL;
+
+	manager = g_object_new(PURPLE_TYPE_CONTACT_MANAGER, NULL);
+
+	account = purple_account_new("test", "test");
+
+	found = TRUE;
+	contact1 = purple_contact_manager_find_or_create(manager, account, "id-1",
+	                                                 &found);
+	g_assert_true(PURPLE_IS_CONTACT(contact1));
+	g_assert_false(found);
+	contact2 = purple_contact_manager_find_or_create(manager, account, "id-1",
+	                                                 &found);
+	g_assert_true(found);
+	g_assert_true(contact1 == contact2);
+
+	/* Cleanup. */
+	g_object_unref(contact2);
+	/* Calling ContactManager.remove so g_assert_finalize doesn't complain about
+	 * weak references.
+	 */
+	purple_contact_manager_remove(manager, contact1);
+	g_assert_finalize_object(contact1);
+	g_assert_finalize_object(manager);
+	g_assert_finalize_object(account);
+}
+
 /******************************************************************************
  * Person Tests
  *****************************************************************************/
@@ -443,6 +476,8 @@
 	                test_purple_contact_manager_find_with_username);
 	g_test_add_func("/contact-manager/find/with-id",
 	                test_purple_contact_manager_find_with_id);
+	g_test_add_func("/contact-manager/find-or-create",
+	                test_purple_contact_manager_find_or_create);
 
 	g_test_add_func("/contact-manager/person/add-remove",
 	                test_purple_contact_manager_person_add_remove);

mercurial