# HG changeset patch
# Node ID 4626234658fd19a91332028e85aaead00479713b
# Parent  5543556bfb085e267c67a25d0f81fa1abe1b1307
diff --git a/libpurple/purplecontactmanager.c b/libpurple/purplecontactmanager.c
--- a/libpurple/purplecontactmanager.c
+++ b/libpurple/purplecontactmanager.c
@@ -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)
diff --git a/libpurple/purplecontactmanager.h b/libpurple/purplecontactmanager.h
--- a/libpurple/purplecontactmanager.h
+++ b/libpurple/purplecontactmanager.h
@@ -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: (nullable): 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].
diff --git a/libpurple/tests/test_contact_manager.c b/libpurple/tests/test_contact_manager.c
--- a/libpurple/tests/test_contact_manager.c
+++ b/libpurple/tests/test_contact_manager.c
@@ -247,6 +247,38 @@
 	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_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 +475,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);
