grim/pidgin

Create the PurpleAccountManager API

2021-12-03, Gary Kramlich
e859c41d8996
Parents fb686c1483bf
Children 5e191561380f
Create the PurpleAccountManager API

This replaces most of the purple_accounts_ API, but not quite everything. The
functions that have been replaced have been marked as deprecated and libpurple
has been updated to use the new API.

Testing Done:
* Connected an XMPP account
* Verified chat and ims worked
* Verified that the saved statuses window didn't crash
* Ran the new unit tests.

Reviewed at https://reviews.imfreedom.org/r/1137/
--- a/libpurple/account.c Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/account.c Fri Dec 03 01:56:48 2021 -0600
@@ -29,6 +29,7 @@
#include "network.h"
#include "notify.h"
#include "prefs.h"
+#include "purpleaccountmanager.h"
#include "purpleaccountpresence.h"
#include "purpleconversationmanager.h"
#include "purplecredentialmanager.h"
@@ -1152,22 +1153,24 @@
* Public API
*****************************************************************************/
PurpleAccount *
-purple_account_new(const char *username, const char *protocol_id)
-{
+purple_account_new(const gchar *username, const gchar *protocol_id) {
PurpleAccount *account;
+ PurpleAccountManager *manager = NULL;
g_return_val_if_fail(username != NULL, NULL);
g_return_val_if_fail(protocol_id != NULL, NULL);
- account = purple_accounts_find(username, protocol_id);
-
- if (account != NULL)
+ manager = purple_account_manager_get_default();
+ account = purple_account_manager_find(manager, username, protocol_id);
+ if(account != NULL) {
return account;
-
- account = g_object_new(PURPLE_TYPE_ACCOUNT,
- "username", username,
- "protocol-id", protocol_id,
- NULL);
+ }
+
+ account = g_object_new(
+ PURPLE_TYPE_ACCOUNT,
+ "username", username,
+ "protocol-id", protocol_id,
+ NULL);
return account;
}
--- a/libpurple/accounts.c Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/accounts.c Fri Dec 03 01:56:48 2021 -0600
@@ -26,6 +26,7 @@
#include "core.h"
#include "debug.h"
#include "network.h"
+#include "purpleaccountmanager.h"
#include "purpleconversationmanager.h"
#include "purplecredentialmanager.h"
#include "purpleenums.h"
@@ -33,7 +34,6 @@
static PurpleAccountUiOps *account_ui_ops = NULL;
-static GList *accounts = NULL;
static guint save_timer = 0;
static gboolean accounts_loaded = FALSE;
@@ -49,20 +49,24 @@
/*********************************************************************
* Writing to disk *
*********************************************************************/
+static void
+accounts_to_xmlnode_helper(PurpleAccount *account, gpointer data) {
+ PurpleXmlNode *node = data, *child = NULL;
+
+ child = _purple_account_to_xmlnode(account);
+ purple_xmlnode_insert_child(node, child);
+}
+
static PurpleXmlNode *
accounts_to_xmlnode(void)
{
- PurpleXmlNode *node, *child;
- GList *cur;
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+ PurpleXmlNode *node = NULL;
node = purple_xmlnode_new("account");
purple_xmlnode_set_attrib(node, "version", "1.0");
- for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
- {
- child = _purple_account_to_xmlnode(cur->data);
- purple_xmlnode_insert_child(node, child);
- }
+ purple_account_manager_foreach(manager, accounts_to_xmlnode_helper, node);
return node;
}
@@ -505,23 +509,27 @@
}
static void
-load_accounts(void)
-{
+load_accounts(void) {
+ PurpleAccountManager *manager = NULL;
PurpleXmlNode *node, *child;
accounts_loaded = TRUE;
node = purple_util_read_xml_from_config_file("accounts.xml", _("accounts"));
- if (node == NULL)
+ if(node == NULL) {
return;
+ }
- for (child = purple_xmlnode_get_child(node, "account"); child != NULL;
- child = purple_xmlnode_get_next_twin(child))
+ manager = purple_account_manager_get_default();
+
+ for(child = purple_xmlnode_get_child(node, "account"); child != NULL;
+ child = purple_xmlnode_get_next_twin(child))
{
PurpleAccount *new_acct;
new_acct = parse_account(child);
- purple_accounts_add(new_acct);
+
+ purple_account_manager_add(manager, new_acct);
}
purple_xmlnode_free(node);
@@ -529,38 +537,6 @@
_purple_buddy_icons_account_loaded_cb();
}
-void
-purple_accounts_add(PurpleAccount *account)
-{
- g_return_if_fail(account != NULL);
-
- if (g_list_find(accounts, account) != NULL)
- return;
-
- accounts = g_list_append(accounts, account);
-
- purple_accounts_schedule_save();
-
- purple_signal_emit(purple_accounts_get_handle(), "account-added", account);
-}
-
-void
-purple_accounts_remove(PurpleAccount *account)
-{
- g_return_if_fail(account != NULL);
-
- accounts = g_list_remove(accounts, account);
-
- purple_accounts_schedule_save();
-
- /* Clearing the error ensures that account-error-changed is emitted,
- * which is the end of the guarantee that the the error's pointer is
- * valid.
- */
- purple_account_clear_current_error(account);
- purple_signal_emit(purple_accounts_get_handle(), "account-removed", account);
-}
-
static void
purple_accounts_delete_set(GObject *obj, GAsyncResult *res, gpointer d) {
PurpleCredentialManager *manager = PURPLE_CREDENTIAL_MANAGER(obj);
@@ -584,10 +560,11 @@
void
purple_accounts_delete(PurpleAccount *account)
{
- PurpleBlistNode *gnode, *cnode, *bnode;
+ PurpleAccountManager *manager = NULL;
+ PurpleBlistNode *gnode = NULL, *cnode = NULL, *bnode = NULL;
PurpleConversationManager *conv_manager = NULL;
PurpleCredentialManager *cred_manager = NULL;
- GList *iter;
+ GList *iter = NULL;
g_return_if_fail(account != NULL);
@@ -602,36 +579,41 @@
purple_notify_close_with_handle(account);
purple_request_close_with_handle(account);
- purple_accounts_remove(account);
+ manager = purple_account_manager_get_default();
+ purple_account_manager_remove(manager, account);
/* Remove this account's buddies */
- for (gnode = purple_blist_get_default_root(); gnode != NULL;
- gnode = purple_blist_node_get_sibling_next(gnode)) {
- if (!PURPLE_IS_GROUP(gnode))
+ for(gnode = purple_blist_get_default_root(); gnode != NULL;
+ gnode = purple_blist_node_get_sibling_next(gnode))
+ {
+ if(!PURPLE_IS_GROUP(gnode)) {
continue;
+ }
cnode = purple_blist_node_get_first_child(gnode);
- while (cnode) {
+ while(cnode) {
PurpleBlistNode *cnode_next = purple_blist_node_get_sibling_next(cnode);
if(PURPLE_IS_CONTACT(cnode)) {
bnode = purple_blist_node_get_first_child(cnode);
- while (bnode) {
+ while(bnode) {
PurpleBlistNode *bnode_next = purple_blist_node_get_sibling_next(bnode);
if (PURPLE_IS_BUDDY(bnode)) {
PurpleBuddy *b = (PurpleBuddy *)bnode;
- if (purple_buddy_get_account(b) == account)
+ if(purple_buddy_get_account(b) == account) {
purple_blist_remove_buddy(b);
+ }
}
bnode = bnode_next;
}
- } else if (PURPLE_IS_CHAT(cnode)) {
+ } else if(PURPLE_IS_CHAT(cnode)) {
PurpleChat *c = (PurpleChat *)cnode;
- if (purple_chat_get_account(c) == account)
+ if(purple_chat_get_account(c) == account) {
purple_blist_remove_chat(c);
+ }
}
cnode = cnode_next;
}
@@ -662,112 +644,34 @@
NULL);
}
-void
-purple_accounts_reorder(PurpleAccount *account, guint new_index)
-{
- gint index;
- GList *l;
+static void
+purple_accounts_restore_current_status(PurpleAccount *account,
+ G_GNUC_UNUSED gpointer data) {
+ gboolean enabled = FALSE, online = FALSE;
+
+ enabled = purple_account_get_enabled(account, purple_core_get_ui());
+ online = purple_presence_is_online(purple_account_get_presence(account));
- g_return_if_fail(account != NULL);
- g_return_if_fail(new_index <= g_list_length(accounts));
-
- index = g_list_index(accounts, account);
+ if(enabled && online) {
+ purple_account_connect(account);
+ }
+}
- if (index < 0) {
- purple_debug_error("accounts",
- "Unregistered account (%s) discovered during reorder!\n",
- purple_account_get_username(account));
+void
+purple_accounts_restore_current_statuses() {
+ PurpleAccountManager *manager = NULL;
+
+ /* If we're not connected to the Internet right now, we bail on this */
+ if (!purple_network_is_available()) {
+ g_warning("Network not connected; skipping reconnect");
+
return;
}
- l = g_list_nth(accounts, index);
-
- if (new_index > (guint)index)
- new_index--;
-
- /* Remove the old one. */
- accounts = g_list_delete_link(accounts, l);
-
- /* Insert it where it should go. */
- accounts = g_list_insert(accounts, account, new_index);
-
- purple_accounts_schedule_save();
-}
-
-GList *
-purple_accounts_get_all(void)
-{
- return accounts;
-}
-
-GList *
-purple_accounts_get_all_active(void)
-{
- GList *list = NULL;
- GList *all = purple_accounts_get_all();
-
- while (all != NULL) {
- PurpleAccount *account = all->data;
-
- if (purple_account_get_enabled(account, purple_core_get_ui()))
- list = g_list_append(list, account);
-
- all = all->next;
- }
-
- return list;
-}
-
-PurpleAccount *
-purple_accounts_find(const char *name, const char *protocol_id)
-{
- PurpleAccount *account = NULL;
- GList *l;
- char *who;
-
- g_return_val_if_fail(name != NULL, NULL);
- g_return_val_if_fail(protocol_id != NULL, NULL);
-
- for (l = purple_accounts_get_all(); l != NULL; l = l->next) {
- account = (PurpleAccount *)l->data;
-
- if (!purple_strequal(purple_account_get_protocol_id(account), protocol_id))
- continue;
-
- who = g_strdup(purple_normalize(account, name));
- if (purple_strequal(purple_normalize(account, purple_account_get_username(account)), who)) {
- g_free(who);
- return account;
- }
- g_free(who);
- }
-
- return NULL;
-}
-
-void
-purple_accounts_restore_current_statuses()
-{
- GList *l;
- PurpleAccount *account;
-
- /* If we're not connected to the Internet right now, we bail on this */
- if (!purple_network_is_available())
- {
- purple_debug_warning("accounts", "Network not connected; skipping reconnect\n");
- return;
- }
-
- for (l = purple_accounts_get_all(); l != NULL; l = l->next)
- {
- account = (PurpleAccount *)l->data;
-
- if (purple_account_get_enabled(account, purple_core_get_ui()) &&
- (purple_presence_is_online(purple_account_get_presence(account))))
- {
- purple_account_connect(account);
- }
- }
+ manager = purple_account_manager_get_default();
+ purple_account_manager_foreach(manager,
+ purple_accounts_restore_current_status,
+ NULL);
}
static PurpleAccountUiOps *
@@ -979,9 +883,52 @@
sync_accounts();
}
- for (; accounts; accounts = g_list_delete_link(accounts, accounts))
- g_object_unref(G_OBJECT(accounts->data));
-
purple_signals_disconnect_by_handle(handle);
purple_signals_unregister_by_instance(handle);
}
+
+/******************************************************************************
+ * Deprecated API
+ *****************************************************************************/
+void
+purple_accounts_add(PurpleAccount *account) {
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+
+ purple_account_manager_add(manager, account);
+}
+
+void
+purple_accounts_remove(PurpleAccount *account) {
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+
+ purple_account_manager_remove(manager, account);
+}
+
+GList *
+purple_accounts_get_all(void) {
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+
+ return purple_account_manager_get_all(manager);
+}
+
+GList *
+purple_accounts_get_all_active(void) {
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+
+ return purple_account_manager_get_active(manager);
+}
+
+void
+purple_accounts_reorder(PurpleAccount *account, guint new_index) {
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+
+ purple_account_manager_reorder(manager, account, new_index);
+}
+
+PurpleAccount *
+purple_accounts_find(const char *name, const char *protocol_id) {
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+
+ return purple_account_manager_find(manager, name, protocol_id);
+}
+
--- a/libpurple/accounts.h Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/accounts.h Fri Dec 03 01:56:48 2021 -0600
@@ -119,6 +119,7 @@
*
* Adds an account to the list of accounts.
*/
+G_DEPRECATED_FOR(purple_account_manager_add)
void purple_accounts_add(PurpleAccount *account);
/**
@@ -127,6 +128,7 @@
*
* Removes an account from the list of accounts.
*/
+G_DEPRECATED_FOR(purple_account_manager_remove)
void purple_accounts_remove(PurpleAccount *account);
/**
@@ -148,6 +150,7 @@
*
* Reorders an account.
*/
+G_DEPRECATED_FOR(purple_account_manager_reorder)
void purple_accounts_reorder(PurpleAccount *account, guint new_index);
/**
@@ -157,6 +160,7 @@
*
* Returns: (element-type PurpleAccount) (transfer none): A list of all accounts.
*/
+G_DEPRECATED_FOR(purple_account_manager_get_all)
GList *purple_accounts_get_all(void);
/**
@@ -167,6 +171,7 @@
* Returns: (element-type PurpleAccount) (transfer container): A list of all
* enabled accounts.
*/
+G_DEPRECATED_FOR(purple_account_manager_get_active)
GList *purple_accounts_get_all_active(void);
/**
@@ -178,6 +183,7 @@
*
* Returns: (transfer none): The account, if found, or %NULL otherwise.
*/
+G_DEPRECATED_FOR(purple_account_manager_find)
PurpleAccount *purple_accounts_find(const char *name, const char *protocol);
/**
--- a/libpurple/buddyicon.c Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/buddyicon.c Fri Dec 03 01:56:48 2021 -0600
@@ -23,6 +23,7 @@
#include "buddyicon.h"
#include "debug.h"
#include "image.h"
+#include "purpleaccountmanager.h"
#include "purpleconversation.h"
#include "purpleconversationmanager.h"
#include "purpleprivate.h"
@@ -1003,33 +1004,39 @@
}
}
-void
-_purple_buddy_icons_account_loaded_cb()
+static void
+_purple_buddy_icons_account_loaded_cb_helper(PurpleAccount *account,
+ gpointer data)
{
- const char *dirname = purple_buddy_icons_get_cache_dir();
- GList *cur;
-
- for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
- {
- PurpleAccount *account = cur->data;
- const char *account_icon_file = purple_account_get_string(account, "buddy_icon", NULL);
+ const gchar *dirname = (const gchar *)data;
+ const gchar *filename = NULL;
- if (account_icon_file != NULL)
- {
- char *path = g_build_filename(dirname, account_icon_file, NULL);
- if (!g_file_test(path, G_FILE_TEST_EXISTS))
- {
- purple_account_set_string(account, "buddy_icon", NULL);
- } else {
- ref_filename(account_icon_file);
- }
- g_free(path);
+ filename = purple_account_get_string(account, "buddy_icon", NULL);
+ if(filename != NULL) {
+ gchar *path = g_build_filename(dirname, filename, NULL);
+
+ if(!g_file_test(path, G_FILE_TEST_EXISTS)) {
+ purple_account_set_string(account, "buddy_icon", NULL);
+ } else {
+ ref_filename(filename);
}
+ g_free(path);
}
}
void
-_purple_buddy_icons_blist_loaded_cb()
+_purple_buddy_icons_account_loaded_cb(void)
+{
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+ const char *dirname = purple_buddy_icons_get_cache_dir();
+
+ purple_account_manager_foreach(manager,
+ _purple_buddy_icons_account_loaded_cb_helper,
+ (gpointer)dirname);
+}
+
+void
+_purple_buddy_icons_blist_loaded_cb(void)
{
PurpleBlistNode *node = purple_blist_get_default_root();
const char *dirname = purple_buddy_icons_get_cache_dir();
--- a/libpurple/buddylist.c Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/buddylist.c Fri Dec 03 01:56:48 2021 -0600
@@ -29,6 +29,7 @@
#include "debug.h"
#include "notify.h"
#include "prefs.h"
+#include "purpleaccountmanager.h"
#include "purpleprivate.h"
#include "purpleprotocol.h"
#include "purpleprotocolchat.h"
@@ -360,8 +361,8 @@
}
static PurpleXmlNode *
-blist_to_xmlnode(void)
-{
+blist_to_xmlnode(void) {
+ PurpleAccountManager *manager = purple_account_manager_get_default();
PurpleXmlNode *node, *child, *grandchild;
PurpleBlistNode *gnode;
GList *cur;
@@ -394,7 +395,8 @@
/* Write privacy settings */
child = purple_xmlnode_new_child(node, "privacy");
- for (cur = purple_accounts_get_all(); cur != NULL; cur = cur->next)
+ for(cur = purple_account_manager_get_all(manager); cur != NULL;
+ cur = cur->next)
{
grandchild = accountprivacy_to_xmlnode(cur->data);
purple_xmlnode_insert_child(child, grandchild);
@@ -497,9 +499,9 @@
}
static void
-parse_buddy(PurpleGroup *group, PurpleContact *contact, PurpleXmlNode *bnode)
-{
+parse_buddy(PurpleGroup *group, PurpleContact *contact, PurpleXmlNode *bnode) {
PurpleAccount *account;
+ PurpleAccountManager *manager = purple_account_manager_get_default();
PurpleBuddy *buddy;
char *name = NULL, *alias = NULL;
const char *acct_name, *proto;
@@ -508,28 +510,33 @@
acct_name = purple_xmlnode_get_attrib(bnode, "account");
proto = purple_xmlnode_get_attrib(bnode, "proto");
- if (!acct_name || !proto)
+ if(!acct_name || !proto) {
return;
+ }
- account = purple_accounts_find(acct_name, proto);
+ account = purple_account_manager_find(manager, acct_name, proto);
- if (!account)
+ if(!account) {
return;
+ }
- if ((x = purple_xmlnode_get_child(bnode, "name")))
+ if((x = purple_xmlnode_get_child(bnode, "name"))) {
name = purple_xmlnode_get_data(x);
+ }
- if (!name)
+ if(!name) {
return;
+ }
- if ((x = purple_xmlnode_get_child(bnode, "alias")))
+ if((x = purple_xmlnode_get_child(bnode, "alias"))) {
alias = purple_xmlnode_get_data(x);
+ }
buddy = purple_buddy_new(account, name, alias);
purple_blist_add_buddy(buddy, contact, group,
_purple_blist_get_last_child((PurpleBlistNode*)contact));
- for (x = purple_xmlnode_get_child(bnode, "setting"); x; x = purple_xmlnode_get_next_twin(x)) {
+ for(x = purple_xmlnode_get_child(bnode, "setting"); x; x = purple_xmlnode_get_next_twin(x)) {
parse_setting((PurpleBlistNode*)buddy, x);
}
@@ -568,8 +575,9 @@
static void
parse_chat(PurpleGroup *group, PurpleXmlNode *cnode)
{
+ PurpleAccount *account;
+ PurpleAccountManager *manager = purple_account_manager_get_default();
PurpleChat *chat;
- PurpleAccount *account;
const char *acct_name, *proto;
PurpleXmlNode *x;
char *alias = NULL;
@@ -578,20 +586,23 @@
acct_name = purple_xmlnode_get_attrib(cnode, "account");
proto = purple_xmlnode_get_attrib(cnode, "proto");
- if (!acct_name || !proto)
+ if(!acct_name || !proto) {
return;
+ }
- account = purple_accounts_find(acct_name, proto);
+ account = purple_account_manager_find(manager, acct_name, proto);
- if (!account)
+ if(!account) {
return;
+ }
- if ((x = purple_xmlnode_get_child(cnode, "alias")))
+ if((x = purple_xmlnode_get_child(cnode, "alias"))) {
alias = purple_xmlnode_get_data(x);
+ }
components = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
- for (x = purple_xmlnode_get_child(cnode, "component"); x; x = purple_xmlnode_get_next_twin(x)) {
+ for(x = purple_xmlnode_get_child(cnode, "component"); x; x = purple_xmlnode_get_next_twin(x)) {
const char *name;
char *value;
@@ -604,7 +615,7 @@
purple_blist_add_chat(chat, group,
_purple_blist_get_last_child((PurpleBlistNode*)group));
- for (x = purple_xmlnode_get_child(cnode, "setting"); x; x = purple_xmlnode_get_next_twin(x)) {
+ for(x = purple_xmlnode_get_child(cnode, "setting"); x; x = purple_xmlnode_get_next_twin(x)) {
parse_setting((PurpleBlistNode*)chat, x);
}
@@ -638,24 +649,28 @@
static void
load_blist(void)
{
+ PurpleAccountManager *manager = NULL;
PurpleXmlNode *purple, *blist, *privacy;
blist_loaded = TRUE;
purple = purple_util_read_xml_from_config_file("blist.xml", _("buddy list"));
- if (purple == NULL)
+ if(purple == NULL) {
return;
+ }
+
+ manager = purple_account_manager_get_default();
blist = purple_xmlnode_get_child(purple, "blist");
- if (blist) {
+ if(blist) {
PurpleXmlNode *groupnode;
localized_default_group_name = g_strdup(
purple_xmlnode_get_attrib(blist,
"localized-default-group"));
- for (groupnode = purple_xmlnode_get_child(blist, "group"); groupnode != NULL;
+ for(groupnode = purple_xmlnode_get_child(blist, "group"); groupnode != NULL;
groupnode = purple_xmlnode_get_next_twin(groupnode)) {
parse_group(groupnode);
}
@@ -665,11 +680,11 @@
}
privacy = purple_xmlnode_get_child(purple, "privacy");
- if (privacy) {
+ if(privacy) {
PurpleXmlNode *anode;
- for (anode = privacy->child; anode; anode = anode->next) {
+ for(anode = privacy->child; anode; anode = anode->next) {
+ PurpleAccount *account;
PurpleXmlNode *x;
- PurpleAccount *account;
int imode;
const char *acct_name, *proto, *mode;
@@ -677,27 +692,30 @@
proto = purple_xmlnode_get_attrib(anode, "proto");
mode = purple_xmlnode_get_attrib(anode, "mode");
- if (!acct_name || !proto || !mode)
+ if(!acct_name || !proto || !mode) {
continue;
+ }
- account = purple_accounts_find(acct_name, proto);
+ account = purple_account_manager_find(manager, acct_name, proto);
- if (!account)
+ if(!account) {
continue;
+ }
imode = atoi(mode);
purple_account_set_privacy_type(account, (imode != 0 ? imode : PURPLE_ACCOUNT_PRIVACY_ALLOW_ALL));
- for (x = anode->child; x; x = x->next) {
+ for(x = anode->child; x; x = x->next) {
char *name;
- if (x->type != PURPLE_XMLNODE_TYPE_TAG)
+ if(x->type != PURPLE_XMLNODE_TYPE_TAG) {
continue;
+ }
- if (purple_strequal(x->name, "permit")) {
+ if(purple_strequal(x->name, "permit")) {
name = purple_xmlnode_get_data(x);
purple_account_privacy_permit_add(account, name, TRUE);
g_free(name);
- } else if (purple_strequal(x->name, "block")) {
+ } else if(purple_strequal(x->name, "block")) {
name = purple_xmlnode_get_data(x);
purple_account_privacy_deny_add(account, name, TRUE);
g_free(name);
@@ -727,17 +745,18 @@
void
purple_blist_boot(void)
{
- GList *account;
+ PurpleAccountManager *manager = NULL;
PurpleBuddyList *gbl = g_object_new(buddy_list_type, NULL);
+ GList *l;
buddies_cache = g_hash_table_new_full(g_direct_hash, g_direct_equal,
NULL, (GDestroyNotify)g_hash_table_destroy);
groups_cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
- for (account = purple_accounts_get_all(); account != NULL; account = account->next)
- {
- purple_blist_buddies_cache_add_account(account->data);
+ manager = purple_account_manager_get_default();
+ for(l = purple_account_manager_get_all(manager); l != NULL; l = l->next) {
+ purple_blist_buddies_cache_add_account(PURPLE_ACCOUNT(l->data));
}
purplebuddylist = gbl;
--- a/libpurple/core.c Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/core.c Fri Dec 03 01:56:48 2021 -0600
@@ -161,6 +161,7 @@
purple_buddy_icons_init();
purple_connections_init();
+ purple_account_manager_startup();
purple_accounts_init();
purple_savedstatuses_init();
purple_notify_init();
@@ -228,6 +229,7 @@
purple_savedstatuses_uninit();
purple_statuses_uninit();
purple_accounts_uninit();
+ purple_account_manager_shutdown();
purple_xfers_uninit();
purple_proxy_uninit();
_purple_image_store_uninit();
--- a/libpurple/meson.build Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/meson.build Fri Dec 03 01:56:48 2021 -0600
@@ -37,6 +37,7 @@
'proxy.c',
'protocols.c',
'purple-gio.c',
+ 'purpleaccountmanager.c',
'purpleaccountoption.c',
'purpleaccountpresence.c',
'purpleaccountusersplit.c',
@@ -128,6 +129,7 @@
'proxy.h',
'protocols.h',
'purple-gio.h',
+ 'purpleaccountmanager.h',
'purpleaccountoption.h',
'purpleaccountpresence.h',
'purpleaccountusersplit.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleaccountmanager.c Fri Dec 03 01:56:48 2021 -0600
@@ -0,0 +1,305 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "purpleaccountmanager.h"
+#include "purpleprivate.h"
+
+#include "account.h"
+#include "accounts.h"
+#include "core.h"
+
+enum {
+ SIG_ADDED,
+ SIG_REMOVED,
+ N_SIGNALS,
+};
+static guint signals[N_SIGNALS] = {0, };
+
+struct _PurpleAccountManager {
+ GObject parent;
+
+ GList *accounts;
+};
+
+static PurpleAccountManager *default_manager = NULL;
+
+G_DEFINE_TYPE(PurpleAccountManager, purple_account_manager, G_TYPE_OBJECT)
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+purple_account_manager_finalize(GObject *obj) {
+ PurpleAccountManager *manager = PURPLE_ACCOUNT_MANAGER(obj);
+ GList *l = NULL;
+
+ for(l = manager->accounts; l != NULL; l = l->next) {
+ g_object_unref(l->data);
+ }
+
+ G_OBJECT_CLASS(purple_account_manager_parent_class)->finalize(obj);
+}
+
+static void
+purple_account_manager_init(PurpleAccountManager *manager) {
+}
+
+static void
+purple_account_manager_class_init(PurpleAccountManagerClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+
+ obj_class->finalize = purple_account_manager_finalize;
+
+ /**
+ * PurpleAccountManager::added:
+ * @manager: The account manager instance.
+ * @account: The account that was added.
+ *
+ * Emitted after @account was added to @manager.
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_ADDED] = g_signal_new_class_handler(
+ "added",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ PURPLE_TYPE_ACCOUNT);
+
+ /**
+ * PurpleAccountManager::removed:
+ * @manager: The account manager instance.
+ * @account: The account that was removed.
+ *
+ * Emitted after @account was removed from @manager.
+ *
+ * Since: 3.0.0
+ */
+ signals[SIG_REMOVED] = g_signal_new_class_handler(
+ "removed",
+ G_OBJECT_CLASS_TYPE(klass),
+ G_SIGNAL_RUN_LAST,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ G_TYPE_NONE,
+ 1,
+ PURPLE_TYPE_ACCOUNT);
+}
+
+/******************************************************************************
+ * Private API
+ *****************************************************************************/
+void
+purple_account_manager_startup(void) {
+ if(!PURPLE_IS_ACCOUNT_MANAGER(default_manager)) {
+ default_manager = g_object_new(PURPLE_TYPE_ACCOUNT_MANAGER, NULL);
+ }
+}
+
+void
+purple_account_manager_shutdown(void) {
+ g_clear_object(&default_manager);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleAccountManager *
+purple_account_manager_get_default(void) {
+ return default_manager;
+}
+
+void
+purple_account_manager_add(PurpleAccountManager *manager,
+ PurpleAccount *account)
+{
+ g_return_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager));
+ g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+ /* If the manager already knows about the account, we do nothing. */
+ if(g_list_find(manager->accounts, account) != NULL) {
+ return;
+ }
+
+ /* Since the manager doesn't know about the account, put the new account
+ * at the start of the list as that's likely to be the first one in user
+ * interfaces and the most likely to have configuration issues as it's a
+ * new account.
+ */
+ manager->accounts = g_list_prepend(manager->accounts, account);
+
+ purple_accounts_schedule_save();
+
+ g_signal_emit(manager, signals[SIG_ADDED], 0, account);
+
+ /* Finally emit the old purple signal that will eventually be removed. */
+ purple_signal_emit(purple_accounts_get_handle(), "account-added", account);
+}
+
+void
+purple_account_manager_remove(PurpleAccountManager *manager,
+ PurpleAccount *account)
+{
+ g_return_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager));
+ g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+ manager->accounts = g_list_remove(manager->accounts, account);
+
+ purple_accounts_schedule_save();
+
+ /* Clearing the error ensures that account-error-changed is emitted,
+ * which is the end of the guarantee that the error's pointer is valid.
+ */
+ purple_account_clear_current_error(account);
+
+ g_signal_emit(manager, signals[SIG_REMOVED], 0, account);
+
+ /* Finally emit the old purple signal that will eventually be removed. */
+ purple_signal_emit(purple_accounts_get_handle(), "account-removed",
+ account);
+}
+
+GList *
+purple_account_manager_get_all(PurpleAccountManager *manager) {
+ g_return_val_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager), NULL);
+
+ return manager->accounts;
+}
+
+GList *
+purple_account_manager_get_active(PurpleAccountManager *manager) {
+ GList *active = NULL, *l = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager), NULL);
+
+ for(l = manager->accounts; l != NULL; l = l->next) {
+ PurpleAccount *account = PURPLE_ACCOUNT(l->data);
+
+ if(purple_account_get_enabled(account, purple_core_get_ui())) {
+ active = g_list_append(active, account);
+ }
+ }
+
+ return active;
+}
+
+void
+purple_account_manager_reorder(PurpleAccountManager *manager,
+ PurpleAccount *account,
+ guint new_index)
+{
+ GList *l = NULL;
+ gboolean found = FALSE;
+ guint index = 0;
+
+ g_return_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager));
+ g_return_if_fail(PURPLE_IS_ACCOUNT(account));
+
+ /* Iterate over the known accounts until we have found a matching account
+ * or exhausted the list. For each iteration increment idx.
+ */
+ for(l = manager->accounts; l != NULL; l = l->next, index++) {
+ if(PURPLE_ACCOUNT(l->data) == account) {
+ manager->accounts = g_list_delete_link(manager->accounts, l);
+
+ found = TRUE;
+
+ /* If new_index is greater than the current index, we need to
+ * decrement new_index by 1 to account for the move as we'll be
+ * inserting into a list with one less item.
+ */
+ if(new_index > index) {
+ new_index--;
+ }
+
+ break;
+ }
+ }
+
+ if(!found) {
+ g_critical("Unregistered account (%s) found during reorder!",
+ purple_account_get_username(account));
+ return;
+ }
+
+ /* Insert the account into its new position. */
+ manager->accounts = g_list_insert(manager->accounts, account, new_index);
+
+ purple_accounts_schedule_save();
+}
+
+PurpleAccount *
+purple_account_manager_find(PurpleAccountManager *manager,
+ const gchar *username, const gchar *protocol_id)
+{
+ GList *l;
+
+ g_return_val_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager), NULL);
+ g_return_val_if_fail(username != NULL, NULL);
+ g_return_val_if_fail(protocol_id != NULL, NULL);
+
+ for(l = manager->accounts; l != NULL; l = l->next) {
+ PurpleAccount *account = PURPLE_ACCOUNT(l->data);
+ gchar *normalized = NULL;
+ const gchar *existing_protocol_id = NULL;
+ const gchar *existing_username = NULL;
+ const gchar *existing_normalized = NULL;
+
+ /* Check if the protocol id matches what the user asked for. */
+ existing_protocol_id = purple_account_get_protocol_id(account);
+ if(!purple_strequal(existing_protocol_id, protocol_id)) {
+ continue;
+ }
+
+ /* Finally verify the username. */
+ existing_username = purple_account_get_username(account);
+ normalized = g_strdup(purple_normalize(account, username));
+ existing_normalized = purple_normalize(account, existing_username);
+
+ if(purple_strequal(existing_normalized, normalized)) {
+ g_free(normalized);
+
+ return account;
+ }
+ g_free(normalized);
+ }
+
+ return NULL;
+}
+
+void
+purple_account_manager_foreach(PurpleAccountManager *manager,
+ PurpleAccountManagerForeachFunc callback,
+ gpointer data)
+{
+ GList *l = NULL;
+
+ g_return_if_fail(PURPLE_IS_ACCOUNT_MANAGER(manager));
+ g_return_if_fail(callback != NULL);
+
+ for(l = manager->accounts; l != NULL; l = l->next) {
+ callback(PURPLE_ACCOUNT(l->data), data);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleaccountmanager.h Fri Dec 03 01:56:48 2021 -0600
@@ -0,0 +1,155 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
+# error "only <pidgin.h> may be included directly"
+#endif
+
+#ifndef PURPLE_ACCOUNT_MANAGER_H
+#define PURPLE_ACCOUNT_MANAGER_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libpurple/account.h>
+
+G_BEGIN_DECLS
+
+#define PURPLE_TYPE_ACCOUNT_MANAGER (purple_account_manager_get_type())
+G_DECLARE_FINAL_TYPE(PurpleAccountManager, purple_account_manager, PURPLE, ACCOUNT_MANAGER, GObject)
+
+/**
+ * PurpleAccountManagerForeachFunc:
+ * @account: The account instance.
+ * @data: User specified data.
+ *
+ * A function used as a callback with purple_account_manager_foreach().
+ *
+ * Since: 3.0.0
+ */
+typedef void (*PurpleAccountManagerForeachFunc)(PurpleAccount *account, gpointer data);
+
+/**
+ * PurpleAccountManager:
+ * @get_idle_time: vfunc to get the time that the user interface has been idle.
+ *
+ * An interface that a user interface can implement to let the core determine
+ * idle times.
+ *
+ * Since: 3.0.0
+ */
+
+/**
+ * purple_account_manager_get_default:
+ *
+ * Gets the default account manager for libpurple.
+ *
+ * Returns: (transfer none): The default account manager for libpurple.
+ *
+ * Since: 3.0.0
+ */
+PurpleAccountManager *purple_account_manager_get_default(void);
+
+/** purple_account_manager_add:
+ * @manager: The account manager instance.
+ * @account: (transfer full): The account to add.
+ *
+ * Adds @account to @manager.
+ *
+ * Since: 3.0.0
+ */
+void purple_account_manager_add(PurpleAccountManager *manager, PurpleAccount *account);
+
+/** purple_account_manager_remove:
+ * @manager: The account manager instance.
+ * @account: The account to remove.
+ *
+ * Removes @account from @manager.
+ *
+ * Since: 3.0.0
+ */
+void purple_account_manager_remove(PurpleAccountManager *manager, PurpleAccount *account);
+
+/**
+ * purple_account_manager_reorder:
+ * @manager: The account manager instance.
+ * @account: The account instance.
+ * @new_index: The numerical position to move @account to.
+ *
+ * Moves @account to @new_index in @manager.
+ *
+ * Since: 3.0.0
+ */
+void purple_account_manager_reorder(PurpleAccountManager *manager, PurpleAccount *account, guint new_index);
+
+/**
+ * purple_account_manager_get_all:
+ * @manager: The account manager instance.
+ *
+ * Gets the list of all accounts.
+ *
+ * Returns: (transfer none) (element-type PurpleAccount): The list of all
+ * accounts.
+ *
+ * Since: 3.0.0
+ */
+GList *purple_account_manager_get_all(PurpleAccountManager *manager);
+
+/**
+ * purple_account_manager_get_active:
+ * @manager: The account manager instance.
+ *
+ * Gets the list of all active accounts.
+ *
+ * Returns: (transfer container) (element-type PurpleAccount): The list of all
+ * active accounts.
+ *
+ * Since: 3.0.0
+ */
+GList *purple_account_manager_get_active(PurpleAccountManager *manager);
+
+/**
+ * purple_account_manager_find:
+ * @manager: The account manager instance.
+ * @username: The username of the account.
+ * @protocol_id: The id of the protocol of the account.
+ *
+ * Attempts to find an account in @manager with the matching @username and
+ * @protocol_id.
+ *
+ * Returns: (transfer none): The account if found, otherwise %NULL.
+ *
+ * Since: 3.0.0
+ */
+PurpleAccount *purple_account_manager_find(PurpleAccountManager *manager, const gchar *username, const gchar *protocol_id);
+
+/**
+ * purple_account_manager_foreach:
+ * @manager: The account manager instance.
+ * @callback: (scope call): The function to call.
+ * @data: User data to pass to @callback.
+ *
+ * Calls @callback with @data for each account that @manager knows about.
+ *
+ * Since: 3.0.0
+ */
+void purple_account_manager_foreach(PurpleAccountManager *manager, PurpleAccountManagerForeachFunc callback, gpointer data);
+
+G_END_DECLS
+
+#endif /* PURPLE_ACCOUNT_MANAGER_H */
--- a/libpurple/purpleprivate.h Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/purpleprivate.h Fri Dec 03 01:56:48 2021 -0600
@@ -182,6 +182,24 @@
_purple_conversation_write_common(PurpleConversation *conv, PurpleMessage *msg);
/**
+ * purple_account_manager_startup:
+ *
+ * Starts up the account manager by creating the default instance.
+ *
+ * Since: 3.0.0
+ */
+void purple_account_manager_startup(void);
+
+/**
+ * purple_account_manager_shutdown:
+ *
+ * Shuts down the account manager by destroying the default instance.
+ *
+ * Since: 3.0.0
+ */
+void purple_account_manager_shutdown(void);
+
+/**
* purple_conversation_manager_startup:
*
* Starts up the conversation manager by creating the default instance.
--- a/libpurple/purpleprotocol.c Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/purpleprotocol.c Fri Dec 03 01:56:48 2021 -0600
@@ -22,7 +22,7 @@
#include "purpleprotocol.h"
-#include "accounts.h"
+#include "purpleaccountmanager.h"
#include "purpleenums.h"
enum {
@@ -145,6 +145,25 @@
g_object_notify_by_pspec(G_OBJECT(protocol), properties[PROP_OPTIONS]);
}
+static void
+purple_protocol_foreach_account_disconnect(PurpleAccount *account,
+ gpointer data)
+{
+ const gchar *protocol_id = (const gchar *)data;
+
+ /* I'm not sure that we can finalize a protocol plugin if an account is
+ * still using it.. Right now accounts don't ref protocols, but maybe
+ * they should?
+ */
+ if(purple_account_is_disconnected(account)) {
+ return;
+ }
+
+ if(purple_strequal(protocol_id, purple_account_get_protocol_id(account))) {
+ purple_account_disconnect(account);
+ }
+}
+
/******************************************************************************
* GObject Implementation
*****************************************************************************/
@@ -228,12 +247,16 @@
static void
purple_protocol_finalize(GObject *object) {
+ PurpleAccountManager *manager = purple_account_manager_get_default();
PurpleProtocol *protocol = PURPLE_PROTOCOL(object);
PurpleProtocolPrivate *priv = NULL;
- GList *accounts, *l;
priv = purple_protocol_get_instance_private(protocol);
+ purple_account_manager_foreach(manager,
+ purple_protocol_foreach_account_disconnect,
+ priv->id);
+
g_clear_pointer(&priv->id, g_free);
g_clear_pointer(&priv->name, g_free);
g_clear_pointer(&priv->description, g_free);
@@ -241,22 +264,6 @@
g_clear_pointer(&priv->icon_search_path, g_free);
g_clear_pointer(&priv->icon_resource_path, g_free);
- /* I'm not sure that we can finalize a protocol plugin if an account is
- * still using it.. Right now accounts don't ref protocols, but maybe
- * they should?
- */
- accounts = purple_accounts_get_all_active();
- for (l = accounts; l != NULL; l = l->next) {
- PurpleAccount *account = PURPLE_ACCOUNT(l->data);
- if (purple_account_is_disconnected(account))
- continue;
-
- if (purple_strequal(priv->id, purple_account_get_protocol_id(account)))
- purple_account_disconnect(account);
- }
-
- g_list_free(accounts);
-
/* these seem to be fallbacks if the subclass protocol doesn't do it's own
* clean up? I kind of want to delete them... - gk 2021-03-03
*/
--- a/libpurple/savedstatuses.c Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/savedstatuses.c Fri Dec 03 01:56:48 2021 -0600
@@ -27,6 +27,7 @@
#include "debug.h"
#include "idle.h"
#include "notify.h"
+#include "purpleaccountmanager.h"
#include "purplemarkup.h"
#include "savedstatuses.h"
#include "request.h"
@@ -374,42 +375,46 @@
/* Read the account */
node = purple_xmlnode_get_child(substatus, "account");
- if (node != NULL)
- {
- char *acct_name;
+ if(node != NULL) {
+ gchar *acct_name;
const char *protocol;
+
acct_name = purple_xmlnode_get_data(node);
protocol = purple_xmlnode_get_attrib(node, "protocol");
- if ((acct_name != NULL) && (protocol != NULL))
- ret->account = purple_accounts_find(acct_name, protocol);
+
+ if(acct_name != NULL && protocol != NULL) {
+ PurpleAccountManager *manager = NULL;
+
+ manager = purple_account_manager_get_default();
+
+ ret->account = purple_account_manager_find(manager, acct_name,
+ protocol);
+ }
+
g_free(acct_name);
}
- if (ret->account == NULL)
- {
+ if(ret->account == NULL) {
g_free(ret);
return NULL;
}
/* Read the state */
node = purple_xmlnode_get_child(substatus, "state");
- if ((node != NULL) && ((data = purple_xmlnode_get_data(node)) != NULL))
- {
+ if((node != NULL) && ((data = purple_xmlnode_get_data(node)) != NULL)) {
ret->type = purple_status_type_find_with_id(
purple_account_get_status_types(ret->account), data);
g_free(data);
}
- if (ret->type == NULL)
- {
+ if(ret->type == NULL) {
g_free(ret);
return NULL;
}
/* Read the message */
node = purple_xmlnode_get_child(substatus, "message");
- if ((node != NULL) && ((data = purple_xmlnode_get_data(node)) != NULL))
- {
+ if((node != NULL) && ((data = purple_xmlnode_get_data(node)) != NULL)) {
ret->message = data;
}
@@ -846,14 +851,15 @@
}
void
-purple_savedstatus_set_idleaway(gboolean idleaway)
-{
+purple_savedstatus_set_idleaway(gboolean idleaway) {
+ PurpleAccountManager *manager = NULL;
+ PurpleSavedStatus *old, *saved_status;
GList *accounts, *node;
- PurpleSavedStatus *old, *saved_status;
- if (purple_savedstatus_is_idleaway() == idleaway)
+ if(purple_savedstatus_is_idleaway() == idleaway) {
/* Don't need to do anything */
return;
+ }
old = purple_savedstatus_get_current();
saved_status = idleaway ? purple_savedstatus_get_idleaway()
@@ -861,16 +867,19 @@
purple_prefs_set_bool("/purple/savedstatus/isidleaway", idleaway);
/* Changing our status makes us un-idle */
- if (!idleaway)
+ if(!idleaway) {
purple_idle_touch();
+ }
- if (idleaway && (purple_savedstatus_get_primitive_type(old) != PURPLE_STATUS_AVAILABLE))
+ if(idleaway && (purple_savedstatus_get_primitive_type(old) != PURPLE_STATUS_AVAILABLE))
+ {
/* Our global status is already "away," so don't change anything */
return;
+ }
- accounts = purple_accounts_get_all_active();
- for (node = accounts; node != NULL; node = node->next)
- {
+ manager = purple_account_manager_get_default();
+ accounts = purple_account_manager_get_active(manager);
+ for (node = accounts; node != NULL; node = node->next) {
PurpleAccount *account;
PurplePresence *presence;
PurpleStatus *status;
@@ -1085,10 +1094,10 @@
}
void
-purple_savedstatus_activate(PurpleSavedStatus *saved_status)
-{
+purple_savedstatus_activate(PurpleSavedStatus *saved_status) {
+ PurpleAccountManager *manager = NULL;
+ PurpleSavedStatus *old = purple_savedstatus_get_current();
GList *accounts, *node;
- PurpleSavedStatus *old = purple_savedstatus_get_current();
g_return_if_fail(saved_status != NULL);
@@ -1096,13 +1105,14 @@
saved_status->lastused = time(NULL);
saved_status->usage_count++;
saved_statuses = g_list_remove(saved_statuses, saved_status);
- saved_statuses = g_list_insert_sorted(saved_statuses, saved_status, saved_statuses_sort_func);
+ saved_statuses = g_list_insert_sorted(saved_statuses, saved_status,
+ saved_statuses_sort_func);
purple_prefs_set_int("/purple/savedstatus/default",
- purple_savedstatus_get_creation_time(saved_status));
+ purple_savedstatus_get_creation_time(saved_status));
- accounts = purple_accounts_get_all_active();
- for (node = accounts; node != NULL; node = node->next)
- {
+ manager = purple_account_manager_get_default();
+ accounts = purple_account_manager_get_active(manager);
+ for(node = accounts; node != NULL; node = node->next) {
PurpleAccount *account;
account = node->data;
@@ -1112,11 +1122,11 @@
g_list_free(accounts);
- if (purple_savedstatus_is_idleaway()) {
+ if(purple_savedstatus_is_idleaway()) {
purple_savedstatus_set_idleaway(FALSE);
} else {
- purple_signal_emit(purple_savedstatuses_get_handle(), "savedstatus-changed",
- saved_status, old);
+ purple_signal_emit(purple_savedstatuses_get_handle(),
+ "savedstatus-changed", saved_status, old);
}
}
--- a/libpurple/tests/meson.build Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/tests/meson.build Fri Dec 03 01:56:48 2021 -0600
@@ -1,5 +1,6 @@
PROGS = [
'account_option',
+ 'account_manager',
'circular_buffer',
'credential_manager',
'credential_provider',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/tests/test_account_manager.c Fri Dec 03 01:56:48 2021 -0600
@@ -0,0 +1,210 @@
+/*
+ * Purple - Internet Messaging Library
+ * Copyright (C) Pidgin Developers <devel@pidgin.im>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include <purple.h>
+
+#include "test_ui.h"
+
+#define PURPLE_GLOBAL_HEADER_INSIDE
+#include "../purpleprivate.h"
+#undef PURPLE_GLOBAL_HEADER_INSIDE
+
+/******************************************************************************
+ * Tests
+ *****************************************************************************/
+static void
+test_purple_account_manager_get_default(void) {
+ PurpleAccountManager *manager1 = NULL, *manager2 = NULL;
+
+ manager1 = purple_account_manager_get_default();
+ g_assert_true(PURPLE_IS_ACCOUNT_MANAGER(manager1));
+
+ manager2 = purple_account_manager_get_default();
+ g_assert_true(PURPLE_IS_ACCOUNT_MANAGER(manager2));
+
+ g_assert_true(manager1 == manager2);
+}
+
+/******************************************************************************
+ * Add/Remove Test
+ *****************************************************************************/
+static void
+test_purple_account_manager_signal_called(G_GNUC_UNUSED PurpleAccountManager *manager,
+ G_GNUC_UNUSED PurpleAccount *account,
+ gpointer data)
+{
+ gboolean *called = (data);
+
+ *called = TRUE;
+}
+
+static void
+test_purple_account_manager_add_remove(void) {
+ PurpleAccount *account = NULL;
+ PurpleAccountManager *manager = NULL;
+ GList *accounts = NULL;
+ gboolean signal_called = FALSE;
+
+ account = purple_account_new("test", "test");
+ manager = g_object_new(PURPLE_TYPE_ACCOUNT_MANAGER, NULL);
+
+ g_signal_connect(manager, "added",
+ G_CALLBACK(test_purple_account_manager_signal_called),
+ &signal_called);
+ g_signal_connect(manager, "removed",
+ G_CALLBACK(test_purple_account_manager_signal_called),
+ &signal_called);
+
+ accounts = purple_account_manager_get_all(manager);
+ g_assert_true(g_list_length(accounts) == 0);
+
+ /* Add the account and verify that it was added and that the signal was
+ * emitted.
+ */
+ purple_account_manager_add(manager, account);
+ accounts = purple_account_manager_get_all(manager);
+ g_assert_true(g_list_length(accounts) == 1);
+ g_assert_true(signal_called);
+
+ signal_called = FALSE;
+
+ /* Remove the account and verify that it was removed and that the signal
+ * was emitted.
+ */
+ purple_account_manager_remove(manager, account);
+ accounts = purple_account_manager_get_all(manager);
+ g_assert_true(g_list_length(accounts) == 0);
+ g_assert_true(signal_called);
+
+ /* Cleanup */
+ g_clear_object(&account);
+ g_clear_object(&manager);
+}
+
+/******************************************************************************
+ * Find Tests
+ *****************************************************************************/
+static void
+test_purple_account_manager_find(void) {
+ PurpleAccount *account = NULL, *found = NULL;
+ PurpleAccountManager *manager = NULL;
+
+ manager = g_object_new(PURPLE_TYPE_ACCOUNT_MANAGER, NULL);
+
+ /* Try to find an account that doesn't exist. */
+ found = purple_account_manager_find(manager, "test", "test");
+ g_assert_null(found);
+
+ /* Create the account that will be used in the rest of the test. */
+ account = purple_account_new("test", "test");
+
+ /* Now add an account and verify that we can find it. */
+ purple_account_manager_add(manager, account);
+ found = purple_account_manager_find(manager, "test", "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");
+ g_assert_null(found);
+
+ /* Cleanup */
+ g_clear_object(&account);
+ g_clear_object(&manager);
+}
+
+/******************************************************************************
+ * Foreach Tests
+ *****************************************************************************/
+static void
+test_purple_account_manager_foreach_func(G_GNUC_UNUSED PurpleAccount *account,
+ gpointer data)
+{
+ guint *count = (guint *)data;
+
+ /* We have to use (*count)++ because *count++ doesn't work as the ++
+ * happens after the statement which is no longer the dereferenced pointer.
+ */
+ (*count)++;
+}
+
+static void
+test_purple_account_manager_foreach(void) {
+ PurpleAccount *accounts[3];
+ PurpleAccountManager *manager = NULL;
+ guint count = 0;
+
+ manager = g_object_new(PURPLE_TYPE_ACCOUNT_MANAGER, NULL);
+
+ accounts[0] = purple_account_new("test0", "test");
+ accounts[1] = purple_account_new("test1", "test");
+ accounts[2] = purple_account_new("test2", "test");
+
+ purple_account_manager_add(manager, accounts[0]);
+ purple_account_manager_add(manager, accounts[1]);
+ purple_account_manager_add(manager, accounts[2]);
+
+ purple_account_manager_foreach(manager,
+ test_purple_account_manager_foreach_func,
+ &count);
+
+ g_assert_cmpuint(count, ==, 3);
+
+ /* Now remove everything and verify that the foreach callback wasn't
+ * called.
+ */
+ purple_account_manager_remove(manager, accounts[0]);
+ purple_account_manager_remove(manager, accounts[1]);
+ purple_account_manager_remove(manager, accounts[2]);
+
+ count = 0;
+ purple_account_manager_foreach(manager,
+ test_purple_account_manager_foreach_func,
+ &count);
+
+ g_assert_cmpuint(count, ==, 0);
+
+ /* Cleanup */
+ g_clear_object(&accounts[0]);
+ g_clear_object(&accounts[1]);
+ g_clear_object(&accounts[2]);
+ g_clear_object(&manager);
+}
+
+/******************************************************************************
+ * Main
+ *****************************************************************************/
+gint
+main(gint argc, gchar *argv[]) {
+ g_test_init(&argc, &argv, NULL);
+
+ test_ui_purple_init();
+
+ g_test_add_func("/account-manager/get-default",
+ test_purple_account_manager_get_default);
+ g_test_add_func("/account-manager/add-remove",
+ test_purple_account_manager_add_remove);
+ g_test_add_func("/account-manager/find",
+ test_purple_account_manager_find);
+ g_test_add_func("/account-manager/foreach",
+ test_purple_account_manager_foreach);
+
+ return g_test_run();
+}
--- a/libpurple/util.c Fri Dec 03 01:55:19 2021 -0600
+++ b/libpurple/util.c Fri Dec 03 01:56:48 2021 -0600
@@ -27,6 +27,7 @@
#include "debug.h"
#include "notify.h"
#include "prefs.h"
+#include "purpleaccountmanager.h"
#include "purpleconversation.h"
#include "purpleprotocol.h"
#include "purpleprotocolclient.h"
@@ -1895,7 +1896,8 @@
void purple_util_set_current_song(const char *title, const char *artist, const char *album)
{
- GList *list = purple_accounts_get_all();
+ PurpleAccountManager *manager = purple_account_manager_get_default();
+ GList *list = purple_account_manager_get_all(manager);
for (; list; list = list->next) {
PurplePresence *presence;
PurpleStatus *tune;