Update ContactManager to call ProtocolRoster.update_async when necessary

Wed, 19 Jul 2023 16:19:54 -0500

author
Gary Kramlich <grim@reaperworld.com>
date
Wed, 19 Jul 2023 16:19:54 -0500
changeset 42245
57a4955beaf3
parent 42244
589616e405b3
child 42246
3230f1a1fb8f

Update ContactManager to call ProtocolRoster.update_async when necessary

Testing Done:
Compiled. I didn't write unit tests because that would have required adding a protocol into `test_contact_manager.c` and that's a lot of work to test that our signal handlers are connected correctly when all of the other code is covered by tests.

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

libpurple/purplecontactmanager.c file | annotate | diff | comparison | revisions
libpurple/purpleprotocolroster.h file | annotate | diff | comparison | revisions
--- a/libpurple/purplecontactmanager.c	Wed Jul 19 16:17:09 2023 -0500
+++ b/libpurple/purplecontactmanager.c	Wed Jul 19 16:19:54 2023 -0500
@@ -22,6 +22,7 @@
 
 #include "purplegdkpixbuf.h"
 #include "purpleprivate.h"
+#include "purpleprotocolroster.h"
 #include "util.h"
 
 enum {
@@ -135,10 +136,34 @@
 	return TRUE;
 }
 
+static void
+purple_contact_manager_protocol_roster_update(PurpleContact *contact) {
+	PurpleAccount *account = NULL;
+
+	account = purple_contact_get_account(contact);
+	if(PURPLE_IS_ACCOUNT(account)) {
+		PurpleProtocol *protocol = NULL;
+
+		protocol = purple_account_get_protocol(account);
+		if(PURPLE_IS_PROTOCOL_ROSTER(protocol)) {
+			purple_protocol_roster_update_async(PURPLE_PROTOCOL_ROSTER(protocol),
+			                                    contact, NULL, NULL, NULL);
+		}
+	}
+}
+
 /******************************************************************************
  * Callbacks
  *****************************************************************************/
 static void
+purple_contact_manager_contact_update_cb(GObject *obj,
+                                         G_GNUC_UNUSED GParamSpec *pspec,
+                                         G_GNUC_UNUSED gpointer data)
+{
+	purple_contact_manager_protocol_roster_update(PURPLE_CONTACT(obj));
+}
+
+static void
 purple_contact_manager_contact_person_changed_cb(GObject *obj,
                                                  G_GNUC_UNUSED GParamSpec *pspec,
                                                  gpointer data)
@@ -159,6 +184,19 @@
 	 * person.
 	 */
 	purple_contact_manager_add_person(manager, person);
+
+	/* Finally tell the ProtocolRoster about this change. */
+	purple_contact_manager_protocol_roster_update(contact);
+}
+
+static void
+purple_contact_manager_tags_changed_cb(G_GNUC_UNUSED PurpleTags *tags,
+                                       G_GNUC_UNUSED const char *tag,
+                                       G_GNUC_UNUSED const char *name,
+                                       G_GNUC_UNUSED const char *value,
+                                       gpointer data)
+{
+	purple_contact_manager_protocol_roster_update(data);
 }
 
 /******************************************************************************
@@ -404,6 +442,7 @@
 	if(added) {
 		PurpleContactInfo *info = PURPLE_CONTACT_INFO(contact);
 		PurplePerson *person = purple_contact_info_get_person(info);
+		PurpleTags *tags = NULL;
 
 		/* If the contact already has a person, add the person to our list of
 		 * people.
@@ -412,10 +451,24 @@
 			purple_contact_manager_add_person(manager, person);
 		}
 
-		/* Add a notify on the person property to track changes. */
+		tags = purple_contact_info_get_tags(info);
+
+		/* Add some notify signals to track changes. */
+		g_signal_connect_object(contact, "notify::alias",
+		                        G_CALLBACK(purple_contact_manager_contact_update_cb),
+		                        manager, 0);
+		g_signal_connect_object(contact, "notify::permission",
+		                        G_CALLBACK(purple_contact_manager_contact_update_cb),
+		                        manager, 0);
 		g_signal_connect_object(contact, "notify::person",
 		                        G_CALLBACK(purple_contact_manager_contact_person_changed_cb),
 		                        manager, 0);
+		g_signal_connect_object(tags, "added",
+		                        G_CALLBACK(purple_contact_manager_tags_changed_cb),
+		                        contact, 0);
+		g_signal_connect_object(tags, "removed",
+		                        G_CALLBACK(purple_contact_manager_tags_changed_cb),
+		                        contact, 0);
 
 		g_signal_emit(manager, signals[SIG_ADDED], 0, contact);
 	}
@@ -439,6 +492,7 @@
 	}
 
 	if(g_list_store_find(contacts, contact, &position)) {
+		PurpleTags *tags = NULL;
 		gboolean removed = FALSE;
 		guint len = 0;
 
@@ -453,6 +507,14 @@
 			removed = TRUE;
 		}
 
+		/* Remove the signals for the contact's tags changing as we're no
+		 * longer tracking the contact they belong to.
+		 */
+		tags = purple_contact_info_get_tags(PURPLE_CONTACT_INFO(contact));
+		g_signal_handlers_disconnect_by_func(tags,
+		                                     purple_contact_manager_tags_changed_cb,
+		                                     contact);
+
 		if(removed) {
 			g_signal_emit(manager, signals[SIG_REMOVED], 0, contact);
 		}
--- a/libpurple/purpleprotocolroster.h	Wed Jul 19 16:17:09 2023 -0500
+++ b/libpurple/purpleprotocolroster.h	Wed Jul 19 16:19:54 2023 -0500
@@ -135,6 +135,11 @@
  * @callback is called, [method@ProtocolRoster.update_finish] should be called
  * to get the result.
  *
+ * This would include things that the libpurple user can change about a remote
+ * contact. Including but not limited to [property@ContactInfo:alias],
+ * [property@ContactInfo:permission], [property@ContactInfo:person], and
+ * [property@ContactInfo:tags].
+ *
  * Since: 3.0.0
  */
 void purple_protocol_roster_update_async(PurpleProtocolRoster *roster, PurpleContact *contact, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data);

mercurial