# HG changeset patch
# Node ID de8ddba976cb
# Parent  d8636f8db50a
diff --git a/libpurple/protocols/gg/gg.c b/libpurple/protocols/gg/gg.c
--- a/libpurple/protocols/gg/gg.c
+++ b/libpurple/protocols/gg/gg.c
@@ -622,7 +622,7 @@ void ggp_async_login_handler(gpointer _g
 	gg_free_event(ev);
 }
 
-static gint
+static gboolean
 gg_uri_handler_find_account(PurpleAccount *account,
                             G_GNUC_UNUSED gconstpointer data)
 {
@@ -630,12 +630,8 @@ gg_uri_handler_find_account(PurpleAccoun
 
 	protocol_id = purple_account_get_protocol_id(account);
 
-	if (purple_strequal(protocol_id, "prpl-gg") &&
-			purple_account_is_connected(account)) {
-		return 0;
-	} else {
-		return -1;
-	}
+	return (purple_strequal(protocol_id, "prpl-gg") &&
+	        purple_account_is_connected(account));
 }
 
 static gboolean
@@ -643,8 +639,7 @@ gg_uri_handler(const gchar *scheme, cons
 		GHashTable *params)
 {
 	PurpleAccountManager *manager = NULL;
-	GList *accounts;
-	GList *account_node;
+	PurpleAccount *account;
 	PurpleConversation *im;
 
 	g_return_val_if_fail(screenname != NULL, FALSE);
@@ -660,15 +655,15 @@ gg_uri_handler(const gchar *scheme, cons
 
 	/* Find online Gadu-Gadu account */
 	manager = purple_account_manager_get_default();
-	accounts = purple_account_manager_get_all(manager);
-	account_node = g_list_find_custom(accounts, NULL,
-	                                  (GCompareFunc)gg_uri_handler_find_account);
+	account = purple_account_manager_find_custom(manager,
+	                                             (GEqualFunc)gg_uri_handler_find_account,
+	                                             NULL);
 
-	if (account_node == NULL) {
+	if (account == NULL) {
 		return FALSE;
 	}
 
-	im = purple_im_conversation_new(account_node->data, screenname);
+	im = purple_im_conversation_new(account, screenname);
 	purple_conversation_present(im);
 
 	return TRUE;
diff --git a/libpurple/protocols/irc/irc.c b/libpurple/protocols/irc/irc.c
--- a/libpurple/protocols/irc/irc.c
+++ b/libpurple/protocols/irc/irc.c
@@ -93,8 +93,6 @@ irc_uri_handler(const gchar *scheme, con
 	PurpleAccountManager *manager = NULL;
 	gchar *target;
 	gchar *server;
-	GList *accounts;
-	GList *account_node;
 	gchar **target_tokens;
 	PurpleAccount *account;
 	gchar **modifier;
@@ -126,11 +124,11 @@ irc_uri_handler(const gchar *scheme, con
 
 	/* Find account with correct server */
 	manager = purple_account_manager_get_default();
-	accounts = purple_account_manager_get_all(manager);
-	account_node = g_list_find_custom(accounts, server,
-	                                  (GCompareFunc)irc_uri_handler_match_server);
+	account = purple_account_manager_find_custom(manager,
+	                                             (GEqualFunc)irc_uri_handler_match_server,
+	                                             server);
 
-	if (account_node == NULL) {
+	if (account == NULL) {
 		purple_debug_warning("irc",
 				"No account online on '%s' for handling URI",
 				server);
@@ -138,8 +136,6 @@ irc_uri_handler(const gchar *scheme, con
 		return FALSE;
 	}
 
-	account = account_node->data;
-
 	/* Tokenize modifiers, +1 to skip the initial '/' */
 	target_tokens = g_strsplit(target + 1, ",", 0);
 	target = g_strdup_printf("#%s", target_tokens[0]);
diff --git a/libpurple/protocols/jabber/jabber.c b/libpurple/protocols/jabber/jabber.c
--- a/libpurple/protocols/jabber/jabber.c
+++ b/libpurple/protocols/jabber/jabber.c
@@ -3532,6 +3532,15 @@ static void jabber_unregister_commands(P
 	g_hash_table_remove(jabber_cmds, protocol);
 }
 
+static gboolean
+find_acct_cb(PurpleAccount *account, const gchar *protocol) {
+	const gchar *account_protocol_id = NULL;
+
+	account_protocol_id = purple_account_get_protocol_id(account);
+	return (purple_strequal(protocol, account_protocol_id) &&
+	        purple_account_is_connected(account));
+}
+
 static PurpleAccount *find_acct(const char *protocol, const char *acct_id)
 {
 	PurpleAccountManager *manager = NULL;
@@ -3546,15 +3555,9 @@ static PurpleAccount *find_acct(const ch
 			acct = NULL;
 		}
 	} else { /* Otherwise find an active account for the protocol */
-		GList *l = purple_account_manager_get_all(manager);
-		while (l) {
-			if (purple_strequal(protocol, purple_account_get_protocol_id(l->data))
-					&& purple_account_is_connected(l->data)) {
-				acct = l->data;
-				break;
-			}
-			l = l->next;
-		}
+		acct = purple_account_manager_find_custom(manager,
+		                                          (GEqualFunc)find_acct_cb,
+		                                          protocol);
 	}
 
 	return acct;
diff --git a/libpurple/purpleaccountmanager.h b/libpurple/purpleaccountmanager.h
--- a/libpurple/purpleaccountmanager.h
+++ b/libpurple/purpleaccountmanager.h
@@ -167,6 +167,21 @@ PurpleAccount *purple_account_manager_fi
 PurpleAccount *purple_account_manager_find(PurpleAccountManager *manager, const gchar *username, const gchar *protocol_id);
 
 /**
+ * purple_account_manager_find_custom:
+ * @manager: The account manager instance.
+ * @func: (scope call): The function to call for each account. It should return
+ *        TRUE when the desired element is found
+ * @data: The user data to pass to the function, as its second argument.
+ *
+ * Attempts to find an account in @manager with a custom matching function.
+ *
+ * Returns: (transfer none): The account if found, otherwise %NULL.
+ *
+ * Since: 3.0.0
+ */
+PurpleAccount * purple_account_manager_find_custom(PurpleAccountManager *manager, GEqualFunc func, gconstpointer data);
+
+/**
  * purple_account_manager_foreach:
  * @manager: The account manager instance.
  * @callback: (scope call): The function to call.
diff --git a/libpurple/purpleaccountmanager.c b/libpurple/purpleaccountmanager.c
--- a/libpurple/purpleaccountmanager.c
+++ b/libpurple/purpleaccountmanager.c
@@ -326,6 +326,26 @@ purple_account_manager_find(PurpleAccoun
 	return NULL;
 }
 
+PurpleAccount *
+purple_account_manager_find_custom(PurpleAccountManager *manager,
+                                   GEqualFunc func, gconstpointer data)
+{
+	GList *l;
+
+	g_return_val_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager), NULL);
+	g_return_val_if_fail(func != NULL, NULL);
+
+	for(l = manager->accounts; l != NULL; l = l->next) {
+		PurpleAccount *account = PURPLE_ACCOUNT(l->data);
+
+		if(func(account, data)) {
+			return account;
+		}
+	}
+
+	return NULL;
+}
+
 void
 purple_account_manager_foreach(PurpleAccountManager *manager,
                                PurpleAccountManagerForeachFunc callback,
diff --git a/libpurple/tests/test_account_manager.c b/libpurple/tests/test_account_manager.c
--- a/libpurple/tests/test_account_manager.c
+++ b/libpurple/tests/test_account_manager.c
@@ -101,6 +101,28 @@ test_purple_account_manager_add_remove(v
 /******************************************************************************
  * Find Tests
  *****************************************************************************/
+static gboolean
+test_purple_account_manager_find_func(gconstpointer a, gconstpointer b) {
+	PurpleAccount *account = PURPLE_ACCOUNT((gpointer)a);
+	const gchar *desired_username = b;
+	const gchar *protocol_id = NULL;
+	const gchar *username = NULL;
+
+	/* Check if the protocol id matches expected. */
+	protocol_id = purple_account_get_protocol_id(account);
+	if(!purple_strequal(protocol_id, "test")) {
+		return FALSE;
+	}
+
+	/* Finally verify the username. */
+	username = purple_account_get_username(account);
+	if(!purple_strequal(username, desired_username)) {
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
 static void
 test_purple_account_manager_find(void) {
 	PurpleAccount *account = NULL, *found = NULL;
@@ -120,6 +142,12 @@ test_purple_account_manager_find(void) {
 	found = purple_account_manager_find(manager, "test", "test");
 	g_assert_nonnull(found);
 
+	/* Verify account can be found using a custom function. */
+	found = purple_account_manager_find_custom(manager,
+	                                           test_purple_account_manager_find_func,
+	                                           "test");
+	g_assert_nonnull(found);
+
 	/* Finally remove the account and verify it can't be found. */
 	purple_account_manager_remove(manager, account);
 	found = purple_account_manager_find(manager, "test", "test");
