pidgin/pidgin

Parents 64287dd40326
Children e393090804c1
Create and add PurpleContacts to the manager when purple_buddy_new is called

This required some additional changes to PurpleContact. Namely that the contact always has a presence and it is no longer writeable.

Testing Done:
Ran the unit tests and verified nothing funky happens when running.

We can't test that all of the properties are properly bound because we would have to start up a lot more of libpurple than I'm willing to do for something that's temporary.

Bugs closed: PIDGIN-17685

Reviewed at https://reviews.imfreedom.org/r/1873/
--- a/libpurple/buddy.c Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/buddy.c Sat Oct 01 01:50:52 2022 -0500
@@ -24,6 +24,7 @@
#include "debug.h"
#include "purplebuddypresence.h"
+#include "purplecontactmanager.h"
#include "purpleconversationmanager.h"
#include "purpleprotocolclient.h"
#include "util.h"
@@ -292,15 +293,25 @@
PurpleBuddy *
purple_buddy_new(PurpleAccount *account, const gchar *name, const gchar *alias)
{
+ PurpleBuddy *buddy = NULL;
+ PurpleContactManager *manager = NULL;
+
g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
g_return_val_if_fail(name != NULL, NULL);
- return g_object_new(
+ buddy = g_object_new(
PURPLE_TYPE_BUDDY,
"account", account,
"name", name,
"local-alias", alias,
NULL);
+
+ manager = purple_contact_manager_get_default();
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ purple_contact_manager_add_buddy(manager, buddy);
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
+ return buddy;
}
const gchar *
--- a/libpurple/purplecontact.c Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/purplecontact.c Sat Oct 01 01:50:52 2022 -0500
@@ -150,9 +150,6 @@
case PROP_AVATAR:
purple_contact_set_avatar(contact, g_value_get_object(value));
break;
- case PROP_PRESENCE:
- purple_contact_set_presence(contact, g_value_get_object(value));
- break;
case PROP_PERSON:
purple_contact_set_person(contact, g_value_get_object(value));
break;
@@ -202,6 +199,7 @@
static void
purple_contact_init(PurpleContact *contact) {
contact->tags = purple_tags_new();
+ contact->presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
}
static void
@@ -308,7 +306,7 @@
"presence", "presence",
"The presence of the contact",
PURPLE_TYPE_PRESENCE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
/**
* PurpleContact:tags:
@@ -443,15 +441,6 @@
return contact->presence;
}
-void
-purple_contact_set_presence(PurpleContact *contact, PurplePresence *presence) {
- g_return_if_fail(PURPLE_IS_CONTACT(contact));
-
- if(g_set_object(&contact->presence, presence)) {
- g_object_notify_by_pspec(G_OBJECT(contact), properties[PROP_PRESENCE]);
- }
-}
-
PurpleTags *
purple_contact_get_tags(PurpleContact *contact) {
g_return_val_if_fail(PURPLE_IS_CONTACT(contact), NULL);
--- a/libpurple/purplecontact.h Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/purplecontact.h Sat Oct 01 01:50:52 2022 -0500
@@ -207,20 +207,6 @@
PurplePresence *purple_contact_get_presence(PurpleContact *contact);
/**
- * purple_contact_set_presence:
- * @contact: The instance.
- * @presence: (nullable): The new [class@Purple.Presence] to set.
- *
- * Sets the presence for @contact to @presence. If @presence is %NULL, the
- * existing presence will be cleared.
- *
- * Typically this should only be called by the protocol plugin.
- *
- * Since: 3.0.0
- */
-void purple_contact_set_presence(PurpleContact *contact, PurplePresence *presence);
-
-/**
* purple_contact_get_tags:
* @contact: The instance.
*
--- a/libpurple/purplecontactmanager.c Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/purplecontactmanager.c Sat Oct 01 01:50:52 2022 -0500
@@ -19,6 +19,8 @@
#include <glib/gi18n-lib.h>
#include "purplecontactmanager.h"
+
+#include "purplegdkpixbuf.h"
#include "purpleprivate.h"
#include "util.h"
@@ -68,6 +70,62 @@
return purple_strequal(id_a, id_b);
}
+static gboolean
+purple_contact_manager_convert_icon_to_avatar(GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ PurpleBuddyIcon *icon = g_value_get_pointer(from_value);
+ GdkPixbuf *avatar = NULL;
+ gconstpointer data = NULL;
+ size_t len;
+
+ if(icon == NULL) {
+ g_value_set_object(to_value, NULL);
+ return TRUE;
+ }
+
+ data = purple_buddy_icon_get_data(icon, &len);
+
+ avatar = purple_gdk_pixbuf_from_data(data, len);
+
+ g_value_take_object(to_value, avatar);
+
+ return TRUE;
+}
+
+static gboolean
+purple_contact_manager_convert_avatar_to_icon(GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ PurpleBuddyIcon *icon = NULL;
+ GdkPixbuf *avatar = g_value_get_object(from_value);
+ gchar *buffer = NULL;
+ gsize len;
+ gboolean result = FALSE;
+
+ if(!GDK_IS_PIXBUF(avatar)) {
+ g_value_set_pointer(to_value, NULL);
+
+ return TRUE;
+ }
+
+ result = gdk_pixbuf_save_to_buffer(avatar, &buffer, &len, "png", NULL,
+ "compression", "9", NULL);
+ if(!result) {
+ return FALSE;
+ }
+
+ purple_buddy_icon_set_data(icon, (guchar *)buffer, len, NULL);
+
+ g_free(buffer);
+
+ return TRUE;
+}
+
/******************************************************************************
* GObject Implementation
*****************************************************************************/
@@ -367,3 +425,60 @@
return NULL;
}
+
+/******************************************************************************
+ * Migration API
+ *****************************************************************************/
+void
+purple_contact_manager_add_buddy(PurpleContactManager *manager,
+ PurpleBuddy *buddy)
+{
+ PurpleAccount *account = NULL;
+ PurpleContact *contact = NULL;
+ PurplePresence *buddy_presence = NULL;
+ PurplePresence *contact_presence = NULL;
+ const gchar *id = NULL;
+
+ g_return_if_fail(PURPLE_IS_CONTACT_MANAGER(manager));
+ g_return_if_fail(PURPLE_IS_BUDDY(buddy));
+
+ /* Create the new contact. */
+ account = purple_buddy_get_account(buddy);
+ id = purple_buddy_get_id(buddy);
+ contact = purple_contact_new(account, id);
+
+ /* Bind all of the properties. */
+ g_object_bind_property(buddy, "name", contact, "username",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property(buddy, "local-alias", contact, "alias",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property(buddy, "server-alias", contact, "display-name",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+
+ buddy_presence = purple_buddy_get_presence(buddy);
+ contact_presence = purple_contact_get_presence(contact);
+
+ g_object_bind_property(buddy_presence, "idle", contact_presence, "idle",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property(buddy_presence, "idle-time", contact_presence,
+ "idle-time",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property(buddy_presence, "login-time", contact_presence,
+ "login-time",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+ g_object_bind_property(buddy_presence, "active-status", contact_presence,
+ "active-status",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
+
+ g_object_bind_property_full(buddy, "icon", contact, "avatar",
+ G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL,
+ purple_contact_manager_convert_icon_to_avatar,
+ purple_contact_manager_convert_avatar_to_icon,
+ NULL, NULL);
+
+ /* Finally add it to the manager. */
+ purple_contact_manager_add(manager, contact);
+
+ /* purple_contact_manager_add adds its own reference, so free our copy. */
+ g_clear_object(&contact);
+}
--- a/libpurple/purplecontactmanager.h Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/purplecontactmanager.h Sat Oct 01 01:50:52 2022 -0500
@@ -141,6 +141,23 @@
*/
PurpleContact *purple_contact_manager_find_with_id(PurpleContactManager *manager, PurpleAccount *account, const gchar *id);
+/**
+ * purple_contact_manager_add_buddy:
+ * @manager: The instance.
+ * @buddy: A [class@Purple.Buddy] instance.
+ *
+ * Creates a new [class@Purple.Contact] and binds its properties to @buddy and
+ * then adds the new [class@Purple.Contact] via
+ * [method@Purple.ContactManager.add].
+ *
+ * This method is meant to help us transition to the new API and this method
+ * shouldn't be used elsewhere.
+ *
+ * Since: 3.0.0
+ */
+G_DEPRECATED
+void purple_contact_manager_add_buddy(PurpleContactManager *manager, PurpleBuddy *buddy);
+
G_END_DECLS
#endif /* PURPLE_CONTACT_MANAGER_H */
--- a/libpurple/purpleperson.c Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/purpleperson.c Sat Oct 01 01:50:52 2022 -0500
@@ -113,18 +113,6 @@
purple_person_sort_contacts(data);
}
-static void
-purple_person_contact_notify_cb(GObject *obj,
- G_GNUC_UNUSED GParamSpec *pspec,
- gpointer data)
-{
- PurpleContact *contact = PURPLE_CONTACT(obj);
-
- g_signal_connect_object(contact, "notify",
- G_CALLBACK(purple_person_presence_notify_cb),
- data, 0);
-}
-
/******************************************************************************
* GListModel Implementation
*****************************************************************************/
@@ -407,17 +395,11 @@
g_ptr_array_add(person->contacts, g_object_ref(contact));
- g_signal_connect_object(contact, "notify::presence",
- G_CALLBACK(purple_person_contact_notify_cb),
+ presence = purple_contact_get_presence(contact);
+ g_signal_connect_object(presence, "notify",
+ G_CALLBACK(purple_person_presence_notify_cb),
person, 0);
- presence = purple_contact_get_presence(contact);
- if(PURPLE_IS_PRESENCE(presence)) {
- g_signal_connect_object(presence, "notify",
- G_CALLBACK(purple_person_presence_notify_cb),
- person, 0);
- }
-
purple_contact_set_person(contact, person);
purple_person_sort_contacts(person);
@@ -441,17 +423,10 @@
if(removed) {
PurplePresence *presence = purple_contact_get_presence(contact);
- /* Disconnect our signal handlers. */
- g_signal_handlers_disconnect_by_func(contact,
- purple_person_contact_notify_cb,
+ g_signal_handlers_disconnect_by_func(presence,
+ purple_person_presence_notify_cb,
person);
- if(PURPLE_IS_PRESENCE(presence)) {
- g_signal_handlers_disconnect_by_func(presence,
- purple_person_presence_notify_cb,
- person);
- }
-
purple_contact_set_person(contact, NULL);
purple_person_sort_contacts(person);
--- a/libpurple/tests/test_contact.c Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/tests/test_contact.c Sat Oct 01 01:50:52 2022 -0500
@@ -47,7 +47,6 @@
PurpleContact *contact = NULL;
PurplePerson *person = NULL;
PurplePerson *person1 = NULL;
- PurplePresence *presence = NULL;
PurplePresence *presence1 = NULL;
PurpleTags *tags = NULL;
GdkPixbuf *avatar = NULL;
@@ -59,7 +58,6 @@
account = purple_account_new("test", "test");
avatar = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, 1, 1);
- presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
person = purple_person_new();
/* Use g_object_new so we can test setting properties by name. All of them
@@ -74,7 +72,6 @@
"display-name", "display-name",
"alias", "alias",
"avatar", avatar,
- "presence", presence,
"person", person,
NULL);
@@ -98,7 +95,7 @@
g_assert_cmpstr(display_name, ==, "display-name");
g_assert_cmpstr(alias, ==, "alias");
g_assert_true(avatar1 == avatar);
- g_assert_true(presence1 == presence);
+ g_assert_nonnull(presence1);
g_assert_nonnull(tags);
g_assert_true(person1 == person);
@@ -114,7 +111,6 @@
g_clear_object(&person);
g_clear_object(&person1);
- g_clear_object(&presence);
g_clear_object(&avatar);
g_clear_object(&contact);
g_clear_object(&account);
--- a/libpurple/tests/test_contact_manager.c Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/tests/test_contact_manager.c Sat Oct 01 01:50:52 2022 -0500
@@ -260,6 +260,90 @@
g_clear_object(&manager);
}
+static void
+test_purple_contact_manager_add_buddy(void) {
+ PurpleAccount *account = NULL;
+ PurpleBuddy *buddy = NULL;
+ PurpleContact *contact = NULL;
+ PurpleContactManager *manager = NULL;
+ PurpleStatusType *type = NULL;
+ GList *statuses = NULL;
+ const gchar *id = NULL;
+ const gchar *source = NULL;
+ const gchar *destination = NULL;
+
+ manager = purple_contact_manager_get_default();
+
+ /* Create our account and add the statuses for testing. */
+ account = purple_account_new("test", "test");
+
+ type = purple_status_type_new(PURPLE_STATUS_OFFLINE, "offline",
+ "offline", TRUE);
+ statuses = g_list_append(statuses, type);
+
+ purple_account_set_status_types(account, statuses);
+
+ /* purple_buddy_new will call purple_contact_manager_add_buddy. */
+ buddy = purple_buddy_new(account, "buddy-name", "buddy-alias");
+
+ /* Verify that we can find the created contact via id. */
+ id = purple_buddy_get_id(buddy);
+ contact = purple_contact_manager_find_with_id(manager, account, id);
+ g_assert_nonnull(contact);
+ g_assert_true(PURPLE_IS_CONTACT(contact));
+
+ /* Verify that we can find the created contact via username. */
+ contact = purple_contact_manager_find_with_username(manager, account,
+ "buddy-name");
+ g_assert_nonnull(contact);
+ g_assert_true(PURPLE_IS_CONTACT(contact));
+
+ /* Now check the alias and display name to make sure they were synced as
+ * well.
+ */
+ source = purple_buddy_get_local_alias(buddy);
+ destination = purple_contact_get_alias(contact);
+ g_assert_cmpstr(destination, ==, source);
+
+ source = purple_buddy_get_server_alias(buddy);
+ destination = purple_contact_get_display_name(contact);
+ g_assert_cmpstr(destination, ==, source);
+
+ /* Now let's change the settings in the buddy and verify they made it to the
+ * contact.
+ */
+ /* We have to skip testing the name because we have to stand up a LOT more
+ * of libpurple to be able to change the name.
+ purple_buddy_set_name(buddy, "guy-name");
+ g_assert_cmpstr(purple_contact_get_username(contact), ==, "guy-name");
+ */
+
+ purple_buddy_set_local_alias(buddy, "guy-alias");
+ g_assert_cmpstr(purple_contact_get_alias(contact), ==, "guy-alias");
+
+ purple_buddy_set_server_alias(buddy, "server-guy");
+ g_assert_cmpstr(purple_contact_get_display_name(contact), ==,
+ "server-guy");
+
+ purple_contact_set_alias(contact, "friend-alias");
+ g_assert_cmpstr(purple_buddy_get_local_alias(buddy), ==, "friend-alias");
+
+ purple_contact_set_display_name(contact, "server-friend");
+ g_assert_cmpstr(purple_buddy_get_server_alias(buddy), ==, "server-friend");
+
+ /* We can't verify the presences changes because PurpleBuddy has to be in
+ * a PurpleMetaContact for that to not crash.
+ */
+
+ /* Since we're working on the default contact manager, make sure we remove
+ * any contacts for our test account.
+ */
+ purple_contact_manager_remove_all(manager, account);
+
+ g_clear_object(&account);
+ g_clear_object(&buddy);
+ g_clear_object(&contact);
+}
/******************************************************************************
* Main
*****************************************************************************/
@@ -286,5 +370,8 @@
g_test_add_func("/contact-manager/find/with-id",
test_purple_contact_manager_find_with_id);
+ g_test_add_func("/contact-manager/add-buddy",
+ test_purple_contact_manager_add_buddy);
+
return g_test_run();
}
--- a/libpurple/tests/test_person.c Sat Oct 01 01:48:31 2022 -0500
+++ b/libpurple/tests/test_person.c Sat Oct 01 01:50:52 2022 -0500
@@ -236,19 +236,18 @@
priority = purple_person_get_priority_contact(person);
g_assert_null(priority);
- /* Build the presence and status for the contact. */
- presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
+ /* Now create a real contact. */
+ contact = purple_contact_new(account, "username");
+ purple_person_add_contact(person, contact);
+
+ /* Set the status of the contact. */
+ presence = purple_contact_get_presence(contact);
status_type = purple_status_type_new(PURPLE_STATUS_AVAILABLE, "available",
"Available", FALSE);
status = purple_status_new(status_type, presence);
g_object_set(G_OBJECT(presence), "active-status", status, NULL);
g_clear_object(&status);
- /* Now create a real contact. */
- contact = purple_contact_new(account, "username");
- purple_contact_set_presence(contact, presence);
- purple_person_add_contact(person, contact);
-
g_assert_true(called);
priority = purple_person_get_priority_contact(person);
@@ -309,17 +308,16 @@
/* Set changed to false as it shouldn't be changed. */
changed = FALSE;
- /* Build the presence and status for the contact. */
- presence = g_object_new(PURPLE_TYPE_PRESENCE, NULL);
- status = purple_status_new(offline, presence);
- g_object_set(G_OBJECT(presence), "active-status", status, NULL);
- g_clear_object(&status);
-
/* Now create a real contact. */
username = g_strdup_printf("username%d", i + 1);
contact = purple_contact_new(account, username);
g_free(username);
- purple_contact_set_presence(contact, presence);
+
+ /* Set the status for the contact. */
+ presence = purple_contact_get_presence(contact);
+ status = purple_status_new(offline, presence);
+ g_object_set(G_OBJECT(presence), "active-status", status, NULL);
+ g_clear_object(&status);
purple_person_add_contact(person, contact);
@@ -336,7 +334,6 @@
}
g_clear_object(&contact);
- g_clear_object(&presence);
}
n_items = g_list_model_get_n_items(G_LIST_MODEL(person));