[Telepathy-commits] [telepathy-glib/master] TpContact: add a fast-path for by_handle using Contacts.GetContactAttributes()

Simon McVittie simon.mcvittie at collabora.co.uk
Mon Dec 1 03:13:57 PST 2008


---
 telepathy-glib/contact.c |  186 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 186 insertions(+), 0 deletions(-)

diff --git a/telepathy-glib/contact.c b/telepathy-glib/contact.c
index 2f22a66..3fb2d4d 100644
--- a/telepathy-glib/contact.c
+++ b/telepathy-glib/contact.c
@@ -20,6 +20,8 @@
 
 #include <telepathy-glib/contact.h>
 
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/gtypes.h>
 #include <telepathy-glib/interfaces.h>
 #include <telepathy-glib/util.h>
 
@@ -1573,6 +1575,128 @@ contacts_context_queue_features (ContactsContext *context,
 }
 
 
+static void
+contacts_got_attributes (TpConnection *connection,
+                         GHashTable *attributes,
+                         const GError *error,
+                         gpointer user_data,
+                         GObject *weak_object)
+{
+  ContactsContext *c = user_data;
+  guint i;
+
+  if (error != NULL)
+    {
+      contacts_context_fail (c, error);
+      return;
+    }
+
+  i = 0;
+
+  while (i < c->handles->len)
+    {
+      TpHandle handle = g_array_index (c->handles, guint, i);
+      GHashTable *asv = g_hash_table_lookup (attributes,
+          GUINT_TO_POINTER (handle));
+
+      if (asv == NULL)
+        {
+          /* not in the hash table => not valid */
+          g_array_append_val (c->invalid, handle);
+          g_array_remove_index_fast (c->handles, i);
+        }
+      else
+        {
+          TpContact *contact = NULL;
+          guint j;
+          const gchar *s;
+          gpointer boxed;
+
+          /* we might already have consumed the only reference we have to
+           * the handle - if we have, we must recycle the same object rather
+           * than calling tp_contact_ensure again */
+          for (j = 0; j < i; j++)
+            {
+              if (handle == g_array_index (c->handles, guint, j))
+                {
+                  contact = g_object_ref (g_ptr_array_index (c->contacts, j));
+                }
+            }
+
+          if (contact == NULL)
+            contact = tp_contact_ensure (connection, handle);
+
+          /* set up the contact with its attributes */
+
+          s = tp_asv_get_string (asv,
+              TP_IFACE_CONNECTION "/contact-id");
+
+          if (s == NULL)
+            {
+              GError *e = g_error_new (TP_DBUS_ERRORS,
+                  TP_DBUS_ERROR_INCONSISTENT,
+                  "Connection manager %s is broken: contact #%u in "
+                  "the GetContactAttributes result has no contact-id",
+                  tp_proxy_get_bus_name (connection), handle);
+
+              contacts_context_fail (c, e);
+              g_error_free (e);
+              g_object_unref (contact);
+              return;
+            }
+          else if (contact->priv->identifier == NULL)
+            {
+              contact->priv->identifier = g_strdup (s);
+            }
+          else if (tp_strdiff (contact->priv->identifier, s))
+            {
+              GError *e = g_error_new (TP_DBUS_ERRORS,
+                  TP_DBUS_ERROR_INCONSISTENT,
+                  "Connection manager %s is broken: contact #%u "
+                  "identifier changed from %s to %s",
+                  tp_proxy_get_bus_name (connection), handle,
+                  contact->priv->identifier, s);
+
+              contacts_context_fail (c, e);
+              g_error_free (e);
+              g_object_unref (contact);
+              return;
+            }
+
+          s = tp_asv_get_string (asv,
+              TP_IFACE_CONNECTION_INTERFACE_ALIASING "/alias");
+
+          if (s != NULL)
+            {
+              contact->priv->has_features |= CONTACT_FEATURE_FLAG_ALIAS;
+              g_free (contact->priv->alias);
+              contact->priv->alias = g_strdup (s);
+              g_object_notify ((GObject *) contact, "alias");
+            }
+
+          s = tp_asv_get_string (asv,
+              TP_IFACE_CONNECTION_INTERFACE_AVATARS "/token");
+
+          if (s != NULL)
+            contacts_avatar_updated (connection, handle, s, NULL, NULL);
+
+          boxed = tp_asv_get_boxed (asv,
+              TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE "/presence",
+              TP_STRUCT_TYPE_SIMPLE_PRESENCE);
+          contact_maybe_set_simple_presence (contact, boxed);
+
+          /* FIXME: TP_IFACE_CONNECTION_INTERFACE_CAPABILITIES "/caps" */
+
+          /* save the contact and move on to the next handle */
+          g_ptr_array_add (c->contacts, contact);
+          i++;
+        }
+    }
+
+  contacts_context_continue (c);
+}
+
+
 /**
  * tp_connection_get_contacts_by_handle:
  * @self: A connection, which must be ready (#TpConnection:connection-ready
@@ -1633,6 +1757,68 @@ tp_connection_get_contacts_by_handle (TpConnection *self,
 
   g_array_append_vals (context->handles, handles, n_handles);
 
+  if (tp_proxy_has_interface_by_id (self,
+        TP_IFACE_QUARK_CONNECTION_INTERFACE_CONTACTS))
+    {
+      GPtrArray *array = g_ptr_array_sized_new (
+          self->priv->contact_attribute_interfaces->len);
+      const gchar **supported_interfaces;
+
+      for (i = 0; i < self->priv->contact_attribute_interfaces->len; i++)
+        {
+          GQuark q = g_array_index (self->priv->contact_attribute_interfaces,
+              GQuark, i);
+
+          if (q == TP_IFACE_QUARK_CONNECTION_INTERFACE_ALIASING)
+            {
+              if ((feature_flags & CONTACT_FEATURE_FLAG_ALIAS) != 0)
+                {
+                  g_ptr_array_add (array,
+                      TP_IFACE_CONNECTION_INTERFACE_ALIASING);
+                  contacts_bind_to_aliases_changed (self);
+                }
+            }
+          else if (q == TP_IFACE_QUARK_CONNECTION_INTERFACE_AVATARS)
+            {
+              if ((feature_flags & CONTACT_FEATURE_FLAG_AVATAR_TOKEN) != 0)
+                {
+                  g_ptr_array_add (array,
+                      TP_IFACE_CONNECTION_INTERFACE_AVATARS);
+                  contacts_bind_to_avatar_updated (self);
+                }
+            }
+          else if (q == TP_IFACE_QUARK_CONNECTION_INTERFACE_SIMPLE_PRESENCE)
+            {
+              if ((feature_flags & CONTACT_FEATURE_FLAG_PRESENCE) != 0)
+                {
+                  g_ptr_array_add (array,
+                      TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE);
+                  contacts_bind_to_presences_changed (self);
+                }
+            }
+        }
+
+      g_ptr_array_add (array, NULL);
+      supported_interfaces = (const gchar **) g_ptr_array_free (array, FALSE);
+
+      /* we support the Contacts interface, so we can hold the handles and
+       * simultaneously inspect them. After that, we'll fill in any
+       * features that are necessary (this becomes a no-op if Contacts
+       * gave us everything). */
+
+      contacts_context_queue_features (context, feature_flags);
+
+      tp_connection_get_contact_attributes (self, -1,
+          n_handles, handles, supported_interfaces, TRUE,
+          contacts_got_attributes,
+          context, contacts_context_unref, weak_object);
+      g_free (supported_interfaces);
+
+      return;
+    }
+
+  /* if we haven't already returned, we're on the slow path */
+
   /* Before we return anything we'll want to inspect the handles */
   g_queue_push_head (&context->todo, contacts_inspect);
 
-- 
1.5.6.5




More information about the Telepathy-commits mailing list